diff --git a/dom/plugins/Makefile.in b/dom/plugins/Makefile.in index 7779058c26b5..8aa6e00d9e23 100644 --- a/dom/plugins/Makefile.in +++ b/dom/plugins/Makefile.in @@ -130,6 +130,12 @@ ifeq (WINNT,$(OS_ARCH)) CPPSRCS += COMMessageFilter.cpp endif +ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) +CMMSRCS += \ + PluginUtilsOSX.mm \ + $(NULL) +endif + LOCAL_INCLUDES = \ -I$(topsrcdir)/modules/plugin/base/public/ \ -I$(topsrcdir)/modules/plugin/base/src/ \ diff --git a/dom/plugins/PluginInstanceChild.cpp b/dom/plugins/PluginInstanceChild.cpp index bd0f8b2f31b8..9e5557c35f3c 100644 --- a/dom/plugins/PluginInstanceChild.cpp +++ b/dom/plugins/PluginInstanceChild.cpp @@ -112,6 +112,7 @@ PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface, , mShColorSpace(nsnull) , mShContext(nsnull) , mDrawingModel(NPDrawingModelCoreGraphics) + , mCurrentEvent(nsnull) #endif { memset(&mWindow, 0, sizeof(mWindow)); @@ -542,6 +543,12 @@ PluginInstanceChild::AnswerNPP_HandleEvent(const NPRemoteEvent& event, #ifdef XP_MACOSX // Mac OS X does not define an NPEvent structure. It defines more specific types. NPCocoaEvent evcopy = event.event; + + // Make sure we reset mCurrentEvent in case of an exception + AutoRestore savePreviousEvent(mCurrentEvent); + + // Track the current event for NPN_PopUpContextMenu. + mCurrentEvent = &event.event; #else // Make a copy since we may modify values. NPEvent evcopy = event.event; diff --git a/dom/plugins/PluginInstanceChild.h b/dom/plugins/PluginInstanceChild.h index 42c394eed52b..aa5dfca7f579 100644 --- a/dom/plugins/PluginInstanceChild.h +++ b/dom/plugins/PluginInstanceChild.h @@ -360,10 +360,18 @@ private: #endif // defined(OS_WIN) #if defined(OS_MACOSX) private: - CGColorSpaceRef mShColorSpace; - CGContextRef mShContext; - int16_t mDrawingModel; - nsCARenderer mCARenderer; + CGColorSpaceRef mShColorSpace; + CGContextRef mShContext; + int16_t mDrawingModel; + nsCARenderer mCARenderer; + +public: + const NPCocoaEvent* getCurrentEvent() { + return mCurrentEvent; + } + +private: + const NPCocoaEvent *mCurrentEvent; #endif }; diff --git a/dom/plugins/PluginModuleChild.cpp b/dom/plugins/PluginModuleChild.cpp index b51c83fbcb12..74099521a37d 100644 --- a/dom/plugins/PluginModuleChild.cpp +++ b/dom/plugins/PluginModuleChild.cpp @@ -69,6 +69,10 @@ #include "COMMessageFilter.h" #endif +#ifdef OS_MACOSX +#include "PluginUtilsOSX.h" +#endif + using namespace mozilla::plugins; #if defined(XP_WIN) @@ -1515,13 +1519,67 @@ _unscheduletimer(NPP npp, uint32_t timerID) InstCast(npp)->UnscheduleTimer(timerID); } + +#ifdef OS_MACOSX +static void ProcessBrowserEvents(void* pluginModule) { + PluginModuleChild* pmc = static_cast(pluginModule); + + if (!pmc) + return; + + pmc->CallProcessSomeEvents(); +} +#endif + NPError NP_CALLBACK _popupcontextmenu(NPP instance, NPMenu* menu) { PLUGIN_LOG_DEBUG_FUNCTION; AssertPluginThread(); - NS_WARNING("Not yet implemented!"); + +#ifdef OS_MACOSX + double pluginX, pluginY; + double screenX, screenY; + + const NPCocoaEvent* currentEvent = InstCast(instance)->getCurrentEvent(); + if (!currentEvent) { + return NPERR_GENERIC_ERROR; + } + + // Ensure that the events has an x/y value. + if (currentEvent->type != NPCocoaEventMouseDown && + currentEvent->type != NPCocoaEventMouseUp && + currentEvent->type != NPCocoaEventMouseMoved && + currentEvent->type != NPCocoaEventMouseEntered && + currentEvent->type != NPCocoaEventMouseExited && + currentEvent->type != NPCocoaEventMouseDragged) { + return NPERR_GENERIC_ERROR; + } + + pluginX = currentEvent->data.mouse.pluginX; + pluginY = currentEvent->data.mouse.pluginY; + + if ((pluginX < 0.0) || (pluginY < 0.0)) + return NPERR_GENERIC_ERROR; + + NPBool success = _convertpoint(instance, + pluginX, pluginY, NPCoordinateSpacePlugin, + &screenX, &screenY, NPCoordinateSpaceScreen); + + if (success) { + return mozilla::plugins::PluginUtilsOSX::ShowCocoaContextMenu(menu, + screenX, screenY, + PluginModuleChild::current(), + ProcessBrowserEvents); + } else { + NS_WARNING("Convertpoint failed, could not created contextmenu."); + return NPERR_GENERIC_ERROR; + } + +#else + NS_WARNING("Not supported on this platform!"); return NPERR_GENERIC_ERROR; +#endif } NPBool NP_CALLBACK @@ -2027,3 +2085,10 @@ PluginModuleChild::ResetEventHooks() mGlobalCallWndProcHook = NULL; } #endif + +#ifdef OS_MACOSX +void +PluginModuleChild::ProcessNativeEvents() { + CallProcessSomeEvents(); +} +#endif diff --git a/dom/plugins/PluginModuleChild.h b/dom/plugins/PluginModuleChild.h index 2ed329144a7c..24ac9396b702 100644 --- a/dom/plugins/PluginModuleChild.h +++ b/dom/plugins/PluginModuleChild.h @@ -193,6 +193,10 @@ public: static NPUTF8* NP_CALLBACK NPN_UTF8FromIdentifier(NPIdentifier aIdentifier); static int32_t NP_CALLBACK NPN_IntFromIdentifier(NPIdentifier aIdentifier); +#ifdef OS_MACOSX + void ProcessNativeEvents(); +#endif + private: bool InitGraphics(); #if defined(MOZ_WIDGET_GTK2) diff --git a/dom/plugins/PluginModuleParent.cpp b/dom/plugins/PluginModuleParent.cpp index bf41dc9bf2a3..b136a4aefa8d 100644 --- a/dom/plugins/PluginModuleParent.cpp +++ b/dom/plugins/PluginModuleParent.cpp @@ -38,6 +38,8 @@ #ifdef MOZ_WIDGET_GTK2 #include +#elif XP_MACOSX +#include "PluginUtilsOSX.h" #endif #ifdef MOZ_WIDGET_QT #include @@ -771,6 +773,14 @@ PluginModuleParent::AnswerProcessSomeEvents() return true; } +#elif defined(XP_MACOSX) +bool +PluginModuleParent::AnswerProcessSomeEvents() +{ + mozilla::plugins::PluginUtilsOSX::InvokeNativeEventLoop(); + return true; +} + #elif !defined(MOZ_WIDGET_GTK2) bool PluginModuleParent::AnswerProcessSomeEvents() diff --git a/dom/plugins/PluginUtilsOSX.h b/dom/plugins/PluginUtilsOSX.h new file mode 100644 index 000000000000..492c806c722d --- /dev/null +++ b/dom/plugins/PluginUtilsOSX.h @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +// vim:set ts=2 sts=2 sw=2 et cin: +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Benoit Girard + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "npapi.h" + +namespace mozilla { +namespace plugins { +namespace PluginUtilsOSX { + +// Need to call back into the browser's to process event. +typedef void (*RemoteProcessEvents) (void*); + +NPError ShowCocoaContextMenu(void* aMenu, int aX, int aY, void* pluginModule, RemoteProcessEvents remoteEvent); + +void InvokeNativeEventLoop(); + +} // namespace PluginUtilsOSX +} // namespace plugins +} // namespace mozilla diff --git a/dom/plugins/PluginUtilsOSX.mm b/dom/plugins/PluginUtilsOSX.mm new file mode 100644 index 000000000000..1f580d297b1d --- /dev/null +++ b/dom/plugins/PluginUtilsOSX.mm @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +// vim:set ts=2 sts=2 sw=2 et cin: +/* ***** 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.org code. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Benoit Girard + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#import +#include "PluginUtilsOSX.h" + +// Remove definitions for try/catch interfering with ObjCException macros. +#include "nsObjCExceptions.h" + +using namespace mozilla::plugins::PluginUtilsOSX; + +@interface EventProcessor : NSObject { + RemoteProcessEvents aRemoteEvents; + void *aPluginModule; +} +- (void)setRemoteEvents:(RemoteProcessEvents) remoteEvents pluginModule:(void*) pluginModule; +- (void)onTick; +@end + +@implementation EventProcessor +- (void) onTick +{ + aRemoteEvents(aPluginModule); +} + +- (void)setRemoteEvents:(RemoteProcessEvents) remoteEvents pluginModule:(void*) pluginModule +{ + aRemoteEvents = remoteEvents; + aPluginModule = pluginModule; +} +@end + +#define EVENT_PROCESS_DELAY 0.05 // 50 ms + +NPError mozilla::plugins::PluginUtilsOSX::ShowCocoaContextMenu(void* aMenu, int aX, int aY, void* pluginModule, RemoteProcessEvents remoteEvent) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + + // Leave out this code until we can fix painting. See bug 568513. + /* + // Create a timer to process browser events while waiting + // on the menu. This prevents the browser from hanging + // during the lifetime of the menu. + EventProcessor* eventProcessor = [[EventProcessor alloc] init]; + [eventProcessor setRemoteEvents:remoteEvent pluginModule:pluginModule]; + NSTimer *eventTimer = [NSTimer timerWithTimeInterval:EVENT_PROCESS_DELAY + target:eventProcessor selector:@selector(onTick) + userInfo:nil repeats:TRUE]; + // Use NSEventTrackingRunLoopMode otherwise the timer will + // not fire during the right click menu. + [[NSRunLoop currentRunLoop] addTimer:eventTimer + forMode:NSEventTrackingRunLoopMode]; + */ + + NSMenu* nsmenu = reinterpret_cast(aMenu); + NSPoint screen_point = ::NSMakePoint(aX, aY); + + [nsmenu popUpMenuPositioningItem:nil atLocation:screen_point inView:nil]; + + //[eventTimer invalidate]; + //[eventProcessor release]; + + return NPERR_NO_ERROR; + + NS_OBJC_END_TRY_ABORT_BLOCK; +} + +void mozilla::plugins::PluginUtilsOSX::InvokeNativeEventLoop() +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + ::CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, true); + NS_OBJC_END_TRY_ABORT_BLOCK; +}