зеркало из https://github.com/mozilla/pjs.git
Bug 279703, backing out the popup changes due to performance regressions. sigh.
This commit is contained in:
Родитель
73453f5971
Коммит
d6cdd07569
|
@ -62,7 +62,6 @@
|
|||
#include "nsIEventListenerManager.h"
|
||||
#include "nsIFocusController.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIMenuFrame.h"
|
||||
#include "nsIHTMLDocument.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsIMenuParent.h"
|
||||
|
@ -802,23 +801,22 @@ nsresult nsRootAccessible::HandleEventWithTarget(nsIDOMEvent* aEvent,
|
|||
}
|
||||
else if (eventType.EqualsLiteral("DOMMenuItemActive")) {
|
||||
if (!treeItemAccessible) {
|
||||
nsCOMPtr<nsPIAccessNode> menuAccessNode = do_QueryInterface(accessible);
|
||||
NS_ENSURE_TRUE(menuAccessNode, NS_ERROR_FAILURE);
|
||||
nsIFrame* menuFrame = menuAccessNode->GetFrame();
|
||||
NS_ENSURE_TRUE(menuFrame, NS_ERROR_FAILURE);
|
||||
nsIMenuFrame* imenuFrame;
|
||||
CallQueryInterface(menuFrame, &imenuFrame);
|
||||
NS_ENSURE_TRUE(imenuFrame, NS_ERROR_FAILURE);
|
||||
if (imenuFrame->IsOnMenuBar()) {
|
||||
if (!imenuFrame->IsOnActiveMenuBar()) {
|
||||
nsCOMPtr<nsIAccessible> containerAccessible;
|
||||
accessible->GetParent(getter_AddRefs(containerAccessible));
|
||||
NS_ENSURE_TRUE(containerAccessible, NS_OK);
|
||||
if (Role(containerAccessible) == nsIAccessibleRole::ROLE_MENUBAR) {
|
||||
nsCOMPtr<nsPIAccessNode> menuBarAccessNode(do_QueryInterface(containerAccessible));
|
||||
NS_ENSURE_TRUE(menuBarAccessNode, NS_ERROR_FAILURE);
|
||||
nsCOMPtr<nsIMenuParent> menuParent = do_QueryInterface(menuBarAccessNode->GetFrame());
|
||||
NS_ENSURE_TRUE(menuParent, NS_ERROR_FAILURE);
|
||||
PRBool isActive;
|
||||
menuParent->GetIsActive(isActive);
|
||||
if (!isActive) {
|
||||
// It is a top level menuitem. Only fire a focus event when the menu bar
|
||||
// is active.
|
||||
return NS_OK;
|
||||
}
|
||||
} else {
|
||||
nsCOMPtr<nsIAccessible> containerAccessible;
|
||||
accessible->GetParent(getter_AddRefs(containerAccessible));
|
||||
NS_ENSURE_TRUE(containerAccessible, NS_ERROR_FAILURE);
|
||||
// It is not top level menuitem
|
||||
// Only fire focus event if it is not inside collapsed popup
|
||||
if (State(containerAccessible) & nsIAccessibleStates::STATE_COLLAPSED)
|
||||
|
|
|
@ -107,7 +107,7 @@
|
|||
</hbox>
|
||||
</tooltip>
|
||||
|
||||
<panel type="autocomplete" chromedir="&locale.dir;" id="PopupAutoComplete"/>
|
||||
<popup type="autocomplete" chromedir="&locale.dir;" id="PopupAutoComplete"/>
|
||||
|
||||
<popup id="toolbar-context-menu"
|
||||
onpopupshowing="onViewToolbarsPopupShowing(event);">
|
||||
|
|
|
@ -3682,7 +3682,6 @@ nsDocument::GetBoxObjectFor(nsIDOMElement* aElement, nsIBoxObject** aResult)
|
|||
contractID += "-menu";
|
||||
else if (tag == nsGkAtoms::popup ||
|
||||
tag == nsGkAtoms::menupopup ||
|
||||
tag == nsGkAtoms::panel ||
|
||||
tag == nsGkAtoms::tooltip)
|
||||
contractID += "-popup";
|
||||
else if (tag == nsGkAtoms::tree)
|
||||
|
|
|
@ -107,6 +107,7 @@
|
|||
#include "nsIViewManager.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsIXULDocument.h"
|
||||
#include "nsIXULPopupListener.h"
|
||||
#include "nsIXULTemplateBuilder.h"
|
||||
#include "nsIXBLService.h"
|
||||
#include "nsLayoutCID.h"
|
||||
|
@ -118,7 +119,6 @@
|
|||
#include "nsIBoxObject.h"
|
||||
#include "nsPIBoxObject.h"
|
||||
#include "nsXULDocument.h"
|
||||
#include "nsXULPopupListener.h"
|
||||
#include "nsRuleWalker.h"
|
||||
#include "nsIDOMViewCSS.h"
|
||||
#include "nsIDOMCSSStyleDeclaration.h"
|
||||
|
@ -2047,17 +2047,18 @@ static void
|
|||
PopupListenerPropertyDtor(void* aObject, nsIAtom* aPropertyName,
|
||||
void* aPropertyValue, void* aData)
|
||||
{
|
||||
nsIDOMEventListener* listener =
|
||||
NS_STATIC_CAST(nsIDOMEventListener*, aPropertyValue);
|
||||
nsIXULPopupListener* listener =
|
||||
NS_STATIC_CAST(nsIXULPopupListener*, aPropertyValue);
|
||||
if (!listener) {
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIDOMEventListener> eventListener = do_QueryInterface(listener);
|
||||
nsCOMPtr<nsIDOMEventTarget> target =
|
||||
do_QueryInterface(NS_STATIC_CAST(nsINode*, aObject));
|
||||
if (target) {
|
||||
target->RemoveEventListener(NS_LITERAL_STRING("mousedown"), listener,
|
||||
target->RemoveEventListener(NS_LITERAL_STRING("mousedown"), eventListener,
|
||||
PR_FALSE);
|
||||
target->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), listener,
|
||||
target->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), eventListener,
|
||||
PR_FALSE);
|
||||
}
|
||||
NS_RELEASE(listener);
|
||||
|
@ -2066,38 +2067,43 @@ PopupListenerPropertyDtor(void* aObject, nsIAtom* aPropertyName,
|
|||
nsresult
|
||||
nsXULElement::AddPopupListener(nsIAtom* aName)
|
||||
{
|
||||
// Add a popup listener to the element
|
||||
PRBool isContext = (aName == nsGkAtoms::context ||
|
||||
aName == nsGkAtoms::contextmenu);
|
||||
nsIAtom* listenerAtom = isContext ?
|
||||
nsGkAtoms::contextmenulistener :
|
||||
nsGkAtoms::popuplistener;
|
||||
XULPopupType popupType;
|
||||
nsCOMPtr<nsIAtom> listenerAtom;
|
||||
if (aName == nsGkAtoms::context || aName == nsGkAtoms::contextmenu) {
|
||||
popupType = eXULPopupType_context;
|
||||
listenerAtom = nsGkAtoms::contextmenulistener;
|
||||
} else {
|
||||
popupType = eXULPopupType_popup;
|
||||
listenerAtom = nsGkAtoms::popuplistener;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMEventListener> popupListener =
|
||||
NS_STATIC_CAST(nsIDOMEventListener*, GetProperty(listenerAtom));
|
||||
nsCOMPtr<nsIXULPopupListener> popupListener =
|
||||
NS_STATIC_CAST(nsIXULPopupListener*, GetProperty(listenerAtom));
|
||||
if (popupListener) {
|
||||
// Popup listener is already installed.
|
||||
return NS_OK;
|
||||
}
|
||||
// Add a popup listener to the element
|
||||
nsresult rv;
|
||||
|
||||
nsresult rv = NS_NewXULPopupListener(this, isContext,
|
||||
getter_AddRefs(popupListener));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
popupListener = do_CreateInstance(kXULPopupListenerCID, &rv);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Unable to create an instance of the popup listener object.");
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Add a weak reference to the node.
|
||||
popupListener->Init(this, popupType);
|
||||
|
||||
// Add the popup as a listener on this element.
|
||||
nsCOMPtr<nsIDOMEventListener> eventListener = do_QueryInterface(popupListener);
|
||||
nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(NS_STATIC_CAST(nsIContent *, this)));
|
||||
NS_ENSURE_TRUE(target, NS_ERROR_FAILURE);
|
||||
rv = SetProperty(listenerAtom, popupListener, PopupListenerPropertyDtor,
|
||||
PR_TRUE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// Want the property to have a reference to the listener.
|
||||
nsIDOMEventListener* listener = nsnull;
|
||||
popupListener.swap(listener);
|
||||
if (isContext)
|
||||
target->AddEventListener(NS_LITERAL_STRING("contextmenu"), listener, PR_FALSE);
|
||||
else
|
||||
target->AddEventListener(NS_LITERAL_STRING("mousedown"), listener, PR_FALSE);
|
||||
nsIXULPopupListener* listener = popupListener;
|
||||
NS_ADDREF(listener);
|
||||
target->AddEventListener(NS_LITERAL_STRING("mousedown"), eventListener, PR_FALSE);
|
||||
target->AddEventListener(NS_LITERAL_STRING("contextmenu"), eventListener, PR_FALSE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,6 @@
|
|||
tracks xul popups and context menus
|
||||
*/
|
||||
|
||||
#include "nsXULPopupListener.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsIDOMElement.h"
|
||||
|
@ -52,23 +51,27 @@
|
|||
#include "nsIDOMNodeList.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDOMDocumentXBL.h"
|
||||
#include "nsIXULPopupListener.h"
|
||||
#include "nsIDOMMouseListener.h"
|
||||
#include "nsIDOMContextMenuListener.h"
|
||||
#include "nsContentCID.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsXULPopupManager.h"
|
||||
|
||||
#include "nsIScriptContext.h"
|
||||
#include "nsIDOMWindowInternal.h"
|
||||
#include "nsIDOMXULDocument.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIDOMMouseEvent.h"
|
||||
#include "nsIDOMNSUIEvent.h"
|
||||
#include "nsIDOMEventTarget.h"
|
||||
#include "nsIDOMNSEvent.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsFrameManager.h"
|
||||
#include "nsHTMLReflowState.h"
|
||||
|
||||
#include "nsIBoxObject.h"
|
||||
#include "nsIPopupBoxObject.h"
|
||||
|
||||
// for event firing in context menus
|
||||
#include "nsPresContext.h"
|
||||
|
@ -76,8 +79,9 @@
|
|||
#include "nsIEventStateManager.h"
|
||||
#include "nsIFocusController.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsIViewManager.h"
|
||||
#include "nsDOMError.h"
|
||||
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIMenuFrame.h"
|
||||
|
||||
// on win32 and os/2, context menus come up on mouse up. On other platforms,
|
||||
|
@ -86,49 +90,124 @@
|
|||
#define NS_CONTEXT_MENU_IS_MOUSEUP 1
|
||||
#endif
|
||||
|
||||
nsXULPopupListener::nsXULPopupListener(nsIDOMElement *aElement, PRBool aIsContext)
|
||||
: mElement(aElement), mPopupContent(nsnull), mIsContext(aIsContext)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// PopupListenerImpl
|
||||
//
|
||||
// This is the popup listener implementation for popup menus and context menus.
|
||||
//
|
||||
class XULPopupListenerImpl : public nsIXULPopupListener,
|
||||
public nsIDOMMouseListener,
|
||||
public nsIDOMContextMenuListener
|
||||
{
|
||||
public:
|
||||
XULPopupListenerImpl(void);
|
||||
virtual ~XULPopupListenerImpl(void);
|
||||
|
||||
public:
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIXULPopupListener
|
||||
NS_IMETHOD Init(nsIDOMElement* aElement, const XULPopupType& popupType);
|
||||
|
||||
// nsIDOMMouseListener
|
||||
NS_IMETHOD MouseDown(nsIDOMEvent* aMouseEvent);
|
||||
NS_IMETHOD MouseUp(nsIDOMEvent* aMouseEvent) { return NS_OK; }
|
||||
NS_IMETHOD MouseClick(nsIDOMEvent* aMouseEvent) { return NS_OK; }
|
||||
NS_IMETHOD MouseDblClick(nsIDOMEvent* aMouseEvent) { return NS_OK; }
|
||||
NS_IMETHOD MouseOver(nsIDOMEvent* aMouseEvent) { return NS_OK; }
|
||||
NS_IMETHOD MouseOut(nsIDOMEvent* aMouseEvent) { return NS_OK; }
|
||||
|
||||
// nsIDOMContextMenuListener
|
||||
NS_IMETHOD ContextMenu(nsIDOMEvent* aContextMenuEvent);
|
||||
|
||||
// nsIDOMEventListener
|
||||
NS_IMETHOD HandleEvent(nsIDOMEvent* anEvent) { return NS_OK; }
|
||||
|
||||
protected:
|
||||
|
||||
virtual nsresult LaunchPopup(nsIDOMEvent* anEvent);
|
||||
virtual nsresult LaunchPopup(PRInt32 aClientX, PRInt32 aClientY) ;
|
||||
|
||||
private:
|
||||
|
||||
nsresult PreLaunchPopup(nsIDOMEvent* aMouseEvent);
|
||||
nsresult FireFocusOnTargetContent(nsIDOMNode* aTargetNode);
|
||||
|
||||
// |mElement| is the node to which this listener is attached.
|
||||
nsIDOMElement* mElement; // Weak ref. The element will go away first.
|
||||
|
||||
// The popup that is getting shown on top of mElement.
|
||||
nsCOMPtr<nsIPopupBoxObject> mPopup;
|
||||
|
||||
// The type of the popup
|
||||
XULPopupType popupType;
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
XULPopupListenerImpl::XULPopupListenerImpl(void)
|
||||
: mElement(nsnull)
|
||||
{
|
||||
}
|
||||
|
||||
nsXULPopupListener::~nsXULPopupListener(void)
|
||||
XULPopupListenerImpl::~XULPopupListenerImpl(void)
|
||||
{
|
||||
ClosePopup();
|
||||
if (mPopup) {
|
||||
mPopup->HidePopup();
|
||||
}
|
||||
|
||||
#ifdef DEBUG_REFS
|
||||
--gInstanceCount;
|
||||
fprintf(stdout, "%d - RDF: XULPopupListenerImpl\n", gInstanceCount);
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(nsXULPopupListener)
|
||||
NS_IMPL_RELEASE(nsXULPopupListener)
|
||||
NS_IMPL_ADDREF(XULPopupListenerImpl)
|
||||
NS_IMPL_RELEASE(XULPopupListenerImpl)
|
||||
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsXULPopupListener)
|
||||
NS_INTERFACE_MAP_BEGIN(XULPopupListenerImpl)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIXULPopupListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMMouseListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMContextMenuListener)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEventListener, nsIDOMMouseListener)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULPopupListener)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMETHODIMP
|
||||
XULPopupListenerImpl::Init(nsIDOMElement* aElement, const XULPopupType& popup)
|
||||
{
|
||||
mElement = aElement; // Weak reference. Don't addref it.
|
||||
popupType = popup;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// nsIDOMMouseListener
|
||||
|
||||
nsresult
|
||||
nsXULPopupListener::MouseDown(nsIDOMEvent* aMouseEvent)
|
||||
XULPopupListenerImpl::MouseDown(nsIDOMEvent* aMouseEvent)
|
||||
{
|
||||
if(!mIsContext)
|
||||
if(popupType != eXULPopupType_context)
|
||||
return PreLaunchPopup(aMouseEvent);
|
||||
else
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXULPopupListener::ContextMenu(nsIDOMEvent* aMouseEvent)
|
||||
XULPopupListenerImpl::ContextMenu(nsIDOMEvent* aMouseEvent)
|
||||
{
|
||||
if(mIsContext)
|
||||
if(popupType == eXULPopupType_context)
|
||||
return PreLaunchPopup(aMouseEvent);
|
||||
else
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXULPopupListener::PreLaunchPopup(nsIDOMEvent* aMouseEvent)
|
||||
XULPopupListenerImpl::PreLaunchPopup(nsIDOMEvent* aMouseEvent)
|
||||
{
|
||||
PRUint16 button;
|
||||
|
||||
|
@ -151,7 +230,7 @@ nsXULPopupListener::PreLaunchPopup(nsIDOMEvent* aMouseEvent)
|
|||
mouseEvent->GetTarget(getter_AddRefs(target));
|
||||
nsCOMPtr<nsIDOMNode> targetNode = do_QueryInterface(target);
|
||||
|
||||
if (!targetNode && mIsContext) {
|
||||
if (!targetNode && popupType == eXULPopupType_context) {
|
||||
// Not a DOM node, see if it's the DOM window (bug 380818).
|
||||
nsCOMPtr<nsIDOMWindow> domWin = do_QueryInterface(target);
|
||||
if (!domWin) {
|
||||
|
@ -171,7 +250,7 @@ nsXULPopupListener::PreLaunchPopup(nsIDOMEvent* aMouseEvent)
|
|||
|
||||
PRBool preventDefault;
|
||||
nsUIEvent->GetPreventDefault(&preventDefault);
|
||||
if (preventDefault && targetNode && mIsContext) {
|
||||
if (preventDefault && targetNode && popupType == eXULPopupType_context) {
|
||||
// Someone called preventDefault on a context menu.
|
||||
// Let's make sure they are allowed to do so.
|
||||
PRBool eventEnabled =
|
||||
|
@ -199,13 +278,13 @@ nsXULPopupListener::PreLaunchPopup(nsIDOMEvent* aMouseEvent)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// prevent popups on menu and menuitems as they handle their own popups
|
||||
// This was added for bug 96920.
|
||||
// This is a gross hack to deal with a recursive popup situation happening in AIM code.
|
||||
// See http://bugzilla.mozilla.org/show_bug.cgi?id=96920.
|
||||
// If a menu item child was clicked on that leads to a popup needing
|
||||
// to show, we know (guaranteed) that we're dealing with a menu or
|
||||
// submenu of an already-showing popup. We don't need to do anything at all.
|
||||
if (popupType == eXULPopupType_popup) {
|
||||
nsCOMPtr<nsIContent> targetContent = do_QueryInterface(target);
|
||||
if (!mIsContext) {
|
||||
nsIAtom *tag = targetContent ? targetContent->Tag() : nsnull;
|
||||
if (tag == nsGkAtoms::menu || tag == nsGkAtoms::menuitem)
|
||||
return NS_OK;
|
||||
|
@ -216,38 +295,48 @@ nsXULPopupListener::PreLaunchPopup(nsIDOMEvent* aMouseEvent)
|
|||
|
||||
// Turn the document into a XUL document so we can use SetPopupNode.
|
||||
nsCOMPtr<nsIDOMXULDocument> xulDocument = do_QueryInterface(content->GetDocument());
|
||||
if (!xulDocument)
|
||||
if (!xulDocument) {
|
||||
NS_ERROR("Popup attached to an element that isn't in XUL!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Store clicked-on node in xul document for context menus and menu popups.
|
||||
xulDocument->SetPopupNode(targetNode);
|
||||
// CLEAR THE POPUP EVENT BEFORE THIS FUNCTION EXITS
|
||||
xulDocument->SetPopupNode( targetNode );
|
||||
xulDocument->SetTrustedPopupEvent( aMouseEvent );
|
||||
|
||||
nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aMouseEvent));
|
||||
|
||||
if (mIsContext) {
|
||||
switch (popupType) {
|
||||
case eXULPopupType_popup:
|
||||
// Check for left mouse button down
|
||||
mouseEvent->GetButton(&button);
|
||||
if (button == 0) {
|
||||
// Time to launch a popup menu.
|
||||
LaunchPopup(aMouseEvent);
|
||||
aMouseEvent->StopPropagation();
|
||||
aMouseEvent->PreventDefault();
|
||||
}
|
||||
break;
|
||||
case eXULPopupType_context:
|
||||
|
||||
// Time to launch a context menu
|
||||
#ifndef NS_CONTEXT_MENU_IS_MOUSEUP
|
||||
// If the context menu launches on mousedown,
|
||||
// we have to fire focus on the content we clicked on
|
||||
FireFocusOnTargetContent(targetNode);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
// Only open popups when the left mouse button is down.
|
||||
mouseEvent->GetButton(&button);
|
||||
if (button != 0)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Open the popup and cancel the default handling of the event.
|
||||
LaunchPopup(aMouseEvent, targetContent);
|
||||
LaunchPopup(aMouseEvent);
|
||||
aMouseEvent->StopPropagation();
|
||||
aMouseEvent->PreventDefault();
|
||||
|
||||
break;
|
||||
}
|
||||
xulDocument->SetTrustedPopupEvent(nsnull);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXULPopupListener::FireFocusOnTargetContent(nsIDOMNode* aTargetNode)
|
||||
XULPopupListenerImpl::FireFocusOnTargetContent(nsIDOMNode* aTargetNode)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMDocument> domDoc;
|
||||
|
@ -319,25 +408,26 @@ nsXULPopupListener::FireFocusOnTargetContent(nsIDOMNode* aTargetNode)
|
|||
return rv;
|
||||
}
|
||||
|
||||
// ClosePopup
|
||||
//
|
||||
// Do everything needed to shut down the popup.
|
||||
// LaunchPopup
|
||||
//
|
||||
// NOTE: This routine is safe to call even if the popup is already closed.
|
||||
//
|
||||
void
|
||||
nsXULPopupListener::ClosePopup()
|
||||
nsresult
|
||||
XULPopupListenerImpl::LaunchPopup ( nsIDOMEvent* anEvent )
|
||||
{
|
||||
if (mPopupContent) {
|
||||
// this is called when the listener is going away, so make sure that the
|
||||
// popup is hidden. Use asynchronous hiding just to be safe so we don't
|
||||
// fire events during destruction.
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (pm)
|
||||
pm->HidePopup(mPopupContent, PR_FALSE, PR_TRUE, PR_TRUE);
|
||||
mPopupContent = nsnull; // release the popup
|
||||
// Retrieve our x and y position.
|
||||
nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(anEvent) );
|
||||
if (!mouseEvent) {
|
||||
//non-ui event passed in. bad things.
|
||||
return NS_OK;
|
||||
}
|
||||
} // ClosePopup
|
||||
|
||||
PRInt32 xPos, yPos;
|
||||
mouseEvent->GetClientX(&xPos);
|
||||
mouseEvent->GetClientY(&yPos);
|
||||
|
||||
return LaunchPopup(xPos, yPos);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
GetImmediateChild(nsIContent* aContent, nsIAtom *aTag, nsIContent** aResult)
|
||||
|
@ -356,6 +446,53 @@ GetImmediateChild(nsIContent* aContent, nsIAtom *aTag, nsIContent** aResult)
|
|||
return;
|
||||
}
|
||||
|
||||
static void ConvertPosition(nsIDOMElement* aPopupElt, nsString& aAnchor, nsString& aAlign, PRInt32& aY)
|
||||
{
|
||||
nsAutoString position;
|
||||
aPopupElt->GetAttribute(NS_LITERAL_STRING("position"), position);
|
||||
if (position.IsEmpty())
|
||||
return;
|
||||
|
||||
if (position.EqualsLiteral("before_start")) {
|
||||
aAnchor.AssignLiteral("topleft");
|
||||
aAlign.AssignLiteral("bottomleft");
|
||||
}
|
||||
else if (position.EqualsLiteral("before_end")) {
|
||||
aAnchor.AssignLiteral("topright");
|
||||
aAlign.AssignLiteral("bottomright");
|
||||
}
|
||||
else if (position.EqualsLiteral("after_start")) {
|
||||
aAnchor.AssignLiteral("bottomleft");
|
||||
aAlign.AssignLiteral("topleft");
|
||||
}
|
||||
else if (position.EqualsLiteral("after_end")) {
|
||||
aAnchor.AssignLiteral("bottomright");
|
||||
aAlign.AssignLiteral("topright");
|
||||
}
|
||||
else if (position.EqualsLiteral("start_before")) {
|
||||
aAnchor.AssignLiteral("topleft");
|
||||
aAlign.AssignLiteral("topright");
|
||||
}
|
||||
else if (position.EqualsLiteral("start_after")) {
|
||||
aAnchor.AssignLiteral("bottomleft");
|
||||
aAlign.AssignLiteral("bottomright");
|
||||
}
|
||||
else if (position.EqualsLiteral("end_before")) {
|
||||
aAnchor.AssignLiteral("topright");
|
||||
aAlign.AssignLiteral("topleft");
|
||||
}
|
||||
else if (position.EqualsLiteral("end_after")) {
|
||||
aAnchor.AssignLiteral("bottomright");
|
||||
aAlign.AssignLiteral("bottomleft");
|
||||
}
|
||||
else if (position.EqualsLiteral("overlap")) {
|
||||
aAnchor.AssignLiteral("topleft");
|
||||
aAlign.AssignLiteral("topleft");
|
||||
}
|
||||
else if (position.EqualsLiteral("after_pointer"))
|
||||
aY += 21;
|
||||
}
|
||||
|
||||
//
|
||||
// LaunchPopup
|
||||
//
|
||||
|
@ -363,23 +500,26 @@ GetImmediateChild(nsIContent* aContent, nsIAtom *aTag, nsIContent** aResult)
|
|||
// Client and widget coordinates, popup a new window showing the appropriate
|
||||
// content.
|
||||
//
|
||||
// aTargetContent is the target of the mouse event aEvent that triggered the
|
||||
// popup. mElement is the element that the popup menu is attached to. The
|
||||
// former may be equal to mElement or it may be a descendant.
|
||||
//
|
||||
// This looks for an attribute on |mElement| of the appropriate popup type
|
||||
// This looks for an attribute on |aElement| of the appropriate popup type
|
||||
// (popup, context) and uses that attribute's value as an ID for
|
||||
// the popup content in the document.
|
||||
//
|
||||
nsresult
|
||||
nsXULPopupListener::LaunchPopup(nsIDOMEvent* aEvent, nsIContent* aTargetContent)
|
||||
XULPopupListenerImpl::LaunchPopup(PRInt32 aClientX, PRInt32 aClientY)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsAutoString type(NS_LITERAL_STRING("popup"));
|
||||
if (mIsContext)
|
||||
if ( popupType == eXULPopupType_context ) {
|
||||
type.AssignLiteral("context");
|
||||
|
||||
// position the menu two pixels down and to the right from the current
|
||||
// mouse position. This makes it easier to dismiss the menu by just
|
||||
// clicking.
|
||||
aClientX += 2;
|
||||
aClientY += 2;
|
||||
}
|
||||
|
||||
nsAutoString identifier;
|
||||
mElement->GetAttribute(type, identifier);
|
||||
|
||||
|
@ -404,14 +544,14 @@ nsXULPopupListener::LaunchPopup(nsIDOMEvent* aEvent, nsIContent* aTargetContent)
|
|||
}
|
||||
|
||||
// Handle the _child case for popups and context menus
|
||||
nsCOMPtr<nsIDOMElement> popupElement;
|
||||
nsCOMPtr<nsIDOMElement> popupContent;
|
||||
|
||||
if (identifier.EqualsLiteral("_child")) {
|
||||
nsCOMPtr<nsIContent> popup;
|
||||
|
||||
GetImmediateChild(content, nsGkAtoms::menupopup, getter_AddRefs(popup));
|
||||
if (popup)
|
||||
popupElement = do_QueryInterface(popup);
|
||||
popupContent = do_QueryInterface(popup);
|
||||
else {
|
||||
nsCOMPtr<nsIDOMDocumentXBL> nsDoc(do_QueryInterface(domDocument));
|
||||
nsCOMPtr<nsIDOMNodeList> list;
|
||||
|
@ -426,7 +566,7 @@ nsXULPopupListener::LaunchPopup(nsIDOMEvent* aEvent, nsIContent* aTargetContent)
|
|||
|
||||
if (childContent->NodeInfo()->Equals(nsGkAtoms::menupopup,
|
||||
kNameSpaceID_XUL)) {
|
||||
popupElement = do_QueryInterface(childContent);
|
||||
popupContent = do_QueryInterface(childContent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -434,60 +574,57 @@ nsXULPopupListener::LaunchPopup(nsIDOMEvent* aEvent, nsIContent* aTargetContent)
|
|||
}
|
||||
}
|
||||
else if (NS_FAILED(rv = domDocument->GetElementById(identifier,
|
||||
getter_AddRefs(popupElement)))) {
|
||||
getter_AddRefs(popupContent)))) {
|
||||
// Use getElementById to obtain the popup content and gracefully fail if
|
||||
// we didn't find any popup content in the document.
|
||||
NS_ERROR("GetElementById had some kind of spasm.");
|
||||
return rv;
|
||||
}
|
||||
|
||||
// return if no popup was found or the popup is the element itself.
|
||||
if ( !popupElement || popupElement == mElement)
|
||||
if ( !popupContent )
|
||||
return NS_OK;
|
||||
|
||||
// Submenus can't be used as context menus or popups, bug 288763.
|
||||
// Similar code also in nsXULTooltipListener::GetTooltipFor.
|
||||
nsCOMPtr<nsIContent> popup = do_QueryInterface(popupElement);
|
||||
nsCOMPtr<nsIContent> popup = do_QueryInterface(popupContent);
|
||||
nsIContent* parent = popup->GetParent();
|
||||
if (parent) {
|
||||
nsIDocument* doc = parent->GetCurrentDoc();
|
||||
nsIPresShell* presShell = doc ? doc->GetPrimaryShell() : nsnull;
|
||||
nsIFrame* frame = presShell ? presShell->GetPrimaryFrameFor(parent) : nsnull;
|
||||
if (frame && frame->GetType() == nsGkAtoms::menuFrame)
|
||||
return NS_OK;
|
||||
if (frame) {
|
||||
nsIMenuFrame* menu = nsnull;
|
||||
CallQueryInterface(frame, &menu);
|
||||
NS_ENSURE_FALSE(menu, NS_OK);
|
||||
}
|
||||
}
|
||||
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (!pm)
|
||||
return NS_OK;
|
||||
// We have some popup content. Obtain our window.
|
||||
nsPIDOMWindow *domWindow = document->GetWindow();
|
||||
|
||||
// XXXndeakin this is temporary. It is needed to grab the mouse location details
|
||||
// used by the spellchecking popup. See bug 383930.
|
||||
pm->SetMouseLocation(aEvent);
|
||||
if (domWindow) {
|
||||
// Find out if we're anchored.
|
||||
nsAutoString anchorAlignment;
|
||||
popupContent->GetAttribute(NS_LITERAL_STRING("popupanchor"), anchorAlignment);
|
||||
|
||||
// if the popup has an anchoring attribute, anchor it to the element,
|
||||
// otherwise just open it at the screen position where the mouse was clicked.
|
||||
mPopupContent = popup;
|
||||
if (mPopupContent->HasAttr(kNameSpaceID_None, nsGkAtoms::position) ||
|
||||
mPopupContent->HasAttr(kNameSpaceID_None, nsGkAtoms::popupanchor) ||
|
||||
mPopupContent->HasAttr(kNameSpaceID_None, nsGkAtoms::popupalign)) {
|
||||
pm->ShowPopup(mPopupContent, content, EmptyString(), 0, 0,
|
||||
mIsContext, PR_TRUE, PR_FALSE);
|
||||
nsAutoString popupAlignment;
|
||||
popupContent->GetAttribute(NS_LITERAL_STRING("popupalign"), popupAlignment);
|
||||
|
||||
PRInt32 xPos = aClientX, yPos = aClientY;
|
||||
|
||||
ConvertPosition(popupContent, anchorAlignment, popupAlignment, yPos);
|
||||
if (!anchorAlignment.IsEmpty() && !popupAlignment.IsEmpty())
|
||||
xPos = yPos = -1;
|
||||
|
||||
nsCOMPtr<nsIBoxObject> popupBox;
|
||||
nsCOMPtr<nsIDOMXULElement> xulPopupElt(do_QueryInterface(popupContent));
|
||||
xulPopupElt->GetBoxObject(getter_AddRefs(popupBox));
|
||||
nsCOMPtr<nsIPopupBoxObject> popupBoxObject(do_QueryInterface(popupBox));
|
||||
if (popupBoxObject) {
|
||||
mPopup = popupBoxObject;
|
||||
popupBoxObject->ShowPopup(mElement, popupContent, xPos, yPos,
|
||||
type.get(), anchorAlignment.get(),
|
||||
popupAlignment.get());
|
||||
}
|
||||
else {
|
||||
PRInt32 xPos = 0, yPos = 0;
|
||||
nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
|
||||
mouseEvent->GetScreenX(&xPos);
|
||||
mouseEvent->GetScreenY(&yPos);
|
||||
|
||||
if (mIsContext) {
|
||||
// position the menu two pixels down and to the right from the current
|
||||
// mouse position. This makes it easier to dismiss the menu by just clicking
|
||||
xPos += 2;
|
||||
yPos += 2;
|
||||
}
|
||||
|
||||
pm->ShowPopupAtScreen(mPopupContent, xPos, yPos, mIsContext);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -495,14 +632,13 @@ nsXULPopupListener::LaunchPopup(nsIDOMEvent* aEvent, nsIContent* aTargetContent)
|
|||
|
||||
////////////////////////////////////////////////////////////////
|
||||
nsresult
|
||||
NS_NewXULPopupListener(nsIDOMElement* aElement, PRBool aIsContext,
|
||||
nsIDOMEventListener** aListener)
|
||||
NS_NewXULPopupListener(nsIXULPopupListener** pop)
|
||||
{
|
||||
nsXULPopupListener* pl = new nsXULPopupListener(aElement, aIsContext);
|
||||
if (!pl)
|
||||
XULPopupListenerImpl* popup = new XULPopupListenerImpl();
|
||||
if (!popup)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
*aListener = NS_STATIC_CAST(nsIDOMMouseListener *, pl);
|
||||
NS_ADDREF(*aListener);
|
||||
NS_ADDREF(popup);
|
||||
*pop = popup;
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -1,123 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
||||
* Dean Tessman <dean_tessman@hotmail.com>
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
* Robert O'Callahan <roc+moz@cs.cmu.edu>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* This is the popup listener implementation for popup menus and context menus.
|
||||
*/
|
||||
|
||||
#ifndef nsXULPopupListener_h___
|
||||
#define nsXULPopupListener_h___
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#include "nsIContent.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsIDOMMouseEvent.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIDOMMouseListener.h"
|
||||
#include "nsIDOMContextMenuListener.h"
|
||||
|
||||
class nsXULPopupListener : public nsIDOMMouseListener,
|
||||
public nsIDOMContextMenuListener
|
||||
{
|
||||
public:
|
||||
// aElement is the element that the popup is attached to. If aIsContext is
|
||||
// false, the popup opens on left click on aElement or a descendant. If
|
||||
// aIsContext is true, the popup is a context menu which opens on a
|
||||
// context menu event.
|
||||
nsXULPopupListener(nsIDOMElement *aElement, PRBool aIsContext);
|
||||
virtual ~nsXULPopupListener(void);
|
||||
|
||||
public:
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIDOMMouseListener
|
||||
NS_IMETHOD MouseDown(nsIDOMEvent* aMouseEvent);
|
||||
NS_IMETHOD MouseUp(nsIDOMEvent* aMouseEvent) { return NS_OK; }
|
||||
NS_IMETHOD MouseClick(nsIDOMEvent* aMouseEvent) { return NS_OK; }
|
||||
NS_IMETHOD MouseDblClick(nsIDOMEvent* aMouseEvent) { return NS_OK; }
|
||||
NS_IMETHOD MouseOver(nsIDOMEvent* aMouseEvent) { return NS_OK; }
|
||||
NS_IMETHOD MouseOut(nsIDOMEvent* aMouseEvent) { return NS_OK; }
|
||||
|
||||
// nsIDOMContextMenuListener
|
||||
NS_IMETHOD ContextMenu(nsIDOMEvent* aContextMenuEvent);
|
||||
|
||||
// nsIDOMEventListener
|
||||
NS_IMETHOD HandleEvent(nsIDOMEvent* anEvent) { return NS_OK; }
|
||||
|
||||
protected:
|
||||
|
||||
// open the popup. aEvent is the event that triggered the popup such as
|
||||
// a mouse click and aTargetContent is the target of this event.
|
||||
virtual nsresult LaunchPopup(nsIDOMEvent* aEvent, nsIContent* aTargetContent);
|
||||
|
||||
// close the popup when the listener goes away
|
||||
virtual void ClosePopup();
|
||||
|
||||
private:
|
||||
|
||||
// PreLaunchPopup is called before LaunchPopup to ensure that the event is
|
||||
// suitable and to initialize the XUL document's popupNode to the event
|
||||
// target.
|
||||
nsresult PreLaunchPopup(nsIDOMEvent* aMouseEvent);
|
||||
|
||||
// When a context menu is opened, focus the target of the contextmenu event.
|
||||
nsresult FireFocusOnTargetContent(nsIDOMNode* aTargetNode);
|
||||
|
||||
// |mElement| is the node to which this listener is attached.
|
||||
nsIDOMElement* mElement; // Weak ref. The element will go away first.
|
||||
|
||||
// The popup that is getting shown on top of mElement.
|
||||
nsCOMPtr<nsIContent> mPopupContent;
|
||||
|
||||
// true if a context popup
|
||||
PRBool mIsContext;
|
||||
};
|
||||
|
||||
// Construct a new nsXULPopupListener and return in aListener. See the
|
||||
// nsXULPopupListener constructor for details about the aElement and
|
||||
// aIsContext arguments.
|
||||
nsresult
|
||||
NS_NewXULPopupListener(nsIDOMElement* aElement, PRBool aIsContext,
|
||||
nsIDOMEventListener** aListener);
|
||||
|
||||
#endif // nsXULPopupListener_h___
|
|
@ -128,7 +128,6 @@
|
|||
#include "nsIDocShellTreeItem.h"
|
||||
#include "nsIDocShellTreeOwner.h"
|
||||
#include "nsIXULWindow.h"
|
||||
#include "nsXULPopupManager.h"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
|
@ -1457,49 +1456,84 @@ nsXULDocument::SetPopupNode(nsIDOMNode* aNode)
|
|||
return rv;
|
||||
}
|
||||
|
||||
// Returns the rangeOffset element from the XUL Popup Manager. This is for
|
||||
// chrome callers only.
|
||||
NS_IMETHODIMP
|
||||
nsXULDocument::GetTrustedPopupEvent(nsIDOMEvent** aEvent)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIFocusController> focusController;
|
||||
GetFocusController(getter_AddRefs(focusController));
|
||||
NS_ENSURE_TRUE(focusController, NS_ERROR_FAILURE);
|
||||
|
||||
rv = focusController->GetPopupEvent(aEvent);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULDocument::SetTrustedPopupEvent(nsIDOMEvent* aEvent)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIFocusController> focusController;
|
||||
GetFocusController(getter_AddRefs(focusController));
|
||||
NS_ENSURE_TRUE(focusController, NS_ERROR_FAILURE);
|
||||
|
||||
rv = focusController->SetPopupEvent(aEvent);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Returns the rangeOffset element from the popupEvent. This is for chrome
|
||||
// callers only.
|
||||
NS_IMETHODIMP
|
||||
nsXULDocument::GetPopupRangeParent(nsIDOMNode** aRangeParent)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aRangeParent);
|
||||
*aRangeParent = nsnull;
|
||||
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (!pm)
|
||||
return NS_ERROR_FAILURE;
|
||||
nsCOMPtr<nsIDOMEvent> event;
|
||||
nsresult rv = GetTrustedPopupEvent(getter_AddRefs(event));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (! event)
|
||||
return NS_ERROR_UNEXPECTED; // no event active
|
||||
|
||||
PRInt32 offset;
|
||||
pm->GetMouseLocation(aRangeParent, &offset);
|
||||
nsCOMPtr<nsIDOMNSUIEvent> uiEvent = do_QueryInterface(event, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = uiEvent->GetRangeParent(aRangeParent); // addrefs
|
||||
|
||||
if (*aRangeParent && !nsContentUtils::CanCallerAccess(*aRangeParent)) {
|
||||
if (NS_SUCCEEDED(rv) && *aRangeParent &&
|
||||
!nsContentUtils::CanCallerAccess(*aRangeParent)) {
|
||||
NS_RELEASE(*aRangeParent);
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Returns the rangeOffset element from the XUL Popup Manager. We check the
|
||||
// rangeParent to determine if the caller has rights to access to the data.
|
||||
// Returns the rangeOffset element from the popupEvent. We check the rangeParent
|
||||
// to determine if the caller has rights to access to the data.
|
||||
NS_IMETHODIMP
|
||||
nsXULDocument::GetPopupRangeOffset(PRInt32* aRangeOffset)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aRangeOffset);
|
||||
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (!pm)
|
||||
return NS_ERROR_FAILURE;
|
||||
nsCOMPtr<nsIDOMEvent> event;
|
||||
nsresult rv = GetTrustedPopupEvent(getter_AddRefs(event));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (! event)
|
||||
return NS_ERROR_UNEXPECTED; // no event active
|
||||
|
||||
nsCOMPtr<nsIDOMNSUIEvent> uiEvent = do_QueryInterface(event, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRInt32 offset;
|
||||
nsCOMPtr<nsIDOMNode> parent;
|
||||
pm->GetMouseLocation(getter_AddRefs(parent), &offset);
|
||||
rv = uiEvent->GetRangeParent(getter_AddRefs(parent));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (parent && !nsContentUtils::CanCallerAccess(parent))
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
|
||||
*aRangeOffset = offset;
|
||||
return NS_OK;
|
||||
return uiEvent->GetRangeOffset(aRangeOffset);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -110,4 +110,9 @@ interface nsIDOMXULDocument : nsISupports
|
|||
* Like trustedGetPopupNode, but gets the tooltip node instead.
|
||||
*/
|
||||
[noscript] nsIDOMNode trustedGetTooltipNode();
|
||||
|
||||
/**
|
||||
* Like trustedGetPopupNode, but gets the
|
||||
*/
|
||||
[noscript] attribute nsIDOMEvent trustedPopupEvent;
|
||||
};
|
||||
|
|
|
@ -158,7 +158,6 @@
|
|||
#include "nsEventDispatcher.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsXULPopupManager.h"
|
||||
|
||||
#include "plbase64.h"
|
||||
|
||||
|
@ -3036,10 +3035,10 @@ nsGlobalWindow::CheckSecurityWidthAndHeight(PRInt32* aWidth, PRInt32* aHeight)
|
|||
{
|
||||
if (!nsContentUtils::IsCallerTrustedForWrite()) {
|
||||
// if attempting to resize the window, hide any open popups
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
|
||||
if (pm && doc)
|
||||
pm->HidePopupsInDocument(doc);
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
mDocShell->GetPresShell(getter_AddRefs(presShell));
|
||||
if (presShell)
|
||||
presShell->HidePopups();
|
||||
}
|
||||
|
||||
// This one is easy. Just ensure the variable is greater than 100;
|
||||
|
@ -3069,10 +3068,10 @@ nsGlobalWindow::CheckSecurityLeftAndTop(PRInt32* aLeft, PRInt32* aTop)
|
|||
|
||||
if (!nsContentUtils::IsCallerTrustedForWrite()) {
|
||||
// if attempting to move the window, hide any open popups
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
|
||||
if (pm && doc)
|
||||
pm->HidePopupsInDocument(doc);
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
mDocShell->GetPresShell(getter_AddRefs(presShell));
|
||||
if (presShell)
|
||||
presShell->HidePopups();
|
||||
|
||||
PRInt32 screenLeft, screenTop, screenWidth, screenHeight;
|
||||
PRInt32 winLeft, winTop, winWidth, winHeight;
|
||||
|
|
|
@ -119,6 +119,7 @@
|
|||
#include "nsContentErrors.h"
|
||||
|
||||
#include "nsIDOMWindowInternal.h"
|
||||
#include "nsIMenuFrame.h"
|
||||
|
||||
#include "nsBox.h"
|
||||
|
||||
|
@ -1705,8 +1706,11 @@ GetChildListNameFor(nsIFrame* aChildFrame)
|
|||
// Out-of-flows that are DISPLAY_POPUP must be kids of the root popup set
|
||||
#ifdef DEBUG
|
||||
nsIFrame* parent = aChildFrame->GetParent();
|
||||
NS_ASSERTION(parent && parent->GetType() == nsGkAtoms::popupSetFrame,
|
||||
"Unexpected parent");
|
||||
if (parent) {
|
||||
nsIPopupSetFrame* popupSet;
|
||||
CallQueryInterface(parent, &popupSet);
|
||||
NS_ASSERTION(popupSet, "Unexpected parent");
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
// XXX FIXME: Bug 350740
|
||||
|
@ -5954,7 +5958,9 @@ nsCSSFrameConstructor::ConstructXULFrame(nsFrameConstructorState& aState,
|
|||
// If, however, the parent is *not* a menu frame, then we need to create
|
||||
// a placeholder frame for the popup, and then we add the popup frame to the
|
||||
// root popup set (that manages all such "detached" popups).
|
||||
if (aParentFrame->GetType() != nsGkAtoms::menuFrame) {
|
||||
nsIMenuFrame* menuFrame;
|
||||
CallQueryInterface(aParentFrame, &menuFrame);
|
||||
if (!menuFrame) {
|
||||
if (!aState.mPopupItems.containingBlock) {
|
||||
// Just don't create a frame for this popup; we can't do
|
||||
// anything with it, since there is no root popup set.
|
||||
|
@ -5964,9 +5970,9 @@ nsCSSFrameConstructor::ConstructXULFrame(nsFrameConstructorState& aState,
|
|||
}
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
NS_ASSERTION(aState.mPopupItems.containingBlock->GetType() ==
|
||||
nsGkAtoms::popupSetFrame,
|
||||
"Popup containing block isn't a nsIPopupSetFrame");
|
||||
nsIPopupSetFrame* popupSet;
|
||||
CallQueryInterface(aState.mPopupItems.containingBlock, &popupSet);
|
||||
NS_ASSERTION(popupSet, "Popup containing block isn't a nsIPopupSetFrame");
|
||||
#endif
|
||||
isPopup = PR_TRUE;
|
||||
}
|
||||
|
@ -6141,16 +6147,6 @@ nsCSSFrameConstructor::ConstructXULFrame(nsFrameConstructorState& aState,
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCSSFrameConstructor::AddLazyChildren(nsIContent* aContent,
|
||||
nsLazyFrameConstructionCallback* aCallback,
|
||||
void* aArg)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
new LazyGenerateChildrenEvent(aContent, mPresShell, aCallback, aArg);
|
||||
return NS_DispatchToCurrentThread(event);
|
||||
}
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
nsCSSFrameConstructor::BeginBuildingScrollFrame(nsFrameConstructorState& aState,
|
||||
nsIContent* aContent,
|
||||
|
@ -10140,6 +10136,29 @@ nsCSSFrameConstructor::AttributeChanged(nsIContent* aContent,
|
|||
aAttribute,
|
||||
aModType);
|
||||
|
||||
// Menus and such can't deal with asynchronous changes of display
|
||||
// when the menugenerated or menuactive attribute changes, so make
|
||||
// sure to process that immediately
|
||||
if (aNameSpaceID == kNameSpaceID_None &&
|
||||
((aAttribute == nsGkAtoms::menugenerated &&
|
||||
aModType != nsIDOMMutationEvent::REMOVAL) ||
|
||||
aAttribute == nsGkAtoms::menuactive)) {
|
||||
PRInt32 namespaceID;
|
||||
nsIAtom* tag =
|
||||
mDocument->BindingManager()->ResolveTag(aContent, &namespaceID);
|
||||
|
||||
if (namespaceID == kNameSpaceID_XUL &&
|
||||
(tag == nsGkAtoms::menupopup || tag == nsGkAtoms::popup ||
|
||||
tag == nsGkAtoms::tooltip || tag == nsGkAtoms::menu)) {
|
||||
nsIViewManager* viewManager = mPresShell->GetViewManager();
|
||||
viewManager->BeginUpdateViewBatch();
|
||||
ProcessOneRestyle(aContent, rshint, hint);
|
||||
viewManager->EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
PostRestyleEvent(aContent, rshint, hint);
|
||||
|
||||
return result;
|
||||
|
@ -13009,42 +13028,3 @@ NS_IMETHODIMP nsCSSFrameConstructor::RestyleEvent::Run() {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCSSFrameConstructor::LazyGenerateChildrenEvent::Run()
|
||||
{
|
||||
mPresShell->GetDocument()->FlushPendingNotifications(Flush_Layout);
|
||||
|
||||
// this is hard-coded to handle only menu popup frames
|
||||
nsIFrame* frame = mPresShell->GetPrimaryFrameFor(mContent);
|
||||
if (frame && frame->GetType() == nsGkAtoms::menuPopupFrame) {
|
||||
// it is possible that the frame is different than the one that requested
|
||||
// the lazy generation, but as long as it's a popup frame that hasn't
|
||||
// generated its children yet, that's OK.
|
||||
nsMenuPopupFrame* menuPopupFrame = NS_STATIC_CAST(nsMenuPopupFrame *, frame);
|
||||
if (menuPopupFrame->HasGeneratedChildren())
|
||||
return NS_OK;
|
||||
|
||||
// indicate that the children have been generated
|
||||
menuPopupFrame->SetGeneratedChildren();
|
||||
|
||||
nsFrameItems childItems;
|
||||
nsFrameConstructorState state(mPresShell, nsnull, nsnull, nsnull);
|
||||
nsCSSFrameConstructor* fc = mPresShell->FrameConstructor();
|
||||
nsresult rv = fc->ProcessChildren(state, mContent, frame, PR_FALSE,
|
||||
childItems, PR_FALSE);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
fc->CreateAnonymousFrames(mContent->Tag(), state, mContent, frame,
|
||||
PR_FALSE, childItems);
|
||||
frame->SetInitialChildList(nsnull, childItems.childList);
|
||||
|
||||
if (mCallback)
|
||||
mCallback(mContent, frame, mArg);
|
||||
|
||||
// call XBL constructors after the frames are created
|
||||
mPresShell->GetDocument()->BindingManager()->ProcessAttachedQueue();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -72,9 +72,6 @@ struct nsFindFrameHint
|
|||
nsFindFrameHint() : mPrimaryFrameForPrevSibling(nsnull) { }
|
||||
};
|
||||
|
||||
typedef void (PR_CALLBACK nsLazyFrameConstructionCallback)
|
||||
(nsIContent* aContent, nsIFrame* aFrame, void* aArg);
|
||||
|
||||
class nsFrameConstructorState;
|
||||
class nsFrameConstructorSaveState;
|
||||
|
||||
|
@ -125,17 +122,6 @@ public:
|
|||
nsIContent* aContent2,
|
||||
PRInt32 aStateMask);
|
||||
|
||||
// Process the children of aContent and indicate that frames should be
|
||||
// created for them. This is used for lazily built content such as that
|
||||
// inside popups so that it is only created when the popup is opened.
|
||||
// This method constructs the frames asynchronously.
|
||||
// aCallback will be called with three arguments, the first is the value
|
||||
// of aContent, the second is aContent's primary frame, and the third is
|
||||
// the value of aArg.
|
||||
nsresult AddLazyChildren(nsIContent* aContent,
|
||||
nsLazyFrameConstructionCallback* aCallback,
|
||||
void* aArg);
|
||||
|
||||
// Should be called when a frame is going to be destroyed and
|
||||
// WillDestroyFrameTree hasn't been called yet.
|
||||
void NotifyDestroyingFrame(nsIFrame* aFrame);
|
||||
|
@ -1017,27 +1003,6 @@ public:
|
|||
friend class nsFrameConstructorState;
|
||||
|
||||
private:
|
||||
|
||||
class LazyGenerateChildrenEvent;
|
||||
friend class LazyGenerateChildrenEvent;
|
||||
|
||||
class LazyGenerateChildrenEvent : public nsRunnable {
|
||||
public:
|
||||
NS_DECL_NSIRUNNABLE
|
||||
LazyGenerateChildrenEvent(nsIContent *aContent,
|
||||
nsIPresShell *aPresShell,
|
||||
nsLazyFrameConstructionCallback* aCallback,
|
||||
void* aArg)
|
||||
: mContent(aContent), mPresShell(aPresShell), mCallback(aCallback), mArg(aArg)
|
||||
{}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIContent> mContent;
|
||||
nsCOMPtr<nsIPresShell> mPresShell;
|
||||
nsLazyFrameConstructionCallback* mCallback;
|
||||
void* mArg;
|
||||
};
|
||||
|
||||
nsIDocument* mDocument; // Weak ref
|
||||
nsIPresShell* mPresShell; // Weak ref
|
||||
|
||||
|
|
|
@ -111,7 +111,6 @@
|
|||
#ifdef MOZ_XUL
|
||||
#include "nsIXULDocument.h"
|
||||
#endif
|
||||
#include "nsXULPopupManager.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
#include "nsIClipboardHelper.h"
|
||||
|
@ -1154,9 +1153,10 @@ DocumentViewerImpl::PageHide(PRBool aIsUnload)
|
|||
|
||||
// look for open menupopups and close them after the unload event, in case
|
||||
// the unload event listeners open any new popups
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (pm && mDocument)
|
||||
pm->HidePopupsInDocument(mDocument);
|
||||
if (mPresShell) {
|
||||
nsCOMPtr<nsIPresShell> kungFuDeathGrip = mPresShell;
|
||||
mPresShell->HidePopups();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -102,10 +102,10 @@ class gfxContext;
|
|||
typedef short SelectionType;
|
||||
typedef PRUint32 nsFrameState;
|
||||
|
||||
// D93B931B-D5EF-4D3C-AB99-444176963464
|
||||
// 9562bb2b-990c-4875-aafd-bd46fc9a4fc1
|
||||
#define NS_IPRESSHELL_IID \
|
||||
{ 0xd93b931b, 0xd5ef, 0x4d3c, \
|
||||
{ 0xab, 0x99, 0x44, 0x41, 0x76, 0x96, 0x34, 0x64 } }
|
||||
{ 0x9562bb2b, 0x990c, 0x4875, \
|
||||
{ 0xaa, 0xfd, 0xbd, 0x46, 0xfc, 0x9a, 0x4f, 0xc1 } }
|
||||
|
||||
// Constants for ScrollContentIntoView() function
|
||||
#define NS_PRESSHELL_SCROLL_TOP 0
|
||||
|
@ -725,6 +725,8 @@ public:
|
|||
nsPoint& aPoint,
|
||||
nsRect* aScreenRect) = 0;
|
||||
|
||||
virtual void HidePopups() = 0;
|
||||
|
||||
void AddWeakFrame(nsWeakFrame* aWeakFrame);
|
||||
void RemoveWeakFrame(nsWeakFrame* aWeakFrame);
|
||||
|
||||
|
|
|
@ -189,7 +189,7 @@
|
|||
#include "nsStyleChangeList.h"
|
||||
#include "nsCSSFrameConstructor.h"
|
||||
#ifdef MOZ_XUL
|
||||
#include "nsMenuFrame.h"
|
||||
#include "nsIMenuFrame.h"
|
||||
#include "nsITreeBoxObject.h"
|
||||
#endif
|
||||
#include "nsIMenuParent.h"
|
||||
|
@ -887,6 +887,8 @@ public:
|
|||
nsPoint& aPoint,
|
||||
nsRect* aScreenRect);
|
||||
|
||||
virtual void HidePopups();
|
||||
|
||||
//nsIViewObserver interface
|
||||
|
||||
NS_IMETHOD Paint(nsIView *aView,
|
||||
|
@ -5837,6 +5839,18 @@ PresShell::Thaw()
|
|||
UnsuppressPainting();
|
||||
}
|
||||
|
||||
void
|
||||
PresShell::HidePopups()
|
||||
{
|
||||
nsIViewManager *vm = GetViewManager();
|
||||
if (vm) {
|
||||
nsIView *rootView = nsnull;
|
||||
vm->GetRootView(rootView);
|
||||
if (rootView)
|
||||
HideViewIfPopup(rootView);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Start of protected and private methods on the PresShell
|
||||
//--------------------------------------------------------
|
||||
|
@ -6171,8 +6185,11 @@ ReResolveMenusAndTrees(nsIFrame *aFrame, void *aClosure)
|
|||
// sub-content, since doing so slows menus to a crawl. That means we
|
||||
// have to special-case them on a skin switch, and ensure that the
|
||||
// popup frames just get destroyed completely.
|
||||
if (aFrame && aFrame->GetType() == nsGkAtoms::menuFrame)
|
||||
(NS_STATIC_CAST(nsMenuFrame *, aFrame))->CloseMenu(PR_TRUE);
|
||||
nsCOMPtr<nsIMenuFrame> menuFrame(do_QueryInterface(aFrame));
|
||||
if (menuFrame) {
|
||||
menuFrame->UngenerateMenu();
|
||||
menuFrame->OpenMenu(PR_FALSE);
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
|
@ -6310,6 +6327,27 @@ PresShell::EnumeratePlugins(nsIDOMDocument *aDocument,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
PresShell::HideViewIfPopup(nsIView* aView)
|
||||
{
|
||||
nsIFrame* frame = NS_STATIC_CAST(nsIFrame*, aView->GetClientData());
|
||||
if (frame) {
|
||||
nsIMenuParent* parent;
|
||||
CallQueryInterface(frame, &parent);
|
||||
if (parent) {
|
||||
parent->HideChain();
|
||||
// really make sure the view is hidden
|
||||
mViewManager->SetViewVisibility(aView, nsViewVisibility_kHide);
|
||||
}
|
||||
}
|
||||
|
||||
nsIView* child = aView->GetFirstChild();
|
||||
while (child) {
|
||||
HideViewIfPopup(child);
|
||||
child = child->GetNextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
// End of protected and private methods on the PresShell
|
||||
//------------------------------------------------------
|
||||
|
|
|
@ -236,6 +236,7 @@ static NS_DEFINE_CID(kWindowCommandTableCID, NS_WINDOWCOMMANDTABLE_CID);
|
|||
#ifdef MOZ_XUL
|
||||
#include "nsIBoxObject.h"
|
||||
#include "nsIXULDocument.h"
|
||||
#include "nsIXULPopupListener.h"
|
||||
#include "nsIXULPrototypeCache.h"
|
||||
#include "nsIXULSortService.h"
|
||||
|
||||
|
@ -508,6 +509,7 @@ MAKE_CTOR(CreateXULSortService, nsIXULSortService, NS_NewXUL
|
|||
// NS_NewXULContentBuilder
|
||||
// NS_NewXULTreeBuilder
|
||||
MAKE_CTOR(CreateXULDocument, nsIXULDocument, NS_NewXULDocument)
|
||||
MAKE_CTOR(CreateXULPopupListener, nsIXULPopupListener, NS_NewXULPopupListener)
|
||||
// NS_NewXULControllers
|
||||
// NS_NewXULPrototypeCache
|
||||
#endif
|
||||
|
@ -1192,6 +1194,11 @@ static const nsModuleComponentInfo gComponents[] = {
|
|||
"@mozilla.org/xul/xul-document;1",
|
||||
CreateXULDocument },
|
||||
|
||||
{ "XUL PopupListener",
|
||||
NS_XULPOPUPLISTENER_CID,
|
||||
"@mozilla.org/xul/xul-popup-listener;1",
|
||||
CreateXULPopupListener },
|
||||
|
||||
{ "XUL Prototype Cache",
|
||||
NS_XULPROTOTYPECACHE_CID,
|
||||
"@mozilla.org/xul/xul-prototype-cache;1",
|
||||
|
|
|
@ -80,7 +80,6 @@
|
|||
#include "nsCellMap.h"
|
||||
#include "nsTextFrameTextRunCache.h"
|
||||
#include "nsCCUncollectableMarker.h"
|
||||
#include "nsXULPopupManager.h"
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
#include "nsXULContentUtils.h"
|
||||
|
@ -224,19 +223,12 @@ nsLayoutStatics::Initialize()
|
|||
return rv;
|
||||
}
|
||||
|
||||
rv = nsXULPopupManager::Init();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("Could not initialize nsXULPopupManager");
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsLayoutStatics::Shutdown()
|
||||
{
|
||||
nsXULPopupManager::Shutdown();
|
||||
nsDOMStorageManager::Shutdown();
|
||||
txMozillaXSLTProcessor::Shutdown();
|
||||
nsDOMAttribute::Shutdown();
|
||||
|
|
|
@ -717,12 +717,7 @@ nsContainerFrame::PositionChildViews(nsIFrame* aFrame)
|
|||
childFrame = childFrame->GetNextSibling();
|
||||
}
|
||||
|
||||
// also process the additional child lists, but skip the popup list as the
|
||||
// view for popups is managed by the parent. Currently only nsMenuFrame
|
||||
// has a popupList and during layout will call nsMenuPopupFrame::AdjustView.
|
||||
do {
|
||||
childListName = aFrame->GetAdditionalChildListName(childListIndex++);
|
||||
} while (childListName == nsGkAtoms::popupList);
|
||||
} while (childListName);
|
||||
}
|
||||
|
||||
|
|
|
@ -49,8 +49,8 @@ GRE_MODULE = 1
|
|||
EXPORTS = \
|
||||
nsPIBoxObject.h \
|
||||
nsIMenuFrame.h \
|
||||
nsIPopupSetFrame.h \
|
||||
nsIScrollbarMediator.h \
|
||||
nsXULPopupManager.h \
|
||||
$(NULL)
|
||||
|
||||
XPIDLSRCS= nsIBoxObject.idl \
|
||||
|
|
|
@ -38,25 +38,53 @@
|
|||
#ifndef nsIMenuFrame_h___
|
||||
#define nsIMenuFrame_h___
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
// this interface exists solely because native themes need to call into it.
|
||||
// Only menu frames should implement it
|
||||
|
||||
// {212521C8-1509-4F41-ADDB-6A0B9356770F}
|
||||
// {2281EFC8-A8BA-4a73-8CF7-DB4EECA5EAEC}
|
||||
#define NS_IMENUFRAME_IID \
|
||||
{ 0x212521C8, 0x1509, 0x4F41, { 0xAD, 0xDB, 0x6A, 0x0B, 0x93, 0x56, 0x77, 0x0F } }
|
||||
{ 0x2281efc8, 0xa8ba, 0x4a73, { 0x8c, 0xf7, 0xdb, 0x4e, 0xec, 0xa5, 0xea, 0xec } }
|
||||
|
||||
class nsIMenuParent;
|
||||
class nsIDOMElement;
|
||||
class nsIDOMKeyEvent;
|
||||
|
||||
enum nsMenuType {
|
||||
eMenuType_Normal = 0,
|
||||
eMenuType_Checkbox = 1,
|
||||
eMenuType_Radio = 2
|
||||
};
|
||||
|
||||
class nsIMenuFrame : public nsISupports {
|
||||
|
||||
public:
|
||||
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMENUFRAME_IID)
|
||||
|
||||
virtual PRBool IsOpen() = 0;
|
||||
virtual PRBool IsMenu() = 0;
|
||||
virtual PRBool IsOnMenuBar() = 0;
|
||||
virtual PRBool IsOnActiveMenuBar() = 0;
|
||||
NS_IMETHOD ActivateMenu(PRBool aActivate) = 0;
|
||||
NS_IMETHOD SelectMenu(PRBool aFlag) = 0;
|
||||
NS_IMETHOD OpenMenu(PRBool aFlag) = 0;
|
||||
|
||||
NS_IMETHOD MenuIsOpen(PRBool& aResult) = 0;
|
||||
NS_IMETHOD MenuIsContainer(PRBool& aResult) = 0;
|
||||
NS_IMETHOD MenuIsChecked(PRBool& aResult) = 0;
|
||||
NS_IMETHOD MenuIsDisabled(PRBool& aResult) = 0;
|
||||
|
||||
NS_IMETHOD SelectFirstItem() = 0;
|
||||
|
||||
NS_IMETHOD Escape(PRBool& aHandledFlag) = 0;
|
||||
NS_IMETHOD Enter() = 0;
|
||||
NS_IMETHOD ShortcutNavigation(nsIDOMKeyEvent* aKeyEvent, PRBool& aHandledFlag) = 0;
|
||||
NS_IMETHOD KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag) = 0;
|
||||
|
||||
virtual nsIMenuParent *GetMenuParent() = 0;
|
||||
virtual nsIFrame *GetMenuChild() = 0;
|
||||
|
||||
NS_IMETHOD GetRadioGroupName(nsString &aName) = 0;
|
||||
NS_IMETHOD GetMenuType(nsMenuType &aType) = 0;
|
||||
|
||||
NS_IMETHOD MarkAsGenerated() = 0;
|
||||
|
||||
NS_IMETHOD UngenerateMenu() = 0;
|
||||
|
||||
NS_IMETHOD GetActiveChild(nsIDOMElement** aResult)=0;
|
||||
NS_IMETHOD SetActiveChild(nsIDOMElement* aChild)=0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIMenuFrame, NS_IMENUFRAME_IID)
|
||||
|
|
|
@ -41,37 +41,24 @@
|
|||
|
||||
interface nsIDOMElement;
|
||||
|
||||
[scriptable, uuid(8714441F-0E24-4EB5-BE58-905F2854B4EB)]
|
||||
|
||||
[scriptable, uuid(116ffbea-336d-4ff1-a978-7335f54d11da)]
|
||||
interface nsIPopupBoxObject : nsISupports
|
||||
{
|
||||
/**
|
||||
* This method is deprecated. Use openPopup or openPopupAtScreen instead.
|
||||
*/
|
||||
void showPopup(in nsIDOMElement srcContent, in nsIDOMElement popupContent,
|
||||
in long xpos, in long ypos,
|
||||
in wstring popupType, in wstring anchorAlignment,
|
||||
in wstring popupAlignment);
|
||||
|
||||
/**
|
||||
* Hide the popup if it is open.
|
||||
*/
|
||||
void hidePopup();
|
||||
|
||||
|
||||
/**
|
||||
* Allow the popup to automatically position itself.
|
||||
*/
|
||||
attribute boolean autoPosition;
|
||||
|
||||
/**
|
||||
* If keyboard navigation is enabled, the keyboard may be used to navigate
|
||||
* the menuitems on the popup. Enabling keyboard navigation is the default
|
||||
* behaviour and will install capturing key event listeners on the popup
|
||||
* that do not propagate key events to the contents. If you wish to place
|
||||
* elements in a popup which accept key events, such as textboxes, keyboard
|
||||
* navigation should be disabled.
|
||||
*
|
||||
* Setting ignorekeys="true" on the popup element also disables keyboard
|
||||
* navigation, and is recommended over calling this method.
|
||||
* Allow the popup to eat all key events
|
||||
*/
|
||||
void enableKeyboardNavigator(in boolean enableKeyboardNavigator);
|
||||
|
||||
|
@ -98,62 +85,10 @@ interface nsIPopupBoxObject : nsISupports
|
|||
void sizeTo(in long width, in long height);
|
||||
|
||||
/**
|
||||
* Move the popup to a point on screen in CSS pixels.
|
||||
* Move the popup to a point on screen
|
||||
*/
|
||||
void moveTo(in long left, in long top);
|
||||
|
||||
/**
|
||||
* Open the popup relative to a specified node at a specific location.
|
||||
*
|
||||
* The popup may be either anchored to another node or opened freely.
|
||||
* To anchor a popup to a node, supply an anchor node and set the position
|
||||
* to a string indicating the manner in which the popup should be anchored.
|
||||
* Possible values for position are:
|
||||
* before_start, before_end, after_start, after_end,
|
||||
* start_before, start_after, end_before, end_after,
|
||||
* overlap, after_pointer
|
||||
*
|
||||
* The anchor node does not need to be in the same document as the popup.
|
||||
*
|
||||
* If the attributesOverride argument is true, the popupanchor, popupalign
|
||||
* and position attributes on the popup node override the position value
|
||||
* argument. If attributesOverride is false, the attributes are only used
|
||||
* if position is empty.
|
||||
*
|
||||
* For an anchored popup, the x and y arguments may be used to offset the
|
||||
* popup from its anchored position by some number, measured in CSS pixels.
|
||||
*
|
||||
* Unanchored popups may be created by supplying null as the anchor node.
|
||||
* An unanchored popup appears at the position specified by x and y,
|
||||
* relative to the viewport of the document containing the popup node. In
|
||||
* this case, position and attributesOverride are ignored.
|
||||
*
|
||||
* @param anchorElement the node to anchor the popup to, may be null
|
||||
* @param position manner is which to anchor the popup to node
|
||||
* @param x horizontal offset
|
||||
* @param y vertical offset
|
||||
* @param isContextMenu true for context menus, false for other popups
|
||||
* @param attributesOverride true if popup node attributes override position
|
||||
*/
|
||||
void openPopup(in nsIDOMElement anchorElement,
|
||||
in AString position,
|
||||
in long x, in long y,
|
||||
in boolean isContextMenu,
|
||||
in boolean attributesOverride);
|
||||
|
||||
/**
|
||||
* Open the popup at a specific screen position specified by x and y. This
|
||||
* position may be adjusted if it would cause the popup to be off of the
|
||||
* screen. The x and y coordinates are measured in CSS pixels. The monitor
|
||||
* selected is determined within the platform specific widget code, but
|
||||
* in general, the coordinates are relative to the screen the window
|
||||
* containing the popup is on.
|
||||
*
|
||||
* @param isContextMenu true for context menus, false for other popups
|
||||
* @param x horizontal screen position
|
||||
* @param y vertical screen position
|
||||
*/
|
||||
void openPopupAtScreen(in long x, in long y, in boolean isContextMenu);
|
||||
};
|
||||
|
||||
%{C++
|
||||
|
|
|
@ -1,636 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Neil Deakin
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* The XUL Popup Manager keeps track of all open popups.
|
||||
*/
|
||||
|
||||
#ifndef nsXULPopupManager_h__
|
||||
#define nsXULPopupManager_h__
|
||||
|
||||
#include "nsIContent.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsIRollupListener.h"
|
||||
#include "nsIMenuRollup.h"
|
||||
#include "nsIDOMKeyListener.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
/**
|
||||
* There are two types that are used:
|
||||
* - dismissable popups such as menus, which should close up when there is a
|
||||
* click outside the popup. In this situation, the entire chain of menus
|
||||
* above should also be closed.
|
||||
* - panels, which stay open until a request is made to close them. This
|
||||
* type is used by tooltips.
|
||||
* XXXndeakin note that panels don't work too well currently due to widget
|
||||
* changes needed to handle activation events properly.
|
||||
*
|
||||
* When a new popup is opened, it is appended to the popup chain, stored in a
|
||||
* linked list in mCurrentMenu for dismissable menus or mPanels for panels.
|
||||
* Popups are stored in this list linked from newest to oldest. When a click
|
||||
* occurs outside one of the open dismissable popups, the chain is closed by
|
||||
* calling Rollup.
|
||||
*/
|
||||
|
||||
class nsIPresShell;
|
||||
class nsMenuFrame;
|
||||
class nsMenuPopupFrame;
|
||||
class nsMenuBarFrame;
|
||||
class nsIMenuParent;
|
||||
class nsIDOMKeyEvent;
|
||||
|
||||
/**
|
||||
* nsNavigationDirection: an enum expressing navigation through the menus in
|
||||
* terms which are independent of the directionality of the chrome. The
|
||||
* terminology, derived from XSL-FO and CSS3 (e.g.
|
||||
* http://www.w3.org/TR/css3-text/#TextLayout), is BASE (Before, After, Start,
|
||||
* End), with the addition of First and Last (mapped to Home and End
|
||||
* respectively).
|
||||
*
|
||||
* In languages such as English where the inline progression is left-to-right
|
||||
* and the block progression is top-to-bottom (lr-tb), these terms will map out
|
||||
* as in the following diagram
|
||||
*
|
||||
* --- inline progression --->
|
||||
*
|
||||
* First |
|
||||
* ... |
|
||||
* Before |
|
||||
* +--------+ block
|
||||
* Start | | End progression
|
||||
* +--------+ |
|
||||
* After |
|
||||
* ... |
|
||||
* Last V
|
||||
*
|
||||
*/
|
||||
|
||||
enum nsNavigationDirection {
|
||||
eNavigationDirection_Last,
|
||||
eNavigationDirection_First,
|
||||
eNavigationDirection_Start,
|
||||
eNavigationDirection_Before,
|
||||
eNavigationDirection_End,
|
||||
eNavigationDirection_After
|
||||
};
|
||||
|
||||
#define NS_DIRECTION_IS_INLINE(dir) (dir == eNavigationDirection_Start || \
|
||||
dir == eNavigationDirection_End)
|
||||
#define NS_DIRECTION_IS_BLOCK(dir) (dir == eNavigationDirection_Before || \
|
||||
dir == eNavigationDirection_After)
|
||||
#define NS_DIRECTION_IS_BLOCK_TO_EDGE(dir) (dir == eNavigationDirection_First || \
|
||||
dir == eNavigationDirection_Last)
|
||||
|
||||
/**
|
||||
* DirectionFromKeyCode_lr_tb: an array that maps keycodes to values of
|
||||
* nsNavigationDirection for left-to-right and top-to-bottom flow orientation
|
||||
*/
|
||||
static nsNavigationDirection DirectionFromKeyCode_lr_tb [6] = {
|
||||
eNavigationDirection_Last, // NS_VK_END
|
||||
eNavigationDirection_First, // NS_VK_HOME
|
||||
eNavigationDirection_Start, // NS_VK_LEFT
|
||||
eNavigationDirection_Before, // NS_VK_UP
|
||||
eNavigationDirection_End, // NS_VK_RIGHT
|
||||
eNavigationDirection_After // NS_VK_DOWN
|
||||
};
|
||||
|
||||
/**
|
||||
* DirectionFromKeyCode_rl_tb: an array that maps keycodes to values of
|
||||
* nsNavigationDirection for right-to-left and top-to-bottom flow orientation
|
||||
*/
|
||||
static nsNavigationDirection DirectionFromKeyCode_rl_tb [6] = {
|
||||
eNavigationDirection_Last, // NS_VK_END
|
||||
eNavigationDirection_First, // NS_VK_HOME
|
||||
eNavigationDirection_End, // NS_VK_LEFT
|
||||
eNavigationDirection_Before, // NS_VK_UP
|
||||
eNavigationDirection_Start, // NS_VK_RIGHT
|
||||
eNavigationDirection_After // NS_VK_DOWN
|
||||
};
|
||||
|
||||
#define NS_DIRECTION_FROM_KEY_CODE(frame, direction, keycode) \
|
||||
NS_ASSERTION(NS_VK_HOME == NS_VK_END + 1, "Broken ordering"); \
|
||||
NS_ASSERTION(NS_VK_LEFT == NS_VK_END + 2, "Broken ordering"); \
|
||||
NS_ASSERTION(NS_VK_UP == NS_VK_END + 3, "Broken ordering"); \
|
||||
NS_ASSERTION(NS_VK_RIGHT == NS_VK_END + 4, "Broken ordering"); \
|
||||
NS_ASSERTION(NS_VK_DOWN == NS_VK_END + 5, "Broken ordering"); \
|
||||
NS_ASSERTION(keycode >= NS_VK_END && keycode <= NS_VK_DOWN, \
|
||||
"Illegal key code"); \
|
||||
const nsStyleVisibility* vis = frame->GetStyleVisibility(); \
|
||||
if (vis->mDirection == NS_STYLE_DIRECTION_RTL) \
|
||||
direction = DirectionFromKeyCode_rl_tb[keycode - NS_VK_END]; \
|
||||
else \
|
||||
direction = DirectionFromKeyCode_lr_tb[keycode - NS_VK_END];
|
||||
|
||||
// nsMenuChainItem holds info about an open popup. Items are stored in a
|
||||
// doubly linked list. Note that the linked list is stored beginning from
|
||||
// the lowest child in a chain of menus, as this is the active submenu.
|
||||
class nsMenuChainItem
|
||||
{
|
||||
private:
|
||||
nsMenuPopupFrame* mFrame; // the popup frame
|
||||
PRPackedBool mIsMenu; // true if the popup is a menu, false for a panel
|
||||
PRPackedBool mIsContext; // true for context menus
|
||||
PRPackedBool mOnMenuBar; // true if the menu is on a menu bar
|
||||
PRPackedBool mIgnoreKeys; // true if keyboard listeners should not be used
|
||||
|
||||
nsMenuChainItem* mParent;
|
||||
nsMenuChainItem* mChild;
|
||||
|
||||
public:
|
||||
nsMenuChainItem(nsMenuPopupFrame* aFrame, PRBool aIsContext, PRBool aIsMenu)
|
||||
: mFrame(aFrame),
|
||||
mIsMenu(aIsMenu),
|
||||
mIsContext(aIsContext),
|
||||
mOnMenuBar(PR_FALSE),
|
||||
mIgnoreKeys(!aIsMenu), // always ignore keys on non-menus
|
||||
mParent(nsnull),
|
||||
mChild(nsnull)
|
||||
{
|
||||
NS_ASSERTION(aFrame, "null frame passed to nsMenuChainItem constructor");
|
||||
MOZ_COUNT_CTOR(nsMenuChainItem);
|
||||
}
|
||||
|
||||
~nsMenuChainItem()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsMenuChainItem);
|
||||
}
|
||||
|
||||
nsIContent* Content();
|
||||
nsMenuPopupFrame* Frame() { return mFrame; }
|
||||
PRBool IsMenu() { return mIsMenu; }
|
||||
PRBool IsContextMenu() { return mIsContext; }
|
||||
PRBool IgnoreKeys() { return mIgnoreKeys; }
|
||||
PRBool IsOnMenuBar() { return mOnMenuBar; }
|
||||
void SetIgnoreKeys(PRBool aIgnoreKeys) { mIgnoreKeys = aIgnoreKeys; }
|
||||
void SetOnMenuBar(PRBool aOnMenuBar) { mOnMenuBar = aOnMenuBar; }
|
||||
nsMenuChainItem* GetParent() { return mParent; }
|
||||
nsMenuChainItem* GetChild() { return mChild; }
|
||||
|
||||
// set the parent of this item to aParent, also changing the parent
|
||||
// to have this as a child.
|
||||
void SetParent(nsMenuChainItem* aParent);
|
||||
|
||||
// removes an item from the chain. The root pointer must be supplied in case
|
||||
// the item is the first item in the chain in which case the pointer will be
|
||||
// set to the next item, or null if there isn't another item. After detaching,
|
||||
// this item will not have a parent or a child.
|
||||
void Detach(nsMenuChainItem** aRoot);
|
||||
};
|
||||
|
||||
// this class is used for dispatching popupshowing events asynchronously.
|
||||
class nsXULPopupShowingEvent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
nsXULPopupShowingEvent(nsIContent *aPopup,
|
||||
nsIContent *aMenu,
|
||||
PRBool aIsContextMenu,
|
||||
PRBool aSelectFirstItem)
|
||||
: mPopup(aPopup),
|
||||
mMenu(aMenu),
|
||||
mIsContextMenu(aIsContextMenu),
|
||||
mSelectFirstItem(aSelectFirstItem)
|
||||
{
|
||||
NS_ASSERTION(aPopup, "null popup supplied to nsXULPopupShowingEvent constructor");
|
||||
NS_ASSERTION(aMenu, "null menu supplied to nsXULPopupShowingEvent constructor");
|
||||
}
|
||||
|
||||
NS_IMETHOD Run();
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIContent> mPopup;
|
||||
nsCOMPtr<nsIContent> mMenu;
|
||||
PRBool mIsContextMenu;
|
||||
PRBool mSelectFirstItem;
|
||||
};
|
||||
|
||||
// this class is used for dispatching popuphiding events asynchronously.
|
||||
class nsXULPopupHidingEvent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
nsXULPopupHidingEvent(nsIContent *aPopup,
|
||||
nsIContent* aNextPopup,
|
||||
nsIContent* aLastPopup,
|
||||
PRBool aIsMenu,
|
||||
PRBool aDeselectMenu)
|
||||
: mPopup(aPopup),
|
||||
mNextPopup(aNextPopup),
|
||||
mLastPopup(aLastPopup),
|
||||
mIsMenu(aIsMenu),
|
||||
mDeselectMenu(aDeselectMenu)
|
||||
{
|
||||
NS_ASSERTION(aPopup, "null popup supplied to nsXULPopupHidingEvent constructor");
|
||||
// aNextPopup and aLastPopup may be null
|
||||
}
|
||||
|
||||
NS_IMETHOD Run();
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIContent> mPopup;
|
||||
nsCOMPtr<nsIContent> mNextPopup;
|
||||
nsCOMPtr<nsIContent> mLastPopup;
|
||||
PRBool mIsMenu;
|
||||
PRBool mDeselectMenu;
|
||||
};
|
||||
|
||||
// this class is used for dispatching menu command events asynchronously.
|
||||
class nsXULMenuCommandEvent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
nsXULMenuCommandEvent(nsIContent *aMenu,
|
||||
PRBool aIsTrusted,
|
||||
PRBool aShift,
|
||||
PRBool aControl,
|
||||
PRBool aAlt,
|
||||
PRBool aMeta)
|
||||
: mMenu(aMenu),
|
||||
mIsTrusted(aIsTrusted),
|
||||
mShift(aShift),
|
||||
mControl(aControl),
|
||||
mAlt(aAlt),
|
||||
mMeta(aMeta)
|
||||
{
|
||||
NS_ASSERTION(aMenu, "null menu supplied to nsXULMenuCommandEvent constructor");
|
||||
}
|
||||
|
||||
NS_IMETHOD Run();
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIContent> mMenu;
|
||||
PRBool mIsTrusted;
|
||||
PRBool mShift;
|
||||
PRBool mControl;
|
||||
PRBool mAlt;
|
||||
PRBool mMeta;
|
||||
};
|
||||
|
||||
class nsXULPopupManager : public nsIDOMKeyListener,
|
||||
public nsIMenuRollup,
|
||||
public nsIRollupListener,
|
||||
public nsITimerCallback
|
||||
{
|
||||
|
||||
public:
|
||||
friend class nsXULPopupShowingEvent;
|
||||
friend class nsXULPopupHidingEvent;
|
||||
friend class nsXULMenuCommandEvent;
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIROLLUPLISTENER
|
||||
NS_DECL_NSIMENUROLLUP
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
|
||||
static nsXULPopupManager* sInstance;
|
||||
|
||||
// initialize and shutdown methods called by nsLayoutStatics
|
||||
static nsresult Init();
|
||||
static void Shutdown();
|
||||
|
||||
// returns a weak reference to the popup manager instance, could return null
|
||||
// if a popup manager could not be allocated
|
||||
static nsXULPopupManager* GetInstance();
|
||||
|
||||
// given a menu frame, find the prevous or next menu frame. If aPopup is
|
||||
// true then navigate a menupopup, from one item on the menu to the previous
|
||||
// or next one. This is used for cursor navigation between items in a popup
|
||||
// menu. If aIsPopup is false, the navigation is on a menubar, so navigate
|
||||
// between menus on the menubar. This is used for left/right cursor navigation.
|
||||
//
|
||||
// Items that not valid, such as non-menu or menuitem elements are skipped,
|
||||
// and the next or previous item after that is checked.
|
||||
//
|
||||
// If aStart is null, the first valid item is retrieved for GetNextMenuItem
|
||||
// or the last valid item for GetPreviousMenuItem is used.
|
||||
//
|
||||
// aParent - the parent menubar or menupopup
|
||||
// aStart - the menu/menuitem to start navigation from. GetPreviousMenuItem
|
||||
// returns the item before it, while GetNextMenuItem returns the
|
||||
// next item.
|
||||
// aIsPopup - true for menupopups, false for menubars
|
||||
static nsMenuFrame* GetPreviousMenuItem(nsIFrame* aParent,
|
||||
nsMenuFrame* aStart,
|
||||
PRBool aIsPopup);
|
||||
static nsMenuFrame* GetNextMenuItem(nsIFrame* aParent,
|
||||
nsMenuFrame* aStart,
|
||||
PRBool aIsPopup);
|
||||
|
||||
// returns true if the menu item aContent is a valid menuitem which may
|
||||
// be navigated to. aIsPopup should be true for items on a popup, or false
|
||||
// for items on a menubar.
|
||||
static PRBool IsValidMenuItem(nsPresContext* aPresContext,
|
||||
nsIContent* aContent,
|
||||
PRBool aOnPopup);
|
||||
|
||||
// inform the popup manager that a menu bar has been activated or deactivated,
|
||||
// either because one of its menus has opened or closed, or that the menubar
|
||||
// has been focused such that its menus may be navigated with the keyboard.
|
||||
// aActivate should be true when the menubar should be focused, and false
|
||||
// when the active menu bar should be defocused. In the latter case, if
|
||||
// aMenuBar isn't currently active, yet another menu bar is, that menu bar
|
||||
// will remain active.
|
||||
void SetActiveMenuBar(nsMenuBarFrame* aMenuBar, PRBool aActivate);
|
||||
|
||||
// retrieve the node and offset of the last mouse event used to open a
|
||||
// context menu. This information is determined from the rangeParent and
|
||||
// the rangeOffset of the event supplied from the last call to SetMouseLocation.
|
||||
// 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);
|
||||
|
||||
/**
|
||||
* Open a <menu> given its content node. If aSelectFirstItem is
|
||||
* set to true, the first item on the menu will automatically be
|
||||
* selected. If aAsynchronous is true, the event will be dispatched
|
||||
* asynchronously. This should be true when called from frame code.
|
||||
*/
|
||||
void ShowMenu(nsIContent *aMenu, PRBool aSelectFirstItem, PRBool aAsynchronous);
|
||||
|
||||
/**
|
||||
* Open a popup, either anchored or unanchored. If aSelectFirstItem is
|
||||
* true, then the first item in the menu is selected. The arguments are
|
||||
* similar to those for nsIPopupBoxObject::OpenPopup.
|
||||
*
|
||||
* This fires the popupshowing event synchronously.
|
||||
*/
|
||||
void ShowPopup(nsIContent* aPopup,
|
||||
nsIContent* aAnchorContent,
|
||||
const nsAString& aPosition,
|
||||
PRInt32 aXPos, PRInt32 aYPos,
|
||||
PRBool aIsContextMenu,
|
||||
PRBool aAttributesOverride,
|
||||
PRBool aSelectFirstItem);
|
||||
|
||||
/**
|
||||
* Open a popup at a specific screen position specified by aXPos and aYPos,
|
||||
* measured in CSS pixels.
|
||||
*
|
||||
* This fires the popupshowing event synchronously.
|
||||
*/
|
||||
void ShowPopupAtScreen(nsIContent* aPopup,
|
||||
PRInt32 aXPos, PRInt32 aYPos,
|
||||
PRBool aIsContextMenu);
|
||||
|
||||
/**
|
||||
* This method is provided only for compatibility with an older popup API.
|
||||
* New code should not call this function and should call ShowPopup instead.
|
||||
*
|
||||
* This fires the popupshowing event synchronously.
|
||||
*/
|
||||
void ShowPopupWithAnchorAlign(nsIContent* aPopup,
|
||||
nsIContent* aAnchorContent,
|
||||
nsAString& aAnchor,
|
||||
nsAString& aAlign,
|
||||
PRInt32 aXPos, PRInt32 aYPos,
|
||||
PRBool aIsContextMenu);
|
||||
|
||||
/*
|
||||
* Hide a popup aPopup. If the popup is in a <menu>, then also inform the
|
||||
* menu that the popup is being hidden.
|
||||
*
|
||||
* aHideChain - true if the entire chain of menus should be closed. If false,
|
||||
* only this popup is closed.
|
||||
* aDeselectMenu - true if the parent <menu> of the popup should be deselected.
|
||||
* This will be false when the menu is closed by pressing the
|
||||
* Escape key.
|
||||
* aAsynchronous - true if the first popuphiding event should be sent
|
||||
* asynchrously. This should be true if HidePopup is called
|
||||
* from a frame.
|
||||
*/
|
||||
void HidePopup(nsIContent* aPopup,
|
||||
PRBool aHideChain,
|
||||
PRBool aDeselectMenu,
|
||||
PRBool aAsynchronous);
|
||||
|
||||
/**
|
||||
* Hide a popup after a short delay. This is used when rolling over menu items.
|
||||
* This timer is stored in mCloseTimer. The timer may be cancelled and the popup
|
||||
* closed by calling KillMenuTimer.
|
||||
*/
|
||||
void HidePopupAfterDelay(nsMenuPopupFrame* aPopup);
|
||||
|
||||
/**
|
||||
* Hide all of the popups from a given document. This should be called when the
|
||||
* document is hidden.
|
||||
*/
|
||||
void HidePopupsInDocument(nsIDocument* aDocument);
|
||||
|
||||
/**
|
||||
* Execute a menu command from the triggering event aEvent.
|
||||
*
|
||||
* aMenu - a menuitem to execute
|
||||
* aEvent - the mouse event which triggered the menu to be executed,
|
||||
* may be null
|
||||
*/
|
||||
void ExecuteMenu(nsIContent* aMenu, nsEvent* aEvent);
|
||||
|
||||
/**
|
||||
* Return true if the popup for the supplied menu parent is open.
|
||||
*/
|
||||
PRBool IsPopupOpenForMenuParent(nsIMenuParent* aMenuParent);
|
||||
|
||||
/**
|
||||
* Return false if a popup may not be opened. This will return false if the
|
||||
* popup is already open, if the popup is in a content shell that is not
|
||||
* focused, or if it is a submenu of another menu that isn't open.
|
||||
*/
|
||||
PRBool MayShowPopup(nsMenuPopupFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Called when a popup frame is destroyed. In this case, just remove the
|
||||
* item and later popups from the list. No point going through HidePopup as
|
||||
* the frames have gone away.
|
||||
*/
|
||||
void PopupDestroyed(nsMenuPopupFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Returns true if there is a context menu open. If aPopup is specified,
|
||||
* then the context menu must be later in the chain than aPopup. If aPopup
|
||||
* is null, returns true if any context menu at all is open.
|
||||
*/
|
||||
PRBool HasContextMenu(nsMenuPopupFrame* aPopup);
|
||||
|
||||
/**
|
||||
* Update the commands for the menus within the menu popup for a given
|
||||
* content node. aPopup should be a XUL menupopup element. This method
|
||||
* changes attributes on the children of aPopup, and deals only with the
|
||||
* content of the popup, not the frames.
|
||||
*/
|
||||
void UpdateMenuItems(nsIContent* aPopup);
|
||||
|
||||
/**
|
||||
* Stop the timer which hides a popup after a delay, started by a previous
|
||||
* call to HidePopupAfterDelay. In addition, the popup awaiting to be hidden
|
||||
* is closed asynchronously.
|
||||
*/
|
||||
void KillMenuTimer();
|
||||
|
||||
/**
|
||||
* Handles navigation for menu accelkeys. Returns true if the key has
|
||||
* been handled.
|
||||
*/
|
||||
PRBool HandleShortcutNavigation(nsIDOMKeyEvent* aKeyEvent);
|
||||
|
||||
/**
|
||||
* Handles cursor navigation within a menu. Returns true if the key has
|
||||
* been handled.
|
||||
*/
|
||||
PRBool HandleKeyboardNavigation(PRUint32 aKeyCode);
|
||||
|
||||
NS_IMETHODIMP HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; }
|
||||
|
||||
NS_IMETHOD KeyUp(nsIDOMEvent* aKeyEvent);
|
||||
NS_IMETHOD KeyDown(nsIDOMEvent* aKeyEvent);
|
||||
NS_IMETHOD KeyPress(nsIDOMEvent* aKeyEvent);
|
||||
|
||||
protected:
|
||||
nsXULPopupManager();
|
||||
~nsXULPopupManager();
|
||||
|
||||
// get the frame for a content node aContent if the frame's type
|
||||
// matches aFrameType. Otherwise, return null.
|
||||
nsIFrame* GetFrameOfTypeForContent(nsIContent* aContent, nsIAtom* aFrameType);
|
||||
|
||||
// get the nsMenuFrame, if any, for the given content node
|
||||
nsMenuFrame* GetMenuFrameForContent(nsIContent* aContent);
|
||||
|
||||
// get the nsMenuPopupFrame, if any, for the given content node
|
||||
nsMenuPopupFrame* GetPopupFrameForContent(nsIContent* aContent);
|
||||
|
||||
// callbacks for ShowPopup and HidePopup as events may be done asynchronously
|
||||
void ShowPopupCallback(nsIContent* aPopup,
|
||||
nsMenuPopupFrame* aPopupFrame,
|
||||
PRBool aIsContextMenu,
|
||||
PRBool aSelectFirstItem);
|
||||
void HidePopupCallback(nsIContent* aPopup,
|
||||
nsMenuPopupFrame* aPopupFrame,
|
||||
nsIContent* aNextPopup,
|
||||
nsIContent* aLastPopup,
|
||||
PRBool aIsMenu,
|
||||
PRBool aDeselectMenu);
|
||||
|
||||
/**
|
||||
* Fire a popupshowing event on the popup aPopup and then open the popup.
|
||||
*
|
||||
* aPopup - the popup node to open
|
||||
* aMenu - should be set to the parent menu if this is a popup associated
|
||||
* with a menu. Otherwise, should be null.
|
||||
* aPresContext - the prescontext
|
||||
* aIsContextMenu - true for context menus
|
||||
* aSelectFirstItem - true to select the first item in the menu
|
||||
*/
|
||||
void FirePopupShowingEvent(nsIContent* aPopup,
|
||||
nsIContent* aMenu,
|
||||
nsPresContext* aPresContext,
|
||||
PRBool aIsContextMenu,
|
||||
PRBool aSelectFirstItem);
|
||||
|
||||
/**
|
||||
* Fire a popuphiding event and then hide the popup. This will be called
|
||||
* recursively if aNextPopup and aLastPopup are set in order to hide a chain
|
||||
* of open menus. If these are not set, only one popup is closed. However,
|
||||
* if aIsMenu is true, yet the next popup is not a menu, then this ends the
|
||||
* closing of popups. This allows a menulist inside a non-menu to close up
|
||||
* the menu but not close up the panel it is contained within.
|
||||
*
|
||||
* aPopup - the popup to hide
|
||||
* aNextPopup - the next popup to hide
|
||||
* aLastPopup - the last popup in the chain to hide
|
||||
* aPresContext - nsPresContext for the popup's frame
|
||||
* aIsMenu - true if aPopup is a menu.
|
||||
* aDeselectMenu - true to unhighlight the menu when hiding it
|
||||
*/
|
||||
void FirePopupHidingEvent(nsIContent* aPopup,
|
||||
nsIContent* aNextPopup,
|
||||
nsIContent* aLastPopup,
|
||||
nsPresContext *aPresContext,
|
||||
PRBool aIsMenu,
|
||||
PRBool aDeselectMenu);
|
||||
|
||||
// handle keyboard navigation within a menu popup. Returns true if the
|
||||
// key was handled and that other default handling should not occur.
|
||||
PRBool HandleKeyboardNavigationInPopup(nsMenuChainItem* item,
|
||||
nsNavigationDirection aDir);
|
||||
|
||||
/**
|
||||
* Set mouse capturing for the current popup. This traps mouse clicks that
|
||||
* occur outside the popup so that it can be closed up. aOldPopup should be
|
||||
* set to the popup that was previously the current popup.
|
||||
*/
|
||||
void SetCaptureState(nsIContent *aOldPopup);
|
||||
|
||||
/**
|
||||
* Key event listeners are attached to the document containing the current
|
||||
* menu for menu and shortcut navigation. Only one listener is needed at a
|
||||
* time, stored in mKeyListener, so switch it only if the document changes.
|
||||
* Having menus in different documents is very rare, so the listeners will
|
||||
* usually only be attached when the first menu opens and removed when all
|
||||
* menus have closed.
|
||||
*
|
||||
* This is also used when only a menubar is active without any open menus,
|
||||
* so that keyboard navigation between menus on the menubar may be done.
|
||||
*/
|
||||
void UpdateKeyboardListeners();
|
||||
|
||||
// the document the key event listener is attached to
|
||||
nsCOMPtr<nsIDOMEventTarget> mKeyListener;
|
||||
|
||||
// widget that is currently listening to rollup events
|
||||
nsCOMPtr<nsIWidget> mWidget;
|
||||
|
||||
// range parent and offset set in SetMouseLocation
|
||||
nsCOMPtr<nsIDOMNode> mRangeParent;
|
||||
PRInt32 mRangeOffset;
|
||||
|
||||
// set to the currently active menu bar, if any
|
||||
nsMenuBarFrame* mActiveMenuBar;
|
||||
|
||||
// linked list of dismissable menus.
|
||||
nsMenuChainItem* mCurrentMenu;
|
||||
|
||||
// linked list of panels
|
||||
nsMenuChainItem* mPanels;
|
||||
|
||||
// timer used for HidePopupAfterDelay
|
||||
nsCOMPtr<nsITimer> mCloseTimer;
|
||||
|
||||
// a popup that is waiting on the timer
|
||||
nsMenuPopupFrame* mTimerMenu;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -119,13 +119,14 @@ CPPSRCS += \
|
|||
nsMenuFrame.cpp \
|
||||
nsMenuBarFrame.cpp \
|
||||
nsMenuBarListener.cpp \
|
||||
nsMenuListener.cpp \
|
||||
nsMenuDismissalListener.cpp \
|
||||
nsPopupSetFrame.cpp \
|
||||
nsTitleBarFrame.cpp \
|
||||
nsResizerFrame.cpp \
|
||||
nsListBoxBodyFrame.cpp \
|
||||
nsListItemFrame.cpp \
|
||||
nsListBoxLayout.cpp \
|
||||
nsXULPopupManager.cpp \
|
||||
$(NULL)
|
||||
|
||||
endif
|
||||
|
|
|
@ -49,12 +49,13 @@
|
|||
#include "nsIAtom.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsBoxFrame.h"
|
||||
#include "nsMenuFrame.h"
|
||||
#include "nsMenuBarListener.h"
|
||||
#include "nsMenuListener.h"
|
||||
#include "nsIMenuParent.h"
|
||||
#include "nsIWidget.h"
|
||||
|
||||
class nsIContent;
|
||||
class nsIMenuFrame;
|
||||
|
||||
nsIFrame* NS_NewMenuBarFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
|
||||
|
||||
|
@ -62,25 +63,47 @@ class nsMenuBarFrame : public nsBoxFrame, public nsIMenuParent
|
|||
{
|
||||
public:
|
||||
nsMenuBarFrame(nsIPresShell* aShell, nsStyleContext* aContext);
|
||||
virtual ~nsMenuBarFrame();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIMenuParentInterface
|
||||
virtual nsMenuFrame* GetCurrentMenuItem();
|
||||
NS_IMETHOD SetCurrentMenuItem(nsMenuFrame* aMenuItem);
|
||||
virtual void CurrentMenuIsBeingDestroyed();
|
||||
NS_IMETHOD ChangeMenuItem(nsMenuFrame* aMenuItem, PRBool aSelectFirstItem);
|
||||
|
||||
virtual nsIMenuFrame* GetCurrentMenuItem();
|
||||
NS_IMETHOD SetCurrentMenuItem(nsIMenuFrame* aMenuItem);
|
||||
virtual nsIMenuFrame* GetNextMenuItem(nsIMenuFrame* aStart);
|
||||
virtual nsIMenuFrame* GetPreviousMenuItem(nsIMenuFrame* aStart);
|
||||
NS_IMETHOD SetActive(PRBool aActiveFlag);
|
||||
NS_IMETHOD GetIsActive(PRBool& isActive) { isActive = IsActive(); return NS_OK; }
|
||||
NS_IMETHOD IsMenuBar(PRBool& isMenuBar) { isMenuBar = PR_TRUE; return NS_OK; }
|
||||
NS_IMETHOD ConsumeOutsideClicks(PRBool& aConsumeOutsideClicks) \
|
||||
{aConsumeOutsideClicks = PR_FALSE; return NS_OK;}
|
||||
NS_IMETHOD ClearRecentlyRolledUp();
|
||||
NS_IMETHOD RecentlyRolledUp(nsIMenuFrame *aMenuFrame, PRBool *aJustRolledUp);
|
||||
|
||||
virtual PRBool IsMenuBar() { return PR_TRUE; }
|
||||
virtual PRBool IsContextMenu() { return PR_FALSE; }
|
||||
virtual PRBool IsActive() { return mIsActive; }
|
||||
virtual PRBool IsMenu() { return PR_FALSE; }
|
||||
virtual PRBool IsOpen() { return PR_TRUE; } // menubars are considered always open
|
||||
NS_IMETHOD SetIsContextMenu(PRBool aIsContextMenu) { return NS_OK; }
|
||||
NS_IMETHOD GetIsContextMenu(PRBool& aIsContextMenu) { aIsContextMenu = PR_FALSE; return NS_OK; }
|
||||
|
||||
PRBool IsMenuOpen() { return mCurrentMenu && mCurrentMenu->IsOpen(); }
|
||||
NS_IMETHOD GetParentPopup(nsIMenuParent** aResult) { *aResult = nsnull;
|
||||
return NS_OK;}
|
||||
|
||||
void InstallKeyboardNavigator();
|
||||
void RemoveKeyboardNavigator();
|
||||
NS_IMETHOD IsActive() { return mIsActive; }
|
||||
|
||||
NS_IMETHOD IsOpen();
|
||||
NS_IMETHOD KillPendingTimers();
|
||||
NS_IMETHOD CancelPendingTimers() { return NS_OK; }
|
||||
|
||||
// Closes up the chain of open cascaded menus.
|
||||
NS_IMETHOD DismissChain();
|
||||
|
||||
// Hides the chain of cascaded menus without closing them up.
|
||||
NS_IMETHOD HideChain();
|
||||
|
||||
NS_IMETHOD InstallKeyboardNavigator();
|
||||
NS_IMETHOD RemoveKeyboardNavigator();
|
||||
|
||||
NS_IMETHOD GetWidget(nsIWidget **aWidget);
|
||||
// The dismissal listener gets created and attached to the window.
|
||||
NS_IMETHOD AttachedDismissalListener() { return NS_OK; }
|
||||
|
||||
NS_IMETHOD Init(nsIContent* aContent,
|
||||
nsIFrame* aParent,
|
||||
|
@ -88,24 +111,24 @@ public:
|
|||
|
||||
virtual void Destroy();
|
||||
|
||||
virtual nsIAtom* GetType() const { return nsGkAtoms::menuBarFrame; }
|
||||
|
||||
// Non-interface helpers
|
||||
|
||||
// Called when a menu on the menu bar is clicked on. Returns a menu if one
|
||||
// needs to be closed.
|
||||
nsMenuFrame* ToggleMenuActiveState();
|
||||
// Called when a menu on the menu bar is clicked on.
|
||||
void ToggleMenuActiveState();
|
||||
|
||||
// indicate that a menu on the menubar was closed. Returns true if the caller
|
||||
// may deselect the menuitem.
|
||||
virtual PRBool MenuClosed();
|
||||
|
||||
// Called when Enter is pressed while the menubar is focused. If the current
|
||||
// menu is open, let the child handle the key.
|
||||
nsMenuFrame* Enter();
|
||||
// Used to move up, down, left, and right in menus.
|
||||
NS_IMETHOD KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag);
|
||||
NS_IMETHOD ShortcutNavigation(nsIDOMKeyEvent* aKeyEvent, PRBool& aHandledFlag);
|
||||
// Called when the ESC key is held down to close levels of menus.
|
||||
NS_IMETHOD Escape(PRBool& aHandledFlag);
|
||||
// Called to execute a menu item.
|
||||
NS_IMETHOD Enter();
|
||||
|
||||
// Used to handle ALT+key combos
|
||||
nsMenuFrame* FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent);
|
||||
nsIMenuFrame* FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent);
|
||||
|
||||
PRBool IsValidItem(nsIContent* aContent);
|
||||
PRBool IsDisabled(nsIContent* aContent);
|
||||
|
||||
virtual PRBool IsFrameOfType(PRUint32 aFlags) const
|
||||
{
|
||||
|
@ -124,11 +147,14 @@ public:
|
|||
|
||||
protected:
|
||||
nsMenuBarListener* mMenuBarListener; // The listener that tells us about key and mouse events.
|
||||
nsMenuListener* mKeyboardNavigator;
|
||||
|
||||
PRBool mIsActive; // Whether or not the menu bar is active (a menu item is highlighted or shown).
|
||||
// The current menu that is active (highlighted), which may not be open. This will
|
||||
// be null if no menu is active.
|
||||
nsMenuFrame* mCurrentMenu;
|
||||
nsIMenuFrame* mCurrentMenu; // The current menu that is active.
|
||||
|
||||
// Can contain a menu that was rolled up via nsIMenuDismissalListener::Rollup()
|
||||
// if nothing has happened since the last click. Otherwise, contains nsnull.
|
||||
nsIMenuFrame* mRecentRollupMenu;
|
||||
|
||||
nsIDOMEventTarget* mTarget;
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@
|
|||
|
||||
#include "nsMenuBarListener.h"
|
||||
#include "nsMenuBarFrame.h"
|
||||
#include "nsMenuPopupFrame.h"
|
||||
#include "nsIDOMKeyListener.h"
|
||||
#include "nsIDOMEventTarget.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
|
@ -132,18 +131,6 @@ void nsMenuBarListener::InitAccessKey()
|
|||
nsContentUtils::GetBoolPref("ui.key.menuAccessKeyFocuses");
|
||||
}
|
||||
|
||||
void
|
||||
nsMenuBarListener::ToggleMenuActiveState()
|
||||
{
|
||||
nsMenuFrame* closemenu = mMenuBarFrame->ToggleMenuActiveState();
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (pm && closemenu) {
|
||||
nsMenuPopupFrame* popupFrame = closemenu->GetPopup();
|
||||
if (popupFrame)
|
||||
pm->HidePopup(popupFrame->GetContent(), PR_FALSE, PR_FALSE, PR_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
nsresult
|
||||
nsMenuBarListener::KeyUp(nsIDOMEvent* aKeyEvent)
|
||||
|
@ -174,7 +161,7 @@ nsMenuBarListener::KeyUp(nsIDOMEvent* aKeyEvent)
|
|||
{
|
||||
// The access key was down and is now up, and no other
|
||||
// keys were pressed in between.
|
||||
ToggleMenuActiveState();
|
||||
mMenuBarFrame->ToggleMenuActiveState();
|
||||
}
|
||||
mAccessKeyDown = PR_FALSE;
|
||||
|
||||
|
@ -182,7 +169,7 @@ nsMenuBarListener::KeyUp(nsIDOMEvent* aKeyEvent)
|
|||
if (active) {
|
||||
aKeyEvent->StopPropagation();
|
||||
aKeyEvent->PreventDefault();
|
||||
return NS_OK; // I am consuming event
|
||||
return NS_ERROR_BASE; // I am consuming event
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -193,6 +180,8 @@ nsMenuBarListener::KeyUp(nsIDOMEvent* aKeyEvent)
|
|||
nsresult
|
||||
nsMenuBarListener::KeyPress(nsIDOMEvent* aKeyEvent)
|
||||
{
|
||||
mMenuBarFrame->ClearRecentlyRolledUp();
|
||||
|
||||
// if event has already been handled, bail
|
||||
nsCOMPtr<nsIDOMNSUIEvent> uiEvent ( do_QueryInterface(aKeyEvent) );
|
||||
if ( uiEvent ) {
|
||||
|
@ -240,13 +229,14 @@ nsMenuBarListener::KeyPress(nsIDOMEvent* aKeyEvent)
|
|||
// Do shortcut navigation.
|
||||
// A letter was pressed. We want to see if a shortcut gets matched. If
|
||||
// so, we'll know the menu got activated.
|
||||
nsMenuFrame* result = mMenuBarFrame->FindMenuWithShortcut(keyEvent);
|
||||
if (result) {
|
||||
mMenuBarFrame->SetActive(PR_TRUE);
|
||||
result->OpenMenu(PR_TRUE);
|
||||
PRBool active = PR_FALSE;
|
||||
mMenuBarFrame->ShortcutNavigation(keyEvent, active);
|
||||
|
||||
if (active) {
|
||||
aKeyEvent->StopPropagation();
|
||||
aKeyEvent->PreventDefault();
|
||||
retVal = NS_OK; // I am consuming event
|
||||
|
||||
retVal = NS_ERROR_BASE; // I am consuming event
|
||||
}
|
||||
}
|
||||
#if !defined(XP_MAC) && !defined(XP_MACOSX)
|
||||
|
@ -255,17 +245,16 @@ nsMenuBarListener::KeyPress(nsIDOMEvent* aKeyEvent)
|
|||
if ((GetModifiers(keyEvent) & ~MODIFIER_CONTROL) == 0) {
|
||||
// The F10 key just went down by itself or with ctrl pressed.
|
||||
// In Windows, both of these activate the menu bar.
|
||||
ToggleMenuActiveState();
|
||||
mMenuBarFrame->ToggleMenuActiveState();
|
||||
|
||||
aKeyEvent->StopPropagation();
|
||||
aKeyEvent->PreventDefault();
|
||||
return NS_OK; // consume the event
|
||||
return NS_ERROR_BASE; // consume the event
|
||||
}
|
||||
}
|
||||
#endif // !XP_MAC && !XP_MACOSX
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
@ -360,8 +349,10 @@ nsMenuBarListener::Focus(nsIDOMEvent* aEvent)
|
|||
nsresult
|
||||
nsMenuBarListener::Blur(nsIDOMEvent* aEvent)
|
||||
{
|
||||
if (!mMenuBarFrame->IsMenuOpen() && mMenuBarFrame->IsActive()) {
|
||||
ToggleMenuActiveState();
|
||||
if (!mMenuBarFrame->IsOpen() && mMenuBarFrame->IsActive()) {
|
||||
mMenuBarFrame->ToggleMenuActiveState();
|
||||
PRBool handled;
|
||||
mMenuBarFrame->Escape(handled);
|
||||
mAccessKeyDown = PR_FALSE;
|
||||
}
|
||||
return NS_OK; // means I am NOT consuming event
|
||||
|
@ -371,8 +362,12 @@ nsMenuBarListener::Blur(nsIDOMEvent* aEvent)
|
|||
nsresult
|
||||
nsMenuBarListener::MouseDown(nsIDOMEvent* aMouseEvent)
|
||||
{
|
||||
if (!mMenuBarFrame->IsMenuOpen() && mMenuBarFrame->IsActive())
|
||||
ToggleMenuActiveState();
|
||||
if (!mMenuBarFrame->IsOpen() && mMenuBarFrame->IsActive()) {
|
||||
mMenuBarFrame->ToggleMenuActiveState();
|
||||
PRBool handled;
|
||||
mMenuBarFrame->Escape(handled);
|
||||
}
|
||||
|
||||
mAccessKeyDown = PR_FALSE;
|
||||
|
||||
return NS_OK; // means I am NOT consuming event
|
||||
|
@ -382,6 +377,8 @@ nsMenuBarListener::MouseDown(nsIDOMEvent* aMouseEvent)
|
|||
nsresult
|
||||
nsMenuBarListener::MouseUp(nsIDOMEvent* aMouseEvent)
|
||||
{
|
||||
mMenuBarFrame->ClearRecentlyRolledUp();
|
||||
|
||||
return NS_OK; // means I am NOT consuming event
|
||||
}
|
||||
|
||||
|
|
|
@ -87,10 +87,6 @@ protected:
|
|||
|
||||
static PRUint32 GetModifiers(nsIDOMKeyEvent* event);
|
||||
|
||||
// This should only be called by the nsMenuBarListener during event dispatch,
|
||||
// thus ensuring that this doesn't get destroyed during the process.
|
||||
void ToggleMenuActiveState();
|
||||
|
||||
nsMenuBarFrame* mMenuBarFrame; // The menu bar object.
|
||||
PRBool mAccessKeyDown; // Whether or not the ALT key is currently down.
|
||||
static PRBool mAccessKeyFocuses; // Does the access key by itself focus the menubar?
|
||||
|
|
|
@ -39,12 +39,11 @@
|
|||
#include "nsIMenuBoxObject.h"
|
||||
#include "nsBoxObject.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsIMenuFrame.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsGUIEvent.h"
|
||||
#include "nsIDOMNSUIEvent.h"
|
||||
#include "nsMenuBarListener.h"
|
||||
#include "nsMenuFrame.h"
|
||||
#include "nsMenuPopupFrame.h"
|
||||
#include "nsPopupSetFrame.h"
|
||||
|
||||
class nsMenuBoxObject : public nsIMenuBoxObject, public nsBoxObject
|
||||
|
@ -90,41 +89,47 @@ nsMenuBoxObject::~nsMenuBoxObject()
|
|||
/* void openMenu (in boolean openFlag); */
|
||||
NS_IMETHODIMP nsMenuBoxObject::OpenMenu(PRBool aOpenFlag)
|
||||
{
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (pm) {
|
||||
nsIFrame* frame = GetFrame(PR_FALSE);
|
||||
if (frame) {
|
||||
if (aOpenFlag) {
|
||||
nsCOMPtr<nsIContent> content = mContent;
|
||||
pm->ShowMenu(content, PR_FALSE, PR_FALSE);
|
||||
}
|
||||
else {
|
||||
if (frame->GetType() == nsGkAtoms::menuFrame) {
|
||||
nsMenuPopupFrame* popupFrame = (NS_STATIC_CAST(nsMenuFrame *, frame))->GetPopup();
|
||||
if (popupFrame)
|
||||
pm->HidePopup(popupFrame->GetContent(), PR_FALSE, PR_TRUE, PR_FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!frame)
|
||||
return NS_OK;
|
||||
|
||||
if (!nsPopupSetFrame::MayOpenPopup(frame))
|
||||
return NS_OK;
|
||||
|
||||
nsIMenuFrame* menuFrame;
|
||||
CallQueryInterface(frame, &menuFrame);
|
||||
if (!menuFrame)
|
||||
return NS_OK;
|
||||
|
||||
return menuFrame->OpenMenu(aOpenFlag);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsMenuBoxObject::GetActiveChild(nsIDOMElement** aResult)
|
||||
{
|
||||
*aResult = nsnull;
|
||||
nsIFrame* frame = GetFrame(PR_FALSE);
|
||||
if (frame && frame->GetType() == nsGkAtoms::menuFrame)
|
||||
return NS_STATIC_CAST(nsMenuFrame *, frame)->GetActiveChild(aResult);
|
||||
if (!frame)
|
||||
return NS_OK;
|
||||
|
||||
nsIMenuFrame* menuFrame;
|
||||
CallQueryInterface(frame, &menuFrame);
|
||||
if (menuFrame)
|
||||
menuFrame->GetActiveChild(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsMenuBoxObject::SetActiveChild(nsIDOMElement* aResult)
|
||||
{
|
||||
nsIFrame* frame = GetFrame(PR_FALSE);
|
||||
if (frame && frame->GetType() == nsGkAtoms::menuFrame)
|
||||
return NS_STATIC_CAST(nsMenuFrame *, frame)->SetActiveChild(aResult);
|
||||
if (!frame)
|
||||
return NS_OK;
|
||||
|
||||
nsIMenuFrame* menuFrame;
|
||||
CallQueryInterface(frame, &menuFrame);
|
||||
if (menuFrame) {
|
||||
menuFrame->MarkAsGenerated();
|
||||
menuFrame->SetActiveChild(aResult);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -134,10 +139,6 @@ NS_IMETHODIMP nsMenuBoxObject::HandleKeyPress(nsIDOMKeyEvent* aKeyEvent, PRBool*
|
|||
*aHandledFlag = PR_FALSE;
|
||||
NS_ENSURE_ARG(aKeyEvent);
|
||||
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (!pm)
|
||||
return NS_OK;
|
||||
|
||||
// if event has already been handled, bail
|
||||
nsCOMPtr<nsIDOMNSUIEvent> uiEvent(do_QueryInterface(aKeyEvent));
|
||||
if (!uiEvent)
|
||||
|
@ -152,11 +153,12 @@ NS_IMETHODIMP nsMenuBoxObject::HandleKeyPress(nsIDOMKeyEvent* aKeyEvent, PRBool*
|
|||
return NS_OK;
|
||||
|
||||
nsIFrame* frame = GetFrame(PR_FALSE);
|
||||
if (!frame || frame->GetType() != nsGkAtoms::menuFrame)
|
||||
if (!frame)
|
||||
return NS_OK;
|
||||
|
||||
nsMenuPopupFrame* popupFrame = NS_STATIC_CAST(nsMenuFrame *, frame)->GetPopup();
|
||||
if (!popupFrame)
|
||||
nsIMenuFrame* menuFrame;
|
||||
CallQueryInterface(frame, &menuFrame);
|
||||
if (!menuFrame)
|
||||
return NS_OK;
|
||||
|
||||
PRUint32 keyCode;
|
||||
|
@ -166,11 +168,9 @@ NS_IMETHODIMP nsMenuBoxObject::HandleKeyPress(nsIDOMKeyEvent* aKeyEvent, PRBool*
|
|||
case NS_VK_DOWN:
|
||||
case NS_VK_HOME:
|
||||
case NS_VK_END:
|
||||
*aHandledFlag = pm->HandleKeyboardNavigation(keyCode);
|
||||
return NS_OK;
|
||||
return menuFrame->KeyboardNavigation(keyCode, *aHandledFlag);
|
||||
default:
|
||||
*aHandledFlag = pm->HandleShortcutNavigation(aKeyEvent);
|
||||
return NS_OK;
|
||||
return menuFrame->ShortcutNavigation(aKeyEvent, *aHandledFlag);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -49,10 +49,9 @@
|
|||
|
||||
#include "nsBoxFrame.h"
|
||||
#include "nsFrameList.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsIMenuParent.h"
|
||||
#include "nsIMenuFrame.h"
|
||||
#include "nsXULPopupManager.h"
|
||||
#include "nsMenuDismissalListener.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsISupportsArray.h"
|
||||
#include "nsIDOMText.h"
|
||||
|
@ -62,21 +61,11 @@
|
|||
nsIFrame* NS_NewMenuFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, PRUint32 aFlags);
|
||||
|
||||
class nsMenuBarFrame;
|
||||
class nsMenuPopupFrame;
|
||||
class nsIScrollableView;
|
||||
|
||||
#define NS_STATE_ACCELTEXT_IS_DERIVED NS_STATE_BOX_CHILD_RESERVED
|
||||
|
||||
// the type of menuitem
|
||||
enum nsMenuType {
|
||||
// a normal menuitem where a command is carried out when activated
|
||||
eMenuType_Normal = 0,
|
||||
// a menuitem with a checkmark that toggles when activated
|
||||
eMenuType_Checkbox = 1,
|
||||
// a radio menuitem where only one of it and its siblings with the same
|
||||
// name attribute can be checked at a time
|
||||
eMenuType_Radio = 2
|
||||
};
|
||||
|
||||
class nsMenuFrame;
|
||||
|
||||
/**
|
||||
|
@ -104,7 +93,7 @@ private:
|
|||
};
|
||||
|
||||
/**
|
||||
* @note *** Methods marked with '@see comment above ***' may cause the frame to be
|
||||
* @note *** Methods marked with '@see comment ***' may cause the frame to be
|
||||
* deleted during the method call. Be careful whenever using those
|
||||
* methods.
|
||||
*/
|
||||
|
@ -133,14 +122,14 @@ public:
|
|||
|
||||
NS_IMETHOD IsActive(PRBool& aResult) { aResult = PR_TRUE; return NS_OK; }
|
||||
|
||||
// The following methods are all overridden so that the menupopup
|
||||
// can be stored in a separate list, so that it doesn't impact reflow of the
|
||||
// actual menu item at all.
|
||||
// The following four methods are all overridden so that the menu children
|
||||
// can be stored in a separate list (so that they don't impact reflow of the
|
||||
// actual menu item at all).
|
||||
virtual nsIFrame* GetFirstChild(nsIAtom* aListName) const;
|
||||
NS_IMETHOD SetInitialChildList(nsIAtom* aListName,
|
||||
nsIFrame* aChildList);
|
||||
virtual nsIAtom* GetAdditionalChildListName(PRInt32 aIndex) const;
|
||||
virtual void Destroy(); // @see comment above ***
|
||||
virtual void Destroy(); // @see comment ***
|
||||
|
||||
// Overridden to prevent events from going to children of the menu.
|
||||
NS_IMETHOD BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder,
|
||||
|
@ -149,7 +138,7 @@ public:
|
|||
|
||||
NS_IMETHOD HandleEvent(nsPresContext* aPresContext,
|
||||
nsGUIEvent* aEvent,
|
||||
nsEventStatus* aEventStatus); // @see comment above ***
|
||||
nsEventStatus* aEventStatus); // @see comment ***
|
||||
|
||||
NS_IMETHOD AppendFrames(nsIAtom* aListName,
|
||||
nsIFrame* aFrameList);
|
||||
|
@ -161,35 +150,36 @@ public:
|
|||
NS_IMETHOD RemoveFrame(nsIAtom* aListName,
|
||||
nsIFrame* aOldFrame);
|
||||
|
||||
virtual nsIAtom* GetType() const { return nsGkAtoms::menuFrame; }
|
||||
// nsIMenuFrame Interface
|
||||
|
||||
NS_IMETHOD SelectMenu(PRBool aActivateFlag); // @see comment above ***
|
||||
NS_IMETHOD ActivateMenu(PRBool aActivateFlag); // @see comment ***
|
||||
NS_IMETHOD SelectMenu(PRBool aActivateFlag); // @see comment ***
|
||||
NS_IMETHOD OpenMenu(PRBool aActivateFlag); // @see comment ***
|
||||
|
||||
/**
|
||||
* NOTE: OpenMenu will open the menu synchronously. Don't call this if a frame
|
||||
* is manipulated afterwards without checking to make sure it is still alive.
|
||||
* All current calls to OpenMenu do not adjust the frame.
|
||||
*/
|
||||
void OpenMenu(PRBool aSelectFirstItem);
|
||||
// CloseMenu closes the menu asynchronously
|
||||
void CloseMenu(PRBool aDeselectMenu);
|
||||
|
||||
PRBool IsChecked() { return mChecked; }
|
||||
NS_IMETHOD MenuIsOpen(PRBool& aResult) { aResult = IsOpen(); return NS_OK; }
|
||||
NS_IMETHOD MenuIsContainer(PRBool& aResult) { aResult = IsMenu(); return NS_OK; }
|
||||
NS_IMETHOD MenuIsChecked(PRBool& aResult) { aResult = mChecked; return NS_OK; }
|
||||
NS_IMETHOD MenuIsDisabled(PRBool& aResult) { aResult = IsDisabled(); return NS_OK; }
|
||||
|
||||
NS_IMETHOD GetActiveChild(nsIDOMElement** aResult);
|
||||
NS_IMETHOD SetActiveChild(nsIDOMElement* aChild); // @see comment above ***
|
||||
NS_IMETHOD SetActiveChild(nsIDOMElement* aChild); // @see comment ***
|
||||
|
||||
// called when the Enter key is pressed while the menuitem is the current
|
||||
// one in its parent popup. This will carry out the command attached to
|
||||
// the menuitem.
|
||||
nsMenuFrame* Enter();
|
||||
NS_IMETHOD UngenerateMenu(); // @see comment ***
|
||||
|
||||
NS_IMETHOD SelectFirstItem(); // @see comment ***
|
||||
|
||||
NS_IMETHOD Escape(PRBool& aHandledFlag); // @see comment ***
|
||||
NS_IMETHOD Enter(); // @see comment ***
|
||||
NS_IMETHOD ShortcutNavigation(nsIDOMKeyEvent* aKeyEvent, PRBool& aHandledFlag); // @see comment ***
|
||||
NS_IMETHOD KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag); // @see comment ***
|
||||
|
||||
NS_IMETHOD SetParent(const nsIFrame* aParent);
|
||||
|
||||
virtual nsIMenuParent *GetMenuParent() { return mMenuParent; }
|
||||
const nsAString& GetRadioGroupName() { return mGroupName; }
|
||||
nsMenuType GetMenuType() { return mType; }
|
||||
nsMenuPopupFrame* GetPopup() { return mPopupFrame; }
|
||||
virtual nsIFrame *GetMenuChild() { return mPopupFrames.FirstChild(); }
|
||||
NS_IMETHOD GetRadioGroupName(nsString &aName) { aName = mGroupName; return NS_OK; }
|
||||
NS_IMETHOD GetMenuType(nsMenuType &aType) { aType = mType; return NS_OK; }
|
||||
NS_IMETHOD MarkAsGenerated();
|
||||
|
||||
// nsIScrollableViewProvider methods
|
||||
|
||||
|
@ -199,26 +189,12 @@ public:
|
|||
|
||||
nsresult DestroyPopupFrames(nsPresContext* aPresContext);
|
||||
|
||||
virtual PRBool IsOnMenuBar() { return mMenuParent && mMenuParent->IsMenuBar(); }
|
||||
virtual PRBool IsOnActiveMenuBar() { return IsOnMenuBar() && mMenuParent->IsActive(); }
|
||||
virtual PRBool IsOpen();
|
||||
virtual PRBool IsMenu();
|
||||
PRBool IsOpen() { return mMenuOpen; }
|
||||
PRBool IsMenu();
|
||||
PRBool IsDisabled();
|
||||
PRBool IsGenerated();
|
||||
void ToggleMenuState();
|
||||
NS_IMETHOD ToggleMenuState(); // @see comment ***
|
||||
|
||||
// indiciate that the menu's popup has just been opened, so that the menu
|
||||
// can update its open state. This method modifies the open attribute on
|
||||
// the menu, so the frames could be gone after this call
|
||||
void PopupOpened();
|
||||
// indiciate that the menu's popup has just been closed, so that the menu
|
||||
// can update its open state. The menu should be unhighlighted if
|
||||
// aDeselectedMenu is true.
|
||||
void PopupClosed(PRBool aDeselectMenu);
|
||||
|
||||
// returns true if this is a menu on another menu popup. A menu is a submenu
|
||||
// if it has a parent popup or menupopup.
|
||||
PRBool IsOnMenu() { return mMenuParent && mMenuParent->IsMenu(); }
|
||||
void SetIsMenu(PRBool aIsMenu) { mIsMenu = aIsMenu; }
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -230,27 +206,44 @@ public:
|
|||
|
||||
static PRBool IsSizedToPopup(nsIContent* aContent, PRBool aRequireAlways);
|
||||
|
||||
static nsIMenuParent *GetContextMenu();
|
||||
|
||||
protected:
|
||||
friend class nsMenuTimerMediator;
|
||||
|
||||
virtual void RePositionPopup(nsBoxLayoutState& aState);
|
||||
|
||||
void
|
||||
ConvertPosition(nsIContent* aPopupElt, nsString& aAnchor, nsString& aAlign);
|
||||
|
||||
friend class nsASyncMenuInitialization;
|
||||
void UpdateMenuType(nsPresContext* aPresContext); // @see comment ***
|
||||
void UpdateMenuSpecialState(nsPresContext* aPresContext); // @see comment ***
|
||||
|
||||
// set mMenuParent to the nearest enclosing menu bar or menupopup frame of
|
||||
// aParent (or aParent itself). This is called when initializing the frame,
|
||||
// so aParent should be the expected parent of this frame.
|
||||
void InitMenuParent(nsIFrame* aParent);
|
||||
|
||||
void UpdateMenuType(nsPresContext* aPresContext); // @see comment above ***
|
||||
void UpdateMenuSpecialState(nsPresContext* aPresContext); // @see comment above ***
|
||||
void OpenMenuInternal(PRBool aActivateFlag); // @see comment ***
|
||||
void GetMenuChildrenElement(nsIContent** aResult);
|
||||
|
||||
// Examines the key node and builds the accelerator.
|
||||
void BuildAcceleratorText();
|
||||
|
||||
// Called to execute our command handler.
|
||||
void Execute(nsGUIEvent *aEvent); // @see comment above ***
|
||||
void Execute(nsGUIEvent *aEvent); // @see comment ***
|
||||
|
||||
// Called as a hook just before the menu gets opened.
|
||||
PRBool OnCreate(); // @see comment ***
|
||||
|
||||
// Called as a hook just after the menu gets opened.
|
||||
PRBool OnCreated(); // @see comment ***
|
||||
|
||||
// Called as a hook just before the menu goes away.
|
||||
PRBool OnDestroy(); // @see comment ***
|
||||
|
||||
// Called as a hook just after the menu goes away.
|
||||
PRBool OnDestroyed(); // @see comment ***
|
||||
|
||||
NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
PRInt32 aModType); // @see comment above ***
|
||||
PRInt32 aModType); // @see comment ***
|
||||
virtual ~nsMenuFrame();
|
||||
|
||||
PRBool SizeToPopup(nsBoxLayoutState& aState, nsSize& aSize);
|
||||
|
@ -261,23 +254,22 @@ protected:
|
|||
#endif
|
||||
NS_HIDDEN_(nsresult) Notify(nsITimer* aTimer);
|
||||
|
||||
nsFrameList mPopupFrames;
|
||||
PRPackedBool mIsMenu; // Whether or not we can even have children or not.
|
||||
PRPackedBool mMenuOpen;
|
||||
PRPackedBool mCreateHandlerSucceeded; // Did the create handler succeed?
|
||||
PRPackedBool mChecked; // are we checked?
|
||||
nsMenuType mType;
|
||||
|
||||
nsIMenuParent* mMenuParent; // Our parent menu.
|
||||
|
||||
// the popup for this menu, owned
|
||||
nsMenuPopupFrame* mPopupFrame;
|
||||
|
||||
nsSize mLastPref;
|
||||
|
||||
// Reference to the mediator which wraps this frame.
|
||||
nsRefPtr<nsMenuTimerMediator> mTimerMediator;
|
||||
|
||||
nsCOMPtr<nsITimer> mOpenTimer;
|
||||
|
||||
nsString mGroupName;
|
||||
nsSize mLastPref;
|
||||
|
||||
//we load some display strings from platformKeys.properties only once
|
||||
static nsrefcnt gRefCnt;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -47,10 +47,9 @@
|
|||
|
||||
#include "prtypes.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsMenuFrame.h"
|
||||
#include "nsIDOMEventTarget.h"
|
||||
#include "nsMenuListener.h"
|
||||
|
||||
#include "nsBoxFrame.h"
|
||||
#include "nsIMenuParent.h"
|
||||
|
@ -58,20 +57,6 @@
|
|||
|
||||
#include "nsITimer.h"
|
||||
|
||||
enum nsPopupType {
|
||||
ePopupTypePanel,
|
||||
ePopupTypeMenu,
|
||||
ePopupTypeTooltip
|
||||
};
|
||||
|
||||
// values are selected so that the direction can be flipped just by
|
||||
// changing the sign
|
||||
#define POPUPALIGNMENT_NONE 0
|
||||
#define POPUPALIGNMENT_TOPLEFT 1
|
||||
#define POPUPALIGNMENT_TOPRIGHT -1
|
||||
#define POPUPALIGNMENT_BOTTOMLEFT 2
|
||||
#define POPUPALIGNMENT_BOTTOMRIGHT -2
|
||||
|
||||
#define INC_TYP_INTERVAL 1000 // 1s. If the interval between two keypresses is shorter than this,
|
||||
// treat as a continue typing
|
||||
// XXX, kyle.yuan@sun.com, there are 4 definitions for the same purpose:
|
||||
|
@ -84,54 +69,75 @@ nsIFrame* NS_NewMenuPopupFrame(nsIPresShell* aPresShell, nsStyleContext* aContex
|
|||
class nsIViewManager;
|
||||
class nsIView;
|
||||
class nsIMenuParent;
|
||||
class nsIMenuFrame;
|
||||
class nsIDOMXULDocument;
|
||||
|
||||
class nsMenuPopupFrame;
|
||||
|
||||
/**
|
||||
* nsMenuPopupTimerMediator is a wrapper around an nsMenuPopupFrame which can be safely
|
||||
* passed to timers. The class is reference counted unlike the underlying
|
||||
* nsMenuPopupFrame, so that it will exist as long as the timer holds a reference
|
||||
* to it. The callback is delegated to the contained nsMenuPopupFrame as long as
|
||||
* the contained nsMenuPopupFrame has not been destroyed.
|
||||
*/
|
||||
class nsMenuPopupTimerMediator : public nsITimerCallback
|
||||
{
|
||||
public:
|
||||
nsMenuPopupTimerMediator(nsMenuPopupFrame* aFrame);
|
||||
~nsMenuPopupTimerMediator();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
|
||||
void ClearFrame();
|
||||
|
||||
private:
|
||||
|
||||
// Pointer to the wrapped frame.
|
||||
nsMenuPopupFrame* mFrame;
|
||||
};
|
||||
|
||||
class nsMenuPopupFrame : public nsBoxFrame, public nsIMenuParent
|
||||
{
|
||||
public:
|
||||
nsMenuPopupFrame(nsIPresShell* aShell, nsStyleContext* aContext);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
|
||||
// nsIMenuParentInterface
|
||||
virtual nsMenuFrame* GetCurrentMenuItem();
|
||||
NS_IMETHOD SetCurrentMenuItem(nsMenuFrame* aMenuItem);
|
||||
virtual void CurrentMenuIsBeingDestroyed();
|
||||
NS_IMETHOD ChangeMenuItem(nsMenuFrame* aMenuItem, PRBool aSelectFirstItem);
|
||||
|
||||
// as popups are opened asynchronously, the popup pending state is used to
|
||||
// prevent multiple requests from attempting to open the same popup twice
|
||||
PRBool IsOpenPending() { return mIsOpenPending; }
|
||||
void ClearOpenPending() { mIsOpenPending = PR_FALSE; }
|
||||
|
||||
virtual nsIMenuFrame* GetCurrentMenuItem();
|
||||
NS_IMETHOD SetCurrentMenuItem(nsIMenuFrame* aMenuItem);
|
||||
virtual nsIMenuFrame* GetNextMenuItem(nsIMenuFrame* aStart);
|
||||
virtual nsIMenuFrame* GetPreviousMenuItem(nsIMenuFrame* aStart);
|
||||
NS_IMETHOD SetActive(PRBool aActiveFlag) { return NS_OK; } // We don't care.
|
||||
virtual PRBool IsActive() { return PR_FALSE; }
|
||||
virtual PRBool IsMenuBar() { return PR_FALSE; }
|
||||
NS_IMETHOD GetIsActive(PRBool& isActive) { isActive = PR_FALSE; return NS_OK; }
|
||||
NS_IMETHOD IsMenuBar(PRBool& isMenuBar) { isMenuBar = PR_FALSE; return NS_OK; }
|
||||
NS_IMETHOD ConsumeOutsideClicks(PRBool& aConsumeOutsideClicks);
|
||||
NS_IMETHOD ClearRecentlyRolledUp() {return NS_OK;}
|
||||
NS_IMETHOD RecentlyRolledUp(nsIMenuFrame *aMenuFrame, PRBool *aJustRolledUp) {*aJustRolledUp = PR_FALSE; return NS_OK;}
|
||||
NS_IMETHOD SetIsContextMenu(PRBool aIsContextMenu) { mIsContextMenu = aIsContextMenu; return NS_OK; }
|
||||
NS_IMETHOD GetIsContextMenu(PRBool& aIsContextMenu) { aIsContextMenu = mIsContextMenu; return NS_OK; }
|
||||
|
||||
/*
|
||||
* When this popup is open, should clicks outside of it be consumed?
|
||||
* Return PR_TRUE if the popup should rollup on an outside click,
|
||||
* but consume that click so it can't be used for anything else.
|
||||
* Return PR_FALSE to allow clicks outside the popup to activate content
|
||||
* even when the popup is open.
|
||||
* ---------------------------------------------------------------------
|
||||
*
|
||||
* Should clicks outside of a popup be eaten?
|
||||
*
|
||||
* Menus Autocomplete Comboboxes
|
||||
* Mac Eat No Eat
|
||||
* Win No No Eat
|
||||
* Unix Eat No Eat
|
||||
*
|
||||
*/
|
||||
PRBool ConsumeOutsideClicks();
|
||||
NS_IMETHOD GetParentPopup(nsIMenuParent** aResult);
|
||||
|
||||
virtual PRBool IsContextMenu() { return mIsContextMenu; }
|
||||
// Closes up the chain of open cascaded menus.
|
||||
NS_IMETHOD DismissChain();
|
||||
|
||||
virtual PRBool MenuClosed() { return PR_TRUE; }
|
||||
// Hides the chain of cascaded menus without closing them up.
|
||||
NS_IMETHOD HideChain();
|
||||
|
||||
NS_IMETHOD KillPendingTimers();
|
||||
NS_IMETHOD CancelPendingTimers();
|
||||
|
||||
NS_IMETHOD InstallKeyboardNavigator();
|
||||
NS_IMETHOD RemoveKeyboardNavigator();
|
||||
|
||||
NS_IMETHOD GetWidget(nsIWidget **aWidget);
|
||||
|
||||
// The dismissal listener gets created and attached to the window.
|
||||
void AttachedDismissalListener();
|
||||
NS_IMETHOD AttachedDismissalListener();
|
||||
|
||||
// Overridden methods
|
||||
NS_IMETHOD Init(nsIContent* aContent,
|
||||
|
@ -142,6 +148,10 @@ public:
|
|||
nsIAtom* aAttribute,
|
||||
PRInt32 aModType);
|
||||
|
||||
NS_IMETHOD HandleEvent(nsPresContext* aPresContext,
|
||||
nsGUIEvent* aEvent,
|
||||
nsEventStatus* aEventStatus);
|
||||
|
||||
virtual void Destroy();
|
||||
|
||||
virtual void InvalidateInternal(const nsRect& aDamageRect,
|
||||
|
@ -150,82 +160,29 @@ public:
|
|||
|
||||
virtual nsresult CreateWidgetForView(nsIView* aView);
|
||||
|
||||
NS_IMETHOD SetInitialChildList(nsIAtom* aListName,
|
||||
nsIFrame* aChildList);
|
||||
|
||||
virtual PRBool IsLeaf() const
|
||||
{
|
||||
if (!mGeneratedChildren && mPopupType == ePopupTypeMenu) {
|
||||
// menu popups generate their child frames lazily only when opened, so
|
||||
// behave like a leaf frame. However, generate child frames normally if
|
||||
// the parent menu has a sizetopopup attribute. In this case the size of
|
||||
// the parent menu is dependant on the size of the popup, so the frames
|
||||
// need to exist in order to calculate this size.
|
||||
nsIContent* parentContent = mContent->GetParent();
|
||||
if (parentContent &&
|
||||
!parentContent->HasAttr(kNameSpaceID_None, nsGkAtoms::sizetopopup))
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// AdjustView should be called by the parent frame after the popup has been
|
||||
// laid out, so that the view can be shown.
|
||||
void AdjustView();
|
||||
|
||||
void GetViewOffset(nsIView* aView, nsPoint& aPoint);
|
||||
nsIView* GetRootViewForPopup(nsIFrame* aStartFrame,
|
||||
PRBool aStopAtViewManagerRoot);
|
||||
static void GetRootViewForPopup(nsIFrame* aStartFrame,
|
||||
PRBool aStopAtViewManagerRoot,
|
||||
nsIView** aResult);
|
||||
|
||||
// set the position of the popup either relative to the anchor aAnchorFrame
|
||||
// (or the frame for mAnchorContent if aAnchorFrame is null) or at a specific
|
||||
// point if a screen position (mScreenXPos and mScreenYPos) are set. The popup
|
||||
// will be adjusted so that it is on screen.
|
||||
nsresult SetPopupPosition(nsIFrame* aAnchorFrame);
|
||||
nsresult SyncViewWithFrame(nsPresContext* aPresContext, const nsString& aPopupAnchor,
|
||||
const nsString& aPopupAlign,
|
||||
nsIFrame* aFrame, PRInt32 aXPos, PRInt32 aYPos);
|
||||
|
||||
PRBool HasGeneratedChildren() { return mGeneratedChildren; }
|
||||
void SetGeneratedChildren() { mGeneratedChildren = PR_TRUE; }
|
||||
NS_IMETHOD KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag);
|
||||
NS_IMETHOD ShortcutNavigation(nsIDOMKeyEvent* aKeyEvent, PRBool& aHandledFlag);
|
||||
|
||||
// called when the Enter key is pressed while the popup is open. This will
|
||||
// just pass the call down to the current menu, if any. Also, calling Enter
|
||||
// will reset the current incremental search string, calculated in
|
||||
// FindMenuWithShortcut
|
||||
nsMenuFrame* Enter();
|
||||
NS_IMETHOD Escape(PRBool& aHandledFlag);
|
||||
NS_IMETHOD Enter();
|
||||
|
||||
PRInt32 PopupType() const { return mPopupType; }
|
||||
PRBool IsMenu() { return mPopupType == ePopupTypeMenu; }
|
||||
PRBool IsOpen() { return mIsOpen; }
|
||||
PRBool HasOpenChanged() { return mIsOpenChanged; }
|
||||
nsIMenuFrame* FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent, PRBool& doAction);
|
||||
|
||||
// the Initialize methods are used to set the anchor position for
|
||||
// each way of opening a popup.
|
||||
void InitializePopup(nsIContent* aAnchorContent,
|
||||
const nsAString& aPosition,
|
||||
PRInt32 aXPos, PRInt32 aYPos,
|
||||
PRBool aAttributesOverride);
|
||||
PRBool IsValidItem(nsIContent* aContent);
|
||||
PRBool IsDisabled(nsIContent* aContent);
|
||||
|
||||
void InitializePopupAtScreen(PRInt32 aXPos, PRInt32 aYPos);
|
||||
nsIMenuParent* GetContextMenu();
|
||||
|
||||
void InitializePopupWithAnchorAlign(nsIContent* aAnchorContent,
|
||||
nsAString& aAnchor,
|
||||
nsAString& aAlign,
|
||||
PRInt32 aXPos, PRInt32 aYPos);
|
||||
|
||||
// indicate that the popup should be opened
|
||||
PRBool ShowPopup(PRBool aIsContextMenu, PRBool aSelectFirstItem);
|
||||
// indicate that the popup should be hidden
|
||||
void HidePopup(PRBool aDeselectMenu);
|
||||
|
||||
// locate and return the menu frame that should be activated for the
|
||||
// supplied key event. If doAction is set to true by this method,
|
||||
// then the menu's action should be carried out, as if the user had pressed
|
||||
// the Enter key. If doAction is false, the menu should just be highlighted.
|
||||
// This method also handles incremental searching in menus so the user can
|
||||
// type the first few letters of an item/s name to select it.
|
||||
nsMenuFrame* FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent, PRBool& doAction);
|
||||
|
||||
void ClearIncrementalString() { mIncrementalString.Truncate(); }
|
||||
NS_IMETHOD KillCloseTimer();
|
||||
|
||||
virtual nsIAtom* GetType() const { return nsGkAtoms::menuPopupFrame; }
|
||||
|
||||
|
@ -236,7 +193,7 @@ public:
|
|||
}
|
||||
#endif
|
||||
|
||||
void EnsureMenuItemIsVisible(nsMenuFrame* aMenuFrame);
|
||||
void EnsureMenuItemIsVisible(nsIMenuFrame* aMenuFrame);
|
||||
|
||||
// This sets 'left' and 'top' attributes.
|
||||
// May kill the frame.
|
||||
|
@ -244,21 +201,29 @@ public:
|
|||
|
||||
void GetAutoPosition(PRBool* aShouldAutoPosition);
|
||||
void SetAutoPosition(PRBool aShouldAutoPosition);
|
||||
void EnableRollup(PRBool aShouldRollup);
|
||||
void SetConsumeRollupEvent(PRUint32 aConsumeMode);
|
||||
|
||||
nsIScrollableView* GetScrollableView(nsIFrame* aStart);
|
||||
|
||||
protected:
|
||||
friend class nsMenuPopupTimerMediator;
|
||||
NS_HIDDEN_(nsresult) Notify(nsITimer* aTimer);
|
||||
|
||||
// Move without updating attributes.
|
||||
void MoveToInternal(PRInt32 aLeft, PRInt32 aTop);
|
||||
|
||||
// redefine to tell the box system not to move the views.
|
||||
// redefine to tell the box system not to move the
|
||||
// views.
|
||||
virtual void GetLayoutFlags(PRUint32& aFlags);
|
||||
|
||||
void InitPositionFromAnchorAlign(const nsAString& aAnchor,
|
||||
const nsAString& aAlign);
|
||||
// given x,y in client coordinates, compensate for nested documents like framesets.
|
||||
void AdjustClientXYForNestedDocuments ( nsIDOMXULDocument* inPopupDoc, nsIPresShell* inPopupShell,
|
||||
PRInt32 inClientX, PRInt32 inClientY,
|
||||
PRInt32* outAdjX, PRInt32* outAdjY ) ;
|
||||
|
||||
void AdjustPositionForAnchorAlign ( PRInt32* ioXPos, PRInt32* ioYPos, const nsRect & inParentRect,
|
||||
const nsString& aPopupAnchor, const nsString& aPopupAlign,
|
||||
PRBool* outFlushWithTopBottom ) ;
|
||||
|
||||
PRBool IsMoreRoomOnOtherSideOfParent ( PRBool inFlushAboveBelow, PRInt32 inScreenViewLocX, PRInt32 inScreenViewLocY,
|
||||
|
@ -273,33 +238,24 @@ protected:
|
|||
// Move the popup to the position specified in its |left| and |top| attributes.
|
||||
void MoveToAttributePosition();
|
||||
|
||||
// the content that the popup is anchored to, if any, which may be in a
|
||||
// different document than the popup.
|
||||
nsCOMPtr<nsIContent> mAnchorContent;
|
||||
|
||||
nsMenuFrame* mCurrentMenu; // The current menu that is active.
|
||||
nsIMenuFrame* mCurrentMenu; // The current menu that is active.
|
||||
|
||||
// popup alignment relative to the anchor node
|
||||
PRInt8 mPopupAlignment;
|
||||
PRInt8 mPopupAnchor;
|
||||
nsMenuListener* mKeyboardNavigator; // The listener that tells us about key events.
|
||||
nsIDOMEventTarget* mTarget;
|
||||
|
||||
// the position of the popup. The screen coordinates, if set to values other
|
||||
// than -1, override mXPos and mYPos.
|
||||
PRInt32 mXPos;
|
||||
PRInt32 mYPos;
|
||||
PRInt32 mScreenXPos;
|
||||
PRInt32 mScreenYPos;
|
||||
nsIMenuFrame* mTimerMenu; // A menu awaiting closure.
|
||||
nsCOMPtr<nsITimer> mCloseTimer; // Close timer.
|
||||
|
||||
nsPopupType mPopupType; // type of popup
|
||||
// Reference to the mediator which wraps this frame.
|
||||
nsRefPtr<nsMenuPopupTimerMediator> mTimerMediator;
|
||||
|
||||
PRPackedBool mIsOpen; // true if the popup is open
|
||||
PRPackedBool mIsOpenChanged; // true if the open state changed since the last layout
|
||||
PRPackedBool mIsOpenPending; // true if an open is pending
|
||||
PRPackedBool mIsContextMenu; // true for context menus
|
||||
PRPackedBool mGeneratedChildren; // true if the contents have been created
|
||||
PRPackedBool mIsContextMenu; // is this a context menu?
|
||||
|
||||
PRPackedBool mMenuCanOverlapOSBar; // can we appear over the taskbar/menubar?
|
||||
PRPackedBool mShouldAutoPosition; // Should SetPopupPosition be allowed to auto position popup?
|
||||
|
||||
PRPackedBool mShouldAutoPosition; // Should SyncViewWithFrame be allowed to auto position popup?
|
||||
PRPackedBool mShouldRollup; // Should this menupopup be allowed to dismiss automatically?
|
||||
PRPackedBool mConsumeRollupEvent; // Should the rollup event be consumed?
|
||||
PRPackedBool mInContentShell; // True if the popup is in a content shell
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIPopupBoxObject.h"
|
||||
#include "nsIPopupSetFrame.h"
|
||||
#include "nsIRootBox.h"
|
||||
#include "nsBoxObject.h"
|
||||
#include "nsIPresShell.h"
|
||||
|
@ -63,86 +64,87 @@ public:
|
|||
protected:
|
||||
virtual ~nsPopupBoxObject() {}
|
||||
|
||||
nsPopupSetFrame* GetPopupSetFrame();
|
||||
nsIPopupSetFrame* GetPopupSetFrame();
|
||||
nsMenuPopupFrame* GetMenuPopupFrame()
|
||||
{
|
||||
nsIFrame* frame = GetFrame(PR_FALSE);
|
||||
if (frame && frame->GetType() == nsGkAtoms::menuPopupFrame)
|
||||
return NS_STATIC_CAST(nsMenuPopupFrame*, frame);
|
||||
return nsnull;
|
||||
}
|
||||
{ return NS_STATIC_CAST(nsMenuPopupFrame*, GetFrame(PR_FALSE)); }
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED1(nsPopupBoxObject, nsBoxObject, nsIPopupBoxObject)
|
||||
|
||||
nsPopupSetFrame*
|
||||
nsIPopupSetFrame*
|
||||
nsPopupBoxObject::GetPopupSetFrame()
|
||||
{
|
||||
nsIRootBox* rootBox = nsIRootBox::GetRootBox(GetPresShell(PR_FALSE));
|
||||
if (!rootBox)
|
||||
return nsnull;
|
||||
|
||||
return rootBox->GetPopupSetFrame();
|
||||
nsIFrame* popupSetFrame = rootBox->GetPopupSetFrame();
|
||||
if (!popupSetFrame)
|
||||
return nsnull;
|
||||
|
||||
nsIPopupSetFrame *popupSet = nsnull;
|
||||
CallQueryInterface(popupSetFrame, &popupSet);
|
||||
return popupSet;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPopupBoxObject::HidePopup()
|
||||
{
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (pm)
|
||||
pm->HidePopup(mContent, PR_FALSE, PR_TRUE, PR_FALSE);
|
||||
nsIPopupSetFrame *popupSet = GetPopupSetFrame();
|
||||
nsIFrame *ourFrame = GetFrame(PR_FALSE);
|
||||
if (ourFrame && popupSet) {
|
||||
nsWeakFrame weakFrame(ourFrame);
|
||||
popupSet->HidePopup(ourFrame);
|
||||
if (weakFrame.IsAlive()) {
|
||||
popupSet->DestroyPopup(ourFrame, PR_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPopupBoxObject::ShowPopup(nsIDOMElement* aAnchorElement,
|
||||
nsIDOMElement* aPopupElement,
|
||||
nsPopupBoxObject::ShowPopup(nsIDOMElement* aSrcContent,
|
||||
nsIDOMElement* aPopupContent,
|
||||
PRInt32 aXPos, PRInt32 aYPos,
|
||||
const PRUnichar *aPopupType,
|
||||
const PRUnichar *aAnchorAlignment,
|
||||
const PRUnichar *anAnchorAlignment,
|
||||
const PRUnichar *aPopupAlignment)
|
||||
{
|
||||
NS_ENSURE_TRUE(aPopupElement, NS_ERROR_INVALID_ARG);
|
||||
nsIPopupSetFrame *popupSet = GetPopupSetFrame();
|
||||
if (!popupSet) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> srcContent(do_QueryInterface(aSrcContent));
|
||||
nsCOMPtr<nsIContent> popupContent(do_QueryInterface(aPopupContent));
|
||||
NS_ENSURE_TRUE(popupContent, NS_ERROR_INVALID_ARG);
|
||||
// srcContent can be null.
|
||||
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (pm) {
|
||||
nsCOMPtr<nsIContent> anchorContent(do_QueryInterface(aAnchorElement));
|
||||
nsAutoString popupType(aPopupType);
|
||||
nsAutoString anchor(aAnchorAlignment);
|
||||
nsAutoString align(aPopupAlignment);
|
||||
pm->ShowPopupWithAnchorAlign(mContent, anchorContent, anchor, align,
|
||||
aXPos, aYPos, popupType.EqualsLiteral("context"));
|
||||
nsAutoString anchorAlign(anAnchorAlignment);
|
||||
nsAutoString popupAlign(aPopupAlignment);
|
||||
|
||||
// Use |left| and |top| dimension attributes to position the popup if
|
||||
// present, as they may have been persisted.
|
||||
nsAutoString left, top;
|
||||
popupContent->GetAttr(kNameSpaceID_None, nsGkAtoms::left, left);
|
||||
popupContent->GetAttr(kNameSpaceID_None, nsGkAtoms::top, top);
|
||||
|
||||
PRInt32 err;
|
||||
if (!left.IsEmpty()) {
|
||||
aXPos = left.ToInteger(&err);
|
||||
if (NS_FAILED(err))
|
||||
return err;
|
||||
}
|
||||
if (!top.IsEmpty()) {
|
||||
aYPos = top.ToInteger(&err);
|
||||
if (NS_FAILED(err))
|
||||
return err;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPopupBoxObject::OpenPopup(nsIDOMElement* aAnchorElement,
|
||||
const nsAString& aPosition,
|
||||
PRInt32 aXPos, PRInt32 aYPos,
|
||||
PRBool aIsContextMenu,
|
||||
PRBool aAttributesOverride)
|
||||
{
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (pm) {
|
||||
nsCOMPtr<nsIContent> anchorContent(do_QueryInterface(aAnchorElement));
|
||||
pm->ShowPopup(mContent, anchorContent, aPosition, aXPos, aYPos,
|
||||
aIsContextMenu, aAttributesOverride, PR_FALSE);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPopupBoxObject::OpenPopupAtScreen(PRInt32 aXPos, PRInt32 aYPos, PRBool aIsContextMenu)
|
||||
{
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (pm)
|
||||
pm->ShowPopupAtScreen(mContent, aXPos, aYPos, aIsContextMenu);
|
||||
return NS_OK;
|
||||
return popupSet->ShowPopup(srcContent, popupContent, aXPos, aYPos,
|
||||
popupType, anchorAlign, popupAlign);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -195,7 +197,11 @@ nsPopupBoxObject::SetAutoPosition(PRBool aShouldAutoPosition)
|
|||
NS_IMETHODIMP
|
||||
nsPopupBoxObject::EnableRollup(PRBool aShouldRollup)
|
||||
{
|
||||
// this does nothing nows
|
||||
nsMenuPopupFrame *menuPopupFrame = GetMenuPopupFrame();
|
||||
if (menuPopupFrame) {
|
||||
menuPopupFrame->EnableRollup(aShouldRollup);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -213,12 +219,14 @@ nsPopupBoxObject::SetConsumeRollupEvent(PRUint32 aConsume)
|
|||
NS_IMETHODIMP
|
||||
nsPopupBoxObject::EnableKeyboardNavigator(PRBool aEnableKeyboardNavigator)
|
||||
{
|
||||
// Use ignorekeys="true" on the popup instead of using this function.
|
||||
if (aEnableKeyboardNavigator)
|
||||
mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::ignorekeys,
|
||||
NS_LITERAL_STRING("true"), PR_TRUE);
|
||||
else
|
||||
mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::ignorekeys, PR_TRUE);
|
||||
nsMenuPopupFrame *menuPopupFrame = GetMenuPopupFrame();
|
||||
if (menuPopupFrame) {
|
||||
if (aEnableKeyboardNavigator) {
|
||||
menuPopupFrame->InstallKeyboardNavigator();
|
||||
} else {
|
||||
menuPopupFrame->RemoveKeyboardNavigator();
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -234,3 +242,4 @@ NS_NewPopupBoxObject(nsIBoxObject** aResult)
|
|||
NS_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,16 +66,47 @@
|
|||
#include "nsCSSFrameConstructor.h"
|
||||
#include "nsGUIEvent.h"
|
||||
#include "nsIRootBox.h"
|
||||
#include "nsIFocusController.h"
|
||||
#include "nsIDocShellTreeItem.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsIBaseWindow.h"
|
||||
#include "nsIViewManager.h"
|
||||
|
||||
#define NS_MENU_POPUP_LIST_INDEX 0
|
||||
|
||||
nsPopupFrameList::nsPopupFrameList(nsIContent* aPopupContent, nsPopupFrameList* aNext)
|
||||
:mNextPopup(aNext),
|
||||
mPopupFrame(nsnull),
|
||||
mPopupContent(aPopupContent)
|
||||
mPopupContent(aPopupContent),
|
||||
mElementContent(nsnull),
|
||||
mCreateHandlerSucceeded(PR_FALSE),
|
||||
mIsOpen(PR_FALSE),
|
||||
mLastPref(-1,-1)
|
||||
{
|
||||
}
|
||||
|
||||
nsPopupFrameList* nsPopupFrameList::GetEntry(nsIContent* aPopupContent) {
|
||||
if (aPopupContent == mPopupContent)
|
||||
return this;
|
||||
|
||||
if (mNextPopup)
|
||||
return mNextPopup->GetEntry(aPopupContent);
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsPopupFrameList* nsPopupFrameList::GetEntryByFrame(nsIFrame* aPopupFrame) {
|
||||
if (aPopupFrame == mPopupFrame)
|
||||
return this;
|
||||
|
||||
if (mNextPopup)
|
||||
return mNextPopup->GetEntryByFrame(aPopupFrame);
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
//
|
||||
// NS_NewPopupSetFrame
|
||||
//
|
||||
|
@ -87,6 +118,25 @@ NS_NewPopupSetFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
|
|||
return new (aPresShell) nsPopupSetFrame (aPresShell, aContext);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsrefcnt)
|
||||
nsPopupSetFrame::AddRef(void)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsrefcnt)
|
||||
nsPopupSetFrame::Release(void)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// QueryInterface
|
||||
//
|
||||
NS_INTERFACE_MAP_BEGIN(nsPopupSetFrame)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIPopupSetFrame)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsBoxFrame)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPopupSetFrame::Init(nsIContent* aContent,
|
||||
nsIFrame* aParent,
|
||||
|
@ -148,15 +198,32 @@ nsPopupSetFrame::SetInitialChildList(nsIAtom* aListName,
|
|||
void
|
||||
nsPopupSetFrame::Destroy()
|
||||
{
|
||||
// remove each popup from the list as we go.
|
||||
// Remove our frame list.
|
||||
if (mPopupList) {
|
||||
// Try to hide any active popups
|
||||
if (nsMenuDismissalListener::sInstance) {
|
||||
nsIMenuParent *menuParent =
|
||||
nsMenuDismissalListener::sInstance->GetCurrentMenuParent();
|
||||
nsIFrame* frame;
|
||||
CallQueryInterface(menuParent, &frame);
|
||||
// Rollup popups, but only if they're ours
|
||||
if (frame && mPopupList->GetEntryByFrame(frame)) {
|
||||
nsMenuDismissalListener::sInstance->Rollup();
|
||||
}
|
||||
}
|
||||
|
||||
// Actually remove each popup from the list as we go. This
|
||||
// keeps things consistent so reentering won't crash us
|
||||
while (mPopupList) {
|
||||
if (mPopupList->mPopupFrame)
|
||||
if (mPopupList->mPopupFrame) {
|
||||
mPopupList->mPopupFrame->Destroy();
|
||||
}
|
||||
|
||||
nsPopupFrameList* temp = mPopupList;
|
||||
mPopupList = mPopupList->mNextPopup;
|
||||
delete temp;
|
||||
}
|
||||
}
|
||||
|
||||
nsIRootBox *rootBox;
|
||||
nsresult res = CallQueryInterface(mParent->GetParent(), &rootBox);
|
||||
|
@ -177,8 +244,10 @@ nsPopupSetFrame::DoLayout(nsBoxLayoutState& aState)
|
|||
// lay out all of our currently open popups.
|
||||
nsPopupFrameList* currEntry = mPopupList;
|
||||
while (currEntry) {
|
||||
nsMenuPopupFrame* popupChild = currEntry->mPopupFrame;
|
||||
if (popupChild && popupChild->IsOpen()) {
|
||||
nsIFrame* popupChild = currEntry->mPopupFrame;
|
||||
if (popupChild) {
|
||||
NS_ASSERTION(popupChild->IsBoxFrame(), "popupChild is not box!!");
|
||||
|
||||
// then get its preferred size
|
||||
nsSize prefSize = popupChild->GetPrefSize(aState);
|
||||
nsSize minSize = popupChild->GetMinSize(aState);
|
||||
|
@ -186,8 +255,13 @@ nsPopupSetFrame::DoLayout(nsBoxLayoutState& aState)
|
|||
|
||||
BoundsCheck(minSize, prefSize, maxSize);
|
||||
|
||||
// if the pref size changed then set bounds to be the pref size
|
||||
// and sync the view. Also set new pref size.
|
||||
// if (currEntry->mLastPref != prefSize) {
|
||||
popupChild->SetBounds(aState, nsRect(0,0,prefSize.width, prefSize.height));
|
||||
popupChild->SetPopupPosition(nsnull);
|
||||
RepositionPopup(currEntry, aState);
|
||||
currEntry->mLastPref = prefSize;
|
||||
// }
|
||||
|
||||
// is the new size too small? Make sure we handle scrollbars correctly
|
||||
nsIBox* child = popupChild->GetChildBox();
|
||||
|
@ -206,6 +280,7 @@ nsPopupSetFrame::DoLayout(nsBoxLayoutState& aState)
|
|||
if (bounds.width < prefSize.width + scrollbars.left + scrollbars.right)
|
||||
{
|
||||
bounds.width += scrollbars.left + scrollbars.right;
|
||||
//printf("Width=%d\n",width);
|
||||
popupChild->SetBounds(aState, bounds);
|
||||
}
|
||||
}
|
||||
|
@ -213,15 +288,483 @@ nsPopupSetFrame::DoLayout(nsBoxLayoutState& aState)
|
|||
|
||||
// layout the child
|
||||
popupChild->Layout(aState);
|
||||
popupChild->AdjustView();
|
||||
|
||||
// only size popup if open
|
||||
if (currEntry->mCreateHandlerSucceeded) {
|
||||
nsIView* view = popupChild->GetView();
|
||||
nsIViewManager* viewManager = view->GetViewManager();
|
||||
nsRect r(0, 0, bounds.width, bounds.height);
|
||||
viewManager->ResizeView(view, r);
|
||||
viewManager->SetViewVisibility(view, nsViewVisibility_kShow);
|
||||
}
|
||||
}
|
||||
|
||||
currEntry = currEntry->mNextPopup;
|
||||
}
|
||||
|
||||
SyncLayout(aState);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG_LAYOUT
|
||||
NS_IMETHODIMP
|
||||
nsPopupSetFrame::SetDebug(nsBoxLayoutState& aState, PRBool aDebug)
|
||||
{
|
||||
// see if our state matches the given debug state
|
||||
PRBool debugSet = mState & NS_STATE_CURRENTLY_IN_DEBUG;
|
||||
PRBool debugChanged = (!aDebug && debugSet) || (aDebug && !debugSet);
|
||||
|
||||
// if it doesn't then tell each child below us the new debug state
|
||||
if (debugChanged)
|
||||
{
|
||||
// XXXdwh fix later. nobody uses this anymore anyway.
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsPopupSetFrame::SetDebug(nsBoxLayoutState& aState, nsIFrame* aList, PRBool aDebug)
|
||||
{
|
||||
if (!aList)
|
||||
return NS_OK;
|
||||
|
||||
while (aList) {
|
||||
if (aList->IsBoxFrame())
|
||||
aList->SetDebug(aState, aDebug);
|
||||
|
||||
aList = aList->GetNextSibling();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
nsPopupSetFrame::RepositionPopup(nsPopupFrameList* aEntry, nsBoxLayoutState& aState)
|
||||
{
|
||||
// Sync up the view.
|
||||
if (aEntry && aEntry->mElementContent) {
|
||||
nsPresContext* presContext = aState.PresContext();
|
||||
nsIFrame* frameToSyncTo = presContext->PresShell()->
|
||||
GetPrimaryFrameFor(aEntry->mElementContent);
|
||||
((nsMenuPopupFrame*)(aEntry->mPopupFrame))->SyncViewWithFrame(presContext,
|
||||
aEntry->mPopupAnchor, aEntry->mPopupAlign, frameToSyncTo, aEntry->mXPos, aEntry->mYPos);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPopupSetFrame::ShowPopup(nsIContent* aElementContent, nsIContent* aPopupContent,
|
||||
PRInt32 aXPos, PRInt32 aYPos,
|
||||
const nsString& aPopupType, const nsString& anAnchorAlignment,
|
||||
const nsString& aPopupAlignment)
|
||||
{
|
||||
if (!MayOpenPopup(this))
|
||||
return NS_OK;
|
||||
|
||||
nsWeakFrame weakFrame(this);
|
||||
// First fire the popupshowing event.
|
||||
if (!OnCreate(aXPos, aYPos, aPopupContent) || !weakFrame.IsAlive())
|
||||
return NS_OK;
|
||||
|
||||
// See if we already have an entry in our list. We must create a new one on a miss.
|
||||
nsPopupFrameList* entry = nsnull;
|
||||
if (mPopupList)
|
||||
entry = mPopupList->GetEntry(aPopupContent);
|
||||
if (!entry) {
|
||||
entry = new nsPopupFrameList(aPopupContent, mPopupList);
|
||||
if (!entry)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
mPopupList = entry;
|
||||
}
|
||||
|
||||
// Cache the element content we're supposed to sync to
|
||||
entry->mPopupType = aPopupType;
|
||||
entry->mElementContent = aElementContent;
|
||||
entry->mPopupAlign = aPopupAlignment;
|
||||
entry->mPopupAnchor = anAnchorAlignment;
|
||||
entry->mXPos = aXPos;
|
||||
entry->mYPos = aYPos;
|
||||
|
||||
// If a frame exists already, go ahead and use it.
|
||||
entry->mPopupFrame = PresContext()->PresShell()
|
||||
->GetPrimaryFrameFor(aPopupContent);
|
||||
|
||||
#ifdef DEBUG_PINK
|
||||
printf("X Pos: %d\n", mXPos);
|
||||
printf("Y Pos: %d\n", mYPos);
|
||||
#endif
|
||||
|
||||
// Generate the popup.
|
||||
entry->mCreateHandlerSucceeded = PR_TRUE;
|
||||
entry->mIsOpen = PR_TRUE;
|
||||
// This may destroy or change entry->mPopupFrame or remove the entry from
|
||||
// mPopupList. |this| may also get deleted.
|
||||
MarkAsGenerated(aPopupContent);
|
||||
|
||||
if (!weakFrame.IsAlive()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsPopupFrameList* newEntry =
|
||||
mPopupList ? mPopupList->GetEntry(aPopupContent) : nsnull;
|
||||
if (!newEntry || newEntry != entry) {
|
||||
NS_WARNING("The popup entry for aPopupContent has changed!");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// determine if this menu is a context menu and flag it
|
||||
nsIMenuParent* childPopup = nsnull;
|
||||
if (entry->mPopupFrame)
|
||||
CallQueryInterface(entry->mPopupFrame, &childPopup);
|
||||
if ( childPopup && aPopupType.EqualsLiteral("context") )
|
||||
childPopup->SetIsContextMenu(PR_TRUE);
|
||||
|
||||
// Now open the popup.
|
||||
OpenPopup(entry, PR_TRUE);
|
||||
|
||||
if (!weakFrame.IsAlive()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Now fire the popupshown event.
|
||||
OnCreated(aXPos, aYPos, aPopupContent);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPopupSetFrame::HidePopup(nsIFrame* aPopup)
|
||||
{
|
||||
if (!mPopupList)
|
||||
return NS_OK; // No active popups
|
||||
|
||||
nsPopupFrameList* entry = mPopupList->GetEntryByFrame(aPopup);
|
||||
if (!entry)
|
||||
return NS_OK;
|
||||
|
||||
if (entry->mCreateHandlerSucceeded)
|
||||
ActivatePopup(entry, PR_FALSE);
|
||||
|
||||
if (entry->mElementContent && entry->mPopupType.EqualsLiteral("context")) {
|
||||
// If we are a context menu, and if we are attached to a
|
||||
// menupopup, then hiding us should also hide the parent menu
|
||||
// popup.
|
||||
if (entry->mElementContent->Tag() == nsGkAtoms::menupopup) {
|
||||
nsIFrame* popupFrame = PresContext()->PresShell()
|
||||
->GetPrimaryFrameFor(entry->mElementContent);
|
||||
if (popupFrame) {
|
||||
nsIMenuParent *menuParent;
|
||||
if (NS_SUCCEEDED(CallQueryInterface(popupFrame, &menuParent))) {
|
||||
menuParent->HideChain();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPopupSetFrame::DestroyPopup(nsIFrame* aPopup, PRBool aDestroyEntireChain)
|
||||
{
|
||||
if (!mPopupList)
|
||||
return NS_OK; // No active popups
|
||||
|
||||
nsPopupFrameList* entry = mPopupList->GetEntryByFrame(aPopup);
|
||||
|
||||
if (entry && entry->mCreateHandlerSucceeded) { // ensure the popup was created before we try to destroy it
|
||||
nsWeakFrame weakFrame(this);
|
||||
OpenPopup(entry, PR_FALSE);
|
||||
nsCOMPtr<nsIContent> popupContent = entry->mPopupContent;
|
||||
if (weakFrame.IsAlive()) {
|
||||
if (aDestroyEntireChain && entry->mElementContent && entry->mPopupType.EqualsLiteral("context")) {
|
||||
// If we are a context menu, and if we are attached to a
|
||||
// menupopup, then destroying us should also dismiss the parent
|
||||
// menu popup.
|
||||
if (entry->mElementContent->Tag() == nsGkAtoms::menupopup) {
|
||||
nsIFrame* popupFrame = PresContext()->PresShell()
|
||||
->GetPrimaryFrameFor(entry->mElementContent);
|
||||
if (popupFrame) {
|
||||
nsIMenuParent *menuParent;
|
||||
if (NS_SUCCEEDED(CallQueryInterface(popupFrame, &menuParent))) {
|
||||
menuParent->DismissChain();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clear things out for next time
|
||||
entry->mPopupType.Truncate();
|
||||
entry->mCreateHandlerSucceeded = PR_FALSE;
|
||||
entry->mElementContent = nsnull;
|
||||
entry->mXPos = entry->mYPos = 0;
|
||||
entry->mLastPref.width = -1;
|
||||
entry->mLastPref.height = -1;
|
||||
}
|
||||
// ungenerate the popup.
|
||||
popupContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::menugenerated, PR_TRUE);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsPopupSetFrame::MarkAsGenerated(nsIContent* aPopupContent)
|
||||
{
|
||||
// Set our attribute, but only if we aren't already generated.
|
||||
// Retrieve the menugenerated attribute.
|
||||
if (!aPopupContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::menugenerated,
|
||||
nsGkAtoms::_true, eCaseMatters)) {
|
||||
// Generate this element.
|
||||
aPopupContent->SetAttr(kNameSpaceID_None, nsGkAtoms::menugenerated, NS_LITERAL_STRING("true"),
|
||||
PR_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsPopupSetFrame::OpenPopup(nsPopupFrameList* aEntry, PRBool aActivateFlag)
|
||||
{
|
||||
nsWeakFrame weakFrame(this);
|
||||
nsIFrame* activeChild = aEntry->mPopupFrame;
|
||||
nsWeakFrame weakPopupFrame(activeChild);
|
||||
nsRefPtr<nsPresContext> presContext = PresContext();
|
||||
nsCOMPtr<nsIContent> popupContent = aEntry->mPopupContent;
|
||||
PRBool createHandlerSucceeded = aEntry->mCreateHandlerSucceeded;
|
||||
nsAutoString popupType = aEntry->mPopupType;
|
||||
if (aActivateFlag) {
|
||||
ActivatePopup(aEntry, PR_TRUE);
|
||||
|
||||
// register the rollup listeners, etc, but not if we're a tooltip
|
||||
if (!popupType.EqualsLiteral("tooltip")) {
|
||||
nsIMenuParent* childPopup = nsnull;
|
||||
if (weakPopupFrame.IsAlive())
|
||||
CallQueryInterface(activeChild, &childPopup);
|
||||
|
||||
// Tooltips don't get keyboard navigation
|
||||
if (childPopup && !nsMenuDismissalListener::sInstance) {
|
||||
// First check and make sure this popup wants keyboard navigation
|
||||
if (!popupContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::ignorekeys,
|
||||
nsGkAtoms::_true, eCaseMatters))
|
||||
childPopup->InstallKeyboardNavigator();
|
||||
}
|
||||
|
||||
nsMenuDismissalListener* listener = nsMenuDismissalListener::GetInstance();
|
||||
if (listener)
|
||||
listener->SetCurrentMenuParent(childPopup);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (createHandlerSucceeded && !OnDestroy(popupContent))
|
||||
return;
|
||||
|
||||
// Unregister, but not if we're a tooltip
|
||||
if (!popupType.EqualsLiteral("tooltip") ) {
|
||||
nsMenuDismissalListener::Shutdown();
|
||||
}
|
||||
|
||||
// Remove any keyboard navigators
|
||||
nsIMenuParent* childPopup = nsnull;
|
||||
if (weakPopupFrame.IsAlive())
|
||||
CallQueryInterface(activeChild, &childPopup);
|
||||
if (childPopup)
|
||||
childPopup->RemoveKeyboardNavigator();
|
||||
|
||||
if (weakPopupFrame.IsAlive())
|
||||
ActivatePopup(aEntry, PR_FALSE);
|
||||
|
||||
OnDestroyed(presContext, popupContent);
|
||||
}
|
||||
|
||||
if (weakFrame.IsAlive()) {
|
||||
PresContext()->PresShell()->
|
||||
FrameNeedsReflow(this, nsIPresShell::eTreeChange,
|
||||
NS_FRAME_HAS_DIRTY_CHILDREN);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsPopupSetFrame::ActivatePopup(nsPopupFrameList* aEntry, PRBool aActivateFlag)
|
||||
{
|
||||
if (aEntry->mPopupContent) {
|
||||
// When we sync the popup view with the frame, we'll show the popup if |menutobedisplayed|
|
||||
// is set by setting the |menuactive| attribute. This used to trip css into showing the menu
|
||||
// but now we do it ourselves.
|
||||
if (aActivateFlag)
|
||||
// XXXben hook in |width| and |height| usage here?
|
||||
aEntry->mPopupContent->SetAttr(kNameSpaceID_None, nsGkAtoms::menutobedisplayed, NS_LITERAL_STRING("true"), PR_TRUE);
|
||||
else {
|
||||
nsWeakFrame weakFrame(this);
|
||||
nsWeakFrame weakActiveChild(aEntry->mPopupFrame);
|
||||
nsCOMPtr<nsIContent> content = aEntry->mPopupContent;
|
||||
content->UnsetAttr(kNameSpaceID_None, nsGkAtoms::menuactive, PR_TRUE);
|
||||
content->UnsetAttr(kNameSpaceID_None, nsGkAtoms::menutobedisplayed, PR_TRUE);
|
||||
|
||||
// get rid of the reflows we just created. If we leave them hanging around, we
|
||||
// can get into trouble if a dialog with a modal event loop comes along and
|
||||
// processes the reflows before we get to call DestroyChain(). Processing the
|
||||
// reflow will cause the popup to show itself again. (bug 71219)
|
||||
nsIDocument* doc = content->GetDocument();
|
||||
if (doc)
|
||||
doc->FlushPendingNotifications(Flush_OnlyReflow);
|
||||
|
||||
// make sure we hide the popup. We can't assume that we'll have a view
|
||||
// since we could be cleaning up after someone that didn't correctly
|
||||
// destroy the popup.
|
||||
if (weakFrame.IsAlive() && weakActiveChild.IsAlive()) {
|
||||
nsIView* view = weakActiveChild.GetFrame()->GetView();
|
||||
NS_ASSERTION(view, "View is gone, looks like someone forgot to roll up the popup!");
|
||||
if (view) {
|
||||
nsIViewManager* viewManager = view->GetViewManager();
|
||||
viewManager->SetViewVisibility(view, nsViewVisibility_kHide);
|
||||
nsRect r(0, 0, 0, 0);
|
||||
viewManager->ResizeView(view, r);
|
||||
if (aEntry->mIsOpen) {
|
||||
aEntry->mIsOpen = PR_FALSE;
|
||||
FireDOMEventSynch(NS_LITERAL_STRING("DOMMenuInactive"), content);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsPopupSetFrame::OnCreate(PRInt32 aX, PRInt32 aY, nsIContent* aPopupContent)
|
||||
{
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
nsMouseEvent event(PR_TRUE, NS_XUL_POPUP_SHOWING, nsnull,
|
||||
nsMouseEvent::eReal);
|
||||
// XXX This is messed up: it needs to account for widgets.
|
||||
nsPoint dummy;
|
||||
event.widget = GetClosestView()->GetNearestWidget(&dummy);
|
||||
event.refPoint.x = aX;
|
||||
event.refPoint.y = aY;
|
||||
|
||||
if (aPopupContent) {
|
||||
nsCOMPtr<nsIContent> kungFuDeathGrip(aPopupContent);
|
||||
nsCOMPtr<nsIPresShell> shell = PresContext()->GetPresShell();
|
||||
if (shell) {
|
||||
nsresult rv = shell->HandleDOMEventWithTarget(aPopupContent, &event,
|
||||
&status);
|
||||
if ( NS_FAILED(rv) || status == nsEventStatus_eConsumeNoDefault )
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(aPopupContent->GetDocument()));
|
||||
if (!domDoc) return PR_FALSE;
|
||||
|
||||
// The menu is going to show, and the create handler has executed.
|
||||
// We should now walk all of our menu item children, checking to see if any
|
||||
// of them has a command attribute. If so, then several attributes must
|
||||
// potentially be updated.
|
||||
|
||||
PRUint32 count = aPopupContent->GetChildCount();
|
||||
for (PRUint32 i = 0; i < count; i++) {
|
||||
nsCOMPtr<nsIContent> grandChild = aPopupContent->GetChildAt(i);
|
||||
|
||||
if (grandChild->Tag() == nsGkAtoms::menuitem) {
|
||||
// See if we have a command attribute.
|
||||
nsAutoString command;
|
||||
grandChild->GetAttr(kNameSpaceID_None, nsGkAtoms::command, command);
|
||||
if (!command.IsEmpty()) {
|
||||
// We do! Look it up in our document
|
||||
nsCOMPtr<nsIDOMElement> commandElt;
|
||||
domDoc->GetElementById(command, getter_AddRefs(commandElt));
|
||||
nsCOMPtr<nsIContent> commandContent(do_QueryInterface(commandElt));
|
||||
if ( commandContent ) {
|
||||
nsAutoString commandValue;
|
||||
// The menu's disabled state needs to be updated to match the command.
|
||||
if (commandContent->GetAttr(kNameSpaceID_None, nsGkAtoms::disabled, commandValue))
|
||||
grandChild->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled, commandValue, PR_TRUE);
|
||||
else
|
||||
grandChild->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, PR_TRUE);
|
||||
|
||||
// The menu's label, accesskey and checked states need to be updated
|
||||
// to match the command. Note that unlike the disabled state if the
|
||||
// command has *no* value, we assume the menu is supplying its own.
|
||||
if (commandContent->GetAttr(kNameSpaceID_None, nsGkAtoms::label, commandValue))
|
||||
grandChild->SetAttr(kNameSpaceID_None, nsGkAtoms::label, commandValue, PR_TRUE);
|
||||
|
||||
if (commandContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, commandValue))
|
||||
grandChild->SetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, commandValue, PR_TRUE);
|
||||
|
||||
if (commandContent->GetAttr(kNameSpaceID_None, nsGkAtoms::checked, commandValue))
|
||||
grandChild->SetAttr(kNameSpaceID_None, nsGkAtoms::checked, commandValue, PR_TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsPopupSetFrame::OnCreated(PRInt32 aX, PRInt32 aY, nsIContent* aPopupContent)
|
||||
{
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
nsMouseEvent event(PR_TRUE, NS_XUL_POPUP_SHOWN, nsnull,
|
||||
nsMouseEvent::eReal);
|
||||
// XXX See OnCreate above
|
||||
//event.point.x = aX;
|
||||
//event.point.y = aY;
|
||||
|
||||
if (aPopupContent) {
|
||||
nsCOMPtr<nsIPresShell> shell = PresContext()->GetPresShell();
|
||||
if (shell) {
|
||||
nsresult rv = shell->HandleDOMEventWithTarget(aPopupContent, &event,
|
||||
&status);
|
||||
if ( NS_FAILED(rv) || status == nsEventStatus_eConsumeNoDefault )
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsPopupSetFrame::OnDestroy(nsIContent* aPopupContent)
|
||||
{
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
nsMouseEvent event(PR_TRUE, NS_XUL_POPUP_HIDING, nsnull,
|
||||
nsMouseEvent::eReal);
|
||||
|
||||
if (aPopupContent) {
|
||||
nsCOMPtr<nsIPresShell> shell = PresContext()->GetPresShell();
|
||||
if (shell) {
|
||||
nsresult rv = shell->HandleDOMEventWithTarget(aPopupContent, &event,
|
||||
&status);
|
||||
if ( NS_FAILED(rv) || status == nsEventStatus_eConsumeNoDefault )
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsPopupSetFrame::OnDestroyed(nsPresContext* aPresContext,
|
||||
nsIContent* aPopupContent)
|
||||
{
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
nsMouseEvent event(PR_TRUE, NS_XUL_POPUP_HIDDEN, nsnull,
|
||||
nsMouseEvent::eReal);
|
||||
|
||||
if (aPopupContent && aPresContext) {
|
||||
nsCOMPtr<nsIPresShell> shell = aPresContext->GetPresShell();
|
||||
if (shell) {
|
||||
nsresult rv = shell->HandleDOMEventWithTarget(aPopupContent, &event,
|
||||
&status);
|
||||
if ( NS_FAILED(rv) || status == nsEventStatus_eConsumeNoDefault )
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsPopupSetFrame::RemovePopupFrame(nsIFrame* aPopup)
|
||||
{
|
||||
|
@ -268,18 +811,14 @@ nsPopupSetFrame::AddPopupFrameList(nsIFrame* aPopupFrameList)
|
|||
nsresult
|
||||
nsPopupSetFrame::AddPopupFrame(nsIFrame* aPopup)
|
||||
{
|
||||
NS_ASSERTION(aPopup->GetType() == nsGkAtoms::menuPopupFrame,
|
||||
"expected a menupopup frame to be added to a popupset");
|
||||
if (aPopup->GetType() != nsGkAtoms::menuPopupFrame)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
// The entry should already exist, but might not (if someone decided to make their
|
||||
// popup visible straightaway, e.g., the autocomplete widget).
|
||||
|
||||
// First look for an entry by content.
|
||||
nsIContent* content = aPopup->GetContent();
|
||||
nsPopupFrameList* entry = mPopupList;
|
||||
while (entry && entry->mPopupContent != content)
|
||||
entry = entry->mNextPopup;
|
||||
nsPopupFrameList* entry = nsnull;
|
||||
if (mPopupList)
|
||||
entry = mPopupList->GetEntry(content);
|
||||
if (!entry) {
|
||||
entry = new nsPopupFrameList(content, mPopupList);
|
||||
if (!entry)
|
||||
|
@ -291,7 +830,49 @@ nsPopupSetFrame::AddPopupFrame(nsIFrame* aPopup)
|
|||
}
|
||||
|
||||
// Set the frame connection.
|
||||
entry->mPopupFrame = NS_STATIC_CAST(nsMenuPopupFrame *, aPopup);
|
||||
entry->mPopupFrame = aPopup;
|
||||
|
||||
// Now return. The remaining entry values will be filled in if/when showPopup is
|
||||
// called for this popup.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//static
|
||||
PRBool
|
||||
nsPopupSetFrame::MayOpenPopup(nsIFrame* aFrame)
|
||||
{
|
||||
nsCOMPtr<nsISupports> cont = aFrame->PresContext()->GetContainer();
|
||||
nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(cont);
|
||||
if (!dsti)
|
||||
return PR_FALSE;
|
||||
|
||||
// chrome shells can always open popups
|
||||
PRInt32 type = -1;
|
||||
if (NS_SUCCEEDED(dsti->GetItemType(&type)) && type == nsIDocShellTreeItem::typeChrome)
|
||||
return PR_TRUE;
|
||||
|
||||
nsCOMPtr<nsIDocShell> shell = do_QueryInterface(dsti);
|
||||
if (!shell)
|
||||
return PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> win = do_GetInterface(shell);
|
||||
if (!win)
|
||||
return PR_FALSE;
|
||||
|
||||
// only allow popups in active windows
|
||||
PRBool active;
|
||||
nsIFocusController* focusController = win->GetRootFocusController();
|
||||
focusController->GetActive(&active);
|
||||
if (!active)
|
||||
return PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(shell);
|
||||
if (!baseWin)
|
||||
return PR_FALSE;
|
||||
|
||||
// only allow popups in visible frames
|
||||
PRBool visible;
|
||||
baseWin->GetVisibility(&visible);
|
||||
return visible;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,11 +46,10 @@
|
|||
#include "prtypes.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsGkAtoms.h"
|
||||
|
||||
#include "nsIPopupSetFrame.h"
|
||||
#include "nsBoxFrame.h"
|
||||
#include "nsFrameList.h"
|
||||
#include "nsMenuPopupFrame.h"
|
||||
#include "nsIMenuParent.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsISupportsArray.h"
|
||||
|
@ -59,20 +58,35 @@ nsIFrame* NS_NewPopupSetFrame(nsIPresShell* aPresShell, nsStyleContext* aContext
|
|||
|
||||
struct nsPopupFrameList {
|
||||
nsPopupFrameList* mNextPopup; // The next popup in the list.
|
||||
nsMenuPopupFrame* mPopupFrame; // Our popup.
|
||||
nsIFrame* mPopupFrame; // Our popup.
|
||||
nsIContent* mPopupContent; // The content element for the <popup> itself.
|
||||
|
||||
nsIContent* mElementContent; // The content that is having something popped up over it <weak>
|
||||
|
||||
PRInt32 mXPos; // This child's x position
|
||||
PRInt32 mYPos; // This child's y position
|
||||
|
||||
nsAutoString mPopupAnchor; // This child's anchor.
|
||||
nsAutoString mPopupAlign; // This child's align.
|
||||
|
||||
nsAutoString mPopupType;
|
||||
PRPackedBool mCreateHandlerSucceeded; // Did the create handler succeed?
|
||||
PRPackedBool mIsOpen;
|
||||
nsSize mLastPref;
|
||||
|
||||
public:
|
||||
nsPopupFrameList(nsIContent* aPopupContent, nsPopupFrameList* aNext);
|
||||
nsPopupFrameList* GetEntry(nsIContent* aPopupContent);
|
||||
nsPopupFrameList* GetEntryByFrame(nsIFrame* aPopupFrame);
|
||||
};
|
||||
|
||||
class nsPopupSetFrame : public nsBoxFrame
|
||||
class nsPopupSetFrame : public nsBoxFrame, public nsIPopupSetFrame
|
||||
{
|
||||
public:
|
||||
nsPopupSetFrame(nsIPresShell* aShell, nsStyleContext* aContext):
|
||||
nsBoxFrame(aShell, aContext) {}
|
||||
|
||||
~nsPopupSetFrame() {}
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD Init(nsIContent* aContent,
|
||||
nsIFrame* aParent,
|
||||
|
@ -89,11 +103,38 @@ public:
|
|||
|
||||
// nsIBox
|
||||
NS_IMETHOD DoLayout(nsBoxLayoutState& aBoxLayoutState);
|
||||
#ifdef DEBUG_LAYOUT
|
||||
NS_IMETHOD SetDebug(nsBoxLayoutState& aState, PRBool aDebug);
|
||||
#endif
|
||||
|
||||
// Used to destroy our popup frames.
|
||||
virtual void Destroy();
|
||||
|
||||
virtual nsIAtom* GetType() const { return nsGkAtoms::popupSetFrame; }
|
||||
// Reflow methods
|
||||
virtual void RepositionPopup(nsPopupFrameList* aEntry, nsBoxLayoutState& aState);
|
||||
|
||||
NS_IMETHOD ShowPopup(nsIContent* aElementContent, nsIContent* aPopupContent,
|
||||
PRInt32 aXPos, PRInt32 aYPos,
|
||||
const nsString& aPopupType, const nsString& anAnchorAlignment,
|
||||
const nsString& aPopupAlignment);
|
||||
NS_IMETHOD HidePopup(nsIFrame* aPopup);
|
||||
NS_IMETHOD DestroyPopup(nsIFrame* aPopup, PRBool aDestroyEntireChain);
|
||||
|
||||
PRBool OnCreate(PRInt32 aX, PRInt32 aY, nsIContent* aPopupContent);
|
||||
PRBool OnDestroy(nsIContent* aPopupContent);
|
||||
PRBool OnCreated(PRInt32 aX, PRInt32 aY, nsIContent* aPopupContent);
|
||||
static PRBool OnDestroyed(nsPresContext* aPresContext,
|
||||
nsIContent* aPopupContent);
|
||||
|
||||
void ActivatePopup(nsPopupFrameList* aEntry, PRBool aActivateFlag);
|
||||
void OpenPopup(nsPopupFrameList* aEntry, PRBool aOpenFlag);
|
||||
|
||||
/**
|
||||
* Return true if the docshell containing aFrame may open a popup. aFrame
|
||||
* doesn't need to be any particular type of frame, just a frame in the
|
||||
* same document.
|
||||
*/
|
||||
static PRBool MayOpenPopup(nsIFrame* aFrame);
|
||||
|
||||
#ifdef DEBUG
|
||||
NS_IMETHOD GetFrameName(nsAString& aResult) const
|
||||
|
@ -108,6 +149,13 @@ protected:
|
|||
nsresult AddPopupFrame(nsIFrame* aPopup);
|
||||
nsresult RemovePopupFrame(nsIFrame* aPopup);
|
||||
|
||||
void MarkAsGenerated(nsIContent* aPopupContent);
|
||||
|
||||
protected:
|
||||
#ifdef DEBUG_LAYOUT
|
||||
nsresult SetDebug(nsBoxLayoutState& aState, nsIFrame* aList, PRBool aDebug);
|
||||
#endif
|
||||
|
||||
nsPopupFrameList* mPopupList;
|
||||
|
||||
}; // class nsPopupSetFrame
|
||||
|
|
|
@ -85,8 +85,8 @@ public:
|
|||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
virtual nsPopupSetFrame* GetPopupSetFrame();
|
||||
virtual void SetPopupSetFrame(nsPopupSetFrame* aPopupSet);
|
||||
virtual nsIFrame* GetPopupSetFrame();
|
||||
virtual void SetPopupSetFrame(nsIFrame* aPopupSet);
|
||||
virtual nsIContent* GetDefaultTooltip();
|
||||
virtual void SetDefaultTooltip(nsIContent* aTooltip);
|
||||
virtual nsresult AddTooltipSupport(nsIContent* aNode);
|
||||
|
@ -131,7 +131,7 @@ public:
|
|||
NS_IMETHOD GetFrameName(nsAString& aResult) const;
|
||||
#endif
|
||||
|
||||
nsPopupSetFrame* mPopupSetFrame;
|
||||
nsIFrame* mPopupSetFrame;
|
||||
|
||||
protected:
|
||||
nsIContent* mDefaultTooltip;
|
||||
|
@ -275,14 +275,14 @@ nsRootBoxFrame::GetType() const
|
|||
return nsGkAtoms::rootFrame;
|
||||
}
|
||||
|
||||
nsPopupSetFrame*
|
||||
nsIFrame*
|
||||
nsRootBoxFrame::GetPopupSetFrame()
|
||||
{
|
||||
return mPopupSetFrame;
|
||||
}
|
||||
|
||||
void
|
||||
nsRootBoxFrame::SetPopupSetFrame(nsPopupSetFrame* aPopupSet)
|
||||
nsRootBoxFrame::SetPopupSetFrame(nsIFrame* aPopupSet)
|
||||
{
|
||||
// Under normal conditions this should only be called once. However,
|
||||
// if something triggers ReconstructDocElementHierarchy, we will
|
||||
|
|
|
@ -45,8 +45,7 @@
|
|||
/* ::::: menupopup ::::: */
|
||||
|
||||
menupopup,
|
||||
popup,
|
||||
panel {
|
||||
popup {
|
||||
-moz-appearance: menupopup;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,8 +45,7 @@
|
|||
/* ::::: menupopup ::::: */
|
||||
|
||||
menupopup,
|
||||
popup,
|
||||
panel {
|
||||
popup {
|
||||
border: 2px solid;
|
||||
-moz-border-top-colors: ThreeDLightShadow ThreeDHighlight;
|
||||
-moz-border-right-colors: ThreeDDarkShadow ThreeDShadow;
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
|
||||
interface nsIAutoCompleteInput;
|
||||
|
||||
[scriptable, uuid(476E1472-4357-4CD0-AFE3-FEA3112617B2)]
|
||||
[scriptable, uuid(bafcfe4f-0850-4106-a176-be5aef2e1e52)]
|
||||
interface nsIAutoCompleteController : nsISupports
|
||||
{
|
||||
/*
|
||||
|
@ -141,4 +141,10 @@ interface nsIAutoCompleteController : nsISupports
|
|||
* Set the current search string, but don't start searching
|
||||
*/
|
||||
void setSearchString(in AString aSearchString);
|
||||
|
||||
/*
|
||||
* Attach or Detach rollup-listener
|
||||
*/
|
||||
void attachRollupListener();
|
||||
void detachRollupListener();
|
||||
};
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
|
||||
interface nsIAutoCompleteInput;
|
||||
|
||||
[scriptable, uuid(816668CC-6AC0-47C3-944E-9C2CF37F224A)]
|
||||
[scriptable, uuid(65F6CD46-22EC-4329-BB3B-BCD1103F2204)]
|
||||
interface nsIAutoCompletePopup : nsISupports
|
||||
{
|
||||
/*
|
||||
|
@ -71,7 +71,7 @@ interface nsIAutoCompletePopup : nsISupports
|
|||
* @param y - The y coordinate to display the popup at
|
||||
* @param width - The width that the popup should size itself to
|
||||
*/
|
||||
void openAutocompletePopup(in nsIAutoCompleteInput input, in long x, in long y, in long width);
|
||||
void openPopup(in nsIAutoCompleteInput input, in long x, in long y, in long width);
|
||||
|
||||
/*
|
||||
* Close the popup and detach from the bound input
|
||||
|
|
|
@ -611,6 +611,27 @@ nsAutoCompleteController::SetSearchString(const nsAString &aSearchString)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAutoCompleteController::AttachRollupListener()
|
||||
{
|
||||
nsIWidget* widget = GetPopupWidget();
|
||||
NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
|
||||
NS_ASSERTION(mInput, "mInput must not be null.");
|
||||
PRBool consumeRollupEvent = PR_FALSE;
|
||||
mInput->GetConsumeRollupEvent(&consumeRollupEvent);
|
||||
return widget->CaptureRollupEvents((nsIRollupListener*)this,
|
||||
PR_TRUE, consumeRollupEvent);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAutoCompleteController::DetachRollupListener()
|
||||
{
|
||||
nsIWidget* widget = GetPopupWidget();
|
||||
NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
|
||||
return widget->CaptureRollupEvents((nsIRollupListener*)this,
|
||||
PR_FALSE, PR_FALSE);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//// nsIAutoCompleteObserver
|
||||
|
||||
|
|
|
@ -246,9 +246,7 @@ nsFormFillController::SetPopupOpen(PRBool aPopupOpen)
|
|||
NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE);
|
||||
|
||||
nsRect popupRect = GetScreenOrigin(mFocusedInput);
|
||||
mFocusedPopup->OpenAutocompletePopup(this, popupRect.x,
|
||||
popupRect.y+popupRect.height,
|
||||
popupRect.width);
|
||||
mFocusedPopup->OpenPopup(this, popupRect.x, popupRect.y+popupRect.height, popupRect.width);
|
||||
} else
|
||||
mFocusedPopup->ClosePopup();
|
||||
}
|
||||
|
|
|
@ -110,8 +110,9 @@
|
|||
if (popupId)
|
||||
popup = document.getElementById(popupId);
|
||||
if (!popup) {
|
||||
popup = document.createElement("panel");
|
||||
popup = document.createElement("popup");
|
||||
popup.setAttribute("type", "autocomplete");
|
||||
popup.setAttribute("hidden", "true");
|
||||
|
||||
var popupset = document.getAnonymousElementByAttribute(this, "anonid", "popupset");
|
||||
popupset.appendChild(popup);
|
||||
|
@ -319,7 +320,7 @@
|
|||
|
||||
<method name="openPopup">
|
||||
<body><![CDATA[
|
||||
this.popup.openAutocompletePopup(this, -1, -1, this.boxObject.width);
|
||||
this.popup.openPopup(this, -1, -1, this.boxObject.width);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
@ -564,7 +565,7 @@
|
|||
<property name="popupOpen" readonly="true"
|
||||
onget="return this.mPopupOpen;"/>
|
||||
|
||||
<method name="openAutocompletePopup">
|
||||
<method name="openPopup">
|
||||
<parameter name="aInput"/>
|
||||
<parameter name="aX"/>
|
||||
<parameter name="aY"/>
|
||||
|
@ -577,6 +578,7 @@
|
|||
|
||||
this.showCommentColumn = this.mInput.showCommentColumn;
|
||||
|
||||
this.removeAttribute("hidden");
|
||||
this.setAttribute("width", aWidth < 100 ? 100 : aWidth);
|
||||
|
||||
document.popupNode = null;
|
||||
|
@ -586,7 +588,8 @@
|
|||
else {
|
||||
this.showPopup(document.documentElement, aX, aY, "popup", null, null);
|
||||
}
|
||||
this.popupBoxObject.setConsumeRollupEvent(this.mInput.consumeRollupEvent);
|
||||
this.enableRollup(false);
|
||||
this.mInput.controller.attachRollupListener();
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
@ -596,8 +599,10 @@
|
|||
if (this.mPopupOpen) {
|
||||
this.hidePopup();
|
||||
document.popupNode = null;
|
||||
// this.setAttribute("hidden", "true");
|
||||
|
||||
this.setAttribute("hidden", "true");
|
||||
this.removeAttribute("width");
|
||||
this.mInput.controller.detachRollupListener();
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
@ -711,8 +716,6 @@
|
|||
// detect the desired height of the tree
|
||||
var bx = this.tree.treeBoxObject;
|
||||
var view = this.tree.view;
|
||||
if (!view)
|
||||
return;
|
||||
var rows = this.maxRows;
|
||||
if (!view.rowCount || (rows && view.rowCount < rows))
|
||||
rows = view.rowCount;
|
||||
|
|
|
@ -11,8 +11,12 @@
|
|||
</resources>
|
||||
</binding>
|
||||
|
||||
<binding id="panel"
|
||||
extends="chrome://global/content/bindings/popup.xml#popup-base">
|
||||
<binding id="popup" extends="chrome://global/content/bindings/popup.xml#popup-base">
|
||||
<content>
|
||||
<xul:arrowscrollbox class="popup-internal-box" flex="1" orient="vertical">
|
||||
<children/>
|
||||
</xul:arrowscrollbox>
|
||||
</content>
|
||||
|
||||
<implementation implements="nsIDOMXULPopupElement, nsIAccessibleProvider">
|
||||
<property name="accessibleType" readonly="true">
|
||||
|
@ -31,40 +35,6 @@
|
|||
</getter>
|
||||
</property>
|
||||
|
||||
<method name="openPopup">
|
||||
<parameter name="aAnchorElement"/>
|
||||
<parameter name="aPosition"/>
|
||||
<parameter name="aX"/>
|
||||
<parameter name="aY"/>
|
||||
<parameter name="aIsContextMenu"/>
|
||||
<parameter name="aAttributesOverride"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
try {
|
||||
var popupBox = this.popupBoxObject;
|
||||
if (popupBox)
|
||||
popupBox.openPopup(aAnchorElement, aPosition, aX, aY,
|
||||
aIsContextMenu, aAttributesOverride);
|
||||
} catch(e) {}
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="openPopupAtScreen">
|
||||
<parameter name="aX"/>
|
||||
<parameter name="aY"/>
|
||||
<parameter name="aIsContextMenu"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
try {
|
||||
var popupBox = this.popupBoxObject;
|
||||
if (popupBox)
|
||||
popupBox.openPopupAtScreen(aX, aY, aIsContextMenu);
|
||||
} catch(e) {}
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="showPopup">
|
||||
<parameter name="element"/>
|
||||
<parameter name="xpos"/>
|
||||
|
@ -161,16 +131,6 @@
|
|||
</method>
|
||||
</implementation>
|
||||
|
||||
</binding>
|
||||
|
||||
<binding id="popup"
|
||||
extends="chrome://global/content/bindings/popup.xml#panel">
|
||||
<content>
|
||||
<xul:arrowscrollbox class="popup-internal-box" flex="1" orient="vertical">
|
||||
<children/>
|
||||
</xul:arrowscrollbox>
|
||||
</content>
|
||||
|
||||
<handlers>
|
||||
<handler event="contextmenu" action="event.preventDefault();"/>
|
||||
|
||||
|
|
|
@ -320,23 +320,24 @@ popup,
|
|||
menupopup {
|
||||
-moz-binding: url("chrome://global/content/bindings/popup.xml#popup");
|
||||
-moz-box-orient: vertical;
|
||||
}
|
||||
|
||||
panel {
|
||||
-moz-binding: url("chrome://global/content/bindings/popup.xml#panel");
|
||||
-moz-box-orient: vertical;
|
||||
display: none;
|
||||
}
|
||||
|
||||
popup,
|
||||
menupopup,
|
||||
panel,
|
||||
tooltip {
|
||||
display: -moz-popup;
|
||||
z-index: 2147483647;
|
||||
}
|
||||
|
||||
menupopup[menugenerated="true"],
|
||||
popup[menugenerated="true"],
|
||||
tooltip[menugenerated="true"] {
|
||||
display: -moz-popup;
|
||||
}
|
||||
|
||||
tooltip {
|
||||
-moz-binding: url("chrome://global/content/bindings/popup.xml#tooltip");
|
||||
display: -moz-popup;
|
||||
margin-top: 21px;
|
||||
}
|
||||
|
||||
|
@ -781,8 +782,9 @@ textbox[type="autocomplete"] {
|
|||
-moz-binding: url("chrome://global/content/bindings/autocomplete.xml#autocomplete");
|
||||
}
|
||||
|
||||
panel[type="autocomplete"] {
|
||||
popup[type="autocomplete"] {
|
||||
-moz-binding: url("chrome://global/content/bindings/autocomplete.xml#autocomplete-result-popup");
|
||||
display: -moz-popup !important;
|
||||
}
|
||||
|
||||
.autocomplete-tree {
|
||||
|
|
|
@ -44,9 +44,7 @@
|
|||
|
||||
/* ::::: menupopup ::::: */
|
||||
|
||||
menupopup,
|
||||
popup,
|
||||
panel {
|
||||
menupopup, popup {
|
||||
-moz-appearance: menupopup;
|
||||
min-width: 1px;
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ textbox.padded {
|
|||
|
||||
/* ::::: autocomplete popups ::::: */
|
||||
|
||||
panel[type="autocomplete"],
|
||||
popup[type="autocomplete"],
|
||||
.autocomplete-history-popup {
|
||||
padding: 0px !important;
|
||||
background-color: -moz-Field !important;
|
||||
|
|
|
@ -46,8 +46,7 @@
|
|||
/* ::::: menupopup ::::: */
|
||||
|
||||
menupopup,
|
||||
popup,
|
||||
panel {
|
||||
popup {
|
||||
-moz-appearance: menupopup;
|
||||
}
|
||||
|
||||
|
|
|
@ -167,7 +167,7 @@ textbox[chromedir="rtl"] .autocomplete-history-dropmarker {
|
|||
|
||||
/* ::::: autocomplete popups ::::: */
|
||||
|
||||
panel[type="autocomplete"],
|
||||
popup[type="autocomplete"],
|
||||
.autocomplete-history-popup {
|
||||
border-width: 1px;
|
||||
-moz-border-top-colors: ThreeDDarkShadow;
|
||||
|
|
|
@ -45,8 +45,7 @@
|
|||
/* ::::: menupopup ::::: */
|
||||
|
||||
menupopup,
|
||||
popup,
|
||||
panel {
|
||||
popup {
|
||||
border: 2px solid transparent;
|
||||
-moz-border-top-colors : ThreeDLightShadow ThreeDHighlight;
|
||||
-moz-border-left-colors : ThreeDLightShadow ThreeDHighlight;
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include "nsGfxCIID.h"
|
||||
#include "nsTransform2D.h"
|
||||
#include "nsIMenuFrame.h"
|
||||
#include "nsIMenuParent.h"
|
||||
#include "prlink.h"
|
||||
#include "nsIDOMHTMLInputElement.h"
|
||||
#include "nsWidgetAtoms.h"
|
||||
|
@ -277,11 +278,15 @@ nsNativeThemeGTK::GetGtkWidgetAndState(PRUint8 aWidgetType, nsIFrame* aFrame,
|
|||
CallQueryInterface(aFrame, &menuFrame);
|
||||
|
||||
if (menuFrame) {
|
||||
isTopLevel = menuFrame->IsOnMenuBar();
|
||||
nsIMenuParent *menuParent = menuFrame->GetMenuParent();
|
||||
if (menuParent)
|
||||
menuParent->IsMenuBar(isTopLevel);
|
||||
}
|
||||
|
||||
if (isTopLevel) {
|
||||
aState->inHover = menuFrame->IsOpen();
|
||||
PRBool isOpen;
|
||||
menuFrame->MenuIsOpen(isOpen);
|
||||
aState->inHover = isOpen;
|
||||
} else {
|
||||
aState->inHover = CheckBooleanAttr(aFrame, nsWidgetAtoms::mozmenuactive);
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include "nsILookAndFeel.h"
|
||||
#include "nsIDOMHTMLInputElement.h"
|
||||
#include "nsIMenuFrame.h"
|
||||
#include "nsIMenuParent.h"
|
||||
#include "nsWidgetAtoms.h"
|
||||
#include <malloc.h>
|
||||
|
||||
|
@ -786,8 +787,8 @@ nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame, PRUint8 aWidgetType,
|
|||
nsIContent* content = aFrame->GetContent();
|
||||
|
||||
nsIFrame* parentFrame = aFrame->GetParent();
|
||||
if (parentFrame->GetType() == nsWidgetAtoms::menuFrame ||
|
||||
(content && content->IsNodeOfType(nsINode::eHTML)))
|
||||
nsCOMPtr<nsIMenuFrame> menuFrame(do_QueryInterface(parentFrame));
|
||||
if (menuFrame || (content && content->IsNodeOfType(nsINode::eHTML)) )
|
||||
// XUL menu lists and HTML selects get state from parent
|
||||
aFrame = parentFrame;
|
||||
|
||||
|
@ -1410,7 +1411,9 @@ nsNativeThemeWin::ClassicGetWidgetBorder(nsIDeviceContext* aContext,
|
|||
if (menuFrame) {
|
||||
// If this is a real menu item, we should check if it is part of the
|
||||
// main menu bar or not, as this affects rendering.
|
||||
isTopLevel = menuFrame->IsOnMenuBar();
|
||||
nsIMenuParent *menuParent = menuFrame->GetMenuParent();
|
||||
if (menuParent)
|
||||
menuParent->IsMenuBar(isTopLevel);
|
||||
}
|
||||
|
||||
// These values are obtained from visual inspection of equivelant
|
||||
|
@ -1630,9 +1633,11 @@ nsresult nsNativeThemeWin::ClassicGetThemePartAndState(nsIFrame* aFrame, PRUint8
|
|||
// If this is a real menu item, we should check if it is part of the
|
||||
// main menu bar or not, and if it is a container, as these affect
|
||||
// rendering.
|
||||
isTopLevel = menuFrame->IsOnMenuBar();
|
||||
isOpen = menuFrame->IsOpen();
|
||||
isContainer = menuFrame->IsMenu();
|
||||
nsIMenuParent *menuParent = menuFrame->GetMenuParent();
|
||||
if (menuParent)
|
||||
menuParent->IsMenuBar(isTopLevel);
|
||||
menuFrame->MenuIsOpen(isOpen);
|
||||
menuFrame->MenuIsContainer(isContainer);
|
||||
}
|
||||
|
||||
if (IsDisabled(aFrame))
|
||||
|
@ -1699,8 +1704,8 @@ nsresult nsNativeThemeWin::ClassicGetThemePartAndState(nsIFrame* aFrame, PRUint8
|
|||
|
||||
nsIContent* content = aFrame->GetContent();
|
||||
nsIFrame* parentFrame = aFrame->GetParent();
|
||||
if (parentFrame->GetType() == nsWidgetAtoms::menuFrame ||
|
||||
(content && content->IsNodeOfType(nsINode::eHTML)))
|
||||
nsCOMPtr<nsIMenuFrame> menuFrame(do_QueryInterface(parentFrame));
|
||||
if (menuFrame || (content && content->IsNodeOfType(nsINode::eHTML)) )
|
||||
// XUL menu lists and HTML selects get state from parent
|
||||
aFrame = parentFrame;
|
||||
// XXX the button really shouldn't depress when clicking the
|
||||
|
|
|
@ -88,7 +88,6 @@ WIDGET_ATOM(menu, "menu") // Represents an XP menu
|
|||
WIDGET_ATOM(menuitem, "menuitem") // Represents an XP menu item
|
||||
WIDGET_ATOM(menupopup, "menupopup") // The XP menu's children.
|
||||
WIDGET_ATOM(menuseparator, "menuseparator") // Divider between menu items
|
||||
WIDGET_ATOM(menuFrame, "menuFrame")
|
||||
WIDGET_ATOM(minpos, "minpos")
|
||||
WIDGET_ATOM(mode, "mode")
|
||||
WIDGET_ATOM(modifiers, "modifiers") // The modifiers attribute
|
||||
|
|
|
@ -114,6 +114,8 @@
|
|||
#define USE_NATIVE_MENUS
|
||||
#endif
|
||||
|
||||
#include "nsIPopupSetFrame.h"
|
||||
|
||||
/* Define Class IDs */
|
||||
static NS_DEFINE_CID(kWindowCID, NS_WINDOW_CID);
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
xbl:inherits="open,hidden=disablehistory" anonid="historydropmarker"/>
|
||||
|
||||
<xul:popupset>
|
||||
<xul:panel type="autocomplete" ignorekeys="true" anonid="popup" class="autocomplete-result-popup" hidden="true" xbl:inherits="for=id,nomatch"/>
|
||||
<xul:popup type="autocomplete" ignorekeys="true" anonid="popup" class="autocomplete-result-popup" hidden="true" xbl:inherits="for=id,nomatch"/>
|
||||
</xul:popupset>
|
||||
|
||||
<children includes="menupopup"/>
|
||||
|
|
|
@ -35,40 +35,6 @@
|
|||
</getter>
|
||||
</property>
|
||||
|
||||
<method name="openPopup">
|
||||
<parameter name="aAnchorElement"/>
|
||||
<parameter name="aPosition"/>
|
||||
<parameter name="aX"/>
|
||||
<parameter name="aY"/>
|
||||
<parameter name="aIsContextMenu"/>
|
||||
<parameter name="aAttributesOverride"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
try {
|
||||
var popupBox = this.popupBoxObject;
|
||||
if (popupBox)
|
||||
popupBox.openPopup(aAnchorElement, aPosition, aX, aY,
|
||||
aIsContextMenu, aAttributesOverride);
|
||||
} catch(e) {}
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="openPopupAtScreen">
|
||||
<parameter name="aX"/>
|
||||
<parameter name="aY"/>
|
||||
<parameter name="aIsContextMenu"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
try {
|
||||
var popupBox = this.popupBoxObject;
|
||||
if (popupBox)
|
||||
popupBox.openPopupAtScreen(aX, aY, aIsContextMenu);
|
||||
} catch(e) {}
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="showPopup">
|
||||
<parameter name="element"/>
|
||||
<parameter name="xpos"/>
|
||||
|
|
|
@ -298,22 +298,27 @@ menuseparator {
|
|||
/* <popup> is deprecated. Only <menupopup> and <tooltip> are still valid. */
|
||||
|
||||
popup,
|
||||
menupopup,
|
||||
panel {
|
||||
menupopup {
|
||||
-moz-binding: url("chrome://global/content/bindings/popup.xml#popup");
|
||||
-moz-box-orient: vertical;
|
||||
display: none;
|
||||
}
|
||||
|
||||
popup,
|
||||
menupopup,
|
||||
panel,
|
||||
tooltip {
|
||||
display: -moz-popup;
|
||||
z-index: 2147483647;
|
||||
}
|
||||
|
||||
menupopup[menugenerated="true"],
|
||||
popup[menugenerated="true"],
|
||||
tooltip[menugenerated="true"] {
|
||||
display: -moz-popup;
|
||||
}
|
||||
|
||||
tooltip {
|
||||
-moz-binding: url("chrome://global/content/bindings/popup.xml#tooltip");
|
||||
display: -moz-popup;
|
||||
margin-top: 21px;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче