Back to index

lightning-sunbird  0.9+nobinonly
EmbedWindow.cpp
Go to the documentation of this file.
00001 /*
00002  * vim:ts=2:et:sw=2
00003  *
00004  * ***** BEGIN LICENSE BLOCK *****
00005  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  * The contents of this file are subject to the Mozilla Public License Version
00008  * 1.1 (the "License"); you may not use this file except in compliance with
00009  * the License. You may obtain a copy of the License at
00010  * http://www.mozilla.org/MPL/
00011  *
00012  * Software distributed under the License is distributed on an "AS IS" basis,
00013  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00014  * for the specific language governing rights and limitations under the
00015  * License.
00016  *
00017  * The Original Code is mozilla.org code.
00018  *
00019  * The Initial Developer of the Original Code is
00020  * Christopher Blizzard. Portions created by Christopher Blizzard are Copyright (C) Christopher Blizzard.  All Rights Reserved.
00021  * Portions created by the Initial Developer are Copyright (C) 2001
00022  * the Initial Developer. All Rights Reserved.
00023  *
00024  * Contributor(s):
00025  *   Christopher Blizzard <blizzard@mozilla.org>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either the GNU General Public License Version 2 or later (the "GPL"), or
00029  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #include <nsCWebBrowser.h>
00042 #include <nsIComponentManager.h>
00043 #include <nsIDocShellTreeItem.h>
00044 #include "nsIWidget.h"
00045 #include "nsReadableUtils.h"
00046 
00047 #include "EmbedWindow.h"
00048 #include "EmbedPrivate.h"
00049 #include "EmbedPrompter.h"
00050 
00051 GtkWidget *EmbedWindow::sTipWindow = nsnull;
00052 
00053 EmbedWindow::EmbedWindow(void)
00054 {
00055   mOwner       = nsnull;
00056   mVisibility  = PR_FALSE;
00057   mIsModal     = PR_FALSE;
00058 }
00059 
00060 EmbedWindow::~EmbedWindow(void)
00061 {
00062   ExitModalEventLoop(PR_FALSE);
00063 }
00064 
00065 nsresult
00066 EmbedWindow::Init(EmbedPrivate *aOwner)
00067 {
00068   // save our owner for later
00069   mOwner = aOwner;
00070 
00071   // create our nsIWebBrowser object and set up some basic defaults.
00072   mWebBrowser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID);
00073   if (!mWebBrowser)
00074     return NS_ERROR_FAILURE;
00075 
00076   mWebBrowser->SetContainerWindow(NS_STATIC_CAST(nsIWebBrowserChrome *, this));
00077   
00078   nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(mWebBrowser);
00079   item->SetItemType(nsIDocShellTreeItem::typeContentWrapper);
00080 
00081   return NS_OK;
00082 }
00083 
00084 nsresult
00085 EmbedWindow::CreateWindow(void)
00086 {
00087   nsresult rv;
00088   GtkWidget *ownerAsWidget = GTK_WIDGET(mOwner->mOwningWidget);
00089 
00090   // Get the base window interface for the web browser object and
00091   // create the window.
00092   mBaseWindow = do_QueryInterface(mWebBrowser);
00093   rv = mBaseWindow->InitWindow(GTK_WIDGET(mOwner->mOwningWidget),
00094                             nsnull,
00095                             0, 0, 
00096                             ownerAsWidget->allocation.width,
00097                             ownerAsWidget->allocation.height);
00098   if (NS_FAILED(rv))
00099     return rv;
00100 
00101   rv = mBaseWindow->Create();
00102   if (NS_FAILED(rv))
00103     return rv;
00104 
00105   return NS_OK;
00106 }
00107 
00108 void
00109 EmbedWindow::ReleaseChildren(void)
00110 {
00111   ExitModalEventLoop(PR_FALSE);
00112     
00113   mBaseWindow->Destroy();
00114   mBaseWindow = 0;
00115   mWebBrowser = 0;
00116 }
00117 
00118 // nsISupports
00119 
00120 NS_IMPL_ADDREF(EmbedWindow)
00121 NS_IMPL_RELEASE(EmbedWindow)
00122 
00123 NS_INTERFACE_MAP_BEGIN(EmbedWindow)
00124   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowserChrome)
00125   NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
00126   NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChromeFocus)
00127   NS_INTERFACE_MAP_ENTRY(nsIEmbeddingSiteWindow)
00128   NS_INTERFACE_MAP_ENTRY(nsITooltipListener)
00129   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
00130 NS_INTERFACE_MAP_END
00131 
00132 // nsIWebBrowserChrome
00133 
00134 NS_IMETHODIMP
00135 EmbedWindow::SetStatus(PRUint32 aStatusType, const PRUnichar *aStatus)
00136 {
00137   switch (aStatusType) {
00138   case STATUS_SCRIPT: 
00139     {
00140       mJSStatus = aStatus;
00141       gtk_signal_emit(GTK_OBJECT(mOwner->mOwningWidget),
00142                     moz_embed_signals[JS_STATUS]);
00143     }
00144     break;
00145   case STATUS_SCRIPT_DEFAULT:
00146     // Gee, that's nice.
00147     break;
00148   case STATUS_LINK:
00149     {
00150       mLinkMessage = aStatus;
00151       gtk_signal_emit(GTK_OBJECT(mOwner->mOwningWidget),
00152                     moz_embed_signals[LINK_MESSAGE]);
00153     }
00154     break;
00155   }
00156   return NS_OK;
00157 }
00158 
00159 NS_IMETHODIMP
00160 EmbedWindow::GetWebBrowser(nsIWebBrowser **aWebBrowser)
00161 {
00162   *aWebBrowser = mWebBrowser;
00163   NS_IF_ADDREF(*aWebBrowser);
00164   return NS_OK;
00165 }
00166 
00167 NS_IMETHODIMP
00168 EmbedWindow::SetWebBrowser(nsIWebBrowser *aWebBrowser)
00169 {
00170   mWebBrowser = aWebBrowser;
00171   return NS_OK;
00172 }
00173 
00174 NS_IMETHODIMP
00175 EmbedWindow::GetChromeFlags(PRUint32 *aChromeFlags)
00176 {
00177   *aChromeFlags = mOwner->mChromeMask;
00178   return NS_OK;
00179 }
00180 
00181 NS_IMETHODIMP
00182 EmbedWindow::SetChromeFlags(PRUint32 aChromeFlags)
00183 {
00184   mOwner->SetChromeMask(aChromeFlags);
00185   return NS_OK;
00186 }
00187 
00188 NS_IMETHODIMP
00189 EmbedWindow::DestroyBrowserWindow(void)
00190 {
00191   // mark the owner as destroyed so it won't emit events anymore.
00192   mOwner->mIsDestroyed = PR_TRUE;
00193 
00194   gtk_signal_emit(GTK_OBJECT(mOwner->mOwningWidget),
00195                 moz_embed_signals[DESTROY_BROWSER]);
00196   return NS_OK;
00197 }
00198 
00199 NS_IMETHODIMP
00200 EmbedWindow::SizeBrowserTo(PRInt32 aCX, PRInt32 aCY)
00201 {
00202   gtk_signal_emit(GTK_OBJECT(mOwner->mOwningWidget),
00203                 moz_embed_signals[SIZE_TO], aCX, aCY);
00204   return NS_OK;
00205 }
00206 
00207 NS_IMETHODIMP
00208 EmbedWindow::ShowAsModal(void)
00209 {
00210   mIsModal = PR_TRUE;
00211   GtkWidget *toplevel;
00212   toplevel = gtk_widget_get_toplevel(GTK_WIDGET(mOwner->mOwningWidget));
00213   gtk_grab_add(toplevel);
00214   gtk_main();
00215   return NS_OK;
00216 }
00217 
00218 NS_IMETHODIMP
00219 EmbedWindow::IsWindowModal(PRBool *_retval)
00220 {
00221   *_retval = mIsModal;
00222   return NS_OK;
00223 }
00224 
00225 NS_IMETHODIMP
00226 EmbedWindow::ExitModalEventLoop(nsresult aStatus)
00227 {
00228   if (mIsModal) {
00229     GtkWidget *toplevel;
00230     toplevel = gtk_widget_get_toplevel(GTK_WIDGET(mOwner->mOwningWidget));
00231     gtk_grab_remove(toplevel);
00232     mIsModal = PR_FALSE;
00233     gtk_main_quit();
00234   }
00235   return NS_OK;
00236 }
00237 
00238 // nsIWebBrowserChromeFocus
00239 
00240 NS_IMETHODIMP
00241 EmbedWindow::FocusNextElement()
00242 {
00243 #ifdef MOZ_WIDGET_GTK
00244   GtkWidget* parent = GTK_WIDGET(mOwner->mOwningWidget)->parent;
00245 
00246   if (GTK_IS_CONTAINER(parent))
00247     gtk_container_focus(GTK_CONTAINER(parent),
00248                         GTK_DIR_TAB_FORWARD);
00249 #endif
00250 
00251 #ifdef MOZ_WIDGET_GTK2
00252   GtkWidget *toplevel;
00253   toplevel = gtk_widget_get_toplevel(GTK_WIDGET(mOwner->mOwningWidget));
00254   if (!GTK_WIDGET_TOPLEVEL(toplevel))
00255     return NS_OK;
00256 
00257   g_signal_emit_by_name(G_OBJECT(toplevel), "move_focus",
00258                      GTK_DIR_TAB_FORWARD);
00259 #endif
00260 
00261   return NS_OK;
00262 }
00263 
00264 NS_IMETHODIMP
00265 EmbedWindow::FocusPrevElement()
00266 {
00267 #ifdef MOZ_WIDGET_GTK
00268   GtkWidget* parent = GTK_WIDGET(mOwner->mOwningWidget)->parent;
00269 
00270   if (GTK_IS_CONTAINER(parent))
00271     gtk_container_focus(GTK_CONTAINER(parent),
00272                         GTK_DIR_TAB_BACKWARD);
00273 #endif
00274 
00275 #ifdef MOZ_WIDGET_GTK2
00276   GtkWidget *toplevel;
00277   toplevel = gtk_widget_get_toplevel(GTK_WIDGET(mOwner->mOwningWidget));
00278   if (!GTK_WIDGET_TOPLEVEL(toplevel))
00279     return NS_OK;
00280 
00281   g_signal_emit_by_name(G_OBJECT(toplevel), "move_focus",
00282                      GTK_DIR_TAB_BACKWARD);
00283 #endif
00284 
00285   return NS_OK;
00286 }
00287 
00288 // nsIEmbeddingSiteWindow
00289 
00290 NS_IMETHODIMP
00291 EmbedWindow::SetDimensions(PRUint32 aFlags, PRInt32 aX, PRInt32 aY,
00292                         PRInt32 aCX, PRInt32 aCY)
00293 {
00294   if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION &&
00295       (aFlags & (nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_INNER |
00296                nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER))) {
00297     return mBaseWindow->SetPositionAndSize(aX, aY, aCX, aCY, PR_TRUE);
00298   }
00299   else if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION) {
00300     return mBaseWindow->SetPosition(aX, aY);
00301   }
00302   else if (aFlags & (nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_INNER |
00303                    nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER)) {
00304     return mBaseWindow->SetSize(aCX, aCY, PR_TRUE);
00305   }
00306   return NS_ERROR_INVALID_ARG;
00307 }
00308 
00309 NS_IMETHODIMP
00310 EmbedWindow::GetDimensions(PRUint32 aFlags, PRInt32 *aX,
00311                         PRInt32 *aY, PRInt32 *aCX, PRInt32 *aCY)
00312 {
00313   if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION &&
00314       (aFlags & (nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_INNER |
00315                nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER))) {
00316     return mBaseWindow->GetPositionAndSize(aX, aY, aCX, aCY);
00317   }
00318   else if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION) {
00319     return mBaseWindow->GetPosition(aX, aY);
00320   }
00321   else if (aFlags & (nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_INNER |
00322                    nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER)) {
00323     return mBaseWindow->GetSize(aCX, aCY);
00324   }
00325   return NS_ERROR_INVALID_ARG;
00326 }
00327 
00328 NS_IMETHODIMP
00329 EmbedWindow::SetFocus(void)
00330 {
00331   // XXX might have to do more here.
00332   return mBaseWindow->SetFocus();
00333 }
00334 
00335 NS_IMETHODIMP
00336 EmbedWindow::GetTitle(PRUnichar **aTitle)
00337 {
00338   *aTitle = ToNewUnicode(mTitle);
00339   return NS_OK;
00340 }
00341 
00342 NS_IMETHODIMP
00343 EmbedWindow::SetTitle(const PRUnichar *aTitle)
00344 {
00345   mTitle = aTitle;
00346   gtk_signal_emit(GTK_OBJECT(mOwner->mOwningWidget),
00347                 moz_embed_signals[TITLE]);
00348   return NS_OK;
00349 }
00350 
00351 NS_IMETHODIMP
00352 EmbedWindow::GetSiteWindow(void **aSiteWindow)
00353 {
00354   GtkWidget *ownerAsWidget (GTK_WIDGET(mOwner->mOwningWidget));
00355   *aSiteWindow = NS_STATIC_CAST(void *, ownerAsWidget);
00356   return NS_OK;
00357 }
00358 
00359 NS_IMETHODIMP
00360 EmbedWindow::GetVisibility(PRBool *aVisibility)
00361 {
00362   // Work around the problem that sometimes the window
00363   // is already visible even though mVisibility isn't true
00364   // yet.
00365   *aVisibility = mVisibility ||
00366                  (!mOwner->mIsChrome &&
00367                   mOwner->mOwningWidget &&
00368                   GTK_WIDGET_MAPPED(mOwner->mOwningWidget));
00369   return NS_OK;
00370 }
00371 
00372 NS_IMETHODIMP
00373 EmbedWindow::SetVisibility(PRBool aVisibility)
00374 {
00375   // We always set the visibility so that if it's chrome and we finish
00376   // the load we know that we have to show the window.
00377   mVisibility = aVisibility;
00378 
00379   // if this is a chrome window and the chrome hasn't finished loading
00380   // yet then don't show the window yet.
00381   if (mOwner->mIsChrome && !mOwner->mChromeLoaded)
00382     return NS_OK;
00383 
00384   gtk_signal_emit(GTK_OBJECT(mOwner->mOwningWidget),
00385                 moz_embed_signals[VISIBILITY],
00386                 aVisibility);
00387   return NS_OK;
00388 }
00389 
00390 // nsITooltipListener
00391 
00392 static gint
00393 tooltips_paint_window(GtkWidget *window)
00394 {
00395   // draw tooltip style border around the text
00396   gtk_paint_flat_box(window->style, window->window,
00397                      GTK_STATE_NORMAL, GTK_SHADOW_OUT,
00398                      NULL, window, "tooltip",
00399                      0, 0,
00400                      window->allocation.width, window->allocation.height);
00401 
00402   return FALSE;
00403 }
00404                                      
00405 NS_IMETHODIMP
00406 EmbedWindow::OnShowTooltip(PRInt32 aXCoords, PRInt32 aYCoords,
00407                         const PRUnichar *aTipText)
00408 {
00409   nsAutoString tipText ( aTipText );
00410 
00411 #ifdef MOZ_WIDGET_GTK
00412   const char* tipString = ToNewCString(tipText);
00413 #endif
00414 
00415 #ifdef MOZ_WIDGET_GTK2
00416   const char* tipString = ToNewUTF8String(tipText);
00417 #endif
00418 
00419   if (sTipWindow)
00420     gtk_widget_destroy(sTipWindow);
00421   
00422   // get the root origin for this content window
00423   nsCOMPtr<nsIWidget> mainWidget;
00424   mBaseWindow->GetMainWidget(getter_AddRefs(mainWidget));
00425   GdkWindow *window;
00426   window = NS_STATIC_CAST(GdkWindow *,
00427                        mainWidget->GetNativeData(NS_NATIVE_WINDOW));
00428   gint root_x, root_y;
00429   gdk_window_get_origin(window, &root_x, &root_y);
00430 
00431   // XXX work around until I can get pink to figure out why
00432   // tooltips vanish if they show up right at the origin of the
00433   // cursor.
00434   root_y += 10;
00435   
00436   sTipWindow = gtk_window_new(GTK_WINDOW_POPUP);
00437   gtk_widget_set_app_paintable(sTipWindow, TRUE);
00438   gtk_window_set_policy(GTK_WINDOW(sTipWindow), FALSE, FALSE, TRUE);
00439   // needed to get colors + fonts etc correctly
00440   gtk_widget_set_name(sTipWindow, "gtk-tooltips");
00441   
00442   // set up the popup window as a transient of the widget.
00443   GtkWidget *toplevel_window;
00444   toplevel_window = gtk_widget_get_toplevel(GTK_WIDGET(mOwner->mOwningWidget));
00445   if (!GTK_WINDOW(toplevel_window)) {
00446     NS_ERROR("no gtk window in hierarchy!\n");
00447     return NS_ERROR_FAILURE;
00448   }
00449   gtk_window_set_transient_for(GTK_WINDOW(sTipWindow),
00450                             GTK_WINDOW(toplevel_window));
00451   
00452   // realize the widget
00453   gtk_widget_realize(sTipWindow);
00454 
00455   gtk_signal_connect(GTK_OBJECT(sTipWindow), "expose_event",
00456                      GTK_SIGNAL_FUNC(tooltips_paint_window), NULL);
00457 
00458   // set up the label for the tooltip
00459   GtkWidget *label = gtk_label_new(tipString);
00460   // wrap automatically
00461   gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
00462   gtk_container_add(GTK_CONTAINER(sTipWindow), label);
00463   gtk_container_set_border_width(GTK_CONTAINER(sTipWindow), 4);
00464   // set the coords for the widget
00465   gtk_widget_set_uposition(sTipWindow, aXCoords + root_x,
00466                         aYCoords + root_y);
00467 
00468   // and show it.
00469   gtk_widget_show_all(sTipWindow);
00470 
00471 #ifdef MOZ_WIDGET_GTK
00472   gtk_widget_popup(sTipWindow, aXCoords + root_x, aYCoords + root_y);
00473 #endif /* MOZ_WIDGET_GTK */
00474   
00475   nsMemory::Free( (void*)tipString );
00476 
00477   return NS_OK;
00478 }
00479 
00480 NS_IMETHODIMP
00481 EmbedWindow::OnHideTooltip(void)
00482 {
00483   if (sTipWindow)
00484     gtk_widget_destroy(sTipWindow);
00485   sTipWindow = NULL;
00486   return NS_OK;
00487 }
00488 
00489 // nsIInterfaceRequestor
00490 
00491 NS_IMETHODIMP
00492 EmbedWindow::GetInterface(const nsIID &aIID, void** aInstancePtr)
00493 {
00494   nsresult rv;
00495   
00496   rv = QueryInterface(aIID, aInstancePtr);
00497 
00498   // pass it up to the web browser object
00499   if (NS_FAILED(rv) || !*aInstancePtr) {
00500     nsCOMPtr<nsIInterfaceRequestor> ir = do_QueryInterface(mWebBrowser);
00501     return ir->GetInterface(aIID, aInstancePtr);
00502   }
00503 
00504   return rv;
00505 }