| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <algorithm> | 5 #include <algorithm> |
| 6 | 6 |
| 7 #include "base/histogram.h" | 7 #include "base/histogram.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/win_util.h" | 9 #include "base/win_util.h" |
| 10 #include "chrome/browser/renderer_host/render_widget_host_view_win.h" | 10 #include "chrome/browser/renderer_host/render_widget_host_view_win.h" |
| (...skipping 25 matching lines...) Expand all Loading... |
| 36 // Subclassing twice is not a problem if no one is subclassing the HWND between | 36 // Subclassing twice is not a problem if no one is subclassing the HWND between |
| 37 // the 2 subclassings (the 2nd subclassing is ignored since the WinProc is the | 37 // the 2 subclassings (the 2nd subclassing is ignored since the WinProc is the |
| 38 // same as the current one). However if some other app goes and subclasses the | 38 // same as the current one). However if some other app goes and subclasses the |
| 39 // HWND between the 2 subclassings, we will end up subclassing twice. | 39 // HWND between the 2 subclassings, we will end up subclassing twice. |
| 40 // This flag lets us test that whether we have or not subclassed yet. | 40 // This flag lets us test that whether we have or not subclassed yet. |
| 41 static const wchar_t* const kFocusSubclassInstalled = | 41 static const wchar_t* const kFocusSubclassInstalled = |
| 42 L"__FOCUS_SUBCLASS_INSTALLED__"; | 42 L"__FOCUS_SUBCLASS_INSTALLED__"; |
| 43 | 43 |
| 44 namespace views { | 44 namespace views { |
| 45 | 45 |
| 46 static bool IsCompatibleWithMouseWheelRedirection(HWND window) { | |
| 47 std::wstring class_name = win_util::GetClassName(window); | |
| 48 // Mousewheel redirection to comboboxes is a surprising and | |
| 49 // undesireable user behavior. | |
| 50 return !(class_name == L"ComboBox" || | |
| 51 class_name == L"ComboBoxEx32"); | |
| 52 } | |
| 53 | |
| 54 static bool CanRedirectMouseWheelFrom(HWND window) { | |
| 55 std::wstring class_name = win_util::GetClassName(window); | |
| 56 | |
| 57 // Older Thinkpad mouse wheel drivers create a window under mouse wheel | |
| 58 // pointer. Detect if we are dealing with this window. In this case we | |
| 59 // don't need to do anything as the Thinkpad mouse driver will send | |
| 60 // mouse wheel messages to the right window. | |
| 61 if ((class_name == L"Syn Visual Class") || | |
| 62 (class_name == L"SynTrackCursorWindowClass")) | |
| 63 return false; | |
| 64 | |
| 65 return true; | |
| 66 } | |
| 67 | |
| 68 bool IsPluginWindow(HWND window) { | |
| 69 HWND current_window = window; | |
| 70 while (GetWindowLong(current_window, GWL_STYLE) & WS_CHILD) { | |
| 71 current_window = GetParent(current_window); | |
| 72 if (!IsWindow(current_window)) | |
| 73 break; | |
| 74 | |
| 75 std::wstring class_name = win_util::GetClassName(current_window); | |
| 76 if (class_name == kRenderWidgetHostHWNDClass) | |
| 77 return true; | |
| 78 } | |
| 79 | |
| 80 return false; | |
| 81 } | |
| 82 | |
| 83 // Forwards mouse wheel messages to the window under it. | |
| 84 // Windows sends mouse wheel messages to the currently active window. | |
| 85 // This causes a window to scroll even if it is not currently under the | |
| 86 // mouse wheel. The following code gives mouse wheel messages to the | |
| 87 // window under the mouse wheel in order to scroll that window. This | |
| 88 // is arguably a better user experience. The returns value says whether | |
| 89 // the mouse wheel message was successfully redirected. | |
| 90 static bool RerouteMouseWheel(HWND window, WPARAM wParam, LPARAM lParam) { | |
| 91 // Since this is called from a subclass for every window, we can get | |
| 92 // here recursively. This will happen if, for example, a control | |
| 93 // reflects wheel scroll messages to its parent. Bail out if we got | |
| 94 // here recursively. | |
| 95 static bool recursion_break = false; | |
| 96 if (recursion_break) | |
| 97 return false; | |
| 98 // Check if this window's class has a bad interaction with rerouting. | |
| 99 if (!IsCompatibleWithMouseWheelRedirection(window)) | |
| 100 return false; | |
| 101 | |
| 102 DWORD current_process = GetCurrentProcessId(); | |
| 103 POINT wheel_location = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; | |
| 104 HWND window_under_wheel = WindowFromPoint(wheel_location); | |
| 105 | |
| 106 if (!CanRedirectMouseWheelFrom(window_under_wheel)) | |
| 107 return false; | |
| 108 | |
| 109 // Find the lowest Chrome window in the hierarchy that can be the | |
| 110 // target of mouse wheel redirection. | |
| 111 while (window != window_under_wheel) { | |
| 112 // If window_under_wheel is not a valid Chrome window, then return | |
| 113 // true to suppress further processing of the message. | |
| 114 if (!::IsWindow(window_under_wheel)) | |
| 115 return true; | |
| 116 DWORD wheel_window_process = 0; | |
| 117 GetWindowThreadProcessId(window_under_wheel, &wheel_window_process); | |
| 118 if (current_process != wheel_window_process) { | |
| 119 if (IsChild(window, window_under_wheel)) { | |
| 120 // If this message is reflected from a child window in a different | |
| 121 // process (happens with out of process windowed plugins) then | |
| 122 // we don't want to reroute the wheel message. | |
| 123 return false; | |
| 124 } else { | |
| 125 // The wheel is scrolling over an unrelated window. If that window | |
| 126 // is a plugin window in a different chrome then we can send it a | |
| 127 // WM_MOUSEWHEEL. Otherwise, we cannot send random WM_MOUSEWHEEL | |
| 128 // messages to arbitrary windows. So just drop the message. | |
| 129 if (!IsPluginWindow(window_under_wheel)) | |
| 130 return true; | |
| 131 } | |
| 132 } | |
| 133 | |
| 134 // window_under_wheel is a Chrome window. If allowed, redirect. | |
| 135 if (IsCompatibleWithMouseWheelRedirection(window_under_wheel)) { | |
| 136 recursion_break = true; | |
| 137 SendMessage(window_under_wheel, WM_MOUSEWHEEL, wParam, lParam); | |
| 138 recursion_break = false; | |
| 139 return true; | |
| 140 } | |
| 141 // If redirection is disallowed, try the parent. | |
| 142 window_under_wheel = GetAncestor(window_under_wheel, GA_PARENT); | |
| 143 } | |
| 144 // If we traversed back to the starting point, we should process | |
| 145 // this message normally; return false. | |
| 146 return false; | |
| 147 } | |
| 148 | |
| 149 // Callback installed via InstallFocusSubclass. | 46 // Callback installed via InstallFocusSubclass. |
| 150 static LRESULT CALLBACK FocusWindowCallback(HWND window, UINT message, | 47 static LRESULT CALLBACK FocusWindowCallback(HWND window, UINT message, |
| 151 WPARAM wParam, LPARAM lParam) { | 48 WPARAM wParam, LPARAM lParam) { |
| 152 if (!::IsWindow(window)) { | 49 if (!::IsWindow(window)) { |
| 153 // QEMU has reported crashes when calling GetProp (this seems to happen for | 50 // QEMU has reported crashes when calling GetProp (this seems to happen for |
| 154 // some weird messages, not sure what they are). | 51 // some weird messages, not sure what they are). |
| 155 // Here we are just trying to avoid the crasher. | 52 // Here we are just trying to avoid the crasher. |
| 156 NOTREACHED(); | 53 NOTREACHED(); |
| 157 return 0; | 54 return 0; |
| 158 } | 55 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 180 // FocusManager::OnActivate attempts to restore the focused view, it | 77 // FocusManager::OnActivate attempts to restore the focused view, it |
| 181 // needs to be called last so the focus it is setting does not get | 78 // needs to be called last so the focus it is setting does not get |
| 182 // overridden. | 79 // overridden. |
| 183 LRESULT result = CallWindowProc(original_handler, window, WM_ACTIVATE, | 80 LRESULT result = CallWindowProc(original_handler, window, WM_ACTIVATE, |
| 184 wParam, lParam); | 81 wParam, lParam); |
| 185 if (!focus_manager->OnPostActivate(window, | 82 if (!focus_manager->OnPostActivate(window, |
| 186 LOWORD(wParam), HIWORD(wParam))) | 83 LOWORD(wParam), HIWORD(wParam))) |
| 187 return 0; | 84 return 0; |
| 188 return result; | 85 return result; |
| 189 } | 86 } |
| 190 case WM_MOUSEWHEEL: | |
| 191 if (RerouteMouseWheel(window, wParam, lParam)) | |
| 192 return 0; | |
| 193 break; | |
| 194 case WM_IME_CHAR: | 87 case WM_IME_CHAR: |
| 195 // Issue 7707: A rich-edit control may crash when it receives a | 88 // Issue 7707: A rich-edit control may crash when it receives a |
| 196 // WM_IME_CHAR message while it is processing a WM_IME_COMPOSITION | 89 // WM_IME_CHAR message while it is processing a WM_IME_COMPOSITION |
| 197 // message. Since view controls don't need WM_IME_CHAR messages, | 90 // message. Since view controls don't need WM_IME_CHAR messages, |
| 198 // we prevent WM_IME_CHAR messages from being dispatched to view | 91 // we prevent WM_IME_CHAR messages from being dispatched to view |
| 199 // controls via the CallWindowProc() call. | 92 // controls via the CallWindowProc() call. |
| 200 return 0; | 93 return 0; |
| 201 default: | 94 default: |
| 202 break; | 95 break; |
| 203 } | 96 } |
| (...skipping 638 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 842 std::find(focus_change_listeners_.begin(), focus_change_listeners_.end(), | 735 std::find(focus_change_listeners_.begin(), focus_change_listeners_.end(), |
| 843 listener); | 736 listener); |
| 844 if (place == focus_change_listeners_.end()) { | 737 if (place == focus_change_listeners_.end()) { |
| 845 NOTREACHED() << "Removing a listener that isn't registered."; | 738 NOTREACHED() << "Removing a listener that isn't registered."; |
| 846 return; | 739 return; |
| 847 } | 740 } |
| 848 focus_change_listeners_.erase(place); | 741 focus_change_listeners_.erase(place); |
| 849 } | 742 } |
| 850 | 743 |
| 851 } // namespace views | 744 } // namespace views |
| OLD | NEW |