diff options
author | stuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-08 19:12:43 +0000 |
---|---|---|
committer | stuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-08 19:12:43 +0000 |
commit | 8348cb325bebf4d3516bd94949f5a4eb7c4056a9 (patch) | |
tree | 19295dfd4bc311c532eab625b170796ac39216c2 /webkit | |
parent | c786d8d4b83c9112b564dc03fdc3aedd38ec3c3e (diff) | |
download | chromium_src-8348cb325bebf4d3516bd94949f5a4eb7c4056a9.zip chromium_src-8348cb325bebf4d3516bd94949f5a4eb7c4056a9.tar.gz chromium_src-8348cb325bebf4d3516bd94949f5a4eb7c4056a9.tar.bz2 |
Add support for NPN_PopUpContextMenu on Mac
BUG=29454
TEST=Right-click in Flash content with Flash 10.1.
Review URL: http://codereview.chromium.org/525099
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@35806 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r-- | webkit/glue/plugins/plugin_host.cc | 9 | ||||
-rw-r--r-- | webkit/glue/plugins/plugin_instance.cc | 8 | ||||
-rw-r--r-- | webkit/glue/plugins/plugin_instance.h | 36 | ||||
-rw-r--r-- | webkit/glue/plugins/plugin_instance_mac.mm | 132 | ||||
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl_mac.mm | 1 | ||||
-rw-r--r-- | webkit/webkit.gyp | 1 |
6 files changed, 186 insertions, 1 deletions
diff --git a/webkit/glue/plugins/plugin_host.cc b/webkit/glue/plugins/plugin_host.cc index a0bee9b..200858b 100644 --- a/webkit/glue/plugins/plugin_host.cc +++ b/webkit/glue/plugins/plugin_host.cc @@ -1039,7 +1039,14 @@ void NPN_UnscheduleTimer(NPP id, uint32 timer_id) { } NPError NPN_PopUpContextMenu(NPP id, NPMenu* menu) { - NOTIMPLEMENTED(); + if (!menu) + return NPERR_INVALID_PARAM; + + scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id); + if (plugin.get()) { + return plugin->PopUpContextMenu(menu); + } + NOTREACHED(); return NPERR_GENERIC_ERROR; } diff --git a/webkit/glue/plugins/plugin_instance.cc b/webkit/glue/plugins/plugin_instance.cc index 4b9b966..6ae7328 100644 --- a/webkit/glue/plugins/plugin_instance.cc +++ b/webkit/glue/plugins/plugin_instance.cc @@ -39,6 +39,7 @@ PluginInstance::PluginInstance(PluginLib *plugin, const std::string &mime_type) #if defined (OS_MACOSX) drawing_model_(0), event_model_(0), + currently_handled_event_(NULL), #endif message_loop_(MessageLoop::current()), load_manually_(false), @@ -406,6 +407,13 @@ void PluginInstance::UnscheduleTimer(uint32 timer_id) { timers_.erase(it); } +#if !defined(OS_MACOSX) +NPError PluginInstance::PopUpContextMenu(NPMenu* menu) { + NOTIMPLEMENTED(); + return NPERR_GENERIC_ERROR; +} +#endif + void PluginInstance::OnTimerCall(void (*func)(NPP id, uint32 timer_id), NPP id, uint32 timer_id) { diff --git a/webkit/glue/plugins/plugin_instance.h b/webkit/glue/plugins/plugin_instance.h index 4d82bb7..4043ed4 100644 --- a/webkit/glue/plugins/plugin_instance.h +++ b/webkit/glue/plugins/plugin_instance.h @@ -37,6 +37,9 @@ class PluginHost; class PluginStream; class PluginStreamUrl; class PluginDataStream; +#if defined(OS_MACOSX) +class ScopedCurrentPluginEvent; +#endif // A PluginInstance is an active, running instance of a Plugin. // A single plugin may have many PluginInstances. @@ -166,6 +169,8 @@ class PluginInstance : public base::RefCountedThreadSafe<PluginInstance> { double* dest_x, double* dest_y, NPCoordinateSpace dest_space); + NPError PopUpContextMenu(NPMenu* menu); + // // NPAPI methods for calling the Plugin Instance // @@ -209,6 +214,17 @@ class PluginInstance : public base::RefCountedThreadSafe<PluginInstance> { private: friend class base::RefCountedThreadSafe<PluginInstance>; +#if defined(OS_MACOSX) + friend class ScopedCurrentPluginEvent; + // Sets the event that the plugin is currently handling. The object is not + // owned or copied, so the caller must call this again with NULL before the + // event pointer becomes invalid. Clients use ScopedCurrentPluginEvent rather + // than calling this directly. + void set_currently_handled_event(NPCocoaEvent* event) { + currently_handled_event_ = event; + } +#endif + virtual ~PluginInstance(); void OnPluginThreadAsyncCall(void (*func)(void *), @@ -257,6 +273,7 @@ class PluginInstance : public base::RefCountedThreadSafe<PluginInstance> { int drawing_model_; int event_model_; gfx::Point plugin_origin_; + NPCocoaEvent* currently_handled_event_; // weak #endif MessageLoop* message_loop_; scoped_refptr<PluginStreamUrl> plugin_data_stream_; @@ -290,6 +307,25 @@ class PluginInstance : public base::RefCountedThreadSafe<PluginInstance> { DISALLOW_EVIL_CONSTRUCTORS(PluginInstance); }; +#if defined(OS_MACOSX) +// Helper to simplify correct usage of set_currently_handled_event. +// Instantiating will set |instance|'s currently handled to |event| for the +// lifetime of the object, then NULL when it goes out of scope. +class ScopedCurrentPluginEvent { + public: + ScopedCurrentPluginEvent(PluginInstance* instance, NPCocoaEvent* event) + : instance_(instance) { + instance_->set_currently_handled_event(event); + } + ~ScopedCurrentPluginEvent() { + instance_->set_currently_handled_event(NULL); + } + private: + scoped_refptr<PluginInstance> instance_; + DISALLOW_COPY_AND_ASSIGN(ScopedCurrentPluginEvent); +}; +#endif + } // namespace NPAPI #endif // WEBKIT_GLUE_PLUGIN_PLUGIN_INSTANCE_H__ diff --git a/webkit/glue/plugins/plugin_instance_mac.mm b/webkit/glue/plugins/plugin_instance_mac.mm new file mode 100644 index 0000000..35e257d --- /dev/null +++ b/webkit/glue/plugins/plugin_instance_mac.mm @@ -0,0 +1,132 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "build/build_config.h" + +#import <AppKit/AppKit.h> + +#include "base/logging.h" +#include "webkit/glue/plugins/plugin_instance.h" + +// When C++ exceptions are disabled, the C++ library defines |try| and +// |catch| so as to allow exception-expecting C++ code to build properly when +// language support for exceptions is not present. These macros interfere +// with the use of |@try| and |@catch| in Objective-C files such as this one. +// Undefine these macros here, after everything has been #included, since +// there will be no C++ uses and only Objective-C uses from this point on. +#undef try +#undef catch + +#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5 +@interface NSMenu (SnowLeopardMenuPopUpDeclaration) +- (BOOL)popUpMenuPositioningItem:(NSMenuItem*)item + atLocation:(NSPoint)location + inView:(NSView*)view; +@end +#endif + +namespace { + +// Returns an autoreleased NSEvent constructed from the given np_event, +// targeting the given window. +NSEvent* NSEventForNPCocoaEvent(NPCocoaEvent* np_event, NSWindow* window) { + bool mouse_down = 1; + switch (np_event->type) { + case NPCocoaEventMouseDown: + mouse_down = 1; + break; + case NPCocoaEventMouseUp: + mouse_down = 0; + break; + default: + // If plugins start bringing up context menus for things other than + // clicks, this will need more plumbing; for now just log it and proceed + // as if it were a mouse down. + NOTREACHED(); + } + NSEventType event_type = NSLeftMouseDown; + switch (np_event->data.mouse.buttonNumber) { + case 0: + event_type = mouse_down ? NSLeftMouseDown : NSLeftMouseUp; + break; + case 1: + event_type = mouse_down ? NSRightMouseDown : NSRightMouseUp; + break; + default: + event_type = mouse_down ? NSOtherMouseDown : NSOtherMouseUp; + break; + } + + NSInteger click_count = np_event->data.mouse.clickCount; + NSInteger modifiers = np_event->data.mouse.modifierFlags; + // NPCocoaEvent doesn't have a timestamp, so just use the current time. + NSEvent* event = + [NSEvent mouseEventWithType:event_type + location:NSMakePoint(0, 0) + modifierFlags:modifiers + timestamp:[[NSApp currentEvent] timestamp] + windowNumber:[window windowNumber] + context:[NSGraphicsContext currentContext] + eventNumber:0 + clickCount:click_count + pressure:1.0]; + return event; +} + +} // namespace + +namespace NPAPI { + +NPError PluginInstance::PopUpContextMenu(NPMenu* menu) { + if (!currently_handled_event_) + return NPERR_GENERIC_ERROR; + + CGRect main_display_bounds = CGDisplayBounds(CGMainDisplayID()); + NSPoint screen_point = NSMakePoint( + plugin_origin_.x() + currently_handled_event_->data.mouse.pluginX, + plugin_origin_.y() + currently_handled_event_->data.mouse.pluginY); + // Plugin offsets are upper-left based, so flip vertically for Cocoa. + screen_point.y = main_display_bounds.size.height - screen_point.y; + + NSMenu* nsmenu = reinterpret_cast<NSMenu*>(menu); + NPError return_val = NPERR_NO_ERROR; + NSWindow* window = nil; + @try { + if ([nsmenu respondsToSelector: + @selector(popUpMenuPositioningItem:atLocation:inView:)]) { + [nsmenu popUpMenuPositioningItem:nil atLocation:screen_point inView:nil]; + } else { + NSRect dummy_window_rect = NSMakeRect(screen_point.x, screen_point.y, + 1, 1); + window = [[NSWindow alloc] initWithContentRect:dummy_window_rect + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreNonretained + defer:NO]; + [window setAlphaValue:0]; + [window orderFront:nil]; + [NSMenu popUpContextMenu:nsmenu + withEvent:NSEventForNPCocoaEvent(currently_handled_event_, + window) + forView:[window contentView]]; + } + } + @catch (NSException* e) { + NSLog(@"Caught exception while handling PopUpContextMenu: %@", e); + return_val = NPERR_GENERIC_ERROR; + } + + if (window) { + @try { + [window orderOut:nil]; + [window release]; + } + @catch (NSException* e) { + NSLog(@"Caught exception while cleaning up in PopUpContextMenu: %@", e); + } + } + + return return_val; +} + +} // namespace NPAPI diff --git a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm index 1a6999c..5706544 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm +++ b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm @@ -752,6 +752,7 @@ bool WebPluginDelegateImpl::HandleInputEvent(const WebInputEvent& event, LOG(WARNING) << "NPCocoaEventFromWebInputEvent failed"; return false; } + NPAPI::ScopedCurrentPluginEvent event_scope(instance(), &np_cocoa_event); ret = instance()->NPP_HandleEvent( reinterpret_cast<NPEvent*>(&np_cocoa_event)) != 0; break; diff --git a/webkit/webkit.gyp b/webkit/webkit.gyp index d7e2030..d7ed2da 100644 --- a/webkit/webkit.gyp +++ b/webkit/webkit.gyp @@ -283,6 +283,7 @@ 'glue/plugins/plugin_host.h', 'glue/plugins/plugin_instance.cc', 'glue/plugins/plugin_instance.h', + 'glue/plugins/plugin_instance_mac.mm', 'glue/plugins/plugin_lib.cc', 'glue/plugins/plugin_lib.h', 'glue/plugins/plugin_lib_linux.cc', |