зеркало из https://github.com/mozilla/pjs.git
Bug 421209, r=cpearce, sr=jst, a=beltzner
This commit is contained in:
Родитель
3882c23eb0
Коммит
758c9b0305
|
@ -868,6 +868,9 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
|||
break;
|
||||
case NS_GOTFOCUS:
|
||||
{
|
||||
#ifdef DEBUG_smaug
|
||||
printf("nsEventStateManager::PreHandleEvent, NS_GOTFOCUS \n");
|
||||
#endif
|
||||
// This is called when a child widget has received focus.
|
||||
// We need to take care of sending a blur event for the previously
|
||||
// focused content and document, then dispatching a focus
|
||||
|
@ -1031,6 +1034,9 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
|||
|
||||
case NS_LOSTFOCUS:
|
||||
{
|
||||
#ifdef DEBUG_smaug
|
||||
printf("nsEventStateManager::PreHandleEvent, NS_LOSTFOCUS \n");
|
||||
#endif
|
||||
// Hide the caret if it's visible.
|
||||
if (mPresContext) {
|
||||
nsIPresShell *presShell = mPresContext->GetPresShell();
|
||||
|
@ -1052,7 +1058,10 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
|||
// This allows "-moz-user-focus: ignore" to work.
|
||||
|
||||
#if defined(XP_WIN) || defined(XP_OS2)
|
||||
if (!static_cast<nsFocusEvent*>(aEvent)->isMozWindowTakingFocus) {
|
||||
//XXXsmaug Change all the NS_LOSTFOCUS/GOTFOCUS events to use
|
||||
// the same event struct type!
|
||||
if (aEvent->eventStructType == NS_FOCUS_EVENT &&
|
||||
!static_cast<nsFocusEvent*>(aEvent)->isMozWindowTakingFocus) {
|
||||
|
||||
// This situation occurs when focus goes to a non-gecko child window
|
||||
// in an embedding application. In this case we do fire a blur
|
||||
|
@ -1124,6 +1133,9 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
|||
|
||||
case NS_ACTIVATE:
|
||||
{
|
||||
#ifdef DEBUG_smaug
|
||||
printf("nsEventStateManager::PreHandleEvent, NS_ACTIVATE \n");
|
||||
#endif
|
||||
// If we have a focus controller, and if it has a focused window and a
|
||||
// focused element in its focus memory, then restore the focus to those
|
||||
// objects.
|
||||
|
@ -1211,6 +1223,9 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
|||
|
||||
case NS_DEACTIVATE:
|
||||
{
|
||||
#ifdef DEBUG_smaug
|
||||
printf("nsEventStateManager::PreHandleEvent, NS_DEACTIVATE \n");
|
||||
#endif
|
||||
EnsureDocument(aPresContext);
|
||||
|
||||
nsIMEStateManager::OnDeactivate(aPresContext);
|
||||
|
|
|
@ -201,6 +201,7 @@ static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
|
|||
#endif
|
||||
|
||||
#include "nsContentErrors.h"
|
||||
#include "nsIFocusEventSuppressor.h"
|
||||
|
||||
// Number of documents currently loading
|
||||
static PRInt32 gNumberOfDocumentsLoading = 0;
|
||||
|
@ -3675,7 +3676,12 @@ nsDocShell::Destroy()
|
|||
if (docShellParentAsItem)
|
||||
docShellParentAsItem->RemoveChild(this);
|
||||
|
||||
nsCOMPtr<nsIFocusEventSuppressorService> suppressor;
|
||||
if (mContentViewer) {
|
||||
suppressor =
|
||||
do_GetService(NS_NSIFOCUSEVENTSUPPRESSORSERVICE_CONTRACTID);
|
||||
NS_ENSURE_STATE(suppressor);
|
||||
suppressor->Suppress();
|
||||
mContentViewer->Close(nsnull);
|
||||
mContentViewer->Destroy();
|
||||
mContentViewer = nsnull;
|
||||
|
@ -3702,7 +3708,9 @@ nsDocShell::Destroy()
|
|||
// Cancel any timers that were set for this docshell; this is needed
|
||||
// to break the cycle between us and the timers.
|
||||
CancelRefreshURITimers();
|
||||
|
||||
if (suppressor) {
|
||||
suppressor->Unsuppress();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -109,6 +109,7 @@ EXPORTS = \
|
|||
nsIReflowCallback.h \
|
||||
nsLayoutErrors.h \
|
||||
nsLayoutUtils.h \
|
||||
nsIFocusEventSuppressor.h \
|
||||
nsPresContext.h \
|
||||
nsPresState.h \
|
||||
nsStyleChangeList.h \
|
||||
|
@ -122,7 +123,7 @@ CPPSRCS = \
|
|||
nsCaret.cpp \
|
||||
nsChildIterator.cpp \
|
||||
nsCounterManager.cpp \
|
||||
nsDisplayList.cpp \
|
||||
nsDisplayList.cpp \
|
||||
nsDocumentViewer.cpp \
|
||||
nsFrameManager.cpp \
|
||||
nsFrameTraversal.cpp \
|
||||
|
@ -137,6 +138,7 @@ CPPSRCS = \
|
|||
nsQuoteList.cpp \
|
||||
nsStyleChangeList.cpp \
|
||||
nsStyleSheetService.cpp \
|
||||
nsFocusEventSuppressor.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifndef MOZ_XUL
|
||||
|
|
|
@ -121,7 +121,7 @@
|
|||
#include "nsIPrincipal.h"
|
||||
#include "nsIDOMWindowInternal.h"
|
||||
#include "nsStyleUtil.h"
|
||||
|
||||
#include "nsIFocusEventSuppressor.h"
|
||||
#include "nsBox.h"
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
|
@ -379,23 +379,6 @@ static nsresult
|
|||
DeletingFrameSubtree(nsFrameManager* aFrameManager,
|
||||
nsIFrame* aFrame);
|
||||
|
||||
void nsFocusEventSuppressor::Suppress(nsIPresShell *aPresShell)
|
||||
{
|
||||
NS_ASSERTION(aPresShell, "Need non-null nsIPresShell!");
|
||||
if (!mViewManager) {
|
||||
nsFrameManager *frameManager = aPresShell->FrameManager();
|
||||
mViewManager = frameManager->GetPresContext()->GetViewManager();
|
||||
NS_ASSERTION(mViewManager, "We must have an mViewManager here");
|
||||
}
|
||||
mViewManager->SuppressFocusEvents();
|
||||
}
|
||||
|
||||
void nsFocusEventSuppressor::Unsuppress()
|
||||
{
|
||||
NS_ASSERTION(mViewManager, "We must have an mViewManager here");
|
||||
mViewManager->UnsuppressFocusEvents();
|
||||
}
|
||||
|
||||
#ifdef MOZ_SVG
|
||||
|
||||
static nsIFrame *
|
||||
|
@ -10252,7 +10235,7 @@ nsCSSFrameConstructor::AttributeChanged(nsIContent* aContent,
|
|||
|
||||
void
|
||||
nsCSSFrameConstructor::BeginUpdate() {
|
||||
mFocusSuppressor.Suppress(mPresShell);
|
||||
NS_SuppressFocusEvent();
|
||||
++mUpdateCount;
|
||||
}
|
||||
|
||||
|
@ -10266,7 +10249,7 @@ nsCSSFrameConstructor::EndUpdate()
|
|||
RecalcQuotesAndCounters();
|
||||
NS_ASSERTION(mUpdateCount == 1, "Odd update count");
|
||||
}
|
||||
mFocusSuppressor.Unsuppress();
|
||||
NS_UnsuppressFocusEvent();
|
||||
--mUpdateCount;
|
||||
}
|
||||
|
||||
|
|
|
@ -74,19 +74,6 @@ struct nsFindFrameHint
|
|||
nsFindFrameHint() : mPrimaryFrameForPrevSibling(nsnull) { }
|
||||
};
|
||||
|
||||
// Class which makes an nsIPresShell's ViewManager supress
|
||||
// focus/blur events. This prevents the frame tree from being changed
|
||||
// by focus handlers etc while *we* are trying to change it.
|
||||
// Fix for bug 399852.
|
||||
class nsFocusEventSuppressor
|
||||
{
|
||||
public:
|
||||
void Suppress(nsIPresShell *aPresShell);
|
||||
void Unsuppress();
|
||||
private:
|
||||
nsCOMPtr<nsIViewManager> mViewManager;
|
||||
};
|
||||
|
||||
typedef void (PR_CALLBACK nsLazyFrameConstructionCallback)
|
||||
(nsIContent* aContent, nsIFrame* aFrame, void* aArg);
|
||||
|
||||
|
@ -177,8 +164,6 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
nsFocusEventSuppressor mFocusSuppressor;
|
||||
|
||||
// Note: It's the caller's responsibility to make sure to wrap a
|
||||
// ProcessOneRestyle call in a view update batch.
|
||||
// This function does not call ProcessAttachedQueue() on the binding manager.
|
||||
|
|
|
@ -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 Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Olli Pettay <Olli.Pettay@helsinki.fi> (Original Author)
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
#include "nsIFocusEventSuppressor.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsFocusEventSuppressorService : public nsIFocusEventSuppressorService
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
virtual void AddObserverCallback(nsFocusEventSuppressorCallback aCallback)
|
||||
{
|
||||
NS_AddFocusSuppressorCallback(aCallback);
|
||||
}
|
||||
virtual void Suppress()
|
||||
{
|
||||
NS_SuppressFocusEvent();
|
||||
}
|
||||
virtual void Unsuppress()
|
||||
{
|
||||
NS_UnsuppressFocusEvent();
|
||||
}
|
||||
};
|
||||
|
||||
static nsTArray<nsFocusEventSuppressorCallback>* sCallbacks = nsnull;
|
||||
static PRUint32 sFocusSuppressCount = 0;
|
||||
|
||||
NS_IMPL_ADDREF(nsFocusEventSuppressorService)
|
||||
NS_IMPL_RELEASE(nsFocusEventSuppressorService)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsFocusEventSuppressorService)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIFocusEventSuppressorService)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
void
|
||||
NS_AddFocusSuppressorCallback(nsFocusEventSuppressorCallback aCallback)
|
||||
{
|
||||
if (aCallback) {
|
||||
if (!sCallbacks) {
|
||||
sCallbacks = new nsTArray<nsFocusEventSuppressorCallback>(2);
|
||||
if (!sCallbacks) {
|
||||
NS_WARNING("Out of memory!");
|
||||
return;
|
||||
}
|
||||
} else if (sCallbacks->Contains(aCallback)) {
|
||||
return;
|
||||
}
|
||||
sCallbacks->AppendElement(aCallback);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
NS_SuppressFocusEvent()
|
||||
{
|
||||
++sFocusSuppressCount;
|
||||
if (sFocusSuppressCount == 1 && sCallbacks) {
|
||||
for (PRUint32 i = 0; i < sCallbacks->Length(); ++i) {
|
||||
sCallbacks->ElementAt(i)(PR_TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
NS_UnsuppressFocusEvent()
|
||||
{
|
||||
--sFocusSuppressCount;
|
||||
if (sFocusSuppressCount == 0 && sCallbacks) {
|
||||
for (PRUint32 i = 0; i < sCallbacks->Length(); ++i) {
|
||||
sCallbacks->ElementAt(i)(PR_FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
NS_ShutdownFocusSuppressor()
|
||||
{
|
||||
delete sCallbacks;
|
||||
sCallbacks = nsnull;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_NewFocusEventSuppressorService(nsIFocusEventSuppressorService** aResult)
|
||||
{
|
||||
nsIFocusEventSuppressorService* it = new nsFocusEventSuppressorService();
|
||||
NS_ENSURE_TRUE(it, NS_ERROR_OUT_OF_MEMORY);
|
||||
NS_ADDREF(*aResult = it);
|
||||
return NS_OK;
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/* -*- 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 Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Olli Pettay <Olli.Pettay@helsinki.fi> (Original Author)
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
#ifndef nsIFocusEventSuppressor_h___
|
||||
#define nsIFocusEventSuppressor_h___
|
||||
#include "nsISupports.h"
|
||||
|
||||
typedef void (*PR_CALLBACK nsFocusEventSuppressorCallback)(PRBool aSuppress);
|
||||
|
||||
#define NS_NSIFOCUSEVENTSUPPRESSORSERVICE_IID \
|
||||
{ 0x8aae5cee, 0x59ab, 0x42d4, \
|
||||
{ 0xa3, 0x76, 0xbf, 0x63, 0x54, 0x04, 0xc7, 0x98 } }
|
||||
|
||||
class nsIFocusEventSuppressorService : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_NSIFOCUSEVENTSUPPRESSORSERVICE_IID)
|
||||
virtual void AddObserverCallback(nsFocusEventSuppressorCallback aCallback) = 0;
|
||||
virtual void Suppress() = 0;
|
||||
virtual void Unsuppress() = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIFocusEventSuppressorService,
|
||||
NS_NSIFOCUSEVENTSUPPRESSORSERVICE_IID)
|
||||
|
||||
#if defined(_IMPL_NS_LAYOUT) || defined(NS_STATIC_FOCUS_SUPPRESSOR)
|
||||
void NS_SuppressFocusEvent();
|
||||
void NS_UnsuppressFocusEvent();
|
||||
void NS_AddFocusSuppressorCallback(nsFocusEventSuppressorCallback aCallback);
|
||||
void NS_ShutdownFocusSuppressor();
|
||||
#endif
|
||||
|
||||
#define NS_NSIFOCUSEVENTSUPPRESSORSERVICE_CID \
|
||||
{ 0x35b2656c, 0x4102, 0x4bc1, \
|
||||
{ 0x87, 0x6a, 0xfd, 0x6c, 0xb8, 0x30, 0x78, 0x7b } }
|
||||
|
||||
#define NS_NSIFOCUSEVENTSUPPRESSORSERVICE_CONTRACTID \
|
||||
"@mozilla.org/focus-event-suppressor-service;1"
|
||||
|
||||
#endif
|
|
@ -127,6 +127,8 @@
|
|||
#include "nsDOMStorage.h"
|
||||
#include "nsJSON.h"
|
||||
|
||||
#include "nsIFocusEventSuppressor.h"
|
||||
|
||||
// Editor stuff
|
||||
#include "nsEditorCID.h"
|
||||
#include "nsEditor.h"
|
||||
|
@ -416,6 +418,7 @@ nsresult NS_NewTextEncoder(nsIDocumentEncoder** aResult);
|
|||
nsresult NS_NewXBLService(nsIXBLService** aResult);
|
||||
nsresult NS_NewContentPolicy(nsIContentPolicy** aResult);
|
||||
nsresult NS_NewDOMEventGroup(nsIDOMEventGroup** aResult);
|
||||
nsresult NS_NewFocusEventSuppressorService(nsIFocusEventSuppressorService** aResult);
|
||||
|
||||
NS_IMETHODIMP NS_NewXULControllers(nsISupports* aOuter, REFNSIID aIID, void** aResult);
|
||||
|
||||
|
@ -503,6 +506,7 @@ MAKE_CTOR(CreateSanitizingHTMLSerializer, nsIContentSerializer, NS_NewSan
|
|||
MAKE_CTOR(CreateXBLService, nsIXBLService, NS_NewXBLService)
|
||||
MAKE_CTOR(CreateContentPolicy, nsIContentPolicy, NS_NewContentPolicy)
|
||||
MAKE_CTOR(CreateComputedDOMStyle, nsIComputedDOMStyle, NS_NewComputedDOMStyle)
|
||||
MAKE_CTOR(CreateFocusEventSuppressorService,nsIFocusEventSuppressorService,NS_NewFocusEventSuppressorService)
|
||||
#ifdef MOZ_XUL
|
||||
MAKE_CTOR(CreateXULSortService, nsIXULSortService, NS_NewXULSortService)
|
||||
// NS_NewXULContentBuilder
|
||||
|
@ -1262,6 +1266,11 @@ static const nsModuleComponentInfo gComponents[] = {
|
|||
{ "View Manager", NS_VIEW_MANAGER_CID, "@mozilla.org/view-manager;1",
|
||||
nsViewManagerConstructor },
|
||||
|
||||
{ "Focus Event Suppressor",
|
||||
NS_NSIFOCUSEVENTSUPPRESSORSERVICE_CID,
|
||||
NS_NSIFOCUSEVENTSUPPRESSORSERVICE_CONTRACTID,
|
||||
CreateFocusEventSuppressorService },
|
||||
|
||||
{ "Plugin Document Loader Factory",
|
||||
NS_PLUGINDOCLOADERFACTORY_CID,
|
||||
"@mozilla.org/content/plugin/document-loader-factory;1",
|
||||
|
|
|
@ -82,6 +82,7 @@
|
|||
#include "nsTextFragment.h"
|
||||
#include "nsCSSRuleProcessor.h"
|
||||
#include "nsXMLHttpRequest.h"
|
||||
#include "nsIFocusEventSuppressor.h"
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
#include "nsXULPopupManager.h"
|
||||
|
@ -310,6 +311,7 @@ nsLayoutStatics::Shutdown()
|
|||
#endif
|
||||
|
||||
nsXMLHttpRequest::ShutdownACCache();
|
||||
NS_ShutdownFocusSuppressor();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -60,10 +60,10 @@ enum nsRectVisibility {
|
|||
nsRectVisibility_kZeroAreaRect
|
||||
};
|
||||
|
||||
// 5a1e80e1-b51c-4f43-8950-1064bd1f39ee
|
||||
// 855e75b8-32cf-4e16-bc50-4e04c53f6cbc
|
||||
#define NS_IVIEWMANAGER_IID \
|
||||
{ 0x5a1e80e1, 0xb51c, 0x4f43, \
|
||||
{ 0x89, 0x50, 0x10, 0x64, 0xbd, 0x1f, 0x39, 0xee } }
|
||||
{ 0x855e75b8, 0x32cf, 0x4e16, \
|
||||
{ 0xbc, 0x50, 0x4e, 0x04, 0xc5, 0x3f, 0x6c, 0xbc } }
|
||||
|
||||
class nsIViewManager : public nsISupports
|
||||
{
|
||||
|
@ -481,30 +481,6 @@ public:
|
|||
* (aFromScroll is false) or scrolled (aFromScroll is true).
|
||||
*/
|
||||
NS_IMETHOD SynthesizeMouseMove(PRBool aFromScroll)=0;
|
||||
|
||||
/**
|
||||
* Enables focus/blur event suppression. This stops focus/blur
|
||||
* events from reaching the widgets. This should be enabled
|
||||
* when we're messing with the frame tree, so focus/blur handlers
|
||||
* don't mess with stuff while we are. See Bug 399852.
|
||||
*/
|
||||
virtual void SuppressFocusEvents()=0;
|
||||
|
||||
/**
|
||||
* Disables focus/blur event suppression. This "reboots" the focus
|
||||
* by sending a blur to what was focused before suppression began,
|
||||
* and by sending a focus event to what should be currently focused.
|
||||
* Note this can run arbitrary code, and could even destroy the view
|
||||
* manager. The suppression should be enabled when we're messing with
|
||||
* the frame tree, so focus/blur handlers don't mess with stuff while
|
||||
* we are. See Bug 399852.
|
||||
*/
|
||||
virtual void UnsuppressFocusEvents()=0;
|
||||
|
||||
/**
|
||||
* Returns true when focus suppression is on.
|
||||
*/
|
||||
virtual PRBool IsFocusSuppressed()=0;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -62,8 +62,9 @@
|
|||
#include "nsCOMArray.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
#include "gfxContext.h"
|
||||
#define NS_STATIC_FOCUS_SUPPRESSOR
|
||||
#include "nsIFocusEventSuppressor.h"
|
||||
|
||||
static NS_DEFINE_IID(kBlenderCID, NS_BLENDER_CID);
|
||||
static NS_DEFINE_IID(kRegionCID, NS_REGION_CID);
|
||||
|
@ -93,6 +94,10 @@ static NS_DEFINE_IID(kRenderingContextCID, NS_RENDERING_CONTEXT_CID);
|
|||
#include "nsITimeRecorder.h"
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_smaug
|
||||
#define DEBUG_FOCUS_SUPPRESSION
|
||||
#endif
|
||||
|
||||
//-------------- Begin Invalidate Event Definition ------------------------
|
||||
|
||||
class nsInvalidateEvent : public nsViewManagerEvent {
|
||||
|
@ -169,7 +174,9 @@ nsViewManager::nsViewManager()
|
|||
|
||||
gViewManagers->AppendElement(this);
|
||||
|
||||
mVMCount++;
|
||||
if (++mVMCount == 1) {
|
||||
NS_AddFocusSuppressorCallback(&nsViewManager::SuppressFocusEvents);
|
||||
}
|
||||
// NOTE: we use a zeroing operator new, so all data members are
|
||||
// assumed to be cleared here.
|
||||
mDefaultBackgroundColor = NS_RGBA(0, 0, 0, 0);
|
||||
|
@ -942,24 +949,20 @@ void nsViewManager::UpdateViews(nsView *aView, PRUint32 aUpdateFlags)
|
|||
|
||||
nsView *nsViewManager::sCurrentlyFocusView = nsnull;
|
||||
nsView *nsViewManager::sViewFocusedBeforeSuppression = nsnull;
|
||||
PRInt32 nsViewManager::sSuppressCount = 0;
|
||||
PRBool nsViewManager::sFocusSuppressed = PR_FALSE;
|
||||
|
||||
void nsViewManager::SuppressFocusEvents()
|
||||
void nsViewManager::SuppressFocusEvents(PRBool aSuppress)
|
||||
{
|
||||
sSuppressCount++;
|
||||
if (sSuppressCount == 1) {
|
||||
// We're turning on focus/blur suppression, remember what had
|
||||
// the focus.
|
||||
if (aSuppress) {
|
||||
sFocusSuppressed = PR_TRUE;
|
||||
SetViewFocusedBeforeSuppression(GetCurrentlyFocusedView());
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void nsViewManager::UnsuppressFocusEvents()
|
||||
{
|
||||
sSuppressCount--;
|
||||
if (sSuppressCount > 0 ||
|
||||
GetCurrentlyFocusedView() == GetViewFocusedBeforeSuppression())
|
||||
return;
|
||||
sFocusSuppressed = PR_FALSE;
|
||||
if (GetCurrentlyFocusedView() == GetViewFocusedBeforeSuppression()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We're turning off suppression, synthesize LOSTFOCUS/GOTFOCUS.
|
||||
nsIWidget *widget = nsnull;
|
||||
|
|
|
@ -201,12 +201,23 @@ public:
|
|||
/* Update the cached RootViewManager pointer on this view manager. */
|
||||
void InvalidateHierarchy();
|
||||
|
||||
virtual void SuppressFocusEvents();
|
||||
virtual void UnsuppressFocusEvents();
|
||||
/**
|
||||
* Enables/disables focus/blur event suppression.
|
||||
* Enabling stops focus/blur events from reaching the widgets.
|
||||
* This should be enabled when we're messing with the frame tree,
|
||||
* so focus/blur handlers don't mess with stuff while we are.
|
||||
*
|
||||
* Disabling "reboots" the focus by sending a blur to what was focused
|
||||
* before suppression began, and by sending a focus event to what should
|
||||
* be currently focused. Note this can run arbitrary code, and could
|
||||
* even destroy the view manager.
|
||||
* See Bug 399852.
|
||||
*/
|
||||
static void SuppressFocusEvents(PRBool aSuppress);
|
||||
|
||||
virtual PRBool IsFocusSuppressed()
|
||||
PRBool IsFocusSuppressed()
|
||||
{
|
||||
return sSuppressCount > 0;
|
||||
return sFocusSuppressed;
|
||||
}
|
||||
|
||||
static void SetCurrentlyFocusedView(nsView *aView)
|
||||
|
@ -236,7 +247,7 @@ private:
|
|||
|
||||
static nsView *sCurrentlyFocusView;
|
||||
static nsView *sViewFocusedBeforeSuppression;
|
||||
static PRInt32 sSuppressCount;
|
||||
static PRBool sFocusSuppressed;
|
||||
|
||||
void FlushPendingInvalidates();
|
||||
void ProcessPendingUpdates(nsView *aView, PRBool aDoInvalidate);
|
||||
|
|
|
@ -107,12 +107,18 @@
|
|||
#include "nsIDocShellTreeNode.h"
|
||||
|
||||
#include "nsIMarkupDocumentViewer.h"
|
||||
#include "nsIFocusEventSuppressor.h"
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
#include "nsIMenuBar.h"
|
||||
#define USE_NATIVE_MENUS
|
||||
#endif
|
||||
|
||||
static nsWebShellWindow* gCurrentlyFocusedWindow = nsnull;
|
||||
static nsWebShellWindow* gFocusedWindowBeforeSuppression = nsnull;
|
||||
static PRBool gFocusSuppressed = PR_FALSE;
|
||||
static PRUint32 gWebShellWindowCount = 0;
|
||||
|
||||
/* Define Class IDs */
|
||||
static NS_DEFINE_CID(kWindowCID, NS_WINDOW_CID);
|
||||
|
||||
|
@ -124,11 +130,25 @@ static NS_DEFINE_CID(kMenuBarCID, NS_MENUBAR_CID);
|
|||
nsWebShellWindow::nsWebShellWindow() : nsXULWindow()
|
||||
{
|
||||
mSPTimerLock = PR_NewLock();
|
||||
if (++gWebShellWindowCount == 1) {
|
||||
nsCOMPtr<nsIFocusEventSuppressorService> suppressor =
|
||||
do_GetService(NS_NSIFOCUSEVENTSUPPRESSORSERVICE_CONTRACTID);
|
||||
if (suppressor) {
|
||||
suppressor->AddObserverCallback(&nsWebShellWindow::SuppressFocusEvents);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nsWebShellWindow::~nsWebShellWindow()
|
||||
{
|
||||
--gWebShellWindowCount;
|
||||
if (gCurrentlyFocusedWindow == this) {
|
||||
gCurrentlyFocusedWindow = nsnull;
|
||||
}
|
||||
if (gFocusedWindowBeforeSuppression == this) {
|
||||
gFocusedWindowBeforeSuppression = nsnull;
|
||||
}
|
||||
if (mWindow)
|
||||
mWindow->SetClientData(0);
|
||||
mWindow = nsnull; // Force release here.
|
||||
|
@ -422,7 +442,7 @@ nsWebShellWindow::HandleEvent(nsGUIEvent *aEvent)
|
|||
}
|
||||
|
||||
case NS_ACTIVATE: {
|
||||
#ifdef DEBUG_saari
|
||||
#if defined(DEBUG_saari) || defined(DEBUG_smaug)
|
||||
printf("nsWebShellWindow::NS_ACTIVATE\n");
|
||||
#endif
|
||||
nsCOMPtr<nsPIDOMWindow> privateDOMWindow = do_GetInterface(docShell);
|
||||
|
@ -433,7 +453,7 @@ nsWebShellWindow::HandleEvent(nsGUIEvent *aEvent)
|
|||
}
|
||||
|
||||
case NS_DEACTIVATE: {
|
||||
#ifdef DEBUG_saari
|
||||
#if defined(DEBUG_saari) || defined(DEBUG_smaug)
|
||||
printf("nsWebShellWindow::NS_DEACTIVATE\n");
|
||||
#endif
|
||||
|
||||
|
@ -450,9 +470,13 @@ nsWebShellWindow::HandleEvent(nsGUIEvent *aEvent)
|
|||
}
|
||||
|
||||
case NS_GOTFOCUS: {
|
||||
#ifdef DEBUG_saari
|
||||
#if defined(DEBUG_saari) || defined(DEBUG_smaug)
|
||||
printf("nsWebShellWindow::GOTFOCUS\n");
|
||||
#endif
|
||||
gCurrentlyFocusedWindow = eventWindow;
|
||||
if (gFocusSuppressed) {
|
||||
break;
|
||||
}
|
||||
nsCOMPtr<nsIDOMDocument> domDocument;
|
||||
nsCOMPtr<nsPIDOMWindow> piWin = do_GetInterface(docShell);
|
||||
if (!piWin) {
|
||||
|
@ -502,6 +526,15 @@ nsWebShellWindow::HandleEvent(nsGUIEvent *aEvent)
|
|||
}
|
||||
break;
|
||||
}
|
||||
case NS_LOSTFOCUS: {
|
||||
#if defined(DEBUG_saari) || defined(DEBUG_smaug)
|
||||
printf("nsWebShellWindow::LOSTFOCUS\n");
|
||||
#endif
|
||||
if (gCurrentlyFocusedWindow == eventWindow) {
|
||||
gCurrentlyFocusedWindow = nsnull;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
|
||||
|
@ -840,3 +873,43 @@ NS_IMETHODIMP nsWebShellWindow::Destroy()
|
|||
return nsXULWindow::Destroy();
|
||||
}
|
||||
|
||||
void
|
||||
nsWebShellWindow::SuppressFocusEvents(PRBool aSuppress)
|
||||
{
|
||||
if (aSuppress) {
|
||||
gFocusSuppressed = PR_TRUE;
|
||||
gFocusedWindowBeforeSuppression = gCurrentlyFocusedWindow;
|
||||
return;
|
||||
}
|
||||
|
||||
gFocusSuppressed = PR_FALSE;
|
||||
if (gFocusedWindowBeforeSuppression == gCurrentlyFocusedWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Backup what is focused before we send the blur. If the
|
||||
// blur causes a focus change, keep that new focus change,
|
||||
// don't overwrite with the old "currently focused window".
|
||||
nsWebShellWindow* currentFocusBeforeBlur = gCurrentlyFocusedWindow;
|
||||
|
||||
if (gFocusedWindowBeforeSuppression) {
|
||||
nsCOMPtr<nsIWidget> widget = gFocusedWindowBeforeSuppression->mWindow;
|
||||
if (widget) {
|
||||
nsRefPtr<nsWebShellWindow> window = gFocusedWindowBeforeSuppression;
|
||||
nsGUIEvent lostfocus(PR_TRUE, NS_LOSTFOCUS, widget);
|
||||
window->HandleEvent(&lostfocus);
|
||||
}
|
||||
}
|
||||
|
||||
// Send NS_GOTFOCUS to the widget that we think should be focused.
|
||||
if (gCurrentlyFocusedWindow &&
|
||||
gCurrentlyFocusedWindow == currentFocusBeforeBlur) {
|
||||
nsCOMPtr<nsIWidget> widget = gCurrentlyFocusedWindow->mWindow;
|
||||
if (widget) {
|
||||
nsRefPtr<nsWebShellWindow> window = gCurrentlyFocusedWindow;
|
||||
nsGUIEvent gotfocus(PR_TRUE, NS_GOTFOCUS, widget);
|
||||
window->HandleEvent(&gotfocus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -76,6 +76,7 @@ public:
|
|||
// nsIBaseWindow
|
||||
NS_IMETHOD Destroy();
|
||||
|
||||
static void SuppressFocusEvents(PRBool aSuppress);
|
||||
protected:
|
||||
|
||||
virtual ~nsWebShellWindow();
|
||||
|
|
Загрузка…
Ссылка в новой задаче