diff options
author | ananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-24 18:30:00 +0000 |
---|---|---|
committer | ananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-24 18:30:00 +0000 |
commit | 669a674860fa52bb5ed97e056b3ecd60ea246e74 (patch) | |
tree | 7aef1563498b99ecf969132c49b554236c3eb1b6 /webkit/plugins | |
parent | e8754396d8ec37823b6e25b574a382a45306f3d8 (diff) | |
download | chromium_src-669a674860fa52bb5ed97e056b3ecd60ea246e74.zip chromium_src-669a674860fa52bb5ed97e056b3ecd60ea246e74.tar.gz chromium_src-669a674860fa52bb5ed97e056b3ecd60ea246e74.tar.bz2 |
Moved the code which sets focus to the dummy activation window created for windowless plugins
from the TrackPopupMenu intercept to the PlatformHandleInputEvent function. This ensures
that the plugin thread has focus for windowless plugins which don't have the TrackPopupMenu
intercept.
The bug which we are trying to fix is flaky behavior of the context menu in windowless plugins
i.e. selections are ignored at times and we cannot scroll through the menu using the keyboard.
This is because these messages are dispatched at times by Chrome's message loop which executes
in the context of the windows modal loop. This is because we allow nested task execution to ensure
that the windowless plugin continues to paint while the context menu is displayed. Chrome's message
loop dispatching input messages starves the TrackPopupMenu loop which expects to handle these
messages leading to the problem.
I also found that we need to allow popups to be displayed in
the context of input messages in windowless plugins. This is on the same lines as Firefox and Safari.
I also updated the list of user gesture messages.
A CL providing a facility to the message loop object indicating that an os modal loop is in effect
is also under review. http://codereview.chromium.org/6676099/
BUG=59864
TEST=manually as described in the bug.
R=jam@chromium.org,darin@chromium.org,*,ananta@chromium.org
Review URL: http://codereview.chromium.org/6696050
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@79302 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/plugins')
-rw-r--r-- | webkit/plugins/npapi/webplugin_delegate_impl_win.cc | 94 |
1 files changed, 53 insertions, 41 deletions
diff --git a/webkit/plugins/npapi/webplugin_delegate_impl_win.cc b/webkit/plugins/npapi/webplugin_delegate_impl_win.cc index 764d6d7..c8078da 100644 --- a/webkit/plugins/npapi/webplugin_delegate_impl_win.cc +++ b/webkit/plugins/npapi/webplugin_delegate_impl_win.cc @@ -686,6 +686,7 @@ LRESULT CALLBACK WebPluginDelegateImpl::FlashWindowlessWndProc(HWND hwnd, lparam); return TRUE; } + default: { break; } @@ -874,9 +875,13 @@ LRESULT CALLBACK WebPluginDelegateImpl::DummyWindowProc( // Returns true if the message passed in corresponds to a user gesture. static bool IsUserGestureMessage(unsigned int message) { switch (message) { + case WM_LBUTTONDOWN: case WM_LBUTTONUP: + case WM_RBUTTONDOWN: case WM_RBUTTONUP: + case WM_MBUTTONDOWN: case WM_MBUTTONUP: + case WM_KEYDOWN: case WM_KEYUP: return true; @@ -1216,6 +1221,8 @@ bool WebPluginDelegateImpl::PlatformHandleInputEvent( } } + HWND last_focus_window = NULL; + if (ShouldTrackEventForModalLoops(&np_event)) { // A windowless plugin can enter a modal loop in a NPP_HandleEvent call. // For e.g. Flash puts up a context menu when we right click on the @@ -1227,12 +1234,18 @@ bool WebPluginDelegateImpl::PlatformHandleInputEvent( handle_event_message_filter_hook_ = SetWindowsHookEx(WH_MSGFILTER, HandleEventMessageFilterHook, NULL, GetCurrentThreadId()); + // To ensure that the plugin receives keyboard events we set focus to the + // dummy window. + // TODO(iyengar) We need a framework in the renderer to identify which + // windowless plugin is under the mouse and to handle this. This would + // also require some changes in RenderWidgetHost to detect this in the + // WM_MOUSEACTIVATE handler and inform the renderer accordingly. + last_focus_window = ::SetFocus(dummy_window_for_activation_); } bool old_task_reentrancy_state = MessageLoop::current()->NestableTasksAllowed(); - // Maintain a local/global stack for the g_current_plugin_instance variable // as this may be a nested invocation. WebPluginDelegateImpl* last_plugin_instance = g_current_plugin_instance; @@ -1241,8 +1254,19 @@ bool WebPluginDelegateImpl::PlatformHandleInputEvent( handle_event_depth_++; + bool popups_enabled = false; + + if (IsUserGestureMessage(np_event.event)) { + instance()->PushPopupsEnabledState(true); + popups_enabled = true; + } + bool ret = instance()->NPP_HandleEvent(&np_event) != 0; + if (popups_enabled) { + instance()->PopPopupsEnabledState(); + } + // Flash and SilverLight always return false, even when they swallow the // event. Flash does this because it passes the event to its window proc, // which is supposed to return 0 if an event was handled. There are few @@ -1260,8 +1284,6 @@ bool WebPluginDelegateImpl::PlatformHandleInputEvent( g_current_plugin_instance = last_plugin_instance; - MessageLoop::current()->SetNestableTasksAllowed(old_task_reentrancy_state); - // We could have multiple NPP_HandleEvent calls nested together in case // the plugin enters a modal loop. Reset the pump messages event when // the outermost NPP_HandleEvent call unwinds. @@ -1269,6 +1291,33 @@ bool WebPluginDelegateImpl::PlatformHandleInputEvent( ResetEvent(handle_event_pump_messages_event_); } + if (::IsWindow(last_focus_window)) { + // Restore the nestable tasks allowed state in the message loop and reset + // the os modal loop state as the plugin returned from the TrackPopupMenu + // API call. + MessageLoop::current()->SetNestableTasksAllowed(old_task_reentrancy_state); + MessageLoop::current()->set_os_modal_loop(false); + // The Flash plugin at times sets focus to its hidden top level window + // with class name SWFlash_PlaceholderX. This causes the chrome browser + // window to receive a WM_ACTIVATEAPP message as a top level window from + // another thread is now active. We end up in a state where the chrome + // browser window is not active even though the user clicked on it. + // Our workaround for this is to send over a raw + // WM_LBUTTONDOWN/WM_LBUTTONUP combination to the last focus window, which + // does the trick. + if (dummy_window_for_activation_ != ::GetFocus()) { + INPUT input_info = {0}; + input_info.type = INPUT_MOUSE; + input_info.mi.dwFlags = MOUSEEVENTF_LEFTDOWN; + ::SendInput(1, &input_info, sizeof(INPUT)); + + input_info.type = INPUT_MOUSE; + input_info.mi.dwFlags = MOUSEEVENTF_LEFTUP; + ::SendInput(1, &input_info, sizeof(INPUT)); + } else { + ::SetFocus(last_focus_window); + } + } return ret; } @@ -1278,6 +1327,7 @@ void WebPluginDelegateImpl::OnModalLoopEntered() { SetEvent(handle_event_pump_messages_event_); MessageLoop::current()->SetNestableTasksAllowed(true); + MessageLoop::current()->set_os_modal_loop(true); UnhookWindowsHookEx(handle_event_message_filter_hook_); handle_event_message_filter_hook_ = NULL; @@ -1298,8 +1348,6 @@ BOOL WINAPI WebPluginDelegateImpl::TrackPopupMenuPatch( HMENU menu, unsigned int flags, int x, int y, int reserved, HWND window, const RECT* rect) { - HWND last_focus_window = NULL; - if (g_current_plugin_instance) { unsigned long window_process_id = 0; unsigned long window_thread_id = @@ -1309,45 +1357,9 @@ BOOL WINAPI WebPluginDelegateImpl::TrackPopupMenuPatch( if (::GetCurrentThreadId() != window_thread_id) { window = g_current_plugin_instance->dummy_window_for_activation_; } - - // To ensure that the plugin receives keyboard events we set focus to the - // dummy window. - // TODO(iyengar) We need a framework in the renderer to identify which - // windowless plugin is under the mouse and to handle this. This would - // also require some changes in RenderWidgetHost to detect this in the - // WM_MOUSEACTIVATE handler and inform the renderer accordingly. - if (g_current_plugin_instance->dummy_window_for_activation_) { - last_focus_window = - ::SetFocus(g_current_plugin_instance->dummy_window_for_activation_); - } } BOOL result = TrackPopupMenu(menu, flags, x, y, reserved, window, rect); - - if (IsWindow(last_focus_window)) { - // The Flash plugin at times sets focus to its hidden top level window - // with class name SWFlash_PlaceholderX. This causes the chrome browser - // window to receive a WM_ACTIVATEAPP message as a top level window from - // another thread is now active. We end up in a state where the chrome - // browser window is not active even though the user clicked on it. - // Our workaround for this is to send over a raw - // WM_LBUTTONDOWN/WM_LBUTTONUP combination to the last focus window, which - // does the trick. - if (g_current_plugin_instance->dummy_window_for_activation_ != - ::GetFocus()) { - INPUT input_info = {0}; - input_info.type = INPUT_MOUSE; - input_info.mi.dwFlags = MOUSEEVENTF_LEFTDOWN; - ::SendInput(1, &input_info, sizeof(INPUT)); - - input_info.type = INPUT_MOUSE; - input_info.mi.dwFlags = MOUSEEVENTF_LEFTUP; - ::SendInput(1, &input_info, sizeof(INPUT)); - } else { - ::SetFocus(last_focus_window); - } - } - return result; } |