Bug 279703, backing out the popup changes due to performance regressions. sigh.

This commit is contained in:
enndeakin%sympatico.ca 2007-06-29 22:16:06 +00:00
Родитель 73453f5971
Коммит d6cdd07569
62 изменённых файлов: 3808 добавлений и 2566 удалений

Просмотреть файл

@ -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;
}