diff --git a/content/events/public/nsIEventStateManager.h b/content/events/public/nsIEventStateManager.h index 35fdd106bc0..f5f52faa958 100644 --- a/content/events/public/nsIEventStateManager.h +++ b/content/events/public/nsIEventStateManager.h @@ -74,6 +74,10 @@ public: NS_IMETHOD GetFocusedContent(nsIContent **aContent) = 0; NS_IMETHOD SetFocusedContent(nsIContent* aContent) = 0; + virtual PRBool ChangeFocus(nsIContent* aFocus, nsIFrame* aFocusFrame, PRBool aSetFocus) = 0; + NS_IMETHOD GetNextTabbableContent(nsIContent* aRootContent, nsIFrame* aFrame, + PRBool forward, nsIContent** aResult) = 0; + // This is an experiement and may be temporary NS_IMETHOD ConsumeFocusEvents(PRBool aDoConsume) = 0; diff --git a/content/events/src/nsEventStateManager.cpp b/content/events/src/nsEventStateManager.cpp index 3b5c6331c0d..e7a949d68b8 100644 --- a/content/events/src/nsEventStateManager.cpp +++ b/content/events/src/nsEventStateManager.cpp @@ -2390,12 +2390,26 @@ nsEventStateManager::ShiftFocus(PRBool forward, nsIContent* aRoot) nsCOMPtr next; //Get the next tab item. This takes tabIndex into account - GetNextTabbableContent(rootContent, primaryFrame, forward, getter_AddRefs(next)); - + if (!topOfDoc) + GetNextTabbableContent(rootContent, primaryFrame, forward, getter_AddRefs(next)); + //Either no tabbable items or the end of the document if (!next) { - PRBool focusTaken = PR_FALSE; + // If we've reached the end of the content in this document, we + // focus the document itself before leaving. + if (!topOfDoc) { + nsCOMPtr sgo; + mDocument->GetScriptGlobalObject(getter_AddRefs(sgo)); + nsCOMPtr domwin(do_QueryInterface(sgo)); + if (domwin) { + SetContentState(nsnull, NS_EVENT_STATE_FOCUS); + if (NS_SUCCEEDED(domwin->Focus())) + return; + } + } + + PRBool focusTaken = PR_FALSE; SetContentState(nsnull, NS_EVENT_STATE_FOCUS); //Offer focus upwards to allow shifting focus to UI controls diff --git a/content/events/src/nsEventStateManager.h b/content/events/src/nsEventStateManager.h index 6d7d785d438..a3cf493e58c 100644 --- a/content/events/src/nsEventStateManager.h +++ b/content/events/src/nsEventStateManager.h @@ -120,8 +120,8 @@ protected: NS_IMETHOD SetClickCount(nsIPresContext* aPresContext, nsMouseEvent *aEvent, nsEventStatus* aStatus); NS_IMETHOD CheckForAndDispatchClick(nsIPresContext* aPresContext, nsMouseEvent *aEvent, nsEventStatus* aStatus); PRBool ChangeFocus(nsIContent* aFocus, nsIFrame* aFocusFrame, PRBool aSetFocus); - void ShiftFocus(PRBool foward, nsIContent* aRoot=nsnull); - NS_IMETHOD GetNextTabbableContent(nsIContent* aRootContent, nsIFrame* aFrame, PRBool foward, nsIContent** aResult); + void ShiftFocus(PRBool forward, nsIContent* aRoot=nsnull); + NS_IMETHOD GetNextTabbableContent(nsIContent* aRootContent, nsIFrame* aFrame, PRBool forward, nsIContent** aResult); PRInt32 GetNextTabIndex(nsIContent* aParent, PRBool foward); NS_IMETHOD SendFocusBlur(nsIPresContext* aPresContext, nsIContent *aContent); PRBool CheckDisabled(nsIContent* aContent); diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index fe18f487ebb..3aadfa316ba 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file @@ -92,6 +92,8 @@ // http://bugzilla.mozilla.org/show_bug.cgi?id=71482 #include "nsIBrowserHistory.h" +#include "nsIEventStateManager.h" + #ifdef IBMBIDI #include "nsIUBidiUtils.h" #endif @@ -1970,96 +1972,108 @@ NS_IMETHODIMP nsDocShell::GetMainWidget(nsIWidget** aMainWidget) NS_IMETHODIMP nsDocShell::SetFocus() { - nsCOMPtr domDoc; - mContentViewer->GetDOMDocument(getter_AddRefs(domDoc)); - nsCOMPtr doc(do_QueryInterface(domDoc)); - if (doc) { - nsCOMPtr sgo; - doc->GetScriptGlobalObject(getter_AddRefs(sgo)); - if (sgo) { - nsCOMPtr domwin(do_QueryInterface(sgo)); - if (domwin) - domwin->Focus(); - } + nsCOMPtr presShell; + nsCOMPtr document; + GetPresShell(getter_AddRefs(presShell)); + if (!presShell) + return NS_ERROR_FAILURE; + presShell->GetDocument(getter_AddRefs(document)); + + nsCOMPtr presContext; + GetPresContext(getter_AddRefs(presContext)); + if (!presContext) + return NS_ERROR_FAILURE; + + nsCOMPtr esm; + presContext->GetEventStateManager(getter_AddRefs(esm)); + if (!esm) + return NS_ERROR_FAILURE; + + nsCOMPtr rootContent(getter_AddRefs(document->GetRootContent())); + if (!rootContent) return NS_ERROR_FAILURE; + + nsCOMPtr focusContent; + esm->GetNextTabbableContent(rootContent, nsnull, PR_TRUE, + getter_AddRefs(focusContent)); + if (focusContent) { + nsIFrame* focusFrame = nsnull; + presShell->GetPrimaryFrameFor(focusContent, &focusFrame); + esm->ChangeFocus(focusContent, focusFrame, PR_TRUE); } + return NS_OK; } NS_IMETHODIMP nsDocShell::FocusAvailable(nsIBaseWindow* aCurrentFocus, - PRBool* aTookFocus) + PRBool* aTookFocus) { - NS_ENSURE_ARG_POINTER(aTookFocus); + NS_ENSURE_ARG_POINTER(aTookFocus); + + // Next person we should call is first the parent otherwise the + // docshell tree owner. - // Next person we should call is first the parent otherwise the - // docshell tree owner. - nsCOMPtr nextCallWin(do_QueryInterface(mParent)); - if(!nextCallWin) - { - nextCallWin = do_QueryInterface(mTreeOwner); + nsCOMPtr nextCallWin(do_QueryInterface(mParent)); + if(!nextCallWin) + nextCallWin = do_QueryInterface(mTreeOwner); + + //If the current focus is us, offer it to the next owner. + if(aCurrentFocus == NS_STATIC_CAST(nsIBaseWindow*, this)) { + if(nextCallWin) { + nsresult ret = nextCallWin->FocusAvailable(aCurrentFocus, aTookFocus); + if (NS_SUCCEEDED(ret) && *aTookFocus) + return NS_OK; + } + + if (!mChildren.Count()) { + //If we don't have children and our parent didn't want + //the focus then we should just stop now. + return NS_OK; + } + } + + + //Otherwise, check the chilren and offer it to the next sibling. + PRInt32 i; + PRInt32 n = mChildren.Count(); + for(i = 0; i < n; i++) { + nsCOMPtr + child(do_QueryInterface((nsISupports*)mChildren.ElementAt(i))); + //If we have focus we offer it to our first child. + if(aCurrentFocus == NS_STATIC_CAST(nsIBaseWindow*, this)) { + if(NS_SUCCEEDED(child->SetFocus())) { + *aTookFocus = PR_TRUE; + return NS_OK; } - - //If the current focus is us, offer it to the next owner. - if(aCurrentFocus == NS_STATIC_CAST(nsIBaseWindow*, this)) - { - if(nextCallWin) - { - nsresult ret = nextCallWin->FocusAvailable(aCurrentFocus, aTookFocus); - if (NS_SUCCEEDED(ret) && *aTookFocus) + else + return NS_ERROR_FAILURE; + } + //If we don't have focus, find the child that does then + //offer focus to the next one. + if (child.get() == aCurrentFocus) { + while(++i < n) { + child = do_QueryInterface((nsISupports*)mChildren.ElementAt(i)); + if(NS_SUCCEEDED(child->SetFocus())) { + *aTookFocus = PR_TRUE; return NS_OK; } - - if (!mChildren.Count()) - { - //If we don't have children and our parent didn't want - //the focus then we should just stop now. - return NS_OK; - } + else + return NS_ERROR_FAILURE; } + } + } + + //Reached the end of our child list. If we aren't currently focused, try + // to accept focus. - //Otherwise, check the chilren and offer it to the next sibling. - PRInt32 i; - PRInt32 n = mChildren.Count(); - for(i = 0; i < n; i++) - { - nsCOMPtr - child(do_QueryInterface((nsISupports*)mChildren.ElementAt(i))); - //If we have focus we offer it to our first child. - if(aCurrentFocus == NS_STATIC_CAST(nsIBaseWindow*, this)) - { - if(NS_SUCCEEDED(child->SetFocus())) - { - *aTookFocus = PR_TRUE; - return NS_OK; - } - else - { - return NS_ERROR_FAILURE; - } - } - //If we don't have focus, find the child that does then - //offer focus to the next one. - if (child.get() == aCurrentFocus) - { - while(++i < n) - { - child = do_QueryInterface((nsISupports*)mChildren.ElementAt(i)); - if(NS_SUCCEEDED(child->SetFocus())) - { - *aTookFocus = PR_TRUE; - return NS_OK; - } - else - { - return NS_ERROR_FAILURE; - } - } - } - } + if ((aCurrentFocus != NS_STATIC_CAST(nsIBaseWindow*, this)) && + NS_SUCCEEDED(SetFocus())) { + *aTookFocus = PR_TRUE; + return NS_OK; + } - //Reached the end of our child list. Call again to offer focus - //upwards and to start at the beginning of our child list if - //no one above us wants focus. - return FocusAvailable(this, aTookFocus); + // Call again to offer focus upwards and to start at the beginning of our + // child list if no one above us wants focus. + return FocusAvailable(this, aTookFocus); } NS_IMETHODIMP nsDocShell::GetTitle(PRUnichar** aTitle)