From 6deabce61b1758b0c395678bf5c2769ee4ca17c6 Mon Sep 17 00:00:00 2001 From: Christian Persch Date: Sat, 25 Aug 2007 20:59:04 +0000 Subject: Initial checkin: merged embed/gecko from xulrunner branch to embed/xulrunner, and svn copied embed/mozilla to embed/xulrunner/embed. Not integreated with the build yet. svn path=/trunk/; revision=7297 --- embed/xulrunner/src/GeckoBrowser.cpp | 676 +++++++++++++++++++++++++++++++++++ 1 file changed, 676 insertions(+) create mode 100644 embed/xulrunner/src/GeckoBrowser.cpp (limited to 'embed/xulrunner/src/GeckoBrowser.cpp') diff --git a/embed/xulrunner/src/GeckoBrowser.cpp b/embed/xulrunner/src/GeckoBrowser.cpp new file mode 100644 index 000000000..5a91a98bf --- /dev/null +++ b/embed/xulrunner/src/GeckoBrowser.cpp @@ -0,0 +1,676 @@ +/* + * Copyright © Christopher Blizzard + * Copyright © 2006 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------------------------- + * Derived from Mozilla.org code, which had the following attributions: + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright © Christopher Blizzard. All Rights Reserved. + * Portions created by the Initial Developer are Copyright © 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Christopher Blizzard + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#include +#include "config.h" + +#include "nsIDocShell.h" +#include "nsIWebProgress.h" +#include "nsIWebBrowserStream.h" +#include "nsIWebBrowserFocus.h" +#include "nsIWidget.h" +#include + +// for NS_APPSHELL_CID +#include "nsWidgetsCID.h" + +// for do_GetInterface +#include "nsIInterfaceRequestor.h" +// for do_CreateInstance +#include "nsIComponentManager.h" + +// for initializing our window watcher service +#include "nsIWindowWatcher.h" + +#include "nsILocalFile.h" +#include "nsEmbedAPI.h" + +// all of the crap that we need for event listeners +// and when chrome windows finish loading +#include "nsIDOMWindow.h" +#include "nsPIDOMWindow.h" +#include "nsIDOMWindowInternal.h" + +// For seting scrollbar visibilty +#include + +// for the focus hacking we need to do +#include "nsIFocusController.h" + +// for profiles +#define STANDALONE_PROFILEDIRSERVICE +#include "nsProfileDirServiceProvider.h" + +// app component registration +#include "nsIGenericFactory.h" +#include "nsIComponentRegistrar.h" + +// all of our local includes +#include "GeckoBrowser.h" +#include "EmbedWindow.h" +#include "EmbedProgress.h" +#include "EmbedContentListener.h" +#include "EmbedEventListener.h" +#include "EmbedWindowCreator.h" + +#ifdef MOZ_ACCESSIBILITY_ATK +#include "nsIAccessibilityService.h" +#include "nsIAccessible.h" +#include "nsIDOMDocument.h" +#endif + +#include "GeckoSingle.h" + +GeckoBrowser::GeckoBrowser(void) + : mOwningWidget(nsnull) + , mWindow(nsnull) + , mProgress(nsnull) + , mContentListener(nsnull) + , mEventListener(nsnull) + , mChromeMask(nsIWebBrowserChrome::CHROME_ALL) + , mIsChrome(PR_FALSE) + , mChromeLoaded(PR_FALSE) + , mListenersAttached(PR_FALSE) + , mMozWindowWidget(nsnull) + , mIsDestroyed(PR_FALSE) +{ + GeckoSingle::AddBrowser(this); +} + +GeckoBrowser::~GeckoBrowser() +{ + GeckoSingle::RemoveBrowser(this); +} + +nsresult +GeckoBrowser::Init(GeckoEmbed *aOwningWidget) +{ + // are we being re-initialized? + if (mOwningWidget) + return NS_OK; + + // hang on with a reference to the owning widget + mOwningWidget = aOwningWidget; + + // Create our embed window, and create an owning reference to it and + // initialize it. It is assumed that this window will be destroyed + // when we go out of scope. + mWindow = new EmbedWindow(); + mWindowGuard = static_cast(mWindow); + mWindow->Init(this); + + // Create our progress listener object, make an owning reference, + // and initialize it. It is assumed that this progress listener + // will be destroyed when we go out of scope. + mProgress = new EmbedProgress(); + mProgressGuard = static_cast + (mProgress); + mProgress->Init(this); + + // Create our content listener object, initialize it and attach it. + // It is assumed that this will be destroyed when we go out of + // scope. + mContentListener = new EmbedContentListener(); + mContentListenerGuard = static_cast(static_cast(mContentListener)); + mContentListener->Init(this); + + // Create our key listener object and initialize it. It is assumed + // that this will be destroyed before we go out of scope. + mEventListener = new EmbedEventListener(this); + mEventListenerGuard = + static_cast(static_cast + (mEventListener)); + + return NS_OK; +} + +nsresult +GeckoBrowser::Realize(PRBool *aAlreadyRealized) +{ + + *aAlreadyRealized = PR_FALSE; + + // Have we ever been initialized before? If so then just reparent + // from the offscreen window. + if (mMozWindowWidget) { + gtk_widget_reparent(mMozWindowWidget, GTK_WIDGET(mOwningWidget)); + *aAlreadyRealized = PR_TRUE; + return NS_OK; + } + + // Get the nsIWebBrowser object for our embedded window. + nsCOMPtr webBrowser; + mWindow->GetWebBrowser(getter_AddRefs(webBrowser)); + + // get a handle on the navigation object + mNavigation = do_QueryInterface(webBrowser); + + // Create our session history object and tell the navigation object + // to use it. We need to do this before we create the web browser + // window. + mSessionHistory = do_CreateInstance(NS_SHISTORY_CONTRACTID); + mNavigation->SetSessionHistory(mSessionHistory); + + // create the window + mWindow->CreateWindow(); + + // bind the progress listener to the browser object + nsCOMPtr supportsWeak; + supportsWeak = do_QueryInterface(mProgressGuard); + nsCOMPtr weakRef; + supportsWeak->GetWeakReference(getter_AddRefs(weakRef)); + webBrowser->AddWebBrowserListener(weakRef, + NS_GET_IID (nsIWebProgressListener)); + + // set ourselves as the parent uri content listener + nsCOMPtr uriListener; + uriListener = do_QueryInterface(mContentListenerGuard); + webBrowser->SetParentURIContentListener(uriListener); + + // save the window id of the newly created window + nsCOMPtr mozWidget; + mWindow->mBaseWindow->GetMainWidget(getter_AddRefs(mozWidget)); + // get the native drawing area + GdkWindow *tmp_window = + static_cast + (mozWidget->GetNativeData(NS_NATIVE_WINDOW)); + // and, thanks to superwin we actually need the parent of that. + // FIXME is this true on gtk2 widget? + tmp_window = gdk_window_get_parent(tmp_window); + // save the widget ID - it should be the mozarea of the window. + gpointer data = nsnull; + gdk_window_get_user_data(tmp_window, &data); + mMozWindowWidget = static_cast(data); + + // Apply the current chrome mask + ApplyChromeMask(); + + return NS_OK; +} + +void +GeckoBrowser::Unrealize(void) +{ + // reparent to our offscreen window + GeckoSingle::ReparentToOffscreen(mMozWindowWidget); +} + +void +GeckoBrowser::Show(void) +{ + // Get the nsIWebBrowser object for our embedded window. + nsCOMPtr webBrowser; + mWindow->GetWebBrowser (getter_AddRefs (webBrowser)); + + // and set the visibility on the thing + nsCOMPtr baseWindow (do_QueryInterface (webBrowser)); + baseWindow->SetVisibility(PR_TRUE); +} + +void +GeckoBrowser::Hide(void) +{ + // Get the nsIWebBrowser object for our embedded window. + nsCOMPtr webBrowser; + mWindow->GetWebBrowser (getter_AddRefs (webBrowser)); + + // and set the visibility on the thing + nsCOMPtr baseWindow (do_QueryInterface (webBrowser)); + baseWindow->SetVisibility (PR_FALSE); +} + +void +GeckoBrowser::Resize(PRUint32 aWidth, PRUint32 aHeight) +{ + mWindow->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION | + nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_INNER, + 0, 0, aWidth, aHeight); +} + +void +GeckoBrowser::Destroy(void) +{ + // This flag might have been set from + // EmbedWindow::DestroyBrowserWindow() as well if someone used a + // window.close() or something or some other script action to close + // the window. No harm setting it again. + mIsDestroyed = PR_TRUE; + + // Get the nsIWebBrowser object for our embedded window. + nsCOMPtr webBrowser; + mWindow->GetWebBrowser(getter_AddRefs(webBrowser)); + + // Release our progress listener + nsCOMPtr supportsWeak + (do_QueryInterface(mProgressGuard)); + nsCOMPtr weakRef; + supportsWeak->GetWeakReference(getter_AddRefs(weakRef)); + webBrowser->RemoveWebBrowserListener(weakRef, + NS_GET_IID (nsIWebProgressListener)); + weakRef = nsnull; + supportsWeak = nsnull; + + // Release our content listener + webBrowser->SetParentURIContentListener(nsnull); + mContentListenerGuard = nsnull; + mContentListener = nsnull; + + // Now that we have removed the listener, release our progress + // object + mProgressGuard = nsnull; + mProgress = nsnull; + + // detach our event listeners and release the event receiver + DetachListeners(); + + mEventTarget = nsnull; + + // destroy our child window + mWindow->ReleaseChildren(); + + // release navigation + mNavigation = nsnull; + + // release session history + mSessionHistory = nsnull; + + mOwningWidget = nsnull; + + mMozWindowWidget = 0; +} + +void +GeckoBrowser::Reload(PRUint32 reloadFlags) +{ + /* Use the session history if it is available, this + * allows framesets to reload correctly */ + nsCOMPtr wn (do_QueryInterface(mSessionHistory)); + + if (!wn) + wn = mNavigation; + + NS_ENSURE_TRUE (wn, ); + + wn->Reload(reloadFlags); +} + +void +GeckoBrowser::ApplyChromeMask() +{ + if (mWindow) { + nsCOMPtr webBrowser; + mWindow->GetWebBrowser(getter_AddRefs(webBrowser)); + + nsCOMPtr domWindow; + webBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); + if (domWindow) { + + nsCOMPtr scrollbars; + domWindow->GetScrollbars(getter_AddRefs(scrollbars)); + if (scrollbars) { + + scrollbars->SetVisible + (mChromeMask & nsIWebBrowserChrome::CHROME_SCROLLBARS ? + PR_TRUE : PR_FALSE); + } + } + } +} + + +void +GeckoBrowser::SetChromeMask(PRUint32 aChromeMask) +{ + mChromeMask = aChromeMask; + + ApplyChromeMask(); +} + +void +GeckoBrowser::SetURI(const char *aURI) +{ + mURI = aURI; +} + +void +GeckoBrowser::LoadCurrentURI(void) +{ + if (mURI.Length()) { + nsCOMPtr piWin; + GetPIDOMWindow(getter_AddRefs(piWin)); + nsAutoPopupStatePusher popupStatePusher(piWin, openAllowed); + + nsEmbedString uri; + NS_CStringToUTF16(mURI, NS_CSTRING_ENCODING_UTF8, uri); + mNavigation->LoadURI(uri.get(), // URI string + nsIWebNavigation::LOAD_FLAGS_NONE, // Load flags + nsnull, // Referring URI + nsnull, // Post data + nsnull); // extra headers + } +} + +#if 0 +nsresult +GeckoBrowser::OpenStream(const char *aBaseURI, const char *aContentType) +{ + nsCOMPtr webBrowser; + mWindow->GetWebBrowser(getter_AddRefs(webBrowser)); + + nsCOMPtr wbStream = do_QueryInterface(webBrowser); + if (!wbStream) return NS_ERROR_FAILURE; + + return wbStream->OpenStream(aBaseURI, aContentType); +} + +nsresult +GeckoBrowser::AppendToStream(const char *aData, PRInt32 aLen) +{ + // Attach listeners to this document since in some cases we don't + // get updates for content added this way. + ContentStateChange(); + + nsCOMPtr webBrowser; + mWindow->GetWebBrowser(getter_AddRefs(webBrowser)); + + nsCOMPtr wbStream = do_QueryInterface(webBrowser); + if (!wbStream) return NS_ERROR_FAILURE; + + return wbStream->AppendToStream(aData, aLen); +} + +nsresult +GeckoBrowser::CloseStream(void) +{ + nsCOMPtr webBrowser; + mWindow->GetWebBrowser(getter_AddRefs(webBrowser)); + + nsCOMPtr wbStream = do_QueryInterface(webBrowser); + if (!wbStream) return NS_ERROR_FAILURE; + + return wbStream->CloseStream(); +} +#endif + +void +GeckoBrowser::ContentStateChange(void) +{ + + // we don't attach listeners to chrome + if (mListenersAttached && !mIsChrome) + return; + + GetListener(); + + if (!mEventTarget) + return; + + AttachListeners(); + +} + +void +GeckoBrowser::ContentFinishedLoading(void) +{ + if (mIsChrome) { + // We're done loading. + mChromeLoaded = PR_TRUE; + + // get the web browser + nsCOMPtr webBrowser; + mWindow->GetWebBrowser(getter_AddRefs(webBrowser)); + + // get the content DOM window for that web browser + nsCOMPtr domWindow; + webBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); + if (!domWindow) { + NS_WARNING("no dom window in content finished loading\n"); + return; + } + + // resize the content + domWindow->SizeToContent(); + + // and since we're done loading show the window, assuming that the + // visibility flag has been set. + PRBool visibility; + mWindow->GetVisibility(&visibility); + if (visibility) + mWindow->SetVisibility(PR_TRUE); + } +} + +void +GeckoBrowser::ChildFocusIn(void) +{ + if (mIsDestroyed) + return; + + nsresult rv; + nsCOMPtr webBrowser; + rv = mWindow->GetWebBrowser(getter_AddRefs(webBrowser)); + if (NS_FAILED(rv)) + return; + + nsCOMPtr webBrowserFocus(do_QueryInterface(webBrowser)); + if (!webBrowserFocus) + return; + + webBrowserFocus->Activate(); +} + +void +GeckoBrowser::ChildFocusOut(void) +{ + if (mIsDestroyed) + return; + + nsresult rv; + nsCOMPtr webBrowser; + rv = mWindow->GetWebBrowser(getter_AddRefs(webBrowser)); + if (NS_FAILED(rv)) + return; + + nsCOMPtr webBrowserFocus(do_QueryInterface(webBrowser)); + if (!webBrowserFocus) + return; + + webBrowserFocus->Deactivate(); +} + +// Get the event listener for the chrome event handler. + +void +GeckoBrowser::GetListener(void) +{ + if (mEventTarget) + return; + + nsCOMPtr piWin; + GetPIDOMWindow(getter_AddRefs(piWin)); + + if (!piWin) + return; + + mEventTarget = do_QueryInterface(piWin->GetChromeEventHandler()); +} + +// attach key and mouse event listeners + +void +GeckoBrowser::AttachListeners(void) +{ + if (!mEventTarget || mListenersAttached) + return; + + nsIDOMEventListener *eventListener = + static_cast + (static_cast(mEventListener)); + + // add the key listener + nsresult rv; + rv = mEventTarget->AddEventListenerByIID(eventListener, + NS_GET_IID(nsIDOMKeyListener)); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to add key listener\n"); + return; + } + + rv = mEventTarget->AddEventListenerByIID(eventListener, + NS_GET_IID(nsIDOMMouseListener)); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to add mouse listener\n"); + return; + } + + rv = mEventTarget->AddEventListenerByIID(eventListener, + NS_GET_IID(nsIDOMUIListener)); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to add UI listener\n"); + return; + } + + rv = mEventTarget->AddEventListenerByIID(eventListener, + NS_GET_IID(nsIDOMContextMenuListener)); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to add context menu listener\n"); + return; + } + + // ok, all set. + mListenersAttached = PR_TRUE; +} + +void +GeckoBrowser::DetachListeners(void) +{ + if (!mListenersAttached || !mEventTarget) + return; + + nsIDOMEventListener *eventListener = + static_cast + (static_cast(mEventListener)); + + nsresult rv; + rv = mEventTarget->RemoveEventListenerByIID(eventListener, + NS_GET_IID(nsIDOMKeyListener)); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to remove key listener\n"); + return; + } + + rv = + mEventTarget->RemoveEventListenerByIID(eventListener, + NS_GET_IID(nsIDOMMouseListener)); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to remove mouse listener\n"); + return; + } + + rv = mEventTarget->RemoveEventListenerByIID(eventListener, + NS_GET_IID(nsIDOMUIListener)); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to remove UI listener\n"); + return; + } + + rv = mEventTarget->RemoveEventListenerByIID(eventListener, + NS_GET_IID(nsIDOMContextMenuListener)); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to remove context menu listener\n"); + return; + } + + mListenersAttached = PR_FALSE; +} + +nsresult +GeckoBrowser::GetPIDOMWindow(nsPIDOMWindow **aPIWin) +{ + *aPIWin = nsnull; + + // get the web browser + nsCOMPtr webBrowser; + mWindow->GetWebBrowser(getter_AddRefs(webBrowser)); + + // get the content DOM window for that web browser + nsCOMPtr domWindow; + webBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); + if (!domWindow) + return NS_ERROR_FAILURE; + + // get the private DOM window + nsCOMPtr domWindowPrivate = do_QueryInterface(domWindow); + // and the root window for that DOM window + *aPIWin = domWindowPrivate->GetPrivateRoot(); + + if (*aPIWin) { + NS_ADDREF(*aPIWin); + return NS_OK; + } + + return NS_ERROR_FAILURE; +} + +#ifdef MOZ_ACCESSIBILITY_ATK +// FIXME does this REALLY work with frames? +void * +GeckoBrowser::GetAtkObjectForCurrentDocument() +{ + if (!mNavigation) + return nsnull; + + nsCOMPtr accService = + do_GetService("@mozilla.org/accessibilityService;1"); + if (accService) { + //get current document + nsCOMPtr domDoc; + mNavigation->GetDocument(getter_AddRefs(domDoc)); + NS_ENSURE_TRUE(domDoc, nsnull); + + nsCOMPtr domNode(do_QueryInterface(domDoc)); + NS_ENSURE_TRUE(domNode, nsnull); + + nsCOMPtr acc; + accService->GetAccessibleFor(domNode, getter_AddRefs(acc)); + NS_ENSURE_TRUE(acc, nsnull); + + void *atkObj = nsnull; + if (NS_SUCCEEDED(acc->GetNativeInterface(&atkObj))) + return atkObj; + } + return nsnull; +} +#endif /* MOZ_ACCESSIBILITY_ATK */ -- cgit v1.2.3