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 |