diff options
-rw-r--r-- | build/all.gyp | 2 | ||||
-rw-r--r-- | ui/base/clipboard/clipboard_unittest.cc | 2 | ||||
-rw-r--r-- | ui/base/win/hwnd_subclass.cc | 64 | ||||
-rw-r--r-- | ui/base/win/hwnd_subclass.h | 58 | ||||
-rw-r--r-- | ui/base/win/hwnd_subclass_unittest.cc | 101 | ||||
-rw-r--r-- | ui/gfx/blit.cc | 4 | ||||
-rw-r--r-- | ui/ui.gyp | 2 | ||||
-rw-r--r-- | ui/ui_unittests.gypi | 3 |
8 files changed, 232 insertions, 4 deletions
diff --git a/build/all.gyp b/build/all.gyp index 49ea1d7..e7470e5 100644 --- a/build/all.gyp +++ b/build/all.gyp @@ -566,6 +566,7 @@ '../chrome/chrome.gyp:ui_tests', '../ui/aura/aura.gyp:*', '../ui/gfx/compositor/compositor.gyp:*', + '../ui/ui.gyp:gfx_unittests', '../ui/views/views.gyp:views', '../ui/views/views.gyp:views_unittests', '../webkit/webkit.gyp:pull_in_webkit_unit_tests', @@ -598,7 +599,6 @@ '../ipc/ipc.gyp:ipc_tests', '../sql/sql.gyp:sql_unittests', '../sync/sync.gyp:sync_unit_tests', - '../ui/ui.gyp:gfx_unittests', ], }], ['OS=="mac"', { diff --git a/ui/base/clipboard/clipboard_unittest.cc b/ui/base/clipboard/clipboard_unittest.cc index a39d27d..f01a89e 100644 --- a/ui/base/clipboard/clipboard_unittest.cc +++ b/ui/base/clipboard/clipboard_unittest.cc @@ -387,7 +387,7 @@ TEST_F(ClipboardTest, SharedBitmapTest) { // The following test somehow fails on GTK. The image when read back from the // clipboard has the alpha channel set to 0xFF for some reason. The other // channels stay intact. So I am turning this on only for aura. -#if defined(USE_AURA) +#if defined(USE_AURA) && !defined(OS_WIN) TEST_F(ClipboardTest, MultipleBitmapReadWriteTest) { Clipboard clipboard; diff --git a/ui/base/win/hwnd_subclass.cc b/ui/base/win/hwnd_subclass.cc new file mode 100644 index 0000000..89a8224 --- /dev/null +++ b/ui/base/win/hwnd_subclass.cc @@ -0,0 +1,64 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/base/win/hwnd_subclass.h" + +#include "base/logging.h" +#include "ui/base/win/hwnd_util.h" + +namespace { +const char kHWNDSubclassKey[] = "__UI_BASE_WIN_HWND_SUBCLASS_PROC__"; + +LRESULT CALLBACK WndProc(HWND hwnd, + UINT message, + WPARAM w_param, + LPARAM l_param) { + ui::HWNDSubclass* wrapped_wnd_proc = + reinterpret_cast<ui::HWNDSubclass*>( + ui::ViewProp::GetValue(hwnd, kHWNDSubclassKey)); + return wrapped_wnd_proc ? wrapped_wnd_proc->OnWndProc(hwnd, + message, + w_param, + l_param) + : DefWindowProc(hwnd, message, w_param, l_param); +} + +WNDPROC GetCurrentWndProc(HWND target) { + return reinterpret_cast<WNDPROC>(GetWindowLong(target, GWL_WNDPROC)); +} + +} // namespace + +namespace ui { + +HWNDSubclass::HWNDSubclass(HWND target) + : target_(target), + original_wnd_proc_(GetCurrentWndProc(target)), + ALLOW_THIS_IN_INITIALIZER_LIST(prop_(target, kHWNDSubclassKey, this)) { + ui::SetWindowProc(target_, &WndProc); +} + +HWNDSubclass::~HWNDSubclass() { +} + +void HWNDSubclass::SetFilter(HWNDMessageFilter* filter) { + filter_.reset(filter); +} + +LRESULT HWNDSubclass::OnWndProc(HWND hwnd, + UINT message, + WPARAM w_param, + LPARAM l_param) { + if (filter_.get()) { + LRESULT l_result = 0; + if (filter_->FilterMessage(hwnd, message, w_param, l_param, &l_result)) + return l_result; + } + + // In most cases, |original_wnd_proc_| will take care of calling + // DefWindowProc. + return CallWindowProc(original_wnd_proc_, hwnd, message, w_param, l_param); +} + +} // namespace ui diff --git a/ui/base/win/hwnd_subclass.h b/ui/base/win/hwnd_subclass.h new file mode 100644 index 0000000..d967c88 --- /dev/null +++ b/ui/base/win/hwnd_subclass.h @@ -0,0 +1,58 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_BASE_WIN_HWND_SUBCLASS_H_ +#define UI_BASE_WIN_HWND_SUBCLASS_H_ +#pragma once + +#include <windows.h> + +#include "base/gtest_prod_util.h" +#include "base/memory/scoped_ptr.h" +#include "ui/base/ui_export.h" +#include "ui/base/view_prop.h" + +namespace ui { + +// Classes implementing this interface get the opportunity to handle and consume +// messages before they are sent to their target HWND. +class UI_EXPORT HWNDMessageFilter { + public: + virtual ~HWNDMessageFilter() {} + + // A derived class overrides this method to perform filtering of the messages + // before the |original_wnd_proc_| sees them. Return true to consume the + // message and prevent |original_wnd_proc_| from seeing them at all, false to + // allow it to process them. + virtual bool FilterMessage(HWND hwnd, + UINT message, + WPARAM w_param, + LPARAM l_param, + LRESULT* l_result) = 0; +}; + +// An object that instance-subclasses a window. If the window has already been +// instance-subclassed, that subclassing is lost. +class UI_EXPORT HWNDSubclass { + public: + explicit HWNDSubclass(HWND target); + ~HWNDSubclass(); + + // HWNDSubclass takes ownership of the filter. + void SetFilter(HWNDMessageFilter* filter); + + LRESULT OnWndProc(HWND hwnd, UINT message, WPARAM w_param, LPARAM l_param); + + private: + HWND target_; + scoped_ptr<HWNDMessageFilter> filter_; + WNDPROC original_wnd_proc_; + ui::ViewProp prop_; + + DISALLOW_COPY_AND_ASSIGN(HWNDSubclass); +}; + +} // namespace ui + +#endif // UI_BASE_WIN_HWND_SUBCLASS_H_ diff --git a/ui/base/win/hwnd_subclass_unittest.cc b/ui/base/win/hwnd_subclass_unittest.cc new file mode 100644 index 0000000..bb48f10 --- /dev/null +++ b/ui/base/win/hwnd_subclass_unittest.cc @@ -0,0 +1,101 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/basictypes.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/win/window_impl.h" +#include "ui/base/win/hwnd_subclass.h" + +namespace ui { + +typedef testing::Test HWNDSubclassTest; + +namespace { + +class TestWindow : public ui::WindowImpl { + public: + TestWindow() : saw_message(false) {} + virtual ~TestWindow() {} + + bool saw_message; + + private: + // Overridden from ui::WindowImpl: + virtual BOOL ProcessWindowMessage(HWND window, + UINT message, + WPARAM w_param, + LPARAM l_param, + LRESULT& result, + DWORD msg_map_id) OVERRIDE { + if (message == WM_NCHITTEST) + saw_message = true; + + return FALSE; // Results in DefWindowProc(). + } + + DISALLOW_COPY_AND_ASSIGN(TestWindow); +}; + +class TestMessageFilter : public HWNDMessageFilter { + public: + TestMessageFilter() : consume_messages(false), saw_message(false) {} + virtual ~TestMessageFilter() {} + + // Setting to true causes the filter subclass to stop messages from reaching + // the subclassed window procedure. + bool consume_messages; + + // True if the message filter saw the message. + bool saw_message; + + private: + // Overridden from HWNDMessageFilter: + virtual bool FilterMessage(HWND hwnd, + UINT message, + WPARAM w_param, + LPARAM l_param, + LRESULT* l_result) OVERRIDE { + if (message == WM_NCHITTEST) { + saw_message = true; + return consume_messages; + } + return false; + } + + DISALLOW_COPY_AND_ASSIGN(TestMessageFilter); +}; + +} // namespace + +TEST_F(HWNDSubclassTest, Filtering) { + TestWindow window; + window.Init(NULL, gfx::Rect(0, 0, 100, 100)); + EXPECT_TRUE(window.hwnd() != NULL); + + { + TestMessageFilter* mf = new TestMessageFilter; + HWNDSubclass subclass(window.hwnd()); + subclass.SetFilter(mf); + + // We are not filtering, so both the filter and the window should receive + // this message: + ::SendMessage(window.hwnd(), WM_NCHITTEST, 0, 0); + + EXPECT_TRUE(mf->saw_message); + EXPECT_TRUE(window.saw_message); + + mf->saw_message = false; + window.saw_message = false; + + mf->consume_messages = true; + + // We are now filtering, so only the filter should see this message: + ::SendMessage(window.hwnd(), WM_NCHITTEST, 0, 0); + + EXPECT_TRUE(mf->saw_message); + EXPECT_FALSE(window.saw_message); + } +} + +} // namespace ui diff --git a/ui/gfx/blit.cc b/ui/gfx/blit.cc index 3a30dfb..5ee6470 100644 --- a/ui/gfx/blit.cc +++ b/ui/gfx/blit.cc @@ -126,7 +126,7 @@ void BlitCanvasToCanvas(SkCanvas *dst_canvas, skia::EndPlatformPaint(dst_canvas); } -#if defined(OS_WIN) +#if defined(OS_WIN) && !defined(USE_AURA) void ScrollCanvas(SkCanvas* canvas, const gfx::Rect& clip, @@ -141,7 +141,7 @@ void ScrollCanvas(SkCanvas* canvas, ScrollDC(hdc, amount.x(), amount.y(), NULL, &r, NULL, &damaged_rect); } -#elif defined(OS_POSIX) +#elif defined(OS_POSIX) || defined(USE_AURA) // Cairo has no nice scroll function so we do our own. On Mac it's possible to // use platform scroll code, but it's complex so we just use the same path // here. Either way it will be software-only, so it shouldn't matter much. @@ -256,6 +256,8 @@ 'base/win/foreground_helper.h', 'base/win/hwnd_util.cc', 'base/win/hwnd_util.h', + 'base/win/hwnd_subclass.cc', + 'base/win/hwnd_subclass.h', 'base/win/ime_input.cc', 'base/win/ime_input.h', 'base/win/message_box_win.cc', diff --git a/ui/ui_unittests.gypi b/ui/ui_unittests.gypi index 7ba4a7d..b294337 100644 --- a/ui/ui_unittests.gypi +++ b/ui/ui_unittests.gypi @@ -112,6 +112,7 @@ # TODO(brettw) re-enable this when the dependencies on WindowImpl are fixed! 'gfx/icon_util_unittest.cc', 'gfx/native_theme_win_unittest.cc', + 'base/win/hwnd_subclass_unittest.cc', ], 'include_dirs': [ '../..', @@ -193,6 +194,8 @@ ['use_aura==1', { 'sources!': [ 'gfx/screen_unittest.cc', + 'gfx/native_theme_win_unittest.cc', + 'base/dragdrop/os_exchange_data_win_unittest.cc', ], }], ['use_aura==1 or toolkit_views==1', { |