Land the remote-tab code from tmp-electrolysis.
authorBenjamin Smedberg <benjamin@smedbergs.us>
Tue, 30 Jun 2009 16:39:22 -0400
changeset 35743 2514fa68b1784bd1d9c94b47663c787237afda0e
parent 35742 042ca6009da4e1e8b55390544a9a38aa3e1dc846
child 35744 768081a8a21175c0a2cae6313cc2fc914e413f9b
push idunknown
push userunknown
push dateunknown
milestone1.9.2a1pre
Land the remote-tab code from tmp-electrolysis.
content/base/src/Makefile.in
content/base/src/nsFrameLoader.cpp
content/base/src/nsFrameLoader.h
docshell/base/nsDocShell.cpp
dom/Makefile.in
dom/ipc/IFrameEmbedding.ipdl
dom/ipc/IFrameEmbeddingProtocol.h
dom/ipc/IFrameEmbeddingProtocolChild.h
dom/ipc/IFrameEmbeddingProtocolParent.h
dom/ipc/Makefile.in
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
dom/ipc/TabProcessParent.cpp
dom/ipc/TabProcessParent.h
dom/ipc/TabThread.cpp
dom/ipc/TabThread.h
dom/ipc/TabTypes.h
dom/ipc/app/Makefile.in
dom/ipc/app/TabApp.cpp
dom/ipc/test.xul
toolkit/library/libxul-config.mk
toolkit/xre/Makefile.in
toolkit/xre/nsEmbedFunctions.cpp
--- a/content/base/src/Makefile.in
+++ b/content/base/src/Makefile.in
@@ -178,26 +178,29 @@ CPPSRCS		= \
 GQI_SRCS = contentbase.gqi
 
 # we don't want the shared lib, but we want to force the creation of a
 # static lib.
 FORCE_STATIC_LIB = 1
 
 EXTRA_COMPONENTS = $(srcdir)/nsBadCertHandler.js
 
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 INCLUDES	+= \
 		-I$(srcdir)/../../events/src \
 		-I$(srcdir)/../../xml/content/src \
 		-I$(srcdir)/../../xul/base/src \
 		-I$(srcdir)/../../xul/content/src \
 		-I$(srcdir)/../../html/content/src \
 		-I$(srcdir)/../../base/src \
 		-I$(srcdir)/../../xbl/src \
 		-I$(srcdir)/../../../layout/generic \
 		-I$(srcdir)/../../../layout/style \
 		-I$(srcdir)/../../../dom/base \
 		-I$(srcdir)/../../xml/document/src \
 		-I$(topsrcdir)/xpcom/io \
+		-I$(topsrcdir)/dom/ipc \
 		$(NULL)
 
 DEFINES += -D_IMPL_NS_LAYOUT
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -78,16 +78,27 @@
 #include "nsIURI.h"
 #include "nsIURL.h"
 #include "nsNetUtil.h"
 
 #include "nsGkAtoms.h"
 #include "nsINameSpaceManager.h"
 
 #include "nsThreadUtils.h"
+#include "nsIView.h"
+
+#include "TabParent.h"
+
+#include "mozcontainer.h"
+
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+
+using namespace mozilla;
+using namespace mozilla::tabs;
 
 class nsAsyncDocShellDestroyer : public nsRunnable
 {
 public:
   nsAsyncDocShellDestroyer(nsIDocShell* aDocShell)
     : mDocShell(aDocShell)
   {
   }
@@ -188,16 +199,28 @@ nsFrameLoader::LoadURI(nsIURI* aURI)
   }
   return rv;
 }
 
 nsresult
 nsFrameLoader::ReallyStartLoading()
 {
   NS_ENSURE_STATE(mURIToLoad && mOwnerContent && mOwnerContent->IsInDoc());
+
+  if (!mTriedNewProcess) {
+    TryNewProcess();
+    mTriedNewProcess = PR_TRUE;
+  }
+
+  if (mChildProcess) {
+    // FIXME get error codes from child
+    mChildProcess->LoadURL(mURIToLoad);
+    return NS_OK;
+  }
+  
   // Just to be safe, recheck uri.
   nsresult rv = CheckURILoad(mURIToLoad);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = EnsureDocShell();
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
@@ -1002,8 +1025,108 @@ nsFrameLoader::CheckForRecursiveLoad(nsI
     }
     nsCOMPtr<nsIDocShellTreeItem> temp;
     temp.swap(parentAsItem);
     temp->GetSameTypeParent(getter_AddRefs(parentAsItem));
   }
 
   return NS_OK;
 }
+
+PRBool
+nsFrameLoader::TryNewProcess()
+{
+  nsIDocument* doc = mOwnerContent->GetDocument();
+  if (!doc) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  if (doc->GetDisplayDocument()) {
+    // Don't allow subframe loads in external reference documents
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  nsCOMPtr<nsIWebNavigation> parentAsWebNav =
+    do_GetInterface(doc->GetScriptGlobalObject());
+
+  if (!parentAsWebNav) {
+    return PR_FALSE;
+  }
+
+  nsCOMPtr<nsIDocShellTreeItem> parentAsItem(do_QueryInterface(parentAsWebNav));
+
+  PRInt32 parentType;
+  parentAsItem->GetItemType(&parentType);
+
+  if (parentType != nsIDocShellTreeItem::typeChrome) {
+    return PR_FALSE;
+  }
+
+  if (!mOwnerContent->IsNodeOfType(nsINode::eXUL)) {
+    return PR_FALSE;
+  }
+
+  NS_ERROR("trying to start new process");
+  nsAutoString value;
+  mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, value);
+
+  if (!value.LowerCaseEqualsLiteral("content") &&
+      !StringBeginsWith(value, NS_LITERAL_STRING("content-"),
+                        nsCaseInsensitiveStringComparator())) {
+    return PR_FALSE;
+  }
+
+  // FIXME shouldn't need to launch a new process every time get here
+
+  // XXXnasty hack get our (parent) widget
+  doc->FlushPendingNotifications(Flush_Layout);
+  nsIFrame* ourFrame =
+    doc->GetPrimaryShell()->GetPrimaryFrameFor(mOwnerContent);
+  nsIView* ancestorView = ourFrame->GetView();
+
+  nsIView* firstChild = ancestorView->GetFirstChild();
+  if (!firstChild) {
+    NS_ERROR("no first child");
+    return PR_FALSE;
+  }
+
+  nsIWidget* w = firstChild->GetWidget();
+  if (!w) {
+    NS_ERROR("we're stuffed!");
+    return PR_FALSE;
+  }
+  // FIXME check that this widget has the size and position we expect for
+  // this iframe?
+
+  GdkWindow* parent_win =
+    static_cast<GdkWindow*>(w->GetNativeData(NS_NATIVE_WINDOW));
+  
+  gpointer user_data = nsnull;
+  gdk_window_get_user_data(parent_win, &user_data);
+
+  MozContainer* parentMozContainer = MOZ_CONTAINER(user_data);
+  GtkContainer* container = GTK_CONTAINER(parentMozContainer);
+
+  // create the widget for the child and add it to the parent's window
+  GtkWidget* socket = gtk_socket_new();
+  gtk_widget_set_parent_window(socket, parent_win);
+  gtk_container_add(container, socket);
+  gtk_widget_realize(socket);
+
+  // set the child window's size and position
+  nsPresContext* presContext = ourFrame->PresContext();
+  GtkAllocation alloc;
+  alloc.x = 0;                  // setting position doesn't look necessary
+  alloc.y = 0;
+  alloc.width = presContext->AppUnitsToDevPixels(ourFrame->GetSize().width);
+  alloc.height = presContext->AppUnitsToDevPixels(ourFrame->GetSize().height);
+  gtk_widget_size_allocate(socket, &alloc);
+
+  gtk_widget_show(socket);
+
+  GdkNativeWindow id = gtk_socket_get_id((GtkSocket*)socket);
+
+  mChildProcess = new TabParent(id);
+
+  mChildProcess->Move(0, 0, alloc.width, alloc.height);
+
+  return PR_TRUE;
+}
--- a/content/base/src/nsFrameLoader.h
+++ b/content/base/src/nsFrameLoader.h
@@ -43,30 +43,38 @@
 
 #ifndef nsFrameLoader_h_
 #define nsFrameLoader_h_
 
 #include "nsIDocShell.h"
 #include "nsStringFwd.h"
 #include "nsIFrameLoader.h"
 #include "nsIURI.h"
+#include "nsAutoPtr.h"
 
 class nsIContent;
 class nsIURI;
+namespace mozilla {
+  namespace tabs {
+    class TabParent;
+  }
+}
 
 class nsFrameLoader : public nsIFrameLoader
 {
 public:
   nsFrameLoader(nsIContent *aOwner) :
     mOwnerContent(aOwner),
     mDepthTooGreat(PR_FALSE),
     mIsTopLevelContent(PR_FALSE),
     mDestroyCalled(PR_FALSE),
     mNeedsAsyncDestroy(PR_FALSE),
-    mInSwap(PR_FALSE)
+    mInSwap(PR_FALSE),
+    mChildProcess(nsnull),
+    mTriedNewProcess(PR_FALSE)
   {}
 
   ~nsFrameLoader() {
     mNeedsAsyncDestroy = PR_TRUE;
     nsFrameLoader::Destroy();
   }
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@@ -84,19 +92,26 @@ public:
                                nsRefPtr<nsFrameLoader>& aFirstToSwap,
                                nsRefPtr<nsFrameLoader>& aSecondToSwap);
 private:
 
   NS_HIDDEN_(nsresult) EnsureDocShell();
   NS_HIDDEN_(void) GetURL(nsString& aURL);
   nsresult CheckURILoad(nsIURI* aURI);
 
+  // True means new process started; nothing else to do
+  PRBool TryNewProcess();
+
   nsCOMPtr<nsIDocShell> mDocShell;
   nsCOMPtr<nsIURI> mURIToLoad;
   nsIContent *mOwnerContent; // WEAK
   PRPackedBool mDepthTooGreat : 1;
   PRPackedBool mIsTopLevelContent : 1;
   PRPackedBool mDestroyCalled : 1;
   PRPackedBool mNeedsAsyncDestroy : 1;
   PRPackedBool mInSwap : 1;
+
+  // XXX leaking
+  mozilla::tabs::TabParent* mChildProcess;
+  PRBool mTriedNewProcess;
 };
 
 #endif
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -9840,20 +9840,23 @@ nsDocShell::EnsureScriptEnvironment()
     nsDebugAutoBoolTrueSetter boolSetter(&mInEnsureScriptEnv);
 #endif
 
     nsCOMPtr<nsIDOMScriptObjectFactory> factory =
         do_GetService(kDOMScriptObjectFactoryCID);
     NS_ENSURE_TRUE(factory, NS_ERROR_FAILURE);
 
     nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner));
-    NS_ENSURE_TRUE(browserChrome, NS_ERROR_NOT_AVAILABLE);
 
     PRUint32 chromeFlags;
-    browserChrome->GetChromeFlags(&chromeFlags);
+    if (browserChrome) {
+        browserChrome->GetChromeFlags(&chromeFlags);
+    } else {
+        chromeFlags = 0;
+    }
 
     PRBool isModalContentWindow =
         (chromeFlags & nsIWebBrowserChrome::CHROME_MODAL) &&
         !(chromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME);
 
     // If our window is modal and we're not opened as chrome, make
     // this window a modal content window.
     factory->NewScriptGlobalObject(mItemType == typeChrome,
--- a/dom/Makefile.in
+++ b/dom/Makefile.in
@@ -79,16 +79,17 @@ DIRS += \
   base \
   src \
   locales \
   $(NULL)
 
 ifdef MOZ_IPC
 DIRS += \
   plugins \
+  ipc \
   $(NULL)
 endif
 
 ifdef ENABLE_TESTS
 DIRS += tests
 endif
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/ipc/IFrameEmbedding.ipdl
@@ -0,0 +1,13 @@
+using MagicWindowHandle;
+
+rpc protocol IFrameEmbedding
+{
+    rpc out init(MagicWindowHandle parentWidget);
+
+    rpc out loadURL(String uri);
+
+    rpc out move(uint32_t x,
+                 uint32_t y,
+                 uint32_t width,
+                 uint32_t height);
+};
new file mode 100644
--- /dev/null
+++ b/dom/ipc/IFrameEmbeddingProtocol.h
@@ -0,0 +1,150 @@
+//
+// Automatically generated by ipdlc.
+// Edit at your own risk.
+//
+#ifndef IFrameEmbeddingProtocol_h
+#define IFrameEmbeddingProtocol_h
+#include "nscore.h"
+#include "IPC/IPCMessageUtils.h"
+#include "mozilla/ipc/MessageTypes.h"
+
+typedef mozilla::ipc::String String;
+typedef mozilla::ipc::StringArray StringArray;
+class NS_FINAL_CLASS IFrameEmbeddingProtocol
+{
+public:
+    /*interface*/ class Parent
+    {
+    public:
+    protected:
+        Parent() { }
+        virtual ~Parent() { }
+        Parent(const Parent&);
+        Parent& operator=(const Parent&);
+    };
+
+    /*interface*/ class Child
+    {
+    public:
+        virtual nsresult init(
+            const MagicWindowHandle& parentWidget) = 0;
+        virtual nsresult loadURL(
+            const String& uri) = 0;
+        virtual nsresult move(
+            const uint32_t& x, const uint32_t& y, const uint32_t& width, const uint32_t& height) = 0;
+    protected:
+        Child() { }
+        virtual ~Child() { }
+        Child(const Child&);
+        Child& operator=(const Child&);
+    };
+
+    enum State { };
+private:
+    IFrameEmbeddingProtocol();
+    virtual ~IFrameEmbeddingProtocol() = 0;
+};
+
+// Parent->child messages
+
+enum IFrameEmbedding_ParentToChildMsgType {
+    IFrameEmbedding_ParentToChildStart = IFrameEmbedding_ParentToChildMsgStart << 12,
+    IFrameEmbedding_ParentToChildPreStart = (IFrameEmbedding_ParentToChildMsgStart << 12) - 1,
+
+    IFrameEmbedding_ParentToChildMsg_init__ID,
+    IFrameEmbedding_ParentToChildMsg_loadURL__ID,
+    IFrameEmbedding_ParentToChildMsg_move__ID,
+
+
+    IFrameEmbedding_ParentToChildEnd
+};
+
+class IFrameEmbedding_ParentToChildMsg_init :
+    public IPC::MessageWithTuple<MagicWindowHandle>
+{
+public:
+    enum { ID = IFrameEmbedding_ParentToChildMsg_init__ID };
+    IFrameEmbedding_ParentToChildMsg_init(
+        const MagicWindowHandle& parentWidget) : 
+        IPC::MessageWithTuple<MagicWindowHandle>(
+            MSG_ROUTING_CONTROL, ID,
+            parentWidget)
+    { }
+};
+
+class IFrameEmbedding_ParentToChildMsg_loadURL :
+    public IPC::MessageWithTuple<String>
+{
+public:
+    enum { ID = IFrameEmbedding_ParentToChildMsg_loadURL__ID };
+    IFrameEmbedding_ParentToChildMsg_loadURL(
+        const String& uri) : 
+        IPC::MessageWithTuple<String>(
+            MSG_ROUTING_CONTROL, ID,
+            uri)
+    { }
+};
+
+class IFrameEmbedding_ParentToChildMsg_move :
+    public IPC::MessageWithTuple< Tuple4 <
+        uint32_t, uint32_t, uint32_t, uint32_t> >
+{
+public:
+    enum { ID = IFrameEmbedding_ParentToChildMsg_move__ID };
+    IFrameEmbedding_ParentToChildMsg_move(
+        const uint32_t& x, const uint32_t& y, const uint32_t& width, const uint32_t& height) : 
+        IPC::MessageWithTuple< Tuple4 <
+            uint32_t, uint32_t, uint32_t, uint32_t> >(
+            MSG_ROUTING_CONTROL, ID,
+            MakeTuple(
+                x, y, width, height))
+    { }
+};
+
+
+// Child->parent messages
+
+enum IFrameEmbedding_ChildToParentMsgType {
+    IFrameEmbedding_ChildToParentStart = IFrameEmbedding_ChildToParentMsgStart << 12,
+    IFrameEmbedding_ChildToParentPreStart = (IFrameEmbedding_ChildToParentMsgStart << 12) - 1,
+
+
+    IFrameEmbedding_ChildToParentMsg_Reply_init__ID,
+    IFrameEmbedding_ChildToParentMsg_Reply_loadURL__ID,
+    IFrameEmbedding_ChildToParentMsg_Reply_move__ID,
+
+    IFrameEmbedding_ChildToParentEnd
+};
+
+class IFrameEmbedding_ChildToParentMsg_Reply_init :
+    public IPC::Message
+{
+public:
+    enum { ID = IFrameEmbedding_ChildToParentMsg_Reply_init__ID };
+    IFrameEmbedding_ChildToParentMsg_Reply_init() : 
+                IPC::Message(MSG_ROUTING_CONTROL, ID, PRIORITY_NORMAL)
+    { }
+};
+
+class IFrameEmbedding_ChildToParentMsg_Reply_loadURL :
+    public IPC::Message
+{
+public:
+    enum { ID = IFrameEmbedding_ChildToParentMsg_Reply_loadURL__ID };
+    IFrameEmbedding_ChildToParentMsg_Reply_loadURL() : 
+                IPC::Message(MSG_ROUTING_CONTROL, ID, PRIORITY_NORMAL)
+    { }
+};
+
+class IFrameEmbedding_ChildToParentMsg_Reply_move :
+    public IPC::Message
+{
+public:
+    enum { ID = IFrameEmbedding_ChildToParentMsg_Reply_move__ID };
+    IFrameEmbedding_ChildToParentMsg_Reply_move() : 
+                IPC::Message(MSG_ROUTING_CONTROL, ID, PRIORITY_NORMAL)
+    { }
+};
+
+
+#endif // ifndef IFrameEmbeddingProtocol_h
new file mode 100644
--- /dev/null
+++ b/dom/ipc/IFrameEmbeddingProtocolChild.h
@@ -0,0 +1,88 @@
+//
+// Automatically generated by ipdlc.
+// Edit at your own risk.
+//
+#include "IFrameEmbeddingProtocol.h"
+
+#include "mozilla/ipc/RPCChannel.h"
+using mozilla::ipc::RPCChannel;
+using IPC::Message;
+
+class NS_FINAL_CLASS IFrameEmbeddingProtocolChild :
+    public IFrameEmbeddingProtocol::Parent,
+    public RPCChannel::Listener
+{
+public:
+    IFrameEmbeddingProtocolChild(IFrameEmbeddingProtocol::Child* aChild) :
+        mChild(aChild),
+        mRpc(this)
+    { }
+
+    bool Open(IPC::Channel* aChannel, MessageLoop* aIOLoop)
+    {
+        return mRpc.Open(aChannel, aIOLoop);
+    }
+
+    void Close()
+    {
+        mRpc.Close();
+    }
+
+    virtual Result OnCallReceived(const Message& msg, Message** reply)
+    {
+        switch (msg.type()) {
+        case IFrameEmbedding_ParentToChildMsg_init__ID: {
+            MagicWindowHandle parentWidget;
+            MagicWindowHandle p;
+            IFrameEmbedding_ParentToChildMsg_init::Read(&msg, &p);
+
+            parentWidget = p;
+
+            nsresult _rv = mChild->init(
+                parentWidget);
+            *reply = new IFrameEmbedding_ChildToParentMsg_Reply_init();
+            (*reply)->set_reply();
+            return MsgProcessed;
+        }
+        case IFrameEmbedding_ParentToChildMsg_loadURL__ID: {
+            String uri;
+            String p;
+            IFrameEmbedding_ParentToChildMsg_loadURL::Read(&msg, &p);
+
+            uri = p;
+
+            nsresult _rv = mChild->loadURL(
+                uri);
+            *reply = new IFrameEmbedding_ChildToParentMsg_Reply_loadURL();
+            (*reply)->set_reply();
+            return MsgProcessed;
+        }
+        case IFrameEmbedding_ParentToChildMsg_move__ID: {
+            uint32_t x;
+            uint32_t y;
+            uint32_t width;
+            uint32_t height;
+            IFrameEmbedding_ParentToChildMsg_move::Param p;
+            IFrameEmbedding_ParentToChildMsg_move::Read(&msg, &p);
+
+            x = p.a;
+            y = p.b;
+            width = p.c;
+            height = p.d;
+
+            nsresult _rv = mChild->move(
+                x, y, width, height);
+            *reply = new IFrameEmbedding_ChildToParentMsg_Reply_move();
+            (*reply)->set_reply();
+            return MsgProcessed;
+        }
+        default: {
+            return MsgNotKnown;
+        }
+        }
+    }
+
+private:
+    IFrameEmbeddingProtocol::Child* mChild;
+    RPCChannel mRpc;
+};
new file mode 100644
--- /dev/null
+++ b/dom/ipc/IFrameEmbeddingProtocolParent.h
@@ -0,0 +1,82 @@
+//
+// Automatically generated by ipdlc.
+// Edit at your own risk.
+//
+#include "IFrameEmbeddingProtocol.h"
+
+#include "mozilla/ipc/RPCChannel.h"
+using mozilla::ipc::RPCChannel;
+using IPC::Message;
+
+class NS_FINAL_CLASS IFrameEmbeddingProtocolParent :
+    public IFrameEmbeddingProtocol::Child,
+    public RPCChannel::Listener
+{
+public:
+    IFrameEmbeddingProtocolParent(IFrameEmbeddingProtocol::Parent* aParent) :
+        mParent(aParent),
+        mRpc(this)
+    { }
+
+    bool Open(IPC::Channel* aChannel)
+    {
+        return mRpc.Open(aChannel);
+    }
+
+    void Close()
+    {
+        mRpc.Close();
+    }
+
+    virtual nsresult init(
+        const MagicWindowHandle& parentWidget)
+    {
+        Message reply;
+        nsresult _rv = mRpc.Call(new IFrameEmbedding_ParentToChildMsg_init(
+            parentWidget)
+            , &reply);
+
+        if (NS_OK == _rv) {
+        }
+        return _rv;
+    }
+
+    virtual nsresult loadURL(
+        const String& uri)
+    {
+        Message reply;
+        nsresult _rv = mRpc.Call(new IFrameEmbedding_ParentToChildMsg_loadURL(
+            uri)
+            , &reply);
+
+        if (NS_OK == _rv) {
+        }
+        return _rv;
+    }
+
+    virtual nsresult move(
+        const uint32_t& x, const uint32_t& y, const uint32_t& width, const uint32_t& height)
+    {
+        Message reply;
+        nsresult _rv = mRpc.Call(new IFrameEmbedding_ParentToChildMsg_move(
+            x, y, width, height)
+            , &reply);
+
+        if (NS_OK == _rv) {
+        }
+        return _rv;
+    }
+
+    virtual Result OnCallReceived(const Message& msg, Message** reply)
+    {
+        switch (msg.type()) {
+        default: {
+            return MsgNotKnown;
+        }
+        }
+    }
+
+private:
+    IFrameEmbeddingProtocol::Parent* mParent;
+    RPCChannel mRpc;
+};
new file mode 100644
--- /dev/null
+++ b/dom/ipc/Makefile.in
@@ -0,0 +1,27 @@
+DEPTH = ../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = dom
+LIBRARY_NAME = domipc_s
+LIBXUL_LIBRARY = 1
+FORCE_STATIC_LIB = 1
+EXPORT_LIBRARY = 1
+
+CPPSRCS = \
+  TabParent.cpp \
+  TabProcessParent.cpp \
+  TabChild.cpp \
+  TabThread.cpp \
+  $(NULL)
+
+TOOL_DIRS = app
+
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
+include $(topsrcdir)/config/rules.mk
+
+DEFINES += -DBIN_SUFFIX='"$(BIN_SUFFIX)"'
new file mode 100644
--- /dev/null
+++ b/dom/ipc/TabChild.cpp
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*- */
+
+#include "TabChild.h"
+
+#include "nsIWebBrowser.h"
+#include "nsEmbedCID.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIBaseWindow.h"
+#include "nsIDocShellTreeItem.h"
+#include "nsThreadUtils.h"
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+
+using namespace mozilla::tabs;
+
+TabChild::TabChild()
+    : mWidget(0)
+    , mChild(this)
+{
+}
+
+TabChild::~TabChild()
+{
+    // TODObsmedberg: destroy the window!
+}
+
+bool
+TabChild::Init(MessageLoop* aIOLoop, IPC::Channel* aChannel)
+{
+    mChild.Open(aChannel, aIOLoop);
+    return true;
+}
+
+nsresult
+TabChild::init(const MagicWindowHandle& parentWidget)
+{
+    printf("creating %d!\n", NS_IsMainThread());
+
+    gtk_init(NULL, NULL);
+
+    nsCOMPtr<nsIWebBrowser> webBrowser(do_CreateInstance(NS_WEBBROWSER_CONTRACTID));
+
+    nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(webBrowser);
+
+    GtkWidget* win = gtk_plug_new((GdkNativeWindow)parentWidget);
+    gtk_widget_show(win);
+    baseWindow->InitWindow(win, 0, 0, 0, 0, 0);
+
+    nsCOMPtr<nsIDocShellTreeItem> docShellItem(do_QueryInterface(baseWindow));
+    docShellItem->SetItemType(nsIDocShellTreeItem::typeContentWrapper);
+
+    baseWindow->Create();
+
+    baseWindow->SetVisibility(PR_TRUE);
+
+    mWebNav = do_QueryInterface(webBrowser);
+    
+    // TODObz: create and embed a window!
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+TabChild::loadURL(const String& uri)
+{
+    printf("loading %s, %d\n", uri.c_str(), NS_IsMainThread());
+
+    return mWebNav->LoadURI(NS_ConvertUTF8toUTF16(uri.c_str()).get(),
+                            nsIWebNavigation::LOAD_FLAGS_NONE,
+                            NULL, NULL, NULL); 
+}
+
+nsresult
+TabChild::move(const uint32_t& x,
+               const uint32_t& y,
+               const uint32_t& width,
+               const uint32_t& height)
+{
+    printf("[TabChild] MOVE to (x,y)=(%ud, %ud), (w,h)= (%ud, %ud)\n",
+           x, y, width, height);
+
+    nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mWebNav);
+    baseWin->SetPositionAndSize(x, y, width, height, PR_TRUE);
+    return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/dom/ipc/TabChild.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*- */
+
+#ifndef mozilla_tabs_TabChild_h
+#define mozilla_tabs_TabChild_h
+
+#include "TabTypes.h"
+#include "IFrameEmbeddingProtocol.h"
+#include "IFrameEmbeddingProtocolChild.h"
+#include "nsIWebNavigation.h"
+#include "nsCOMPtr.h"
+
+namespace mozilla {
+namespace tabs {
+
+class TabChild
+    : public IFrameEmbeddingProtocol::Child
+{
+private:
+    typedef mozilla::ipc::String String;
+
+public:
+    TabChild();
+    virtual ~TabChild();
+
+    bool Init(MessageLoop* aIOLoop, IPC::Channel* aChannel);
+
+    virtual nsresult init(const MagicWindowHandle& parentWidget);
+    virtual nsresult loadURL(const String& uri);
+    virtual nsresult move(const uint32_t& x,
+                          const uint32_t& y,
+                          const uint32_t& width,
+                          const uint32_t& height);
+
+private:
+    MagicWindowHandle mWidget;
+    IFrameEmbeddingProtocolChild mChild;
+    nsCOMPtr<nsIWebNavigation> mWebNav;
+
+    DISALLOW_EVIL_CONSTRUCTORS(TabChild);
+};
+
+}
+}
+
+#endif // mozilla_tabs_TabChild_h
new file mode 100644
--- /dev/null
+++ b/dom/ipc/TabParent.cpp
@@ -0,0 +1,64 @@
+#include "TabParent.h"
+
+#include "mozilla/ipc/GeckoThread.h"
+
+#include "nsIURI.h"
+
+using mozilla::ipc::BrowserProcessSubThread;
+
+template<>
+struct RunnableMethodTraits<mozilla::tabs::TabParent>
+{
+    static void RetainCallee(mozilla::tabs::TabParent* obj) { }
+    static void ReleaseCallee(mozilla::tabs::TabParent* obj) { }
+};
+
+namespace mozilla {
+namespace tabs {
+
+TabParent::TabParent(MagicWindowHandle parentWidget)
+    : mSubprocess()
+    , mParent(this)
+    , mMonitor("mozilla.dom.ipc.TabParent")
+{
+    {
+        MonitorAutoEnter mon(mMonitor);
+        BrowserProcessSubThread::GetMessageLoop(BrowserProcessSubThread::IO)->
+            PostTask(FROM_HERE, NewRunnableMethod(this, &TabParent::LaunchSubprocess));
+        mon.Wait();
+    }
+
+    mParent.Open(mSubprocess.GetChannel());
+
+    mParent.init(parentWidget);
+}
+
+TabParent::~TabParent()
+{
+}
+
+void
+TabParent::LaunchSubprocess()
+{
+    MonitorAutoEnter mon(mMonitor);
+    mSubprocess.Launch();
+    mon.Notify();
+}
+
+void
+TabParent::LoadURL(nsIURI* aURI)
+{
+    nsCString spec;
+    aURI->GetSpec(spec);
+
+    mParent.loadURL(spec.get());
+}
+
+void
+TabParent::Move(PRUint32 x, PRUint32 y, PRUint32 width, PRUint32 height)
+{
+    mParent.move(x, y, width, height);
+}
+
+} // namespace tabs
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/ipc/TabParent.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: sw=4 ts=4 et : */
+
+#ifndef mozilla_tabs_TabParent_h
+#define mozilla_tabs_TabParent_h
+
+#include "TabTypes.h"
+#include "IFrameEmbeddingProtocol.h"
+#include "IFrameEmbeddingProtocolParent.h"
+#include "TabProcessParent.h"
+
+#include "mozilla/Monitor.h"
+
+class nsIURI;
+
+namespace mozilla {
+namespace tabs {
+
+class TabParent
+    : private IFrameEmbeddingProtocol::Parent
+{
+public:
+    TabParent(MagicWindowHandle parentWidget);
+    virtual ~TabParent();
+
+    void LoadURL(nsIURI* aURI);
+    void Move(PRUint32 x, PRUint32 y, PRUint32 width, PRUint32 height);
+
+private:
+    void LaunchSubprocess();
+
+    TabProcessParent mSubprocess;
+    IFrameEmbeddingProtocolParent mParent;
+
+    mozilla::Monitor mMonitor;
+};
+
+} // namespace tabs
+} // namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/ipc/TabProcessParent.cpp
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: sw=4 ts=4 et : */
+
+#include "TabProcessParent.h"
+
+#include "chrome/common/chrome_switches.h"
+
+namespace mozilla {
+namespace tabs {
+
+char const *const TabProcessParent::kTabProcessName = "gecko-iframe" BIN_SUFFIX;
+
+TabProcessParent::TabProcessParent()
+{
+}
+
+TabProcessParent::~TabProcessParent()
+{
+}
+
+bool TabProcessParent::Launch()
+{
+    if (!CreateChannel())
+        return false;
+
+    FilePath exePath =
+        FilePath::FromWStringHack(CommandLine::ForCurrentProcess()->program());
+    exePath = exePath.DirName();
+    exePath = exePath.AppendASCII(kTabProcessName);
+
+#if defined(OS_POSIX)
+    int srcChannelFd, dstChannelFd;
+    channel().GetClientFileDescriptorMapping(&srcChannelFd, &dstChannelFd);
+    mFileMap.push_back(std::pair<int,int>(srcChannelFd, dstChannelFd));
+#endif
+
+    CommandLine cmdLine(exePath.ToWStringHack());
+    cmdLine.AppendSwitchWithValue(switches::kProcessChannelID, channel_id());
+
+    base::ProcessHandle process;
+#if defined(OS_POSIX)
+    base::LaunchApp(cmdLine.argv(), mFileMap, false, &process);
+#else
+#error Loser
+#endif
+
+    if (!process)
+        return false;
+
+    SetHandle(process);
+    return true;
+}
+
+} // namespace tabs
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/ipc/TabProcessParent.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: sw=4 ts=4 et : */
+
+#ifndef mozilla_tabs_TabProcessParent_h
+#define mozilla_tabs_TabProcessParent_h
+
+#include "mozilla/ipc/GeckoChildProcessHost.h"
+
+namespace mozilla {
+namespace tabs {
+
+class TabProcessParent
+    : private mozilla::ipc::GeckoChildProcessHost
+{
+public:
+    TabProcessParent();
+    ~TabProcessParent();
+
+    /**
+     * Asynchronously launch the plugin process.
+     */
+    bool Launch();
+
+    IPC::Channel* GetChannel() {
+        return channelp();
+    }
+
+    virtual bool CanShutdown() {
+        return true;
+    }
+
+    base::WaitableEvent* GetShutDownEvent() {
+        return GetProcessEvent();
+    }
+
+private:
+    static char const *const kTabProcessName;
+
+    DISALLOW_EVIL_CONSTRUCTORS(TabProcessParent);
+};
+
+}
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/ipc/TabThread.cpp
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Plugin App.
+ *
+ * The Initial Developer of the Original Code is
+ *   Ben Turner <bent.mozilla@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Chris Jones <jones.chris.g@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "TabThread.h"
+
+#include "prlink.h"
+
+#include "base/command_line.h"
+#include "base/string_util.h"
+#include "chrome/common/child_process.h"
+#include "chrome/common/chrome_switches.h"
+
+using mozilla::ipc::GeckoThread;
+
+namespace mozilla {
+namespace tabs {
+
+TabThread::TabThread() :
+    GeckoThread(),
+    mTab()
+{
+}
+
+TabThread::~TabThread()
+{
+}
+
+void
+TabThread::Init()
+{
+    GeckoThread::Init();
+
+    // FIXME/cjones: set up channel stuff, etc.
+    
+    // FIXME owner_loop() is bad here
+    mTab.Init(owner_loop(), channel());
+}
+
+void
+TabThread::CleanUp()
+{
+    GeckoThread::CleanUp();
+}
+
+} // namespace tabs
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/ipc/TabThread.h
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Plugin App.
+ *
+ * The Initial Developer of the Original Code is
+ *   Ben Turner <bent.mozilla@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Chris Jones <jones.chris.g@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef dom_tabs_TabThread_h
+#define dom_tabs_TabThread_h 1
+
+#include "chrome/common/child_thread.h"
+#include "base/file_path.h"
+
+#include "mozilla/ipc/GeckoThread.h"
+#include "TabChild.h"
+
+#undef _MOZ_LOG
+#define _MOZ_LOG(s)  printf("[TabThread] %s", s)
+
+namespace mozilla {
+namespace tabs {
+//-----------------------------------------------------------------------------
+
+// The TabThread class represents a background thread where tab instances
+// live.
+class TabThread : public mozilla::ipc::GeckoThread {
+public:
+    TabThread();
+    ~TabThread();
+
+private:
+    // Thread implementation:
+    virtual void Init();
+    virtual void CleanUp();
+
+    TabChild mTab;
+    IPC::Channel* mChannel;
+
+    DISALLOW_EVIL_CONSTRUCTORS(TabThread);
+};
+
+}  // namespace tabs
+}  // namespace mozilla
+
+#endif  // ifndef dom_tabs_TabThread_h
new file mode 100644
--- /dev/null
+++ b/dom/ipc/TabTypes.h
@@ -0,0 +1,16 @@
+#ifndef mozilla_tabs_TabTypes_h
+#define mozilla_tabs_TabTypes_h
+
+#ifdef XP_WIN
+#include <windows.h>
+
+typedef HWND MagicWindowHandle;
+#elif defined(MOZ_WIDGET_GTK2)
+#include <X11/X.h>
+
+typedef XID MagicWindowHandle;
+#else
+#error Not implemented, stooge
+#endif
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/ipc/app/Makefile.in
@@ -0,0 +1,105 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla Plugin App.
+#
+# The Initial Developer of the Original Code is
+#   Ben Turner <bent.mozilla@gmail.com>.
+# Portions created by the Initial Developer are Copyright (C) 2009
+# the Initial Developer. All Rights Reserved.
+#   Chris Jones <jones.chris.g@gmail.com>
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = dom
+
+##
+## Build the child process that runs plugins
+##
+DEFINES += -DNO_NSPR_10_SUPPORT=1
+
+PROGRAM = gecko-iframe$(BIN_SUFFIX)
+
+CPPSRCS = \
+  TabApp.cpp \
+  $(NULL)
+
+LIBS += \
+  $(XPCOM_LIBS) \
+  $(NSPR_LIBS) \
+  $(NULL)
+
+# This switches $(INSTALL) to copy mode, like $(SYSINSTALL), so things that
+# shouldn't get 755 perms need $(IFLAGS1) for either way of calling nsinstall.
+NSDISTMODE = copy
+
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
+
+ifdef _MSC_VER
+# Always enter a Windows program through wmain, whether or not we're
+# a console application.
+ifdef WINCE
+WIN32_EXE_LDFLAGS += -ENTRY:mainWCRTStartup
+else
+WIN32_EXE_LDFLAGS += -ENTRY:wmainCRTStartup
+endif
+endif
+
+ifdef WINCE
+EXTRA_DSO_LDOPTS += $(call EXPAND_LIBNAME,corelibc)
+endif
+
+ifeq ($(OS_ARCH),WINNT)
+OS_LIBS += $(call EXPAND_LIBNAME,comctl32 comdlg32 uuid shell32 ole32 oleaut32 version winspool)
+OS_LIBS += $(call EXPAND_LIBNAME,usp10 msimg32)
+endif
+
+include $(topsrcdir)/config/rules.mk
+
+ifeq ($(OS_ARCH),WINNT)
+#
+# Control the default heap size.
+# This is the heap returned by GetProcessHeap().
+# As we use the CRT heap, the default size is too large and wastes VM.
+#
+# The default heap size is 1MB on Win32.
+# The heap will grow if need be.
+#
+# Set it to 256k.  See bug 127069.
+#
+ifndef GNU_CC
+LDFLAGS += /HEAP:0x40000
+endif
+endif
new file mode 100644
--- /dev/null
+++ b/dom/ipc/app/TabApp.cpp
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Plugin App.
+ *
+ * The Initial Developer of the Original Code is
+ *   Ben Turner <bent.mozilla@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Chris Jones <jones.chris.g@gmail.com>.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsXPCOM.h"
+#include "nsXULAppAPI.h"
+
+
+// FIXME/cjones testing
+#include <unistd.h>
+
+
+#ifdef XP_WIN
+#include <windows.h>
+// we want a wmain entry point
+#include "nsWindowsWMain.cpp"
+#endif
+
+class ScopedLogging
+{
+public:
+    ScopedLogging() { NS_LogInit(); }
+    ~ScopedLogging() { NS_LogTerm(); }
+};
+
+int
+main(int argc, char* argv[])
+{
+    ScopedLogging log;
+    nsresult rv = XRE_InitChildProcess(argc, argv, "TabThread");
+    NS_ENSURE_SUCCESS(rv, 1);
+}
new file mode 100644
--- /dev/null
+++ b/dom/ipc/test.xul
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        width="800" height="800" onload="setTimeout(restart, 0)" orient="vertical">
+  <script>
+    function restart() {
+      var y = document.getElementById('page');
+      var p = y.parentNode;
+      p.removeChild(y);
+      p.appendChild(y);
+    }
+    
+    function loadURL(url) {
+      document.getElementById('page').setAttribute('src', url);
+    }
+  </script>
+
+  <toolbar id="controls">
+    <toolbarbutton label="Back"/>
+    <toolbarbutton label="Forward"/>
+    <textbox onchange="loadURL(this.value)" flex="1" id="URL"/>
+    <toolbarbutton onclick="restart()" label="Recover"/>
+  </toolbar>
+
+  <iframe type="content" src="http://www.google.com/" flex="1" id="page"/>
+</window>
--- a/toolkit/library/libxul-config.mk
+++ b/toolkit/library/libxul-config.mk
@@ -88,16 +88,17 @@ RCFLAGS += -i $(topsrcdir)/widget/src/os
 endif
 
 LOCAL_INCLUDES += -I$(topsrcdir)/widget/src/os2
 endif
 
 # dependent libraries
 ifdef MOZ_IPC
 STATIC_LIBS += \
+  domipc_s \
   domplugins_s \
   mozipc_s \
   chromium_s \
   $(NULL)
 
 OS_LIBS += -lrt
 endif
 
--- a/toolkit/xre/Makefile.in
+++ b/toolkit/xre/Makefile.in
@@ -204,16 +204,18 @@ endif
 ifdef ENABLE_TESTS
 DIRS += test
 endif
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
+LOCAL_INCLUDES += -I$(topsrcdir)/dom/ipc
+
 ifdef BUILD_STATIC_LIBS
 export::
 	@$(PERL) -I$(MOZILLA_DIR)/config $(MOZILLA_DIR)/config/build-list.pl $(FINAL_LINK_COMP_NAMES) Apprunner
 #	embedding/browser/gtk/src/Makefile.in sucks! we need to add an empty line to 
 # FINAL_LINK_COMPS to keep the two lists in sync :-(
 	@$(PERL) -I$(MOZILLA_DIR)/config $(MOZILLA_DIR)/config/build-list.pl $(FINAL_LINK_COMPS) ""
 endif
 
--- a/toolkit/xre/nsEmbedFunctions.cpp
+++ b/toolkit/xre/nsEmbedFunctions.cpp
@@ -63,23 +63,25 @@
 #include "nsWidgetsCID.h"
 #include "nsXREDirProvider.h"
 
 #include "mozilla/ipc/GeckoChildProcessHost.h"
 #include "mozilla/ipc/GeckoThread.h"
 #include "ScopedXREEmbed.h"
 
 #include "mozilla/plugins/PluginThreadChild.h"
+#include "TabThread.h"
 
 using mozilla::ipc::BrowserProcessSubThread;
 using mozilla::ipc::GeckoChildProcessHost;
 using mozilla::ipc::GeckoThread;
 using mozilla::ipc::ScopedXREEmbed;
 
 using mozilla::plugins::PluginThreadChild;
+using mozilla::tabs::TabThread;
 
 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
 
 void
 XRE_GetStaticComponents(nsStaticModuleInfo const **aStaticComponents,
                         PRUint32 *aComponentCount)
 {
   *aStaticComponents = kPStaticModules;
@@ -208,16 +210,18 @@ XRE_InitChildProcess(int aArgc,
 
   {
     GeckoThread* mainThread;
 
     if (!aMainThreadClass)
       mainThread = new GeckoThread();
     else if (!strcmp("PluginThreadChild", aMainThreadClass))
       mainThread = new PluginThreadChild();
+    else if (!strcmp("TabThread", aMainThreadClass))
+      mainThread = new TabThread();
     else {
         NS_RUNTIMEABORT("Unknown main thread class");
     }
 
     ChildProcess process(mainThread);
 
     // Do IPC event loop
     MessageLoop::current()->Run();