Bug 421209, r=cpearce, sr=jst, a=beltzner

This commit is contained in:
Olli.Pettay@helsinki.fi 2008-03-20 13:24:36 -07:00
Родитель 3882c23eb0
Коммит 758c9b0305
14 изменённых файлов: 354 добавлений и 89 удалений

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

@ -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();