Bug 279703, rework XUL popups to use asynchronous opening, plus many other fixes, attempt 2 with creating widgets later, r=bz,neil,roc,sr=bz

This commit is contained in:
enndeakin%sympatico.ca 2007-07-04 15:49:46 +00:00
Родитель 57286498df
Коммит a71cb5f411
71 изменённых файлов: 4323 добавлений и 4508 удалений

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

@ -62,6 +62,7 @@
#include "nsIEventListenerManager.h"
#include "nsIFocusController.h"
#include "nsIFrame.h"
#include "nsIMenuFrame.h"
#include "nsIHTMLDocument.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIMenuParent.h"
@ -801,22 +802,23 @@ nsresult nsRootAccessible::HandleEventWithTarget(nsIDOMEvent* aEvent,
}
else if (eventType.EqualsLiteral("DOMMenuItemActive")) {
if (!treeItemAccessible) {
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) {
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()) {
// 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>
<popup type="autocomplete" chromedir="&locale.dir;" id="PopupAutoComplete"/>
<panel type="autocomplete" chromedir="&locale.dir;" id="PopupAutoComplete"/>
<popup id="toolbar-context-menu"
onpopupshowing="onViewToolbarsPopupShowing(event);">

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

@ -3682,6 +3682,7 @@ 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)

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

@ -488,7 +488,6 @@ GK_ATOM(menugenerated, "menugenerated")
GK_ATOM(menuitem, "menuitem")
GK_ATOM(menulist, "menulist")
GK_ATOM(menupopup, "menupopup")
GK_ATOM(menutobedisplayed, "menutobedisplayed")
GK_ATOM(message, "message")
GK_ATOM(meta, "meta")
GK_ATOM(method, "method")
@ -520,6 +519,7 @@ GK_ATOM(never, "never")
GK_ATOM(_new, "new")
GK_ATOM(nextBidi, "NextBidi")
GK_ATOM(no, "no")
GK_ATOM(noautohide, "noautohide")
GK_ATOM(nobr, "nobr")
GK_ATOM(node, "node")
GK_ATOM(nodeSet, "node-set")
@ -634,6 +634,7 @@ GK_ATOM(pageincrement, "pageincrement")
GK_ATOM(pagex, "pagex")
GK_ATOM(pagey, "pagey")
GK_ATOM(palettename, "palettename")
GK_ATOM(panel, "panel")
GK_ATOM(param, "param")
GK_ATOM(parameter, "parameter")
GK_ATOM(parent, "parent")
@ -1391,12 +1392,15 @@ GK_ATOM(legendFrame, "LegendFrame")
GK_ATOM(letterFrame, "LetterFrame")
GK_ATOM(lineFrame, "LineFrame")
GK_ATOM(listControlFrame,"ListControlFrame")
GK_ATOM(menuBarFrame,"MenuBarFrame")
GK_ATOM(menuFrame,"MenuFrame")
GK_ATOM(menuPopupFrame,"MenuPopupFrame")
GK_ATOM(objectFrame, "ObjectFrame")
GK_ATOM(pageFrame, "PageFrame")
GK_ATOM(pageBreakFrame, "PageBreakFrame")
GK_ATOM(pageContentFrame, "PageContentFrame")
GK_ATOM(placeholderFrame, "PlaceholderFrame")
GK_ATOM(popupSetFrame, "PopupSetFrame")
GK_ATOM(positionedInlineFrame, "PositionedInlineFrame")
GK_ATOM(canvasFrame, "CanvasFrame")
GK_ATOM(rootFrame, "RootFrame")

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

@ -43,7 +43,7 @@ VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = xul
DIRS = public src test
DIRS = src test
include $(topsrcdir)/config/rules.mk

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

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

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

@ -107,7 +107,6 @@
#include "nsIViewManager.h"
#include "nsIWidget.h"
#include "nsIXULDocument.h"
#include "nsIXULPopupListener.h"
#include "nsIXULTemplateBuilder.h"
#include "nsIXBLService.h"
#include "nsLayoutCID.h"
@ -119,6 +118,7 @@
#include "nsIBoxObject.h"
#include "nsPIBoxObject.h"
#include "nsXULDocument.h"
#include "nsXULPopupListener.h"
#include "nsRuleWalker.h"
#include "nsIDOMViewCSS.h"
#include "nsIDOMCSSStyleDeclaration.h"
@ -2046,18 +2046,17 @@ static void
PopupListenerPropertyDtor(void* aObject, nsIAtom* aPropertyName,
void* aPropertyValue, void* aData)
{
nsIXULPopupListener* listener =
NS_STATIC_CAST(nsIXULPopupListener*, aPropertyValue);
nsIDOMEventListener* listener =
NS_STATIC_CAST(nsIDOMEventListener*, 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"), eventListener,
target->RemoveEventListener(NS_LITERAL_STRING("mousedown"), listener,
PR_FALSE);
target->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), eventListener,
target->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), listener,
PR_FALSE);
}
NS_RELEASE(listener);
@ -2066,43 +2065,38 @@ PopupListenerPropertyDtor(void* aObject, nsIAtom* aPropertyName,
nsresult
nsXULElement::AddPopupListener(nsIAtom* aName)
{
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;
}
// Add a popup listener to the element
PRBool isContext = (aName == nsGkAtoms::context ||
aName == nsGkAtoms::contextmenu);
nsIAtom* listenerAtom = isContext ?
nsGkAtoms::contextmenulistener :
nsGkAtoms::popuplistener;
nsCOMPtr<nsIXULPopupListener> popupListener =
NS_STATIC_CAST(nsIXULPopupListener*, GetProperty(listenerAtom));
nsCOMPtr<nsIDOMEventListener> popupListener =
NS_STATIC_CAST(nsIDOMEventListener*, GetProperty(listenerAtom));
if (popupListener) {
// Popup listener is already installed.
return NS_OK;
}
// Add a popup listener to the element
nsresult 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);
nsresult rv = NS_NewXULPopupListener(this, isContext,
getter_AddRefs(popupListener));
if (NS_FAILED(rv))
return rv;
// 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);
nsIXULPopupListener* listener = popupListener;
NS_ADDREF(listener);
target->AddEventListener(NS_LITERAL_STRING("mousedown"), eventListener, PR_FALSE);
target->AddEventListener(NS_LITERAL_STRING("contextmenu"), eventListener, PR_FALSE);
// 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);
return NS_OK;
}

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

@ -44,6 +44,7 @@
tracks xul popups and context menus
*/
#include "nsXULPopupListener.h"
#include "nsCOMPtr.h"
#include "nsGkAtoms.h"
#include "nsIDOMElement.h"
@ -51,27 +52,23 @@
#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 "nsIBoxObject.h"
#include "nsIPopupBoxObject.h"
#include "nsLayoutUtils.h"
#include "nsFrameManager.h"
#include "nsHTMLReflowState.h"
// for event firing in context menus
#include "nsPresContext.h"
@ -79,9 +76,8 @@
#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,
@ -90,124 +86,49 @@
#define NS_CONTEXT_MENU_IS_MOUSEUP 1
#endif
////////////////////////////////////////////////////////////////////////
// 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(nsIDOMElement *aElement, PRBool aIsContext)
: mElement(aElement), mPopupContent(nsnull), mIsContext(aIsContext)
{
}
XULPopupListenerImpl::~XULPopupListenerImpl(void)
nsXULPopupListener::~nsXULPopupListener(void)
{
if (mPopup) {
mPopup->HidePopup();
}
#ifdef DEBUG_REFS
--gInstanceCount;
fprintf(stdout, "%d - RDF: XULPopupListenerImpl\n", gInstanceCount);
#endif
ClosePopup();
}
NS_IMPL_ADDREF(XULPopupListenerImpl)
NS_IMPL_RELEASE(XULPopupListenerImpl)
NS_IMPL_ADDREF(nsXULPopupListener)
NS_IMPL_RELEASE(nsXULPopupListener)
NS_INTERFACE_MAP_BEGIN(XULPopupListenerImpl)
NS_INTERFACE_MAP_ENTRY(nsIXULPopupListener)
NS_INTERFACE_MAP_BEGIN(nsXULPopupListener)
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
XULPopupListenerImpl::MouseDown(nsIDOMEvent* aMouseEvent)
nsXULPopupListener::MouseDown(nsIDOMEvent* aMouseEvent)
{
if(popupType != eXULPopupType_context)
if(!mIsContext)
return PreLaunchPopup(aMouseEvent);
else
return NS_OK;
}
nsresult
XULPopupListenerImpl::ContextMenu(nsIDOMEvent* aMouseEvent)
nsXULPopupListener::ContextMenu(nsIDOMEvent* aMouseEvent)
{
if(popupType == eXULPopupType_context)
if(mIsContext)
return PreLaunchPopup(aMouseEvent);
else
return NS_OK;
}
nsresult
XULPopupListenerImpl::PreLaunchPopup(nsIDOMEvent* aMouseEvent)
nsXULPopupListener::PreLaunchPopup(nsIDOMEvent* aMouseEvent)
{
PRUint16 button;
@ -230,7 +151,7 @@ XULPopupListenerImpl::PreLaunchPopup(nsIDOMEvent* aMouseEvent)
mouseEvent->GetTarget(getter_AddRefs(target));
nsCOMPtr<nsIDOMNode> targetNode = do_QueryInterface(target);
if (!targetNode && popupType == eXULPopupType_context) {
if (!targetNode && mIsContext) {
// Not a DOM node, see if it's the DOM window (bug 380818).
nsCOMPtr<nsIDOMWindow> domWin = do_QueryInterface(target);
if (!domWin) {
@ -250,7 +171,7 @@ XULPopupListenerImpl::PreLaunchPopup(nsIDOMEvent* aMouseEvent)
PRBool preventDefault;
nsUIEvent->GetPreventDefault(&preventDefault);
if (preventDefault && targetNode && popupType == eXULPopupType_context) {
if (preventDefault && targetNode && mIsContext) {
// Someone called preventDefault on a context menu.
// Let's make sure they are allowed to do so.
PRBool eventEnabled =
@ -278,13 +199,13 @@ XULPopupListenerImpl::PreLaunchPopup(nsIDOMEvent* aMouseEvent)
return NS_OK;
}
// 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.
// prevent popups on menu and menuitems as they handle their own popups
// This was added for bug 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);
nsCOMPtr<nsIContent> targetContent = do_QueryInterface(target);
if (!mIsContext) {
nsIAtom *tag = targetContent ? targetContent->Tag() : nsnull;
if (tag == nsGkAtoms::menu || tag == nsGkAtoms::menuitem)
return NS_OK;
@ -295,48 +216,38 @@ XULPopupListenerImpl::PreLaunchPopup(nsIDOMEvent* aMouseEvent)
// Turn the document into a XUL document so we can use SetPopupNode.
nsCOMPtr<nsIDOMXULDocument> xulDocument = do_QueryInterface(content->GetDocument());
if (!xulDocument) {
NS_ERROR("Popup attached to an element that isn't in XUL!");
if (!xulDocument)
return NS_ERROR_FAILURE;
}
// Store clicked-on node in xul document for context menus and menu popups.
// CLEAR THE POPUP EVENT BEFORE THIS FUNCTION EXITS
xulDocument->SetPopupNode( targetNode );
xulDocument->SetTrustedPopupEvent( aMouseEvent );
xulDocument->SetPopupNode(targetNode);
nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aMouseEvent));
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
if (mIsContext) {
#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);
// If the context menu launches on mousedown,
// we have to fire focus on the content we clicked on
FireFocusOnTargetContent(targetNode);
#endif
LaunchPopup(aMouseEvent);
aMouseEvent->StopPropagation();
aMouseEvent->PreventDefault();
break;
}
xulDocument->SetTrustedPopupEvent(nsnull);
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);
aMouseEvent->StopPropagation();
aMouseEvent->PreventDefault();
return NS_OK;
}
nsresult
XULPopupListenerImpl::FireFocusOnTargetContent(nsIDOMNode* aTargetNode)
nsXULPopupListener::FireFocusOnTargetContent(nsIDOMNode* aTargetNode)
{
nsresult rv;
nsCOMPtr<nsIDOMDocument> domDoc;
@ -408,26 +319,25 @@ XULPopupListenerImpl::FireFocusOnTargetContent(nsIDOMNode* aTargetNode)
return rv;
}
// ClosePopup
//
// LaunchPopup
// Do everything needed to shut down the popup.
//
nsresult
XULPopupListenerImpl::LaunchPopup ( nsIDOMEvent* anEvent )
// NOTE: This routine is safe to call even if the popup is already closed.
//
void
nsXULPopupListener::ClosePopup()
{
// Retrieve our x and y position.
nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(anEvent) );
if (!mouseEvent) {
//non-ui event passed in. bad things.
return NS_OK;
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
}
PRInt32 xPos, yPos;
mouseEvent->GetClientX(&xPos);
mouseEvent->GetClientY(&yPos);
return LaunchPopup(xPos, yPos);
}
} // ClosePopup
static void
GetImmediateChild(nsIContent* aContent, nsIAtom *aTag, nsIContent** aResult)
@ -446,53 +356,6 @@ 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
//
@ -500,25 +363,22 @@ static void ConvertPosition(nsIDOMElement* aPopupElt, nsString& aAnchor, nsStrin
// Client and widget coordinates, popup a new window showing the appropriate
// content.
//
// This looks for an attribute on |aElement| of the appropriate popup type
// 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
// (popup, context) and uses that attribute's value as an ID for
// the popup content in the document.
//
nsresult
XULPopupListenerImpl::LaunchPopup(PRInt32 aClientX, PRInt32 aClientY)
nsXULPopupListener::LaunchPopup(nsIDOMEvent* aEvent, nsIContent* aTargetContent)
{
nsresult rv = NS_OK;
nsAutoString type(NS_LITERAL_STRING("popup"));
if ( popupType == eXULPopupType_context ) {
if (mIsContext)
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);
@ -544,14 +404,14 @@ XULPopupListenerImpl::LaunchPopup(PRInt32 aClientX, PRInt32 aClientY)
}
// Handle the _child case for popups and context menus
nsCOMPtr<nsIDOMElement> popupContent;
nsCOMPtr<nsIDOMElement> popupElement;
if (identifier.EqualsLiteral("_child")) {
nsCOMPtr<nsIContent> popup;
GetImmediateChild(content, nsGkAtoms::menupopup, getter_AddRefs(popup));
if (popup)
popupContent = do_QueryInterface(popup);
popupElement = do_QueryInterface(popup);
else {
nsCOMPtr<nsIDOMDocumentXBL> nsDoc(do_QueryInterface(domDocument));
nsCOMPtr<nsIDOMNodeList> list;
@ -566,7 +426,7 @@ XULPopupListenerImpl::LaunchPopup(PRInt32 aClientX, PRInt32 aClientY)
if (childContent->NodeInfo()->Equals(nsGkAtoms::menupopup,
kNameSpaceID_XUL)) {
popupContent = do_QueryInterface(childContent);
popupElement = do_QueryInterface(childContent);
break;
}
}
@ -574,58 +434,60 @@ XULPopupListenerImpl::LaunchPopup(PRInt32 aClientX, PRInt32 aClientY)
}
}
else if (NS_FAILED(rv = domDocument->GetElementById(identifier,
getter_AddRefs(popupContent)))) {
getter_AddRefs(popupElement)))) {
// 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;
}
if (!popupContent || mElement == popupContent)
// return if no popup was found or the popup is the element itself.
if ( !popupElement || popupElement == mElement)
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(popupContent);
nsCOMPtr<nsIContent> popup = do_QueryInterface(popupElement);
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) {
nsIMenuFrame* menu = nsnull;
CallQueryInterface(frame, &menu);
NS_ENSURE_FALSE(menu, NS_OK);
}
if (frame && frame->GetType() == nsGkAtoms::menuFrame)
return NS_OK;
}
// We have some popup content. Obtain our window.
nsPIDOMWindow *domWindow = document->GetWindow();
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (!pm)
return NS_OK;
if (domWindow) {
// Find out if we're anchored.
nsAutoString anchorAlignment;
popupContent->GetAttribute(NS_LITERAL_STRING("popupanchor"), anchorAlignment);
// XXXndeakin this is temporary. It is needed to grab the mouse location details
// used by the spellchecking popup. See bug 383930.
pm->SetMouseLocation(aEvent);
nsAutoString popupAlignment;
popupContent->GetAttribute(NS_LITERAL_STRING("popupalign"), popupAlignment);
// 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);
}
else {
PRInt32 xPos = 0, yPos = 0;
nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
mouseEvent->GetScreenX(&xPos);
mouseEvent->GetScreenY(&yPos);
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());
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;
@ -633,13 +495,14 @@ XULPopupListenerImpl::LaunchPopup(PRInt32 aClientX, PRInt32 aClientY)
////////////////////////////////////////////////////////////////
nsresult
NS_NewXULPopupListener(nsIXULPopupListener** pop)
NS_NewXULPopupListener(nsIDOMElement* aElement, PRBool aIsContext,
nsIDOMEventListener** aListener)
{
XULPopupListenerImpl* popup = new XULPopupListenerImpl();
if (!popup)
nsXULPopupListener* pl = new nsXULPopupListener(aElement, aIsContext);
if (!pl)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(popup);
*pop = popup;
*aListener = NS_STATIC_CAST(nsIDOMMouseListener *, pl);
NS_ADDREF(*aListener);
return NS_OK;
}

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

@ -0,0 +1,123 @@
/* -*- 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,6 +128,7 @@
#include "nsIDocShellTreeItem.h"
#include "nsIDocShellTreeOwner.h"
#include "nsIXULWindow.h"
#include "nsXULPopupManager.h"
//----------------------------------------------------------------------
//
@ -1456,84 +1457,49 @@ nsXULDocument::SetPopupNode(nsIDOMNode* aNode)
return rv;
}
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.
// Returns the rangeOffset element from the XUL Popup Manager. This is for
// chrome callers only.
NS_IMETHODIMP
nsXULDocument::GetPopupRangeParent(nsIDOMNode** aRangeParent)
{
NS_ENSURE_ARG_POINTER(aRangeParent);
*aRangeParent = nsnull;
nsCOMPtr<nsIDOMEvent> event;
nsresult rv = GetTrustedPopupEvent(getter_AddRefs(event));
NS_ENSURE_SUCCESS(rv, rv);
if (! event)
return NS_ERROR_UNEXPECTED; // no event active
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (!pm)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNSUIEvent> uiEvent = do_QueryInterface(event, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = uiEvent->GetRangeParent(aRangeParent); // addrefs
PRInt32 offset;
pm->GetMouseLocation(aRangeParent, &offset);
if (NS_SUCCEEDED(rv) && *aRangeParent &&
!nsContentUtils::CanCallerAccess(*aRangeParent)) {
if (*aRangeParent && !nsContentUtils::CanCallerAccess(*aRangeParent)) {
NS_RELEASE(*aRangeParent);
return NS_ERROR_DOM_SECURITY_ERR;
}
return rv;
return NS_OK;
}
// Returns the rangeOffset element from the popupEvent. We check the rangeParent
// to determine if the caller has rights to access to the data.
// 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.
NS_IMETHODIMP
nsXULDocument::GetPopupRangeOffset(PRInt32* aRangeOffset)
{
NS_ENSURE_ARG_POINTER(aRangeOffset);
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);
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (!pm)
return NS_ERROR_FAILURE;
PRInt32 offset;
nsCOMPtr<nsIDOMNode> parent;
rv = uiEvent->GetRangeParent(getter_AddRefs(parent));
NS_ENSURE_SUCCESS(rv, rv);
pm->GetMouseLocation(getter_AddRefs(parent), &offset);
if (parent && !nsContentUtils::CanCallerAccess(parent))
return NS_ERROR_DOM_SECURITY_ERR;
return uiEvent->GetRangeOffset(aRangeOffset);
*aRangeOffset = offset;
return NS_OK;
}
NS_IMETHODIMP

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

@ -110,9 +110,4 @@ interface nsIDOMXULDocument : nsISupports
* Like trustedGetPopupNode, but gets the tooltip node instead.
*/
[noscript] nsIDOMNode trustedGetTooltipNode();
/**
* Like trustedGetPopupNode, but gets the
*/
[noscript] attribute nsIDOMEvent trustedPopupEvent;
};

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

@ -159,6 +159,7 @@
#include "nsIObserverService.h"
#include "nsIXULAppInfo.h"
#include "nsNetUtil.h"
#include "nsXULPopupManager.h"
#include "plbase64.h"
@ -3037,10 +3038,10 @@ nsGlobalWindow::CheckSecurityWidthAndHeight(PRInt32* aWidth, PRInt32* aHeight)
{
if (!nsContentUtils::IsCallerTrustedForWrite()) {
// if attempting to resize the window, hide any open popups
nsCOMPtr<nsIPresShell> presShell;
mDocShell->GetPresShell(getter_AddRefs(presShell));
if (presShell)
presShell->HidePopups();
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
if (pm && doc)
pm->HidePopupsInDocument(doc);
}
// This one is easy. Just ensure the variable is greater than 100;
@ -3070,10 +3071,10 @@ nsGlobalWindow::CheckSecurityLeftAndTop(PRInt32* aLeft, PRInt32* aTop)
if (!nsContentUtils::IsCallerTrustedForWrite()) {
// if attempting to move the window, hide any open popups
nsCOMPtr<nsIPresShell> presShell;
mDocShell->GetPresShell(getter_AddRefs(presShell));
if (presShell)
presShell->HidePopups();
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
if (pm && doc)
pm->HidePopupsInDocument(doc);
PRInt32 screenLeft, screenTop, screenWidth, screenHeight;
PRInt32 winLeft, winTop, winWidth, winHeight;

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

@ -119,7 +119,6 @@
#include "nsContentErrors.h"
#include "nsIDOMWindowInternal.h"
#include "nsIMenuFrame.h"
#include "nsBox.h"
@ -1706,11 +1705,8 @@ GetChildListNameFor(nsIFrame* aChildFrame)
// Out-of-flows that are DISPLAY_POPUP must be kids of the root popup set
#ifdef DEBUG
nsIFrame* parent = aChildFrame->GetParent();
if (parent) {
nsIPopupSetFrame* popupSet;
CallQueryInterface(parent, &popupSet);
NS_ASSERTION(popupSet, "Unexpected parent");
}
NS_ASSERTION(parent && parent->GetType() == nsGkAtoms::popupSetFrame,
"Unexpected parent");
#endif // DEBUG
// XXX FIXME: Bug 350740
@ -5956,9 +5952,7 @@ 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).
nsIMenuFrame* menuFrame;
CallQueryInterface(aParentFrame, &menuFrame);
if (!menuFrame) {
if (aParentFrame->GetType() != nsGkAtoms::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.
@ -5968,9 +5962,9 @@ nsCSSFrameConstructor::ConstructXULFrame(nsFrameConstructorState& aState,
}
#ifdef NS_DEBUG
nsIPopupSetFrame* popupSet;
CallQueryInterface(aState.mPopupItems.containingBlock, &popupSet);
NS_ASSERTION(popupSet, "Popup containing block isn't a nsIPopupSetFrame");
NS_ASSERTION(aState.mPopupItems.containingBlock->GetType() ==
nsGkAtoms::popupSetFrame,
"Popup containing block isn't a nsIPopupSetFrame");
#endif
isPopup = PR_TRUE;
}
@ -6145,6 +6139,16 @@ 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,
@ -10133,29 +10137,6 @@ 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;
@ -13025,3 +13006,42 @@ 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,6 +72,9 @@ struct nsFindFrameHint
nsFindFrameHint() : mPrimaryFrameForPrevSibling(nsnull) { }
};
typedef void (PR_CALLBACK nsLazyFrameConstructionCallback)
(nsIContent* aContent, nsIFrame* aFrame, void* aArg);
class nsFrameConstructorState;
class nsFrameConstructorSaveState;
@ -122,6 +125,17 @@ 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);
@ -1003,6 +1017,27 @@ 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,6 +111,7 @@
#ifdef MOZ_XUL
#include "nsIXULDocument.h"
#endif
#include "nsXULPopupManager.h"
#include "nsPrintfCString.h"
#include "nsIClipboardHelper.h"
@ -1153,10 +1154,9 @@ 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
if (mPresShell) {
nsCOMPtr<nsIPresShell> kungFuDeathGrip = mPresShell;
mPresShell->HidePopups();
}
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm && mDocument)
pm->HidePopupsInDocument(mDocument);
return NS_OK;
}

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

@ -102,10 +102,10 @@ class gfxContext;
typedef short SelectionType;
typedef PRUint32 nsFrameState;
// 9562bb2b-990c-4875-aafd-bd46fc9a4fc1
// D93B931B-D5EF-4D3C-AB99-444176963464
#define NS_IPRESSHELL_IID \
{ 0x9562bb2b, 0x990c, 0x4875, \
{ 0xaa, 0xfd, 0xbd, 0x46, 0xfc, 0x9a, 0x4f, 0xc1 } }
{ 0xd93b931b, 0xd5ef, 0x4d3c, \
{ 0xab, 0x99, 0x44, 0x41, 0x76, 0x96, 0x34, 0x64 } }
// Constants for ScrollContentIntoView() function
#define NS_PRESSHELL_SCROLL_TOP 0
@ -725,8 +725,6 @@ 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 "nsIMenuFrame.h"
#include "nsMenuFrame.h"
#include "nsITreeBoxObject.h"
#endif
#include "nsIMenuParent.h"
@ -888,8 +888,6 @@ public:
nsPoint& aPoint,
nsRect* aScreenRect);
virtual void HidePopups();
//nsIViewObserver interface
NS_IMETHOD Paint(nsIView *aView,
@ -5840,18 +5838,6 @@ 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
//--------------------------------------------------------
@ -6186,11 +6172,8 @@ 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.
nsCOMPtr<nsIMenuFrame> menuFrame(do_QueryInterface(aFrame));
if (menuFrame) {
menuFrame->UngenerateMenu();
menuFrame->OpenMenu(PR_FALSE);
}
if (aFrame && aFrame->GetType() == nsGkAtoms::menuFrame)
(NS_STATIC_CAST(nsMenuFrame *, aFrame))->CloseMenu(PR_TRUE);
return PR_TRUE;
}
@ -6328,27 +6311,6 @@ 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
//------------------------------------------------------

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

@ -235,7 +235,6 @@ 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,7 +507,6 @@ 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,11 +1190,6 @@ 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",

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

@ -79,6 +79,7 @@
#include "nsCellMap.h"
#include "nsTextFrameTextRunCache.h"
#include "nsCCUncollectableMarker.h"
#include "nsXULPopupManager.h"
#include "nsTextFragment.h"
#ifdef MOZ_XUL
@ -218,12 +219,19 @@ 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();

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

@ -497,7 +497,7 @@ nsContainerFrame::SyncFrameViewProperties(nsPresContext* aPresContext,
// visible in all cases because the scrollbars will be showing
// XXXldb Does the view system really enforce this correctly?
viewIsVisible = PR_FALSE;
} else {
} else if (aFrame->GetType() == nsGkAtoms::menuPopupFrame) {
// if the view is for a popup, don't show the view if the popup is closed
nsIWidget* widget = aView->GetWidget();
if (widget) {
@ -507,6 +507,11 @@ nsContainerFrame::SyncFrameViewProperties(nsPresContext* aPresContext,
widget->IsVisible(viewIsVisible);
}
}
else {
// widgets for popups can be created later when the popup is opened,
// so if there is no widget, the popup won't be open.
viewIsVisible = PR_FALSE;
}
}
vm->SetViewVisibility(aView, viewIsVisible ? nsViewVisibility_kShow :
@ -716,7 +721,12 @@ nsContainerFrame::PositionChildViews(nsIFrame* aFrame)
childFrame = childFrame->GetNextSibling();
}
childListName = aFrame->GetAdditionalChildListName(childListIndex++);
// 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,53 +38,25 @@
#ifndef nsIMenuFrame_h___
#define nsIMenuFrame_h___
// {2281EFC8-A8BA-4a73-8CF7-DB4EECA5EAEC}
#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}
#define NS_IMENUFRAME_IID \
{ 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
};
{ 0x212521C8, 0x1509, 0x4F41, { 0xAD, 0xDB, 0x6A, 0x0B, 0x93, 0x56, 0x77, 0x0F } }
class nsIMenuFrame : public nsISupports {
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMENUFRAME_IID)
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;
virtual PRBool IsOpen() = 0;
virtual PRBool IsMenu() = 0;
virtual PRBool IsOnMenuBar() = 0;
virtual PRBool IsOnActiveMenuBar() = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIMenuFrame, NS_IMENUFRAME_IID)

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

@ -41,16 +41,21 @@
interface nsIDOMElement;
[scriptable, uuid(116ffbea-336d-4ff1-a978-7335f54d11da)]
[scriptable, uuid(8714441F-0E24-4EB5-BE58-905F2854B4EB)]
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);
void hidePopup();
/**
* Hide the popup if it is open.
*/
void hidePopup();
/**
* Allow the popup to automatically position itself.
@ -58,7 +63,15 @@ interface nsIPopupBoxObject : nsISupports
attribute boolean autoPosition;
/**
* Allow the popup to eat all key events
* 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.
*/
void enableKeyboardNavigator(in boolean enableKeyboardNavigator);
@ -85,10 +98,62 @@ interface nsIPopupBoxObject : nsISupports
void sizeTo(in long width, in long height);
/**
* Move the popup to a point on screen
* Move the popup to a point on screen in CSS pixels.
*/
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++

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

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

@ -0,0 +1,636 @@
/* -*- 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,14 +119,13 @@ 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

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

@ -1793,25 +1793,37 @@ nsresult
nsBoxFrame::CreateViewForFrame(nsPresContext* aPresContext,
nsIFrame* aFrame,
nsStyleContext* aStyleContext,
PRBool aForce)
PRBool aForce,
PRBool aIsPopup)
{
NS_ASSERTION(aForce, "We only get called to force view creation now");
// If we don't yet have a view, see if we need a view
if (!aFrame->HasView()) {
nsViewVisibility visibility = nsViewVisibility_kShow;
PRInt32 zIndex = 0;
PRBool autoZIndex = PR_FALSE;
if (aForce) {
// Create a view
nsIFrame* parent = aFrame->GetAncestorWithView();
NS_ASSERTION(parent, "GetAncestorWithView failed");
nsIView* parentView = parent->GetView();
NS_ASSERTION(parentView, "no parent with view");
nsIViewManager* viewManager = parentView->GetViewManager();
nsIView* parentView;
nsIViewManager* viewManager = aPresContext->GetViewManager();
NS_ASSERTION(nsnull != viewManager, "null view manager");
// Create a view
nsIView *view = viewManager->CreateView(aFrame->GetRect(), parentView);
if (aIsPopup) {
viewManager->GetRootView(parentView);
visibility = nsViewVisibility_kHide;
zIndex = PR_INT32_MAX;
}
else {
nsIFrame* parent = aFrame->GetAncestorWithView();
NS_ASSERTION(parent, "GetAncestorWithView failed");
parentView = parent->GetView();
}
NS_ASSERTION(parentView, "no parent view");
// Create a view
nsIView *view = viewManager->CreateView(aFrame->GetRect(), parentView, visibility);
if (view) {
// Insert the view into the view hierarchy. If the parent view is a
// scrolling view we need to do this differently

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

@ -162,11 +162,14 @@ public:
virtual ~nsBoxFrame();
nsBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, PRBool aIsRoot = nsnull, nsIBoxLayout* aLayoutManager = nsnull);
// if aIsPopup is true, then the view is for a popup. In this case,
// the view is added a child of the root view, and is initially hidden
static nsresult CreateViewForFrame(nsPresContext* aPresContext,
nsIFrame* aChild,
nsStyleContext* aStyleContext,
PRBool aForce);
PRBool aForce,
PRBool aIsPopup = PR_FALSE);
// virtual so nsStackFrame, nsButtonBoxFrame, nsSliderFrame and nsMenuFrame
// can override it

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

@ -39,145 +39,53 @@
#ifndef nsIMenuParent_h___
#define nsIMenuParent_h___
// {33f700c8-976a-4cdb-8f6c-d9f4cfee8366}
#define NS_IMENUPARENT_IID \
{ 0x33f700c8, 0x976a, 0x4cdb, { 0x8f, 0x6c, 0xd9, 0xf4, 0xcf, 0xee, 0x83, 0x66 } }
class nsIMenuFrame;
class nsIDOMKeyEvent;
class nsMenuFrame;
/*
* nsIMenuParent is implemented on frames and thus should not be
* refcounted. Eventually it should not inherit from nsISupports.
*/
/**
* 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).
* nsIMenuParent is an interface implemented by nsMenuBarFrame and nsMenuPopupFrame
* as both serve as parent frames to nsMenuFrame.
*
* 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
*
* Don't implement this interface on other classes unless you also fix up references,
* as this interface is directly cast to and from nsMenuBarFrame and nsMenuPopupFrame.
*/
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
};
#ifdef IBMBIDI
#define NS_DIRECTION_FROM_KEY_CODE(direction, keycode) \
NS_ASSERTION(keycode >= NS_VK_END && keycode <= NS_VK_DOWN, \
"Illegal key code"); \
const nsStyleVisibility* vis = 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];
#else
#define NS_DIRECTION_FROM_KEY_CODE(direction, keycode) \
direction = DirectionFromKeyCode_lr_tb[keycode - NS_VK_END];
#endif
class nsIMenuParent : public nsISupports {
class nsIMenuParent {
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMENUPARENT_IID)
// returns the menu frame of the currently active item within the menu
virtual nsMenuFrame *GetCurrentMenuItem() = 0;
// sets the currently active menu frame.
NS_IMETHOD SetCurrentMenuItem(nsMenuFrame* aMenuItem) = 0;
// indicate that the current menu frame is being destroyed, so clear the
// current menu item
virtual void CurrentMenuIsBeingDestroyed() = 0;
// deselects the current item and closes its popup if any, then selects the
// new item aMenuItem. For a menubar, if another menu is already open, the
// new menu aMenuItem is opened. In this case, if aSelectFirstItem is true,
// select the first item in it. For menupoups, the menu is not opened and
// the aSelectFirstItem argument is not used.
NS_IMETHOD ChangeMenuItem(nsMenuFrame* aMenuItem, PRBool aSelectFirstItem) = 0;
virtual nsIMenuFrame *GetCurrentMenuItem() = 0;
NS_IMETHOD SetCurrentMenuItem(nsIMenuFrame* aMenuItem) = 0;
virtual nsIMenuFrame *GetNextMenuItem(nsIMenuFrame* aStart) = 0;
virtual nsIMenuFrame *GetPreviousMenuItem(nsIMenuFrame* aStart) = 0;
// returns true if the menupopup is open. For menubars, returns false.
virtual PRBool IsOpen() = 0;
// returns true if the menubar is currently active. For menupopups, returns false.
virtual PRBool IsActive() = 0;
// returns true if this is a menubar. If false, it is a popup
virtual PRBool IsMenuBar() = 0;
// returns true if this is a menu, which has a tag of menupopup or popup.
// Otherwise, this returns false
virtual PRBool IsMenu() = 0;
// returns true if this is a context menu
virtual PRBool IsContextMenu() = 0;
// indicate that the menubar should become active or inactive
NS_IMETHOD SetActive(PRBool aActiveFlag) = 0;
NS_IMETHOD GetIsActive(PRBool& isActive) = 0;
NS_IMETHOD GetWidget(nsIWidget **aWidget) = 0;
NS_IMETHOD IsMenuBar(PRBool& isMenuBar) = 0;
NS_IMETHOD ConsumeOutsideClicks(PRBool& aConsumeOutsideClicks) = 0;
NS_IMETHOD ClearRecentlyRolledUp() = 0;
NS_IMETHOD RecentlyRolledUp(nsIMenuFrame *aMenuFrame, PRBool *aJustRolledUp) = 0;
NS_IMETHOD DismissChain() = 0;
NS_IMETHOD HideChain() = 0;
NS_IMETHOD KillPendingTimers() = 0;
NS_IMETHOD CancelPendingTimers() = 0;
NS_IMETHOD AttachedDismissalListener() = 0;
NS_IMETHOD InstallKeyboardNavigator() = 0;
NS_IMETHOD RemoveKeyboardNavigator() = 0;
// Used to move up, down, left, and right in menus.
NS_IMETHOD KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag) = 0;
NS_IMETHOD ShortcutNavigation(nsIDOMKeyEvent* aKeyEvent, PRBool& aHandledFlag) = 0;
// Called when the ESC key is held down to close levels of menus.
NS_IMETHOD Escape(PRBool& aHandledFlag) = 0;
// Called to execute a menu item.
NS_IMETHOD Enter() = 0;
NS_IMETHOD SetIsContextMenu(PRBool aIsContextMenu) = 0;
NS_IMETHOD GetIsContextMenu(PRBool& aIsContextMenu) = 0;
NS_IMETHOD GetParentPopup(nsIMenuParent** aResult) = 0;
// notify that the menu has been closed and any active state should be
// cleared. This should return true if the menu should be deselected
// by the caller.
virtual PRBool MenuClosed() = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIMenuParent, NS_IMENUPARENT_IID)
#endif

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

@ -41,14 +41,14 @@
#define nsIRootBox_h___
#include "nsISupports.h"
class nsIFrame;
class nsPopupSetFrame;
class nsIContent;
class nsIPresShell;
// {2256d568-3f5a-42ec-b932-3d0f78551a1a}
// {9777EC2A-9A46-4D01-8CEB-B9CEB2C262A5}
#define NS_IROOTBOX_IID \
{ 0x2256d568, 0x3f5a, 0x42ec, \
{ 0xb9, 0x32, 0x3d, 0x0f, 0x78, 0x55, 0x1a, 0x1a } }
{ 0x9777EC2A, 0x9A46, 0x4D01, \
{ 0x8C, 0xEB, 0xB9, 0xCE, 0xB2, 0xC2, 0x62, 0xA5 } }
class nsIRootBox : public nsISupports {
@ -56,8 +56,8 @@ class nsIRootBox : public nsISupports {
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IROOTBOX_IID)
virtual nsIFrame* GetPopupSetFrame() = 0;
virtual void SetPopupSetFrame(nsIFrame* aPopupSet)=0;
virtual nsPopupSetFrame* GetPopupSetFrame() = 0;
virtual void SetPopupSetFrame(nsPopupSetFrame* aPopupSet) = 0;
virtual nsIContent* GetDefaultTooltip() = 0;
virtual void SetDefaultTooltip(nsIContent* aTooltip) = 0;

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

@ -37,11 +37,9 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsMenuListener.h"
#include "nsMenuBarFrame.h"
#include "nsIServiceManager.h"
#include "nsIContent.h"
#include "nsContentUtils.h"
#include "prtypes.h"
#include "nsIAtom.h"
#include "nsPresContext.h"
@ -79,51 +77,18 @@ NS_NewMenuBarFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
return new (aPresShell) nsMenuBarFrame (aPresShell, aContext);
}
NS_IMETHODIMP_(nsrefcnt)
nsMenuBarFrame::AddRef(void)
{
return NS_OK;
}
NS_IMETHODIMP_(nsrefcnt)
nsMenuBarFrame::Release(void)
{
return NS_OK;
}
//
// QueryInterface
//
NS_INTERFACE_MAP_BEGIN(nsMenuBarFrame)
NS_INTERFACE_MAP_ENTRY(nsIMenuParent)
NS_INTERFACE_MAP_END_INHERITING(nsBoxFrame)
//
// nsMenuBarFrame cntr
//
nsMenuBarFrame::nsMenuBarFrame(nsIPresShell* aShell, nsStyleContext* aContext):
nsBoxFrame(aShell, aContext),
mMenuBarListener(nsnull),
mKeyboardNavigator(nsnull),
mIsActive(PR_FALSE),
mTarget(nsnull),
mCaretWasVisible(PR_FALSE)
{
} // cntr
nsMenuBarFrame::~nsMenuBarFrame()
{
/* The menubar can still be active at this point under unusual circumstances.
(say, while switching skins (which tears down all frames including
this one) after having made a menu selection (say, Edit->Preferences,
to get to the skin switching UI)). SetActive(PR_FALSE) releases
mKeyboardNavigator, which is by now pointing to a deleted frame.
*/
SetActive(PR_FALSE);
}
NS_IMETHODIMP
nsMenuBarFrame::Init(nsIContent* aContent,
nsIFrame* aParent,
@ -156,20 +121,6 @@ nsMenuBarFrame::Init(nsIContent* aContent,
return rv;
}
NS_IMETHODIMP
nsMenuBarFrame::IsOpen()
{
PRBool isOpen = PR_FALSE;
if(mCurrentMenu) {
mCurrentMenu->MenuIsOpen(isOpen);
if (isOpen) {
return PR_TRUE;
}
}
return PR_FALSE;
}
NS_IMETHODIMP
nsMenuBarFrame::SetActive(PRBool aActiveFlag)
{
@ -177,6 +128,15 @@ nsMenuBarFrame::SetActive(PRBool aActiveFlag)
if (mIsActive == aActiveFlag)
return NS_OK;
if (!aActiveFlag) {
// if there is a request to deactivate the menu bar, check to see whether
// there is a menu popup open for the menu bar. In this case, don't
// deactivate the menu bar.
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm && pm->IsPopupOpenForMenuParent(this))
return NS_OK;
}
mIsActive = aActiveFlag;
if (mIsActive) {
InstallKeyboardNavigator();
@ -239,22 +199,22 @@ nsMenuBarFrame::SetActive(PRBool aActiveFlag)
NS_NAMED_LITERAL_STRING(active, "DOMMenuBarActive");
NS_NAMED_LITERAL_STRING(inactive, "DOMMenuBarInactive");
FireDOMEventSynch(mIsActive ? active : inactive);
FireDOMEvent(mIsActive ? active : inactive, mContent);
return NS_OK;
}
void
nsMenuFrame*
nsMenuBarFrame::ToggleMenuActiveState()
{
if (mIsActive) {
// Deactivate the menu bar
SetActive(PR_FALSE);
if (mCurrentMenu) {
// Deactivate the menu.
mCurrentMenu->OpenMenu(PR_FALSE);
mCurrentMenu->SelectMenu(PR_FALSE);
nsMenuFrame* closeframe = mCurrentMenu;
closeframe->SelectMenu(PR_FALSE);
mCurrentMenu = nsnull;
return closeframe;
}
}
else {
@ -268,7 +228,7 @@ nsMenuBarFrame::ToggleMenuActiveState()
// Set the active menu to be the top left item (e.g., the File menu).
// We use an attribute called "menuactive" to track the current
// active menu.
nsIMenuFrame* firstFrame = GetNextMenuItem(nsnull);
nsMenuFrame* firstFrame = nsXULPopupManager::GetNextMenuItem(this, nsnull, PR_FALSE);
if (firstFrame) {
firstFrame->SelectMenu(PR_TRUE);
@ -276,10 +236,13 @@ nsMenuBarFrame::ToggleMenuActiveState()
mCurrentMenu = firstFrame;
}
}
return nsnull;
}
static void GetInsertionPoint(nsIPresShell* aShell, nsIFrame* aFrame, nsIFrame* aChild,
nsIFrame** aResult)
static void
GetInsertionPoint(nsIPresShell* aShell, nsIFrame* aFrame, nsIFrame* aChild,
nsIFrame** aResult)
{
nsIContent* child = nsnull;
if (aChild)
@ -287,7 +250,7 @@ static void GetInsertionPoint(nsIPresShell* aShell, nsIFrame* aFrame, nsIFrame*
aShell->FrameConstructor()->GetInsertionPoint(aFrame, child, aResult);
}
nsIMenuFrame*
nsMenuFrame*
nsMenuBarFrame::FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent)
{
PRUint32 charCode;
@ -305,7 +268,7 @@ nsMenuBarFrame::FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent)
nsIContent* current = currFrame->GetContent();
// See if it's a menu item.
if (IsValidItem(current)) {
if (nsXULPopupManager::IsValidMenuItem(PresContext(), current, PR_FALSE)) {
// Get the shortcut attribute.
nsAutoString shortcutKey;
current->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, shortcutKey);
@ -315,11 +278,8 @@ nsMenuBarFrame::FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent)
if ( shortcutKey.Equals(Substring(&letter, &letter+1),
nsCaseInsensitiveStringComparator()) ) {
// We match!
nsIMenuFrame *menuFrame;
if (NS_FAILED(CallQueryInterface(currFrame, &menuFrame))) {
menuFrame = nsnull;
}
return menuFrame;
return (currFrame->GetType() == nsGkAtoms::menuFrame) ?
NS_STATIC_CAST(nsMenuFrame *, currFrame) : nsnull;
}
}
}
@ -335,263 +295,36 @@ nsMenuBarFrame::FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent)
soundInterface->Beep();
}
DismissChain();
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm)
pm->Rollup();
SetCurrentMenuItem(nsnull);
SetActive(PR_FALSE);
#endif // #ifdef XP_WIN
return nsnull;
}
NS_IMETHODIMP
nsMenuBarFrame::ShortcutNavigation(nsIDOMKeyEvent* aKeyEvent, PRBool& aHandledFlag)
{
if (mCurrentMenu) {
PRBool isOpen = PR_FALSE;
mCurrentMenu->MenuIsOpen(isOpen);
if (isOpen) {
// No way this applies to us. Give it to our child.
mCurrentMenu->ShortcutNavigation(aKeyEvent, aHandledFlag);
return NS_OK;
}
}
// This applies to us. Let's see if one of the shortcuts applies
nsIMenuFrame* result = FindMenuWithShortcut(aKeyEvent);
if (result) {
// We got one!
nsWeakFrame weakFrame(this);
nsIFrame* frame = nsnull;
CallQueryInterface(result, &frame);
nsWeakFrame weakResult(frame);
aHandledFlag = PR_TRUE;
SetActive(PR_TRUE);
if (weakFrame.IsAlive()) {
SetCurrentMenuItem(result);
}
if (weakResult.IsAlive()) {
result->OpenMenu(PR_TRUE);
if (weakResult.IsAlive()) {
result->SelectFirstItem();
}
}
}
return NS_OK;
}
NS_IMETHODIMP
nsMenuBarFrame::KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag)
{
nsNavigationDirection theDirection;
NS_DIRECTION_FROM_KEY_CODE(theDirection, aKeyCode);
if (!mCurrentMenu)
return NS_OK;
nsWeakFrame weakFrame(this);
PRBool isContainer = PR_FALSE;
PRBool isOpen = PR_FALSE;
mCurrentMenu->MenuIsContainer(isContainer);
mCurrentMenu->MenuIsOpen(isOpen);
aHandledFlag = PR_FALSE;
if (isOpen) {
// Let the child menu try to handle it.
mCurrentMenu->KeyboardNavigation(aKeyCode, aHandledFlag);
}
if (aHandledFlag)
return NS_OK;
if NS_DIRECTION_IS_INLINE(theDirection) {
nsIMenuFrame* nextItem = (theDirection == eNavigationDirection_End) ?
GetNextMenuItem(mCurrentMenu) :
GetPreviousMenuItem(mCurrentMenu);
nsIFrame* nextFrame = nsnull;
if (nextItem) {
CallQueryInterface(nextItem, &nextFrame);
}
nsWeakFrame weakNext(nextFrame);
SetCurrentMenuItem(nextItem);
if (weakNext.IsAlive()) {
PRBool nextIsOpen;
nextItem->MenuIsOpen(nextIsOpen);
if (nextIsOpen) {
// Select the first item.
nextItem->SelectFirstItem();
}
}
}
else if NS_DIRECTION_IS_BLOCK(theDirection) {
NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
nsIFrame* frame = nsnull;
CallQueryInterface(mCurrentMenu, &frame);
nsWeakFrame weakCurrentMenu(frame);
nsIMenuFrame* currentMenu = mCurrentMenu;
// Open the menu and select its first item.
currentMenu->OpenMenu(PR_TRUE);
if (weakCurrentMenu.IsAlive()) {
currentMenu->SelectFirstItem();
}
}
return NS_OK;
}
/* virtual */ nsIMenuFrame*
nsMenuBarFrame::GetNextMenuItem(nsIMenuFrame* aStart)
{
nsIFrame* immediateParent = nsnull;
GetInsertionPoint(PresContext()->PresShell(), this, nsnull, &immediateParent);
if (!immediateParent)
immediateParent = this;
nsIFrame* currFrame = nsnull;
nsIFrame* startFrame = nsnull;
if (aStart) {
aStart->QueryInterface(NS_GET_IID(nsIFrame), (void**)&currFrame);
if (currFrame) {
startFrame = currFrame;
currFrame = currFrame->GetNextSibling();
}
}
else
currFrame = immediateParent->GetFirstChild(nsnull);
while (currFrame) {
// See if it's a menu item.
if (IsValidItem(currFrame->GetContent())) {
nsIMenuFrame *menuFrame;
if (NS_FAILED(CallQueryInterface(currFrame, &menuFrame)))
menuFrame = nsnull;
return menuFrame;
}
currFrame = currFrame->GetNextSibling();
}
currFrame = immediateParent->GetFirstChild(nsnull);
// Still don't have anything. Try cycling from the beginning.
while (currFrame && currFrame != startFrame) {
// See if it's a menu item.
if (IsValidItem(currFrame->GetContent())) {
nsIMenuFrame *menuFrame;
if (NS_FAILED(CallQueryInterface(currFrame, &menuFrame)))
menuFrame = nsnull;
return menuFrame;
}
currFrame = currFrame->GetNextSibling();
}
// No luck. Just return our start value.
return aStart;
}
/* virtual */ nsIMenuFrame*
nsMenuBarFrame::GetPreviousMenuItem(nsIMenuFrame* aStart)
{
nsIFrame* immediateParent = nsnull;
GetInsertionPoint(PresContext()->PresShell(), this, nsnull, &immediateParent);
if (!immediateParent)
immediateParent = this;
nsFrameList frames(immediateParent->GetFirstChild(nsnull));
nsIFrame* currFrame = nsnull;
nsIFrame* startFrame = nsnull;
if (aStart) {
aStart->QueryInterface(NS_GET_IID(nsIFrame), (void**)&currFrame);
if (currFrame) {
startFrame = currFrame;
currFrame = frames.GetPrevSiblingFor(currFrame);
}
}
else currFrame = frames.LastChild();
while (currFrame) {
// See if it's a menu item.
if (IsValidItem(currFrame->GetContent())) {
nsIMenuFrame *menuFrame;
if (NS_FAILED(CallQueryInterface(currFrame, &menuFrame)))
menuFrame = nsnull;
return menuFrame;
}
currFrame = frames.GetPrevSiblingFor(currFrame);
}
currFrame = frames.LastChild();
// Still don't have anything. Try cycling from the end.
while (currFrame && currFrame != startFrame) {
// See if it's a menu item.
if (IsValidItem(currFrame->GetContent())) {
nsIMenuFrame *menuFrame;
if (NS_FAILED(CallQueryInterface(currFrame, &menuFrame)))
menuFrame = nsnull;
return menuFrame;
}
currFrame = frames.GetPrevSiblingFor(currFrame);
}
// No luck. Just return our start value.
return aStart;
}
/* virtual */ nsIMenuFrame*
/* virtual */ nsMenuFrame*
nsMenuBarFrame::GetCurrentMenuItem()
{
return mCurrentMenu;
}
NS_IMETHODIMP nsMenuBarFrame::SetCurrentMenuItem(nsIMenuFrame* aMenuItem)
NS_IMETHODIMP
nsMenuBarFrame::SetCurrentMenuItem(nsMenuFrame* aMenuItem)
{
if (mCurrentMenu == aMenuItem)
return NS_OK;
PRBool wasOpen = PR_FALSE;
// check if there's an open context menu, we ignore this
if (nsMenuFrame::GetContextMenu())
return NS_OK;
nsWeakFrame weakFrame(this);
if (mCurrentMenu)
mCurrentMenu->SelectMenu(PR_FALSE);
// Unset the current child.
if (mCurrentMenu) {
nsIFrame* frame = nsnull;
CallQueryInterface(mCurrentMenu, &frame);
nsWeakFrame weakCurrentMenu(frame);
nsIMenuFrame* currentMenu = mCurrentMenu;
currentMenu->MenuIsOpen(wasOpen);
currentMenu->SelectMenu(PR_FALSE);
if (wasOpen && weakCurrentMenu.IsAlive()) {
currentMenu->OpenMenu(PR_FALSE);
}
}
NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
// Set the new child.
if (aMenuItem) {
nsIFrame* newMenu = nsnull;
CallQueryInterface(aMenuItem, &newMenu);
nsWeakFrame weakNewMenu(newMenu);
if (aMenuItem)
aMenuItem->SelectMenu(PR_TRUE);
NS_ENSURE_TRUE(weakNewMenu.IsAlive(), NS_OK);
aMenuItem->MarkAsGenerated(); // Have the menu building. Get it ready to be shown.
NS_ENSURE_TRUE(weakNewMenu.IsAlive(), NS_OK);
PRBool isDisabled = PR_FALSE;
aMenuItem->MenuIsDisabled(isDisabled);
if (wasOpen&&!isDisabled)
aMenuItem->OpenMenu(PR_TRUE);
ClearRecentlyRolledUp();
}
NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
mCurrentMenu = aMenuItem;
@ -599,211 +332,103 @@ NS_IMETHODIMP nsMenuBarFrame::SetCurrentMenuItem(nsIMenuFrame* aMenuItem)
return NS_OK;
}
NS_IMETHODIMP
nsMenuBarFrame::Escape(PRBool& aHandledFlag)
void
nsMenuBarFrame::CurrentMenuIsBeingDestroyed()
{
if (!mCurrentMenu)
mCurrentMenu->SelectMenu(PR_FALSE);
mCurrentMenu = nsnull;
}
NS_IMETHODIMP
nsMenuBarFrame::ChangeMenuItem(nsMenuFrame* aMenuItem,
PRBool aSelectFirstItem)
{
if (mCurrentMenu == aMenuItem)
return NS_OK;
nsWeakFrame weakFrame(this);
// See if our menu is open.
PRBool isOpen = PR_FALSE;
mCurrentMenu->MenuIsOpen(isOpen);
if (isOpen) {
// Let the child menu handle this.
aHandledFlag = PR_FALSE;
mCurrentMenu->Escape(aHandledFlag);
NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
if (!aHandledFlag) {
// Close up this menu but keep our current menu item
// designation.
mCurrentMenu->OpenMenu(PR_FALSE);
NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
}
// check if there's an open context menu, we ignore this
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm && pm->HasContextMenu(nsnull))
return NS_OK;
// Unset the current child.
PRBool wasOpen = PR_FALSE;
if (mCurrentMenu) {
wasOpen = mCurrentMenu->IsOpen();
mCurrentMenu->SelectMenu(PR_FALSE);
if (wasOpen) {
nsMenuPopupFrame* popupFrame = mCurrentMenu->GetPopup();
if (popupFrame)
pm->HidePopup(popupFrame->GetContent(), PR_FALSE, PR_FALSE, PR_TRUE);
}
}
// Clear our current menu item if we've got one.
SetCurrentMenuItem(nsnull);
NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
// set to null first in case the IsAlive check below returns false
mCurrentMenu = nsnull;
SetActive(PR_FALSE);
// Set the new child.
if (aMenuItem) {
nsCOMPtr<nsIContent> content = aMenuItem->GetContent();
nsWeakFrame weakNewMenu(aMenuItem);
aMenuItem->SelectMenu(PR_TRUE);
NS_ENSURE_TRUE(weakNewMenu.IsAlive(), NS_OK);
mCurrentMenu = aMenuItem;
if (wasOpen && !aMenuItem->IsDisabled())
pm->ShowMenu(content, aSelectFirstItem, PR_TRUE);
}
// Clear out our dismissal listener
nsMenuDismissalListener::Shutdown();
return NS_OK;
}
NS_IMETHODIMP
nsMenuFrame*
nsMenuBarFrame::Enter()
{
if (!mCurrentMenu)
return NS_OK;
return nsnull;
ClearRecentlyRolledUp();
if (mCurrentMenu->IsOpen())
return mCurrentMenu->Enter();
// See if our menu is open.
PRBool isOpen = PR_FALSE;
mCurrentMenu->MenuIsOpen(isOpen);
if (isOpen) {
// Let the child menu handle this.
mCurrentMenu->Enter();
return NS_OK;
}
// It's us. Open the current menu.
mCurrentMenu->OpenMenu(PR_TRUE);
mCurrentMenu->SelectFirstItem();
return NS_OK;
return mCurrentMenu;
}
NS_IMETHODIMP
nsMenuBarFrame::ClearRecentlyRolledUp()
PRBool
nsMenuBarFrame::MenuClosed()
{
// We're no longer in danger of popping down a menu from the same
// click on the menubar, which was supposed to toggle the menu closed
mRecentRollupMenu = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsMenuBarFrame::RecentlyRolledUp(nsIMenuFrame *aMenuFrame, PRBool *aJustRolledUp)
{
// Don't let a click reopen a menu that was just rolled up
// from the same click. Otherwise, the user can't click on
// a menubar item to toggle its submenu closed.
*aJustRolledUp = (mRecentRollupMenu == aMenuFrame);
return NS_OK;
}
NS_IMETHODIMP
nsMenuBarFrame::HideChain()
{
// XXX hack if a context menu is active, do an Escape, which is
// currently bugged and destroys everything. We need to close
// the context menu first, otherwise SetCurrentMenuItem above
// would get blocked.
if (nsMenuFrame::GetContextMenu()) {
PRBool dummy;
mCurrentMenu->Escape(dummy);
}
// Stop capturing rollups
// (must do this during Hide, which happens before the menu item is executed,
// since this reinstates normal event handling.)
nsMenuDismissalListener::Shutdown();
ClearRecentlyRolledUp();
if (mCurrentMenu) {
mCurrentMenu->ActivateMenu(PR_FALSE);
SetActive(PR_FALSE);
if (!mIsActive && mCurrentMenu) {
mCurrentMenu->SelectMenu(PR_FALSE);
mRecentRollupMenu = mCurrentMenu;
mCurrentMenu = nsnull;
return PR_TRUE;
}
if (mIsActive) {
ToggleMenuActiveState();
}
return NS_OK;
return PR_FALSE;
}
NS_IMETHODIMP
nsMenuBarFrame::DismissChain()
{
// Stop capturing rollups
nsMenuDismissalListener::Shutdown();
nsWeakFrame weakFrame(this);
SetCurrentMenuItem(nsnull);
if (weakFrame.IsAlive()) {
SetActive(PR_FALSE);
}
return NS_OK;
}
NS_IMETHODIMP
nsMenuBarFrame::KillPendingTimers ( )
{
return NS_OK;
} // KillPendingTimers
NS_IMETHODIMP
nsMenuBarFrame::GetWidget(nsIWidget **aWidget)
{
// (pinkerton/hyatt)
// since the menubar is a menuparent but not a menuItem, the win32 rollup code
// would erroneously add the entire top-level window to the widget list built up for
// determining if a click is in a submenu's menu chain. To get around this, we just
// don't let the menubar have a widget. Things seem to work because the dismissal
// listener is registered when a new menu is popped up, which is the only real reason
// why we need a widget at all.
*aWidget = nsnull;
return NS_OK;
}
NS_IMETHODIMP
void
nsMenuBarFrame::InstallKeyboardNavigator()
{
if (mKeyboardNavigator)
return NS_OK;
mKeyboardNavigator = new nsMenuListener(this);
NS_IF_ADDREF(mKeyboardNavigator);
mTarget->AddEventListener(NS_LITERAL_STRING("keypress"), (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
mTarget->AddEventListener(NS_LITERAL_STRING("keydown"), (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
mTarget->AddEventListener(NS_LITERAL_STRING("keyup"), (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
nsContentUtils::NotifyInstalledMenuKeyboardListener(PR_TRUE);
return NS_OK;
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm)
pm->SetActiveMenuBar(this, PR_TRUE);
}
NS_IMETHODIMP
void
nsMenuBarFrame::RemoveKeyboardNavigator()
{
if (!mKeyboardNavigator || mIsActive)
return NS_OK;
mTarget->RemoveEventListener(NS_LITERAL_STRING("keypress"), (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
mTarget->RemoveEventListener(NS_LITERAL_STRING("keydown"), (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
mTarget->RemoveEventListener(NS_LITERAL_STRING("keyup"), (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
NS_IF_RELEASE(mKeyboardNavigator);
nsContentUtils::NotifyInstalledMenuKeyboardListener(PR_FALSE);
return NS_OK;
}
// helpers ///////////////////////////////////////////////////////////
PRBool
nsMenuBarFrame::IsValidItem(nsIContent* aContent)
{
nsIAtom *tag = aContent->Tag();
return ((tag == nsGkAtoms::menu ||
tag == nsGkAtoms::menuitem) &&
!IsDisabled(aContent));
}
PRBool
nsMenuBarFrame::IsDisabled(nsIContent* aContent)
{
return aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
nsGkAtoms::_true, eCaseMatters);
if (!mIsActive) {
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm)
pm->SetActiveMenuBar(this, PR_FALSE);
}
}
void
nsMenuBarFrame::Destroy()
{
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm)
pm->SetActiveMenuBar(this, PR_FALSE);
mTarget->RemoveEventListener(NS_LITERAL_STRING("keypress"), (nsIDOMKeyListener*)mMenuBarListener, PR_FALSE);
mTarget->RemoveEventListener(NS_LITERAL_STRING("keydown"), (nsIDOMKeyListener*)mMenuBarListener, PR_FALSE);
mTarget->RemoveEventListener(NS_LITERAL_STRING("keyup"), (nsIDOMKeyListener*)mMenuBarListener, PR_FALSE);
@ -815,4 +440,3 @@ nsMenuBarFrame::Destroy()
nsBoxFrame::Destroy();
}

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

@ -49,13 +49,12 @@
#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);
@ -63,47 +62,25 @@ class nsMenuBarFrame : public nsBoxFrame, public nsIMenuParent
{
public:
nsMenuBarFrame(nsIPresShell* aShell, nsStyleContext* aContext);
virtual ~nsMenuBarFrame();
NS_DECL_ISUPPORTS
// nsIMenuParentInterface
virtual nsIMenuFrame* GetCurrentMenuItem();
NS_IMETHOD SetCurrentMenuItem(nsIMenuFrame* aMenuItem);
virtual nsIMenuFrame* GetNextMenuItem(nsIMenuFrame* aStart);
virtual nsIMenuFrame* GetPreviousMenuItem(nsIMenuFrame* aStart);
virtual nsMenuFrame* GetCurrentMenuItem();
NS_IMETHOD SetCurrentMenuItem(nsMenuFrame* aMenuItem);
virtual void CurrentMenuIsBeingDestroyed();
NS_IMETHOD ChangeMenuItem(nsMenuFrame* aMenuItem, PRBool aSelectFirstItem);
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);
NS_IMETHOD SetIsContextMenu(PRBool aIsContextMenu) { return NS_OK; }
NS_IMETHOD GetIsContextMenu(PRBool& aIsContextMenu) { aIsContextMenu = PR_FALSE; return NS_OK; }
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 GetParentPopup(nsIMenuParent** aResult) { *aResult = nsnull;
return NS_OK;}
PRBool IsMenuOpen() { return mCurrentMenu && mCurrentMenu->IsOpen(); }
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; }
void InstallKeyboardNavigator();
void RemoveKeyboardNavigator();
NS_IMETHOD Init(nsIContent* aContent,
nsIFrame* aParent,
@ -111,24 +88,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.
void ToggleMenuActiveState();
// 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();
// Called when a menu on the menu bar is clicked on. Returns a menu if one
// needs to be closed.
nsMenuFrame* 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 handle ALT+key combos
nsIMenuFrame* FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent);
PRBool IsValidItem(nsIContent* aContent);
PRBool IsDisabled(nsIContent* aContent);
nsMenuFrame* FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent);
virtual PRBool IsFrameOfType(PRUint32 aFlags) const
{
@ -147,14 +124,11 @@ 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).
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;
// The current menu that is active (highlighted), which may not be open. This will
// be null if no menu is active.
nsMenuFrame* mCurrentMenu;
nsIDOMEventTarget* mTarget;

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

@ -40,6 +40,7 @@
#include "nsMenuBarListener.h"
#include "nsMenuBarFrame.h"
#include "nsMenuPopupFrame.h"
#include "nsIDOMKeyListener.h"
#include "nsIDOMEventTarget.h"
#include "nsIDOMEventListener.h"
@ -131,6 +132,18 @@ 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)
@ -161,7 +174,7 @@ nsMenuBarListener::KeyUp(nsIDOMEvent* aKeyEvent)
{
// The access key was down and is now up, and no other
// keys were pressed in between.
mMenuBarFrame->ToggleMenuActiveState();
ToggleMenuActiveState();
}
mAccessKeyDown = PR_FALSE;
@ -169,7 +182,7 @@ nsMenuBarListener::KeyUp(nsIDOMEvent* aKeyEvent)
if (active) {
aKeyEvent->StopPropagation();
aKeyEvent->PreventDefault();
return NS_ERROR_BASE; // I am consuming event
return NS_OK; // I am consuming event
}
}
@ -180,8 +193,6 @@ 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 ) {
@ -229,14 +240,13 @@ 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.
PRBool active = PR_FALSE;
mMenuBarFrame->ShortcutNavigation(keyEvent, active);
if (active) {
nsMenuFrame* result = mMenuBarFrame->FindMenuWithShortcut(keyEvent);
if (result) {
mMenuBarFrame->SetActive(PR_TRUE);
result->OpenMenu(PR_TRUE);
aKeyEvent->StopPropagation();
aKeyEvent->PreventDefault();
retVal = NS_ERROR_BASE; // I am consuming event
retVal = NS_OK; // I am consuming event
}
}
#if !defined(XP_MAC) && !defined(XP_MACOSX)
@ -245,16 +255,17 @@ 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.
mMenuBarFrame->ToggleMenuActiveState();
ToggleMenuActiveState();
aKeyEvent->StopPropagation();
aKeyEvent->PreventDefault();
return NS_ERROR_BASE; // consume the event
return NS_OK; // consume the event
}
}
#endif // !XP_MAC && !XP_MACOSX
}
}
return retVal;
}
@ -349,10 +360,8 @@ nsMenuBarListener::Focus(nsIDOMEvent* aEvent)
nsresult
nsMenuBarListener::Blur(nsIDOMEvent* aEvent)
{
if (!mMenuBarFrame->IsOpen() && mMenuBarFrame->IsActive()) {
mMenuBarFrame->ToggleMenuActiveState();
PRBool handled;
mMenuBarFrame->Escape(handled);
if (!mMenuBarFrame->IsMenuOpen() && mMenuBarFrame->IsActive()) {
ToggleMenuActiveState();
mAccessKeyDown = PR_FALSE;
}
return NS_OK; // means I am NOT consuming event
@ -362,12 +371,8 @@ nsMenuBarListener::Blur(nsIDOMEvent* aEvent)
nsresult
nsMenuBarListener::MouseDown(nsIDOMEvent* aMouseEvent)
{
if (!mMenuBarFrame->IsOpen() && mMenuBarFrame->IsActive()) {
mMenuBarFrame->ToggleMenuActiveState();
PRBool handled;
mMenuBarFrame->Escape(handled);
}
if (!mMenuBarFrame->IsMenuOpen() && mMenuBarFrame->IsActive())
ToggleMenuActiveState();
mAccessKeyDown = PR_FALSE;
return NS_OK; // means I am NOT consuming event
@ -377,8 +382,6 @@ nsMenuBarListener::MouseDown(nsIDOMEvent* aMouseEvent)
nsresult
nsMenuBarListener::MouseUp(nsIDOMEvent* aMouseEvent)
{
mMenuBarFrame->ClearRecentlyRolledUp();
return NS_OK; // means I am NOT consuming event
}

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

@ -87,6 +87,10 @@ 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,11 +39,12 @@
#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
@ -88,47 +89,41 @@ nsMenuBoxObject::~nsMenuBoxObject()
/* void openMenu (in boolean openFlag); */
NS_IMETHODIMP nsMenuBoxObject::OpenMenu(PRBool aOpenFlag)
{
nsIFrame* frame = GetFrame(PR_FALSE);
if (!frame)
return NS_OK;
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 (!nsPopupSetFrame::MayOpenPopup(frame))
return NS_OK;
nsIMenuFrame* menuFrame;
CallQueryInterface(frame, &menuFrame);
if (!menuFrame)
return NS_OK;
return menuFrame->OpenMenu(aOpenFlag);
return NS_OK;
}
NS_IMETHODIMP nsMenuBoxObject::GetActiveChild(nsIDOMElement** aResult)
{
*aResult = nsnull;
nsIFrame* frame = GetFrame(PR_FALSE);
if (!frame)
return NS_OK;
nsIMenuFrame* menuFrame;
CallQueryInterface(frame, &menuFrame);
if (menuFrame)
menuFrame->GetActiveChild(aResult);
if (frame && frame->GetType() == nsGkAtoms::menuFrame)
return NS_STATIC_CAST(nsMenuFrame *, frame)->GetActiveChild(aResult);
return NS_OK;
}
NS_IMETHODIMP nsMenuBoxObject::SetActiveChild(nsIDOMElement* aResult)
{
nsIFrame* frame = GetFrame(PR_FALSE);
if (!frame)
return NS_OK;
nsIMenuFrame* menuFrame;
CallQueryInterface(frame, &menuFrame);
if (menuFrame) {
menuFrame->MarkAsGenerated();
menuFrame->SetActiveChild(aResult);
}
if (frame && frame->GetType() == nsGkAtoms::menuFrame)
return NS_STATIC_CAST(nsMenuFrame *, frame)->SetActiveChild(aResult);
return NS_OK;
}
@ -138,6 +133,10 @@ 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,12 +151,11 @@ NS_IMETHODIMP nsMenuBoxObject::HandleKeyPress(nsIDOMKeyEvent* aKeyEvent, PRBool*
return NS_OK;
nsIFrame* frame = GetFrame(PR_FALSE);
if (!frame)
if (!frame || frame->GetType() != nsGkAtoms::menuFrame)
return NS_OK;
nsIMenuFrame* menuFrame;
CallQueryInterface(frame, &menuFrame);
if (!menuFrame)
nsMenuPopupFrame* popupFrame = NS_STATIC_CAST(nsMenuFrame *, frame)->GetPopup();
if (!popupFrame)
return NS_OK;
PRUint32 keyCode;
@ -167,9 +165,11 @@ NS_IMETHODIMP nsMenuBoxObject::HandleKeyPress(nsIDOMKeyEvent* aKeyEvent, PRBool*
case NS_VK_DOWN:
case NS_VK_HOME:
case NS_VK_END:
return menuFrame->KeyboardNavigation(keyCode, *aHandledFlag);
*aHandledFlag = pm->HandleKeyboardNavigation(keyCode);
return NS_OK;
default:
return menuFrame->ShortcutNavigation(aKeyEvent, *aHandledFlag);
*aHandledFlag = pm->HandleShortcutNavigation(aKeyEvent);
return NS_OK;
}
}

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

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

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -49,9 +49,10 @@
#include "nsBoxFrame.h"
#include "nsFrameList.h"
#include "nsGkAtoms.h"
#include "nsIMenuParent.h"
#include "nsIMenuFrame.h"
#include "nsMenuDismissalListener.h"
#include "nsXULPopupManager.h"
#include "nsITimer.h"
#include "nsISupportsArray.h"
#include "nsIDOMText.h"
@ -61,11 +62,21 @@
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;
/**
@ -93,7 +104,7 @@ private:
};
/**
* @note *** Methods marked with '@see comment ***' may cause the frame to be
* @note *** Methods marked with '@see comment above ***' may cause the frame to be
* deleted during the method call. Be careful whenever using those
* methods.
*/
@ -122,14 +133,14 @@ public:
NS_IMETHOD IsActive(PRBool& aResult) { aResult = PR_TRUE; return NS_OK; }
// 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).
// 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.
virtual nsIFrame* GetFirstChild(nsIAtom* aListName) const;
NS_IMETHOD SetInitialChildList(nsIAtom* aListName,
nsIFrame* aChildList);
virtual nsIAtom* GetAdditionalChildListName(PRInt32 aIndex) const;
virtual void Destroy(); // @see comment ***
virtual void Destroy(); // @see comment above ***
// Overridden to prevent events from going to children of the menu.
NS_IMETHOD BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder,
@ -138,7 +149,7 @@ public:
NS_IMETHOD HandleEvent(nsPresContext* aPresContext,
nsGUIEvent* aEvent,
nsEventStatus* aEventStatus); // @see comment ***
nsEventStatus* aEventStatus); // @see comment above ***
NS_IMETHOD AppendFrames(nsIAtom* aListName,
nsIFrame* aFrameList);
@ -150,36 +161,35 @@ public:
NS_IMETHOD RemoveFrame(nsIAtom* aListName,
nsIFrame* aOldFrame);
// nsIMenuFrame Interface
virtual nsIAtom* GetType() const { return nsGkAtoms::menuFrame; }
NS_IMETHOD ActivateMenu(PRBool aActivateFlag); // @see comment ***
NS_IMETHOD SelectMenu(PRBool aActivateFlag); // @see comment ***
NS_IMETHOD OpenMenu(PRBool aActivateFlag); // @see comment ***
NS_IMETHOD SelectMenu(PRBool aActivateFlag); // @see comment above ***
/**
* 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 ***
NS_IMETHOD SetActiveChild(nsIDOMElement* aChild); // @see comment above ***
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 ***
// 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 SetParent(const nsIFrame* aParent);
virtual nsIMenuParent *GetMenuParent() { return mMenuParent; }
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();
const nsAString& GetRadioGroupName() { return mGroupName; }
nsMenuType GetMenuType() { return mType; }
nsMenuPopupFrame* GetPopup() { return mPopupFrame; }
// nsIScrollableViewProvider methods
@ -189,12 +199,26 @@ public:
nsresult DestroyPopupFrames(nsPresContext* aPresContext);
PRBool IsOpen() { return mMenuOpen; }
PRBool IsMenu();
virtual PRBool IsOnMenuBar() { return mMenuParent && mMenuParent->IsMenuBar(); }
virtual PRBool IsOnActiveMenuBar() { return IsOnMenuBar() && mMenuParent->IsActive(); }
virtual PRBool IsOpen();
virtual PRBool IsMenu();
PRBool IsDisabled();
PRBool IsGenerated();
NS_IMETHOD ToggleMenuState(); // @see comment ***
void ToggleMenuState();
// 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
@ -206,44 +230,27 @@ 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 ***
void OpenMenuInternal(PRBool aActivateFlag); // @see comment ***
void GetMenuChildrenElement(nsIContent** aResult);
// 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 ***
// Examines the key node and builds the accelerator.
void BuildAcceleratorText();
// Called to execute our command handler.
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 ***
void Execute(nsGUIEvent *aEvent); // @see comment above ***
NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
PRInt32 aModType); // @see comment ***
PRInt32 aModType); // @see comment above ***
virtual ~nsMenuFrame();
PRBool SizeToPopup(nsBoxLayoutState& aState, nsSize& aSize);
@ -254,22 +261,23 @@ 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,9 +47,10 @@
#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"
@ -57,6 +58,20 @@
#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:
@ -69,75 +84,54 @@ 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 nsIMenuFrame* GetCurrentMenuItem();
NS_IMETHOD SetCurrentMenuItem(nsIMenuFrame* aMenuItem);
virtual nsIMenuFrame* GetNextMenuItem(nsIMenuFrame* aStart);
virtual nsIMenuFrame* GetPreviousMenuItem(nsIMenuFrame* aStart);
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; }
NS_IMETHOD SetActive(PRBool aActiveFlag) { return NS_OK; } // We don't care.
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; }
NS_IMETHOD GetParentPopup(nsIMenuParent** aResult);
virtual PRBool IsActive() { return PR_FALSE; }
virtual PRBool IsMenuBar() { return PR_FALSE; }
// Closes up the chain of open cascaded menus.
NS_IMETHOD DismissChain();
/*
* 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();
// Hides the chain of cascaded menus without closing them up.
NS_IMETHOD HideChain();
virtual PRBool IsContextMenu() { return mIsContextMenu; }
NS_IMETHOD KillPendingTimers();
NS_IMETHOD CancelPendingTimers();
NS_IMETHOD InstallKeyboardNavigator();
NS_IMETHOD RemoveKeyboardNavigator();
virtual PRBool MenuClosed() { return PR_TRUE; }
NS_IMETHOD GetWidget(nsIWidget **aWidget);
// The dismissal listener gets created and attached to the window.
NS_IMETHOD AttachedDismissalListener();
void AttachedDismissalListener();
// Overridden methods
NS_IMETHOD Init(nsIContent* aContent,
@ -148,41 +142,92 @@ public:
nsIAtom* aAttribute,
PRInt32 aModType);
NS_IMETHOD HandleEvent(nsPresContext* aPresContext,
nsGUIEvent* aEvent,
nsEventStatus* aEventStatus);
virtual void Destroy();
virtual void InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild,
PRBool aImmediate);
void EnsureWidget();
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);
static void GetRootViewForPopup(nsIFrame* aStartFrame,
PRBool aStopAtViewManagerRoot,
nsIView** aResult);
nsIView* GetRootViewForPopup(nsIFrame* aStartFrame,
PRBool aStopAtViewManagerRoot);
nsresult SyncViewWithFrame(nsPresContext* aPresContext, const nsString& aPopupAnchor,
const nsString& aPopupAlign,
nsIFrame* aFrame, PRInt32 aXPos, PRInt32 aYPos);
// 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);
NS_IMETHOD KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag);
NS_IMETHOD ShortcutNavigation(nsIDOMKeyEvent* aKeyEvent, PRBool& aHandledFlag);
NS_IMETHOD Escape(PRBool& aHandledFlag);
NS_IMETHOD Enter();
PRBool HasGeneratedChildren() { return mGeneratedChildren; }
void SetGeneratedChildren() { mGeneratedChildren = PR_TRUE; }
nsIMenuFrame* FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent, PRBool& doAction);
// 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();
PRBool IsValidItem(nsIContent* aContent);
PRBool IsDisabled(nsIContent* aContent);
PRInt32 PopupType() const { return mPopupType; }
PRBool IsMenu() { return mPopupType == ePopupTypeMenu; }
PRBool IsOpen() { return mIsOpen; }
PRBool HasOpenChanged() { return mIsOpenChanged; }
nsIMenuParent* GetContextMenu();
// 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);
NS_IMETHOD KillCloseTimer();
void InitializePopupAtScreen(PRInt32 aXPos, PRInt32 aYPos);
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(); }
virtual nsIAtom* GetType() const { return nsGkAtoms::menuPopupFrame; }
@ -193,7 +238,7 @@ public:
}
#endif
void EnsureMenuItemIsVisible(nsIMenuFrame* aMenuFrame);
void EnsureMenuItemIsVisible(nsMenuFrame* aMenuFrame);
// This sets 'left' and 'top' attributes.
// May kill the frame.
@ -201,30 +246,22 @@ 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);
// 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);
// 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 InitPositionFromAnchorAlign(const nsAString& aAnchor,
const nsAString& aAlign);
void AdjustPositionForAnchorAlign ( PRInt32* ioXPos, PRInt32* ioYPos, const nsRect & inParentRect,
const nsString& aPopupAnchor, const nsString& aPopupAlign,
PRBool* outFlushWithTopBottom ) ;
PRBool* outFlushWithTopBottom ) ;
PRBool IsMoreRoomOnOtherSideOfParent ( PRBool inFlushAboveBelow, PRInt32 inScreenViewLocX, PRInt32 inScreenViewLocY,
const nsRect & inScreenParentFrameRect, PRInt32 inScreenTopTwips, PRInt32 inScreenLeftTwips,
@ -238,24 +275,33 @@ 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;
nsIMenuFrame* mCurrentMenu; // The current menu that is active.
nsMenuFrame* mCurrentMenu; // The current menu that is active.
nsMenuListener* mKeyboardNavigator; // The listener that tells us about key events.
nsIDOMEventTarget* mTarget;
// popup alignment relative to the anchor node
PRInt8 mPopupAlignment;
PRInt8 mPopupAnchor;
nsIMenuFrame* mTimerMenu; // A menu awaiting closure.
nsCOMPtr<nsITimer> mCloseTimer; // Close timer.
// 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;
// Reference to the mediator which wraps this frame.
nsRefPtr<nsMenuPopupTimerMediator> mTimerMediator;
nsPopupType mPopupType; // type of popup
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 SyncViewWithFrame be allowed to auto position popup?
PRPackedBool mShouldRollup; // Should this menupopup be allowed to dismiss automatically?
PRPackedBool mShouldAutoPosition; // Should SetPopupPosition be allowed to auto position popup?
PRPackedBool mConsumeRollupEvent; // Should the rollup event be consumed?
PRPackedBool mInContentShell; // True if the popup is in a content shell

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

@ -38,7 +38,6 @@
* ***** END LICENSE BLOCK ***** */
#include "nsCOMPtr.h"
#include "nsIPopupBoxObject.h"
#include "nsIPopupSetFrame.h"
#include "nsIRootBox.h"
#include "nsBoxObject.h"
#include "nsIPresShell.h"
@ -64,87 +63,86 @@ public:
protected:
virtual ~nsPopupBoxObject() {}
nsIPopupSetFrame* GetPopupSetFrame();
nsPopupSetFrame* GetPopupSetFrame();
nsMenuPopupFrame* GetMenuPopupFrame()
{ return NS_STATIC_CAST(nsMenuPopupFrame*, GetFrame(PR_FALSE)); }
{
nsIFrame* frame = GetFrame(PR_FALSE);
if (frame && frame->GetType() == nsGkAtoms::menuPopupFrame)
return NS_STATIC_CAST(nsMenuPopupFrame*, frame);
return nsnull;
}
};
NS_IMPL_ISUPPORTS_INHERITED1(nsPopupBoxObject, nsBoxObject, nsIPopupBoxObject)
nsIPopupSetFrame*
nsPopupSetFrame*
nsPopupBoxObject::GetPopupSetFrame()
{
nsIRootBox* rootBox = nsIRootBox::GetRootBox(GetPresShell(PR_FALSE));
if (!rootBox)
return nsnull;
nsIFrame* popupSetFrame = rootBox->GetPopupSetFrame();
if (!popupSetFrame)
return nsnull;
nsIPopupSetFrame *popupSet = nsnull;
CallQueryInterface(popupSetFrame, &popupSet);
return popupSet;
return rootBox->GetPopupSetFrame();
}
NS_IMETHODIMP
nsPopupBoxObject::HidePopup()
{
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);
}
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm)
pm->HidePopup(mContent, PR_FALSE, PR_TRUE, PR_FALSE);
return NS_OK;
}
NS_IMETHODIMP
nsPopupBoxObject::ShowPopup(nsIDOMElement* aAnchorElement,
nsIDOMElement* aPopupElement,
PRInt32 aXPos, PRInt32 aYPos,
const PRUnichar *aPopupType,
const PRUnichar *aAnchorAlignment,
const PRUnichar *aPopupAlignment)
{
NS_ENSURE_TRUE(aPopupElement, 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"));
}
return NS_OK;
}
NS_IMETHODIMP
nsPopupBoxObject::ShowPopup(nsIDOMElement* aSrcContent,
nsIDOMElement* aPopupContent,
PRInt32 aXPos, PRInt32 aYPos,
const PRUnichar *aPopupType,
const PRUnichar *anAnchorAlignment,
const PRUnichar *aPopupAlignment)
nsPopupBoxObject::OpenPopup(nsIDOMElement* aAnchorElement,
const nsAString& aPosition,
PRInt32 aXPos, PRInt32 aYPos,
PRBool aIsContextMenu,
PRBool aAttributesOverride)
{
nsIPopupSetFrame *popupSet = GetPopupSetFrame();
if (!popupSet) {
return NS_OK;
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm) {
nsCOMPtr<nsIContent> anchorContent(do_QueryInterface(aAnchorElement));
pm->ShowPopup(mContent, anchorContent, aPosition, aXPos, aYPos,
aIsContextMenu, aAttributesOverride, PR_FALSE);
}
nsCOMPtr<nsIContent> srcContent(do_QueryInterface(aSrcContent));
nsCOMPtr<nsIContent> popupContent(do_QueryInterface(aPopupContent));
NS_ENSURE_TRUE(popupContent, NS_ERROR_INVALID_ARG);
// srcContent can be null.
return NS_OK;
}
nsAutoString popupType(aPopupType);
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 popupSet->ShowPopup(srcContent, popupContent, aXPos, aYPos,
popupType, anchorAlign, popupAlign);
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;
}
NS_IMETHODIMP
@ -197,11 +195,7 @@ nsPopupBoxObject::SetAutoPosition(PRBool aShouldAutoPosition)
NS_IMETHODIMP
nsPopupBoxObject::EnableRollup(PRBool aShouldRollup)
{
nsMenuPopupFrame *menuPopupFrame = GetMenuPopupFrame();
if (menuPopupFrame) {
menuPopupFrame->EnableRollup(aShouldRollup);
}
// this does nothing nows
return NS_OK;
}
@ -219,14 +213,12 @@ nsPopupBoxObject::SetConsumeRollupEvent(PRUint32 aConsume)
NS_IMETHODIMP
nsPopupBoxObject::EnableKeyboardNavigator(PRBool aEnableKeyboardNavigator)
{
nsMenuPopupFrame *menuPopupFrame = GetMenuPopupFrame();
if (menuPopupFrame) {
if (aEnableKeyboardNavigator) {
menuPopupFrame->InstallKeyboardNavigator();
} else {
menuPopupFrame->RemoveKeyboardNavigator();
}
}
// 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);
return NS_OK;
}
@ -242,4 +234,3 @@ NS_NewPopupBoxObject(nsIBoxObject** aResult)
NS_ADDREF(*aResult);
return NS_OK;
}

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

@ -66,47 +66,16 @@
#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),
mElementContent(nsnull),
mCreateHandlerSucceeded(PR_FALSE),
mIsOpen(PR_FALSE),
mLastPref(-1,-1)
mPopupContent(aPopupContent)
{
}
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
//
@ -118,25 +87,6 @@ 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,
@ -198,31 +148,14 @@ nsPopupSetFrame::SetInitialChildList(nsIAtom* aListName,
void
nsPopupSetFrame::Destroy()
{
// 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();
}
}
// remove each popup from the list as we go.
while (mPopupList) {
if (mPopupList->mPopupFrame)
mPopupList->mPopupFrame->Destroy();
// 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) {
mPopupList->mPopupFrame->Destroy();
}
nsPopupFrameList* temp = mPopupList;
mPopupList = mPopupList->mNextPopup;
delete temp;
}
nsPopupFrameList* temp = mPopupList;
mPopupList = mPopupList->mNextPopup;
delete temp;
}
nsIRootBox *rootBox;
@ -244,10 +177,8 @@ nsPopupSetFrame::DoLayout(nsBoxLayoutState& aState)
// lay out all of our currently open popups.
nsPopupFrameList* currEntry = mPopupList;
while (currEntry) {
nsIFrame* popupChild = currEntry->mPopupFrame;
if (popupChild) {
NS_ASSERTION(popupChild->IsBoxFrame(), "popupChild is not box!!");
nsMenuPopupFrame* popupChild = currEntry->mPopupFrame;
if (popupChild && popupChild->IsOpen()) {
// then get its preferred size
nsSize prefSize = popupChild->GetPrefSize(aState);
nsSize minSize = popupChild->GetMinSize(aState);
@ -255,13 +186,8 @@ 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));
RepositionPopup(currEntry, aState);
currEntry->mLastPref = prefSize;
// }
popupChild->SetBounds(aState, nsRect(0,0,prefSize.width, prefSize.height));
popupChild->SetPopupPosition(nsnull);
// is the new size too small? Make sure we handle scrollbars correctly
nsIBox* child = popupChild->GetChildBox();
@ -280,493 +206,22 @@ 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);
}
}
}
// layout the child
popupChild->Layout(aState);
// 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);
}
popupChild->AdjustView();
}
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)
{
NS_ASSERTION(aElementContent != aPopupContent, "self referential popup");
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)
{
@ -813,14 +268,18 @@ 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 = nsnull;
if (mPopupList)
entry = mPopupList->GetEntry(content);
nsPopupFrameList* entry = mPopupList;
while (entry && entry->mPopupContent != content)
entry = entry->mNextPopup;
if (!entry) {
entry = new nsPopupFrameList(content, mPopupList);
if (!entry)
@ -832,49 +291,7 @@ nsPopupSetFrame::AddPopupFrame(nsIFrame* aPopup)
}
// Set the frame connection.
entry->mPopupFrame = aPopup;
entry->mPopupFrame = NS_STATIC_CAST(nsMenuPopupFrame *, 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,10 +46,11 @@
#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"
@ -58,35 +59,20 @@ nsIFrame* NS_NewPopupSetFrame(nsIPresShell* aPresShell, nsStyleContext* aContext
struct nsPopupFrameList {
nsPopupFrameList* mNextPopup; // The next popup in the list.
nsIFrame* mPopupFrame; // Our popup.
nsMenuPopupFrame* 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, public nsIPopupSetFrame
class nsPopupSetFrame : public nsBoxFrame
{
public:
nsPopupSetFrame(nsIPresShell* aShell, nsStyleContext* aContext):
nsBoxFrame(aShell, aContext) {}
NS_DECL_ISUPPORTS
~nsPopupSetFrame() {}
NS_IMETHOD Init(nsIContent* aContent,
nsIFrame* aParent,
@ -100,41 +86,14 @@ public:
nsIFrame* aFrameList);
NS_IMETHOD SetInitialChildList(nsIAtom* aListName,
nsIFrame* aChildList);
// 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();
// 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);
virtual nsIAtom* GetType() const { return nsGkAtoms::popupSetFrame; }
#ifdef DEBUG
NS_IMETHOD GetFrameName(nsAString& aResult) const
@ -149,13 +108,6 @@ 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 nsIFrame* GetPopupSetFrame();
virtual void SetPopupSetFrame(nsIFrame* aPopupSet);
virtual nsPopupSetFrame* GetPopupSetFrame();
virtual void SetPopupSetFrame(nsPopupSetFrame* 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
nsIFrame* mPopupSetFrame;
nsPopupSetFrame* mPopupSetFrame;
protected:
nsIContent* mDefaultTooltip;
@ -275,14 +275,14 @@ nsRootBoxFrame::GetType() const
return nsGkAtoms::rootFrame;
}
nsIFrame*
nsPopupSetFrame*
nsRootBoxFrame::GetPopupSetFrame()
{
return mPopupSetFrame;
}
void
nsRootBoxFrame::SetPopupSetFrame(nsIFrame* aPopupSet)
nsRootBoxFrame::SetPopupSetFrame(nsPopupSetFrame* aPopupSet)
{
// Under normal conditions this should only be called once. However,
// if something triggers ReconstructDocElementHierarchy, we will

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -46,7 +46,6 @@
#include "nsGkAtoms.h"
#include "nsIPresShell.h"
#include "nsIFrame.h"
#include "nsIMenuFrame.h"
#include "nsIPopupBoxObject.h"
#include "nsIServiceManager.h"
#ifdef MOZ_XUL
@ -59,6 +58,7 @@
#include "nsIScriptContext.h"
#include "nsPIDOMWindow.h"
#include "nsContentUtils.h"
#include "nsXULPopupManager.h"
#include "nsIRootBox.h"
nsXULTooltipListener* nsXULTooltipListener::mInstance = nsnull;
@ -209,8 +209,8 @@ nsXULTooltipListener::MouseMove(nsIDOMEvent* aMouseEvent)
// mouse has really moved before proceeding.
nsCOMPtr<nsIDOMMouseEvent> mouseEvent(do_QueryInterface(aMouseEvent));
PRInt32 newMouseX, newMouseY;
mouseEvent->GetClientX(&newMouseX);
mouseEvent->GetClientY(&newMouseY);
mouseEvent->GetScreenX(&newMouseX);
mouseEvent->GetScreenY(&newMouseY);
if (mMouseClientX == newMouseX && mMouseClientY == newMouseY)
return NS_OK;
mMouseClientX = newMouseX;
@ -413,12 +413,8 @@ nsXULTooltipListener::ShowTooltip()
// at this point, |mCurrentTooltip| holds the content node of
// the tooltip. If there is an attribute on the popup telling us
// not to create the auto-hide timer, don't.
nsCOMPtr<nsIDOMElement> tooltipEl(do_QueryInterface(mCurrentTooltip));
if (!tooltipEl)
return NS_ERROR_FAILURE;
nsAutoString noAutoHide;
tooltipEl->GetAttribute(NS_LITERAL_STRING("noautohide"), noAutoHide);
if (!noAutoHide.EqualsLiteral("true"))
if (mCurrentTooltip->AttrValueIs(kNameSpaceID_None, nsGkAtoms::noautohide,
nsGkAtoms::_true, eCaseMatters))
CreateAutoHideTimer();
// listen for popuphidden on the tooltip node, so that we can
@ -489,66 +485,38 @@ nsXULTooltipListener::LaunchTooltip()
if (!mCurrentTooltip)
return;
nsCOMPtr<nsIBoxObject> popupBox;
nsCOMPtr<nsIDOMXULElement> xulTooltipEl(do_QueryInterface(mCurrentTooltip));
if (!xulTooltipEl) {
NS_ERROR("tooltip isn't a XUL element!");
return;
}
xulTooltipEl->GetBoxObject(getter_AddRefs(popupBox));
nsCOMPtr<nsIPopupBoxObject> popupBoxObject(do_QueryInterface(popupBox));
if (popupBoxObject) {
PRInt32 x = mMouseClientX;
PRInt32 y = mMouseClientY;
#ifdef MOZ_XUL
if (mIsSourceTree && mNeedTitletip) {
nsCOMPtr<nsITreeBoxObject> obx;
GetSourceTreeBoxObject(getter_AddRefs(obx));
#ifdef DEBUG_crap
GetTreeCellCoords(obx, mSourceNode,
mLastTreeRow, mLastTreeCol, &x, &y);
#endif
if (mIsSourceTree && mNeedTitletip) {
nsCOMPtr<nsITreeBoxObject> obx;
GetSourceTreeBoxObject(getter_AddRefs(obx));
SetTitletipLabel(obx, mCurrentTooltip, mLastTreeRow, mLastTreeCol);
if (!mCurrentTooltip) {
// Because of mutation events, mCurrentTooltip can be null.
return;
}
mCurrentTooltip->SetAttr(kNameSpaceID_None, nsGkAtoms::titletip,
NS_LITERAL_STRING("true"), PR_TRUE);
} else {
mCurrentTooltip->UnsetAttr(kNameSpaceID_None, nsGkAtoms::titletip,
PR_TRUE);
}
SetTitletipLabel(obx, mCurrentTooltip, mLastTreeRow, mLastTreeCol);
if (!mCurrentTooltip) {
// Because of mutation events, mCurrentTooltip can be null.
return;
}
mCurrentTooltip->SetAttr(nsnull, nsGkAtoms::titletip, NS_LITERAL_STRING("true"), PR_TRUE);
} else {
mCurrentTooltip->UnsetAttr(nsnull, nsGkAtoms::titletip, PR_TRUE);
}
if (!mCurrentTooltip) {
// Because of mutation events, mCurrentTooltip can be null.
return;
}
#endif
nsCOMPtr<nsIDOMElement> targetEl(do_QueryInterface(mSourceNode));
popupBoxObject->ShowPopup(targetEl, xulTooltipEl, x, y,
NS_LITERAL_STRING("tooltip").get(),
NS_LITERAL_STRING("none").get(),
NS_LITERAL_STRING("topleft").get());
}
return;
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm)
pm->ShowPopupAtScreen(mCurrentTooltip, mMouseClientX, mMouseClientY, PR_FALSE);
}
nsresult
nsXULTooltipListener::HideTooltip()
{
if (mCurrentTooltip) {
// hide the popup through its box object
nsCOMPtr<nsIDOMXULElement> tooltipEl(do_QueryInterface(mCurrentTooltip));
nsCOMPtr<nsIBoxObject> boxObject;
if (tooltipEl)
tooltipEl->GetBoxObject(getter_AddRefs(boxObject));
nsCOMPtr<nsIPopupBoxObject> popupObject(do_QueryInterface(boxObject));
if (popupObject)
popupObject->HidePopup();
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm)
pm->HidePopup(mCurrentTooltip, PR_FALSE, PR_FALSE, PR_FALSE);
}
DestroyTooltip();
@ -669,10 +637,9 @@ nsXULTooltipListener::GetTooltipFor(nsIContent* aTarget, nsIContent** aTooltip)
nsIDocument* doc = parent->GetCurrentDoc();
nsIPresShell* presShell = doc ? doc->GetPrimaryShell() : nsnull;
nsIFrame* frame = presShell ? presShell->GetPrimaryFrameFor(parent) : nsnull;
if (frame) {
nsIMenuFrame* menu = nsnull;
CallQueryInterface(frame, &menu);
NS_ENSURE_FALSE(menu, NS_ERROR_FAILURE);
if (frame && frame->GetType() == nsGkAtoms::menuFrame) {
NS_WARNING("Menu cannot be used as a tooltip");
return NS_ERROR_FAILURE;
}
}
@ -741,7 +708,7 @@ nsXULTooltipListener::CreateAutoHideTimer()
mAutoHideTimer->Cancel();
mAutoHideTimer = nsnull;
}
mAutoHideTimer = do_CreateInstance("@mozilla.org/timer;1");
if ( mAutoHideTimer )
mAutoHideTimer->InitWithFuncCallback(sAutoHideCallback, this, kTooltipAutoHideTime,

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

@ -45,7 +45,8 @@
/* ::::: menupopup ::::: */
menupopup,
popup {
popup,
panel {
-moz-appearance: menupopup;
}

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

@ -45,7 +45,8 @@
/* ::::: menupopup ::::: */
menupopup,
popup {
popup,
panel {
border: 2px solid;
-moz-border-top-colors: ThreeDLightShadow ThreeDHighlight;
-moz-border-right-colors: ThreeDDarkShadow ThreeDShadow;

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

@ -41,7 +41,7 @@
interface nsIAutoCompleteInput;
[scriptable, uuid(bafcfe4f-0850-4106-a176-be5aef2e1e52)]
[scriptable, uuid(476E1472-4357-4CD0-AFE3-FEA3112617B2)]
interface nsIAutoCompleteController : nsISupports
{
/*
@ -141,10 +141,4 @@ 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(65F6CD46-22EC-4329-BB3B-BCD1103F2204)]
[scriptable, uuid(816668CC-6AC0-47C3-944E-9C2CF37F224A)]
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 openPopup(in nsIAutoCompleteInput input, in long x, in long y, in long width);
void openAutocompletePopup(in nsIAutoCompleteInput input, in long x, in long y, in long width);
/*
* Close the popup and detach from the bound input

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

@ -611,27 +611,6 @@ 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,7 +246,9 @@ nsFormFillController::SetPopupOpen(PRBool aPopupOpen)
NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE);
nsRect popupRect = GetScreenOrigin(mFocusedInput);
mFocusedPopup->OpenPopup(this, popupRect.x, popupRect.y+popupRect.height, popupRect.width);
mFocusedPopup->OpenAutocompletePopup(this, popupRect.x,
popupRect.y+popupRect.height,
popupRect.width);
} else
mFocusedPopup->ClosePopup();
}

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

@ -110,9 +110,8 @@
if (popupId)
popup = document.getElementById(popupId);
if (!popup) {
popup = document.createElement("popup");
popup = document.createElement("panel");
popup.setAttribute("type", "autocomplete");
popup.setAttribute("hidden", "true");
var popupset = document.getAnonymousElementByAttribute(this, "anonid", "popupset");
popupset.appendChild(popup);
@ -320,7 +319,7 @@
<method name="openPopup">
<body><![CDATA[
this.popup.openPopup(this, -1, -1, this.boxObject.width);
this.popup.openAutocompletePopup(this, -1, -1, this.boxObject.width);
]]></body>
</method>
@ -565,7 +564,7 @@
<property name="popupOpen" readonly="true"
onget="return this.mPopupOpen;"/>
<method name="openPopup">
<method name="openAutocompletePopup">
<parameter name="aInput"/>
<parameter name="aX"/>
<parameter name="aY"/>
@ -578,7 +577,6 @@
this.showCommentColumn = this.mInput.showCommentColumn;
this.removeAttribute("hidden");
this.setAttribute("width", aWidth < 100 ? 100 : aWidth);
document.popupNode = null;
@ -588,8 +586,7 @@
else {
this.showPopup(document.documentElement, aX, aY, "popup", null, null);
}
this.enableRollup(false);
this.mInput.controller.attachRollupListener();
this.popupBoxObject.setConsumeRollupEvent(this.mInput.consumeRollupEvent);
}
]]></body>
</method>
@ -599,10 +596,8 @@
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>
@ -716,6 +711,8 @@
// 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,12 +11,8 @@
</resources>
</binding>
<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>
<binding id="panel"
extends="chrome://global/content/bindings/popup.xml#popup-base">
<implementation implements="nsIDOMXULPopupElement, nsIAccessibleProvider">
<property name="accessibleType" readonly="true">
@ -34,6 +30,40 @@
return this.boxObject.QueryInterface(Components.interfaces.nsIPopupBoxObject);
</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"/>
@ -131,6 +161,16 @@
</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,24 +320,23 @@ popup,
menupopup {
-moz-binding: url("chrome://global/content/bindings/popup.xml#popup");
-moz-box-orient: vertical;
display: none;
}
panel {
-moz-binding: url("chrome://global/content/bindings/popup.xml#panel");
-moz-box-orient: vertical;
}
popup,
menupopup,
panel,
tooltip {
z-index: 2147483647;
}
menupopup[menugenerated="true"],
popup[menugenerated="true"],
tooltip[menugenerated="true"] {
display: -moz-popup;
z-index: 2147483647;
}
tooltip {
-moz-binding: url("chrome://global/content/bindings/popup.xml#tooltip");
display: -moz-popup;
margin-top: 21px;
}
@ -782,9 +781,8 @@ textbox[type="autocomplete"] {
-moz-binding: url("chrome://global/content/bindings/autocomplete.xml#autocomplete");
}
popup[type="autocomplete"] {
panel[type="autocomplete"] {
-moz-binding: url("chrome://global/content/bindings/autocomplete.xml#autocomplete-result-popup");
display: -moz-popup !important;
}
.autocomplete-tree {

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

@ -44,7 +44,9 @@
/* ::::: menupopup ::::: */
menupopup, popup {
menupopup,
popup,
panel {
-moz-appearance: menupopup;
min-width: 1px;
}

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

@ -74,7 +74,7 @@ textbox.padded {
/* ::::: autocomplete popups ::::: */
popup[type="autocomplete"],
panel[type="autocomplete"],
.autocomplete-history-popup {
padding: 0px !important;
background-color: -moz-Field !important;

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

@ -46,7 +46,8 @@
/* ::::: menupopup ::::: */
menupopup,
popup {
popup,
panel {
-moz-appearance: menupopup;
}

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

@ -167,7 +167,7 @@ textbox[chromedir="rtl"] .autocomplete-history-dropmarker {
/* ::::: autocomplete popups ::::: */
popup[type="autocomplete"],
panel[type="autocomplete"],
.autocomplete-history-popup {
border-width: 1px;
-moz-border-top-colors: ThreeDDarkShadow;

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

@ -45,7 +45,8 @@
/* ::::: menupopup ::::: */
menupopup,
popup {
popup,
panel {
border: 2px solid transparent;
-moz-border-top-colors : ThreeDLightShadow ThreeDHighlight;
-moz-border-left-colors : ThreeDLightShadow ThreeDHighlight;

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

@ -55,7 +55,6 @@
#include "nsGfxCIID.h"
#include "nsTransform2D.h"
#include "nsIMenuFrame.h"
#include "nsIMenuParent.h"
#include "prlink.h"
#include "nsIDOMHTMLInputElement.h"
#include "nsWidgetAtoms.h"
@ -278,15 +277,11 @@ nsNativeThemeGTK::GetGtkWidgetAndState(PRUint8 aWidgetType, nsIFrame* aFrame,
CallQueryInterface(aFrame, &menuFrame);
if (menuFrame) {
nsIMenuParent *menuParent = menuFrame->GetMenuParent();
if (menuParent)
menuParent->IsMenuBar(isTopLevel);
isTopLevel = menuFrame->IsOnMenuBar();
}
if (isTopLevel) {
PRBool isOpen;
menuFrame->MenuIsOpen(isOpen);
aState->inHover = isOpen;
aState->inHover = menuFrame->IsOpen();
} else {
aState->inHover = CheckBooleanAttr(aFrame, nsWidgetAtoms::mozmenuactive);
}

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

@ -55,7 +55,6 @@
#include "nsILookAndFeel.h"
#include "nsIDOMHTMLInputElement.h"
#include "nsIMenuFrame.h"
#include "nsIMenuParent.h"
#include "nsWidgetAtoms.h"
#include <malloc.h>
@ -789,8 +788,8 @@ nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame, PRUint8 aWidgetType,
nsIContent* content = aFrame->GetContent();
nsIFrame* parentFrame = aFrame->GetParent();
nsCOMPtr<nsIMenuFrame> menuFrame(do_QueryInterface(parentFrame));
if (menuFrame || (content && content->IsNodeOfType(nsINode::eHTML)) )
if (parentFrame->GetType() == nsWidgetAtoms::menuFrame ||
(content && content->IsNodeOfType(nsINode::eHTML)))
// XUL menu lists and HTML selects get state from parent
aFrame = parentFrame;
@ -1421,9 +1420,7 @@ 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.
nsIMenuParent *menuParent = menuFrame->GetMenuParent();
if (menuParent)
menuParent->IsMenuBar(isTopLevel);
isTopLevel = menuFrame->IsOnMenuBar();
}
// These values are obtained from visual inspection of equivelant
@ -1643,11 +1640,9 @@ 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.
nsIMenuParent *menuParent = menuFrame->GetMenuParent();
if (menuParent)
menuParent->IsMenuBar(isTopLevel);
menuFrame->MenuIsOpen(isOpen);
menuFrame->MenuIsContainer(isContainer);
isTopLevel = menuFrame->IsOnMenuBar();
isOpen = menuFrame->IsOpen();
isContainer = menuFrame->IsMenu();
}
if (IsDisabled(aFrame))
@ -1714,8 +1709,8 @@ nsresult nsNativeThemeWin::ClassicGetThemePartAndState(nsIFrame* aFrame, PRUint8
nsIContent* content = aFrame->GetContent();
nsIFrame* parentFrame = aFrame->GetParent();
nsCOMPtr<nsIMenuFrame> menuFrame(do_QueryInterface(parentFrame));
if (menuFrame || (content && content->IsNodeOfType(nsINode::eHTML)) )
if (parentFrame->GetType() == nsWidgetAtoms::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,6 +88,7 @@ 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,8 +114,6 @@
#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:popup type="autocomplete" ignorekeys="true" anonid="popup" class="autocomplete-result-popup" hidden="true" xbl:inherits="for=id,nomatch"/>
<xul:panel type="autocomplete" ignorekeys="true" anonid="popup" class="autocomplete-result-popup" hidden="true" xbl:inherits="for=id,nomatch"/>
</xul:popupset>
<children includes="menupopup"/>

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

@ -34,7 +34,41 @@
return this.boxObject.QueryInterface(Components.interfaces.nsIPopupBoxObject);
</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,27 +298,22 @@ menuseparator {
/* <popup> is deprecated. Only <menupopup> and <tooltip> are still valid. */
popup,
menupopup {
menupopup,
panel {
-moz-binding: url("chrome://global/content/bindings/popup.xml#popup");
-moz-box-orient: vertical;
display: none;
}
popup,
menupopup,
panel,
tooltip {
z-index: 2147483647;
}
menupopup[menugenerated="true"],
popup[menugenerated="true"],
tooltip[menugenerated="true"] {
display: -moz-popup;
z-index: 2147483647;
}
tooltip {
-moz-binding: url("chrome://global/content/bindings/popup.xml#tooltip");
display: -moz-popup;
margin-top: 21px;
}