From 358bcc130a9e5b99d126d77994cecdeaa40968de Mon Sep 17 00:00:00 2001 From: "pinkerton%netscape.com" Date: Thu, 1 Jul 1999 00:07:41 +0000 Subject: [PATCH] Changing CreatePopup to return the popup. Adding a bunch of stuff for tooltips to the popup code. Fixing some bugs in webshell with loading malformed popups. Renamed "popup" to "popupElement" in the document and added "tooltipElement" as well. --- .../xul/content/src/nsXULPopupListener.cpp | 315 +++++++++++++++--- content/xul/document/src/nsXULDocument.cpp | 39 ++- docshell/base/nsWebShell.cpp | 6 +- dom/public/base/nsIDOMWindow.h | 6 +- dom/public/idl/base/Window.idl | 10 +- dom/public/idl/xul/XULDocument.idl | 4 +- dom/public/xul/nsIDOMXULDocument.h | 19 +- dom/src/base/nsGlobalWindow.cpp | 5 +- dom/src/base/nsGlobalWindow.h | 2 +- dom/src/base/nsJSWindow.cpp | 5 +- dom/src/xul/nsJSXULDocument.cpp | 163 ++++++++- rdf/content/public/idl/XULDocument.idl | 4 +- rdf/content/public/nsIDOMXULDocument.h | 19 +- rdf/content/src/nsJSXULDocument.cpp | 163 ++++++++- rdf/content/src/nsXULDocument.cpp | 39 ++- rdf/content/src/nsXULPopupListener.cpp | 315 +++++++++++++++--- webshell/public/nsIWebShell.h | 2 +- webshell/src/nsWebShell.cpp | 6 +- webshell/tests/viewer/nsBrowserWindow.cpp | 2 +- webshell/tests/viewer/nsBrowserWindow.h | 2 +- webshell/tests/viewer/nsXPBaseWindow.cpp | 2 +- webshell/tests/viewer/nsXPBaseWindow.h | 2 +- xpfe/appshell/src/nsWebShellWindow.cpp | 29 +- xpfe/appshell/src/nsWebShellWindow.h | 2 +- 24 files changed, 975 insertions(+), 186 deletions(-) diff --git a/content/xul/content/src/nsXULPopupListener.cpp b/content/xul/content/src/nsXULPopupListener.cpp index 9fb9805375a0..bc6f2483400a 100644 --- a/content/xul/content/src/nsXULPopupListener.cpp +++ b/content/xul/content/src/nsXULPopupListener.cpp @@ -34,6 +34,8 @@ #include "nsIDocument.h" #include "nsIContent.h" #include "nsIDOMUIEvent.h" +#include "nsITimer.h" + //////////////////////////////////////////////////////////////////////// @@ -41,10 +43,6 @@ static NS_DEFINE_IID(kXULPopupListenerCID, NS_XULPOPUPLISTENER_CID); static NS_DEFINE_IID(kIXULPopupListenerIID, NS_IXULPOPUPLISTENER_IID); static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); -static NS_DEFINE_IID(kIDomNodeIID, NS_IDOMNODE_IID); -static NS_DEFINE_IID(kIDomElementIID, NS_IDOMELEMENT_IID); -static NS_DEFINE_IID(kIDomEventListenerIID, NS_IDOMEVENTLISTENER_IID); - //////////////////////////////////////////////////////////////////////// // PopupListenerImpl // @@ -71,8 +69,8 @@ public: virtual nsresult MouseUp(nsIDOMEvent* aMouseEvent) { return NS_OK; }; virtual nsresult MouseClick(nsIDOMEvent* aMouseEvent) { return NS_OK; }; virtual nsresult MouseDblClick(nsIDOMEvent* aMouseEvent) { return NS_OK; }; - virtual nsresult MouseOver(nsIDOMEvent* aMouseEvent) { return NS_OK; }; - virtual nsresult MouseOut(nsIDOMEvent* aMouseEvent) { return NS_OK; }; + virtual nsresult MouseOver(nsIDOMEvent* aMouseEvent) ; + virtual nsresult MouseOut(nsIDOMEvent* aMouseEvent) ; // nsIDOMFocusListener virtual nsresult Focus(nsIDOMEvent* aEvent) { return NS_OK; }; @@ -82,16 +80,35 @@ public: virtual nsresult HandleEvent(nsIDOMEvent* anEvent) { return NS_OK; }; protected: + virtual nsresult LaunchPopup(nsIDOMEvent* anEvent); + virtual nsresult LaunchPopup( nsIDOMElement* aElement, PRInt32 aScreenX, PRInt32 aScreenY, + PRInt32 aClientX, PRInt32 aClientY ) ; + + nsresult FindDocumentForNode ( nsIDOMNode* inNode, nsIDOMXULDocument** outDoc ) ; private: - nsIDOMElement* element; // Weak reference. The element will go away first. + // |mElement| is the node to which this listener is attached. + nsIDOMElement* mElement; // Weak ref. The element will go away first. XULPopupType popupType; + nsCOMPtr mPopup; // The popup. We are responsible for making it go away. + + // The following members are not used unless |popupType| is tooltip. + + // a timer for determining if a tooltip should be displayed. + static void sTooltipCallback ( nsITimer *aTimer, void *aClosure ) ; + nsCOMPtr mTooltipTimer; + PRInt32 mMouseLocX, mMouseLocY; // mouse coordinates for tooltip event + // The node hovered over that fired the timer. This may turn into the node that + // triggered the tooltip, but only if the timer ever gets around to firing. + nsIDOMNode* mPossibleTooltipNode; // weak ref. + }; //////////////////////////////////////////////////////////////////////// XULPopupListenerImpl::XULPopupListenerImpl(void) + : mElement(nsnull), mPossibleTooltipNode(nsnull), mMouseLocX(0), mMouseLocY(0) { NS_INIT_REFCNT(); @@ -99,6 +116,11 @@ XULPopupListenerImpl::XULPopupListenerImpl(void) XULPopupListenerImpl::~XULPopupListenerImpl(void) { + //XXX do we need to close the popup here? Will we get the right events as + //XXX the topLevel window is going away when the closebox is pressed? + if ( mPopup ) + mPopup->Close(); + } NS_IMPL_ADDREF(XULPopupListenerImpl) @@ -126,7 +148,7 @@ XULPopupListenerImpl::QueryInterface(REFNSIID iid, void** result) NS_ADDREF_THIS(); return NS_OK; } - else if (iid.Equals(kIDomEventListenerIID)) { + else if (iid.Equals(nsIDOMEventListener::GetIID())) { *result = (nsIDOMEventListener*)(nsIDOMMouseListener*)this; NS_ADDREF_THIS(); return NS_OK; @@ -138,7 +160,7 @@ XULPopupListenerImpl::QueryInterface(REFNSIID iid, void** result) NS_IMETHODIMP XULPopupListenerImpl::Init(nsIDOMElement* aElement, const XULPopupType& popup) { - element = aElement; // Weak reference. Don't addref it. + mElement = aElement; // Weak reference. Don't addref it. popupType = popup; return NS_OK; } @@ -187,24 +209,186 @@ XULPopupListenerImpl::MouseDown(nsIDOMEvent* aMouseEvent) return NS_OK; } + +// +// MouseOver +// +// If we're a tooltip, fire off a timer to see if a tooltip should be shown. +// nsresult -XULPopupListenerImpl::LaunchPopup(nsIDOMEvent* anEvent) +XULPopupListenerImpl::MouseOver(nsIDOMEvent* aMouseEvent) +{ + nsresult rv = NS_OK; + + // make sure we're a tooltip. if not, bail. + if ( popupType != eXULPopupType_tooltip ) + return NS_OK; + + //XXX recognize when a popup is already up and immediately show the + //XXX tooltip for the new item if the dom element is different than + //XXX the element for which we are currently displaying the tip. + //XXX + //XXX for now, just be stupid to get things working. + + // Kill off an old timer and create a new one. + if ( mTooltipTimer ) { + mTooltipTimer->Cancel(); + mTooltipTimer = nsnull; + } + NS_NewTimer ( getter_AddRefs(mTooltipTimer) ); + if ( mTooltipTimer ) { + nsCOMPtr uiEvent ( do_QueryInterface(aMouseEvent) ); + if ( uiEvent ) { + // stash the coordinates of the event so that we can still get back to it from within the + // timer scallback. Also stash the node that started this so we can put it into the + // document later on (if the timer ever fires). + nsCOMPtr eventTarget; + aMouseEvent->GetTarget(getter_AddRefs(eventTarget)); + mPossibleTooltipNode = eventTarget.get(); +// BUG: 8598, widget and mouse coords not set for MouseOver events. +// uiEvent->GetScreenX(&mMouseLocX); +// uiEvent->GetScreenY(&mMouseLocY); + mMouseLocX = 50; mMouseLocY = 50; // XXX until bug 8598 fixed + mTooltipTimer->Init(sTooltipCallback, this, 1000); // one second delay + } + } + else + NS_WARNING ( "Could not create a timer for tooltip tracking" ); + + return NS_OK; + +} // MouseOver + + +// +// MouseOut +// +// If we're a tooltip, hide any tip that might be showing and remove any +// timer that is pending since the mouse is no longer over this area. +// +nsresult +XULPopupListenerImpl::MouseOut(nsIDOMEvent* aMouseEvent) +{ + // make sure we're a tooltip. if not, bail. + if ( popupType != eXULPopupType_tooltip ) + return NS_OK; + + if ( mTooltipTimer ) + mTooltipTimer->Cancel(); + + if ( mPopup ) { + mPopup->Close(); // hide the popup + mPopup = nsnull; // release the popup + + // clear out the tooltip node on the document + nsCOMPtr eventTarget; + aMouseEvent->GetTarget(getter_AddRefs(eventTarget)); + nsCOMPtr doc; + FindDocumentForNode ( eventTarget, getter_AddRefs(doc) ); + if ( doc ) + doc->SetTooltipElement(nsnull); + } + + return NS_OK; + +} // MouseOut + + +// +// FindDocumentForNode +// +// Given a DOM content node, finds the XUL document associated with it +// +nsresult +XULPopupListenerImpl :: FindDocumentForNode ( nsIDOMNode* inElement, nsIDOMXULDocument** outDoc ) +{ + nsresult rv = NS_OK; + + if ( !outDoc || !inElement ) + return NS_ERROR_INVALID_ARG; + + // get the document associated with this content element + nsCOMPtr document; + nsCOMPtr content = do_QueryInterface(inElement); + if (NS_FAILED(rv = content->GetDocument(*getter_AddRefs(document)))) { + NS_ERROR("Unable to retrieve the document."); + return rv; + } + + // Turn the document into a XUL document so we can use getElementById + nsCOMPtr xulDocument = do_QueryInterface(document); + if (xulDocument == nsnull) { + NS_ERROR("Popup attached to an element that isn't in XUL!"); + return NS_ERROR_FAILURE; + } + + *outDoc = xulDocument; + NS_ADDREF ( *outDoc ); + + return rv; + +} // FindDocumentForNode + + +// +// LaunchPopup +// +nsresult +XULPopupListenerImpl::LaunchPopup ( nsIDOMEvent* anEvent ) +{ + // Retrieve our x and y position. + nsCOMPtr uiEvent ( do_QueryInterface(anEvent) ); + if (!uiEvent) { + //non-ui event passed in. bad things. + return NS_OK; + } + + PRInt32 xPos, yPos; + uiEvent->GetScreenX(&xPos); + uiEvent->GetScreenY(&yPos); + + PRInt32 offsetX, offsetY; + uiEvent->GetClientX(&offsetX); + uiEvent->GetClientY(&offsetY); + + return LaunchPopup ( mElement, xPos, yPos, offsetX, offsetY ); +} + + +// +// LaunchPopup +// +// Given the element on which the event was triggered and the mouse locations in +// screen and widget coordinates, popup a new window showing the appropriate +// content. +// +// This looks for an attribute on |aElement| of the appropriate popup type +// (popup, context, tooltip) and uses that attribute's value as an ID for +// the popup content in the document. +// +nsresult +XULPopupListenerImpl::LaunchPopup( nsIDOMElement* aElement, PRInt32 aScreenX, PRInt32 aScreenY, + PRInt32 aOffsetX, PRInt32 aOffsetY ) { nsresult rv = NS_OK; nsAutoString type("popup"); - if (eXULPopupType_context == popupType) + if ( popupType == eXULPopupType_context ) type = "context"; + else if ( popupType == eXULPopupType_tooltip ) + type = "tooltip"; nsAutoString identifier; - element->GetAttribute(type, identifier); + mElement->GetAttribute(type, identifier); if (identifier == "") return rv; - // Try to find the popup content. + // Try to find the popup content and the document. We don't use FindDocumentForNode() + // in this case because we need the nsIDocument interface anyway for the script + // context. nsCOMPtr document; - nsCOMPtr content = do_QueryInterface(element); + nsCOMPtr content = do_QueryInterface(mElement); if (NS_FAILED(rv = content->GetDocument(*getter_AddRefs(document)))) { NS_ERROR("Unable to retrieve the document."); return rv; @@ -219,17 +403,15 @@ XULPopupListenerImpl::LaunchPopup(nsIDOMEvent* anEvent) // XXX Handle the _child case for popups and context menus! - // Use getElementById to obtain the popup content. + // Use getElementById to obtain the popup content and gracefully fail if + // we didn't find any popup content in the document. nsCOMPtr popupContent; if (NS_FAILED(rv = xulDocument->GetElementById(identifier, getter_AddRefs(popupContent)))) { NS_ERROR("GetElementById had some kind of spasm."); return rv; } - - if (popupContent == nsnull) { - // Gracefully fail in this case. + if ( !popupContent ) return NS_OK; - } // We have some popup content. Obtain our window. nsIScriptContextOwner* owner = document->GetScriptContextOwner(); @@ -242,42 +424,30 @@ XULPopupListenerImpl::LaunchPopup(nsIDOMEvent* anEvent) if (domWindow != nsnull) { // Find out if we're anchored. nsAutoString anchorAlignment("none"); - element->GetAttribute("popupanchor", anchorAlignment); + mElement->GetAttribute("popupanchor", anchorAlignment); nsAutoString popupAlignment("topleft"); - element->GetAttribute("popupalign", popupAlignment); + mElement->GetAttribute("popupalign", popupAlignment); - // Set the popup in the document for the duration of this call. - xulDocument->SetPopup(element); + // Set the popup in the document for the duration of this call. + xulDocument->SetPopupElement(mElement); - // Retrieve our x and y position. - nsCOMPtruiEvent; - uiEvent = do_QueryInterface(anEvent); - if (!uiEvent) { - //non-ui event passed in. bad things. - return NS_OK; - } - - PRInt32 xPos, yPos; - uiEvent->GetScreenX(&xPos); - uiEvent->GetScreenY(&yPos); - // If we're anchored, we pass in client/screen offsets so that - // we can translate the frames corners to screen coords. + // we can translate the frames corners to screen coords. + PRInt32 xPos = aScreenX, yPos = aScreenY; if (anchorAlignment != "none") { - PRInt32 offsetX, offsetY; - uiEvent->GetClientX(&offsetX); - uiEvent->GetClientY(&offsetY); - xPos = xPos-offsetX; - yPos = yPos-offsetY; + xPos -= aOffsetX; + yPos -= aOffsetY; } - - domWindow->CreatePopup(element, popupContent, - xPos, yPos, - type, anchorAlignment, popupAlignment); + domWindow->CreatePopup(mElement, popupContent, + xPos, yPos, + type, anchorAlignment, popupAlignment, + getter_AddRefs(mPopup)); + if ( popupType == eXULPopupType_popup && mPopup ) + mPopup->Focus(); // XXX For menus only, clear the document.popup field. - } + } NS_RELEASE(global); } } @@ -290,10 +460,12 @@ nsresult XULPopupListenerImpl::Blur(nsIDOMEvent* aMouseEvent) { nsresult rv = NS_OK; - + +#if 0 +// ONLY NEEDED BECAUSE HYATT WAS LAZY // Try to find the popup content. nsCOMPtr document; - nsCOMPtr content = do_QueryInterface(element); + nsCOMPtr content = do_QueryInterface(mElement); if (NS_FAILED(rv = content->GetDocument(*getter_AddRefs(document)))) { NS_ERROR("Unable to retrieve the document."); return rv; @@ -319,7 +491,20 @@ XULPopupListenerImpl::Blur(nsIDOMEvent* aMouseEvent) domWindow->Close(); } } +#endif + // Blur events don't bubble, so this means our window lost focus. + // Let's check just to make sure. + nsCOMPtr eventTarget; + aMouseEvent->GetTarget(getter_AddRefs(eventTarget)); + + // Close, but only if we are the same target. + nsCOMPtr windowNode = do_QueryInterface(mPopup); + if (windowNode.get() == eventTarget.get()) { + mPopup->Close(); + mPopup = nsnull; + } + // XXX Figure out how to fire the DESTROY event for the // arbitrary XUL case @@ -329,6 +514,40 @@ XULPopupListenerImpl::Blur(nsIDOMEvent* aMouseEvent) return rv; } + +// +// sTooltipCallback +// +// A timer callback, fired when the mouse has hovered inside of a frame for the +// appropriate amount of time. Getting to this point means that we should show the +// toolip. +// +// This relies on certain things being cached into the |aClosure| object passed to +// us by the timer: +// -- the x/y coordinates of the mouse +// -- the dom node the user hovered over +// +void +XULPopupListenerImpl :: sTooltipCallback (nsITimer *aTimer, void *aClosure) +{ + XULPopupListenerImpl* self = NS_STATIC_CAST(XULPopupListenerImpl*, aClosure); + if ( self ) { + // set the node in the document that triggered the tooltip and show it + nsCOMPtr doc; + self->FindDocumentForNode ( self->mPossibleTooltipNode, getter_AddRefs(doc) ); + if ( doc ) { + nsCOMPtr element ( do_QueryInterface(self->mPossibleTooltipNode) ); + if ( element ) { + doc->SetTooltipElement ( element ); + self->LaunchPopup ( element, self->mMouseLocX, self->mMouseLocY, 0, 0 ); + } + } // if document + } // if "self" data valid + +} // sTimerCallback + + + //////////////////////////////////////////////////////////////// nsresult NS_NewXULPopupListener(nsIXULPopupListener** pop) diff --git a/content/xul/document/src/nsXULDocument.cpp b/content/xul/document/src/nsXULDocument.cpp index 7c547b879daf..3c07b0ae45d6 100644 --- a/content/xul/document/src/nsXULDocument.cpp +++ b/content/xul/document/src/nsXULDocument.cpp @@ -782,10 +782,20 @@ protected: nsString mCommand; nsCOMPtr mFragmentRoot; // [OWNER] nsVoidArray mSubDocuments; // [OWNER] of subelements - nsCOMPtr mPopup; // [OWNER] of this popup element in the doc PRBool mIsPopup; nsCOMPtr mHiddenForm; // [OWNER] of this content element nsCOMPtr mFocusTracker; // [OWNER] of the focus tracker + + // The following are pointers into the content model which provide access to + // the objects triggering either a popup or a tooltip. These are marked as + // [OWNER] only because someone could, through DOM calls, delete the object from the + // content model while the popup/tooltip was visible. If we didn't have a reference + // to it, the object would go away and we'd be left pointing to garbage. This + // does not introduce cycles into the ownership model because this is still + // parent/child ownership. Just wanted the reader to know hyatt and I had thought about + // this (pinkerton). + nsCOMPtr mPopupElement; // [OWNER] element triggering the popup + nsCOMPtr mTooltipElement; // [OWNER] element triggering the tooltip }; PRInt32 XULDocumentImpl::gRefCnt = 0; @@ -2902,20 +2912,37 @@ XULDocumentImpl::CreateRange(nsIDOMRange** aRange) // nsIDOMXULDocument interface NS_IMETHODIMP -XULDocumentImpl::GetPopup(nsIDOMElement** anElement) +XULDocumentImpl::GetPopupElement(nsIDOMElement** anElement) { - *anElement = mPopup; + *anElement = mPopupElement; NS_IF_ADDREF(*anElement); return NS_OK; } NS_IMETHODIMP -XULDocumentImpl::SetPopup(nsIDOMElement* anElement) +XULDocumentImpl::SetPopupElement(nsIDOMElement* anElement) { - mPopup = dont_QueryInterface(anElement); + mPopupElement = dont_QueryInterface(anElement); return NS_OK; } + +NS_IMETHODIMP +XULDocumentImpl::GetTooltipElement(nsIDOMElement** anElement) +{ + *anElement = mTooltipElement; + NS_IF_ADDREF(*anElement); + return NS_OK; +} + +NS_IMETHODIMP +XULDocumentImpl::SetTooltipElement(nsIDOMElement* anElement) +{ + mTooltipElement = dont_QueryInterface(anElement); + return NS_OK; +} + + NS_IMETHODIMP XULDocumentImpl::GetFocus(nsIDOMXULFocusTracker** aTracker) { @@ -3128,7 +3155,7 @@ XULDocumentImpl::CreatePopupDocument(nsIContent* aPopupElement, nsIDocument** aR popupDoc->mNameSpaceManager = mNameSpaceManager; // We share the mPopup - popupDoc->mPopup = mPopup; + popupDoc->mPopupElement = mPopupElement; // Suck all of the root's content into our document. // We need to make the XUL builder instantiate this node. diff --git a/docshell/base/nsWebShell.cpp b/docshell/base/nsWebShell.cpp index 6f90cffc07a9..58fde3d49577 100644 --- a/docshell/base/nsWebShell.cpp +++ b/docshell/base/nsWebShell.cpp @@ -266,7 +266,7 @@ public: PRInt32 aXPos, PRInt32 aYPos, const nsString& aPopupType, const nsString& anAnchorAlignment, const nsString& aPopupAlignment, - nsIDOMWindow* aWindow); + nsIDOMWindow* aWindow, nsIDOMWindow** outPopup); NS_IMETHOD FindWebShellWithName(const PRUnichar* aName, nsIWebShell*& aResult); NS_IMETHOD FocusAvailable(nsIWebShell* aFocusedWebShell, PRBool& aFocusTaken); @@ -2198,12 +2198,12 @@ nsWebShell::CreatePopup(nsIDOMElement* aElement, nsIDOMElement* aPopupContent, PRInt32 aXPos, PRInt32 aYPos, const nsString& aPopupType, const nsString& anAnchorAlignment, const nsString& aPopupAlignment, - nsIDOMWindow* aWindow) + nsIDOMWindow* aWindow, nsIDOMWindow** outPopup) { if (nsnull != mContainer) { return mContainer->CreatePopup(aElement, aPopupContent, aXPos, aYPos, aPopupType, anAnchorAlignment, aPopupAlignment, - aWindow); + aWindow, outPopup); } return NS_OK; } diff --git a/dom/public/base/nsIDOMWindow.h b/dom/public/base/nsIDOMWindow.h index 568c9e62df18..a08250e271e1 100644 --- a/dom/public/base/nsIDOMWindow.h +++ b/dom/public/base/nsIDOMWindow.h @@ -158,7 +158,7 @@ public: NS_IMETHOD SetInterval(JSContext *cx, jsval *argv, PRUint32 argc, PRInt32* aReturn)=0; - NS_IMETHOD CreatePopup(nsIDOMElement* aElement, nsIDOMElement* aPopupContent, PRInt32 aXPos, PRInt32 aYPos, const nsString& aPopupType, const nsString& aAnchorAlignment, const nsString& aPopupAlignment)=0; + NS_IMETHOD CreatePopup(nsIDOMElement* aElement, nsIDOMElement* aPopupContent, PRInt32 aXPos, PRInt32 aYPos, const nsString& aPopupType, const nsString& aAnchorAlignment, const nsString& aPopupAlignment, nsIDOMWindow** aReturn)=0; NS_IMETHOD Open(JSContext *cx, jsval *argv, PRUint32 argc, nsIDOMWindow** aReturn)=0; @@ -231,7 +231,7 @@ public: NS_IMETHOD ClearInterval(PRInt32 aTimerID); \ NS_IMETHOD SetTimeout(JSContext *cx, jsval *argv, PRUint32 argc, PRInt32* aReturn); \ NS_IMETHOD SetInterval(JSContext *cx, jsval *argv, PRUint32 argc, PRInt32* aReturn); \ - NS_IMETHOD CreatePopup(nsIDOMElement* aElement, nsIDOMElement* aPopupContent, PRInt32 aXPos, PRInt32 aYPos, const nsString& aPopupType, const nsString& aAnchorAlignment, const nsString& aPopupAlignment); \ + NS_IMETHOD CreatePopup(nsIDOMElement* aElement, nsIDOMElement* aPopupContent, PRInt32 aXPos, PRInt32 aYPos, const nsString& aPopupType, const nsString& aAnchorAlignment, const nsString& aPopupAlignment, nsIDOMWindow** aReturn); \ NS_IMETHOD Open(JSContext *cx, jsval *argv, PRUint32 argc, nsIDOMWindow** aReturn); \ NS_IMETHOD OpenDialog(JSContext *cx, jsval *argv, PRUint32 argc, nsIDOMWindow** aReturn); \ @@ -302,7 +302,7 @@ public: NS_IMETHOD ClearInterval(PRInt32 aTimerID) { return _to ClearInterval(aTimerID); } \ NS_IMETHOD SetTimeout(JSContext *cx, jsval *argv, PRUint32 argc, PRInt32* aReturn) { return _to SetTimeout(cx, argv, argc, aReturn); } \ NS_IMETHOD SetInterval(JSContext *cx, jsval *argv, PRUint32 argc, PRInt32* aReturn) { return _to SetInterval(cx, argv, argc, aReturn); } \ - NS_IMETHOD CreatePopup(nsIDOMElement* aElement, nsIDOMElement* aPopupContent, PRInt32 aXPos, PRInt32 aYPos, const nsString& aPopupType, const nsString& aAnchorAlignment, const nsString& aPopupAlignment) { return _to CreatePopup(aElement, aPopupContent, aXPos, aYPos, aPopupType, aAnchorAlignment, aPopupAlignment); } \ + NS_IMETHOD CreatePopup(nsIDOMElement* aElement, nsIDOMElement* aPopupContent, PRInt32 aXPos, PRInt32 aYPos, const nsString& aPopupType, const nsString& aAnchorAlignment, const nsString& aPopupAlignment, nsIDOMWindow** aReturn) { return _to CreatePopup(aElement, aPopupContent, aXPos, aYPos, aPopupType, aAnchorAlignment, aPopupAlignment, aReturn); } \ NS_IMETHOD Open(JSContext *cx, jsval *argv, PRUint32 argc, nsIDOMWindow** aReturn) { return _to Open(cx, argv, argc, aReturn); } \ NS_IMETHOD OpenDialog(JSContext *cx, jsval *argv, PRUint32 argc, nsIDOMWindow** aReturn) { return _to OpenDialog(cx, argv, argc, aReturn); } \ diff --git a/dom/public/idl/base/Window.idl b/dom/public/idl/base/Window.idl index 41de63e6ebd3..41dff8e9ade1 100644 --- a/dom/public/idl/base/Window.idl +++ b/dom/public/idl/base/Window.idl @@ -57,11 +57,11 @@ long setTimeout(/* ... */); long setInterval(/* ... */); - void createPopup(in Element element, in Element popupContent, - in long xPos, in long yPos, - in DOMString popupType, in DOMString anchorAlignment, - in DOMString popupAlignment); - + Window createPopup(in Element element, in Element popupContent, + in long xPos, in long yPos, + in DOMString popupType, in DOMString anchorAlignment, + in DOMString popupAlignment); + Window open(/* ... */); Window openDialog(/* ... */); }; diff --git a/dom/public/idl/xul/XULDocument.idl b/dom/public/idl/xul/XULDocument.idl index 4384235a701e..c9ade6221328 100644 --- a/dom/public/idl/xul/XULDocument.idl +++ b/dom/public/idl/xul/XULDocument.idl @@ -3,7 +3,9 @@ interface XULDocument : Document { /* IID: { 0x17ddd8c0, 0xc5f8, 0x11d2, \ { 0xa6, 0xae, 0x0, 0x10, 0x4b, 0xde, 0x60, 0x48 } } */ - attribute Element popup; + attribute Element popupElement; + attribute Element tooltipElement; + readonly attribute XULFocusTracker focus; Element getElementById(in DOMString id); diff --git a/dom/public/xul/nsIDOMXULDocument.h b/dom/public/xul/nsIDOMXULDocument.h index 3f20070c2c09..22da40adc3d8 100644 --- a/dom/public/xul/nsIDOMXULDocument.h +++ b/dom/public/xul/nsIDOMXULDocument.h @@ -37,8 +37,11 @@ class nsIDOMXULDocument : public nsIDOMDocument { public: static const nsIID& GetIID() { static nsIID iid = NS_IDOMXULDOCUMENT_IID; return iid; } - NS_IMETHOD GetPopup(nsIDOMElement** aPopup)=0; - NS_IMETHOD SetPopup(nsIDOMElement* aPopup)=0; + NS_IMETHOD GetPopupElement(nsIDOMElement** aPopupElement)=0; + NS_IMETHOD SetPopupElement(nsIDOMElement* aPopupElement)=0; + + NS_IMETHOD GetTooltipElement(nsIDOMElement** aTooltipElement)=0; + NS_IMETHOD SetTooltipElement(nsIDOMElement* aTooltipElement)=0; NS_IMETHOD GetFocus(nsIDOMXULFocusTracker** aFocus)=0; @@ -49,8 +52,10 @@ public: #define NS_DECL_IDOMXULDOCUMENT \ - NS_IMETHOD GetPopup(nsIDOMElement** aPopup); \ - NS_IMETHOD SetPopup(nsIDOMElement* aPopup); \ + NS_IMETHOD GetPopupElement(nsIDOMElement** aPopupElement); \ + NS_IMETHOD SetPopupElement(nsIDOMElement* aPopupElement); \ + NS_IMETHOD GetTooltipElement(nsIDOMElement** aTooltipElement); \ + NS_IMETHOD SetTooltipElement(nsIDOMElement* aTooltipElement); \ NS_IMETHOD GetFocus(nsIDOMXULFocusTracker** aFocus); \ NS_IMETHOD GetElementById(const nsString& aId, nsIDOMElement** aReturn); \ NS_IMETHOD GetElementsByAttribute(const nsString& aName, const nsString& aValue, nsIDOMNodeList** aReturn); \ @@ -58,8 +63,10 @@ public: #define NS_FORWARD_IDOMXULDOCUMENT(_to) \ - NS_IMETHOD GetPopup(nsIDOMElement** aPopup) { return _to GetPopup(aPopup); } \ - NS_IMETHOD SetPopup(nsIDOMElement* aPopup) { return _to SetPopup(aPopup); } \ + NS_IMETHOD GetPopupElement(nsIDOMElement** aPopupElement) { return _to GetPopupElement(aPopupElement); } \ + NS_IMETHOD SetPopupElement(nsIDOMElement* aPopupElement) { return _to SetPopupElement(aPopupElement); } \ + NS_IMETHOD GetTooltipElement(nsIDOMElement** aTooltipElement) { return _to GetTooltipElement(aTooltipElement); } \ + NS_IMETHOD SetTooltipElement(nsIDOMElement* aTooltipElement) { return _to SetTooltipElement(aTooltipElement); } \ NS_IMETHOD GetFocus(nsIDOMXULFocusTracker** aFocus) { return _to GetFocus(aFocus); } \ NS_IMETHOD GetElementById(const nsString& aId, nsIDOMElement** aReturn) { return _to GetElementById(aId, aReturn); } \ NS_IMETHOD GetElementsByAttribute(const nsString& aName, const nsString& aValue, nsIDOMNodeList** aReturn) { return _to GetElementsByAttribute(aName, aValue, aReturn); } \ diff --git a/dom/src/base/nsGlobalWindow.cpp b/dom/src/base/nsGlobalWindow.cpp index a4a3eef53d0b..73d267bc27f1 100644 --- a/dom/src/base/nsGlobalWindow.cpp +++ b/dom/src/base/nsGlobalWindow.cpp @@ -2079,14 +2079,15 @@ NS_IMETHODIMP GlobalWindowImpl::CreatePopup(nsIDOMElement* aElement, nsIDOMElement* aPopupContent, PRInt32 aXPos, PRInt32 aYPos, const nsString& aPopupType, - const nsString& anAnchorAlignment, const nsString& aPopupAlignment) + const nsString& anAnchorAlignment, const nsString& aPopupAlignment, + nsIDOMWindow** outPopup) { if (nsnull != mWebShell) { // Pass this off to the parent. nsCOMPtr webShellContainer = do_QueryInterface(mWebShell); if (webShellContainer) { webShellContainer->CreatePopup(aElement, aPopupContent, aXPos, aYPos, aPopupType, - anAnchorAlignment, aPopupAlignment, this); + anAnchorAlignment, aPopupAlignment, this, outPopup); } } return NS_OK; diff --git a/dom/src/base/nsGlobalWindow.h b/dom/src/base/nsGlobalWindow.h index af2487b7257b..b633b1e7c2c9 100644 --- a/dom/src/base/nsGlobalWindow.h +++ b/dom/src/base/nsGlobalWindow.h @@ -165,7 +165,7 @@ public: NS_IMETHOD CreatePopup(nsIDOMElement* aElement, nsIDOMElement* aPopupContent, PRInt32 aXPos, PRInt32 aYPos, const nsString& aPopupType, const nsString& anAnchorAlignment, - const nsString& aPopupAlignment); + const nsString& aPopupAlignment, nsIDOMWindow** outPopup); // nsIDOMEventCapturer interface NS_IMETHOD CaptureEvent(const nsString& aType); diff --git a/dom/src/base/nsJSWindow.cpp b/dom/src/base/nsJSWindow.cpp index 94fe3b5b4692..c9ceee3f8837 100644 --- a/dom/src/base/nsJSWindow.cpp +++ b/dom/src/base/nsJSWindow.cpp @@ -2083,6 +2083,7 @@ WindowCreatePopup(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval * { nsIDOMWindow *nativeThis = (nsIDOMWindow*)nsJSUtils::nsGetNativeThis(cx, obj); JSBool rBool = JS_FALSE; + nsIDOMWindow* nativeRet; nsIDOMElementPtr b0; nsIDOMElementPtr b1; PRInt32 b2; @@ -2147,11 +2148,11 @@ WindowCreatePopup(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval * nsJSUtils::nsConvertJSValToString(b6, cx, argv[6]); - if (NS_OK != nativeThis->CreatePopup(b0, b1, b2, b3, b4, b5, b6)) { + if (NS_OK != nativeThis->CreatePopup(b0, b1, b2, b3, b4, b5, b6, &nativeRet)) { return JS_FALSE; } - *rval = JSVAL_VOID; + nsJSUtils::nsConvertObjectToJSVal(nativeRet, cx, rval); } else { JS_ReportError(cx, "Function createPopup requires 7 parameters"); diff --git a/dom/src/xul/nsJSXULDocument.cpp b/dom/src/xul/nsJSXULDocument.cpp index 9bb0833dabc5..8912f0ab0d7d 100644 --- a/dom/src/xul/nsJSXULDocument.cpp +++ b/dom/src/xul/nsJSXULDocument.cpp @@ -50,8 +50,12 @@ NS_DEF_PTR(nsIDOMNodeList); // XULDocument property ids // enum XULDocument_slots { - XULDOCUMENT_POPUP = -1, - XULDOCUMENT_FOCUS = -2 + XULDOCUMENT_POPUPELEMENT = -1, + + XULDOCUMENT_TOOLTIPELEMENT = -2, + + XULDOCUMENT_FOCUS = -3 + }; /***********************************************************************/ @@ -61,30 +65,88 @@ enum XULDocument_slots { PR_STATIC_CALLBACK(JSBool) GetXULDocumentProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { - nsIDOMXULDocument *a = (nsIDOMXULDocument*)JS_GetPrivate(cx, obj); + nsIDOMXULDocument *a = (nsIDOMXULDocument*)nsJSUtils::nsGetNativeThis(cx, obj); + + // If there's no private data, this must be the prototype, so ignore + if (nsnull == a) { + return JS_TRUE; + } + + if (JSVAL_IS_INT(id)) { + nsIScriptContext *scriptCX = (nsIScriptContext *)JS_GetContextPrivate(cx); + nsIScriptSecurityManager *secMan; - PRBool ok; + + PRBool ok = PR_FALSE; + if (NS_OK != scriptCX->GetSecurityManager(&secMan)) { + return JS_FALSE; + } + switch(JSVAL_TO_INT(id)) { - case XULDOCUMENT_POPUP: + + case XULDOCUMENT_POPUPELEMENT: + { - secMan->CheckScriptAccess(scriptCX, obj, "xuldocument.popup", &ok); + + secMan->CheckScriptAccess(scriptCX, obj, "xuldocument.popupelement", &ok); + if (!ok) { + //Need to throw error here + return JS_FALSE; + } + nsIDOMElement* prop; - if (NS_OK == a->GetPopup(&prop)) { + + if (NS_OK == a->GetPopupElement(&prop)) { + + // get the js object + + nsJSUtils::nsConvertObjectToJSVal((nsISupports *)prop, cx, vp); + + } + + else { + + return JS_FALSE; + + } + + break; + + } + + case XULDOCUMENT_TOOLTIPELEMENT: + + { + + secMan->CheckScriptAccess(scriptCX, obj, "xuldocument.tooltipelement", &ok); + + if (!ok) { + + //Need to throw error here + + return JS_FALSE; + + } + + nsIDOMElement* prop; + + if (NS_OK == a->GetTooltipElement(&prop)) { + // get the js object nsJSUtils::nsConvertObjectToJSVal((nsISupports *)prop, cx, vp); } @@ -129,36 +191,102 @@ GetXULDocumentProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) PR_STATIC_CALLBACK(JSBool) SetXULDocumentProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { - nsIDOMXULDocument *a = (nsIDOMXULDocument*)JS_GetPrivate(cx, obj); + nsIDOMXULDocument *a = (nsIDOMXULDocument*)nsJSUtils::nsGetNativeThis(cx, obj); + + // If there's no private data, this must be the prototype, so ignore + if (nsnull == a) { + return JS_TRUE; + } + + if (JSVAL_IS_INT(id)) { + nsIScriptContext *scriptCX = (nsIScriptContext *)JS_GetContextPrivate(cx); + nsIScriptSecurityManager *secMan; - PRBool ok; + + PRBool ok = PR_FALSE; + if (NS_OK != scriptCX->GetSecurityManager(&secMan)) { + return JS_FALSE; + } + switch(JSVAL_TO_INT(id)) { - case XULDOCUMENT_POPUP: + + case XULDOCUMENT_POPUPELEMENT: + { - secMan->CheckScriptAccess(scriptCX, obj, "xuldocument.popup", &ok); + + secMan->CheckScriptAccess(scriptCX, obj, "xuldocument.popupelement", &ok); + if (!ok) { + //Need to throw error here + return JS_FALSE; + } + nsIDOMElement* prop; + if (PR_FALSE == nsJSUtils::nsConvertJSValToObject((nsISupports **)&prop, + kIElementIID, "Element", + cx, *vp)) { + return JS_FALSE; + } + - a->SetPopup(prop); + + a->SetPopupElement(prop); + + NS_IF_RELEASE(prop); + + break; + + } + + case XULDOCUMENT_TOOLTIPELEMENT: + + { + + secMan->CheckScriptAccess(scriptCX, obj, "xuldocument.tooltipelement", &ok); + + if (!ok) { + + //Need to throw error here + + return JS_FALSE; + + } + + nsIDOMElement* prop; + + if (PR_FALSE == nsJSUtils::nsConvertJSValToObject((nsISupports **)&prop, + + kIElementIID, "Element", + + cx, *vp)) { + + return JS_FALSE; + + } + + + + a->SetTooltipElement(prop); + NS_IF_RELEASE(prop); break; } @@ -211,7 +339,8 @@ ResolveXULDocument(JSContext *cx, JSObject *obj, jsval id) PR_STATIC_CALLBACK(JSBool) XULDocumentGetElementById(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { - nsIDOMXULDocument *nativeThis = (nsIDOMXULDocument*)JS_GetPrivate(cx, obj); + nsIDOMXULDocument *nativeThis = (nsIDOMXULDocument*)nsJSUtils::nsGetNativeThis(cx, obj); + JSBool rBool = JS_FALSE; nsIDOMElement* nativeRet; nsAutoString b0; @@ -263,7 +392,8 @@ XULDocumentGetElementById(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, PR_STATIC_CALLBACK(JSBool) XULDocumentGetElementsByAttribute(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { - nsIDOMXULDocument *nativeThis = (nsIDOMXULDocument*)JS_GetPrivate(cx, obj); + nsIDOMXULDocument *nativeThis = (nsIDOMXULDocument*)nsJSUtils::nsGetNativeThis(cx, obj); + JSBool rBool = JS_FALSE; nsIDOMNodeList* nativeRet; nsAutoString b0; @@ -335,7 +465,10 @@ JSClass XULDocumentClass = { // static JSPropertySpec XULDocumentProperties[] = { - {"popup", XULDOCUMENT_POPUP, JSPROP_ENUMERATE}, + {"popupElement", XULDOCUMENT_POPUPELEMENT, JSPROP_ENUMERATE}, + + {"tooltipElement", XULDOCUMENT_TOOLTIPELEMENT, JSPROP_ENUMERATE}, + {"focus", XULDOCUMENT_FOCUS, JSPROP_ENUMERATE | JSPROP_READONLY}, {0} }; diff --git a/rdf/content/public/idl/XULDocument.idl b/rdf/content/public/idl/XULDocument.idl index 4384235a701e..c9ade6221328 100644 --- a/rdf/content/public/idl/XULDocument.idl +++ b/rdf/content/public/idl/XULDocument.idl @@ -3,7 +3,9 @@ interface XULDocument : Document { /* IID: { 0x17ddd8c0, 0xc5f8, 0x11d2, \ { 0xa6, 0xae, 0x0, 0x10, 0x4b, 0xde, 0x60, 0x48 } } */ - attribute Element popup; + attribute Element popupElement; + attribute Element tooltipElement; + readonly attribute XULFocusTracker focus; Element getElementById(in DOMString id); diff --git a/rdf/content/public/nsIDOMXULDocument.h b/rdf/content/public/nsIDOMXULDocument.h index 3f20070c2c09..22da40adc3d8 100644 --- a/rdf/content/public/nsIDOMXULDocument.h +++ b/rdf/content/public/nsIDOMXULDocument.h @@ -37,8 +37,11 @@ class nsIDOMXULDocument : public nsIDOMDocument { public: static const nsIID& GetIID() { static nsIID iid = NS_IDOMXULDOCUMENT_IID; return iid; } - NS_IMETHOD GetPopup(nsIDOMElement** aPopup)=0; - NS_IMETHOD SetPopup(nsIDOMElement* aPopup)=0; + NS_IMETHOD GetPopupElement(nsIDOMElement** aPopupElement)=0; + NS_IMETHOD SetPopupElement(nsIDOMElement* aPopupElement)=0; + + NS_IMETHOD GetTooltipElement(nsIDOMElement** aTooltipElement)=0; + NS_IMETHOD SetTooltipElement(nsIDOMElement* aTooltipElement)=0; NS_IMETHOD GetFocus(nsIDOMXULFocusTracker** aFocus)=0; @@ -49,8 +52,10 @@ public: #define NS_DECL_IDOMXULDOCUMENT \ - NS_IMETHOD GetPopup(nsIDOMElement** aPopup); \ - NS_IMETHOD SetPopup(nsIDOMElement* aPopup); \ + NS_IMETHOD GetPopupElement(nsIDOMElement** aPopupElement); \ + NS_IMETHOD SetPopupElement(nsIDOMElement* aPopupElement); \ + NS_IMETHOD GetTooltipElement(nsIDOMElement** aTooltipElement); \ + NS_IMETHOD SetTooltipElement(nsIDOMElement* aTooltipElement); \ NS_IMETHOD GetFocus(nsIDOMXULFocusTracker** aFocus); \ NS_IMETHOD GetElementById(const nsString& aId, nsIDOMElement** aReturn); \ NS_IMETHOD GetElementsByAttribute(const nsString& aName, const nsString& aValue, nsIDOMNodeList** aReturn); \ @@ -58,8 +63,10 @@ public: #define NS_FORWARD_IDOMXULDOCUMENT(_to) \ - NS_IMETHOD GetPopup(nsIDOMElement** aPopup) { return _to GetPopup(aPopup); } \ - NS_IMETHOD SetPopup(nsIDOMElement* aPopup) { return _to SetPopup(aPopup); } \ + NS_IMETHOD GetPopupElement(nsIDOMElement** aPopupElement) { return _to GetPopupElement(aPopupElement); } \ + NS_IMETHOD SetPopupElement(nsIDOMElement* aPopupElement) { return _to SetPopupElement(aPopupElement); } \ + NS_IMETHOD GetTooltipElement(nsIDOMElement** aTooltipElement) { return _to GetTooltipElement(aTooltipElement); } \ + NS_IMETHOD SetTooltipElement(nsIDOMElement* aTooltipElement) { return _to SetTooltipElement(aTooltipElement); } \ NS_IMETHOD GetFocus(nsIDOMXULFocusTracker** aFocus) { return _to GetFocus(aFocus); } \ NS_IMETHOD GetElementById(const nsString& aId, nsIDOMElement** aReturn) { return _to GetElementById(aId, aReturn); } \ NS_IMETHOD GetElementsByAttribute(const nsString& aName, const nsString& aValue, nsIDOMNodeList** aReturn) { return _to GetElementsByAttribute(aName, aValue, aReturn); } \ diff --git a/rdf/content/src/nsJSXULDocument.cpp b/rdf/content/src/nsJSXULDocument.cpp index 9bb0833dabc5..8912f0ab0d7d 100644 --- a/rdf/content/src/nsJSXULDocument.cpp +++ b/rdf/content/src/nsJSXULDocument.cpp @@ -50,8 +50,12 @@ NS_DEF_PTR(nsIDOMNodeList); // XULDocument property ids // enum XULDocument_slots { - XULDOCUMENT_POPUP = -1, - XULDOCUMENT_FOCUS = -2 + XULDOCUMENT_POPUPELEMENT = -1, + + XULDOCUMENT_TOOLTIPELEMENT = -2, + + XULDOCUMENT_FOCUS = -3 + }; /***********************************************************************/ @@ -61,30 +65,88 @@ enum XULDocument_slots { PR_STATIC_CALLBACK(JSBool) GetXULDocumentProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { - nsIDOMXULDocument *a = (nsIDOMXULDocument*)JS_GetPrivate(cx, obj); + nsIDOMXULDocument *a = (nsIDOMXULDocument*)nsJSUtils::nsGetNativeThis(cx, obj); + + // If there's no private data, this must be the prototype, so ignore + if (nsnull == a) { + return JS_TRUE; + } + + if (JSVAL_IS_INT(id)) { + nsIScriptContext *scriptCX = (nsIScriptContext *)JS_GetContextPrivate(cx); + nsIScriptSecurityManager *secMan; - PRBool ok; + + PRBool ok = PR_FALSE; + if (NS_OK != scriptCX->GetSecurityManager(&secMan)) { + return JS_FALSE; + } + switch(JSVAL_TO_INT(id)) { - case XULDOCUMENT_POPUP: + + case XULDOCUMENT_POPUPELEMENT: + { - secMan->CheckScriptAccess(scriptCX, obj, "xuldocument.popup", &ok); + + secMan->CheckScriptAccess(scriptCX, obj, "xuldocument.popupelement", &ok); + if (!ok) { + //Need to throw error here + return JS_FALSE; + } + nsIDOMElement* prop; - if (NS_OK == a->GetPopup(&prop)) { + + if (NS_OK == a->GetPopupElement(&prop)) { + + // get the js object + + nsJSUtils::nsConvertObjectToJSVal((nsISupports *)prop, cx, vp); + + } + + else { + + return JS_FALSE; + + } + + break; + + } + + case XULDOCUMENT_TOOLTIPELEMENT: + + { + + secMan->CheckScriptAccess(scriptCX, obj, "xuldocument.tooltipelement", &ok); + + if (!ok) { + + //Need to throw error here + + return JS_FALSE; + + } + + nsIDOMElement* prop; + + if (NS_OK == a->GetTooltipElement(&prop)) { + // get the js object nsJSUtils::nsConvertObjectToJSVal((nsISupports *)prop, cx, vp); } @@ -129,36 +191,102 @@ GetXULDocumentProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) PR_STATIC_CALLBACK(JSBool) SetXULDocumentProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { - nsIDOMXULDocument *a = (nsIDOMXULDocument*)JS_GetPrivate(cx, obj); + nsIDOMXULDocument *a = (nsIDOMXULDocument*)nsJSUtils::nsGetNativeThis(cx, obj); + + // If there's no private data, this must be the prototype, so ignore + if (nsnull == a) { + return JS_TRUE; + } + + if (JSVAL_IS_INT(id)) { + nsIScriptContext *scriptCX = (nsIScriptContext *)JS_GetContextPrivate(cx); + nsIScriptSecurityManager *secMan; - PRBool ok; + + PRBool ok = PR_FALSE; + if (NS_OK != scriptCX->GetSecurityManager(&secMan)) { + return JS_FALSE; + } + switch(JSVAL_TO_INT(id)) { - case XULDOCUMENT_POPUP: + + case XULDOCUMENT_POPUPELEMENT: + { - secMan->CheckScriptAccess(scriptCX, obj, "xuldocument.popup", &ok); + + secMan->CheckScriptAccess(scriptCX, obj, "xuldocument.popupelement", &ok); + if (!ok) { + //Need to throw error here + return JS_FALSE; + } + nsIDOMElement* prop; + if (PR_FALSE == nsJSUtils::nsConvertJSValToObject((nsISupports **)&prop, + kIElementIID, "Element", + cx, *vp)) { + return JS_FALSE; + } + - a->SetPopup(prop); + + a->SetPopupElement(prop); + + NS_IF_RELEASE(prop); + + break; + + } + + case XULDOCUMENT_TOOLTIPELEMENT: + + { + + secMan->CheckScriptAccess(scriptCX, obj, "xuldocument.tooltipelement", &ok); + + if (!ok) { + + //Need to throw error here + + return JS_FALSE; + + } + + nsIDOMElement* prop; + + if (PR_FALSE == nsJSUtils::nsConvertJSValToObject((nsISupports **)&prop, + + kIElementIID, "Element", + + cx, *vp)) { + + return JS_FALSE; + + } + + + + a->SetTooltipElement(prop); + NS_IF_RELEASE(prop); break; } @@ -211,7 +339,8 @@ ResolveXULDocument(JSContext *cx, JSObject *obj, jsval id) PR_STATIC_CALLBACK(JSBool) XULDocumentGetElementById(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { - nsIDOMXULDocument *nativeThis = (nsIDOMXULDocument*)JS_GetPrivate(cx, obj); + nsIDOMXULDocument *nativeThis = (nsIDOMXULDocument*)nsJSUtils::nsGetNativeThis(cx, obj); + JSBool rBool = JS_FALSE; nsIDOMElement* nativeRet; nsAutoString b0; @@ -263,7 +392,8 @@ XULDocumentGetElementById(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, PR_STATIC_CALLBACK(JSBool) XULDocumentGetElementsByAttribute(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { - nsIDOMXULDocument *nativeThis = (nsIDOMXULDocument*)JS_GetPrivate(cx, obj); + nsIDOMXULDocument *nativeThis = (nsIDOMXULDocument*)nsJSUtils::nsGetNativeThis(cx, obj); + JSBool rBool = JS_FALSE; nsIDOMNodeList* nativeRet; nsAutoString b0; @@ -335,7 +465,10 @@ JSClass XULDocumentClass = { // static JSPropertySpec XULDocumentProperties[] = { - {"popup", XULDOCUMENT_POPUP, JSPROP_ENUMERATE}, + {"popupElement", XULDOCUMENT_POPUPELEMENT, JSPROP_ENUMERATE}, + + {"tooltipElement", XULDOCUMENT_TOOLTIPELEMENT, JSPROP_ENUMERATE}, + {"focus", XULDOCUMENT_FOCUS, JSPROP_ENUMERATE | JSPROP_READONLY}, {0} }; diff --git a/rdf/content/src/nsXULDocument.cpp b/rdf/content/src/nsXULDocument.cpp index 7c547b879daf..3c07b0ae45d6 100644 --- a/rdf/content/src/nsXULDocument.cpp +++ b/rdf/content/src/nsXULDocument.cpp @@ -782,10 +782,20 @@ protected: nsString mCommand; nsCOMPtr mFragmentRoot; // [OWNER] nsVoidArray mSubDocuments; // [OWNER] of subelements - nsCOMPtr mPopup; // [OWNER] of this popup element in the doc PRBool mIsPopup; nsCOMPtr mHiddenForm; // [OWNER] of this content element nsCOMPtr mFocusTracker; // [OWNER] of the focus tracker + + // The following are pointers into the content model which provide access to + // the objects triggering either a popup or a tooltip. These are marked as + // [OWNER] only because someone could, through DOM calls, delete the object from the + // content model while the popup/tooltip was visible. If we didn't have a reference + // to it, the object would go away and we'd be left pointing to garbage. This + // does not introduce cycles into the ownership model because this is still + // parent/child ownership. Just wanted the reader to know hyatt and I had thought about + // this (pinkerton). + nsCOMPtr mPopupElement; // [OWNER] element triggering the popup + nsCOMPtr mTooltipElement; // [OWNER] element triggering the tooltip }; PRInt32 XULDocumentImpl::gRefCnt = 0; @@ -2902,20 +2912,37 @@ XULDocumentImpl::CreateRange(nsIDOMRange** aRange) // nsIDOMXULDocument interface NS_IMETHODIMP -XULDocumentImpl::GetPopup(nsIDOMElement** anElement) +XULDocumentImpl::GetPopupElement(nsIDOMElement** anElement) { - *anElement = mPopup; + *anElement = mPopupElement; NS_IF_ADDREF(*anElement); return NS_OK; } NS_IMETHODIMP -XULDocumentImpl::SetPopup(nsIDOMElement* anElement) +XULDocumentImpl::SetPopupElement(nsIDOMElement* anElement) { - mPopup = dont_QueryInterface(anElement); + mPopupElement = dont_QueryInterface(anElement); return NS_OK; } + +NS_IMETHODIMP +XULDocumentImpl::GetTooltipElement(nsIDOMElement** anElement) +{ + *anElement = mTooltipElement; + NS_IF_ADDREF(*anElement); + return NS_OK; +} + +NS_IMETHODIMP +XULDocumentImpl::SetTooltipElement(nsIDOMElement* anElement) +{ + mTooltipElement = dont_QueryInterface(anElement); + return NS_OK; +} + + NS_IMETHODIMP XULDocumentImpl::GetFocus(nsIDOMXULFocusTracker** aTracker) { @@ -3128,7 +3155,7 @@ XULDocumentImpl::CreatePopupDocument(nsIContent* aPopupElement, nsIDocument** aR popupDoc->mNameSpaceManager = mNameSpaceManager; // We share the mPopup - popupDoc->mPopup = mPopup; + popupDoc->mPopupElement = mPopupElement; // Suck all of the root's content into our document. // We need to make the XUL builder instantiate this node. diff --git a/rdf/content/src/nsXULPopupListener.cpp b/rdf/content/src/nsXULPopupListener.cpp index 9fb9805375a0..bc6f2483400a 100644 --- a/rdf/content/src/nsXULPopupListener.cpp +++ b/rdf/content/src/nsXULPopupListener.cpp @@ -34,6 +34,8 @@ #include "nsIDocument.h" #include "nsIContent.h" #include "nsIDOMUIEvent.h" +#include "nsITimer.h" + //////////////////////////////////////////////////////////////////////// @@ -41,10 +43,6 @@ static NS_DEFINE_IID(kXULPopupListenerCID, NS_XULPOPUPLISTENER_CID); static NS_DEFINE_IID(kIXULPopupListenerIID, NS_IXULPOPUPLISTENER_IID); static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); -static NS_DEFINE_IID(kIDomNodeIID, NS_IDOMNODE_IID); -static NS_DEFINE_IID(kIDomElementIID, NS_IDOMELEMENT_IID); -static NS_DEFINE_IID(kIDomEventListenerIID, NS_IDOMEVENTLISTENER_IID); - //////////////////////////////////////////////////////////////////////// // PopupListenerImpl // @@ -71,8 +69,8 @@ public: virtual nsresult MouseUp(nsIDOMEvent* aMouseEvent) { return NS_OK; }; virtual nsresult MouseClick(nsIDOMEvent* aMouseEvent) { return NS_OK; }; virtual nsresult MouseDblClick(nsIDOMEvent* aMouseEvent) { return NS_OK; }; - virtual nsresult MouseOver(nsIDOMEvent* aMouseEvent) { return NS_OK; }; - virtual nsresult MouseOut(nsIDOMEvent* aMouseEvent) { return NS_OK; }; + virtual nsresult MouseOver(nsIDOMEvent* aMouseEvent) ; + virtual nsresult MouseOut(nsIDOMEvent* aMouseEvent) ; // nsIDOMFocusListener virtual nsresult Focus(nsIDOMEvent* aEvent) { return NS_OK; }; @@ -82,16 +80,35 @@ public: virtual nsresult HandleEvent(nsIDOMEvent* anEvent) { return NS_OK; }; protected: + virtual nsresult LaunchPopup(nsIDOMEvent* anEvent); + virtual nsresult LaunchPopup( nsIDOMElement* aElement, PRInt32 aScreenX, PRInt32 aScreenY, + PRInt32 aClientX, PRInt32 aClientY ) ; + + nsresult FindDocumentForNode ( nsIDOMNode* inNode, nsIDOMXULDocument** outDoc ) ; private: - nsIDOMElement* element; // Weak reference. The element will go away first. + // |mElement| is the node to which this listener is attached. + nsIDOMElement* mElement; // Weak ref. The element will go away first. XULPopupType popupType; + nsCOMPtr mPopup; // The popup. We are responsible for making it go away. + + // The following members are not used unless |popupType| is tooltip. + + // a timer for determining if a tooltip should be displayed. + static void sTooltipCallback ( nsITimer *aTimer, void *aClosure ) ; + nsCOMPtr mTooltipTimer; + PRInt32 mMouseLocX, mMouseLocY; // mouse coordinates for tooltip event + // The node hovered over that fired the timer. This may turn into the node that + // triggered the tooltip, but only if the timer ever gets around to firing. + nsIDOMNode* mPossibleTooltipNode; // weak ref. + }; //////////////////////////////////////////////////////////////////////// XULPopupListenerImpl::XULPopupListenerImpl(void) + : mElement(nsnull), mPossibleTooltipNode(nsnull), mMouseLocX(0), mMouseLocY(0) { NS_INIT_REFCNT(); @@ -99,6 +116,11 @@ XULPopupListenerImpl::XULPopupListenerImpl(void) XULPopupListenerImpl::~XULPopupListenerImpl(void) { + //XXX do we need to close the popup here? Will we get the right events as + //XXX the topLevel window is going away when the closebox is pressed? + if ( mPopup ) + mPopup->Close(); + } NS_IMPL_ADDREF(XULPopupListenerImpl) @@ -126,7 +148,7 @@ XULPopupListenerImpl::QueryInterface(REFNSIID iid, void** result) NS_ADDREF_THIS(); return NS_OK; } - else if (iid.Equals(kIDomEventListenerIID)) { + else if (iid.Equals(nsIDOMEventListener::GetIID())) { *result = (nsIDOMEventListener*)(nsIDOMMouseListener*)this; NS_ADDREF_THIS(); return NS_OK; @@ -138,7 +160,7 @@ XULPopupListenerImpl::QueryInterface(REFNSIID iid, void** result) NS_IMETHODIMP XULPopupListenerImpl::Init(nsIDOMElement* aElement, const XULPopupType& popup) { - element = aElement; // Weak reference. Don't addref it. + mElement = aElement; // Weak reference. Don't addref it. popupType = popup; return NS_OK; } @@ -187,24 +209,186 @@ XULPopupListenerImpl::MouseDown(nsIDOMEvent* aMouseEvent) return NS_OK; } + +// +// MouseOver +// +// If we're a tooltip, fire off a timer to see if a tooltip should be shown. +// nsresult -XULPopupListenerImpl::LaunchPopup(nsIDOMEvent* anEvent) +XULPopupListenerImpl::MouseOver(nsIDOMEvent* aMouseEvent) +{ + nsresult rv = NS_OK; + + // make sure we're a tooltip. if not, bail. + if ( popupType != eXULPopupType_tooltip ) + return NS_OK; + + //XXX recognize when a popup is already up and immediately show the + //XXX tooltip for the new item if the dom element is different than + //XXX the element for which we are currently displaying the tip. + //XXX + //XXX for now, just be stupid to get things working. + + // Kill off an old timer and create a new one. + if ( mTooltipTimer ) { + mTooltipTimer->Cancel(); + mTooltipTimer = nsnull; + } + NS_NewTimer ( getter_AddRefs(mTooltipTimer) ); + if ( mTooltipTimer ) { + nsCOMPtr uiEvent ( do_QueryInterface(aMouseEvent) ); + if ( uiEvent ) { + // stash the coordinates of the event so that we can still get back to it from within the + // timer scallback. Also stash the node that started this so we can put it into the + // document later on (if the timer ever fires). + nsCOMPtr eventTarget; + aMouseEvent->GetTarget(getter_AddRefs(eventTarget)); + mPossibleTooltipNode = eventTarget.get(); +// BUG: 8598, widget and mouse coords not set for MouseOver events. +// uiEvent->GetScreenX(&mMouseLocX); +// uiEvent->GetScreenY(&mMouseLocY); + mMouseLocX = 50; mMouseLocY = 50; // XXX until bug 8598 fixed + mTooltipTimer->Init(sTooltipCallback, this, 1000); // one second delay + } + } + else + NS_WARNING ( "Could not create a timer for tooltip tracking" ); + + return NS_OK; + +} // MouseOver + + +// +// MouseOut +// +// If we're a tooltip, hide any tip that might be showing and remove any +// timer that is pending since the mouse is no longer over this area. +// +nsresult +XULPopupListenerImpl::MouseOut(nsIDOMEvent* aMouseEvent) +{ + // make sure we're a tooltip. if not, bail. + if ( popupType != eXULPopupType_tooltip ) + return NS_OK; + + if ( mTooltipTimer ) + mTooltipTimer->Cancel(); + + if ( mPopup ) { + mPopup->Close(); // hide the popup + mPopup = nsnull; // release the popup + + // clear out the tooltip node on the document + nsCOMPtr eventTarget; + aMouseEvent->GetTarget(getter_AddRefs(eventTarget)); + nsCOMPtr doc; + FindDocumentForNode ( eventTarget, getter_AddRefs(doc) ); + if ( doc ) + doc->SetTooltipElement(nsnull); + } + + return NS_OK; + +} // MouseOut + + +// +// FindDocumentForNode +// +// Given a DOM content node, finds the XUL document associated with it +// +nsresult +XULPopupListenerImpl :: FindDocumentForNode ( nsIDOMNode* inElement, nsIDOMXULDocument** outDoc ) +{ + nsresult rv = NS_OK; + + if ( !outDoc || !inElement ) + return NS_ERROR_INVALID_ARG; + + // get the document associated with this content element + nsCOMPtr document; + nsCOMPtr content = do_QueryInterface(inElement); + if (NS_FAILED(rv = content->GetDocument(*getter_AddRefs(document)))) { + NS_ERROR("Unable to retrieve the document."); + return rv; + } + + // Turn the document into a XUL document so we can use getElementById + nsCOMPtr xulDocument = do_QueryInterface(document); + if (xulDocument == nsnull) { + NS_ERROR("Popup attached to an element that isn't in XUL!"); + return NS_ERROR_FAILURE; + } + + *outDoc = xulDocument; + NS_ADDREF ( *outDoc ); + + return rv; + +} // FindDocumentForNode + + +// +// LaunchPopup +// +nsresult +XULPopupListenerImpl::LaunchPopup ( nsIDOMEvent* anEvent ) +{ + // Retrieve our x and y position. + nsCOMPtr uiEvent ( do_QueryInterface(anEvent) ); + if (!uiEvent) { + //non-ui event passed in. bad things. + return NS_OK; + } + + PRInt32 xPos, yPos; + uiEvent->GetScreenX(&xPos); + uiEvent->GetScreenY(&yPos); + + PRInt32 offsetX, offsetY; + uiEvent->GetClientX(&offsetX); + uiEvent->GetClientY(&offsetY); + + return LaunchPopup ( mElement, xPos, yPos, offsetX, offsetY ); +} + + +// +// LaunchPopup +// +// Given the element on which the event was triggered and the mouse locations in +// screen and widget coordinates, popup a new window showing the appropriate +// content. +// +// This looks for an attribute on |aElement| of the appropriate popup type +// (popup, context, tooltip) and uses that attribute's value as an ID for +// the popup content in the document. +// +nsresult +XULPopupListenerImpl::LaunchPopup( nsIDOMElement* aElement, PRInt32 aScreenX, PRInt32 aScreenY, + PRInt32 aOffsetX, PRInt32 aOffsetY ) { nsresult rv = NS_OK; nsAutoString type("popup"); - if (eXULPopupType_context == popupType) + if ( popupType == eXULPopupType_context ) type = "context"; + else if ( popupType == eXULPopupType_tooltip ) + type = "tooltip"; nsAutoString identifier; - element->GetAttribute(type, identifier); + mElement->GetAttribute(type, identifier); if (identifier == "") return rv; - // Try to find the popup content. + // Try to find the popup content and the document. We don't use FindDocumentForNode() + // in this case because we need the nsIDocument interface anyway for the script + // context. nsCOMPtr document; - nsCOMPtr content = do_QueryInterface(element); + nsCOMPtr content = do_QueryInterface(mElement); if (NS_FAILED(rv = content->GetDocument(*getter_AddRefs(document)))) { NS_ERROR("Unable to retrieve the document."); return rv; @@ -219,17 +403,15 @@ XULPopupListenerImpl::LaunchPopup(nsIDOMEvent* anEvent) // XXX Handle the _child case for popups and context menus! - // Use getElementById to obtain the popup content. + // Use getElementById to obtain the popup content and gracefully fail if + // we didn't find any popup content in the document. nsCOMPtr popupContent; if (NS_FAILED(rv = xulDocument->GetElementById(identifier, getter_AddRefs(popupContent)))) { NS_ERROR("GetElementById had some kind of spasm."); return rv; } - - if (popupContent == nsnull) { - // Gracefully fail in this case. + if ( !popupContent ) return NS_OK; - } // We have some popup content. Obtain our window. nsIScriptContextOwner* owner = document->GetScriptContextOwner(); @@ -242,42 +424,30 @@ XULPopupListenerImpl::LaunchPopup(nsIDOMEvent* anEvent) if (domWindow != nsnull) { // Find out if we're anchored. nsAutoString anchorAlignment("none"); - element->GetAttribute("popupanchor", anchorAlignment); + mElement->GetAttribute("popupanchor", anchorAlignment); nsAutoString popupAlignment("topleft"); - element->GetAttribute("popupalign", popupAlignment); + mElement->GetAttribute("popupalign", popupAlignment); - // Set the popup in the document for the duration of this call. - xulDocument->SetPopup(element); + // Set the popup in the document for the duration of this call. + xulDocument->SetPopupElement(mElement); - // Retrieve our x and y position. - nsCOMPtruiEvent; - uiEvent = do_QueryInterface(anEvent); - if (!uiEvent) { - //non-ui event passed in. bad things. - return NS_OK; - } - - PRInt32 xPos, yPos; - uiEvent->GetScreenX(&xPos); - uiEvent->GetScreenY(&yPos); - // If we're anchored, we pass in client/screen offsets so that - // we can translate the frames corners to screen coords. + // we can translate the frames corners to screen coords. + PRInt32 xPos = aScreenX, yPos = aScreenY; if (anchorAlignment != "none") { - PRInt32 offsetX, offsetY; - uiEvent->GetClientX(&offsetX); - uiEvent->GetClientY(&offsetY); - xPos = xPos-offsetX; - yPos = yPos-offsetY; + xPos -= aOffsetX; + yPos -= aOffsetY; } - - domWindow->CreatePopup(element, popupContent, - xPos, yPos, - type, anchorAlignment, popupAlignment); + domWindow->CreatePopup(mElement, popupContent, + xPos, yPos, + type, anchorAlignment, popupAlignment, + getter_AddRefs(mPopup)); + if ( popupType == eXULPopupType_popup && mPopup ) + mPopup->Focus(); // XXX For menus only, clear the document.popup field. - } + } NS_RELEASE(global); } } @@ -290,10 +460,12 @@ nsresult XULPopupListenerImpl::Blur(nsIDOMEvent* aMouseEvent) { nsresult rv = NS_OK; - + +#if 0 +// ONLY NEEDED BECAUSE HYATT WAS LAZY // Try to find the popup content. nsCOMPtr document; - nsCOMPtr content = do_QueryInterface(element); + nsCOMPtr content = do_QueryInterface(mElement); if (NS_FAILED(rv = content->GetDocument(*getter_AddRefs(document)))) { NS_ERROR("Unable to retrieve the document."); return rv; @@ -319,7 +491,20 @@ XULPopupListenerImpl::Blur(nsIDOMEvent* aMouseEvent) domWindow->Close(); } } +#endif + // Blur events don't bubble, so this means our window lost focus. + // Let's check just to make sure. + nsCOMPtr eventTarget; + aMouseEvent->GetTarget(getter_AddRefs(eventTarget)); + + // Close, but only if we are the same target. + nsCOMPtr windowNode = do_QueryInterface(mPopup); + if (windowNode.get() == eventTarget.get()) { + mPopup->Close(); + mPopup = nsnull; + } + // XXX Figure out how to fire the DESTROY event for the // arbitrary XUL case @@ -329,6 +514,40 @@ XULPopupListenerImpl::Blur(nsIDOMEvent* aMouseEvent) return rv; } + +// +// sTooltipCallback +// +// A timer callback, fired when the mouse has hovered inside of a frame for the +// appropriate amount of time. Getting to this point means that we should show the +// toolip. +// +// This relies on certain things being cached into the |aClosure| object passed to +// us by the timer: +// -- the x/y coordinates of the mouse +// -- the dom node the user hovered over +// +void +XULPopupListenerImpl :: sTooltipCallback (nsITimer *aTimer, void *aClosure) +{ + XULPopupListenerImpl* self = NS_STATIC_CAST(XULPopupListenerImpl*, aClosure); + if ( self ) { + // set the node in the document that triggered the tooltip and show it + nsCOMPtr doc; + self->FindDocumentForNode ( self->mPossibleTooltipNode, getter_AddRefs(doc) ); + if ( doc ) { + nsCOMPtr element ( do_QueryInterface(self->mPossibleTooltipNode) ); + if ( element ) { + doc->SetTooltipElement ( element ); + self->LaunchPopup ( element, self->mMouseLocX, self->mMouseLocY, 0, 0 ); + } + } // if document + } // if "self" data valid + +} // sTimerCallback + + + //////////////////////////////////////////////////////////////// nsresult NS_NewXULPopupListener(nsIXULPopupListener** pop) diff --git a/webshell/public/nsIWebShell.h b/webshell/public/nsIWebShell.h index dd46adf4573e..77f9b42bb65f 100644 --- a/webshell/public/nsIWebShell.h +++ b/webshell/public/nsIWebShell.h @@ -111,7 +111,7 @@ public: PRInt32 aXPos, PRInt32 aYPos, const nsString& aPopupType, const nsString& anAnchorAlignment, const nsString& aPopupAlignment, - nsIDOMWindow* aWindow) = 0; + nsIDOMWindow* aWindow, nsIDOMWindow** outPopup) = 0; /** * Notify the WebShellContainer that a contained webshell is diff --git a/webshell/src/nsWebShell.cpp b/webshell/src/nsWebShell.cpp index 6f90cffc07a9..58fde3d49577 100644 --- a/webshell/src/nsWebShell.cpp +++ b/webshell/src/nsWebShell.cpp @@ -266,7 +266,7 @@ public: PRInt32 aXPos, PRInt32 aYPos, const nsString& aPopupType, const nsString& anAnchorAlignment, const nsString& aPopupAlignment, - nsIDOMWindow* aWindow); + nsIDOMWindow* aWindow, nsIDOMWindow** outPopup); NS_IMETHOD FindWebShellWithName(const PRUnichar* aName, nsIWebShell*& aResult); NS_IMETHOD FocusAvailable(nsIWebShell* aFocusedWebShell, PRBool& aFocusTaken); @@ -2198,12 +2198,12 @@ nsWebShell::CreatePopup(nsIDOMElement* aElement, nsIDOMElement* aPopupContent, PRInt32 aXPos, PRInt32 aYPos, const nsString& aPopupType, const nsString& anAnchorAlignment, const nsString& aPopupAlignment, - nsIDOMWindow* aWindow) + nsIDOMWindow* aWindow, nsIDOMWindow** outPopup) { if (nsnull != mContainer) { return mContainer->CreatePopup(aElement, aPopupContent, aXPos, aYPos, aPopupType, anAnchorAlignment, aPopupAlignment, - aWindow); + aWindow, outPopup); } return NS_OK; } diff --git a/webshell/tests/viewer/nsBrowserWindow.cpp b/webshell/tests/viewer/nsBrowserWindow.cpp index d04588356f6a..971e8f56b49e 100644 --- a/webshell/tests/viewer/nsBrowserWindow.cpp +++ b/webshell/tests/viewer/nsBrowserWindow.cpp @@ -1807,7 +1807,7 @@ nsBrowserWindow::CreatePopup(nsIDOMElement* aElement, nsIDOMElement* aPopupConte PRInt32 aXPos, PRInt32 aYPos, const nsString& aPopupType, const nsString& anAnchorAlignment, const nsString& aPopupAlignment, - nsIDOMWindow* aWindow) + nsIDOMWindow* aWindow, nsIDOMWindow** outPopup) { return NS_OK; } diff --git a/webshell/tests/viewer/nsBrowserWindow.h b/webshell/tests/viewer/nsBrowserWindow.h index bb9d8cf2a4cb..0e9fe2aad86a 100644 --- a/webshell/tests/viewer/nsBrowserWindow.h +++ b/webshell/tests/viewer/nsBrowserWindow.h @@ -137,7 +137,7 @@ public: PRInt32 aXPos, PRInt32 aYPos, const nsString& aPopupType, const nsString& anAnchorAlignment, const nsString& aPopupAlignment, - nsIDOMWindow* aWindow); + nsIDOMWindow* aWindow, nsIDOMWindow** outPopup); NS_IMETHOD FindWebShellWithName(const PRUnichar* aName, nsIWebShell*& aResult); NS_IMETHOD FocusAvailable(nsIWebShell* aFocusedWebShell, PRBool& aFocusTaken); diff --git a/webshell/tests/viewer/nsXPBaseWindow.cpp b/webshell/tests/viewer/nsXPBaseWindow.cpp index bb88f2dca5b6..4976e0800819 100644 --- a/webshell/tests/viewer/nsXPBaseWindow.cpp +++ b/webshell/tests/viewer/nsXPBaseWindow.cpp @@ -575,7 +575,7 @@ nsXPBaseWindow::CreatePopup(nsIDOMElement* aElement, nsIDOMElement* aPopupConten PRInt32 aXPos, PRInt32 aYPos, const nsString& aPopupType, const nsString& anAnchorAlignment, const nsString& aPopupAlignment, - nsIDOMWindow* aWindow) + nsIDOMWindow* aWindow, nsIDOMWindow** outPopup) { return NS_OK; } diff --git a/webshell/tests/viewer/nsXPBaseWindow.h b/webshell/tests/viewer/nsXPBaseWindow.h index d0630b4cab6b..da09fb73d838 100644 --- a/webshell/tests/viewer/nsXPBaseWindow.h +++ b/webshell/tests/viewer/nsXPBaseWindow.h @@ -118,7 +118,7 @@ public: PRInt32 aXPos, PRInt32 aYPos, const nsString& aPopupType, const nsString& anAnchorAlignment, const nsString& aPopupAlignment, - nsIDOMWindow* aWindow); + nsIDOMWindow* aWindow, nsIDOMWindow** outPopup); NS_IMETHOD FindWebShellWithName(const PRUnichar* aName, nsIWebShell*& aResult); NS_IMETHOD FocusAvailable(nsIWebShell* aFocusedWebShell, PRBool& aFocusTaken); diff --git a/xpfe/appshell/src/nsWebShellWindow.cpp b/xpfe/appshell/src/nsWebShellWindow.cpp index fb6ff3106fdf..3f4d55f2c370 100644 --- a/xpfe/appshell/src/nsWebShellWindow.cpp +++ b/xpfe/appshell/src/nsWebShellWindow.cpp @@ -1004,9 +1004,17 @@ nsWebShellWindow::CreatePopup(nsIDOMElement* aElement, nsIDOMElement* aPopupCont PRInt32 aXPos, PRInt32 aYPos, const nsString& aPopupType, const nsString& anAnchorAlignment, const nsString& aPopupAlignment, - nsIDOMWindow* aWindow) + nsIDOMWindow* aWindow, nsIDOMWindow** outPopup) { nsresult rv = NS_OK; + + // clear out result param up front. It's an error if a legal place to + // stick the result isn't provided. + if ( !outPopup ) { + NS_ERROR ( "Invalid param -- need to provide a place for result" ); + return NS_ERROR_INVALID_ARG; + } + *outPopup = nsnull; nsCOMPtr contentViewerContainer; contentViewerContainer = do_QueryInterface(mWebShell); @@ -1082,6 +1090,8 @@ nsWebShellWindow::CreatePopup(nsIDOMElement* aElement, nsIDOMElement* aPopupCont } nsCOMPtr popupContent = do_QueryInterface(aPopupContent); + if ( !popupContent ) + return NS_OK; // It's ok. Really. // Fire the CONSTRUCT DOM event to give JS/C++ a chance to build the popup // dynamically. @@ -1090,7 +1100,7 @@ nsWebShellWindow::CreatePopup(nsIDOMElement* aElement, nsIDOMElement* aPopupCont event.eventStructType = NS_EVENT; event.message = NS_POPUP_CONSTRUCT; rv = popupContent->HandleDOMEvent(*presContext, &event, nsnull, NS_EVENT_FLAG_INIT, status); - if (rv != NS_OK) + if ( NS_FAILED(rv) ) return rv; // Find out if we're a menu. @@ -1103,10 +1113,9 @@ nsWebShellWindow::CreatePopup(nsIDOMElement* aElement, nsIDOMElement* aPopupCont if (NS_FAILED(popupContent->ChildAt(0, *getter_AddRefs(rootContent)))) return NS_OK; // Doesn't matter. Don't report it. - nsCOMPtr rootElement = do_QueryInterface(rootContent); - nsString tagName; - if (NS_FAILED(rootElement->GetTagName(tagName))) + nsCOMPtr rootElement = do_QueryInterface(rootContent); + if ( !rootElement || NS_FAILED(rootElement->GetTagName(tagName))) return NS_OK; // It's ok. Really. if (tagName == "menu") { @@ -1223,16 +1232,18 @@ nsWebShellWindow::CreatePopup(nsIDOMElement* aElement, nsIDOMElement* aPopupCont // (8) Set up the opener property domWindow->SetOpener(aWindow); - // (9) Show the window, and give the window the focus. + // (9) Show the window. Don't give the focus yet because we may not want to. + // For example, popup windows want focus, but tooltips do not. newWindow->Show(PR_TRUE); - domWindow->Focus(); // (10) Do some layout. nsCOMPtr popupChild = do_QueryInterface(popupDocument); popupChild->LayoutPopupDocument(); - // XXX Do we return the popup document? Might want to, since it's kind of like - // a sick and twisted distortion of a window.open call. + // return the popup. + *outPopup = domWindow; + NS_ADDREF(*outPopup); + return rv; } diff --git a/xpfe/appshell/src/nsWebShellWindow.h b/xpfe/appshell/src/nsWebShellWindow.h index 6e88bda47653..15c50c6640df 100644 --- a/xpfe/appshell/src/nsWebShellWindow.h +++ b/xpfe/appshell/src/nsWebShellWindow.h @@ -88,7 +88,7 @@ public: PRInt32 aXPos, PRInt32 aYPos, const nsString& aPopupType, const nsString& anAnchorAlignment, const nsString& aPopupAlignment, - nsIDOMWindow* aWindow); + nsIDOMWindow* aWindow, nsIDOMWindow** outPopup); NS_IMETHOD ContentShellAdded(nsIWebShell* aChildShell, nsIContent* frameNode);