diff options
Diffstat (limited to 'embed/xulrunner/src/EmbedWindow.cpp')
-rw-r--r-- | embed/xulrunner/src/EmbedWindow.cpp | 467 |
1 files changed, 467 insertions, 0 deletions
diff --git a/embed/xulrunner/src/EmbedWindow.cpp b/embed/xulrunner/src/EmbedWindow.cpp new file mode 100644 index 000000000..15c098f28 --- /dev/null +++ b/embed/xulrunner/src/EmbedWindow.cpp @@ -0,0 +1,467 @@ +/* + * 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 <blizzard@mozilla.org> + * --------------------------------------------------------------------------- + * + * $Id$ + */ + +#include <mozilla-config.h> +#include <config.h> + +#include <nsCWebBrowser.h> +#include <nsIComponentManager.h> +#include <nsComponentManagerUtils.h> +#include <nsIDocShellTreeItem.h> +#include "nsIWidget.h" + +#include "EmbedWindow.h" +#include "GeckoBrowser.h" + +#include "gecko-embed-signals.h" + +GtkWidget *EmbedWindow::sTipWindow = nsnull; + +EmbedWindow::EmbedWindow(void) +{ + mOwner = nsnull; + mVisibility = PR_FALSE; + mIsModal = PR_FALSE; +} + +EmbedWindow::~EmbedWindow(void) +{ + ExitModalEventLoop(PR_FALSE); +} + +nsresult +EmbedWindow::Init(GeckoBrowser *aOwner) +{ + // 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<nsIWebBrowserChrome *>(this)); + + nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(mWebBrowser); + item->SetItemType(nsIDocShellTreeItem::typeContentWrapper); + + return NS_OK; +} + +nsresult +EmbedWindow::CreateWindow(void) +{ + nsresult rv; + GtkWidget *ownerAsWidget = GTK_WIDGET(mOwner->mOwningWidget); + + // Get the base window interface for the web browser object and + // create the window. + mBaseWindow = do_QueryInterface(mWebBrowser); + rv = mBaseWindow->InitWindow(GTK_WIDGET(mOwner->mOwningWidget), + nsnull, + 0, 0, + ownerAsWidget->allocation.width, + ownerAsWidget->allocation.height); + if (NS_FAILED(rv)) + return rv; + + rv = mBaseWindow->Create(); + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} + +void +EmbedWindow::ReleaseChildren(void) +{ + ExitModalEventLoop(PR_FALSE); + + mBaseWindow->Destroy(); + mBaseWindow = 0; + mWebBrowser = 0; +} + +// nsISupports + +NS_IMPL_ADDREF(EmbedWindow) +NS_IMPL_RELEASE(EmbedWindow) + +NS_INTERFACE_MAP_BEGIN(EmbedWindow) + 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(nsIInterfaceRequestor) +NS_INTERFACE_MAP_END + +// nsIWebBrowserChrome + +NS_IMETHODIMP +EmbedWindow::SetStatus(PRUint32 aStatusType, const PRUnichar *aStatus) +{ + switch (aStatusType) { + case STATUS_SCRIPT: + { + mJSStatus = aStatus; + g_signal_emit (mOwner->mOwningWidget, gecko_embed_signals[JS_STATUS], 0); + } + break; + case STATUS_SCRIPT_DEFAULT: + // Gee, that's nice. + break; + case STATUS_LINK: + { + mLinkMessage = aStatus; + g_signal_emit (mOwner->mOwningWidget, gecko_embed_signals[LINK_MESSAGE], 0); + } + break; + } + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::GetWebBrowser(nsIWebBrowser **aWebBrowser) +{ + *aWebBrowser = mWebBrowser; + NS_IF_ADDREF(*aWebBrowser); + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::SetWebBrowser(nsIWebBrowser *aWebBrowser) +{ + mWebBrowser = aWebBrowser; + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::GetChromeFlags(PRUint32 *aChromeFlags) +{ + *aChromeFlags = mOwner->mChromeMask; + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::SetChromeFlags(PRUint32 aChromeFlags) +{ + mOwner->SetChromeMask(aChromeFlags); + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::DestroyBrowserWindow(void) +{ + // mark the owner as destroyed so it won't emit events anymore. + mOwner->mIsDestroyed = PR_TRUE; + + g_signal_emit (mOwner->mOwningWidget, gecko_embed_signals[DESTROY_BROWSER], 0); + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::SizeBrowserTo(PRInt32 aCX, PRInt32 aCY) +{ + g_signal_emit (mOwner->mOwningWidget, gecko_embed_signals[SIZE_TO], 0, aCX, aCY); + + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::ShowAsModal(void) +{ + mIsModal = PR_TRUE; + GtkWidget *toplevel; + toplevel = gtk_widget_get_toplevel(GTK_WIDGET(mOwner->mOwningWidget)); + gtk_grab_add(toplevel); + gtk_main(); + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::IsWindowModal(PRBool *_retval) +{ + *_retval = mIsModal; + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::ExitModalEventLoop(nsresult aStatus) +{ + if (mIsModal) { + GtkWidget *toplevel; + toplevel = gtk_widget_get_toplevel(GTK_WIDGET(mOwner->mOwningWidget)); + gtk_grab_remove(toplevel); + mIsModal = PR_FALSE; + gtk_main_quit(); + } + return NS_OK; +} + +// nsIWebBrowserChromeFocus + +NS_IMETHODIMP +EmbedWindow::FocusNextElement() +{ + GtkWidget *toplevel; + toplevel = gtk_widget_get_toplevel(GTK_WIDGET(mOwner->mOwningWidget)); + if (!GTK_WIDGET_TOPLEVEL(toplevel)) + return NS_OK; + + g_signal_emit_by_name (toplevel, "move_focus", GTK_DIR_TAB_FORWARD); + + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::FocusPrevElement() +{ + GtkWidget *toplevel; + toplevel = gtk_widget_get_toplevel(GTK_WIDGET(mOwner->mOwningWidget)); + if (!GTK_WIDGET_TOPLEVEL(toplevel)) + return NS_OK; + + g_signal_emit_by_name (toplevel, "move_focus", GTK_DIR_TAB_BACKWARD); + + return NS_OK; +} + +// nsIEmbeddingSiteWindow + +NS_IMETHODIMP +EmbedWindow::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 +EmbedWindow::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 +EmbedWindow::SetFocus(void) +{ + // XXX might have to do more here. + return mBaseWindow->SetFocus(); +} + +NS_IMETHODIMP +EmbedWindow::GetTitle(PRUnichar **aTitle) +{ + *aTitle = NS_StringCloneData(mTitle); + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::SetTitle(const PRUnichar *aTitle) +{ + mTitle = aTitle; + g_signal_emit (mOwner->mOwningWidget, gecko_embed_signals[TITLE], 0); + + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::GetSiteWindow(void **aSiteWindow) +{ + GtkWidget *ownerAsWidget (GTK_WIDGET(mOwner->mOwningWidget)); + *aSiteWindow = static_cast<void *>(ownerAsWidget); + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::GetVisibility(PRBool *aVisibility) +{ + // Work around the problem that sometimes the window + // is already visible even though mVisibility isn't true + // yet. + *aVisibility = mVisibility || + (!mOwner->mIsChrome && + mOwner->mOwningWidget && + GTK_WIDGET_MAPPED(mOwner->mOwningWidget)); + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::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 (mOwner->mOwningWidget, gecko_embed_signals[VISIBILITY], 0, + aVisibility); + return NS_OK; +} + +// nsITooltipListener + +static gboolean +tooltips_paint_window (GtkWidget *window) +{ + // draw tooltip style border around the text + gtk_paint_flat_box (window->style, window->window, + GTK_STATE_NORMAL, GTK_SHADOW_OUT, + NULL, window, "tooltip", + 0, 0, + window->allocation.width, window->allocation.height); + + return FALSE; +} + +NS_IMETHODIMP +EmbedWindow::OnShowTooltip(PRInt32 aXCoords, PRInt32 aYCoords, + const PRUnichar *aTipText) +{ + nsEmbedCString tipText; + + NS_UTF16ToCString(nsEmbedString(aTipText), + NS_CSTRING_ENCODING_UTF8, tipText); + + if (sTipWindow) + gtk_widget_destroy(sTipWindow); + + // get the root origin for this content window + nsCOMPtr<nsIWidget> mainWidget; + mBaseWindow->GetMainWidget(getter_AddRefs(mainWidget)); + GdkWindow *window; + window = static_cast<GdkWindow *> + (mainWidget->GetNativeData(NS_NATIVE_WINDOW)); + gint root_x, root_y; + gdk_window_get_origin(window, &root_x, &root_y); + + // XXX work around until I can get pink to figure out why + // tooltips vanish if they show up right at the origin of the + // cursor. + root_y += 10; + + sTipWindow = gtk_window_new(GTK_WINDOW_POPUP); + gtk_widget_set_app_paintable(sTipWindow, TRUE); + gtk_window_set_policy(GTK_WINDOW(sTipWindow), FALSE, FALSE, TRUE); + // needed to get colors + fonts etc correctly + gtk_widget_set_name(sTipWindow, "gtk-tooltips"); + + // set up the popup window as a transient of the widget. + GtkWidget *toplevel_window; + toplevel_window = gtk_widget_get_toplevel(GTK_WIDGET(mOwner->mOwningWidget)); + if (!GTK_WINDOW(toplevel_window)) { + NS_ERROR("no gtk window in hierarchy!\n"); + return NS_ERROR_FAILURE; + } + gtk_window_set_transient_for(GTK_WINDOW(sTipWindow), + GTK_WINDOW(toplevel_window)); + + // realize the widget + gtk_widget_realize(sTipWindow); + + g_signal_connect (G_OBJECT(sTipWindow), "expose-event", + G_CALLBACK(tooltips_paint_window), NULL); + + // set up the label for the tooltip + GtkWidget *label = gtk_label_new(tipText.get()); + // wrap automatically + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + gtk_container_add(GTK_CONTAINER(sTipWindow), label); + gtk_container_set_border_width(GTK_CONTAINER(sTipWindow), 4); + // set the coords for the widget + gtk_widget_set_uposition(sTipWindow, aXCoords + root_x, + aYCoords + root_y); + + // and show it. + gtk_widget_show_all(sTipWindow); + + return NS_OK; +} + +NS_IMETHODIMP +EmbedWindow::OnHideTooltip(void) +{ + if (sTipWindow) + gtk_widget_destroy(sTipWindow); + sTipWindow = NULL; + return NS_OK; +} + +// nsIInterfaceRequestor + +NS_IMETHODIMP +EmbedWindow::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<nsIInterfaceRequestor> ir = do_QueryInterface(mWebBrowser); + return ir->GetInterface(aIID, aInstancePtr); + } + + return rv; +} |