summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/win_util.cc6
-rw-r--r--base/win_util.h3
-rw-r--r--chrome/views/focus_manager.cc29
3 files changed, 36 insertions, 2 deletions
diff --git a/base/win_util.cc b/base/win_util.cc
index 37c5075..cfd7f2b 100644
--- a/base/win_util.cc
+++ b/base/win_util.cc
@@ -257,6 +257,12 @@ void* GetWindowUserData(HWND hwnd) {
// installed.
static const wchar_t* const kHandlerKey = L"__ORIGINAL_MESSAGE_HANDLER__";
+bool IsSubclassed(HWND window, WNDPROC subclass_proc) {
+ WNDPROC original_handler =
+ reinterpret_cast<WNDPROC>(GetWindowLongPtr(window, GWLP_WNDPROC));
+ return original_handler == subclass_proc;
+}
+
bool Subclass(HWND window, WNDPROC subclass_proc) {
WNDPROC original_handler =
reinterpret_cast<WNDPROC>(GetWindowLongPtr(window, GWLP_WNDPROC));
diff --git a/base/win_util.h b/base/win_util.h
index 2165e62..317c332 100644
--- a/base/win_util.h
+++ b/base/win_util.h
@@ -50,6 +50,9 @@ bool GetLogonSessionOnlyDACL(SECURITY_DESCRIPTOR** security_descriptor);
// Useful for subclassing a HWND. Returns the previous window procedure.
WNDPROC SetWindowProc(HWND hwnd, WNDPROC wndproc);
+// Returns true if the existing window procedure is the same as |subclass_proc|.
+bool IsSubclassed(HWND window, WNDPROC subclass_proc);
+
// Subclasses a window, replacing its existing window procedure with the
// specified one. Returns true if the current window procedure was replaced,
// false if the window has already been subclassed with the specified
diff --git a/chrome/views/focus_manager.cc b/chrome/views/focus_manager.cc
index da23bda..b48fe594 100644
--- a/chrome/views/focus_manager.cc
+++ b/chrome/views/focus_manager.cc
@@ -4,6 +4,7 @@
#include <algorithm>
+#include "base/histogram.h"
#include "base/logging.h"
#include "base/win_util.h"
#include "chrome/browser/render_widget_host_view_win.h"
@@ -30,6 +31,16 @@ static const wchar_t* const kFocusManagerKey = L"__VIEW_CONTAINER__";
// - prevent tab key events from being sent to views.
static const wchar_t* const kViewKey = L"__CHROME_VIEW__";
+// A property set to 1 to indicate whether the focus manager has subclassed that
+// window. We are doing this to ensure we are not subclassing several times.
+// Subclassing twice is not a problem if no one is subclassing the HWND between
+// the 2 subclassings (the 2nd subclassing is ignored since the WinProc is the
+// same as the current one). However if some other app goes and subclasses the
+// HWND between the 2 subclassings, we will end up subclassing twice.
+// This flag lets us test that whether we have or not subclassed yet.
+static const wchar_t* const kFocusSubclassInstalled =
+ L"__FOCUS_SUBCLASS_INSTALLED__";
+
namespace views {
static bool IsCompatibleWithMouseWheelRedirection(HWND window) {
@@ -209,15 +220,29 @@ FocusManager* FocusManager::CreateFocusManager(HWND window,
// static
void FocusManager::InstallFocusSubclass(HWND window, View* view) {
DCHECK(window);
- win_util::Subclass(window, &FocusWindowCallback);
+
+ bool already_subclassed =
+ reinterpret_cast<bool>(GetProp(window,
+ kFocusSubclassInstalled));
+ if (already_subclassed &&
+ !win_util::IsSubclassed(window, &FocusWindowCallback)) {
+ NOTREACHED() << "window sub-classed by someone other than the FocusManager";
+ // Track in UMA so we know if this case happens.
+ UMA_HISTOGRAM_COUNTS(L"FocusManager.MultipleSubclass", 1);
+ } else {
+ win_util::Subclass(window, &FocusWindowCallback);
+ SetProp(window, kFocusSubclassInstalled, reinterpret_cast<HANDLE>(true));
+ }
if (view)
SetProp(window, kViewKey, view);
}
void FocusManager::UninstallFocusSubclass(HWND window) {
DCHECK(window);
- if (win_util::Unsubclass(window, &FocusWindowCallback))
+ if (win_util::Unsubclass(window, &FocusWindowCallback)) {
RemoveProp(window, kViewKey);
+ RemoveProp(window, kFocusSubclassInstalled);
+ }
}
// static