diff --git a/modules/plugin/base/src/Makefile.in b/modules/plugin/base/src/Makefile.in index 7966bb2e08a..eb2a62c1b06 100644 --- a/modules/plugin/base/src/Makefile.in +++ b/modules/plugin/base/src/Makefile.in @@ -81,7 +81,7 @@ ifeq ($(OS_ARCH),WINNT) else ifeq ($(MOZ_WIDGET_TOOLKIT),os2) CPPSRCS += nsPluginsDirOS2.cpp - CPPSRCS += nsPluginNativeWindow.cpp + CPPSRCS += nsPluginNativeWindowOS2.cpp else ifeq ($(OS_ARCH),Darwin) CPPSRCS += nsPluginsDirDarwin.cpp @@ -121,6 +121,10 @@ CXXFLAGS += -GX OS_LIBS += version.lib endif +ifeq ($(OS_ARCH),OS2) +ADD_TO_DEF_FILE = cat < $(srcdir)/extradefs.os2 >> $(DEF_FILE) +endif + ifdef MOZ_ENABLE_GTK CXXFLAGS += $(MOZ_GTK_CFLAGS) CFLAGS += $(MOZ_GTK_CFLAGS) diff --git a/modules/plugin/base/src/extradefs.os2 b/modules/plugin/base/src/extradefs.os2 new file mode 100644 index 00000000000..1e62c7dd1b7 --- /dev/null +++ b/modules/plugin/base/src/extradefs.os2 @@ -0,0 +1,4 @@ +IMPORTS + WinQueryProperty = PMMERGE.5450 + WinRemoveProperty = PMMERGE.5451 + WinSetProperty = PMMERGE.5452 diff --git a/modules/plugin/base/src/nsPluginNativeWindowOS2.cpp b/modules/plugin/base/src/nsPluginNativeWindowOS2.cpp new file mode 100644 index 00000000000..7eabb281864 --- /dev/null +++ b/modules/plugin/base/src/nsPluginNativeWindowOS2.cpp @@ -0,0 +1,418 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Andrei Volkov + * Brian Stell + * Peter Lubczynski + * + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#define INCL_WIN +#include "os2.h" + +#include "nsDebug.h" + +#include "plevent.h" +#include "nsIEventQueueService.h" + +#include "nsIPluginInstancePeer.h" +#include "nsPluginSafety.h" +#include "nsPluginNativeWindow.h" + +static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); +static NS_DEFINE_CID(kCPluginManagerCID, NS_PLUGINMANAGER_CID); // needed for NS_TRY_SAFE_CALL + +#define NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION "MozillaPluginWindowPropertyAssociation" + +extern "C" { +PVOID APIENTRY WinQueryProperty(HWND hwnd, PCSZ pszNameOrAtom); + +PVOID APIENTRY WinRemoveProperty(HWND hwnd, PCSZ pszNameOrAtom); + +BOOL APIENTRY WinSetProperty(HWND hwnd, PCSZ pszNameOrAtom, + PVOID pvData, ULONG ulFlags); +} + +/** + * PLEvent handling code + */ +class PluginWindowEvent : public PLEvent { +public: + PluginWindowEvent(); + void Init(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2); + void Clear(); + HWND GetWnd() { return mWnd; }; + ULONG GetMsg() { return mMsg; }; + MPARAM GetWParam() { return mWParam; }; + MPARAM GetLParam() { return mLParam; }; + PRBool GetIsAlloced() { return mIsAlloced; }; + void SetIsAlloced(PRBool aIsAlloced) { mIsAlloced = aIsAlloced; }; + PRBool InUse() { return (mWnd!=NULL || mMsg!=0); }; + +protected: + HWND mWnd; + ULONG mMsg; + MPARAM mWParam; + MPARAM mLParam; + PRBool mIsAlloced; +}; + +PluginWindowEvent::PluginWindowEvent() +{ + Clear(); +} + +void PluginWindowEvent::Clear() +{ + mWnd = NULL; + mMsg = 0; + mWParam = 0; + mLParam = 0; +} + +void PluginWindowEvent::Init(HWND aWnd, ULONG aMsg, MPARAM mp1, MPARAM mp2) +{ + NS_ASSERTION(aWnd!=NULL && aMsg!=0, "invalid plugin event value"); + NS_ASSERTION(mWnd==NULL && mMsg==0 && mWParam==0 && mLParam==0,"event already in use"); + mWnd = aWnd; + mMsg = aMsg; + mWParam = mp1; + mLParam = mp2; +} + +/** + * nsPluginNativeWindow Windows specific class declaration + */ + +typedef enum { + nsPluginType_Unknown = 0, + nsPluginType_Flash, + nsPluginType_Java_vm, + nsPluginType_Other +} nsPluginType; + +class nsPluginNativeWindowOS2 : public nsPluginNativeWindow { +public: + nsPluginNativeWindowOS2(); + virtual ~nsPluginNativeWindowOS2(); + + virtual nsresult CallSetWindow(nsCOMPtr &aPluginInstance); + +private: + nsresult SubclassAndAssociateWindow(); + nsresult UndoSubclassAndAssociateWindow(); + +public: + // locals + PFNWP GetWindowProc(); + nsresult GetEventService(nsCOMPtr &aEventService); + PluginWindowEvent * GetPluginWindowEvent(HWND aWnd, ULONG aMsg, MPARAM mp1, MPARAM mp2); + +private: + PFNWP mPluginWinProc; + nsCOMPtr mEventService; + PluginWindowEvent mPluginWindowEvent; + +public: + nsPluginType mPluginType; +}; + +static PRBool ProcessFlashMessageDelayed(nsPluginNativeWindowOS2 * aWin, + HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + NS_ENSURE_TRUE(aWin, NS_ERROR_NULL_POINTER); + + if (msg != WM_USER+1) + return PR_FALSE; // no need to delay + + // do stuff + nsCOMPtr eventService; + if (NS_SUCCEEDED(aWin->GetEventService(eventService))) { + nsCOMPtr eventQueue; + eventService->GetThreadEventQueue(PR_GetCurrentThread(), getter_AddRefs(eventQueue)); + if (eventQueue) { + PluginWindowEvent *pwe = aWin->GetPluginWindowEvent(hWnd, msg, mp1, mp2); + if (pwe) { + eventQueue->PostEvent(pwe); + return PR_TRUE; + } + } + } + return PR_FALSE; +} + +/** + * New plugin window procedure + */ +MRESULT EXPENTRY PluginWndProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + nsPluginNativeWindowOS2 * win = (nsPluginNativeWindowOS2 *)::WinQueryProperty(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); + if (!win) + return (MRESULT)TRUE; + + // check plugin mime type and cache whether it is Flash or java-vm or not + // flash and java-vm will need special treatment later + if (win->mPluginType == nsPluginType_Unknown) { + nsCOMPtr inst; + win->GetPluginInstance(inst); + if (inst) { + nsCOMPtr pip; + inst->GetPeer(getter_AddRefs(pip)); + if (pip) { + nsMIMEType mimetype = nsnull; + pip->GetMIMEType(&mimetype); + if (mimetype) { + if (!strcmp(mimetype, "application/x-shockwave-flash")) + win->mPluginType = nsPluginType_Flash; + else if (!strcmp(mimetype, "application/x-java-vm")) + win->mPluginType = nsPluginType_Java_vm; + else + win->mPluginType = nsPluginType_Other; + } + } + } + } + + // Macromedia Flash plugin may flood the message queue with some special messages + // (WM_USER+1) causing 100% CPU consumption and GUI freeze, see mozilla bug 132759; + // we can prevent this from happening by delaying the processing such messages; + if (win->mPluginType == nsPluginType_Flash) { + if (ProcessFlashMessageDelayed(win, hWnd, msg, mp1, mp2)) + return (MRESULT)TRUE; + } + + MRESULT res = (MRESULT)TRUE; + + nsCOMPtr inst; + win->GetPluginInstance(inst); + + if (win->mPluginType == nsPluginType_Java_vm) { + NS_TRY_SAFE_CALL_RETURN(res, WinDefWindowProc(hWnd, msg, mp1, mp2), nsnull, inst); + } else { + NS_TRY_SAFE_CALL_RETURN(res, (win->GetWindowProc())(hWnd, msg, mp1, mp2), nsnull, inst); + } + + return res; +} + +/** + * nsPluginNativeWindowOS2 implementation + */ +nsPluginNativeWindowOS2::nsPluginNativeWindowOS2() : nsPluginNativeWindow() +{ + // initialize the struct fields + window = nsnull; + x = 0; + y = 0; + width = 0; + height = 0; + + mPluginWinProc = NULL; + mPluginWindowEvent.SetIsAlloced(PR_FALSE); + mPluginType = nsPluginType_Unknown; +} + +nsPluginNativeWindowOS2::~nsPluginNativeWindowOS2() +{ + // clear any pending events to avoid dangling pointers + nsCOMPtr eventService(do_GetService(kEventQueueServiceCID)); + if (eventService) { + nsCOMPtr eventQueue; + eventService->GetThreadEventQueue(PR_GetCurrentThread(), getter_AddRefs(eventQueue)); + if (eventQueue) { + eventQueue->RevokeEvents(this); + } + } +} + +PFNWP nsPluginNativeWindowOS2::GetWindowProc() +{ + return mPluginWinProc; +} + +PR_STATIC_CALLBACK(void*) +PluginWindowEvent_Handle(PLEvent* self) +{ + if (!self) + return nsnull; + + PluginWindowEvent *event = NS_STATIC_CAST(PluginWindowEvent*, self); + + HWND hWnd = event->GetWnd(); + if (!hWnd) + return nsnull; + + nsPluginNativeWindowOS2 * win = (nsPluginNativeWindowOS2 *)::WinQueryProperty(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); + if (win) { + nsCOMPtr inst; + win->GetPluginInstance(inst); + NS_TRY_SAFE_CALL_VOID((win->GetWindowProc()) + (hWnd, + event->GetMsg(), + event->GetWParam(), + event->GetLParam()), + nsnull, inst); + } + + return nsnull; +} + +PR_STATIC_CALLBACK(void) +PluginWindowEvent_Destroy(PLEvent* self) +{ + if (!self) + return; + + PluginWindowEvent *event = NS_STATIC_CAST(PluginWindowEvent*, self); + if (event->GetIsAlloced()) { + delete event; + } + else + event->Clear(); +} + +nsresult nsPluginNativeWindowOS2::GetEventService(nsCOMPtr &aEventService) +{ + if (!mEventService) { + mEventService = do_GetService(kEventQueueServiceCID); + if (!mEventService) + return NS_ERROR_FAILURE; + } + aEventService = mEventService; + return NS_OK; +} + +PluginWindowEvent* +nsPluginNativeWindowOS2::GetPluginWindowEvent(HWND aWnd, ULONG aMsg, MPARAM aMp1, MPARAM aMp2) +{ + PluginWindowEvent *event; + if (mPluginWindowEvent.InUse()) { + // We have the ability to alloc if needed in case in the future some plugin + // should post multiple PostMessages. However, this could lead to many + // alloc's per second which could become a performance issue. If/when this + // is asserting then this needs to be studied. See bug 169247 + NS_ASSERTION(1, "possible plugin performance issue"); + event = new PluginWindowEvent(); + if (!event) + return nsnull; + + event->SetIsAlloced(PR_TRUE); + } + else { + event = &mPluginWindowEvent; + } + + event->Init(aWnd, aMsg, aMp1, aMp2); + PL_InitEvent(event, (void *)this, &PluginWindowEvent_Handle, PluginWindowEvent_Destroy); + return event; +}; + +nsresult nsPluginNativeWindowOS2::CallSetWindow(nsCOMPtr &aPluginInstance) +{ + // check the incoming instance, null indicates that window is going away and we are + // not interested in subclassing business any more, undo and don't subclass + if (!aPluginInstance) + UndoSubclassAndAssociateWindow(); + + nsPluginNativeWindow::CallSetWindow(aPluginInstance); + + if (aPluginInstance) + SubclassAndAssociateWindow(); + + return NS_OK; +} + +nsresult nsPluginNativeWindowOS2::SubclassAndAssociateWindow() +{ + if (type != nsPluginWindowType_Window) + return NS_ERROR_FAILURE; + + HWND hWnd = (HWND)window; + if (!hWnd) + return NS_ERROR_FAILURE; + + // check if we need to re-subclass + PFNWP currentWndProc = (PFNWP)::WinQueryWindowPtr(hWnd, QWP_PFNWP); + if (PluginWndProc == currentWndProc) + return NS_OK; + + mPluginWinProc = WinSubclassWindow(hWnd, PluginWndProc); + if (!mPluginWinProc) + return NS_ERROR_FAILURE; + + nsPluginNativeWindowOS2 * win = (nsPluginNativeWindowOS2 *)::WinQueryProperty(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); + NS_ASSERTION(!win || (win == this), "plugin window already has property and this is not us"); + + if (!::WinSetProperty(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION, (PVOID)this, 0)) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +nsresult nsPluginNativeWindowOS2::UndoSubclassAndAssociateWindow() +{ + // release plugin instance + SetPluginInstance(nsnull); + + // remove window property + HWND hWnd = (HWND)window; + if (WinIsWindow(/*HAB*/0, hWnd)) + ::WinRemoveProperty(hWnd, NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION); + + // restore the original win proc + // but only do this if this were us last time + if (mPluginWinProc) { + PFNWP currentWndProc = (PFNWP)::WinQueryWindowPtr(hWnd, QWP_PFNWP); + if (currentWndProc == PluginWndProc) + WinSubclassWindow(hWnd, mPluginWinProc); + } + + return NS_OK; +} + +nsresult PLUG_NewPluginNativeWindow(nsPluginNativeWindow ** aPluginNativeWindow) +{ + NS_ENSURE_ARG_POINTER(aPluginNativeWindow); + + *aPluginNativeWindow = new nsPluginNativeWindowOS2(); + + return *aPluginNativeWindow ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +nsresult PLUG_DeletePluginNativeWindow(nsPluginNativeWindow * aPluginNativeWindow) +{ + NS_ENSURE_ARG_POINTER(aPluginNativeWindow); + nsPluginNativeWindowOS2 *p = (nsPluginNativeWindowOS2 *)aPluginNativeWindow; + delete p; + return NS_OK; +}