mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-13 18:27:35 +00:00
Giving menus some seriously tough love.
This commit is contained in:
parent
8fce707653
commit
229b94b63f
@ -49,6 +49,18 @@ public:
|
||||
NS_IMETHOD HideChain() = 0;
|
||||
|
||||
NS_IMETHOD CreateDismissalListener() = 0;
|
||||
|
||||
NS_IMETHOD InstallKeyboardNavigator() = 0;
|
||||
NS_IMETHOD RemoveKeyboardNavigator() = 0;
|
||||
|
||||
// Used to move up, down, left, and right in menus.
|
||||
NS_IMETHOD KeyboardNavigation(PRUint32 aDirection, PRBool& aHandledFlag) = 0;
|
||||
NS_IMETHOD ShortcutNavigation(PRUint32 aLetter, 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;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -61,6 +61,7 @@ CPPSRCS = \
|
||||
nsMenuFrame.cpp \
|
||||
nsMenuBarFrame.cpp \
|
||||
nsMenuBarListener.cpp \
|
||||
nsMenuListener.cpp \
|
||||
nsMenuDismissalListener.cpp \
|
||||
nsPopupSetFrame.cpp \
|
||||
nsRepeatService.cpp \
|
||||
|
@ -60,6 +60,7 @@ CPPSRCS= \
|
||||
nsMenuFrame.cpp \
|
||||
nsMenuBarFrame.cpp \
|
||||
nsMenuBarListener.cpp \
|
||||
nsMenuListener.cpp \
|
||||
nsMenuDismissalListener.cpp \
|
||||
nsPopupSetFrame.cpp \
|
||||
$(NULL)
|
||||
@ -97,6 +98,7 @@ CPP_OBJS= \
|
||||
.\$(OBJDIR)\nsMenuFrame.obj \
|
||||
.\$(OBJDIR)\nsMenuBarFrame.obj \
|
||||
.\$(OBJDIR)\nsMenuBarListener.obj \
|
||||
.\$(OBJDIR)\nsMenuListener.obj \
|
||||
.\$(OBJDIR)\nsMenuDismissalListener.obj \
|
||||
.\$(OBJDIR)\nsPopupSetFrame.obj \
|
||||
$(NULL)
|
||||
|
@ -49,6 +49,18 @@ public:
|
||||
NS_IMETHOD HideChain() = 0;
|
||||
|
||||
NS_IMETHOD CreateDismissalListener() = 0;
|
||||
|
||||
NS_IMETHOD InstallKeyboardNavigator() = 0;
|
||||
NS_IMETHOD RemoveKeyboardNavigator() = 0;
|
||||
|
||||
// Used to move up, down, left, and right in menus.
|
||||
NS_IMETHOD KeyboardNavigation(PRUint32 aDirection, PRBool& aHandledFlag) = 0;
|
||||
NS_IMETHOD ShortcutNavigation(PRUint32 aLetter, 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;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -20,9 +20,8 @@
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
|
||||
#include "nsMenuListener.h"
|
||||
#include "nsMenuBarFrame.h"
|
||||
|
||||
#include "nsIContent.h"
|
||||
#include "prtypes.h"
|
||||
#include "nsIAtom.h"
|
||||
@ -85,7 +84,7 @@ NS_INTERFACE_MAP_END_INHERITING(nsToolbarFrame)
|
||||
// nsMenuBarFrame cntr
|
||||
//
|
||||
nsMenuBarFrame::nsMenuBarFrame()
|
||||
:mIsActive(PR_FALSE), mTarget(nsnull)
|
||||
:mIsActive(PR_FALSE), mTarget(nsnull), mKeyboardNavigator(nsnull), mMenuBarListener(nsnull)
|
||||
{
|
||||
|
||||
} // cntr
|
||||
@ -108,11 +107,12 @@ nsMenuBarFrame::Init(nsIPresContext* aPresContext,
|
||||
|
||||
// Create the menu bar listener.
|
||||
mMenuBarListener = new nsMenuBarListener(this);
|
||||
NS_IF_ADDREF(mMenuBarListener);
|
||||
if (! mMenuBarListener)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// Hook up the menu bar as a key listener (capturer) on the whole document. It will see every
|
||||
// key press that occurs before anyone else does and will know when to take control.
|
||||
// Hook up the menu bar as a key listener on the whole document. It will see every
|
||||
// key press that occurs, but after everyone else does.
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
aContent->GetDocument(*getter_AddRefs(doc));
|
||||
nsCOMPtr<nsIDOMEventReceiver> target = do_QueryInterface(doc);
|
||||
@ -122,14 +122,13 @@ nsMenuBarFrame::Init(nsIPresContext* aPresContext,
|
||||
// Also hook up the listener to the window listening for focus events. This is so we can keep proper
|
||||
// state as the user alt-tabs through processes.
|
||||
|
||||
target->AddEventListener("blur", (nsIDOMFocusListener*)mMenuBarListener, PR_TRUE);
|
||||
target->AddEventListener("blur", (nsIDOMFocusListener*)mMenuBarListener, PR_FALSE);
|
||||
|
||||
target->AddEventListener("mousedown", (nsIDOMMouseListener*)mMenuBarListener, PR_TRUE);
|
||||
target->AddEventListener("mousedown", (nsIDOMMouseListener*)mMenuBarListener, PR_FALSE);
|
||||
|
||||
target->AddEventListener("keypress", (nsIDOMKeyListener*)mMenuBarListener, PR_TRUE);
|
||||
target->AddEventListener("keydown", (nsIDOMKeyListener*)mMenuBarListener, PR_TRUE);
|
||||
target->AddEventListener("keyup", (nsIDOMKeyListener*)mMenuBarListener, PR_TRUE);
|
||||
NS_ADDREF(mMenuBarListener);
|
||||
target->AddEventListener("keypress", (nsIDOMKeyListener*)mMenuBarListener, PR_FALSE);
|
||||
target->AddEventListener("keydown", (nsIDOMKeyListener*)mMenuBarListener, PR_FALSE);
|
||||
target->AddEventListener("keyup", (nsIDOMKeyListener*)mMenuBarListener, PR_FALSE);
|
||||
|
||||
return rv;
|
||||
}
|
||||
@ -152,6 +151,11 @@ NS_IMETHODIMP
|
||||
nsMenuBarFrame::SetActive(PRBool aActiveFlag)
|
||||
{
|
||||
mIsActive = aActiveFlag;
|
||||
if (mIsActive) {
|
||||
InstallKeyboardNavigator();
|
||||
}
|
||||
else RemoveKeyboardNavigator();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -166,12 +170,15 @@ nsMenuBarFrame::ToggleMenuActiveState()
|
||||
mCurrentMenu->OpenMenu(PR_FALSE);
|
||||
mCurrentMenu->SelectMenu(PR_FALSE);
|
||||
mCurrentMenu = nsnull;
|
||||
RemoveKeyboardNavigator();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Activate the menu bar
|
||||
SetActive(PR_TRUE);
|
||||
|
||||
InstallKeyboardNavigator();
|
||||
|
||||
// Set the active menu to be the top left item (e.g., the File menu).
|
||||
// We use an attribute called "active" to track the current active menu.
|
||||
nsCOMPtr<nsIContent> firstMenuItem;
|
||||
@ -218,7 +225,7 @@ nsMenuBarFrame::FindMenuWithShortcut(PRUint32 aLetter)
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
void
|
||||
NS_IMETHODIMP
|
||||
nsMenuBarFrame::ShortcutNavigation(PRUint32 aLetter, PRBool& aHandledFlag)
|
||||
{
|
||||
if (mCurrentMenu) {
|
||||
@ -227,7 +234,7 @@ nsMenuBarFrame::ShortcutNavigation(PRUint32 aLetter, PRBool& aHandledFlag)
|
||||
if (isOpen) {
|
||||
// No way this applies to us. Give it to our child.
|
||||
mCurrentMenu->ShortcutNavigation(aLetter, aHandledFlag);
|
||||
return;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,28 +248,30 @@ nsMenuBarFrame::ShortcutNavigation(PRUint32 aLetter, PRBool& aHandledFlag)
|
||||
result->OpenMenu(PR_TRUE);
|
||||
result->SelectFirstItem();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsMenuBarFrame::KeyboardNavigation(PRUint32 aDirection)
|
||||
NS_IMETHODIMP
|
||||
nsMenuBarFrame::KeyboardNavigation(PRUint32 aDirection, PRBool& aHandledFlag)
|
||||
{
|
||||
if (!mCurrentMenu)
|
||||
return;
|
||||
return NS_OK;
|
||||
|
||||
PRBool isContainer = PR_FALSE;
|
||||
PRBool isOpen = PR_FALSE;
|
||||
mCurrentMenu->MenuIsContainer(isContainer);
|
||||
mCurrentMenu->MenuIsOpen(isOpen);
|
||||
|
||||
PRBool handled = PR_FALSE;
|
||||
aHandledFlag = PR_FALSE;
|
||||
|
||||
if (isOpen) {
|
||||
// Let the child menu try to handle it.
|
||||
mCurrentMenu->KeyboardNavigation(aDirection, handled);
|
||||
mCurrentMenu->KeyboardNavigation(aDirection, aHandledFlag);
|
||||
}
|
||||
|
||||
if (handled)
|
||||
return;
|
||||
if (aHandledFlag)
|
||||
return NS_OK;
|
||||
|
||||
if (aDirection == NS_VK_RIGHT || aDirection == NS_VK_LEFT) {
|
||||
|
||||
@ -287,6 +296,8 @@ nsMenuBarFrame::KeyboardNavigation(PRUint32 aDirection)
|
||||
mCurrentMenu->OpenMenu(PR_TRUE);
|
||||
mCurrentMenu->SelectFirstItem();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -421,27 +432,27 @@ NS_IMETHODIMP nsMenuBarFrame::SetCurrentMenuItem(nsIMenuFrame* aMenuItem)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsMenuBarFrame::Escape()
|
||||
NS_IMETHODIMP
|
||||
nsMenuBarFrame::Escape(PRBool& aHandledFlag)
|
||||
{
|
||||
if (!mCurrentMenu)
|
||||
return;
|
||||
return NS_OK;
|
||||
|
||||
// See if our menu is open.
|
||||
PRBool isOpen = PR_FALSE;
|
||||
mCurrentMenu->MenuIsOpen(isOpen);
|
||||
if (isOpen) {
|
||||
// Let the child menu handle this.
|
||||
PRBool handled = PR_FALSE;
|
||||
mCurrentMenu->Escape(handled);
|
||||
if (!handled) {
|
||||
aHandledFlag = PR_FALSE;
|
||||
mCurrentMenu->Escape(aHandledFlag);
|
||||
if (!aHandledFlag) {
|
||||
// Close up this menu but keep our current menu item
|
||||
// designation.
|
||||
mCurrentMenu->OpenMenu(PR_FALSE);
|
||||
}
|
||||
if (nsMenuFrame::mDismissalListener)
|
||||
nsMenuFrame::mDismissalListener->Unregister();
|
||||
return;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// It's us. Just set our active flag to false.
|
||||
@ -453,13 +464,15 @@ nsMenuBarFrame::Escape()
|
||||
// Clear out our dismissal listener
|
||||
if (nsMenuFrame::mDismissalListener)
|
||||
nsMenuFrame::mDismissalListener->Unregister();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
NS_IMETHODIMP
|
||||
nsMenuBarFrame::Enter()
|
||||
{
|
||||
if (!mCurrentMenu)
|
||||
return;
|
||||
return NS_OK;
|
||||
|
||||
// See if our menu is open.
|
||||
PRBool isOpen = PR_FALSE;
|
||||
@ -467,12 +480,14 @@ nsMenuBarFrame::Enter()
|
||||
if (isOpen) {
|
||||
// Let the child menu handle this.
|
||||
mCurrentMenu->Enter();
|
||||
return;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// It's us. Open the current menu.
|
||||
mCurrentMenu->OpenMenu(PR_TRUE);
|
||||
mCurrentMenu->SelectFirstItem();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -523,6 +538,39 @@ nsMenuBarFrame::CreateDismissalListener()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMenuBarFrame::InstallKeyboardNavigator()
|
||||
{
|
||||
if (mKeyboardNavigator)
|
||||
return NS_OK;
|
||||
|
||||
mKeyboardNavigator = new nsMenuListener(this);
|
||||
NS_IF_ADDREF(mKeyboardNavigator);
|
||||
|
||||
mTarget->AddEventListener("keypress", (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
|
||||
mTarget->AddEventListener("keydown", (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
|
||||
mTarget->AddEventListener("keyup", (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMenuBarFrame::RemoveKeyboardNavigator()
|
||||
{
|
||||
if (!mKeyboardNavigator)
|
||||
return NS_OK;
|
||||
|
||||
mTarget->RemoveEventListener("keypress", (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
|
||||
mTarget->RemoveEventListener("keydown", (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
|
||||
mTarget->RemoveEventListener("keyup", (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
|
||||
|
||||
NS_IF_RELEASE(mKeyboardNavigator);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// helpers ///////////////////////////////////////////////////////////
|
||||
|
||||
PRBool
|
||||
nsMenuBarFrame::IsValidItem(nsIContent* aContent)
|
||||
{
|
||||
|
@ -66,6 +66,9 @@ public:
|
||||
// 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 CreateDismissalListener();
|
||||
@ -84,23 +87,23 @@ public:
|
||||
void ToggleMenuActiveState();
|
||||
|
||||
// Used to move up, down, left, and right in menus.
|
||||
void KeyboardNavigation(PRUint32 aDirection);
|
||||
|
||||
// Used to handle ALT+key combos
|
||||
void ShortcutNavigation(PRUint32 aLetter, PRBool& aHandledFlag);
|
||||
nsIMenuFrame* FindMenuWithShortcut(PRUint32 aLetter);
|
||||
|
||||
NS_IMETHOD KeyboardNavigation(PRUint32 aDirection, PRBool& aHandledFlag);
|
||||
NS_IMETHOD ShortcutNavigation(PRUint32 aLetter, PRBool& aHandledFlag);
|
||||
// Called when the ESC key is held down to close levels of menus.
|
||||
void Escape();
|
||||
|
||||
NS_IMETHOD Escape(PRBool& aHandledFlag);
|
||||
// Called to execute a menu item.
|
||||
void Enter();
|
||||
NS_IMETHOD Enter();
|
||||
|
||||
// Used to handle ALT+key combos
|
||||
nsIMenuFrame* FindMenuWithShortcut(PRUint32 aLetter);
|
||||
|
||||
PRBool IsValidItem(nsIContent* aContent);
|
||||
PRBool IsDisabled(nsIContent* aContent);
|
||||
|
||||
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.
|
||||
|
||||
|
@ -55,7 +55,7 @@ NS_IMPL_QUERY_INTERFACE3(nsMenuBarListener, nsIDOMKeyListener, nsIDOMFocusListen
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsMenuBarListener::nsMenuBarListener(nsMenuBarFrame* aMenuBar)
|
||||
:mAltKeyDown(PR_FALSE), mKeyboardNavigationActive(PR_FALSE)
|
||||
:mAltKeyDown(PR_FALSE)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
mMenuBarFrame = aMenuBar;
|
||||
@ -89,13 +89,12 @@ nsMenuBarListener::KeyUp(nsIDOMEvent* aKeyEvent)
|
||||
|
||||
PRBool active = mMenuBarFrame->IsActive();
|
||||
if (active) {
|
||||
mKeyboardNavigationActive = PR_TRUE;
|
||||
|
||||
aKeyEvent->PreventBubble();
|
||||
aKeyEvent->PreventBubble();
|
||||
aKeyEvent->PreventCapture();
|
||||
aKeyEvent->PreventDefault();
|
||||
return NS_ERROR_BASE; // I am consuming event
|
||||
} else
|
||||
mKeyboardNavigationActive = PR_FALSE;
|
||||
}
|
||||
|
||||
return NS_OK; // means I am NOT consuming event
|
||||
}
|
||||
|
||||
@ -103,8 +102,7 @@ nsMenuBarListener::KeyUp(nsIDOMEvent* aKeyEvent)
|
||||
nsresult
|
||||
nsMenuBarListener::KeyDown(nsIDOMEvent* aKeyEvent)
|
||||
{
|
||||
PRBool active = mMenuBarFrame->IsActive();
|
||||
|
||||
#ifndef XP_UNIX
|
||||
nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aKeyEvent);
|
||||
PRUint32 theChar;
|
||||
keyEvent->GetKeyCode(&theChar);
|
||||
@ -114,59 +112,25 @@ nsMenuBarListener::KeyDown(nsIDOMEvent* aKeyEvent)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool altKeyWasDown = mAltKeyDown;
|
||||
mAltKeyDown = PR_FALSE;
|
||||
if (mAltKeyDown) {
|
||||
mAltKeyDown = PR_FALSE;
|
||||
|
||||
if (theChar == NS_VK_LEFT ||
|
||||
theChar == NS_VK_RIGHT ||
|
||||
theChar == NS_VK_UP ||
|
||||
theChar == NS_VK_DOWN) {
|
||||
// The arrow keys were pressed. User is moving around within
|
||||
// the menus.
|
||||
if (active) {
|
||||
mMenuBarFrame->KeyboardNavigation(theChar);
|
||||
mKeyboardNavigationActive = PR_TRUE;
|
||||
} else
|
||||
mKeyboardNavigationActive = PR_FALSE;
|
||||
}
|
||||
else if (theChar == NS_VK_ESCAPE) {
|
||||
// Close one level.
|
||||
if (active) {
|
||||
mMenuBarFrame->Escape();
|
||||
mKeyboardNavigationActive = PR_FALSE;
|
||||
}
|
||||
}
|
||||
else if (theChar == NS_VK_ENTER ||
|
||||
theChar == NS_VK_RETURN) {
|
||||
// Open one level.
|
||||
if (active)
|
||||
mMenuBarFrame->Enter();
|
||||
}
|
||||
#ifndef XP_UNIX
|
||||
else if (active || altKeyWasDown) {
|
||||
// Get the character code.
|
||||
nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aKeyEvent);
|
||||
if (keyEvent) {
|
||||
// See if a letter was pressed.
|
||||
PRUint32 charCode;
|
||||
keyEvent->GetKeyCode(&charCode);
|
||||
// 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(theChar, active);
|
||||
|
||||
// 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.
|
||||
mMenuBarFrame->ShortcutNavigation(charCode, active);
|
||||
if (active) {
|
||||
aKeyEvent->PreventBubble();
|
||||
aKeyEvent->PreventCapture();
|
||||
aKeyEvent->PreventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
return NS_ERROR_BASE; // I am consuming event
|
||||
}
|
||||
#endif
|
||||
|
||||
if (active) {
|
||||
mKeyboardNavigationActive = PR_TRUE;
|
||||
aKeyEvent->PreventBubble();
|
||||
aKeyEvent->PreventCapture();
|
||||
return NS_ERROR_BASE; // I am consuming event
|
||||
} else
|
||||
mKeyboardNavigationActive = PR_FALSE;
|
||||
|
||||
return NS_OK; // means I am NOT consuming event
|
||||
}
|
||||
|
||||
@ -174,18 +138,6 @@ nsMenuBarListener::KeyDown(nsIDOMEvent* aKeyEvent)
|
||||
nsresult
|
||||
nsMenuBarListener::KeyPress(nsIDOMEvent* aKeyEvent)
|
||||
{
|
||||
nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aKeyEvent);
|
||||
|
||||
PRBool active = mMenuBarFrame->IsActive();
|
||||
|
||||
if (active) {
|
||||
mKeyboardNavigationActive = PR_TRUE;
|
||||
aKeyEvent->PreventBubble();
|
||||
aKeyEvent->PreventCapture();
|
||||
return NS_ERROR_BASE; // I am consuming event
|
||||
} else
|
||||
mKeyboardNavigationActive = PR_FALSE;
|
||||
|
||||
return NS_OK; // means I am NOT consuming event
|
||||
}
|
||||
|
||||
@ -201,11 +153,11 @@ nsMenuBarListener::Focus(nsIDOMEvent* aEvent)
|
||||
nsresult
|
||||
nsMenuBarListener::Blur(nsIDOMEvent* aEvent)
|
||||
{
|
||||
if (mKeyboardNavigationActive && mMenuBarFrame->IsActive()) {
|
||||
if (!mMenuBarFrame->IsOpen() && mMenuBarFrame->IsActive()) {
|
||||
mMenuBarFrame->ToggleMenuActiveState();
|
||||
mMenuBarFrame->Escape();
|
||||
PRBool handled;
|
||||
mMenuBarFrame->Escape(handled);
|
||||
mAltKeyDown = PR_FALSE;
|
||||
mKeyboardNavigationActive = PR_FALSE;
|
||||
}
|
||||
|
||||
return NS_OK; // means I am NOT consuming event
|
||||
@ -217,9 +169,9 @@ nsMenuBarListener::MouseDown(nsIDOMEvent* aMouseEvent)
|
||||
{
|
||||
if (!mMenuBarFrame->IsOpen() && mMenuBarFrame->IsActive()) {
|
||||
mMenuBarFrame->ToggleMenuActiveState();
|
||||
mMenuBarFrame->Escape();
|
||||
PRBool handled;
|
||||
mMenuBarFrame->Escape(handled);
|
||||
mAltKeyDown = PR_FALSE;
|
||||
mKeyboardNavigationActive = PR_FALSE;
|
||||
}
|
||||
return NS_OK; // means I am NOT consuming event
|
||||
}
|
||||
@ -230,9 +182,9 @@ nsMenuBarListener::MouseUp(nsIDOMEvent* aMouseEvent)
|
||||
{
|
||||
if (!mMenuBarFrame->IsOpen() && mMenuBarFrame->IsActive()) {
|
||||
mMenuBarFrame->ToggleMenuActiveState();
|
||||
mMenuBarFrame->Escape();
|
||||
mKeyboardNavigationActive = PR_FALSE;
|
||||
mAltKeyDown = PR_FALSE;
|
||||
PRBool handled;
|
||||
mMenuBarFrame->Escape(handled);
|
||||
mAltKeyDown = PR_FALSE;
|
||||
}
|
||||
return NS_OK; // means I am NOT consuming event
|
||||
}
|
||||
@ -242,9 +194,9 @@ nsMenuBarListener::MouseClick(nsIDOMEvent* aMouseEvent)
|
||||
{
|
||||
if (!mMenuBarFrame->IsOpen() && mMenuBarFrame->IsActive()) {
|
||||
mMenuBarFrame->ToggleMenuActiveState();
|
||||
mMenuBarFrame->Escape();
|
||||
mKeyboardNavigationActive = PR_FALSE;
|
||||
mAltKeyDown = PR_FALSE;
|
||||
PRBool handled;
|
||||
mMenuBarFrame->Escape(handled);
|
||||
mAltKeyDown = PR_FALSE;
|
||||
}
|
||||
|
||||
return NS_OK; // means I am NOT consuming event
|
||||
|
@ -64,7 +64,6 @@ public:
|
||||
protected:
|
||||
nsMenuBarFrame* mMenuBarFrame; // The menu bar object.
|
||||
PRBool mAltKeyDown; // Whether or not the ALT key is currently down.
|
||||
PRBool mKeyboardNavigationActive; // Are we currently navigating via the keyboard
|
||||
};
|
||||
|
||||
|
||||
|
@ -510,6 +510,16 @@ nsMenuFrame::OpenMenuInternal(PRBool aActivateFlag)
|
||||
nsMenuPopupFrame* menuPopup = (nsMenuPopupFrame*)frame;
|
||||
|
||||
if (menuPopup) {
|
||||
// Install a keyboard navigation listener if we're the root of the menu chain.
|
||||
PRBool onMenuBar = PR_TRUE;
|
||||
if (mMenuParent)
|
||||
mMenuParent->IsMenuBar(onMenuBar);
|
||||
|
||||
if (mMenuParent && onMenuBar)
|
||||
mMenuParent->InstallKeyboardNavigator();
|
||||
else if (!mMenuParent)
|
||||
menuPopup->InstallKeyboardNavigator();
|
||||
|
||||
// Tell the menu bar we're active.
|
||||
if (mMenuParent)
|
||||
mMenuParent->SetActive(PR_TRUE);
|
||||
@ -523,10 +533,7 @@ nsMenuFrame::OpenMenuInternal(PRBool aActivateFlag)
|
||||
menuPopupContent->GetAttribute(kNameSpaceID_None, nsXULAtoms::popupanchor, popupAnchor);
|
||||
menuPopupContent->GetAttribute(kNameSpaceID_None, nsXULAtoms::popupalign, popupAlign);
|
||||
|
||||
PRBool onMenuBar = PR_TRUE;
|
||||
if (mMenuParent)
|
||||
mMenuParent->IsMenuBar(onMenuBar);
|
||||
|
||||
|
||||
if (onMenuBar) {
|
||||
if (popupAnchor == "")
|
||||
popupAnchor = "bottomleft";
|
||||
@ -571,9 +578,19 @@ nsMenuFrame::OpenMenuInternal(PRBool aActivateFlag)
|
||||
nsMenuPopupFrame* menuPopup = (nsMenuPopupFrame*)frame;
|
||||
|
||||
// Make sure we clear out our own items.
|
||||
if (menuPopup)
|
||||
if (menuPopup) {
|
||||
menuPopup->SetCurrentMenuItem(nsnull);
|
||||
|
||||
PRBool onMenuBar = PR_TRUE;
|
||||
if (mMenuParent)
|
||||
mMenuParent->IsMenuBar(onMenuBar);
|
||||
|
||||
if (mMenuParent && onMenuBar)
|
||||
mMenuParent->RemoveKeyboardNavigator();
|
||||
else if (!mMenuParent)
|
||||
menuPopup->RemoveKeyboardNavigator();
|
||||
}
|
||||
|
||||
ActivateMenu(PR_FALSE);
|
||||
|
||||
mMenuOpen = PR_FALSE;
|
||||
|
@ -402,8 +402,7 @@ nsMenuPopupFrame::SyncViewWithFrame(nsIPresContext* aPresContext,
|
||||
//
|
||||
// At this point, we should be positioned where we're told. Ensure that we fit
|
||||
// on the screen.
|
||||
//
|
||||
|
||||
//
|
||||
nsCOMPtr<nsIDOMWindow> window(do_QueryInterface(scriptGlobalObject));
|
||||
nsCOMPtr<nsIDOMScreen> screen;
|
||||
window->GetScreen(getter_AddRefs(screen));
|
||||
@ -647,11 +646,11 @@ nsMenuPopupFrame::CaptureMouseEvents(nsIPresContext* aPresContext, PRBool aGrabM
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
NS_IMETHODIMP
|
||||
nsMenuPopupFrame::Escape(PRBool& aHandledFlag)
|
||||
{
|
||||
if (!mCurrentMenu)
|
||||
return;
|
||||
return NS_OK;
|
||||
|
||||
// See if our menu is open.
|
||||
PRBool isOpen = PR_FALSE;
|
||||
@ -664,16 +663,19 @@ nsMenuPopupFrame::Escape(PRBool& aHandledFlag)
|
||||
mCurrentMenu->OpenMenu(PR_FALSE);
|
||||
aHandledFlag = PR_TRUE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
NS_IMETHODIMP
|
||||
nsMenuPopupFrame::Enter()
|
||||
{
|
||||
// Give it to the child.
|
||||
if (mCurrentMenu)
|
||||
mCurrentMenu->Enter();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIMenuFrame*
|
||||
@ -688,13 +690,16 @@ nsMenuPopupFrame::FindMenuWithShortcut(PRUint32 aLetter)
|
||||
// See if it's a menu item.
|
||||
if (IsValidItem(current)) {
|
||||
// Get the shortcut attribute.
|
||||
nsString shortcutKey = "";
|
||||
nsAutoString shortcutKey = "";
|
||||
current->GetAttribute(kNameSpaceID_None, nsXULAtoms::accesskey, shortcutKey);
|
||||
shortcutKey.ToUpperCase();
|
||||
if (shortcutKey.Length() > 0) {
|
||||
// We've got something.
|
||||
PRUnichar shortcutChar = shortcutKey.CharAt(0);
|
||||
if (shortcutChar == aLetter) {
|
||||
char tempChar[2];
|
||||
tempChar[0] = aLetter;
|
||||
tempChar[1] = 0;
|
||||
nsAutoString tempChar2 = tempChar;
|
||||
|
||||
if (shortcutKey.EqualsIgnoreCase(tempChar2)) {
|
||||
// We match!
|
||||
nsCOMPtr<nsIMenuFrame> menuFrame = do_QueryInterface(currFrame);
|
||||
if (menuFrame)
|
||||
@ -708,7 +713,7 @@ nsMenuPopupFrame::FindMenuWithShortcut(PRUint32 aLetter)
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
void
|
||||
NS_IMETHODIMP
|
||||
nsMenuPopupFrame::ShortcutNavigation(PRUint32 aLetter, PRBool& aHandledFlag)
|
||||
{
|
||||
if (mCurrentMenu) {
|
||||
@ -717,7 +722,7 @@ nsMenuPopupFrame::ShortcutNavigation(PRUint32 aLetter, PRBool& aHandledFlag)
|
||||
if (isOpen) {
|
||||
// No way this applies to us. Give it to our child.
|
||||
mCurrentMenu->ShortcutNavigation(aLetter, aHandledFlag);
|
||||
return;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
@ -729,9 +734,11 @@ nsMenuPopupFrame::ShortcutNavigation(PRUint32 aLetter, PRBool& aHandledFlag)
|
||||
SetCurrentMenuItem(result);
|
||||
result->Enter();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
NS_IMETHODIMP
|
||||
nsMenuPopupFrame::KeyboardNavigation(PRUint32 aDirection, PRBool& aHandledFlag)
|
||||
{
|
||||
// This method only gets called if we're open.
|
||||
@ -746,7 +753,7 @@ nsMenuPopupFrame::KeyboardNavigation(PRUint32 aDirection, PRBool& aHandledFlag)
|
||||
SetCurrentMenuItem(nextItem);
|
||||
}
|
||||
}
|
||||
return;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool isContainer = PR_FALSE;
|
||||
@ -768,7 +775,7 @@ nsMenuPopupFrame::KeyboardNavigation(PRUint32 aDirection, PRBool& aHandledFlag)
|
||||
}
|
||||
|
||||
if (aHandledFlag)
|
||||
return; // The child menu took it for us.
|
||||
return NS_OK; // The child menu took it for us.
|
||||
|
||||
// For the vertical direction, we can move up or down.
|
||||
if (aDirection == NS_VK_UP || aDirection == NS_VK_DOWN) {
|
||||
@ -790,6 +797,8 @@ nsMenuPopupFrame::KeyboardNavigation(PRUint32 aDirection, PRBool& aHandledFlag)
|
||||
aHandledFlag = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -905,6 +914,38 @@ nsMenuPopupFrame::CreateDismissalListener()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMenuPopupFrame::InstallKeyboardNavigator()
|
||||
{
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
mContent->GetDocument(*getter_AddRefs(doc));
|
||||
nsCOMPtr<nsIDOMEventReceiver> target = do_QueryInterface(doc);
|
||||
|
||||
mTarget = target;
|
||||
mKeyboardNavigator = new nsMenuListener(this);
|
||||
NS_IF_ADDREF(mKeyboardNavigator);
|
||||
|
||||
target->AddEventListener("keypress", (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
|
||||
target->AddEventListener("keydown", (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
|
||||
target->AddEventListener("keyup", (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMenuPopupFrame::RemoveKeyboardNavigator()
|
||||
{
|
||||
mTarget->RemoveEventListener("keypress", (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
|
||||
mTarget->RemoveEventListener("keydown", (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
|
||||
mTarget->RemoveEventListener("keyup", (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
|
||||
|
||||
NS_IF_RELEASE(mKeyboardNavigator);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// helpers /////////////////////////////////////////////////////////////
|
||||
|
||||
PRBool
|
||||
nsMenuPopupFrame::IsValidItem(nsIContent* aContent)
|
||||
{
|
||||
|
@ -30,6 +30,8 @@
|
||||
#include "prtypes.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIDOMEventReceiver.h"
|
||||
#include "nsMenuListener.h"
|
||||
|
||||
#include "nsBoxFrame.h"
|
||||
#include "nsIMenuParent.h"
|
||||
@ -67,6 +69,9 @@ public:
|
||||
// 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.
|
||||
@ -99,13 +104,13 @@ public:
|
||||
|
||||
NS_IMETHOD CaptureMouseEvents(nsIPresContext* aPresContext, PRBool aGrabMouseEvents);
|
||||
|
||||
void KeyboardNavigation(PRUint32 aDirection, PRBool& aHandledFlag);
|
||||
NS_IMETHOD KeyboardNavigation(PRUint32 aDirection, PRBool& aHandledFlag);
|
||||
NS_IMETHOD ShortcutNavigation(PRUint32 aLetter, PRBool& aHandledFlag);
|
||||
|
||||
void ShortcutNavigation(PRUint32 aLetter, PRBool& aHandledFlag);
|
||||
nsIMenuFrame* FindMenuWithShortcut(PRUint32 aLetter);
|
||||
NS_IMETHOD Escape(PRBool& aHandledFlag);
|
||||
NS_IMETHOD Enter();
|
||||
|
||||
void Escape(PRBool& aHandledFlag);
|
||||
void Enter();
|
||||
nsIMenuFrame* FindMenuWithShortcut(PRUint32 aLetter);
|
||||
|
||||
PRBool IsValidItem(nsIContent* aContent);
|
||||
PRBool IsDisabled(nsIContent* aContent);
|
||||
@ -123,6 +128,10 @@ protected:
|
||||
PRBool mIsCapturingMouseEvents; // Whether or not we're grabbing the mouse events.
|
||||
// XXX Hack
|
||||
nsIPresContext* mPresContext; // weak reference
|
||||
|
||||
nsMenuListener* mKeyboardNavigator; // The listener that tells us about key events.
|
||||
nsIDOMEventReceiver* mTarget;
|
||||
|
||||
}; // class nsMenuPopupFrame
|
||||
|
||||
#endif
|
||||
|
@ -455,6 +455,7 @@ nsPopupSetFrame::OpenPopup(PRBool aActivateFlag)
|
||||
|
||||
nsCOMPtr<nsIMenuParent> childPopup = do_QueryInterface(activeChild);
|
||||
UpdateDismissalListener(childPopup);
|
||||
childPopup->InstallKeyboardNavigator();
|
||||
}
|
||||
else {
|
||||
if (!OnDestroy())
|
||||
@ -465,6 +466,11 @@ nsPopupSetFrame::OpenPopup(PRBool aActivateFlag)
|
||||
nsMenuFrame::mDismissalListener->Unregister();
|
||||
}
|
||||
|
||||
// Remove any keyboard navigators
|
||||
nsIFrame* activeChild = GetActiveChild();
|
||||
nsCOMPtr<nsIMenuParent> childPopup = do_QueryInterface(activeChild);
|
||||
childPopup->RemoveKeyboardNavigator();
|
||||
|
||||
ActivatePopup(PR_FALSE);
|
||||
}
|
||||
}
|
||||
@ -553,5 +559,3 @@ nsPopupSetFrame::UpdateDismissalListener(nsIMenuParent* aMenuParent)
|
||||
// innermost menu popup frame is.
|
||||
nsMenuFrame::mDismissalListener->SetCurrentMenuParent(aMenuParent);
|
||||
}
|
||||
|
||||
|
||||
|
@ -103,7 +103,8 @@ nsTreeTwistyListener::MouseDown(nsIDOMEvent* aEvent)
|
||||
// Eat the event.
|
||||
aEvent->PreventCapture();
|
||||
aEvent->PreventBubble();
|
||||
|
||||
aEvent->PreventDefault();
|
||||
|
||||
nsAutoString open;
|
||||
treeItem->GetAttribute("open", open);
|
||||
if (open == "true")
|
||||
|
Loading…
Reference in New Issue
Block a user