merge bent's changes from libchromiumipc. Gtk plugins now drawing
authorBen Turner <bent.mozilla@gmail.com>
Wed, 01 Jul 2009 14:19:32 -0700
changeset 35747 561253b4575b2ebd17cb53efea9b3ffaf82f53a1
parent 35746 9c16bf14545c177f98ba8a3ffabf871dbe7c2c55
child 35748 6e9c444a65ac4203c69d741cd7b9dc304f9dfa5d
push idunknown
push userunknown
push dateunknown
milestone1.9.2a1pre
merge bent's changes from libchromiumipc. Gtk plugins now drawing
dom/plugins/NPAPI.ipdl
dom/plugins/NPAPIPluginChild.cpp
dom/plugins/NPAPIPluginChild.h
dom/plugins/NPAPIPluginParent.cpp
dom/plugins/NPAPIPluginParent.h
dom/plugins/NPAPIProtocol.h
dom/plugins/NPAPIProtocolChild.h
dom/plugins/NPAPIProtocolParent.h
dom/plugins/NPPInstanceChild.cpp
dom/plugins/NPPInstanceChild.h
ipc/glue/MessagePump.cpp
ipc/glue/MessagePump.h
modules/plugin/base/src/nsPluginNativeWindowWin.cpp
modules/plugin/test/testplugin/nptest_gtk2.cpp
--- a/dom/plugins/NPAPI.ipdl
+++ b/dom/plugins/NPAPI.ipdl
@@ -12,17 +12,16 @@ rpc protocol NPAPI
 {
     manages NPP;
 //    manages NPObject;
 
     rpc out NP_Initialize() returns (NPError rv);
 
 
     rpc out NPP(String aMimeType,
-                int aHandle,
                 uint16_t aMode,
                 StringArray aNames,
                 StringArray aValues) returns (NPError rv);
     rpc out ~NPP() returns (NPError rv);
 
 //    rpc in TradeNPPsForSomeReason(NPP n) returns (NPP n2);
 };
 
--- a/dom/plugins/NPAPIPluginChild.cpp
+++ b/dom/plugins/NPAPIPluginChild.cpp
@@ -909,26 +909,30 @@ NPAPIPluginChild::AnswerNP_Initialize(NP
     return NS_OK;
 #else
 #  error Please implement me for your platform
 #endif
 }
 
 NPPProtocolChild*
 NPAPIPluginChild::NPPConstructor(const String& aMimeType,
-                                 /*const NPPParent*&*/const int& aHandle,
                                  const uint16_t& aMode,
                                  const StringArray& aNames,
                                  const StringArray& aValues,
                                  NPError* rv)
 {
     _MOZ_LOG(__FUNCTION__);
 
     // create our wrapper instance
-    NPPInstanceChild* childInstance = new NPPInstanceChild(&mFunctions);
+    nsAutoPtr<NPPInstanceChild> childInstance(
+        new NPPInstanceChild(&mFunctions));
+    if (!childInstance->Initialize()) {
+        *rv = NPERR_GENERIC_ERROR;
+        return 0;
+    }
 
     // unpack the arguments into a C format
     int argc = aNames.size();
     NS_ASSERTION(argc == (int) aValues.size(),
                  "argn.length != argv.length");
 
     char** argn = (char**) calloc(1 + argc, sizeof(char*));
     char** argv = (char**) calloc(1 + argc, sizeof(char*));
@@ -962,21 +966,27 @@ out:
     printf ("[NPAPIPluginChild] %s: returning %hd\n", __FUNCTION__, *rv);
     for (int i = 0; i < argc; ++i) {
         free(argn[i]);
         free(argv[i]);
     }
     free(argn);
     free(argv);
 
-    return childInstance;
+    return childInstance.forget();
 }
 
-
 nsresult
 NPAPIPluginChild::NPPDestructor(NPPProtocolChild* actor, NPError* rv)
 {
+    _MOZ_LOG(__FUNCTION__);
+
+    NPPInstanceChild* inst = static_cast<NPPInstanceChild*>(actor);
+    *rv = mFunctions.destroy(inst->GetNPP(), 0);
+    delete actor;
+    inst->GetNPP()->ndata = 0;
+
     return NS_OK;
 }
 
 
 } // namespace plugins
 } // namespace mozilla
--- a/dom/plugins/NPAPIPluginChild.h
+++ b/dom/plugins/NPAPIPluginChild.h
@@ -47,17 +47,17 @@
 #include "base/basictypes.h"
 
 #include "prlink.h"
 
 #include "npapi.h"
 #include "npfunctions.h"
 #include "nsplugindefs.h"
 
-#include "base/hash_tables.h"
+#include "nsAutoPtr.h"
 
 #include "mozilla/plugins/NPAPIProtocolChild.h"
 #include "mozilla/plugins/NPPInstanceChild.h"
 
 // NOTE: stolen from nsNPAPIPlugin.h
 
 /*
  * Use this macro before each exported function
@@ -97,17 +97,16 @@ namespace plugins {
 class NPAPIPluginChild : public NPAPIProtocolChild
 {
 protected:
     // Implement the NPAPIProtocolChild interface
     virtual nsresult AnswerNP_Initialize(NPError* rv);
 
     virtual NPPProtocolChild* NPPConstructor(
         const String& aMimeType,
-        /*const NPPParent*&*/const int& aHandle,
         const uint16_t& aMode,
         const StringArray& aNames,
         const StringArray& aValues,
         NPError* rv);
 
     virtual nsresult NPPDestructor(
         NPPProtocolChild* actor,
         NPError* rv);
@@ -125,19 +124,16 @@ public:
     static const NPNetscapeFuncs sBrowserFuncs;
 
 private:
     bool InitGraphics();
 
     std::string mPluginFilename;
     PRLibrary* mLibrary;
 
-//  base::hash_map<int, Instance*> mInstances;
-//  int mNextInstanceId;
-
     // we get this from the plugin
 #ifdef OS_LINUX
     NP_PLUGINUNIXINIT mInitializeFunc;
 #elif OS_WIN
     NP_PLUGININIT mInitializeFunc;
     NP_GETENTRYPOINTS mGetEntryPointsFunc;
 #endif
     NP_PLUGINSHUTDOWN mShutdownFunc;
--- a/dom/plugins/NPAPIPluginParent.cpp
+++ b/dom/plugins/NPAPIPluginParent.cpp
@@ -101,30 +101,31 @@ NPAPIPluginParent::LaunchSubprocess()
 {
     MonitorAutoEnter mon(mMonitor);
     mSubprocess.Launch();
     mon.Notify();
 }
 
 NPPProtocolParent*
 NPAPIPluginParent::NPPConstructor(const String& aMimeType,
-                                  const int& aHandle,
                                   const uint16_t& aMode,
                                   const StringArray& aNames,
                                   const StringArray& aValues,
                                   NPError* rv)
 {
+    _MOZ_LOG(__FUNCTION__);
     return new NPPInstanceParent(mNPNIface);
 }
 
 nsresult
 NPAPIPluginParent::NPPDestructor(NPPProtocolParent* __a,
                                  NPError* rv)
 {
-    return NS_OK;
+    _MOZ_LOG(__FUNCTION__);
+    delete __a;
 }
 
 void
 NPAPIPluginParent::SetPluginFuncs(NPPluginFuncs* aFuncs)
 {
     aFuncs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
     aFuncs->javaClass = nsnull;
 
@@ -200,38 +201,56 @@ NPAPIPluginParent::NPP_New(NPMIMEType pl
     StringArray values;
 
     for (int i = 0; i < argc; ++i) {
         names.push_back(argn[i]);
         values.push_back(argv[i]);
     }
 
     NPError prv;
-    NPPInstanceParent* parentInstance = static_cast<NPPInstanceParent*>(
-        CallNPPConstructor(pluginType,
-                           /*instance*/42,
-                           mode, names,
-                           values,
-                           &prv));
+    nsAutoPtr<NPPInstanceParent> parentInstance(
+        static_cast<NPPInstanceParent*>(CallNPPConstructor(pluginType,
+                                                           mode, names,
+                                                           values,
+                                                           &prv)));
     printf ("[NPAPIPluginParent] %s: got return value %hd\n", __FUNCTION__,
             prv);
 
     if (NPERR_NO_ERROR != prv)
         return prv;
     NS_ASSERTION(parentInstance,
                  "if there's no parentInstance, there should be an error");
 
-    // FIXME/cjones: HACK ALERT!  kill this and manage through NPAPI
-//    parentInstance->mNpp.SetChannel(mNpapi.HACK_getchannel_please());
-//    mNpapi.HACK_npp = &(parentInstance->mNpp);
-
-
-    instance->pdata = (void*) parentInstance;
+    instance->pdata = (void*) parentInstance.forget();
     return prv;
 }
 
+NPError
+NPAPIPluginParent::NPP_Destroy(NPP instance,
+                               NPSavedData** save)
+{
+    // FIXME/cjones:
+    //  (1) send a "destroy" message to the child
+    //  (2) the child shuts down its instance
+    //  (3) remove both parent and child IDs from map
+    //  (4) free parent
+
+    _MOZ_LOG(__FUNCTION__);
+
+    NPPInstanceParent* parentInstance =
+        static_cast<NPPInstanceParent*>(instance->pdata);
+
+    NPError prv;
+    if (CallNPPDestructor(parentInstance, &prv)) {
+        prv = NPERR_GENERIC_ERROR;
+    }
+    instance->pdata = nsnull;
+
+    return prv;
+ }
+
 // HACKS
 NPAPIPluginParent* NPAPIPluginParent::Shim::HACK_target;
 
 
 } // namespace plugins
 } // namespace mozilla
 
--- a/dom/plugins/NPAPIPluginParent.h
+++ b/dom/plugins/NPAPIPluginParent.h
@@ -53,16 +53,18 @@
 
 #include "mozilla/Monitor.h"
 #include "mozilla/SharedLibrary.h"
 #include "mozilla/plugins/NPAPIProtocol.h"
 #include "mozilla/plugins/NPAPIProtocolParent.h"
 #include "mozilla/plugins/NPPInstanceParent.h"
 #include "mozilla/plugins/PluginProcessParent.h"
 
+#include "nsAutoPtr.h"
+
 #undef _MOZ_LOG
 #define _MOZ_LOG(s) printf("[NPAPIPluginParent] %s\n", s)
 
 namespace mozilla {
 namespace plugins {
 //-----------------------------------------------------------------------------
 
 /**
@@ -79,17 +81,16 @@ namespace plugins {
 class NPAPIPluginParent : public NPAPIProtocolParent
 {
 private:
     typedef mozilla::SharedLibrary SharedLibrary;
 
 protected:
     NPPProtocolParent* NPPConstructor(
                 const String& aMimeType,
-                const int& aHandle,
                 const uint16_t& aMode,
                 const StringArray& aNames,
                 const StringArray& aValues,
                 NPError* rv);
 
     virtual nsresult NPPDestructor(
                 NPPProtocolParent* __a,
                 NPError* rv);
@@ -156,27 +157,17 @@ private:
     // NPP-like API that Gecko calls are trampolined into.  These 
     // messages then get forwarded along to the plugin instance,
     // and then eventually the child process.
 
     NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode,
                     int16_t argc, char* argn[], char* argv[],
                     NPSavedData* saved);
 
-    NPError NPP_Destroy(NPP instance, NPSavedData** save)
-    {
-        // FIXME/cjones:
-        //  (1) send a "destroy" message to the child
-        //  (2) the child shuts down its instance
-        //  (3) remove both parent and child IDs from map
-        //  (4) free parent
-
-        _MOZ_LOG(__FUNCTION__);
-        return 1;
-    }
+    NPError NPP_Destroy(NPP instance, NPSavedData** save);
 
     static inline NPPInstanceParent& InstCast(void* p)
     {
         return *static_cast<NPPInstanceParent*>(p);
     }
 
     static inline const NPPInstanceParent& InstCast(const void* p)
     {
--- a/dom/plugins/NPAPIProtocol.h
+++ b/dom/plugins/NPAPIProtocol.h
@@ -91,50 +91,43 @@ private:
     typedef mozilla::ipc::StringArray StringArray;
 
 public:
     enum {
         ID = Msg_NPPConstructor__ID
     };
     Msg_NPPConstructor(
                 const String& aMimeType,
-                const int& aHandle,
                 const uint16_t& aMode,
                 const StringArray& aNames,
                 const StringArray& aValues,
                 const mozilla::ipc::ActorHandle& __ah) :
         IPC::Message(MSG_ROUTING_NONE, ID, PRIORITY_NORMAL)
     {
         IPC::WriteParam(this, aMimeType);
-        IPC::WriteParam(this, aHandle);
         IPC::WriteParam(this, aMode);
         IPC::WriteParam(this, aNames);
         IPC::WriteParam(this, aValues);
         IPC::WriteParam(this, __ah);
     }
 
     static bool Read(
                 const Message* msg,
                 String* aMimeType,
-                int* aHandle,
                 uint16_t* aMode,
                 StringArray* aNames,
                 StringArray* aValues,
                 mozilla::ipc::ActorHandle* __ah)
     {
         void* iter = 0;
 
         if (!(IPC::ReadParam(msg, &(iter), aMimeType))) {
             return false;
         }
 
-        if (!(IPC::ReadParam(msg, &(iter), aHandle))) {
-            return false;
-        }
-
         if (!(IPC::ReadParam(msg, &(iter), aMode))) {
             return false;
         }
 
         if (!(IPC::ReadParam(msg, &(iter), aNames))) {
             return false;
         }
 
--- a/dom/plugins/NPAPIProtocolChild.h
+++ b/dom/plugins/NPAPIProtocolChild.h
@@ -21,17 +21,16 @@ class /*NS_ABSTRACT_CLASS*/ NPAPIProtoco
 {
 protected:
     typedef mozilla::ipc::String String;
     typedef mozilla::ipc::StringArray StringArray;
 
     virtual nsresult AnswerNP_Initialize(NPError* rv) = 0;
     virtual NPPProtocolChild* NPPConstructor(
                 const String& aMimeType,
-                const int& aHandle,
                 const uint16_t& aMode,
                 const StringArray& aNames,
                 const StringArray& aValues,
                 NPError* rv) = 0;
     virtual nsresult NPPDestructor(
                 NPPProtocolChild* __a,
                 NPError* rv) = 0;
 
@@ -112,29 +111,28 @@ public:
 
                 reply = new NPAPIProtocol::Reply_NP_Initialize(rv);
                 reply->set_reply();
                 return MsgProcessed;
             }
         case NPAPIProtocol::Msg_NPPConstructor__ID:
             {
                 String aMimeType;
-                int aHandle;
                 uint16_t aMode;
                 StringArray aNames;
                 StringArray aValues;
                 NPError rv;
                 mozilla::ipc::ActorHandle __ah;
 
-                if (!(NPAPIProtocol::Msg_NPPConstructor::Read(&(msg), &(aMimeType), &(aHandle), &(aMode), &(aNames), &(aValues), &(__ah)))) {
+                if (!(NPAPIProtocol::Msg_NPPConstructor::Read(&(msg), &(aMimeType), &(aMode), &(aNames), &(aValues), &(__ah)))) {
                     return MsgPayloadError;
                 }
 
                 NPPProtocolChild* __a;
-                __a = NPPConstructor(aMimeType, aHandle, aMode, aNames, aValues, &(rv));
+                __a = NPPConstructor(aMimeType, aMode, aNames, aValues, &(rv));
                 if (!(__a)) {
                     return MsgValueError;
                 }
 
                 __ah.mChildId = __a->mId = Register(__a);
                 __a->mPeerId = __ah.mParentId;
                 __a->mManager = this;
                 __a->mChannel = &(mChannel);
--- a/dom/plugins/NPAPIProtocolParent.h
+++ b/dom/plugins/NPAPIProtocolParent.h
@@ -20,17 +20,16 @@ class /*NS_ABSTRACT_CLASS*/ NPAPIProtoco
     public mozilla::ipc::IProtocolManager
 {
 protected:
     typedef mozilla::ipc::String String;
     typedef mozilla::ipc::StringArray StringArray;
 
     virtual NPPProtocolParent* NPPConstructor(
                 const String& aMimeType,
-                const int& aHandle,
                 const uint16_t& aMode,
                 const StringArray& aNames,
                 const StringArray& aValues,
                 NPError* rv) = 0;
     virtual nsresult NPPDestructor(
                 NPPProtocolParent* __a,
                 NPError* rv) = 0;
 
@@ -72,34 +71,33 @@ public:
         if (!(NPAPIProtocol::Reply_NP_Initialize::Read(&(__reply), rv))) {
             return NS_ERROR_ILLEGAL_VALUE;
         }
         return NS_OK;
     }
 
     NPPProtocolParent* CallNPPConstructor(
                 const String& aMimeType,
-                const int& aHandle,
                 const uint16_t& aMode,
                 const StringArray& aNames,
                 const StringArray& aValues,
                 NPError* rv)
     {
         NPPProtocolParent* __a;
-        __a = NPPConstructor(aMimeType, aHandle, aMode, aNames, aValues, rv);
+        __a = NPPConstructor(aMimeType, aMode, aNames, aValues, rv);
         if (!(__a)) {
             return 0;
         }
         __a->mId = Register(__a);
         mozilla::ipc::ActorHandle __ah;
         __ah.mParentId = __a->mId;
 
         Message __reply;
         Message* __msg;
-        __msg = new NPAPIProtocol::Msg_NPPConstructor(aMimeType, aHandle, aMode, aNames, aValues, __ah);
+        __msg = new NPAPIProtocol::Msg_NPPConstructor(aMimeType, aMode, aNames, aValues, __ah);
         __msg->set_routing_id(MSG_ROUTING_CONTROL);
         if (!(mChannel.Call(__msg, &(__reply)))) {
             return 0;
         }
         if (!(NPAPIProtocol::Reply_NPPConstructor::Read(&(__reply), rv, &(__ah)))) {
             return 0;
         }
         __a->mPeerId = __ah.mChildId;
--- a/dom/plugins/NPPInstanceChild.cpp
+++ b/dom/plugins/NPPInstanceChild.cpp
@@ -33,21 +33,27 @@
  * 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 "NPPInstanceChild.h"
 
-#ifdef OS_LINUX
+#if defined(OS_LINUX)
+
 #include <gtk/gtk.h>
 #include <gdk/gdkx.h>
 #include <gdk/gdk.h>
 #include "gtk2xtbin.h"
+
+#elif defined(OS_WIN)
+
+#include <windows.h>
+
 #endif
 
 namespace mozilla {
 namespace plugins {
 //-----------------------------------------------------------------------------
 
 static const char*
 NPNVariableToString(NPNVariable aVar)
@@ -76,33 +82,40 @@ NPNVariableToString(NPNVariable aVar)
 
         VARSTR(NPNVprivateModeBool);
 
     default: return "???";
     }
 #undef VARSTR
 }
 
+NPPInstanceChild::~NPPInstanceChild()
+{
+#if defined(OS_WIN)
+  DestroyPluginWindow();
+#endif
+}
+
 NPError
 NPPInstanceChild::NPN_GetValue(NPNVariable aVar, void* aValue)
 {
     printf ("[NPPInstanceChild] NPN_GetValue(%s)\n",
             NPNVariableToString(aVar));
 
     switch(aVar) {
 
     case NPNVSupportsWindowless:
-        // FIXME/cjones report PR_TRUE here and use XComposite + child
+        // FIXME/cjones report true here and use XComposite + child
         // surface to implement windowless plugins
-        *((NPBool*)aValue) = PR_FALSE;
+        *((NPBool*)aValue) = false;
         return NPERR_NO_ERROR;
 
 #if defined(OS_LINUX)
     case NPNVSupportsXEmbedBool:
-        *((NPBool*)aValue) = PR_TRUE;
+        *((NPBool*)aValue) = true;
         return NPERR_NO_ERROR;
 
     case NPNVToolkit:
         *((NPNToolkitType*)aValue) = NPNVGtk2;
         return NPERR_NO_ERROR;
 
 #elif defined(OS_WIN)
     case NPNVToolkit:
@@ -154,25 +167,194 @@ NPPInstanceChild::AnswerNPP_SetWindow(co
         GDK_COLORMAP_XCOLORMAP(gdk_drawable_get_colormap(gdkWindow));
     GdkVisual* gdkVisual = gdk_drawable_get_visual(gdkWindow);
     mWsInfo.visual = GDK_VISUAL_XVISUAL(gdkVisual);
     mWsInfo.depth = gdkVisual->depth;
 #endif
 
     mWindow.ws_info = (void*) &mWsInfo;
 
+    *rv = mPluginIface->setwindow(&mData, &mWindow);
+
 #elif defined(OS_WIN)
-    mWindow.window = aWindow.window;
+    ReparentPluginWindow((HWND)aWindow.window);
+    SizePluginWindow(aWindow.width, aWindow.height);
+
+    mWindow.window = (void*)mPluginWindowHWND;
     mWindow.width = aWindow.width;
     mWindow.height = aWindow.height;
     mWindow.type = NPWindowTypeWindow;
 
+    *rv = mPluginIface->setwindow(&mData, &mWindow);
+    if (*rv == NPERR_NO_ERROR) {
+        WNDPROC wndProc = reinterpret_cast<WNDPROC>(
+            GetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC));
+        if (wndProc != PluginWindowProc) {
+            mPluginWndProc = reinterpret_cast<WNDPROC>(
+                SetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC,
+                                 reinterpret_cast<LONG>(PluginWindowProc)));
+        }
+    }
+
 #else
 #  error Implement me for your OS
 #endif
 
-    *rv = mPluginIface->setwindow(&mData, &mWindow);
     return NS_OK;
 }
 
+bool
+NPPInstanceChild::Initialize()
+{
+#if defined(OS_WIN)
+  if (!CreatePluginWindow())
+      return false;
+#endif
+
+  return true;
+}
+
+#if defined(OS_WIN)
+
+static const TCHAR kWindowClassName[] = TEXT("GeckoPluginWindow");
+static const TCHAR kNPPInstanceChildProperty[] = TEXT("NPPInstanceChildProperty");
+
+// static
+bool
+NPPInstanceChild::RegisterWindowClass()
+{
+    static bool alreadyRegistered = false;
+    if (alreadyRegistered)
+        return true;
+
+    alreadyRegistered = true;
+
+    WNDCLASSEX wcex;
+    wcex.cbSize         = sizeof(WNDCLASSEX);
+    wcex.style          = CS_DBLCLKS;
+    wcex.lpfnWndProc    = DummyWindowProc;
+    wcex.cbClsExtra     = 0;
+    wcex.cbWndExtra     = 0;
+    wcex.hInstance      = GetModuleHandle(NULL);
+    wcex.hIcon          = 0;
+    wcex.hCursor        = 0;
+    wcex.hbrBackground  = reinterpret_cast<HBRUSH>(COLOR_WINDOW1);
+    wcex.lpszMenuName   = 0;
+    wcex.lpszClassName  = kWindowClassName;
+    wcex.hIconSm        = 0;
+
+    return RegisterClassEx(&wcex) ? true : false;
+}
+
+bool
+NPPInstanceChild::CreatePluginWindow()
+{
+    if (!RegisterWindowClass())
+        return false;
+
+    if (!mPluginWindowHWND) {
+        mPluginWindowHWND =
+            CreateWindowEx(WS_EX_LEFT | WS_EX_LTRREADING |
+                           WS_EX_NOPARENTNOTIFY | // XXXbent Get rid of this!
+                           WS_EX_RIGHTSCROLLBAR,
+                           kWindowClassName, 0,
+                           WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0,
+                           0, 0, NULL, 0, GetModuleHandle(NULL), 0);
+        if (!mPluginWindowHWND)
+            return false;
+        if (!SetProp(mPluginWindowHWND, kNPPInstanceChildProperty, this))
+            return false;
+
+        // Apparently some plugins require an ASCII WndProc.
+        SetWindowLongPtrA(mPluginWindowHWND, GWLP_WNDPROC,
+                          reinterpret_cast<LONG>(DefWindowProcA));
+    }
+
+    return true;
+}
+
+void
+NPPInstanceChild::DestroyPluginWindow()
+{
+    if (mPluginWindowHWND) {
+        // Unsubclass the window.
+        WNDPROC wndProc = reinterpret_cast<WNDPROC>(
+            GetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC));
+        if (wndProc == PluginWindowProc) {
+            NS_ASSERTION(mPluginWndProc, "Should have old proc here!");
+            SetWindowLongPtr(mPluginWindowHWND, GWLP_WNDPROC,
+                             reinterpret_cast<LONG>(mPluginWndProc));
+            mPluginWndProc = 0;
+        }
+
+        RemoveProp(mPluginWindowHWND, kNPPInstanceChildProperty);
+        DestroyWindow(mPluginWindowHWND);
+        mPluginWindowHWND = 0;
+    }
+}
+
+void
+NPPInstanceChild::ReparentPluginWindow(HWND hWndParent)
+{
+    if (hWndParent != mPluginParentHWND && IsWindow(hWndParent)) {
+        LONG style = GetWindowLongPtr(mPluginWindowHWND, GWL_STYLE);
+        style |= WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
+        SetWindowLongPtr(mPluginWindowHWND, GWL_STYLE, style);
+        SetParent(mPluginWindowHWND, hWndParent);
+        ShowWindow(mPluginWindowHWND, SW_SHOWNA);
+    }
+    mPluginParentHWND = hWndParent;
+}
+
+void
+NPPInstanceChild::SizePluginWindow(int width,
+                                   int height)
+{
+    if (mPluginWindowHWND) {
+        SetWindowPos(mPluginWindowHWND, NULL, 0, 0, width, height,
+                     SWP_NOZORDER | SWP_NOREPOSITION);
+    }
+}
+
+// See chromium's webplugin_delegate_impl.cc for explanation of this function.
+// static
+LRESULT CALLBACK
+NPPInstanceChild::DummyWindowProc(HWND hWnd,
+                                  UINT message,
+                                  WPARAM wParam,
+                                  LPARAM lParam)
+{
+    return CallWindowProc(DefWindowProc, hWnd, message, wParam, lParam);
+}
+
+// static
+LRESULT CALLBACK
+NPPInstanceChild::PluginWindowProc(HWND hWnd,
+                                   UINT message,
+                                   WPARAM wParam,
+                                   LPARAM lParam)
+{
+    NPPInstanceChild* self = reinterpret_cast<NPPInstanceChild*>(
+        GetProp(hWnd, kNPPInstanceChildProperty));
+    if (!self) {
+        NS_NOTREACHED("Badness!");
+        return 0;
+    }
+
+    NS_ASSERTION(self->mPluginWindowHWND == hWnd, "Wrong window!");
+
+    LRESULT res = CallWindowProc(self->mPluginWndProc, hWnd, message, wParam,
+                                 lParam);
+
+    if (message == WM_CLOSE)
+        self->DestroyPluginWindow();
+
+    if (message == WM_NCDESTROY)
+        RemoveProp(hWnd, kNPPInstanceChildProperty);
+
+    return res;
+}
+
+#endif // OS_WIN
+
 
 } // namespace plugins
 } // namespace mozilla
--- a/dom/plugins/NPPInstanceChild.h
+++ b/dom/plugins/NPPInstanceChild.h
@@ -47,49 +47,86 @@
 #define _MOZ_LOG(s) printf("[NPPInstanceChild] %s\n", s)
 
 namespace mozilla {
 namespace plugins {
 //-----------------------------------------------------------------------------
 
 class NPPInstanceChild : public NPPProtocolChild
 {
+#ifdef OS_WIN
+    friend LRESULT CALLBACK PluginWindowProc(HWND hWnd,
+                                             UINT message,
+                                             WPARAM wParam,
+                                             LPARAM lParam);
+#endif
+
 protected:
     virtual nsresult AnswerNPP_SetWindow(const NPWindow& window, NPError* rv);
 
     virtual nsresult AnswerNPP_GetValue(const String& key, String* value);
 
 public:
     NPPInstanceChild(const NPPluginFuncs* aPluginIface) :
         mPluginIface(aPluginIface)
+#if defined(OS_LINUX)
+        , mPlug(0)
+#elif defined(OS_WIN)
+        , mPluginWindowHWND(0)
+        , mPluginWndProc(0)
+        , mPluginParentHWND(0)
+#endif
     {
         memset(&mWindow, 0, sizeof(mWindow));
         mData.ndata = (void*) this;
+#if defined(OS_LINUX)
+        memset(&mWsInfo, 0, sizeof(mWsInfo));
+#endif
     }
 
-    virtual ~NPPInstanceChild()
-    {
+    virtual ~NPPInstanceChild();
 
-    }
+    bool Initialize();
 
     NPP GetNPP()
     {
         return &mData;
     }
 
     NPError NPN_GetValue(NPNVariable aVariable, void* aValue);
 
 private:
+
+#if defined(OS_WIN)
+    static bool RegisterWindowClass();
+    bool CreatePluginWindow();
+    void DestroyPluginWindow();
+    void ReparentPluginWindow(HWND hWndParent);
+    void SizePluginWindow(int width, int height);
+    static LRESULT CALLBACK DummyWindowProc(HWND hWnd,
+                                            UINT message,
+                                            WPARAM wParam,
+                                            LPARAM lParam);
+    static LRESULT CALLBACK PluginWindowProc(HWND hWnd,
+                                             UINT message,
+                                             WPARAM wParam,
+                                             LPARAM lParam);
+#endif
+
     const NPPluginFuncs* mPluginIface;
     NPP_t mData;
 #ifdef OS_LINUX
     GtkWidget* mPlug;
 #endif
     NPWindow mWindow;
 #ifdef OS_LINUX
     NPSetWindowCallbackStruct mWsInfo;
+#elif defined(OS_WIN)
+    HWND mPluginWindowHWND;
+    WNDPROC mPluginWndProc;
+    HWND mPluginParentHWND;
 #endif
 };
 
 } // namespace plugins
 } // namespace mozilla
 
 #endif // ifndef dom_plugins_NPPInstanceChild_h
--- a/ipc/glue/MessagePump.cpp
+++ b/ipc/glue/MessagePump.cpp
@@ -33,135 +33,81 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "MessagePump.h"
 
 #include "nsIAppShell.h"
 #include "nsIThread.h"
-#include "nsIThreadInternal.h"
+#include "nsITimer.h"
 
+#include "nsComponentManagerUtils.h"
 #include "nsCOMPtr.h"
 #include "nsServiceManagerUtils.h"
 #include "nsStringGlue.h"
 #include "nsThreadUtils.h"
 #include "nsWidgetsCID.h"
+#include "pratom.h"
 #include "prthread.h"
 
 #include "base/logging.h"
 #include "base/scoped_nsautorelease_pool.h"
 
 using mozilla::ipc::MessagePump;
 using mozilla::ipc::MessagePumpForChildProcess;
 
 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
 
-namespace mozilla {
-namespace ipc {
-
-class UIThreadObserver : public nsIThreadObserver
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSITHREADOBSERVER
+namespace {
 
-  UIThreadObserver(MessagePump& aPump,
-                   nsIThreadObserver* aRealObserver)
-  : mPump(aPump),
-    mRealObserver(aRealObserver),
-    mPRThread(PR_GetCurrentThread())
-  {
-    NS_ASSERTION(aRealObserver, "This should never be null!");
-  }
-
-private:
-  MessagePump& mPump;
-  nsIThreadObserver* mRealObserver;
-  PRThread* mPRThread;
-};
-
-} /* namespace ipc */
-} /* namespace mozilla */
-
-using mozilla::ipc::UIThreadObserver;
-
-NS_IMETHODIMP_(nsrefcnt)
-UIThreadObserver::AddRef()
+void
+TimerCallback(nsITimer* aTimer,
+              void* aClosure)
 {
-  return 2;
+  MessagePump* messagePump = reinterpret_cast<MessagePump*>(aClosure);
+  messagePump->ScheduleWork();
 }
 
-NS_IMETHODIMP_(nsrefcnt)
-UIThreadObserver::Release()
+} /* anonymous namespace */
+
+MessagePump::MessagePump()
+: mThread(nsnull)
 {
-  return 1;
+  mDummyEvent = new nsRunnable();
+  // I'm tired of adding OOM checks.
+  NS_ADDREF(mDummyEvent);
 }
 
-NS_IMPL_QUERY_INTERFACE1(UIThreadObserver, nsIThreadObserver)
-
-NS_IMETHODIMP
-UIThreadObserver::OnDispatchedEvent(nsIThreadInternal* aThread)
+MessagePump::~MessagePump()
 {
-  // XXXbent See if we can figure out some faster way of doing this. On posix
-  // the Signal() call grabs a lock and on windows it calls SetEvent. Seems
-  // like a good idea to avoid calling Signal if we're on the main thead.
-  if (PR_GetCurrentThread() != mPRThread) {
-    mPump.event_.Signal();
-  }
-  return mRealObserver->OnDispatchedEvent(aThread);
-}
-
-NS_IMETHODIMP
-UIThreadObserver::OnProcessNextEvent(nsIThreadInternal* aThread,
-                                     PRBool aMayWait,
-                                     PRUint32 aRecursionDepth)
-{
-  return mRealObserver->OnProcessNextEvent(aThread, aMayWait, aRecursionDepth);
-}
-
-NS_IMETHODIMP
-UIThreadObserver::AfterProcessNextEvent(nsIThreadInternal* aThread,
-                                        PRUint32 aRecursionDepth)
-{
-  return mRealObserver->AfterProcessNextEvent(aThread, aRecursionDepth);
+  NS_RELEASE(mDummyEvent);
 }
 
 void
 MessagePump::Run(MessagePump::Delegate* aDelegate)
 {
   NS_ASSERTION(keep_running_, "Quit must have been called outside of Run!");
 
-  nsCOMPtr<nsIThread> thread(do_GetCurrentThread());
-  NS_ASSERTION(thread, "This should never be null!");
-
-  nsCOMPtr<nsIThreadInternal> threadInternal(do_QueryInterface(thread));
-  NS_ASSERTION(threadInternal, "QI failed?!");
-
-  nsCOMPtr<nsIThreadObserver> realObserver;
-  threadInternal->GetObserver(getter_AddRefs(realObserver));
-  NS_ASSERTION(realObserver, "This should never be null!");
+  NS_ASSERTION(NS_IsMainThread(),
+               "This should only ever happen on Gecko's main thread!");
 
-  UIThreadObserver observer(*this, realObserver);
-  threadInternal->SetObserver(&observer);
+  mThread = NS_GetCurrentThread();
+  NS_ASSERTION(mThread, "This should never be null!");
 
-#ifdef DEBUG
-  {
-    nsCOMPtr<nsIAppShell> appShell(do_QueryInterface(realObserver));
-    NS_ASSERTION(appShell, "Should be the app shell!");
-  }
-#endif
+  nsCOMPtr<nsITimer> timer(do_CreateInstance(NS_TIMER_CONTRACTID));
+  NS_ASSERTION(timer, "Failed to create timer!");
 
+  base::ScopedNSAutoreleasePool autoReleasePool;
 
   for (;;) {
-    // XXXbent This looks fishy... Maybe have one that calls Recycle each time
-    // through the loop? Copied straight from message_pump_default.
-    base::ScopedNSAutoreleasePool autorelease_pool;
+    autoReleasePool.Recycle();
+    timer->Cancel();
 
-    bool did_work = NS_ProcessNextEvent(thread, PR_FALSE) ? true : false;
+    bool did_work = NS_ProcessNextEvent(mThread, PR_FALSE) ? true : false;
     if (!keep_running_)
       break;
 
     did_work |= aDelegate->DoWork();
     if (!keep_running_)
       break;
 
     did_work |= aDelegate->DoDelayedWork(&delayed_work_time_);
@@ -174,36 +120,52 @@ MessagePump::Run(MessagePump::Delegate* 
     did_work = aDelegate->DoIdleWork();
     if (!keep_running_)
       break;
 
     if (did_work)
       continue;
 
     if (delayed_work_time_.is_null()) {
-      event_.Wait();
-    } else {
-      base::TimeDelta delay = delayed_work_time_ - base::Time::Now();
-      if (delay > base::TimeDelta()) {
-        event_.TimedWait(delay);
-      } else {
-        // It looks like delayed_work_time_ indicates a time in the past, so we
-        // need to call DoDelayedWork now.
-        delayed_work_time_ = base::Time();
-      }
+      // This will sleep or process native events.
+      NS_ProcessNextEvent(mThread, PR_TRUE);
+      continue;
     }
-    // Since event_ is auto-reset, we don't need to do anything special here
-    // other than service each delegate method.
+
+    base::TimeDelta delay = delayed_work_time_ - base::Time::Now();
+    if (delay > base::TimeDelta()) {
+      PRUint32 delayMS = PRUint32(delay.InMilliseconds());
+      timer->InitWithFuncCallback(TimerCallback, this, delayMS,
+                                  nsITimer::TYPE_ONE_SHOT);
+      // This will sleep or process native events. The timer should wake us up
+      // if nothing else does.
+      NS_ProcessNextEvent(mThread, PR_TRUE);
+      continue;
+    }
+
+    // It looks like delayed_work_time_ indicates a time in the past, so we
+    // need to call DoDelayedWork now.
+    delayed_work_time_ = base::Time();
   }
 
-  threadInternal->SetObserver(realObserver);
+  timer->Cancel();
 
   keep_running_ = true;
 }
 
+void
+MessagePump::ScheduleWork()
+{
+  // Make sure the event loop wakes up.
+  if (mThread) {
+    mThread->Dispatch(mDummyEvent, NS_DISPATCH_NORMAL);
+    event_.Signal();
+  }
+}
+
 #ifdef DEBUG
 namespace {
 MessagePump::Delegate* gFirstDelegate = nsnull;
 }
 #endif
 
 void
 MessagePumpForChildProcess::Run(MessagePump::Delegate* aDelegate)
@@ -223,13 +185,15 @@ MessagePumpForChildProcess::Run(MessageP
       }
     }
 #ifdef DEBUG
     NS_ASSERTION(aDelegate && aDelegate == gFirstDelegate, "Huh?!");
     gFirstDelegate = nsnull;
 #endif
     return;
   }
+
 #ifdef DEBUG
   NS_ASSERTION(aDelegate && aDelegate == gFirstDelegate, "Huh?!");
 #endif
+  // Really run.
   mozilla::ipc::MessagePump::Run(aDelegate);
 }
--- a/ipc/glue/MessagePump.h
+++ b/ipc/glue/MessagePump.h
@@ -34,25 +34,39 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef __IPC_GLUE_MESSAGEPUMP_H__
 #define __IPC_GLUE_MESSAGEPUMP_H__
 
 #include "base/message_pump_default.h"
 
+#include "prtypes.h"
+#include "nsCOMPtr.h"
+
+class nsIRunnable;
+class nsIThread;
+
 namespace mozilla {
 namespace ipc {
 
 class MessagePump : public base::MessagePumpDefault
 {
 public:
-  friend class UIThreadObserver;
+  MessagePump();
+  ~MessagePump();
 
   virtual void Run(base::MessagePump::Delegate* aDelegate);
+  virtual void ScheduleWork();
+
+private:
+  nsIRunnable* mDummyEvent;
+
+  // Weak!
+  nsIThread* mThread;
 };
 
 class MessagePumpForChildProcess : public MessagePump
 {
 public:
   MessagePumpForChildProcess()
   : mFirstRun(true)
   { }
--- a/modules/plugin/base/src/nsPluginNativeWindowWin.cpp
+++ b/modules/plugin/base/src/nsPluginNativeWindowWin.cpp
@@ -537,16 +537,20 @@ nsresult nsPluginNativeWindowWin::Subcla
   if (!hWnd)
     return NS_ERROR_FAILURE;
 
   // check if we need to re-subclass
   WNDPROC currentWndProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_WNDPROC);
   if (PluginWndProc == currentWndProc)
     return NS_OK;
 
+  LONG style = GetWindowLongPtr(hWnd, GWL_STYLE);
+  style |= WS_CLIPCHILDREN;
+  SetWindowLongPtr(hWnd, GWL_STYLE, style);
+
   mPluginWinProc = SubclassWindow(hWnd, (LONG_PTR)PluginWndProc);
   if (!mPluginWinProc)
     return NS_ERROR_FAILURE;
 
   nsPluginNativeWindowWin * win = (nsPluginNativeWindowWin *)::GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION);
   NS_ASSERTION(!win || (win == this), "plugin window already has property and this is not us");
   
   if (!::SetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION, (HANDLE)this))
@@ -566,16 +570,20 @@ nsresult nsPluginNativeWindowWin::UndoSu
     ::RemoveProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION);
 
   // restore the original win proc
   // but only do this if this were us last time
   if (mPluginWinProc) {
     WNDPROC currentWndProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_WNDPROC);
     if (currentWndProc == PluginWndProc)
       SubclassWindow(hWnd, (LONG_PTR)mPluginWinProc);
+
+    LONG style = GetWindowLongPtr(hWnd, GWL_STYLE);
+    style &= ~WS_CLIPCHILDREN;
+    SetWindowLongPtr(hWnd, GWL_STYLE, style);
   }
 
   return NS_OK;
 }
 #endif // WINCE
 
 nsresult PLUG_NewPluginNativeWindow(nsPluginNativeWindow ** aPluginNativeWindow)
 {
--- a/modules/plugin/test/testplugin/nptest_gtk2.cpp
+++ b/modules/plugin/test/testplugin/nptest_gtk2.cpp
@@ -149,17 +149,17 @@ pluginDrawWindow(InstanceData* instanceD
   NPWindow& window = instanceData->window;
   // When we have a widget, window.x/y are meaningless since our
   // widget is always positioned correctly and we just draw into it at 0,0
   int x = instanceData->hasWidget ? 0 : window.x;
   int y = instanceData->hasWidget ? 0 : window.y;
   int width = window.width;
   int height = window.height;
 
-  if (instanceData->scriptableObject->drawMode == DM_SOLID_COLOR) {
+  if (0 && instanceData->scriptableObject->drawMode == DM_SOLID_COLOR) {
     // drawing a solid color for reftests
     pluginDrawSolid(instanceData, gdkWindow, x, y, width, height);
     return;
   }
 
   NPP npp = instanceData->npp;
   if (!npp)
     return;