由于工作需要,研究了一下gecko的引擎嵌入的问题,花了三天多的时间,总算成功让gecko在Gtk控件下正确显示网页了。其实并不复杂,如果能找对正确的做法。基本思路是:
Makefile如下:
test.cpp如下:
#include "nsXPCOM.h"
#include "nscore.h"
#include "nsEmbedAPI.h"
#include "nsWeakReference.h"
#include "nsIWebBrowserChrome.h"
#include "nsIEmbeddingSiteWindow.h"
#include "nsCOMPtr.h"
#include "nsIInterfaceRequestor.h"
#include "nsEmbedString.h"
#include "nsIWebBrowser.h"
#include "widget/nsIBaseWindow.h"
#include "nsEmbedCID.h"
#include "nsComponentManagerUtils.h"
#include "nsIWebProgressListener.h"
#include "docshell/nsIWebNavigation.h"
#include "docshell/nsIDocShellTreeItem.h"
#include <iostream>
#include <gtk/gtk.h>

using namespace std;

class SillyBrowser: public nsIWebBrowserChrome,
public nsIEmbeddingSiteWindow,
public nsIInterfaceRequestor
{
public:
SillyBrowser();
~SillyBrowser();

NS_DECL_ISUPPORTS
NS_DECL_NSIWEBBROWSERCHROME
NS_DECL_NSIEMBEDDINGSITEWINDOW

NS_DECL_NSIINTERFACEREQUESTOR

GtkWidget* getMainWindow();
void init(nsIWebBrowser *aWebBrowser);
private:
GtkWidget *_mainWindow;
nsCOMPtr<nsIWebBrowser> _webBrowser;
nsCOMPtr<nsIBaseWindow> _baseWindow;
};


class ProgressListener: public nsIWebProgressListener,
public nsSupportsWeakReference // this is xpcom glue
{
public:
ProgressListener();
~ProgressListener();

NS_DECL_ISUPPORTS
NS_DECL_NSIWEBPROGRESSLISTENER

};

NS_IMPL_ISUPPORTS3(SillyBrowser, nsIWebBrowserChrome,
nsIEmbeddingSiteWindow, nsIInterfaceRequestor)

SillyBrowser::SillyBrowser()
{
_mainWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
g_signal_connect( G_OBJECT(_mainWindow), "delete_event",
gtk_main_quit, NULL );
gtk_widget_set_size_request( _mainWindow, 600, 400 );
}

SillyBrowser::~SillyBrowser()
{
gtk_widget_destroy( _mainWindow );
}

void SillyBrowser::init(nsIWebBrowser *aWebBrowser)
{
_webBrowser = aWebBrowser;
}

GtkWidget* SillyBrowser::getMainWindow()
{
return (GtkWidget*)_mainWindow;
}

NS_IMETHODIMP SillyBrowser::GetInterface(const nsIID &aIID, void** aInstancePtr)
{
nsresult rv;
rv = QueryInterface(aIID, aInstancePtr);
if ( NS_FAILED(rv) || *aInstancePtr ) {
nsCOMPtr<nsIInterfaceRequestor> ir = do_QueryInterface(_webBrowser);
return ir->GetInterface(aIID, aInstancePtr);
}

return rv;
}

NS_IMPL_ISUPPORTS2(ProgressListener, nsIWebProgressListener, nsISupportsWeakReference)

ProgressListener::ProgressListener()
{

}

ProgressListener::~ProgressListener()
{

}

//----------------- nsiwebprogresslistener ------------------------------//
/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aStateFlags, in nsresult aStatus); */
NS_IMETHODIMP ProgressListener::OnStateChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest, PRUint32 aStateFlags, nsresult aStatus)
{
cout << __FUNCTION__ << " called. ";
cout << " current state is " << (unsigned)aStateFlags << endl;
return NS_OK;
}

/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
NS_IMETHODIMP ProgressListener::OnProgressChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest, PRInt32 aCurSelfProgress, PRInt32 aMaxSelfProgress,
PRInt32 aCurTotalProgress, PRInt32 aMaxTotalProgress)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}

/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI aLocation); */
NS_IMETHODIMP ProgressListener::OnLocationChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest, nsIURI *aLocation)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}

/* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
NS_IMETHODIMP ProgressListener::OnStatusChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest, nsresult aStatus, const PRUnichar *aMessage)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}

/* void onSecurityChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aState); */
NS_IMETHODIMP ProgressListener::OnSecurityChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest, PRUint32 aState)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}

//---------------------

/* void setStatus (in unsigned long statusType, in wstring status); */
NS_IMETHODIMP SillyBrowser::SetStatus(PRUint32 statusType, const PRUnichar *status)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}

/* attribute nsIWebBrowser webBrowser; */
NS_IMETHODIMP SillyBrowser::GetWebBrowser(nsIWebBrowser * *aWebBrowser)
{
cout << __FUNCTION__ << " called. ";
*aWebBrowser = _webBrowser;
NS_IF_ADDREF(*aWebBrowser);
return NS_OK;
}

NS_IMETHODIMP SillyBrowser::SetWebBrowser(nsIWebBrowser * aWebBrowser)
{
cout << __FUNCTION__ << " called. ";
_webBrowser = aWebBrowser;
return NS_OK;
}

/* attribute unsigned long chromeFlags; */
NS_IMETHODIMP SillyBrowser::GetChromeFlags(PRUint32 *aChromeFlags)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}
NS_IMETHODIMP SillyBrowser::SetChromeFlags(PRUint32 aChromeFlags)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}

/* void destroyBrowserWindow (); */
NS_IMETHODIMP SillyBrowser::DestroyBrowserWindow()
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}

/* void sizeBrowserTo (in long aCX, in long aCY); */
NS_IMETHODIMP SillyBrowser::SizeBrowserTo(PRInt32 aCX, PRInt32 aCY)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}

/* void showAsModal (); */
NS_IMETHODIMP SillyBrowser::ShowAsModal()
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}

/* boolean isWindowModal (); */
NS_IMETHODIMP SillyBrowser::IsWindowModal(PRBool *_retval)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}

/* void exitModalEventLoop (in nsresult aStatus); */
NS_IMETHODIMP SillyBrowser::ExitModalEventLoop(nsresult aStatus)
{

cout << __FUNCTION__ << " called. ";
return NS_OK;
}


/* void setDimensions (in unsigned long flags, in long x, in long y, in long cx, in long cy); */
NS_IMETHODIMP SillyBrowser::SetDimensions(PRUint32 flags, PRInt32 x, PRInt32 y,
PRInt32 cx, PRInt32 cy)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}

/* void getDimensions (in unsigned long flags, out long x, out long y, out long cx, out long cy); */
NS_IMETHODIMP SillyBrowser::GetDimensions(PRUint32 flags, PRInt32 *x, PRInt32 *y,
PRInt32 *cx, PRInt32 *cy)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}

/* void setFocus (); */
NS_IMETHODIMP SillyBrowser::SetFocus()
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}

/* attribute boolean visibility; */
NS_IMETHODIMP SillyBrowser::GetVisibility(PRBool *aVisibility)
{
cout << __FUNCTION__ << " called. ";
*aVisibility = GTK_WIDGET_VISIBLE( _mainWindow );
if ( *aVisibility == PR_FALSE )
cout << __FUNCTION__ << ": not visible. ";
else
cout << __FUNCTION__ << ": visible. ";
return NS_OK;
}

NS_IMETHODIMP SillyBrowser::SetVisibility(PRBool aVisibility)
{
cout << __FUNCTION__ << " called. ";
if ( aVisibility == PR_TRUE ) {
gtk_widget_show_all( (GtkWidget*)_mainWindow );
} else
gtk_widget_hide( (GtkWidget*)_mainWindow );
return NS_OK;
}

/* attribute wstring title; */
NS_IMETHODIMP SillyBrowser::GetTitle(PRUnichar * *aTitle)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}

NS_IMETHODIMP SillyBrowser::SetTitle(const PRUnichar * aTitle)
{
cout << __FUNCTION__ << " called. ";
gtk_window_set_title( (GtkWindow*)_mainWindow, (char*)aTitle );
return NS_OK;
}

/* [noscript] readonly attribute voidPtr siteWindow; */
NS_IMETHODIMP SillyBrowser::GetSiteWindow(void * *aSiteWindow)
{
cout << __FUNCTION__ << " called. ";
*aSiteWindow = static_cast<void*>(_mainWindow);
return NS_OK;
}

int main(int argc, char *argv[])
{
gtk_init(&argc, &argv);

cout << "start embedding ";
char *curDir = nsnull;
if ( argc > 1 )
curDir = argv[1];
nsresult rv;

rv = NS_InitEmbedding( nsnull, nsnull );
if ( NS_FAILED(rv) ) {
cerr << "init embed failed. ";
exit(-1);
}
cout << "success init embed. ";

nsCOMPtr<nsIBaseWindow> baseWindow;
nsCOMPtr<nsIWebBrowser> webBrowser;
SillyBrowser *pSillyBrowser = new SillyBrowser();
ProgressListener *pProgressListener = new ProgressListener();

webBrowser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
cout << "webBrowser created. ";

pSillyBrowser->init( webBrowser );
pSillyBrowser->AddRef();
rv = webBrowser->SetContainerWindow((nsIWebBrowserChrome*)pSillyBrowser);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(webBrowser);
item->SetItemType( nsIDocShellTreeItem::typeContentWrapper );

baseWindow = do_QueryInterface(webBrowser, &rv);
if ( NS_FAILED(rv) ) return rv;
cout << "baseWindow queried. ";

GtkWidget *w = pSillyBrowser->getMainWindow();
rv = baseWindow->InitWindow((void*)w, nsnull,
0, 0, 600, 400 );
if (NS_FAILED(rv)) return rv;
cout << "InitWindow success. ";
rv = baseWindow->Create();
if (NS_FAILED(rv)) return rv;
cout << "baseWindow Create success. ";
nsCOMPtr<nsISupportsWeakReference> supportWeak = (nsISupportsWeakReference*)pProgressListener;
nsCOMPtr<nsIWeakReference> weakRef;
supportWeak->GetWeakReference( getter_AddRefs(weakRef) );

webBrowser->AddWebBrowserListener(weakRef, NS_GET_IID(nsIWebProgressListener));

baseWindow->SetVisibility( PR_TRUE );

nsCOMPtr<nsIWebNavigation> webNav( do_QueryInterface(webBrowser, &rv) );
if ( NS_FAILED(rv) ) return rv;
cout << " get nsIWebNavigation success. ";

PRUnichar uniURL[] = {
'w','w','w','.','s','i','n','a','.','c','o','m',''
};
char asciiURI[] = "http://www.google.com";
nsString nsURI = NS_ConvertUTF8toUTF16( asciiURI, strlen(asciiURI) );
if(webNav)
webNav->LoadURI(nsURI.get(),
nsIWebNavigation::LOAD_FLAGS_NONE, // Load flags
nsnull, // Referring URI
nsnull, // Post data
nsnull);
cout << "load uri success. ";
gtk_widget_show( w );
gtk_main();

rv = NS_TermEmbedding();
if ( NS_FAILED(rv) ) {
cerr << "term embed failed. ";
exit(-1);
}

return 0;
}
有几个关键问题是:
- 下载mozilla的cvs代码。参考moziila官方的说明。这里重要的是要选择checkout xulrunner。我在多次尝试后,发现只有xulrunner能够正常的运行自己写的demo和embedding的demo,当然官方提供的TestGtkEmbed在browser下跑时也会有问题,如果不想走弯路,xulrunner是正确的选择。.mozconfig参考如下:
ff_topsrc=/mnt/sda2/devel/mozilla
. ${ff_topsrc}/xulrunner/config/mozconfig
mk_add_options MOZ_OBJDIR=${ff_topsrc}/xulrunner-build
ac_add_options --enable-application=xulrunner
ac_add_options --enable-optimize
ac_add_options --enable-default-toolkit=cairo-gtk2
ac_add_options --enable-xft
ac_add_options --enable-shared
ac_add_options --disable-static
ac_add_options --enable-debug
ac_add_options --enable-libxul
ac_add_options --disable-tests
- 编译xulrunner。编译的.mozconfig文件中记得按照xulrunner编写,必须enable libxul。
Makefile如下:
MOZ_ROOT=/mnt/sda2/devel/mozilla/xulrunner-build
LDFLAGS=-lpthread -Wl,-rpath -Wl,${MOZ_ROOT}/dist/bin/ -Wl,-rpath -Wl,${MOZ_ROOT}/dist/lib
-L${MOZ_ROOT}/dist/lib/ -lxpcom -lnspr4
CXXFLAGS= -ggdb -fno-rtti -fno-exceptions -Wall -Wconversion -Wpointer-arith -Wcast-align
-Woverloaded-virtual -Wsynth -Wno-ctor-dtor-privacy -Wno-non-virtual-dtor -Wno-long-long -pedantic
-fshort-wchar -pthread -pipe -DNDEBUG -DTRIMMED -O -I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include
-I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/glib-2.0
-I/usr/lib/glib-2.0/include -I/usr/include/freetype2 -I/usr/include/libpng12
COMPILE_CFLAGS= -I ${MOZ_ROOT}/dist/include/system_wrappers
-include /mnt/sda2/devel/mozilla/config/gcc_hidden.h -DMOZILLA_STRICT_API
-DOSTYPE="Linux2.6.22" -DOSARCH=Linux -I ${MOZ_ROOT}/dist/include/xpcom
-I${MOZ_ROOT}/dist/include/intl -I${MOZ_ROOT}/dist/include/embedcomponents
-I${MOZ_ROOT}/dist/include -I${MOZ_ROOT}/dist/include/embed_base
-I${MOZ_ROOT}/dist/include/nspr -I${MOZ_ROOT}/dist/include/gtkembedmoz
-DMOZ_PNG_READ -DMOZ_PNG_WRITE -I${MOZ_ROOT}/dist/sdk/include
-Wall -W -Wno-unused -Wpointer-arith -Wcast-align -Wno-long-long -pedantic
-pthread -pipe -DNDEBUG -DTRIMMED -O -include ${MOZ_ROOT}/mozilla-config.h
-DMOZILLA_CLIENT

all: test

test: test.o
g++ -o test $(LDFLAGS) `pkg-config --libs gtk+-2.0` test.o ${MOZ_ROOT}/embedding/base/libembed_base_s.a ${MOZ_ROOT}/xpcom/glue/standalone/libxpcomglue.a

${MOZ_ROOT}/embedding/base/libembed_base_s.a

test.o: test.cpp
g++ -c $(CXXFLAGS) $(COMPILE_CFLAGS) `pkg-config --cflags gtk+-2.0` test.cpp

clean:
rm *.o test

LDFLAGS=-lpthread -Wl,-rpath -Wl,${MOZ_ROOT}/dist/bin/ -Wl,-rpath -Wl,${MOZ_ROOT}/dist/lib
-L${MOZ_ROOT}/dist/lib/ -lxpcom -lnspr4
CXXFLAGS= -ggdb -fno-rtti -fno-exceptions -Wall -Wconversion -Wpointer-arith -Wcast-align
-Woverloaded-virtual -Wsynth -Wno-ctor-dtor-privacy -Wno-non-virtual-dtor -Wno-long-long -pedantic
-fshort-wchar -pthread -pipe -DNDEBUG -DTRIMMED -O -I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include
-I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/glib-2.0
-I/usr/lib/glib-2.0/include -I/usr/include/freetype2 -I/usr/include/libpng12
COMPILE_CFLAGS= -I ${MOZ_ROOT}/dist/include/system_wrappers
-include /mnt/sda2/devel/mozilla/config/gcc_hidden.h -DMOZILLA_STRICT_API
-DOSTYPE="Linux2.6.22" -DOSARCH=Linux -I ${MOZ_ROOT}/dist/include/xpcom
-I${MOZ_ROOT}/dist/include/intl -I${MOZ_ROOT}/dist/include/embedcomponents
-I${MOZ_ROOT}/dist/include -I${MOZ_ROOT}/dist/include/embed_base
-I${MOZ_ROOT}/dist/include/nspr -I${MOZ_ROOT}/dist/include/gtkembedmoz
-DMOZ_PNG_READ -DMOZ_PNG_WRITE -I${MOZ_ROOT}/dist/sdk/include
-Wall -W -Wno-unused -Wpointer-arith -Wcast-align -Wno-long-long -pedantic
-pthread -pipe -DNDEBUG -DTRIMMED -O -include ${MOZ_ROOT}/mozilla-config.h
-DMOZILLA_CLIENT

all: test

test: test.o
g++ -o test $(LDFLAGS) `pkg-config --libs gtk+-2.0` test.o ${MOZ_ROOT}/embedding/base/libembed_base_s.a ${MOZ_ROOT}/xpcom/glue/standalone/libxpcomglue.a

${MOZ_ROOT}/embedding/base/libembed_base_s.a
test.o: test.cpp
g++ -c $(CXXFLAGS) $(COMPILE_CFLAGS) `pkg-config --cflags gtk+-2.0` test.cpp
clean:
rm *.o test
test.cpp如下:
#include "nsXPCOM.h"
#include "nscore.h"
#include "nsEmbedAPI.h"
#include "nsWeakReference.h"
#include "nsIWebBrowserChrome.h"
#include "nsIEmbeddingSiteWindow.h"
#include "nsCOMPtr.h"
#include "nsIInterfaceRequestor.h"
#include "nsEmbedString.h"
#include "nsIWebBrowser.h"
#include "widget/nsIBaseWindow.h"
#include "nsEmbedCID.h"
#include "nsComponentManagerUtils.h"
#include "nsIWebProgressListener.h"
#include "docshell/nsIWebNavigation.h"
#include "docshell/nsIDocShellTreeItem.h"
#include <iostream>
#include <gtk/gtk.h>
using namespace std;
class SillyBrowser: public nsIWebBrowserChrome,
public nsIEmbeddingSiteWindow,
public nsIInterfaceRequestor
{
public:
SillyBrowser();
~SillyBrowser();
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBBROWSERCHROME
NS_DECL_NSIEMBEDDINGSITEWINDOW
NS_DECL_NSIINTERFACEREQUESTOR
GtkWidget* getMainWindow();
void init(nsIWebBrowser *aWebBrowser);
private:
GtkWidget *_mainWindow;
nsCOMPtr<nsIWebBrowser> _webBrowser;
nsCOMPtr<nsIBaseWindow> _baseWindow;
};

class ProgressListener: public nsIWebProgressListener,public nsSupportsWeakReference // this is xpcom glue
{
public:
ProgressListener();
~ProgressListener();
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBPROGRESSLISTENER
};
NS_IMPL_ISUPPORTS3(SillyBrowser, nsIWebBrowserChrome,
nsIEmbeddingSiteWindow, nsIInterfaceRequestor)
SillyBrowser::SillyBrowser()
{
_mainWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
g_signal_connect( G_OBJECT(_mainWindow), "delete_event",
gtk_main_quit, NULL );
gtk_widget_set_size_request( _mainWindow, 600, 400 );
}
SillyBrowser::~SillyBrowser()
{
gtk_widget_destroy( _mainWindow );
}
void SillyBrowser::init(nsIWebBrowser *aWebBrowser)
{
_webBrowser = aWebBrowser;
}
GtkWidget* SillyBrowser::getMainWindow()
{
return (GtkWidget*)_mainWindow;
}
NS_IMETHODIMP SillyBrowser::GetInterface(const nsIID &aIID, void** aInstancePtr)
{
nsresult rv;
rv = QueryInterface(aIID, aInstancePtr);
if ( NS_FAILED(rv) || *aInstancePtr ) {
nsCOMPtr<nsIInterfaceRequestor> ir = do_QueryInterface(_webBrowser);
return ir->GetInterface(aIID, aInstancePtr);
}
return rv;
}
NS_IMPL_ISUPPORTS2(ProgressListener, nsIWebProgressListener, nsISupportsWeakReference)
ProgressListener::ProgressListener()
{
}
ProgressListener::~ProgressListener()
{
}
//----------------- nsiwebprogresslistener ------------------------------//
/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aStateFlags, in nsresult aStatus); */
NS_IMETHODIMP ProgressListener::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 aStateFlags, nsresult aStatus)
{
cout << __FUNCTION__ << " called. ";
cout << " current state is " << (unsigned)aStateFlags << endl;
return NS_OK;
}
/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
NS_IMETHODIMP ProgressListener::OnProgressChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRInt32 aCurSelfProgress, PRInt32 aMaxSelfProgress,
PRInt32 aCurTotalProgress, PRInt32 aMaxTotalProgress)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}
/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI aLocation); */
NS_IMETHODIMP ProgressListener::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *aLocation)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}
/* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
NS_IMETHODIMP ProgressListener::OnStatusChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsresult aStatus, const PRUnichar *aMessage)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}
/* void onSecurityChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aState); */
NS_IMETHODIMP ProgressListener::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 aState)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}
//---------------------
/* void setStatus (in unsigned long statusType, in wstring status); */
NS_IMETHODIMP SillyBrowser::SetStatus(PRUint32 statusType, const PRUnichar *status)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}
/* attribute nsIWebBrowser webBrowser; */
NS_IMETHODIMP SillyBrowser::GetWebBrowser(nsIWebBrowser * *aWebBrowser)
{
cout << __FUNCTION__ << " called. ";
*aWebBrowser = _webBrowser;
NS_IF_ADDREF(*aWebBrowser);
return NS_OK;
}
NS_IMETHODIMP SillyBrowser::SetWebBrowser(nsIWebBrowser * aWebBrowser)
{
cout << __FUNCTION__ << " called. ";
_webBrowser = aWebBrowser;
return NS_OK;
}
/* attribute unsigned long chromeFlags; */
NS_IMETHODIMP SillyBrowser::GetChromeFlags(PRUint32 *aChromeFlags)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}
NS_IMETHODIMP SillyBrowser::SetChromeFlags(PRUint32 aChromeFlags)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}
/* void destroyBrowserWindow (); */
NS_IMETHODIMP SillyBrowser::DestroyBrowserWindow()
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}
/* void sizeBrowserTo (in long aCX, in long aCY); */
NS_IMETHODIMP SillyBrowser::SizeBrowserTo(PRInt32 aCX, PRInt32 aCY)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}
/* void showAsModal (); */
NS_IMETHODIMP SillyBrowser::ShowAsModal()
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}
/* boolean isWindowModal (); */
NS_IMETHODIMP SillyBrowser::IsWindowModal(PRBool *_retval)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}
/* void exitModalEventLoop (in nsresult aStatus); */
NS_IMETHODIMP SillyBrowser::ExitModalEventLoop(nsresult aStatus)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}

/* void setDimensions (in unsigned long flags, in long x, in long y, in long cx, in long cy); */
NS_IMETHODIMP SillyBrowser::SetDimensions(PRUint32 flags, PRInt32 x, PRInt32 y,
PRInt32 cx, PRInt32 cy)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}
/* void getDimensions (in unsigned long flags, out long x, out long y, out long cx, out long cy); */
NS_IMETHODIMP SillyBrowser::GetDimensions(PRUint32 flags, PRInt32 *x, PRInt32 *y,PRInt32 *cx, PRInt32 *cy)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}
/* void setFocus (); */
NS_IMETHODIMP SillyBrowser::SetFocus()
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}
/* attribute boolean visibility; */
NS_IMETHODIMP SillyBrowser::GetVisibility(PRBool *aVisibility)
{
cout << __FUNCTION__ << " called. ";
*aVisibility = GTK_WIDGET_VISIBLE( _mainWindow );
if ( *aVisibility == PR_FALSE )
cout << __FUNCTION__ << ": not visible. ";
else
cout << __FUNCTION__ << ": visible. ";
return NS_OK;
}
NS_IMETHODIMP SillyBrowser::SetVisibility(PRBool aVisibility)
{
cout << __FUNCTION__ << " called. ";
if ( aVisibility == PR_TRUE ) {
gtk_widget_show_all( (GtkWidget*)_mainWindow );
} else
gtk_widget_hide( (GtkWidget*)_mainWindow );
return NS_OK;
}
/* attribute wstring title; */
NS_IMETHODIMP SillyBrowser::GetTitle(PRUnichar * *aTitle)
{
cout << __FUNCTION__ << " called. ";
return NS_OK;
}
NS_IMETHODIMP SillyBrowser::SetTitle(const PRUnichar * aTitle)
{
cout << __FUNCTION__ << " called. ";
gtk_window_set_title( (GtkWindow*)_mainWindow, (char*)aTitle );
return NS_OK;
}
/* [noscript] readonly attribute voidPtr siteWindow; */
NS_IMETHODIMP SillyBrowser::GetSiteWindow(void * *aSiteWindow)
{
cout << __FUNCTION__ << " called. ";
*aSiteWindow = static_cast<void*>(_mainWindow);
return NS_OK;
}
int main(int argc, char *argv[])
{
gtk_init(&argc, &argv);
cout << "start embedding ";
char *curDir = nsnull;
if ( argc > 1 )
curDir = argv[1];
nsresult rv;
rv = NS_InitEmbedding( nsnull, nsnull );
if ( NS_FAILED(rv) ) {
cerr << "init embed failed. ";
exit(-1);
}
cout << "success init embed. ";
nsCOMPtr<nsIBaseWindow> baseWindow;
nsCOMPtr<nsIWebBrowser> webBrowser;
SillyBrowser *pSillyBrowser = new SillyBrowser();
ProgressListener *pProgressListener = new ProgressListener();
webBrowser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
cout << "webBrowser created. ";
pSillyBrowser->init( webBrowser );
pSillyBrowser->AddRef();
rv = webBrowser->SetContainerWindow((nsIWebBrowserChrome*)pSillyBrowser);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(webBrowser);
item->SetItemType( nsIDocShellTreeItem::typeContentWrapper );
baseWindow = do_QueryInterface(webBrowser, &rv);
if ( NS_FAILED(rv) ) return rv;
cout << "baseWindow queried. ";
GtkWidget *w = pSillyBrowser->getMainWindow();
rv = baseWindow->InitWindow((void*)w, nsnull,
0, 0, 600, 400 );
if (NS_FAILED(rv)) return rv;
cout << "InitWindow success. ";
rv = baseWindow->Create();
if (NS_FAILED(rv)) return rv;
cout << "baseWindow Create success. ";
nsCOMPtr<nsISupportsWeakReference> supportWeak = (nsISupportsWeakReference*)pProgressListener;
nsCOMPtr<nsIWeakReference> weakRef;
supportWeak->GetWeakReference( getter_AddRefs(weakRef) );
webBrowser->AddWebBrowserListener(weakRef, NS_GET_IID(nsIWebProgressListener));
baseWindow->SetVisibility( PR_TRUE );
nsCOMPtr<nsIWebNavigation> webNav( do_QueryInterface(webBrowser, &rv) );
if ( NS_FAILED(rv) ) return rv;
cout << " get nsIWebNavigation success. ";
PRUnichar uniURL[] = {
'w','w','w','.','s','i','n','a','.','c','o','m',''
};
char asciiURI[] = "http://www.google.com";
nsString nsURI = NS_ConvertUTF8toUTF16( asciiURI, strlen(asciiURI) );
if(webNav)
webNav->LoadURI(nsURI.get(),
nsIWebNavigation::LOAD_FLAGS_NONE, // Load flags
nsnull, // Referring URI
nsnull, // Post data
nsnull);
cout << "load uri success. ";
gtk_widget_show( w );
gtk_main();
rv = NS_TermEmbedding();
if ( NS_FAILED(rv) ) {
cerr << "term embed failed. ";
exit(-1);
}
return 0;
}
有几个关键问题是:
- 我的目的是将gecko嵌入QT中,但是后来发现gecko的nsIBaseWindow在内部管理的窗口是gtk句柄的,因此你是没法直接使用Qt或者其他的非Gtk控件作为容器父控件的。所以正确的做法是用一个GtkWindow作为容器,然后再将此控件嵌入QT的控件中。
- 正确理解nsCOMPtr、nsWeakPtr等对象管理方法。错误的使用可能导致莫名奇妙的问题。
- 更好的方法也可以是使用mozilla提供的libxpcomglue来作嵌入的初始化,它将帮组用户找到正确的GRE。
- 如果要运行TestGtkEmbed,记住要export GRE_HOME=${MOZ_OBJDIR}/dist/bin/ 来指定GRE的目录。没有这一步,会提示说找不到GRE。然后在此目录使用./run-mozilla.sh ./TestGetEmbed运行测试。
本文介绍了如何下载Mozilla的cvs代码并选择xulrunner进行编译,以实现Gecko引擎的正确嵌入。重点在于理解nsCOMPtr和nsWeakPtr的使用,以及通过libxpcomglue库简化初始化过程。同时,由于Gecko内部管理窗口使用gtk,因此需要使用GtkWindow作为容器,再将其嵌入到QT控件中。

2236

被折叠的 条评论
为什么被折叠?



