michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/BasicEvents.h" michael@0: #include "mozilla/DebugOnly.h" michael@0: michael@0: #include "windows.h" michael@0: #include "windowsx.h" michael@0: michael@0: // XXXbz windowsx.h defines GetFirstChild, GetNextSibling, michael@0: // GetPrevSibling are macros, apparently... Eeevil. We have functions michael@0: // called that on some classes, so undef them. michael@0: #undef GetFirstChild michael@0: #undef GetNextSibling michael@0: #undef GetPrevSibling michael@0: michael@0: #include "nsDebug.h" michael@0: michael@0: #include "nsWindowsDllInterceptor.h" michael@0: #include "nsPluginNativeWindow.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsTWeakRef.h" michael@0: #include "nsCrashOnException.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: #define NP_POPUP_API_VERSION 16 michael@0: michael@0: #define nsMajorVersion(v) (((int32_t)(v) >> 16) & 0xffff) michael@0: #define nsMinorVersion(v) ((int32_t)(v) & 0xffff) michael@0: #define versionOK(suppliedV, requiredV) \ michael@0: (nsMajorVersion(suppliedV) == nsMajorVersion(requiredV) \ michael@0: && nsMinorVersion(suppliedV) >= nsMinorVersion(requiredV)) michael@0: michael@0: michael@0: #define NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION TEXT("MozillaPluginWindowPropertyAssociation") michael@0: #define NS_PLUGIN_CUSTOM_MSG_ID TEXT("MozFlashUserRelay") michael@0: #define WM_USER_FLASH WM_USER+1 michael@0: static UINT sWM_FLASHBOUNCEMSG = 0; michael@0: michael@0: typedef nsTWeakRef PluginWindowWeakRef; michael@0: michael@0: /** michael@0: * PLEvent handling code michael@0: */ michael@0: class PluginWindowEvent : public nsRunnable { michael@0: public: michael@0: PluginWindowEvent(); michael@0: void Init(const PluginWindowWeakRef &ref, HWND hWnd, UINT msg, WPARAM wParam, michael@0: LPARAM lParam); michael@0: void Clear(); michael@0: HWND GetWnd() { return mWnd; }; michael@0: UINT GetMsg() { return mMsg; }; michael@0: WPARAM GetWParam() { return mWParam; }; michael@0: LPARAM GetLParam() { return mLParam; }; michael@0: bool InUse() { return mWnd != nullptr; }; michael@0: michael@0: NS_DECL_NSIRUNNABLE michael@0: michael@0: protected: michael@0: PluginWindowWeakRef mPluginWindowRef; michael@0: HWND mWnd; michael@0: UINT mMsg; michael@0: WPARAM mWParam; michael@0: LPARAM mLParam; michael@0: }; michael@0: michael@0: PluginWindowEvent::PluginWindowEvent() michael@0: { michael@0: Clear(); michael@0: } michael@0: michael@0: void PluginWindowEvent::Clear() michael@0: { michael@0: mWnd = nullptr; michael@0: mMsg = 0; michael@0: mWParam = 0; michael@0: mLParam = 0; michael@0: } michael@0: michael@0: void PluginWindowEvent::Init(const PluginWindowWeakRef &ref, HWND aWnd, michael@0: UINT aMsg, WPARAM aWParam, LPARAM aLParam) michael@0: { michael@0: NS_ASSERTION(aWnd != nullptr, "invalid plugin event value"); michael@0: NS_ASSERTION(mWnd == nullptr, "event already in use"); michael@0: mPluginWindowRef = ref; michael@0: mWnd = aWnd; michael@0: mMsg = aMsg; michael@0: mWParam = aWParam; michael@0: mLParam = aLParam; michael@0: } michael@0: michael@0: /** michael@0: * nsPluginNativeWindow Windows specific class declaration michael@0: */ michael@0: michael@0: typedef enum { michael@0: nsPluginType_Unknown = 0, michael@0: nsPluginType_Flash, michael@0: nsPluginType_Real, michael@0: nsPluginType_PDF, michael@0: nsPluginType_Other michael@0: } nsPluginType; michael@0: michael@0: class nsPluginNativeWindowWin : public nsPluginNativeWindow { michael@0: public: michael@0: nsPluginNativeWindowWin(); michael@0: virtual ~nsPluginNativeWindowWin(); michael@0: michael@0: virtual nsresult CallSetWindow(nsRefPtr &aPluginInstance); michael@0: michael@0: private: michael@0: nsresult SubclassAndAssociateWindow(); michael@0: nsresult UndoSubclassAndAssociateWindow(); michael@0: michael@0: public: michael@0: // locals michael@0: WNDPROC GetPrevWindowProc(); michael@0: void SetPrevWindowProc(WNDPROC proc) { mPluginWinProc = proc; } michael@0: WNDPROC GetWindowProc(); michael@0: PluginWindowEvent * GetPluginWindowEvent(HWND aWnd, michael@0: UINT aMsg, michael@0: WPARAM aWParam, michael@0: LPARAM aLParam); michael@0: michael@0: private: michael@0: WNDPROC mPluginWinProc; michael@0: WNDPROC mPrevWinProc; michael@0: PluginWindowWeakRef mWeakRef; michael@0: nsRefPtr mCachedPluginWindowEvent; michael@0: michael@0: HWND mParentWnd; michael@0: LONG_PTR mParentProc; michael@0: public: michael@0: nsPluginType mPluginType; michael@0: }; michael@0: michael@0: static bool sInMessageDispatch = false; michael@0: static bool sInPreviousMessageDispatch = false; michael@0: static UINT sLastMsg = 0; michael@0: michael@0: static bool ProcessFlashMessageDelayed(nsPluginNativeWindowWin * aWin, nsNPAPIPluginInstance * aInst, michael@0: HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) michael@0: { michael@0: NS_ENSURE_TRUE(aWin, false); michael@0: NS_ENSURE_TRUE(aInst, false); michael@0: michael@0: if (msg == sWM_FLASHBOUNCEMSG) { michael@0: // See PluginWindowEvent::Run() below. michael@0: NS_ASSERTION((sWM_FLASHBOUNCEMSG != 0), "RegisterWindowMessage failed in flash plugin WM_USER message handling!"); michael@0: ::CallWindowProc((WNDPROC)aWin->GetWindowProc(), hWnd, WM_USER_FLASH, wParam, lParam); michael@0: return true; michael@0: } michael@0: michael@0: if (msg != WM_USER_FLASH) michael@0: return false; // no need to delay michael@0: michael@0: // do stuff michael@0: nsCOMPtr pwe = aWin->GetPluginWindowEvent(hWnd, msg, wParam, lParam); michael@0: if (pwe) { michael@0: NS_DispatchToCurrentThread(pwe); michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: class nsDelayedPopupsEnabledEvent : public nsRunnable michael@0: { michael@0: public: michael@0: nsDelayedPopupsEnabledEvent(nsNPAPIPluginInstance *inst) michael@0: : mInst(inst) michael@0: {} michael@0: michael@0: NS_DECL_NSIRUNNABLE michael@0: michael@0: private: michael@0: nsRefPtr mInst; michael@0: }; michael@0: michael@0: NS_IMETHODIMP nsDelayedPopupsEnabledEvent::Run() michael@0: { michael@0: mInst->PushPopupsEnabledState(false); michael@0: return NS_OK; michael@0: } michael@0: michael@0: static LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); michael@0: michael@0: /** michael@0: * New plugin window procedure michael@0: */ michael@0: static LRESULT CALLBACK PluginWndProcInternal(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) michael@0: { michael@0: nsPluginNativeWindowWin * win = (nsPluginNativeWindowWin *)::GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); michael@0: if (!win) michael@0: return TRUE; michael@0: michael@0: // The DispatchEvent(NS_PLUGIN_ACTIVATE) below can trigger a reentrant focus michael@0: // event which might destroy us. Hold a strong ref on the plugin instance michael@0: // to prevent that, bug 374229. michael@0: nsRefPtr inst; michael@0: win->GetPluginInstance(inst); michael@0: michael@0: // Real may go into a state where it recursivly dispatches the same event michael@0: // when subclassed. If this is Real, lets examine the event and drop it michael@0: // on the floor if we get into this recursive situation. See bug 192914. michael@0: if (win->mPluginType == nsPluginType_Real) { michael@0: if (sInMessageDispatch && msg == sLastMsg) michael@0: return true; michael@0: // Cache the last message sent michael@0: sLastMsg = msg; michael@0: } michael@0: michael@0: bool enablePopups = false; michael@0: michael@0: // Activate/deactivate mouse capture on the plugin widget michael@0: // here, before we pass the Windows event to the plugin michael@0: // because its possible our widget won't get paired events michael@0: // (see bug 131007) and we'll look frozen. Note that this michael@0: // is also done in ChildWindow::DispatchMouseEvent. michael@0: switch (msg) { michael@0: case WM_LBUTTONDOWN: michael@0: case WM_MBUTTONDOWN: michael@0: case WM_RBUTTONDOWN: { michael@0: nsCOMPtr widget; michael@0: win->GetPluginWidget(getter_AddRefs(widget)); michael@0: if (widget) michael@0: widget->CaptureMouse(true); michael@0: break; michael@0: } michael@0: case WM_LBUTTONUP: michael@0: enablePopups = true; michael@0: michael@0: // fall through michael@0: case WM_MBUTTONUP: michael@0: case WM_RBUTTONUP: { michael@0: nsCOMPtr widget; michael@0: win->GetPluginWidget(getter_AddRefs(widget)); michael@0: if (widget) michael@0: widget->CaptureMouse(false); michael@0: break; michael@0: } michael@0: case WM_KEYDOWN: michael@0: // Ignore repeating keydown messages... michael@0: if ((lParam & 0x40000000) != 0) { michael@0: break; michael@0: } michael@0: michael@0: // fall through michael@0: case WM_KEYUP: michael@0: enablePopups = true; michael@0: michael@0: break; michael@0: michael@0: case WM_MOUSEACTIVATE: { michael@0: // If a child window of this plug-in is already focused, michael@0: // don't focus the parent to avoid focus dance. We'll michael@0: // receive a follow up WM_SETFOCUS which will notify michael@0: // the appropriate window anyway. michael@0: HWND focusedWnd = ::GetFocus(); michael@0: if (!::IsChild((HWND)win->window, focusedWnd)) { michael@0: // Notify the dom / focus manager the plugin has focus when one of michael@0: // it's child windows receives it. OOPP specific - this code is michael@0: // critical in notifying the dom of focus changes when the plugin michael@0: // window in the child process receives focus via a mouse click. michael@0: // WM_MOUSEACTIVATE is sent by nsWindow via a custom window event michael@0: // sent from PluginInstanceParent in response to focus events sent michael@0: // from the child. (bug 540052) Note, this gui event could also be michael@0: // sent directly from widget. michael@0: nsCOMPtr widget; michael@0: win->GetPluginWidget(getter_AddRefs(widget)); michael@0: if (widget) { michael@0: WidgetGUIEvent event(true, NS_PLUGIN_ACTIVATE, widget); michael@0: nsEventStatus status; michael@0: widget->DispatchEvent(&event, status); michael@0: } michael@0: } michael@0: } michael@0: break; michael@0: michael@0: case WM_SETFOCUS: michael@0: case WM_KILLFOCUS: { michael@0: // RealPlayer can crash, don't process the message for those, michael@0: // see bug 328675. michael@0: if (win->mPluginType == nsPluginType_Real && msg == sLastMsg) michael@0: return TRUE; michael@0: // Make sure setfocus and killfocus get through to the widget procedure michael@0: // even if they are eaten by the plugin. Also make sure we aren't calling michael@0: // recursively. michael@0: WNDPROC prevWndProc = win->GetPrevWindowProc(); michael@0: if (prevWndProc && !sInPreviousMessageDispatch) { michael@0: sInPreviousMessageDispatch = true; michael@0: ::CallWindowProc(prevWndProc, hWnd, msg, wParam, lParam); michael@0: sInPreviousMessageDispatch = false; michael@0: } michael@0: break; michael@0: } michael@0: } michael@0: michael@0: // Macromedia Flash plugin may flood the message queue with some special messages michael@0: // (WM_USER+1) causing 100% CPU consumption and GUI freeze, see mozilla bug 132759; michael@0: // we can prevent this from happening by delaying the processing such messages; michael@0: if (win->mPluginType == nsPluginType_Flash) { michael@0: if (ProcessFlashMessageDelayed(win, inst, hWnd, msg, wParam, lParam)) michael@0: return TRUE; michael@0: } michael@0: michael@0: if (enablePopups && inst) { michael@0: uint16_t apiVersion; michael@0: if (NS_SUCCEEDED(inst->GetPluginAPIVersion(&apiVersion)) && michael@0: !versionOK(apiVersion, NP_POPUP_API_VERSION)) { michael@0: inst->PushPopupsEnabledState(true); michael@0: } michael@0: } michael@0: michael@0: sInMessageDispatch = true; michael@0: LRESULT res; michael@0: WNDPROC proc = (WNDPROC)win->GetWindowProc(); michael@0: if (PluginWndProc == proc) { michael@0: NS_WARNING("Previous plugin window procedure references PluginWndProc! " michael@0: "Report this bug!"); michael@0: res = CallWindowProc(DefWindowProc, hWnd, msg, wParam, lParam); michael@0: } else { michael@0: res = CallWindowProc(proc, hWnd, msg, wParam, lParam); michael@0: } michael@0: sInMessageDispatch = false; michael@0: michael@0: if (inst) { michael@0: // Popups are enabled (were enabled before the call to michael@0: // CallWindowProc()). Some plugins (at least the flash player) michael@0: // post messages from their key handlers etc that delay the actual michael@0: // processing, so we need to delay the disabling of popups so that michael@0: // popups remain enabled when the flash player ends up processing michael@0: // the actual key handlers. We do this by posting an event that michael@0: // does the disabling, this way our disabling will happen after michael@0: // the handlers in the plugin are done. michael@0: michael@0: // Note that it's not fatal if any of this fails (which won't michael@0: // happen unless we're out of memory anyways) since the plugin michael@0: // code will pop any popup state pushed by this plugin on michael@0: // destruction. michael@0: michael@0: nsCOMPtr event = new nsDelayedPopupsEnabledEvent(inst); michael@0: if (event) michael@0: NS_DispatchToCurrentThread(event); michael@0: } michael@0: michael@0: return res; michael@0: } michael@0: michael@0: static LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) michael@0: { michael@0: return mozilla::CallWindowProcCrashProtected(PluginWndProcInternal, hWnd, msg, wParam, lParam); michael@0: } michael@0: michael@0: /* michael@0: * Flash will reset the subclass of our widget at various times. michael@0: * (Notably when entering and exiting full screen mode.) This michael@0: * occurs independent of the main plugin window event procedure. michael@0: * We trap these subclass calls to prevent our subclass hook from michael@0: * getting dropped. michael@0: * Note, ascii versions can be nixed once flash versions < 10.1 michael@0: * are considered obsolete. michael@0: */ michael@0: static WindowsDllInterceptor sUser32Intercept; michael@0: michael@0: #ifdef _WIN64 michael@0: typedef LONG_PTR michael@0: (WINAPI *User32SetWindowLongPtrA)(HWND hWnd, michael@0: int nIndex, michael@0: LONG_PTR dwNewLong); michael@0: typedef LONG_PTR michael@0: (WINAPI *User32SetWindowLongPtrW)(HWND hWnd, michael@0: int nIndex, michael@0: LONG_PTR dwNewLong); michael@0: static User32SetWindowLongPtrA sUser32SetWindowLongAHookStub = nullptr; michael@0: static User32SetWindowLongPtrW sUser32SetWindowLongWHookStub = nullptr; michael@0: #else michael@0: typedef LONG michael@0: (WINAPI *User32SetWindowLongA)(HWND hWnd, michael@0: int nIndex, michael@0: LONG dwNewLong); michael@0: typedef LONG michael@0: (WINAPI *User32SetWindowLongW)(HWND hWnd, michael@0: int nIndex, michael@0: LONG dwNewLong); michael@0: static User32SetWindowLongA sUser32SetWindowLongAHookStub = nullptr; michael@0: static User32SetWindowLongW sUser32SetWindowLongWHookStub = nullptr; michael@0: #endif michael@0: static inline bool michael@0: SetWindowLongHookCheck(HWND hWnd, michael@0: int nIndex, michael@0: LONG_PTR newLong) michael@0: { michael@0: nsPluginNativeWindowWin * win = michael@0: (nsPluginNativeWindowWin *)GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); michael@0: if (!win || (win && win->mPluginType != nsPluginType_Flash) || michael@0: (nIndex == GWLP_WNDPROC && michael@0: newLong == reinterpret_cast(PluginWndProc))) michael@0: return true; michael@0: return false; michael@0: } michael@0: michael@0: #ifdef _WIN64 michael@0: LONG_PTR WINAPI michael@0: SetWindowLongPtrAHook(HWND hWnd, michael@0: int nIndex, michael@0: LONG_PTR newLong) michael@0: #else michael@0: LONG WINAPI michael@0: SetWindowLongAHook(HWND hWnd, michael@0: int nIndex, michael@0: LONG newLong) michael@0: #endif michael@0: { michael@0: if (SetWindowLongHookCheck(hWnd, nIndex, newLong)) michael@0: return sUser32SetWindowLongAHookStub(hWnd, nIndex, newLong); michael@0: michael@0: // Set flash's new subclass to get the result. michael@0: LONG_PTR proc = sUser32SetWindowLongAHookStub(hWnd, nIndex, newLong); michael@0: michael@0: // We already checked this in SetWindowLongHookCheck michael@0: nsPluginNativeWindowWin * win = michael@0: (nsPluginNativeWindowWin *)GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); michael@0: michael@0: // Hook our subclass back up, just like we do on setwindow. michael@0: win->SetPrevWindowProc( michael@0: reinterpret_cast(sUser32SetWindowLongWHookStub(hWnd, nIndex, michael@0: reinterpret_cast(PluginWndProc)))); michael@0: return proc; michael@0: } michael@0: michael@0: #ifdef _WIN64 michael@0: LONG_PTR WINAPI michael@0: SetWindowLongPtrWHook(HWND hWnd, michael@0: int nIndex, michael@0: LONG_PTR newLong) michael@0: #else michael@0: LONG WINAPI michael@0: SetWindowLongWHook(HWND hWnd, michael@0: int nIndex, michael@0: LONG newLong) michael@0: #endif michael@0: { michael@0: if (SetWindowLongHookCheck(hWnd, nIndex, newLong)) michael@0: return sUser32SetWindowLongWHookStub(hWnd, nIndex, newLong); michael@0: michael@0: // Set flash's new subclass to get the result. michael@0: LONG_PTR proc = sUser32SetWindowLongWHookStub(hWnd, nIndex, newLong); michael@0: michael@0: // We already checked this in SetWindowLongHookCheck michael@0: nsPluginNativeWindowWin * win = michael@0: (nsPluginNativeWindowWin *)GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); michael@0: michael@0: // Hook our subclass back up, just like we do on setwindow. michael@0: win->SetPrevWindowProc( michael@0: reinterpret_cast(sUser32SetWindowLongWHookStub(hWnd, nIndex, michael@0: reinterpret_cast(PluginWndProc)))); michael@0: return proc; michael@0: } michael@0: michael@0: static void michael@0: HookSetWindowLongPtr() michael@0: { michael@0: sUser32Intercept.Init("user32.dll"); michael@0: #ifdef _WIN64 michael@0: if (!sUser32SetWindowLongAHookStub) michael@0: sUser32Intercept.AddHook("SetWindowLongPtrA", michael@0: reinterpret_cast(SetWindowLongPtrAHook), michael@0: (void**) &sUser32SetWindowLongAHookStub); michael@0: if (!sUser32SetWindowLongWHookStub) michael@0: sUser32Intercept.AddHook("SetWindowLongPtrW", michael@0: reinterpret_cast(SetWindowLongPtrWHook), michael@0: (void**) &sUser32SetWindowLongWHookStub); michael@0: #else michael@0: if (!sUser32SetWindowLongAHookStub) michael@0: sUser32Intercept.AddHook("SetWindowLongA", michael@0: reinterpret_cast(SetWindowLongAHook), michael@0: (void**) &sUser32SetWindowLongAHookStub); michael@0: if (!sUser32SetWindowLongWHookStub) michael@0: sUser32Intercept.AddHook("SetWindowLongW", michael@0: reinterpret_cast(SetWindowLongWHook), michael@0: (void**) &sUser32SetWindowLongWHookStub); michael@0: #endif michael@0: } michael@0: michael@0: /** michael@0: * nsPluginNativeWindowWin implementation michael@0: */ michael@0: nsPluginNativeWindowWin::nsPluginNativeWindowWin() : nsPluginNativeWindow() michael@0: { michael@0: // initialize the struct fields michael@0: window = nullptr; michael@0: x = 0; michael@0: y = 0; michael@0: width = 0; michael@0: height = 0; michael@0: michael@0: mPrevWinProc = nullptr; michael@0: mPluginWinProc = nullptr; michael@0: mPluginType = nsPluginType_Unknown; michael@0: michael@0: mParentWnd = nullptr; michael@0: mParentProc = 0; michael@0: michael@0: if (!sWM_FLASHBOUNCEMSG) { michael@0: sWM_FLASHBOUNCEMSG = ::RegisterWindowMessage(NS_PLUGIN_CUSTOM_MSG_ID); michael@0: } michael@0: } michael@0: michael@0: nsPluginNativeWindowWin::~nsPluginNativeWindowWin() michael@0: { michael@0: // clear weak reference to self to prevent any pending events from michael@0: // dereferencing this. michael@0: mWeakRef.forget(); michael@0: } michael@0: michael@0: WNDPROC nsPluginNativeWindowWin::GetPrevWindowProc() michael@0: { michael@0: return mPrevWinProc; michael@0: } michael@0: michael@0: WNDPROC nsPluginNativeWindowWin::GetWindowProc() michael@0: { michael@0: return mPluginWinProc; michael@0: } michael@0: michael@0: NS_IMETHODIMP PluginWindowEvent::Run() michael@0: { michael@0: nsPluginNativeWindowWin *win = mPluginWindowRef.get(); michael@0: if (!win) michael@0: return NS_OK; michael@0: michael@0: HWND hWnd = GetWnd(); michael@0: if (!hWnd) michael@0: return NS_OK; michael@0: michael@0: nsRefPtr inst; michael@0: win->GetPluginInstance(inst); michael@0: michael@0: if (GetMsg() == WM_USER_FLASH) { michael@0: // XXX Unwind issues related to runnable event callback depth for this michael@0: // event and destruction of the plugin. (Bug 493601) michael@0: ::PostMessage(hWnd, sWM_FLASHBOUNCEMSG, GetWParam(), GetLParam()); michael@0: } michael@0: else { michael@0: // Currently not used, but added so that processing events here michael@0: // is more generic. michael@0: ::CallWindowProc(win->GetWindowProc(), michael@0: hWnd, michael@0: GetMsg(), michael@0: GetWParam(), michael@0: GetLParam()); michael@0: } michael@0: michael@0: Clear(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: PluginWindowEvent * michael@0: nsPluginNativeWindowWin::GetPluginWindowEvent(HWND aWnd, UINT aMsg, WPARAM aWParam, LPARAM aLParam) michael@0: { michael@0: if (!mWeakRef) { michael@0: mWeakRef = this; michael@0: if (!mWeakRef) michael@0: return nullptr; michael@0: } michael@0: michael@0: PluginWindowEvent *event; michael@0: michael@0: // We have the ability to alloc if needed in case in the future some plugin michael@0: // should post multiple PostMessages. However, this could lead to many michael@0: // alloc's per second which could become a performance issue. See bug 169247. michael@0: if (!mCachedPluginWindowEvent) michael@0: { michael@0: event = new PluginWindowEvent(); michael@0: if (!event) return nullptr; michael@0: mCachedPluginWindowEvent = event; michael@0: } michael@0: else if (mCachedPluginWindowEvent->InUse()) michael@0: { michael@0: event = new PluginWindowEvent(); michael@0: if (!event) return nullptr; michael@0: } michael@0: else michael@0: { michael@0: event = mCachedPluginWindowEvent; michael@0: } michael@0: michael@0: event->Init(mWeakRef, aWnd, aMsg, aWParam, aLParam); michael@0: return event; michael@0: } michael@0: michael@0: nsresult nsPluginNativeWindowWin::CallSetWindow(nsRefPtr &aPluginInstance) michael@0: { michael@0: // Note, 'window' can be null michael@0: michael@0: // check the incoming instance, null indicates that window is going away and we are michael@0: // not interested in subclassing business any more, undo and don't subclass michael@0: if (!aPluginInstance) { michael@0: UndoSubclassAndAssociateWindow(); michael@0: nsPluginNativeWindow::CallSetWindow(aPluginInstance); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // check plugin mime type and cache it if it will need special treatment later michael@0: if (mPluginType == nsPluginType_Unknown) { michael@0: const char* mimetype = nullptr; michael@0: aPluginInstance->GetMIMEType(&mimetype); michael@0: if (mimetype) { michael@0: if (!strcmp(mimetype, "application/x-shockwave-flash")) michael@0: mPluginType = nsPluginType_Flash; michael@0: else if (!strcmp(mimetype, "audio/x-pn-realaudio-plugin")) michael@0: mPluginType = nsPluginType_Real; michael@0: else if (!strcmp(mimetype, "application/pdf")) michael@0: mPluginType = nsPluginType_PDF; michael@0: else michael@0: mPluginType = nsPluginType_Other; michael@0: } michael@0: } michael@0: michael@0: if (window) { michael@0: // grab the widget procedure before the plug-in does a subclass in michael@0: // setwindow. We'll use this in PluginWndProc for forwarding focus michael@0: // events to the widget. michael@0: WNDPROC currentWndProc = michael@0: (WNDPROC)::GetWindowLongPtr((HWND)window, GWLP_WNDPROC); michael@0: if (!mPrevWinProc && currentWndProc != PluginWndProc) michael@0: mPrevWinProc = currentWndProc; michael@0: michael@0: // PDF plugin v7.0.9, v8.1.3, and v9.0 subclass parent window, bug 531551 michael@0: // V8.2.2 and V9.1 don't have such problem. michael@0: if (mPluginType == nsPluginType_PDF) { michael@0: HWND parent = ::GetParent((HWND)window); michael@0: if (mParentWnd != parent) { michael@0: NS_ASSERTION(!mParentWnd, "Plugin's parent window changed"); michael@0: mParentWnd = parent; michael@0: mParentProc = ::GetWindowLongPtr(mParentWnd, GWLP_WNDPROC); michael@0: } michael@0: } michael@0: } michael@0: michael@0: nsPluginNativeWindow::CallSetWindow(aPluginInstance); michael@0: michael@0: SubclassAndAssociateWindow(); michael@0: michael@0: if (window && mPluginType == nsPluginType_Flash && michael@0: !GetPropW((HWND)window, L"PluginInstanceParentProperty")) { michael@0: HookSetWindowLongPtr(); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult nsPluginNativeWindowWin::SubclassAndAssociateWindow() michael@0: { michael@0: if (type != NPWindowTypeWindow || !window) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: HWND hWnd = (HWND)window; michael@0: michael@0: // check if we need to subclass michael@0: WNDPROC currentWndProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_WNDPROC); michael@0: if (currentWndProc == PluginWndProc) michael@0: return NS_OK; michael@0: michael@0: // If the plugin reset the subclass, set it back. michael@0: if (mPluginWinProc) { michael@0: #ifdef DEBUG michael@0: NS_WARNING("A plugin cleared our subclass - resetting."); michael@0: if (currentWndProc != mPluginWinProc) { michael@0: NS_WARNING("Procedures do not match up, discarding old subclass value."); michael@0: } michael@0: if (mPrevWinProc && currentWndProc == mPrevWinProc) { michael@0: NS_WARNING("The new procedure is our widget procedure?"); michael@0: } michael@0: #endif michael@0: SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)PluginWndProc); michael@0: return NS_OK; michael@0: } michael@0: michael@0: LONG_PTR style = GetWindowLongPtr(hWnd, GWL_STYLE); michael@0: // Out of process plugins must not have the WS_CLIPCHILDREN style set on their michael@0: // parent windows or else synchronous paints (via UpdateWindow() and others) michael@0: // will cause deadlocks. michael@0: if (::GetPropW(hWnd, L"PluginInstanceParentProperty")) michael@0: style &= ~WS_CLIPCHILDREN; michael@0: else michael@0: style |= WS_CLIPCHILDREN; michael@0: SetWindowLongPtr(hWnd, GWL_STYLE, style); michael@0: michael@0: mPluginWinProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)PluginWndProc); michael@0: if (!mPluginWinProc) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: DebugOnly win = (nsPluginNativeWindowWin *)::GetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); michael@0: NS_ASSERTION(!win || (win == this), "plugin window already has property and this is not us"); michael@0: michael@0: if (!::SetProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION, (HANDLE)this)) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult nsPluginNativeWindowWin::UndoSubclassAndAssociateWindow() michael@0: { michael@0: // release plugin instance michael@0: SetPluginInstance(nullptr); michael@0: michael@0: // remove window property michael@0: HWND hWnd = (HWND)window; michael@0: if (IsWindow(hWnd)) michael@0: ::RemoveProp(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); michael@0: michael@0: // restore the original win proc michael@0: // but only do this if this were us last time michael@0: if (mPluginWinProc) { michael@0: WNDPROC currentWndProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_WNDPROC); michael@0: if (currentWndProc == PluginWndProc) michael@0: SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)mPluginWinProc); michael@0: mPluginWinProc = nullptr; michael@0: michael@0: LONG_PTR style = GetWindowLongPtr(hWnd, GWL_STYLE); michael@0: style &= ~WS_CLIPCHILDREN; michael@0: SetWindowLongPtr(hWnd, GWL_STYLE, style); michael@0: } michael@0: michael@0: if (mPluginType == nsPluginType_PDF && mParentWnd) { michael@0: ::SetWindowLongPtr(mParentWnd, GWLP_WNDPROC, mParentProc); michael@0: mParentWnd = nullptr; michael@0: mParentProc = 0; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult PLUG_NewPluginNativeWindow(nsPluginNativeWindow ** aPluginNativeWindow) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aPluginNativeWindow); michael@0: michael@0: *aPluginNativeWindow = new nsPluginNativeWindowWin(); michael@0: michael@0: return *aPluginNativeWindow ? NS_OK : NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: nsresult PLUG_DeletePluginNativeWindow(nsPluginNativeWindow * aPluginNativeWindow) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aPluginNativeWindow); michael@0: nsPluginNativeWindowWin *p = (nsPluginNativeWindowWin *)aPluginNativeWindow; michael@0: delete p; michael@0: return NS_OK; michael@0: }