Bug 141295 and 153681 - fix some timing problems with initial focus. Make sure that window watcher's activeWindow accurately reflects the last window to receive an NS_ACTIVATE. Remove the GetFocusController API from nsIDocument, since the focus controller can now be obtained for the entire lifetime of the document by using GetContainer(). Cleaned up some methods on nsEventStateManager/nsIEventStateManager that were virtual for no reason. r=danm, sr=jst.

This commit is contained in:
bryner%netscape.com 2002-09-06 00:19:58 +00:00
parent a017e8a053
commit 11659c8e1c
14 changed files with 155 additions and 135 deletions

View File

@ -80,7 +80,6 @@ class nsIObserver;
class nsISupportsArray;
class nsIScriptLoader;
class nsString;
class nsIFocusController;
class nsIContentSink;
// IID for the nsIDocument interface
@ -302,14 +301,6 @@ public:
*/
NS_IMETHOD GetScriptLoader(nsIScriptLoader** aScriptLoader) = 0;
/**
* Get the focus controller for this document
* This can usually be gotten through the ScriptGlobalObject, but
* it is set to null during document destruction, when we still might
* need to fire focus events.
*/
NS_IMETHOD GetFocusController(nsIFocusController** aFocusController) = 0;
//----------------------------------------------------------------------
// Document notification API's

View File

@ -119,7 +119,6 @@
#include "nsIDOMWindowInternal.h"
#include "nsPIDOMWindow.h"
#include "nsIFocusController.h"
#include "nsIDOMElement.h"
#include "nsIBoxObject.h"
@ -1724,6 +1723,16 @@ nsDocument::GetScriptGlobalObject(nsIScriptGlobalObject** aScriptGlobalObject)
{
NS_ENSURE_ARG_POINTER(aScriptGlobalObject);
// If we're going away, we've already released the reference to our
// ScriptGlobalObject. We can, however, try to obtain it for the
// caller through our docshell.
if (mIsGoingAway) {
nsCOMPtr<nsIInterfaceRequestor> requestor = do_QueryReferent(mDocumentContainer);
if (requestor)
return CallGetInterface(requestor.get(), aScriptGlobalObject);
}
*aScriptGlobalObject = mScriptGlobalObject;
NS_IF_ADDREF(*aScriptGlobalObject);
return NS_OK;
@ -1770,31 +1779,12 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
#endif
mContentWrapperHash.Reset();
} else if (aScriptGlobalObject != mScriptGlobalObject) {
// Update our weak ref to the focus controller
nsCOMPtr<nsPIDOMWindow> domPrivate = do_QueryInterface(aScriptGlobalObject);
if (domPrivate) {
nsCOMPtr<nsIFocusController> fc;
domPrivate->GetRootFocusController(getter_AddRefs(fc));
mFocusController = getter_AddRefs(NS_GetWeakReference(fc));
}
}
mScriptGlobalObject = aScriptGlobalObject;
return NS_OK;
}
NS_IMETHODIMP
nsDocument::GetFocusController(nsIFocusController** aFocusController)
{
NS_ENSURE_ARG_POINTER(aFocusController);
nsCOMPtr<nsIFocusController> fc = do_QueryReferent(mFocusController);
*aFocusController = fc;
NS_IF_ADDREF(*aFocusController);
return NS_OK;
}
NS_IMETHODIMP
nsDocument::GetNameSpaceManager(nsINameSpaceManager*& aManager)
{

View File

@ -457,14 +457,6 @@ public:
*/
NS_IMETHOD GetScriptLoader(nsIScriptLoader** aScriptLoader);
/**
* Get the focus controller for this document
* This can usually be gotten through the ScriptGlobalObject, but
* it is set to null during document destruction, when we still might
* need to fire focus events.
*/
NS_IMETHOD GetFocusController(nsIFocusController** aFocusController);
/**
* Add a new observer of document change notifications. Whenever
* content is changed, appended, inserted or removed the observers are
@ -678,7 +670,6 @@ protected:
nsSupportsHashtable mContentWrapperHash;
nsCOMPtr<nsICSSLoader> mCSSLoader;
nsWeakPtr mFocusController;
nsString mContentLanguage;
nsString mContentType;

View File

@ -101,9 +101,6 @@ public:
NS_IMETHOD MoveFocusToCaret(PRBool aCanFocusDoc, PRBool *aIsSelectionWithFocus) = 0;
NS_IMETHOD MoveCaretToFocus() = 0;
NS_IMETHOD GetNextTabbableContent(nsIContent* aRootContent, nsIFrame* aFrame,
PRBool forward, PRBool aIgnoreTabIndex, nsIContent** aResult) = 0;
// This is an experiment and may be temporary
NS_IMETHOD ConsumeFocusEvents(PRBool aDoConsume) = 0;

View File

@ -730,8 +730,7 @@ nsEventStateManager::PreHandleEvent(nsIPresContext* aPresContext,
// de-activation. This will cause it to remember the last
// focused sub-window and sub-element for this top-level
// window.
nsCOMPtr<nsIFocusController> focusController;
mDocument->GetFocusController(getter_AddRefs(focusController));
nsCOMPtr<nsIFocusController> focusController = getter_AddRefs(GetFocusControllerForDocument(mDocument));
if (focusController) {
// Suppress the command dispatcher.
focusController->SetSuppressFocus(PR_TRUE, "Deactivate Suppression");
@ -782,8 +781,7 @@ nsEventStateManager::PreHandleEvent(nsIPresContext* aPresContext,
// the window, but we still need to tell the focus controller
// that it isn't active.
nsCOMPtr<nsIFocusController> fc;
gLastFocusedDocument->GetFocusController(getter_AddRefs(fc));
nsCOMPtr<nsIFocusController> fc = getter_AddRefs(GetFocusControllerForDocument(gLastFocusedDocument));
if (fc)
fc->SetActive(PR_FALSE);
}
@ -2733,7 +2731,7 @@ nsEventStateManager::GenerateDragDropEnterExit(nsIPresContext* aPresContext, nsG
FlushPendingEvents(aPresContext);
}
NS_IMETHODIMP
nsresult
nsEventStateManager::SetClickCount(nsIPresContext* aPresContext,
nsMouseEvent *aEvent,
nsEventStatus* aStatus)
@ -2799,7 +2797,7 @@ nsEventStateManager::SetClickCount(nsIPresContext* aPresContext,
return ret;
}
NS_IMETHODIMP
nsresult
nsEventStateManager::CheckForAndDispatchClick(nsIPresContext* aPresContext,
nsMouseEvent *aEvent,
nsEventStatus* aStatus)
@ -3243,7 +3241,7 @@ void nsEventStateManager::TabIndexFrom(nsIContent *aFrom, PRInt32 *aOutIndex)
}
NS_IMETHODIMP
nsresult
nsEventStateManager::GetNextTabbableContent(nsIContent* aRootContent, nsIFrame* aFrame, PRBool forward, PRBool aIgnoreTabIndex,
nsIContent** aResult)
{
@ -3949,7 +3947,7 @@ nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState)
return NS_OK;
}
NS_IMETHODIMP
nsresult
nsEventStateManager::SendFocusBlur(nsIPresContext* aPresContext, nsIContent *aContent, PRBool aEnsureWindowHasFocus)
{
nsCOMPtr<nsIPresShell> presShell;
@ -5193,3 +5191,18 @@ nsEventStateManager::ShiftFocusByDoc(PRBool aForward)
}
}
// Get the FocusController given an nsIDocument
nsIFocusController*
nsEventStateManager::GetFocusControllerForDocument(nsIDocument* aDocument)
{
nsCOMPtr<nsISupports> container;
aDocument->GetContainer(getter_AddRefs(container));
nsCOMPtr<nsPIDOMWindow> windowPrivate = do_GetInterface(container);
nsIFocusController* fc;
if (windowPrivate)
windowPrivate->GetRootFocusController(&fc);
else
fc = nsnull;
return fc;
}

View File

@ -55,6 +55,7 @@ class nsIFrameSelection;
class nsIDocShell;
class nsIDocShellTreeNode;
class nsIDocShellTreeItem;
class nsIFocusController;
// mac uses click-hold context menus, a holdover from 4.x
#if defined(XP_MAC) || defined(XP_MACOSX)
@ -142,18 +143,19 @@ protected:
void UpdateCursor(nsIPresContext* aPresContext, nsEvent* aEvent, nsIFrame* aTargetFrame, nsEventStatus* aStatus);
void GenerateMouseEnterExit(nsIPresContext* aPresContext, nsGUIEvent* aEvent);
void GenerateDragDropEnterExit(nsIPresContext* aPresContext, nsGUIEvent* aEvent);
NS_IMETHOD SetClickCount(nsIPresContext* aPresContext, nsMouseEvent *aEvent, nsEventStatus* aStatus);
NS_IMETHOD CheckForAndDispatchClick(nsIPresContext* aPresContext, nsMouseEvent *aEvent, nsEventStatus* aStatus);
nsresult SetClickCount(nsIPresContext* aPresContext, nsMouseEvent *aEvent, nsEventStatus* aStatus);
nsresult CheckForAndDispatchClick(nsIPresContext* aPresContext, nsMouseEvent *aEvent, nsEventStatus* aStatus);
PRBool ChangeFocus(nsIContent* aFocus, PRInt32 aFocusedWith);
NS_IMETHOD GetNextTabbableContent(nsIContent* aRootContent, nsIFrame* aFrame, PRBool forward, PRBool ignoreTabIndex, nsIContent** aResult);
nsresult GetNextTabbableContent(nsIContent* aRootContent, nsIFrame* aFrame, PRBool forward, PRBool ignoreTabIndex, nsIContent** aResult);
void TabIndexFrom(nsIContent *aFrom, PRInt32 *aOutIndex);
PRInt32 GetNextTabIndex(nsIContent* aParent, PRBool foward);
NS_IMETHOD SendFocusBlur(nsIPresContext* aPresContext, nsIContent *aContent, PRBool aEnsureWindowHasFocus);
nsresult SendFocusBlur(nsIPresContext* aPresContext, nsIContent *aContent, PRBool aEnsureWindowHasFocus);
PRBool CheckDisabled(nsIContent* aContent);
void EnsureDocument(nsIPresShell* aPresShell);
void EnsureDocument(nsIPresContext* aPresContext);
void FlushPendingEvents(nsIPresContext* aPresContext);
nsIFocusController* GetFocusControllerForDocument(nsIDocument* aDocument);
typedef enum {
eAccessKeyProcessingNormal = 0,

View File

@ -160,6 +160,7 @@
#include "nsIObjectInputStream.h"
#include "nsIObjectOutputStream.h"
#include "nsIPref.h"
#include "nsIFocusController.h"
//----------------------------------------------------------------------
@ -1643,31 +1644,12 @@ nsXULDocument::SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject)
#endif
mContentWrapperHash.Reset();
} else if (mScriptGlobalObject != aScriptGlobalObject) {
// Update our weak ref to the focus controller
nsCOMPtr<nsPIDOMWindow> domPrivate = do_QueryInterface(aScriptGlobalObject);
if (domPrivate) {
nsCOMPtr<nsIFocusController> fc;
domPrivate->GetRootFocusController(getter_AddRefs(fc));
mFocusController = getter_AddRefs(NS_GetWeakReference(fc));
}
}
mScriptGlobalObject = aScriptGlobalObject;
return NS_OK;
}
NS_IMETHODIMP
nsXULDocument::GetFocusController(nsIFocusController** aFocusController)
{
NS_ENSURE_ARG_POINTER(aFocusController);
nsCOMPtr<nsIFocusController> fc = do_QueryReferent(mFocusController);
*aFocusController = fc;
NS_IF_ADDREF(*aFocusController);
return NS_OK;
}
NS_IMETHODIMP
nsXULDocument::GetNameSpaceManager(nsINameSpaceManager*& aManager)
{
@ -3630,8 +3612,7 @@ nsXULDocument::GetPopupNode(nsIDOMNode** aNode)
// get focus controller
nsCOMPtr<nsIFocusController> focusController;
rv = GetFocusController(getter_AddRefs(focusController));
NS_ENSURE_SUCCESS(rv, rv);
GetFocusController(getter_AddRefs(focusController));
NS_ENSURE_TRUE(focusController, NS_ERROR_FAILURE);
// get popup node
rv = focusController->GetPopupNode(aNode); // addref happens here
@ -3646,8 +3627,7 @@ nsXULDocument::SetPopupNode(nsIDOMNode* aNode)
// get focus controller
nsCOMPtr<nsIFocusController> focusController;
rv = GetFocusController(getter_AddRefs(focusController));
NS_ENSURE_SUCCESS(rv, rv);
GetFocusController(getter_AddRefs(focusController));
NS_ENSURE_TRUE(focusController, NS_ERROR_FAILURE);
// set popup node
rv = focusController->SetPopupNode(aNode);
@ -7081,6 +7061,18 @@ nsXULDocument::ParserObserver::OnStopRequest(nsIRequest *request,
return rv;
}
void
nsXULDocument::GetFocusController(nsIFocusController** aFocusController)
{
nsCOMPtr<nsIInterfaceRequestor> ir = do_QueryReferent(mDocumentContainer);
nsCOMPtr<nsPIDOMWindow> windowPrivate = do_GetInterface(ir);
if (windowPrivate) {
windowPrivate->GetRootFocusController(aFocusController);
NS_IF_ADDREF(*aFocusController);
} else
*aFocusController = nsnull;
}
#ifdef IBMBIDI
/**
* Retrieve and get bidi state of the document

View File

@ -84,7 +84,6 @@
#include "nsIBindingManager.h"
#include "nsINodeInfo.h"
#include "nsIDOMDocumentEvent.h"
#include "nsIFocusController.h"
#include "nsScriptLoader.h"
#include "pldhash.h"
@ -97,6 +96,7 @@ class nsIRDFService;
class nsITimer;
class nsIXULContentUtils;
class nsIXULPrototypeCache;
class nsIFocusController;
#if 0 // XXXbe save me, scc (need NSCAP_FORWARD_DECL(nsXULPrototypeScript))
class nsIObjectInputStream;
class nsIObjectOutputStream;
@ -262,8 +262,6 @@ public:
NS_IMETHOD GetScriptLoader(nsIScriptLoader** aScriptLoader);
NS_IMETHOD GetFocusController(nsIFocusController** aFocusController);
virtual void AddObserver(nsIDocumentObserver* aObserver);
virtual PRBool RemoveObserver(nsIDocumentObserver* aObserver);
@ -497,6 +495,8 @@ protected:
nsIDOMElement* aListener,
nsIAtom* aAttr);
void GetFocusController(nsIFocusController** aFocusController);
protected:
// pseudo constants
static PRInt32 gRefCnt;
@ -612,8 +612,6 @@ protected:
nsCOMPtr<nsIDOMNode> mTooltipNode; // [OWNER] element triggering the tooltip
nsCOMPtr<nsINodeInfoManager> mNodeInfoManager; // [OWNER] list of names in the document
nsWeakPtr mFocusController;
/**
* Context stack, which maintains the state of the Builder and allows
* it to be interrupted.

View File

@ -308,6 +308,13 @@ NS_IMETHODIMP nsDocShell::GetInterface(const nsIID & aIID, void **aSink)
aSink), NS_ERROR_FAILURE);
return NS_OK;
}
else if (aIID.Equals(NS_GET_IID(nsPIDOMWindow)) &&
NS_SUCCEEDED(EnsureScriptEnvironment())) {
NS_ENSURE_SUCCESS(mScriptGlobal->
QueryInterface(NS_GET_IID(nsPIDOMWindow), aSink),
NS_ERROR_FAILURE);
return NS_OK;
}
else if (aIID.Equals(NS_GET_IID(nsIDOMWindow)) &&
NS_SUCCEEDED(EnsureScriptEnvironment())) {
NS_ENSURE_SUCCESS(mScriptGlobal->

View File

@ -42,6 +42,11 @@
#include "nsIEventStateManager.h"
#include "nsIDocShell.h"
#include "nsIBaseWindow.h"
#include "nsIWindowWatcher.h"
#include "nsIDocShellTreeItem.h"
#include "nsIDocShellTreeOwner.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIServiceManagerUtils.h"
#ifdef INCLUDE_XUL
#include "nsIDOMXULDocument.h"
@ -53,7 +58,8 @@
nsFocusController::nsFocusController(void)
: mSuppressFocus(0),
mSuppressFocusScroll(PR_FALSE),
mActive(PR_FALSE)
mActive(PR_FALSE),
mUpdateWindowWatcher(PR_FALSE)
{
NS_INIT_REFCNT();
}
@ -138,6 +144,14 @@ nsFocusController::SetFocusedWindow(nsIDOMWindowInternal* aWindow)
else if (aWindow) mPreviousWindow = aWindow;
mCurrentWindow = aWindow;
if (mUpdateWindowWatcher) {
NS_ASSERTION(mActive, "This shouldn't happen");
if (mCurrentWindow)
UpdateWWActiveWindow();
mUpdateWindowWatcher = PR_FALSE;
}
return NS_OK;
}
@ -467,9 +481,43 @@ NS_IMETHODIMP
nsFocusController::SetActive(PRBool aActive)
{
mActive = aActive;
// We may be activated before we ever have a focused window set.
// This happens on window creation, where the FocusController
// is activated just prior to setting the focused window.
// (see nsEventStateManager::PreHandleEvent/NS_ACTIVATE)
// If this is the case, we need to queue a notification of the
// WindowWatcher until SetFocusedWindow is called.
if (mCurrentWindow)
UpdateWWActiveWindow();
else
mUpdateWindowWatcher = PR_TRUE;
return NS_OK;
}
void
nsFocusController::UpdateWWActiveWindow()
{
// Inform the window watcher of the new active window.
nsCOMPtr<nsIWindowWatcher> wwatch = do_GetService("@mozilla.org/embedcomp/window-watcher;1");
if (!wwatch) return;
// This gets the toplevel DOMWindow
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(mCurrentWindow);
nsCOMPtr<nsIDocShell> docShell;
sgo->GetDocShell(getter_AddRefs(docShell));
if (!docShell) return;
nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(docShell));
nsCOMPtr<nsIDocShellTreeItem> rootItem;
docShellAsItem->GetRootTreeItem(getter_AddRefs(rootItem));
NS_ASSERTION(rootItem, "Invalid docshell tree - no root!");
nsCOMPtr<nsIDOMWindow> domWin = do_GetInterface(rootItem);
wwatch->SetActiveWindow(domWin);
}
NS_IMETHODIMP
nsFocusController::GetPopupNode(nsIDOMNode** aNode)
{

View File

@ -83,6 +83,7 @@ public:
protected:
NS_IMETHOD UpdateCommands(const nsAString& aEventName);
void UpdateWWActiveWindow();
public:
static nsresult GetParentWindowFromDocument(nsIDOMDocument* aElement, nsIDOMWindowInternal** aWindow);
@ -96,8 +97,9 @@ protected:
nsCOMPtr<nsIDOMNode> mPopupNode; // [OWNER]
PRUint32 mSuppressFocus;
PRBool mSuppressFocusScroll;
PRBool mActive;
PRPackedBool mSuppressFocusScroll;
PRPackedBool mActive;
PRPackedBool mUpdateWindowWatcher;
};
#endif // nsFocusController_h__

View File

@ -63,6 +63,8 @@
#include "nsIFocusController.h"
#include "nsIDOMWindowInternal.h"
#include "nsIDOMDocument.h"
#include "nsPIDOMWindow.h"
#include "nsIInterfaceRequestorUtils.h"
#ifdef XP_WIN
#include "nsISound.h"
#include "nsWidgetsCID.h"
@ -201,38 +203,52 @@ nsMenuBarFrame::SetActive(PRBool aActiveFlag)
// We don't want the caret to blink while the menus are active
// The caret distracts screen readers and other assistive technologies from the menu selection
// There is 1 caret per document, we need to find the focused document and toggle its caret
nsCOMPtr<nsIDocument> document;
nsCOMPtr<nsIFocusController> focusController;
nsCOMPtr<nsIPresShell> presShell;
mPresContext->GetShell(getter_AddRefs(presShell));
if (presShell) {
do {
nsCOMPtr<nsIPresShell> presShell;
mPresContext->GetShell(getter_AddRefs(presShell));
if (!presShell)
break;
nsCOMPtr<nsIDocument> document;
presShell->GetDocument(getter_AddRefs(document));
if (document)
document->GetFocusController(getter_AddRefs(focusController));
}
nsCOMPtr<nsIDOMWindow> window;
if (focusController) {
if (!document)
break;
nsCOMPtr<nsISupports> container;
document->GetContainer(getter_AddRefs(container));
nsCOMPtr<nsPIDOMWindow> windowPrivate = do_GetInterface(container);
if (!windowPrivate)
break;
nsCOMPtr<nsIFocusController> focusController;
windowPrivate->GetRootFocusController(getter_AddRefs(focusController));
if (!focusController)
break;
nsCOMPtr<nsIDOMWindowInternal> windowInternal;
focusController->GetFocusedWindow(getter_AddRefs(windowInternal));
window = do_QueryInterface(windowInternal);
}
nsCOMPtr<nsICaret> caret;
if (window) {
if (!windowInternal)
break;
nsCOMPtr<nsIDOMDocument> domDoc;
window->GetDocument(getter_AddRefs(domDoc));
windowInternal->GetDocument(getter_AddRefs(domDoc));
document = do_QueryInterface(domDoc);
if (document) {
document->GetShellAt(0, getter_AddRefs(presShell));
if (presShell)
presShell->GetCaret(getter_AddRefs(caret));
}
}
if (caret) {
if (mIsActive) // store whether caret was visible so that we can restore that state when menu is closed
if (!document)
break;
document->GetShellAt(0, getter_AddRefs(presShell));
if (!presShell)
break;
nsCOMPtr<nsICaret> caret;
presShell->GetCaret(getter_AddRefs(caret));
if (!caret)
break;
if (mIsActive) // store whether caret was visible so that we can restore that state when menu is closed
caret->GetCaretVisible(&mCaretWasVisible);
if (mCaretWasVisible)
caret->SetCaretVisible(!mIsActive);
}
} while (0);
NS_NAMED_LITERAL_STRING(active, "DOMMenuBarActive");
NS_NAMED_LITERAL_STRING(inactive, "DOMMenuBarInactive");

View File

@ -204,18 +204,6 @@ nsWindowMediator::UnregisterWindow(nsWindowInfo *inInfo)
mTopmostWindow = 0;
delete inInfo;
// inform WindowWatcher
nsWindowInfo *info = MostRecentWindowInfo(0);
nsCOMPtr<nsIDOMWindow> domWindow;
if (info && info->mWindow) {
nsCOMPtr<nsIDOMWindowInternal> idomWindow;
GetDOMWindow(info->mWindow, idomWindow);
domWindow = do_QueryInterface(idomWindow);
}
// failure or no more windows sets it to 0, which is acceptable
mWatcher->SetActiveWindow(domWindow);
return NS_OK;
}
@ -387,15 +375,6 @@ nsWindowMediator::UpdateWindowTimeStamp( nsIXULWindow* inWindow)
if (info->mWindow.get() == inWindow) {
// increment the window's time stamp
info->mTimeStamp = ++mTimeStamp;
// inform WindowWatcher
nsCOMPtr<nsIDOMWindowInternal> idomwindow;
GetDOMWindow(info->mWindow, idomwindow);
nsCOMPtr<nsIDOMWindow> domwindow(do_QueryInterface(idomwindow));
// if for some reason anything failed, it'll be set to 0, which is
// better than an invalid pointer.
mWatcher->SetActiveWindow(domwindow);
return NS_OK;
}
info = info->mYounger;
@ -670,10 +649,6 @@ nsWindowMediator::Init()
return NS_ERROR_OUT_OF_MEMORY;
}
mWatcher = do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
if (NS_FAILED(rv))
return rv;
return NS_OK;
}

View File

@ -40,7 +40,6 @@
#include "nsCOMPtr.h"
#include "nsIWindowMediator.h"
#include "nsIWindowWatcher.h"
#include "nsISupportsArray.h"
#include "nsVoidArray.h"
#include "nsXPIDLString.h"
@ -90,7 +89,6 @@ private:
PRInt32 mTimeStamp;
PRInt32 mUpdateBatchNest;
PRLock *mListLock;
nsCOMPtr<nsIWindowWatcher> mWatcher;
nsCOMPtr<nsISupportsArray> mListeners;
static PRInt32 gRefCnt;