gecko-dev/xpfe/appshell/src/nsXULWindow.cpp

1293 lines
37 KiB
C++
Raw Normal View History

/* -*- Mode: C++; tab-width: 3; 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
* 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 the Mozilla browser.
*
* The Initial Developer of the Original Code is Netscape
* Communications, Inc. Portions created by Netscape are
* Copyright (C) 1999, Mozilla. All Rights Reserved.
*
* Contributor(s):
* Travis Bogard <travis@netscape.com>
*/
// Local includes
#include "nsXULWindow.h"
// Helper classes
#include "nsAppShellCIDs.h"
#include "nsString.h"
#include "nsWidgetsCID.h"
#include "prprf.h"
//Interfaces needed to be included
#include "nsIAppShell.h"
#include "nsIAppShellService.h"
#include "nsIServiceManager.h"
#include "nsIDocumentViewer.h"
#include "nsIDocument.h"
#include "nsIDOMDocument.h"
#include "nsIDOMElement.h"
#include "nsIDOMWindow.h"
#include "nsIDOMXULDocument.h"
#include "nsIInterfaceRequestor.h"
#include "nsIIOService.h"
#include "nsIJSContextStack.h"
#include "nsIMarkupDocumentViewer.h"
#include "nsIObserverService.h"
#include "nsIWindowMediator.h"
// XXX Get rid of this
#pragma message("WARNING: XXX bad include, remove it.")
#include "nsIWebShellWindow.h"
2000-04-01 22:13:46 +00:00
#include "nsWebShellWindow.h" // get rid of this one, too...
// CIDs
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
static NS_DEFINE_CID(kAppShellServiceCID, NS_APPSHELL_SERVICE_CID);
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
static NS_DEFINE_CID(kWindowMediatorCID, NS_WINDOWMEDIATOR_CID);
//*****************************************************************************
//*** nsXULWindow: Object Management
//*****************************************************************************
nsXULWindow::nsXULWindow() : mChromeTreeOwner(nsnull),
mContentTreeOwner(nsnull), mPrimaryContentTreeOwner(nsnull),
mContinueModalLoop(PR_FALSE), mChromeLoaded(PR_FALSE),
2000-04-01 22:13:46 +00:00
mShowAfterLoad(PR_FALSE), mIntrinsicallySized(PR_FALSE),
mZlevel(nsIXULWindow::normalZ)
{
NS_INIT_REFCNT();
}
nsXULWindow::~nsXULWindow()
{
Destroy();
}
//*****************************************************************************
// nsXULWindow::nsISupports
//*****************************************************************************
NS_IMPL_ADDREF(nsXULWindow)
NS_IMPL_RELEASE(nsXULWindow)
NS_INTERFACE_MAP_BEGIN(nsXULWindow)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULWindow)
NS_INTERFACE_MAP_ENTRY(nsIXULWindow)
NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
NS_INTERFACE_MAP_END
//*****************************************************************************
// nsXULWindow::nsIIntefaceRequestor
//*****************************************************************************
NS_IMETHODIMP nsXULWindow::GetInterface(const nsIID& aIID, void** aSink)
{
NS_ENSURE_ARG_POINTER(aSink);
if(aIID.Equals(NS_GET_IID(nsIWebBrowserChrome)) &&
NS_SUCCEEDED(EnsureContentTreeOwner()) &&
NS_SUCCEEDED(mContentTreeOwner->QueryInterface(aIID, aSink)))
return NS_OK;
else
return QueryInterface(aIID, aSink);
NS_IF_ADDREF(((nsISupports*)*aSink));
return NS_OK;
}
//*****************************************************************************
// nsXULWindow::nsIXULWindow
//*****************************************************************************
NS_IMETHODIMP nsXULWindow::GetDocShell(nsIDocShell** aDocShell)
{
NS_ENSURE_ARG_POINTER(aDocShell);
*aDocShell = mDocShell;
NS_IF_ADDREF(*aDocShell);
return NS_OK;
}
2000-04-01 22:13:46 +00:00
NS_IMETHODIMP nsXULWindow::GetZlevel(PRUint32 *outLevel)
{
// report our known zlevel, or be on top if currently modal
*outLevel = mContinueModalLoop ? nsIXULWindow::highestZ : mZlevel;
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::SetIntrinsicallySized(PRBool aIntrinsicallySized)
{
mIntrinsicallySized = aIntrinsicallySized;
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::GetIntrinsicallySized(PRBool* aIntrinsicallySized)
{
NS_ENSURE_ARG_POINTER(aIntrinsicallySized);
*aIntrinsicallySized = mIntrinsicallySized;
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::GetPrimaryContentShell(nsIDocShellTreeItem**
aDocShellTreeItem)
{
NS_ENSURE_ARG_POINTER(aDocShellTreeItem);
*aDocShellTreeItem = nsnull;
PRInt32 count = mContentShells.Count();
for(PRInt32 i = 0; i < count; i++)
{
nsContentShellInfo* shellInfo = (nsContentShellInfo*)mContentShells.ElementAt(i);
if(shellInfo->primary)
{
*aDocShellTreeItem = shellInfo->child;
NS_ADDREF(*aDocShellTreeItem);
return NS_OK;
}
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsXULWindow::GetContentShellById(const PRUnichar* aID,
nsIDocShellTreeItem** aDocShellTreeItem)
{
NS_ENSURE_ARG_POINTER(aDocShellTreeItem);
*aDocShellTreeItem = nsnull;
PRInt32 count = mContentShells.Count();
for(PRInt32 i = 0; i < count; i++)
{
nsContentShellInfo* shellInfo = (nsContentShellInfo*)mContentShells.ElementAt(i);
if(shellInfo->id == aID)
{
*aDocShellTreeItem = shellInfo->child;
NS_ADDREF(*aDocShellTreeItem);
return NS_OK;
}
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsXULWindow::SetPersistence(PRBool aPersistX, PRBool aPersistY,
PRBool aPersistCX, PRBool aPersistCY,
PRBool aPersistSizeMode)
{
nsCOMPtr<nsIDOMElement> docShellElement;
GetWindowDOMElement(getter_AddRefs(docShellElement));
if(!docShellElement)
return NS_ERROR_FAILURE;
nsAutoString persistString;
docShellElement->GetAttribute("persist", persistString);
PRBool saveString = PR_FALSE;
PRInt32 index;
// Set X
index = persistString.Find("screenX");
if(!aPersistX && (index >= 0))
{
persistString.Cut(index, 7);
saveString = PR_TRUE;
}
else if(aPersistX && (index < 0 ))
{
persistString.Append(" screenX");
saveString = PR_TRUE;
}
// Set Y
index = persistString.Find("screenY");
if(!aPersistY && (index >= 0))
{
persistString.Cut(index, 7);
saveString = PR_TRUE;
}
else if(aPersistY && (index < 0 ))
{
persistString.Append(" screenY");
saveString = PR_TRUE;
}
// Set CX
index = persistString.Find("width");
if(!aPersistCX && (index >= 0))
{
persistString.Cut(index, 5);
saveString = PR_TRUE;
}
else if(aPersistCX && (index < 0 ))
{
persistString.Append(" width");
saveString = PR_TRUE;
}
// Set CY
index = persistString.Find("height");
if(!aPersistCY && (index >= 0))
{
persistString.Cut(index, 6);
saveString = PR_TRUE;
}
else if(aPersistCY && (index < 0 ))
{
persistString.Append(" height");
saveString = PR_TRUE;
}
index = persistString.Find("sizemode");
if (!aPersistSizeMode && index >= 0) {
persistString.Append(" sizemode");
saveString = PR_TRUE;
} else if (aPersistSizeMode && index < 0) {
persistString.Cut(index, 8);
saveString = PR_TRUE;
}
if(saveString)
docShellElement->SetAttribute("persist", persistString);
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::GetPersistence(PRBool* aPersistX, PRBool* aPersistY,
PRBool* aPersistCX, PRBool* aPersistCY,
PRBool* aPersistSizeMode)
{
nsCOMPtr<nsIDOMElement> docShellElement;
GetWindowDOMElement(getter_AddRefs(docShellElement));
if(!docShellElement)
return NS_ERROR_FAILURE;
nsAutoString persistString;
docShellElement->GetAttribute("persist", persistString);
if(aPersistX)
*aPersistX = persistString.Find("screenX") >= 0 ? PR_TRUE : PR_FALSE;
if(aPersistY)
*aPersistY = persistString.Find("screenY") >= 0 ? PR_TRUE : PR_FALSE;
if(aPersistCX)
*aPersistCX = persistString.Find("width") >= 0 ? PR_TRUE : PR_FALSE;
if(aPersistCY)
*aPersistCY = persistString.Find("height") >= 0 ? PR_TRUE : PR_FALSE;
if(aPersistSizeMode)
*aPersistSizeMode = persistString.Find("sizemode") >= 0 ? PR_TRUE : PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::ShowModal()
{
nsCOMPtr<nsIAppShell> appShell(do_CreateInstance(kAppShellCID));
NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE);
appShell->Create(0, nsnull);
appShell->Spinup();
// Store locally so it doesn't die on us
nsCOMPtr<nsIWidget> window = mWindow;
nsCOMPtr<nsIXULWindow> tempRef = this;
window->SetModal(PR_TRUE);
mContinueModalLoop = PR_TRUE;
EnableParent(PR_FALSE);
nsCOMPtr<nsIJSContextStack> stack(do_GetService("nsThreadJSContextStack"));
nsresult rv = NS_OK;
if(stack && NS_SUCCEEDED(stack->Push(nsnull)))
{
while(NS_SUCCEEDED(rv) && mContinueModalLoop)
{
void* data;
PRBool isRealEvent;
PRBool processEvent;
rv = appShell->GetNativeEvent(isRealEvent, data);
if(NS_SUCCEEDED(rv))
{
window->ModalEventFilter(isRealEvent, data, &processEvent);
if(processEvent)
appShell->DispatchNativeEvent(isRealEvent, data);
}
}
JSContext* cx;
stack->Pop(&cx);
NS_ASSERTION(cx == nsnull, "JSContextStack mismatch");
}
else
rv = NS_ERROR_FAILURE;
mContinueModalLoop = PR_FALSE;
window->SetModal(PR_FALSE);
appShell->Spindown();
return NS_OK;
}
//*****************************************************************************
// nsXULWindow::nsIBaseWindow
//*****************************************************************************
NS_IMETHODIMP nsXULWindow::InitWindow(nativeWindow aParentNativeWindow,
nsIWidget* parentWidget, PRInt32 x, PRInt32 y, PRInt32 cx, PRInt32 cy)
{
//XXX First Check In
NS_ASSERTION(PR_FALSE, "Not Yet Implemented");
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::Create()
{
//XXX First Check In
NS_ASSERTION(PR_FALSE, "Not Yet Implemented");
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::Destroy()
{
if(!mWindow)
return NS_OK;
#ifdef XP_MAC // Anyone still using native menus should add themselves here.
// unregister as document listener
// this is needed for menus
nsCOMPtr<nsIContentViewer> cv;
if(mDocShell)
mDocShell->GetContentViewer(getter_AddRefs(cv));
nsCOMPtr<nsIDocumentViewer> docv(do_QueryInterface(cv));
if(docv)
{
nsCOMPtr<nsIDocument> doc;
docv->GetDocument(*getter_AddRefs(doc));
/* if(doc)
doc->RemoveObserver(NS_STATIC_CAST(nsIDocumentObserver*, this)); */
}
#endif
nsCOMPtr<nsIAppShellService> appShell(do_GetService(kAppShellServiceCID));
if(appShell)
appShell->UnregisterTopLevelWindow(NS_STATIC_CAST(nsIXULWindow*, this));
// let's make sure the window doesn't get deleted out from under us
// while we are trying to close....this can happen if the docshell
// we close ends up being the last owning reference to this xulwindow
// XXXTAB This shouldn't be an issue anymore because the ownership model
// only goes in one direction. When webshell container is fully removed
// try removing this...
nsCOMPtr<nsIXULWindow> placeHolder = this;
// Remove modality (if any) and hide while destroying. More than
// a convenience, the hide prevents user interaction with the partially
// destroyed window. This is especially necessary when the eldest window
// in a stack of modal windows is destroyed first. It happens.
ExitModalLoop();
mWindow->Show(PR_FALSE);
mDOMWindow = nsnull;
if(mDocShell)
{
nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(mDocShell));
shellAsWin->Destroy();
mDocShell = nsnull;
}
// Remove our ref on the content shells
PRInt32 count;
count = mContentShells.Count();
for(PRInt32 i = 0; i < count; i++)
{
nsContentShellInfo* shellInfo = (nsContentShellInfo*)(mContentShells.ElementAt(i));
delete shellInfo;
}
mContentShells.Clear();
if(mContentTreeOwner)
{
mContentTreeOwner->XULWindow(nsnull);
NS_RELEASE(mContentTreeOwner);
}
if(mPrimaryContentTreeOwner)
{
mPrimaryContentTreeOwner->XULWindow(nsnull);
NS_RELEASE(mPrimaryContentTreeOwner);
}
if(mChromeTreeOwner)
{
mChromeTreeOwner->XULWindow(nsnull);
NS_RELEASE(mChromeTreeOwner);
}
2000-04-01 22:13:46 +00:00
mWindow->SetClientData(0); // nsWebShellWindow hackery
mWindow = nsnull;
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::SetPosition(PRInt32 aX, PRInt32 aY)
{
NS_ENSURE_SUCCESS(mWindow->Move(aX, aY), NS_ERROR_FAILURE);
PersistPositionAndSize(PR_TRUE, PR_FALSE, PR_FALSE);
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::GetPosition(PRInt32* aX, PRInt32* aY)
{
return GetPositionAndSize(aX, aY, nsnull, nsnull);
}
NS_IMETHODIMP nsXULWindow::SetSize(PRInt32 aCX, PRInt32 aCY, PRBool aRepaint)
{
mIntrinsicallySized = PR_FALSE;
NS_ENSURE_SUCCESS(mWindow->Resize(aCX, aCY, aRepaint), NS_ERROR_FAILURE);
PersistPositionAndSize(PR_FALSE, PR_TRUE, PR_FALSE);
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::GetSize(PRInt32* aCX, PRInt32* aCY)
{
return GetPositionAndSize(nsnull, nsnull, aCX, aCY);
}
NS_IMETHODIMP nsXULWindow::SetPositionAndSize(PRInt32 aX, PRInt32 aY,
PRInt32 aCX, PRInt32 aCY, PRBool aRepaint)
{
mIntrinsicallySized = PR_FALSE;
NS_ENSURE_SUCCESS(mWindow->Resize(aX, aY, aCX, aCY, aRepaint), NS_ERROR_FAILURE);
PersistPositionAndSize(PR_TRUE, PR_TRUE, PR_FALSE);
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::GetPositionAndSize(PRInt32* x, PRInt32* y, PRInt32* cx,
PRInt32* cy)
{
nsRect rect;
mWindow->GetScreenBounds(rect);
if(x)
*x = rect.x;
if(y)
*y = rect.y;
if(cx)
*cx = rect.width;
if(cy)
*cy = rect.height;
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::Repaint(PRBool aForce)
{
//XXX First Check In
NS_ASSERTION(PR_FALSE, "Not Yet Implemented");
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::GetParentWidget(nsIWidget** aParentWidget)
{
NS_ENSURE_ARG_POINTER(aParentWidget);
NS_ENSURE_STATE(mWindow);
*aParentWidget = mWindow->GetParent();
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::SetParentWidget(nsIWidget* aParentWidget)
{
//XXX First Check In
NS_ASSERTION(PR_FALSE, "Not Yet Implemented");
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::GetParentNativeWindow(nativeWindow* aParentNativeWindow)
{
NS_ENSURE_ARG_POINTER(aParentNativeWindow);
nsCOMPtr<nsIWidget> parentWidget;
NS_ENSURE_SUCCESS(GetParentWidget(getter_AddRefs(parentWidget)), NS_ERROR_FAILURE);
*aParentNativeWindow = parentWidget->GetNativeData(NS_NATIVE_WIDGET);
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::SetParentNativeWindow(nativeWindow aParentNativeWindow)
{
//XXX First Check In
NS_ASSERTION(PR_FALSE, "Not Yet Implemented");
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::GetVisibility(PRBool* aVisibility)
{
NS_ENSURE_ARG_POINTER(aVisibility);
//XXX First Check In
NS_ASSERTION(PR_FALSE, "Not Yet Implemented");
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::SetVisibility(PRBool aVisibility)
{
if(!mChromeLoaded)
{
mShowAfterLoad = aVisibility;
return NS_OK;
}
if(mDebuting)
return NS_OK;
mDebuting = PR_TRUE; // (Show / Focus is recursive)
//XXXTAB Do we really need to show docshell and the window? Isn't
// the window good enough?
nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(mDocShell));
shellAsWin->SetVisibility(aVisibility);
mWindow->Show(aVisibility);
nsCOMPtr<nsIWindowMediator> windowMediator(do_GetService(kWindowMediatorCID));
if(windowMediator)
windowMediator->UpdateWindowTimeStamp(NS_STATIC_CAST(nsIXULWindow*, this));
// Hide splash screen (if there is one).
static PRBool splashScreenGone = PR_FALSE;
if(!splashScreenGone)
{
nsCOMPtr<nsIAppShellService> appShellService(do_GetService(kAppShellServiceCID));
if(appShellService)
appShellService->HideSplashScreen();
splashScreenGone = PR_TRUE;
}
mDebuting = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::GetMainWidget(nsIWidget** aMainWidget)
{
NS_ENSURE_ARG_POINTER(aMainWidget);
*aMainWidget = mWindow;
NS_IF_ADDREF(*aMainWidget);
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::SetFocus()
{
//XXX First Check In
NS_ASSERTION(PR_FALSE, "Not Yet Implemented");
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::FocusAvailable(nsIBaseWindow* aCurrentFocus,
PRBool* aTookFocus)
{
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::GetTitle(PRUnichar** aTitle)
{
NS_ENSURE_ARG_POINTER(aTitle);
//XXX First Check In
NS_ASSERTION(PR_FALSE, "Not Yet Implemented");
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::SetTitle(const PRUnichar* aTitle)
{
NS_ENSURE_STATE(mWindow);
nsAutoString title(aTitle);
NS_ENSURE_SUCCESS(mWindow->SetTitle(title), NS_ERROR_FAILURE);
// Tell the window mediator that a title has changed
nsCOMPtr<nsIWindowMediator> windowMediator(do_GetService(kWindowMediatorCID));
if(!windowMediator)
return NS_OK;
windowMediator->UpdateWindowTitle(NS_STATIC_CAST(nsIXULWindow*, this), aTitle);
return NS_OK;
}
//*****************************************************************************
// nsXULWindow: Helpers
//*****************************************************************************
NS_IMETHODIMP nsXULWindow::EnsureChromeTreeOwner()
{
if(mChromeTreeOwner)
return NS_OK;
mChromeTreeOwner = new nsChromeTreeOwner();
NS_ENSURE_TRUE(mChromeTreeOwner, NS_ERROR_OUT_OF_MEMORY);
NS_ADDREF(mChromeTreeOwner);
mChromeTreeOwner->XULWindow(this);
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::EnsureContentTreeOwner()
{
if(mContentTreeOwner)
return NS_OK;
mContentTreeOwner = new nsContentTreeOwner(PR_FALSE);
NS_ENSURE_TRUE(mContentTreeOwner, NS_ERROR_FAILURE);
NS_ADDREF(mContentTreeOwner);
mContentTreeOwner->XULWindow(this);
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::EnsurePrimaryContentTreeOwner()
{
if(mPrimaryContentTreeOwner)
return NS_OK;
mPrimaryContentTreeOwner = new nsContentTreeOwner(PR_TRUE);
NS_ENSURE_TRUE(mPrimaryContentTreeOwner, NS_ERROR_FAILURE);
NS_ADDREF(mPrimaryContentTreeOwner);
mPrimaryContentTreeOwner->XULWindow(this);
return NS_OK;
}
void nsXULWindow::OnChromeLoaded()
{
mChromeLoaded = PR_TRUE;
if(mContentTreeOwner)
mContentTreeOwner->ApplyChromeMask();
LoadTitleFromXUL();
LoadPositionAndSizeFromXUL(PR_TRUE, PR_TRUE);
if(mIntrinsicallySized)
{
nsCOMPtr<nsIContentViewer> cv;
mDocShell->GetContentViewer(getter_AddRefs(cv));
nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(cv));
if(markupViewer)
markupViewer->SizeToContent();
}
//LoadContentAreas();
if(mShowAfterLoad)
SetVisibility(PR_TRUE);
}
NS_IMETHODIMP nsXULWindow::LoadPositionAndSizeFromXUL(PRBool aPosition,
PRBool aSize)
{
/* NB: we'll want to pay attention to the "sizemode" attribute (maximizing
the window if it asks) someday after the widget implementations know how
to do that.
*/
nsCOMPtr<nsIDOMElement> docShellElement;
GetWindowDOMElement(getter_AddRefs(docShellElement));
NS_ENSURE_TRUE(docShellElement, NS_ERROR_FAILURE);
PRInt32 curX = 0;
PRInt32 curY = 0;
PRInt32 curCX = 0;
PRInt32 curCY = 0;
GetPositionAndSize(&curX, &curY, &curCX, &curCY);
PRInt32 errorCode;
PRInt32 temp;
if(aPosition)
{
PRInt32 specX = curX;
PRInt32 specY = curY;
nsAutoString sizeString;
if(NS_SUCCEEDED(docShellElement->GetAttribute("screenX", sizeString)))
{
temp = sizeString.ToInteger(&errorCode);
if(NS_SUCCEEDED(errorCode) && temp > 0)
specX = temp;
}
if(NS_SUCCEEDED(docShellElement->GetAttribute("screenY", sizeString)))
{
temp = sizeString.ToInteger(&errorCode);
if(NS_SUCCEEDED(errorCode) && temp > 0)
specY = temp;
}
if((specX != curX) || (specY != curY))
SetPosition(specX, specY);
}
if(aSize)
{
PRInt32 specCX = curCX;
PRInt32 specCY = curCY;
nsAutoString sizeString;
if(NS_SUCCEEDED(docShellElement->GetAttribute("width", sizeString)))
{
temp = sizeString.ToInteger(&errorCode);
if(NS_SUCCEEDED(errorCode) && temp > 0)
{
specCX = temp;
mIntrinsicallySized = PR_FALSE;
}
}
if(NS_SUCCEEDED(docShellElement->GetAttribute("height", sizeString)))
{
temp = sizeString.ToInteger(&errorCode);
if(NS_SUCCEEDED(errorCode) && temp > 0)
{
specCY = temp;
mIntrinsicallySized = PR_FALSE;
}
}
if((specCX != curCX) || (specCY != curCY))
SetSize(specCX, specCY, PR_FALSE);
}
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::LoadTitleFromXUL()
{
nsCOMPtr<nsIDOMElement> docShellElement;
GetWindowDOMElement(getter_AddRefs(docShellElement));
NS_ENSURE_TRUE(docShellElement, NS_ERROR_FAILURE);
nsAutoString windowTitle;
docShellElement->GetAttribute("title", windowTitle);
if(windowTitle.IsEmpty())
return NS_OK;
NS_ENSURE_SUCCESS(EnsureChromeTreeOwner(), NS_ERROR_FAILURE);
mChromeTreeOwner->SetTitle(windowTitle.GetUnicode());
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::PersistPositionAndSize(PRBool aPosition, PRBool aSize, PRBool aSizeMode)
{
// can happen when the persistence timer fires at an inopportune time
// during window shutdown
if (!mDocShell)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMElement> docShellElement;
GetWindowDOMElement(getter_AddRefs(docShellElement));
if(!docShellElement)
return NS_ERROR_FAILURE;
PRInt32 x, y, cx, cy;
PRInt32 sizeMode;
NS_ENSURE_SUCCESS(GetPositionAndSize(&x, &y, &cx, &cy), NS_ERROR_FAILURE);
mWindow->GetSizeMode(&sizeMode);
// (But only for size elements which are persisted.)
/* Note we use the same cheesy way to determine that as in
nsXULDocument.cpp. Some day that'll be fixed and there will
be an obscure bug here. */
/* Note that storing sizes which are not persisted makes it
difficult to distinguish between windows intrinsically sized
and not. */
nsAutoString persistString;
docShellElement->GetAttribute("persist", persistString);
char sizeBuf[10];
nsAutoString sizeString;
if(aPosition && sizeMode == nsSizeMode_Normal)
{
if(persistString.Find("screenX") >= 0)
{
PR_snprintf(sizeBuf, sizeof(sizeBuf), "%ld", (long)x);
sizeString = sizeBuf;
docShellElement->SetAttribute("screenX", sizeString);
}
if(persistString.Find("screenY") >= 0)
{
PR_snprintf(sizeBuf, sizeof(sizeBuf), "%ld", (long)y);
sizeString = sizeBuf;
docShellElement->SetAttribute("screenY", sizeString);
}
}
if(aSize && sizeMode == nsSizeMode_Normal)
{
if(persistString.Find("width") >= 0)
{
PR_snprintf(sizeBuf, sizeof(sizeBuf), "%ld", (long)cx);
sizeString = sizeBuf;
docShellElement->SetAttribute("width", sizeString);
}
if(persistString.Find("height") >= 0)
{
PR_snprintf(sizeBuf, sizeof(sizeBuf), "%ld", (long)cy);
sizeString = sizeBuf;
docShellElement->SetAttribute("height", sizeString);
}
}
if (aSizeMode && persistString.Find("sizemode") >= 0) {
PRInt32 sizemode;
if (NS_FAILED(mWindow->GetSizeMode(&sizemode)))
sizemode = nsSizeMode_Normal;
sizeString = "n";
if (sizemode == nsSizeMode_Minimized)
sizeString = "m";
else if (sizemode == nsSizeMode_Maximized)
sizeString = "M";
docShellElement->SetAttribute("sizemode", sizeString);
}
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::GetWindowDOMWindow(nsIDOMWindow** aDOMWindow)
{
NS_ENSURE_STATE(mDocShell);
if(!mDOMWindow)
mDOMWindow = do_GetInterface(mDocShell);
NS_ENSURE_TRUE(mDOMWindow, NS_ERROR_FAILURE);
*aDOMWindow = mDOMWindow;
NS_ADDREF(*aDOMWindow);
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::GetWindowDOMElement(nsIDOMElement** aDOMElement)
{
NS_ENSURE_STATE(mDocShell);
NS_ENSURE_ARG_POINTER(aDOMElement);
*aDOMElement = nsnull;
nsCOMPtr<nsIContentViewer> cv;
mDocShell->GetContentViewer(getter_AddRefs(cv));
if(!cv)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDocumentViewer> docv(do_QueryInterface(cv));
if(!docv)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDocument> doc;
docv->GetDocument(*getter_AddRefs(doc));
nsCOMPtr<nsIDOMDocument> domdoc(do_QueryInterface(doc));
if(!domdoc)
return NS_ERROR_FAILURE;
domdoc->GetDocumentElement(aDOMElement);
if(!*aDOMElement)
return NS_ERROR_FAILURE;
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::GetDOMElementById(char* aID, nsIDOMElement** aDOMElement)
{
NS_ENSURE_STATE(mDocShell);
NS_ENSURE_ARG_POINTER(aDOMElement);
*aDOMElement = nsnull;
nsCOMPtr<nsIContentViewer> cv;
mDocShell->GetContentViewer(getter_AddRefs(cv));
if(!cv)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDocumentViewer> docv(do_QueryInterface(cv));
if(!docv)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDocument> doc;
docv->GetDocument(*getter_AddRefs(doc));
nsCOMPtr<nsIDOMXULDocument> domdoc(do_QueryInterface(doc));
if(!domdoc)
return NS_ERROR_FAILURE;
NS_ENSURE_SUCCESS(domdoc->GetElementById(aID, aDOMElement), NS_ERROR_FAILURE);
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::ContentShellAdded(nsIDocShellTreeItem* aContentShell,
PRBool aPrimary, const PRUnichar* aID)
{
nsContentShellInfo* shellInfo = new nsContentShellInfo(aID, aPrimary, aContentShell);
mContentShells.AppendElement((void*)shellInfo);
// Set the default content tree owner if one does not exist.
nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
aContentShell->GetTreeOwner(getter_AddRefs(treeOwner));
if(!treeOwner)
{
if(aPrimary)
{
NS_ENSURE_SUCCESS(EnsurePrimaryContentTreeOwner(), NS_ERROR_FAILURE);
aContentShell->SetTreeOwner(mPrimaryContentTreeOwner);
}
else
{
NS_ENSURE_SUCCESS(EnsureContentTreeOwner(), NS_ERROR_FAILURE);
aContentShell->SetTreeOwner(mContentTreeOwner);
}
}
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::SizeShellTo(nsIDocShellTreeItem* aShellItem,
PRInt32 aCX, PRInt32 aCY)
{
// XXXTAB This is wrong, we should actually reflow based on the passed in'
// shell. For now we are hacking and doing delta sizing. This is bad
// because it assumes all size we add will go to the shell which probably
// won't happen.
nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(aShellItem));
NS_ENSURE_TRUE(shellAsWin, NS_ERROR_FAILURE);
PRInt32 width = 0;
PRInt32 height = 0;
shellAsWin->GetSize(&width, &height);
PRInt32 widthDelta = aCX - width;
PRInt32 heightDelta = aCY - height;
if(widthDelta || heightDelta)
{
PRInt32 winCX = 0;
PRInt32 winCY = 0;
GetSize(&winCX, &winCY);
SetSize(winCX + widthDelta, winCY + heightDelta, PR_TRUE);
PersistPositionAndSize(PR_FALSE, PR_TRUE, PR_FALSE);
}
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::ExitModalLoop()
{
if (mContinueModalLoop) // was a modal window
EnableParent(PR_TRUE);
mContinueModalLoop = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::GetNewWindow(PRInt32 aChromeFlags,
nsIDocShellTreeItem** aDocShellTreeItem)
{
NS_ENSURE_ARG_POINTER(aDocShellTreeItem);
if(aChromeFlags & nsIWebBrowserChrome::openAsChrome)
return CreateNewChromeWindow(aChromeFlags, aDocShellTreeItem);
else
return CreateNewContentWindow(aChromeFlags, aDocShellTreeItem);
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsXULWindow::CreateNewChromeWindow(PRInt32 aChromeFlags,
nsIDocShellTreeItem** aDocShellTreeItem)
{
nsCOMPtr<nsIAppShellService> appShell(do_GetService(kAppShellServiceCID));
NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE);
// Just do a normal create of a window and return.
//XXXTAB remove this when appshell talks in terms of nsIXULWindow
nsCOMPtr<nsIXULWindow> parent;
if(aChromeFlags & nsIWebBrowserChrome::dependent)
parent = this;
nsCOMPtr<nsIXULWindow> newWindow;
appShell->CreateTopLevelWindow(parent, nsnull, PR_FALSE, PR_FALSE,
aChromeFlags, NS_SIZETOCONTENT, NS_SIZETOCONTENT,
getter_AddRefs(newWindow));
NS_ENSURE_TRUE(newWindow, NS_ERROR_FAILURE);
// XXX Ick, this should be able to go away.....
nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(newWindow));
if(browserChrome)
browserChrome->SetChromeMask(aChromeFlags);
nsCOMPtr<nsIDocShell> docShell;
newWindow->GetDocShell(getter_AddRefs(docShell));
CallQueryInterface(docShell, aDocShellTreeItem);
return NS_OK;
}
NS_IMETHODIMP nsXULWindow::CreateNewContentWindow(PRInt32 aChromeFlags,
nsIDocShellTreeItem** aDocShellTreeItem)
{
nsCOMPtr<nsIAppShellService> appShell(do_GetService(kAppShellServiceCID));
NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE);
// We need to create a new top level window and then enter a nested
// loop. Eventually the new window will be told that it has loaded,
// at which time we know it is safe to spin out of the nested loop
// and allow the opening code to proceed.
// First push a nested event queue for event processing from netlib
// onto our UI thread queue stack.
nsEventQueueStack queuePusher;
NS_ENSURE_SUCCESS(queuePusher.Success(), NS_ERROR_FAILURE);
char * urlStr = "chrome://navigator/content/";
nsCOMPtr<nsIIOService> service(do_GetService(kIOServiceCID));
NS_ENSURE_TRUE(service, NS_ERROR_FAILURE);
nsCOMPtr<nsIURI> uri;
service->NewURI(urlStr, nsnull, getter_AddRefs(uri));
NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
nsCOMPtr<nsIXULWindow> newWindow;
appShell->CreateTopLevelWindow(nsnull, uri, PR_FALSE, PR_FALSE,
aChromeFlags, 615, 480,
getter_AddRefs(newWindow));
NS_ENSURE_TRUE(newWindow, NS_ERROR_FAILURE);
nsCOMPtr<nsIWebShellWindow> webShellWindow(do_QueryInterface(newWindow));
nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(newWindow));
if(browserChrome)
browserChrome->SetChromeMask(aChromeFlags);
nsCOMPtr<nsIAppShell> subShell(do_CreateInstance(kAppShellCID));
NS_ENSURE_TRUE(subShell, NS_ERROR_FAILURE);
subShell->Create(0, nsnull);
subShell->Spinup();
// Specify that we want the window to remain locked until the chrome has loaded.
webShellWindow->LockUntilChromeLoad();
PRBool locked = PR_FALSE;
webShellWindow->GetLockedState(locked);
// Push nsnull onto the JSContext stack before we dispatch a native event.
nsCOMPtr<nsIJSContextStack> stack(do_GetService("nsThreadJSContextStack"));
if(stack && NS_SUCCEEDED(stack->Push(nsnull)))
{
nsresult looprv = NS_OK;
while(NS_SUCCEEDED(looprv) && locked)
{
void *data;
PRBool isRealEvent;
looprv = subShell->GetNativeEvent(isRealEvent, data);
subShell->DispatchNativeEvent(isRealEvent, data);
webShellWindow->GetLockedState(locked);
}
JSContext *cx;
stack->Pop(&cx);
NS_ASSERTION(cx == nsnull, "JSContextStack mismatch");
}
subShell->Spindown();
// We're out of the nested loop.
// During the layout of the new window, all content shells were located and placed
// into the new window's content shell array. Locate the "content area" content
// shell.
newWindow->GetPrimaryContentShell(aDocShellTreeItem);
return NS_OK;
}
// XXX can this switch now?
/// This should rightfully be somebody's PROGID?
// Will switch when the "app shell browser component" arrives.
static const char *prefix = "component://netscape/appshell/component/browser/window";
NS_IMETHODIMP nsXULWindow::NotifyObservers(const PRUnichar* aTopic,
const PRUnichar* aData)
{
nsCOMPtr<nsIObserverService> service(do_GetService(NS_OBSERVERSERVICE_PROGID));
if(!service)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIWebShellWindow>
removeme(do_QueryInterface(NS_STATIC_CAST(nsIXULWindow*, this)));
nsAutoString topic(prefix);
topic += ";";
topic += aTopic;
NS_ENSURE_SUCCESS(service->Notify(removeme, topic.GetUnicode(), aData),
NS_ERROR_FAILURE);
return NS_OK;
}
void nsXULWindow::EnableParent(PRBool aEnable)
{
nsCOMPtr<nsIBaseWindow> parentWindow;
nsCOMPtr<nsIWidget> parentWidget;
parentWindow = do_QueryReferent(mParentWindow);
if (parentWindow)
parentWindow->GetMainWidget(getter_AddRefs(parentWidget));
if (parentWidget)
parentWidget->Enable(aEnable);
}
2000-04-01 22:13:46 +00:00
// Constrain the window to its proper z-level
PRBool nsXULWindow::ConstrainToZLevel(
PRBool aImmediate,
nsWindowZ *aPlacement,
nsIWidget *aReqBelow,
nsIWidget **aActualBelow) {
#if 0
/* Do we have a parent window? This means our z-order is already constrained,
since we're a dependent window. Our window list isn't hierarchical,
so we can't properly calculate placement for such a window.
Should we just abort? */
nsCOMPtr<nsIBaseWindow> parentWindow = do_QueryReferent(mParentWindow);
if (parentWindow)
return PR_FALSE;
#endif
nsCOMPtr<nsIWindowMediator> mediator(do_GetService(kWindowMediatorCID));
if(!mediator)
return PR_FALSE;
PRBool altered;
PRUint32 position,
newPosition;
nsIXULWindow *us = NS_STATIC_CAST(nsIXULWindow *, this);
altered = PR_FALSE;
// translate from nsIWindowMediator to nsGUIEvent constants
position = nsIWindowMediator::zLevelTop;
if (*aPlacement == nsWindowZBottom)
position = nsIWindowMediator::zLevelBottom;
else if (*aPlacement == nsWindowZRelative)
position = nsIWindowMediator::zLevelBelow;
if (NS_SUCCEEDED(mediator->CalculateZPosition(us, position, aReqBelow,
&newPosition, aActualBelow, &altered))) {
if (altered || aImmediate) {
2000-04-01 22:13:46 +00:00
if (newPosition == nsIWindowMediator::zLevelTop)
*aPlacement = nsWindowZTop;
else if (newPosition == nsIWindowMediator::zLevelBottom)
*aPlacement = nsWindowZBottom;
else
*aPlacement = nsWindowZRelative;
if (aImmediate) {
nsCOMPtr<nsIBaseWindow> ourBase = do_QueryInterface(NS_STATIC_CAST(nsIXULWindow *,this));
if (ourBase) {
nsCOMPtr<nsIWidget> ourWidget;
ourBase->GetMainWidget(getter_AddRefs(ourWidget));
ourWidget->PlaceBehind(*aActualBelow);
}
}
}
/* (CalculateZPosition can tell us to be below nothing, because it tries
not to change something it doesn't recognize. A request to verify
being below an unrecognized window, then, is treated as a request
to come to the top (below null) */
nsCOMPtr<nsIXULWindow> windowAbove;
if (newPosition == nsIWindowMediator::zLevelBelow && *aActualBelow) {
void *data;
(*aActualBelow)->GetClientData(data);
if (data) {
nsWebShellWindow *win;
win = NS_REINTERPRET_CAST(nsWebShellWindow *, data);
windowAbove = do_QueryInterface(NS_STATIC_CAST(nsIWebShellWindow *,win));
}
}
mediator->SetZPosition(us, newPosition, windowAbove);
}
return altered;
}
//*****************************************************************************
// nsXULWindow: Accessors
//*****************************************************************************
//*****************************************************************************
//*** nsContentShellInfo: Object Management
//*****************************************************************************
nsContentShellInfo::nsContentShellInfo(const nsString& aID, PRBool aPrimary,
nsIDocShellTreeItem* aContentShell) : id(aID), primary(aPrimary), child(aContentShell)
{
}
nsContentShellInfo::~nsContentShellInfo()
{
//XXX Set Tree Owner to null if the tree owner is nsXULWindow->mContentTreeOwner
}
//*****************************************************************************
//*** nsEventQueueStack: Object Implementation
//*****************************************************************************
nsEventQueueStack::nsEventQueueStack() : mQueue(nsnull)
{
mService = do_GetService(kEventQueueServiceCID);
if(mService)
mService->PushThreadEventQueue(&mQueue);
}
nsEventQueueStack::~nsEventQueueStack()
{
if(mQueue)
mService->PopThreadEventQueue(mQueue);
mService = nsnull;
}
nsresult nsEventQueueStack::Success()
{
return mQueue ? NS_OK : NS_ERROR_FAILURE;
}