/* * vim:ts=2:et:sw=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 * Christopher Blizzard. * Portions created by the Initial Developer are Copyright (C) 2001 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Christopher Blizzard * Chris Lord * * Alternatively, the contents of this file may be used under the terms of * either 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 "nsCWebBrowser.h" #include "nsIComponentManager.h" #include "nsComponentManagerUtils.h" #include "nsIDocShellTreeItem.h" #include "nsIWidget.h" #include "nsThreadUtils.h" #include "nsNetUtil.h" #include "nsISelection.h" #include "nsIDOMWindow.h" #include "nsIDOMDocument.h" #include "nsIDOM3Document.h" #include "nsIDocument.h" #include "nsIDOMNode.h" #include "HeadlessWindow.h" #include "HeadlessPrivate.h" #include "HeadlessPrompter.h" #include "moz-headless-internal.h" //GtkWidget *HeadlessWindow::sTipWindow = nsnull; HeadlessWindow::HeadlessWindow(void) { mOwner = nsnull; mVisibility = PR_FALSE; mIsModal = PR_FALSE; mContinueModalLoop = PR_FALSE; mModalStatus = NS_OK; } HeadlessWindow::~HeadlessWindow(void) { ExitModalEventLoop(PR_FALSE); } nsresult HeadlessWindow::Init(HeadlessPrivate *aOwner, long aItemType) { // save our owner for later mOwner = aOwner; // create our nsIWebBrowser object and set up some basic defaults. mWebBrowser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID); if (!mWebBrowser) return NS_ERROR_FAILURE; mWebBrowser->SetContainerWindow(static_cast(this)); nsCOMPtr item = do_QueryInterface(mWebBrowser); item->SetItemType(aItemType); return NS_OK; } nsresult HeadlessWindow::CreateWindow(void) { nsresult rv; gint width, height; // Get the base window interface for the web browser object and // create the window. mBaseWindow = do_QueryInterface(mWebBrowser); MozDrawingArea *drawingArea = moz_headless_get_drawing_area (mOwner->mOwningObject); g_object_get (G_OBJECT (drawingArea), "width", (gpointer)&width, "height", (gpointer)&height, NULL); rv = mBaseWindow->InitWindow(drawingArea, nsnull, 0, 0, width, height); if (NS_FAILED(rv)) return rv; rv = mBaseWindow->Create(); if (NS_FAILED(rv)) return rv; return NS_OK; } void HeadlessWindow::ReleaseChildren(void) { ExitModalEventLoop(PR_FALSE); mBaseWindow->Destroy(); mBaseWindow = 0; mWebBrowser = 0; } // nsISupports NS_IMPL_ADDREF(HeadlessWindow) NS_IMPL_RELEASE(HeadlessWindow) NS_INTERFACE_MAP_BEGIN(HeadlessWindow) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowserChrome) NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome) NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChromeFocus) NS_INTERFACE_MAP_ENTRY(nsIEmbeddingSiteWindow) NS_INTERFACE_MAP_ENTRY(nsITooltipListener) NS_INTERFACE_MAP_ENTRY(nsIContextMenuListener2) NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) NS_INTERFACE_MAP_END // nsIWebBrowserChrome NS_IMETHODIMP HeadlessWindow::SetStatus(PRUint32 aStatusType, const PRUnichar *aStatus) { switch (aStatusType) { case STATUS_SCRIPT: { mJSStatus = aStatus; g_signal_emit(G_OBJECT(mOwner->mOwningObject), moz_headless_signals[JS_STATUS], 0); } break; case STATUS_SCRIPT_DEFAULT: // Gee, that's nice. break; case STATUS_LINK: { mLinkMessage = aStatus; g_signal_emit(G_OBJECT(mOwner->mOwningObject), moz_headless_signals[LINK_MESSAGE], 0); } break; } return NS_OK; } NS_IMETHODIMP HeadlessWindow::GetWebBrowser(nsIWebBrowser **aWebBrowser) { *aWebBrowser = mWebBrowser; NS_IF_ADDREF(*aWebBrowser); return NS_OK; } NS_IMETHODIMP HeadlessWindow::SetWebBrowser(nsIWebBrowser *aWebBrowser) { mWebBrowser = aWebBrowser; return NS_OK; } NS_IMETHODIMP HeadlessWindow::GetChromeFlags(PRUint32 *aChromeFlags) { *aChromeFlags = mOwner->mChromeMask; return NS_OK; } NS_IMETHODIMP HeadlessWindow::SetChromeFlags(PRUint32 aChromeFlags) { mOwner->SetChromeMask(aChromeFlags); return NS_OK; } NS_IMETHODIMP HeadlessWindow::DestroyBrowserWindow(void) { // mark the owner as destroyed so it won't emit events anymore. mOwner->mIsDestroyed = PR_TRUE; g_signal_emit(G_OBJECT(mOwner->mOwningObject), moz_headless_signals[DESTROY_BROWSER], 0); return NS_OK; } NS_IMETHODIMP HeadlessWindow::SizeBrowserTo(PRInt32 aCX, PRInt32 aCY) { g_signal_emit(G_OBJECT(mOwner->mOwningObject), moz_headless_signals[SIZE_TO], 0, aCX, aCY); return NS_OK; } NS_IMETHODIMP HeadlessWindow::ShowAsModal(void) { mIsModal = PR_TRUE; mContinueModalLoop = PR_TRUE; // FIXME: Add some kind of grab here... nsIThread *thread = NS_GetCurrentThread(); while (mContinueModalLoop) if (!NS_ProcessNextEvent(thread)) break; mContinueModalLoop = PR_FALSE; return mModalStatus; } NS_IMETHODIMP HeadlessWindow::IsWindowModal(PRBool *_retval) { *_retval = mIsModal; return NS_OK; } NS_IMETHODIMP HeadlessWindow::ExitModalEventLoop(nsresult aStatus) { mContinueModalLoop = PR_FALSE; mModalStatus = aStatus; return NS_OK; } // nsIWebBrowserChromeFocus NS_IMETHODIMP HeadlessWindow::FocusNextElement() { // FIXME: Implement /* GtkWidget *toplevel; toplevel = gtk_widget_get_toplevel(GTK_WIDGET(mOwner->mOwningObject)); if (!GTK_WIDGET_TOPLEVEL(toplevel)) return NS_OK; g_signal_emit_by_name(G_OBJECT(toplevel), "move_focus", GTK_DIR_TAB_FORWARD); */ return NS_OK; } NS_IMETHODIMP HeadlessWindow::FocusPrevElement() { // FIXME: Implement /* GtkWidget *toplevel; toplevel = gtk_widget_get_toplevel(GTK_WIDGET(mOwner->mOwningObject)); if (!GTK_WIDGET_TOPLEVEL(toplevel)) return NS_OK; g_signal_emit_by_name(G_OBJECT(toplevel), "move_focus", GTK_DIR_TAB_BACKWARD); */ return NS_OK; } // nsIEmbeddingSiteWindow NS_IMETHODIMP HeadlessWindow::SetDimensions(PRUint32 aFlags, PRInt32 aX, PRInt32 aY, PRInt32 aCX, PRInt32 aCY) { if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION && (aFlags & (nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_INNER | nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER))) { return mBaseWindow->SetPositionAndSize(aX, aY, aCX, aCY, PR_TRUE); } else if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION) { return mBaseWindow->SetPosition(aX, aY); } else if (aFlags & (nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_INNER | nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER)) { return mBaseWindow->SetSize(aCX, aCY, PR_TRUE); } return NS_ERROR_INVALID_ARG; } NS_IMETHODIMP HeadlessWindow::GetDimensions(PRUint32 aFlags, PRInt32 *aX, PRInt32 *aY, PRInt32 *aCX, PRInt32 *aCY) { if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION && (aFlags & (nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_INNER | nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER))) { return mBaseWindow->GetPositionAndSize(aX, aY, aCX, aCY); } else if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION) { return mBaseWindow->GetPosition(aX, aY); } else if (aFlags & (nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_INNER | nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER)) { return mBaseWindow->GetSize(aCX, aCY); } return NS_ERROR_INVALID_ARG; } NS_IMETHODIMP HeadlessWindow::SetFocus(void) { // XXX might have to do more here. return mBaseWindow->SetFocus(); } NS_IMETHODIMP HeadlessWindow::GetTitle(PRUnichar **aTitle) { *aTitle = ToNewUnicode(mTitle); return NS_OK; } NS_IMETHODIMP HeadlessWindow::SetTitle(const PRUnichar *aTitle) { mTitle = aTitle; g_signal_emit(G_OBJECT(mOwner->mOwningObject), moz_headless_signals[TITLE], 0); return NS_OK; } NS_IMETHODIMP HeadlessWindow::GetSiteWindow(void **aSiteWindow) { *aSiteWindow = static_cast(mOwner->mOwningObject); return NS_OK; } NS_IMETHODIMP HeadlessWindow::GetVisibility(PRBool *aVisibility) { // XXX See bug 312998 // Work around the problem that sometimes the window // is already visible even though mVisibility isn't true // yet. *aVisibility = mVisibility || (!mOwner->mIsChrome && mOwner->mOwningObject); return NS_OK; } NS_IMETHODIMP HeadlessWindow::SetVisibility(PRBool aVisibility) { // We always set the visibility so that if it's chrome and we finish // the load we know that we have to show the window. mVisibility = aVisibility; // if this is a chrome window and the chrome hasn't finished loading // yet then don't show the window yet. if (mOwner->mIsChrome && !mOwner->mChromeLoaded) return NS_OK; g_signal_emit(G_OBJECT(mOwner->mOwningObject), moz_headless_signals[VISIBILITY], 0, aVisibility); return NS_OK; } // nsITooltipListener NS_IMETHODIMP HeadlessWindow::OnShowTooltip(PRInt32 aXCoords, PRInt32 aYCoords, const PRUnichar *aTipText) { char *text = ToNewUTF8String (nsAutoString (aTipText)); g_signal_emit (G_OBJECT (mOwner->mOwningObject), moz_headless_signals[SHOW_TOOLTIP], 0, text, (gint)aXCoords, (gint)aYCoords); NS_Free (text); return NS_OK; } NS_IMETHODIMP HeadlessWindow::OnHideTooltip(void) { g_signal_emit (G_OBJECT (mOwner->mOwningObject), moz_headless_signals[HIDE_TOOLTIP], 0); return NS_OK; } // nsIContextMenuListener NS_IMETHODIMP HeadlessWindow::OnShowContextMenu(PRUint32 aContextFlags, nsIContextMenuInfo *aContextMenuInfo) { nsresult rv; nsString hrefString; guint mozheadlessContextFlags = MOZ_HEADLESS_CTX_NONE; if (aContextFlags & nsIContextMenuListener2::CONTEXT_LINK) { aContextMenuInfo->GetAssociatedLink(hrefString); mozheadlessContextFlags |= MOZ_HEADLESS_CTX_LINK; } nsCOMPtr imgSrc; nsCAutoString imgSrcString; if (aContextFlags & nsIContextMenuListener2::CONTEXT_IMAGE) { aContextMenuInfo->GetImageSrc(getter_AddRefs(imgSrc)); imgSrc->GetSpec(imgSrcString); mozheadlessContextFlags |= MOZ_HEADLESS_CTX_IMAGE; } if (aContextFlags & nsIContextMenuListener2::CONTEXT_DOCUMENT) mozheadlessContextFlags |= MOZ_HEADLESS_CTX_DOCUMENT; if (aContextFlags & nsIContextMenuListener2::CONTEXT_TEXT) mozheadlessContextFlags |= MOZ_HEADLESS_CTX_TEXT; if (aContextFlags & nsIContextMenuListener2::CONTEXT_INPUT) mozheadlessContextFlags |= MOZ_HEADLESS_CTX_INPUT; if (aContextFlags & nsIContextMenuListener2::CONTEXT_BACKGROUND_IMAGE) mozheadlessContextFlags |= MOZ_HEADLESS_CTX_BACKGROUND; nsCOMPtr selection; nsString selectionString; // get the web browser nsCOMPtr webBrowser; mOwner->mWindow->GetWebBrowser(getter_AddRefs(webBrowser)); // get the content DOM window for that web browser nsCOMPtr domWindow; webBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); domWindow->GetSelection(getter_AddRefs(selection)); selection->ToString(getter_Copies(selectionString)); if (!selectionString.IsEmpty()) { mozheadlessContextFlags |= MOZ_HEADLESS_CTX_SELECTION; } nsString ctxUriString; nsCOMPtr targetNode; rv = aContextMenuInfo->GetTargetNode(getter_AddRefs(targetNode)); if (NS_SUCCEEDED (rv)) { nsCOMPtr domDoc; rv = targetNode->GetOwnerDocument(getter_AddRefs(domDoc)); if (NS_SUCCEEDED(rv)) { nsCOMPtr docUri = do_QueryInterface((nsISupports*)domDoc.get()); if (docUri) docUri->GetDocumentURI(ctxUriString); } } //printf("ShowContextMenu 0x%x:\n\turi: %s\n\thref: %s\n\timg_src: %s\n\ttext_selection: %s\n", // mozheadlessContextFlags, // NS_ConvertUTF16toUTF8(ctxUriString).get(), // NS_ConvertUTF16toUTF8(hrefString).get(), // imgSrcString.get(), // NS_ConvertUTF16toUTF8(selectionString).get()); g_signal_emit (G_OBJECT (mOwner->mOwningObject), moz_headless_signals[CONTEXT_INFO], 0, mozheadlessContextFlags, NS_SUCCEEDED (rv) ? NS_ConvertUTF16toUTF8(ctxUriString).get() : NULL, NS_ConvertUTF16toUTF8(hrefString).get(), imgSrcString.get(), NS_ConvertUTF16toUTF8(selectionString).get()); return NS_OK; } // nsIInterfaceRequestor NS_IMETHODIMP HeadlessWindow::GetInterface(const nsIID &aIID, void** aInstancePtr) { nsresult rv; rv = QueryInterface(aIID, aInstancePtr); // pass it up to the web browser object if (NS_FAILED(rv) || !*aInstancePtr) { nsCOMPtr ir = do_QueryInterface(mWebBrowser); return ir->GetInterface(aIID, aInstancePtr); } return rv; }