summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/plugin_process_host.cc2
-rw-r--r--chrome/browser/plugin_process_host.h1
-rw-r--r--chrome/browser/plugin_process_host_mac.cc15
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_mac.mm30
-rw-r--r--chrome/common/plugin_messages_internal.h14
-rw-r--r--chrome/plugin/plugin_thread.cc19
-rw-r--r--chrome/plugin/plugin_thread.h1
-rw-r--r--chrome/plugin/webplugin_delegate_stub.cc19
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl.h19
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl_mac.mm41
10 files changed, 158 insertions, 3 deletions
diff --git a/chrome/browser/plugin_process_host.cc b/chrome/browser/plugin_process_host.cc
index 4d5cd22..e09807b 100644
--- a/chrome/browser/plugin_process_host.cc
+++ b/chrome/browser/plugin_process_host.cc
@@ -512,6 +512,8 @@ void PluginProcessHost::OnMessageReceived(const IPC::Message& msg) {
OnPluginHideWindow)
IPC_MESSAGE_HANDLER(PluginProcessHostMsg_PluginDisposeWindow,
OnPluginDisposeWindow)
+ IPC_MESSAGE_HANDLER(PluginProcessHostMsg_PluginReceivedFocus,
+ OnPluginReceivedFocus)
#endif
IPC_MESSAGE_UNHANDLED_ERROR()
IPC_END_MESSAGE_MAP()
diff --git a/chrome/browser/plugin_process_host.h b/chrome/browser/plugin_process_host.h
index 5d0c7e3..c2a240d 100644
--- a/chrome/browser/plugin_process_host.h
+++ b/chrome/browser/plugin_process_host.h
@@ -130,6 +130,7 @@ class PluginProcessHost : public ChildProcessHost,
bool modal);
void OnPluginHideWindow(uint32 window_id, gfx::Rect window_rect);
void OnPluginDisposeWindow(uint32 window_id, gfx::Rect window_rect);
+ void OnPluginReceivedFocus(int process_id, int instance_id);
#endif
virtual bool CanShutdown() { return sent_requests_.empty(); }
diff --git a/chrome/browser/plugin_process_host_mac.cc b/chrome/browser/plugin_process_host_mac.cc
index bea1cbc..f1f0ff8 100644
--- a/chrome/browser/plugin_process_host_mac.cc
+++ b/chrome/browser/plugin_process_host_mac.cc
@@ -12,6 +12,8 @@
#include "base/mac_util.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/plugin_process_host.h"
+#include "chrome/common/plugin_messages.h"
+
void PluginProcessHost::OnPluginSelectWindow(uint32 window_id,
gfx::Rect window_rect,
@@ -75,3 +77,16 @@ void PluginProcessHost::OnAppActivation() {
NewRunnableFunction(mac_util::ActivateProcess, handle()));
}
}
+
+void PluginProcessHost::OnPluginReceivedFocus(int process_id, int instance_id) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
+ // A plugin has received keyboard focus, so tell all other plugin processes
+ // that they no longer have it (simulating the OS-level focus notifications
+ // that Gtk and Windows provide).
+ for (ChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS);
+ !iter.Done(); ++iter) {
+ PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter);
+ int instance = (plugin->handle() == process_id) ? instance_id : 0;
+ plugin->Send(new PluginProcessMsg_PluginFocusNotify(instance));
+ }
+}
diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.mm b/chrome/browser/renderer_host/render_widget_host_view_mac.mm
index d36e999..881a0b3 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm
@@ -10,12 +10,14 @@
#include "base/sys_string_conversions.h"
#include "chrome/browser/browser_trial.h"
#import "chrome/browser/cocoa/rwhvm_editcommand_helper.h"
+#include "chrome/browser/plugin_process_host.h"
#include "chrome/browser/renderer_host/backing_store.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
#include "chrome/browser/spellchecker_platform_engine.h"
#include "chrome/common/native_web_keyboard_event.h"
#include "chrome/common/edit_command.h"
+#include "chrome/common/plugin_messages.h"
#include "chrome/common/render_messages.h"
#include "skia/ext/platform_canvas.h"
#include "third_party/WebKit/WebKit/chromium/public/mac/WebInputEventFactory.h"
@@ -48,6 +50,26 @@ namespace {
// Maximum number of characters we allow in a tooltip.
const size_t kMaxTooltipLength = 1024;
+class NotifyPluginProcessHostTask : public Task {
+ public:
+ NotifyPluginProcessHostTask(uint32 process_id, uint32 instance_id)
+ : process_id_(process_id), instance_id_(instance_id) { }
+
+ private:
+ void Run() {
+ for (ChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS);
+ !iter.Done(); ++iter) {
+ PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter);
+ uint32 plugin_pid = plugin->handle();
+ uint32 instance = (plugin_pid == process_id_) ? instance_id_ : 0;
+ plugin->Send(new PluginProcessMsg_PluginFocusNotify(instance));
+ }
+ }
+
+ uint32 process_id_;
+ uint32 instance_id_;
+};
+
}
// RenderWidgetHostView --------------------------------------------------------
@@ -134,6 +156,10 @@ void RenderWidgetHostViewMac::WasHidden() {
// everything again when we become selected again.
is_hidden_ = true;
+ // tell any plugins that thought they had the focus that they do not now.
+ ChromeThread::PostTask(ChromeThread::IO, FROM_HERE,
+ new NotifyPluginProcessHostTask(0, 0));
+
// If we have a renderer, then inform it that we are being hidden so it can
// reduce its resource utilization.
render_widget_host_->WasHidden();
@@ -453,6 +479,10 @@ gfx::Rect RenderWidgetHostViewMac::GetRootWindowRect() {
void RenderWidgetHostViewMac::SetActive(bool active) {
if (render_widget_host_)
render_widget_host_->SetActive(active);
+ if (!active)
+ // tell any plugins that thought they had the focus that they do not now.
+ ChromeThread::PostTask(ChromeThread::IO, FROM_HERE,
+ new NotifyPluginProcessHostTask(0, 0));
}
void RenderWidgetHostViewMac::SetBackground(const SkBitmap& background) {
diff --git a/chrome/common/plugin_messages_internal.h b/chrome/common/plugin_messages_internal.h
index 84f9cd3..0cfbc9f 100644
--- a/chrome/common/plugin_messages_internal.h
+++ b/chrome/common/plugin_messages_internal.h
@@ -47,6 +47,15 @@ IPC_BEGIN_MESSAGES(PluginProcess)
bool /* on or off */)
#endif
+#if defined(OS_MACOSX)
+ // Notifies a plugin process that keyboard focus has changed. If another
+ // plugin instance has received focus, the process and instance IDs are
+ // passed as parameters; if focus has been taken away from a plugin, 0 is
+ // passed for both parameters.
+ IPC_MESSAGE_CONTROL1(PluginProcessMsg_PluginFocusNotify,
+ uint32 /* instance ID */)
+#endif
+
IPC_END_MESSAGES(PluginProcess)
@@ -151,6 +160,11 @@ IPC_BEGIN_MESSAGES(PluginProcessHost)
IPC_MESSAGE_CONTROL2(PluginProcessHostMsg_PluginDisposeWindow,
uint32 /* window ID */,
gfx::Rect /* window rect */)
+
+ // Notifies the browser that a plugin instance has received keyboard focus
+ IPC_MESSAGE_CONTROL2(PluginProcessHostMsg_PluginReceivedFocus,
+ uint32 /* process ID */,
+ uint32 /* instance ID */)
#endif
IPC_END_MESSAGES(PluginProcessHost)
diff --git a/chrome/plugin/plugin_thread.cc b/chrome/plugin/plugin_thread.cc
index 914a8ce..9ef6c45 100644
--- a/chrome/plugin/plugin_thread.cc
+++ b/chrome/plugin/plugin_thread.cc
@@ -21,6 +21,7 @@
#include "net/base/net_errors.h"
#include "webkit/glue/plugins/plugin_lib.h"
#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/plugins/webplugin_delegate_impl.h"
static base::LazyInstance<base::ThreadLocalPointer<PluginThread> > lazy_tls(
base::LINKER_INITIALIZED);
@@ -102,6 +103,10 @@ void PluginThread::OnControlMessageReceived(const IPC::Message& msg) {
IPC_BEGIN_MESSAGE_MAP(PluginThread, msg)
IPC_MESSAGE_HANDLER(PluginProcessMsg_CreateChannel, OnCreateChannel)
IPC_MESSAGE_HANDLER(PluginProcessMsg_PluginMessage, OnPluginMessage)
+#if defined(OS_MACOSX)
+ IPC_MESSAGE_HANDLER(PluginProcessMsg_PluginFocusNotify,
+ OnPluginFocusNotify)
+#endif
IPC_END_MESSAGE_MAP()
}
@@ -138,6 +143,20 @@ void PluginThread::OnPluginMessage(const std::vector<unsigned char> &data) {
ChildProcess::current()->ReleaseProcess();
}
+#if defined(OS_MACOSX)
+void PluginThread::OnPluginFocusNotify(uint32 instance_id) {
+ WebPluginDelegateImpl* instance =
+ reinterpret_cast<WebPluginDelegateImpl*>(instance_id);
+ std::set<WebPluginDelegateImpl*> active_delegates =
+ WebPluginDelegateImpl::GetActiveDelegates();
+ for (std::set<WebPluginDelegateImpl*>::iterator iter =
+ active_delegates.begin();
+ iter != active_delegates.end(); iter++) {
+ (*iter)->FocusNotify(instance);
+ }
+}
+#endif
+
namespace webkit_glue {
#if defined(OS_WIN)
diff --git a/chrome/plugin/plugin_thread.h b/chrome/plugin/plugin_thread.h
index 435d8c3..b5eeefc 100644
--- a/chrome/plugin/plugin_thread.h
+++ b/chrome/plugin/plugin_thread.h
@@ -37,6 +37,7 @@ class PluginThread : public ChildThread {
void OnPluginMessage(const std::vector<uint8> &data);
#if defined(OS_MACOSX)
void OnAppActivated();
+ void OnPluginFocusNotify(uint32 instance_id);
#endif
// The plugin module which is preloaded in Init
diff --git a/chrome/plugin/webplugin_delegate_stub.cc b/chrome/plugin/webplugin_delegate_stub.cc
index a4dabfb..6807b7b 100644
--- a/chrome/plugin/webplugin_delegate_stub.cc
+++ b/chrome/plugin/webplugin_delegate_stub.cc
@@ -46,6 +46,22 @@ class FinishDestructionTask : public Task {
WebPlugin* webplugin_;
};
+#if defined(OS_MACOSX)
+namespace {
+
+void FocusNotifier(WebPluginDelegateImpl *instance) {
+ uint32 process_id = getpid();
+ uint32 instance_id = reinterpret_cast<uint32>(instance);
+ PluginThread* plugin_thread = PluginThread::current();
+ if (plugin_thread) {
+ plugin_thread->Send(
+ new PluginProcessHostMsg_PluginReceivedFocus(process_id, instance_id));
+ }
+}
+
+}
+#endif
+
WebPluginDelegateStub::WebPluginDelegateStub(
const std::string& mime_type, int instance_id, PluginChannel* channel) :
mime_type_(mime_type),
@@ -164,6 +180,9 @@ void WebPluginDelegateStub::OnInit(const PluginMsg_Init_Params& params,
params.arg_values,
webplugin_,
params.load_manually);
+#if defined(OS_MACOSX)
+ delegate_->SetFocusNotifier(FocusNotifier);
+#endif
}
}
diff --git a/webkit/glue/plugins/webplugin_delegate_impl.h b/webkit/glue/plugins/webplugin_delegate_impl.h
index 1665a8b..5d6757d 100644
--- a/webkit/glue/plugins/webplugin_delegate_impl.h
+++ b/webkit/glue/plugins/webplugin_delegate_impl.h
@@ -9,6 +9,7 @@
#include <string>
#include <list>
+#include <set>
#include "app/gfx/native_widget_types.h"
#include "base/file_path.h"
@@ -113,6 +114,20 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate {
// Informs the delegate that the context used for painting windowless plugins
// has changed.
void UpdateContext(gfx::NativeDrawingContext context);
+ // returns a vector of currently active delegates in this process.
+ static std::set<WebPluginDelegateImpl*> GetActiveDelegates();
+ // Informs the delegate which plugin instance has just received keyboard focus
+ // so that it can notify the plugin as appropriate. If |process_id| and
+ // |instance_id| are both 0, this signifies that no plugin has keyboard
+ // focus.
+ void FocusNotify(WebPluginDelegateImpl* focused_delegate);
+ // Set a notifier function that gets called when the delegate is accepting
+ // the focus. If no notifier function has been set, the delegate will just
+ // call FocusNotify(this). This is used in a multiprocess environment to
+ // propagate focus notifications to all running plugin processes.
+ void SetFocusNotifier(void (*notifier)(WebPluginDelegateImpl*)) {
+ focus_notifier_ = notifier;
+ }
#endif
private:
@@ -305,6 +320,10 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate {
// Last mouse position within the plugin's rect (used for null events).
int last_mouse_x_;
int last_mouse_y_;
+ // True if the plugin thinks it has keyboard focus
+ bool have_focus_;
+ // A function to call when we want to accept keyboard focus
+ void (*focus_notifier_)(WebPluginDelegateImpl* notifier);
#endif
// Called by the message filter hook when the plugin enters a modal loop.
diff --git a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm
index 262b002..28daa29 100644
--- a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm
+++ b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm
@@ -7,6 +7,7 @@
#include "webkit/glue/plugins/webplugin_delegate_impl.h"
#include <string>
+#include <unistd.h>
#include <vector>
#include "base/file_util.h"
@@ -72,6 +73,9 @@ const int kPluginIdleThrottleDelayMs = 20; // 20ms (50Hz)
int g_current_x_offset = 0;
int g_current_y_offset = 0;
+base::LazyInstance<std::set<WebPluginDelegateImpl*> > g_active_delegates(
+ base::LINKER_INITIALIZED);
+
} // namespace
WebPluginDelegateImpl::WebPluginDelegateImpl(
@@ -89,6 +93,7 @@ WebPluginDelegateImpl::WebPluginDelegateImpl(
waiting_to_die_(false),
last_mouse_x_(0),
last_mouse_y_(0),
+ have_focus_(false),
handle_event_depth_(0),
user_gesture_message_posted_(this),
user_gesture_msg_factory_(this) {
@@ -105,9 +110,13 @@ WebPluginDelegateImpl::WebPluginDelegateImpl(
// CoreAnimation, just ignore what QuickTime asks for.
quirks_ |= PLUGIN_QUIRK_IGNORE_NEGOTIATED_DRAWING_MODEL;
}
+ std::set<WebPluginDelegateImpl*>* delegates = g_active_delegates.Pointer();
+ delegates->insert(this);
}
WebPluginDelegateImpl::~WebPluginDelegateImpl() {
+ std::set<WebPluginDelegateImpl*>* delegates = g_active_delegates.Pointer();
+ delegates->erase(this);
#ifndef NP_NO_QUICKDRAW
if (qd_port_.port) {
DisposeGWorld(qd_port_.port);
@@ -402,11 +411,24 @@ void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) {
DCHECK(err == NPERR_NO_ERROR);
}
-void WebPluginDelegateImpl::SetFocus() {
+std::set<WebPluginDelegateImpl*> WebPluginDelegateImpl::GetActiveDelegates() {
+ std::set<WebPluginDelegateImpl*>* delegates = g_active_delegates.Pointer();
+ return *delegates;
+}
+
+void WebPluginDelegateImpl::FocusNotify(WebPluginDelegateImpl* delegate) {
+ if (waiting_to_die_)
+ return;
+
+ have_focus_ = (delegate == this);
+
switch (instance()->event_model()) {
case NPEventModelCarbon: {
NPEvent focus_event = { 0 };
- focus_event.what = NPEventType_GetFocusEvent;
+ if (have_focus_)
+ focus_event.what = NPEventType_GetFocusEvent;
+ else
+ focus_event.what = NPEventType_LoseFocusEvent;
focus_event.when = TickCount();
instance()->NPP_HandleEvent(&focus_event);
break;
@@ -415,13 +437,20 @@ void WebPluginDelegateImpl::SetFocus() {
NPCocoaEvent focus_event;
memset(&focus_event, 0, sizeof(focus_event));
focus_event.type = NPCocoaEventFocusChanged;
- focus_event.data.focus.hasFocus = true;
+ focus_event.data.focus.hasFocus = have_focus_;
instance()->NPP_HandleEvent(reinterpret_cast<NPEvent*>(&focus_event));
break;
}
}
}
+void WebPluginDelegateImpl::SetFocus() {
+ if (focus_notifier_)
+ focus_notifier_(this);
+ else
+ FocusNotify(this);
+}
+
int WebPluginDelegateImpl::PluginDrawingModel() {
if (quirks_ & PLUGIN_QUIRK_IGNORE_NEGOTIATED_DRAWING_MODEL)
return NPDrawingModelQuickDraw;
@@ -699,6 +728,12 @@ bool WebPluginDelegateImpl::HandleInputEvent(const WebInputEvent& event,
UpdateWindowLocation(reinterpret_cast<WindowRef>(cg_context_.window),
*mouse_event);
}
+ // if we do not currently have focus and this is a mouseDown, trigger a
+ // notification that we are taking the keyboard focus. We can't just key
+ // off of incoming calls to SetFocus, since WebKit may already think we
+ // have it if we were the most recently focused element on our parent tab.
+ if (np_event.what == mouseDown && !have_focus_)
+ SetFocus();
}
#endif