/* * 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 #include #include #include #include #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(this)); nsCOMPtr 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(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 mainWidget; mBaseWindow->GetMainWidget(getter_AddRefs(mainWidget)); GdkWindow *window; window = static_cast (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 ir = do_QueryInterface(mWebBrowser); return ir->GetInterface(aIID, aInstancePtr); } return rv; }