summaryrefslogtreecommitdiffstats
path: root/views
diff options
context:
space:
mode:
authorben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-15 04:24:41 +0000
committerben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-15 04:24:41 +0000
commit4101aebea15c3b1411a017a19f1df97fd2a4ffcb (patch)
tree4cb81322bef4f8313f5edc4b833c7893b0279c8c /views
parenta769d6e25f36e3b6fa1580d932117a7aa7021cdc (diff)
downloadchromium_src-4101aebea15c3b1411a017a19f1df97fd2a4ffcb.zip
chromium_src-4101aebea15c3b1411a017a19f1df97fd2a4ffcb.tar.gz
chromium_src-4101aebea15c3b1411a017a19f1df97fd2a4ffcb.tar.bz2
Begin implementing a new widget.
This brings over code from ui/views, and bandaids it into compiling with the existing RootView/Widget interface. It compiles but probably doesn't run, which is OK since no one uses it. BUG=72040 TEST=none Review URL: http://codereview.chromium.org/6523008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@74915 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views')
-rw-r--r--views/views.gyp11
-rw-r--r--views/widget/native_widget.h10
-rw-r--r--views/widget/native_widget_listener.h5
-rw-r--r--views/widget/native_widget_win.cc681
-rw-r--r--views/widget/native_widget_win.h274
-rw-r--r--views/widget/native_widget_win_unittest.cc90
-rw-r--r--views/widget/widget_impl.cc355
-rw-r--r--views/widget/widget_impl.h167
-rw-r--r--views/widget/widget_impl_test_util.cc34
-rw-r--r--views/widget/widget_impl_test_util.h22
-rw-r--r--views/widget/widget_impl_unittest.cc38
11 files changed, 1563 insertions, 124 deletions
diff --git a/views/views.gyp b/views/views.gyp
index df8abce..d41d1b1 100644
--- a/views/views.gyp
+++ b/views/views.gyp
@@ -346,6 +346,12 @@
'widget/tooltip_window_gtk.h',
'widget/monitor_win.cc',
'widget/monitor_win.h',
+ 'widget/native_widget.h',
+ 'widget/native_widget_listener.h',
+ 'widget/native_widget_win.cc',
+ 'widget/native_widget_win.h',
+ 'widget/widget_impl.cc',
+ 'widget/widget_impl.h',
'widget/widget.h',
'widget/widget_gtk.cc',
'widget/widget_gtk.h',
@@ -411,9 +417,9 @@
'widget/child_window_message_processor.h',
'widget/aero_tooltip_manager.cc',
'widget/root_view_drop_target.cc',
+ 'widget/widget_win.cc',
'window/hit_test.cc',
'window/native_frame_view.cc',
- 'widget/widget_win.cc',
],
}],
['touchui==1', {
@@ -488,6 +494,9 @@
'run_all_unittests.cc',
'test/test_views_delegate.h',
'view_unittest.cc',
+ 'widget/native_widget_win_unittest.cc',
+ 'widget/widget_impl_test_util.cc',
+ 'widget/widget_impl_test_util.h',
'widget/widget_win_unittest.cc',
'window/window_win_unittest.cc',
diff --git a/views/widget/native_widget.h b/views/widget/native_widget.h
index a173fc2..3b8572c 100644
--- a/views/widget/native_widget.h
+++ b/views/widget/native_widget.h
@@ -5,7 +5,7 @@
#ifndef VIEWS_WIDGET_NATIVE_WIDGET_H_
#define VIEWS_WIDGET_NATIVE_WIDGET_H_
-#include "ui/views/native_types.h"
+#include "views/native_types.h"
namespace gfx{
class Path;
@@ -17,7 +17,7 @@ namespace internal {
class NativeWidgetListener;
}
class View;
-class Widget;
+class WidgetImpl;
////////////////////////////////////////////////////////////////////////////////
// NativeWidget interface
@@ -44,7 +44,7 @@ class NativeWidget {
// NativeView, or NULL if there is no NativeWidget that contains it.
static NativeWidget* GetTopLevelNativeWidget(gfx::NativeView native_view);
- // See Widget for documentation and notes.
+ // See WidgetImpl for documentation and notes.
virtual void InitWithNativeViewParent(gfx::NativeView parent,
const gfx::Rect& bounds) = 0;
virtual void SetNativeWindowProperty(const char* name, void* value) = 0;
@@ -69,9 +69,11 @@ class NativeWidget {
virtual void InvalidateRect(const gfx::Rect& invalid_rect) = 0;
virtual void Paint() = 0;
virtual void FocusNativeView(gfx::NativeView native_view) = 0;
- virtual Widget* GetWidget() const = 0;
+ virtual WidgetImpl* GetWidgetImpl() = 0;
+ virtual const WidgetImpl* GetWidgetImpl() const = 0;
};
} // namespace views
#endif // VIEWS_WIDGET_NATIVE_WIDGET_H_
+
diff --git a/views/widget/native_widget_listener.h b/views/widget/native_widget_listener.h
index e3e5de1..d9f524d 100644
--- a/views/widget/native_widget_listener.h
+++ b/views/widget/native_widget_listener.h
@@ -5,8 +5,6 @@
#ifndef VIEWS_WIDGET_NATIVE_WIDGET_LISTENER_H_
#define VIEWS_WIDGET_NATIVE_WIDGET_LISTENER_H_
-#include "ui/gfx/native_widget_types.h"
-
namespace gfx {
class Canvas;
class Point;
@@ -53,7 +51,8 @@ class NativeWidgetListener {
virtual void OnWorkAreaChanged() = 0;
- virtual WidgetImpl* GetWidgetImpl() const = 0;
+ virtual WidgetImpl* GetWidgetImpl() = 0;
+ virtual const WidgetImpl* GetWidgetImpl() const = 0;
};
} // namespace internal
diff --git a/views/widget/native_widget_win.cc b/views/widget/native_widget_win.cc
new file mode 100644
index 0000000..b75285e
--- /dev/null
+++ b/views/widget/native_widget_win.cc
@@ -0,0 +1,681 @@
+// Copyright (c) 2011 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 "views/widget/native_widget_win.h"
+
+#include "base/scoped_ptr.h"
+#include "ui/base/system_monitor/system_monitor.h"
+#include "ui/base/view_prop.h"
+#include "ui/base/win/hwnd_util.h"
+#include "ui/gfx/canvas_skia.h"
+#include "ui/gfx/native_theme_win.h"
+#include "ui/gfx/path.h"
+#include "views/view.h"
+#include "views/widget/widget_impl.h"
+
+namespace views {
+namespace internal {
+
+namespace {
+
+// Called from NativeWidgetWin::Paint() to asynchronously redraw child windows.
+BOOL CALLBACK EnumChildProcForRedraw(HWND hwnd, LPARAM lparam) {
+ DWORD process_id;
+ GetWindowThreadProcessId(hwnd, &process_id);
+ gfx::Rect invalid_rect = *reinterpret_cast<gfx::Rect*>(lparam);
+
+ RECT window_rect;
+ GetWindowRect(hwnd, &window_rect);
+ invalid_rect.Offset(-window_rect.left, -window_rect.top);
+
+ int flags = RDW_INVALIDATE | RDW_NOCHILDREN | RDW_FRAME;
+ if (process_id == GetCurrentProcessId())
+ flags |= RDW_UPDATENOW;
+ RedrawWindow(hwnd, &invalid_rect.ToRECT(), NULL, flags);
+ return TRUE;
+}
+
+// Links the HWND to its Widget.
+const char* const kNativeWidgetKey = "__VIEWS_NATIVE_WIDGET__";
+
+// A custom MSAA object id used to determine if a screen reader is actively
+// listening for MSAA events.
+const int kMSAAObjectID = 1;
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetWin, public:
+
+NativeWidgetWin::NativeWidgetWin(NativeWidgetListener* listener)
+ : listener_(listener),
+ active_mouse_tracking_flags_(0),
+ has_capture_(false) {
+}
+
+NativeWidgetWin::~NativeWidgetWin() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetWin, NativeWidget implementation:
+
+void NativeWidgetWin::InitWithNativeViewParent(gfx::NativeView parent,
+ const gfx::Rect& bounds) {
+ WindowImpl::Init(parent, bounds);
+}
+
+void NativeWidgetWin::SetNativeWindowProperty(const char* name, void* value) {
+ // Remove the existing property (if any).
+ for (ViewProps::iterator i = props_.begin(); i != props_.end(); ++i) {
+ if ((*i)->Key() == name) {
+ props_.erase(i);
+ break;
+ }
+ }
+
+ if (value)
+ props_.push_back(new ui::ViewProp(hwnd(), name, value));
+}
+
+void* NativeWidgetWin::GetNativeWindowProperty(const char* name) const {
+ return ui::ViewProp::GetValue(hwnd(), name);
+}
+
+gfx::Rect NativeWidgetWin::GetWindowScreenBounds() const {
+ RECT r;
+ GetWindowRect(hwnd(), &r);
+ return gfx::Rect(r);
+}
+
+gfx::Rect NativeWidgetWin::GetClientAreaScreenBounds() const {
+ RECT r;
+ GetClientRect(hwnd(), &r);
+ POINT point = { r.left, r.top };
+ ClientToScreen(hwnd(), &point);
+ return gfx::Rect(point.x, point.y, r.right - r.left, r.bottom - r.top);
+}
+
+void NativeWidgetWin::SetBounds(const gfx::Rect& bounds) {
+ SetWindowPos(hwnd(), NULL, bounds.x(), bounds.y(), bounds.width(),
+ bounds.height(), SWP_NOACTIVATE | SWP_NOZORDER);
+}
+
+void NativeWidgetWin::SetShape(const gfx::Path& shape) {
+ SetWindowRgn(hwnd(), shape.CreateNativeRegion(), TRUE);
+}
+
+gfx::NativeView NativeWidgetWin::GetNativeView() const {
+ return hwnd();
+}
+
+void NativeWidgetWin::Show() {
+ if (IsWindow(hwnd()))
+ ShowWindow(hwnd(), SW_SHOWNOACTIVATE);
+ // TODO(beng): move to windowposchanging to trap visibility changes instead.
+ if (IsLayeredWindow())
+ Invalidate();
+}
+
+void NativeWidgetWin::Hide() {
+ if (IsWindow(hwnd())) {
+ // NOTE: Be careful not to activate any windows here (for example, calling
+ // ShowWindow(SW_HIDE) will automatically activate another window). This
+ // code can be called while a window is being deactivated, and activating
+ // another window will screw up the activation that is already in progress.
+ SetWindowPos(hwnd(), NULL, 0, 0, 0, 0,
+ SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE |
+ SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER);
+ }
+}
+
+void NativeWidgetWin::Close() {
+ DestroyWindow(hwnd());
+}
+
+void NativeWidgetWin::MoveAbove(NativeWidget* other) {
+ SetWindowPos(hwnd(), other->GetNativeView(), 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
+}
+
+void NativeWidgetWin::SetAlwaysOnTop(bool always_on_top) {
+ DWORD style = always_on_top ? window_ex_style() | WS_EX_TOPMOST
+ : window_ex_style() & ~WS_EX_TOPMOST;
+ set_window_ex_style(style);
+ SetWindowLong(hwnd(), GWL_EXSTYLE, window_ex_style());
+}
+
+bool NativeWidgetWin::IsVisible() const {
+ return !!IsWindowVisible(hwnd());
+}
+
+bool NativeWidgetWin::IsActive() const {
+ WINDOWINFO info;
+ return ::GetWindowInfo(hwnd(), &info) &&
+ ((info.dwWindowStatus & WS_ACTIVECAPTION) != 0);
+}
+
+void NativeWidgetWin::SetMouseCapture() {
+ SetCapture(hwnd());
+ has_capture_ = true;
+}
+
+void NativeWidgetWin::ReleaseMouseCapture() {
+ ReleaseCapture();
+ has_capture_ = false;
+}
+
+bool NativeWidgetWin::HasMouseCapture() const {
+ return has_capture_;
+}
+
+bool NativeWidgetWin::ShouldReleaseCaptureOnMouseReleased() const {
+ return true;
+}
+
+void NativeWidgetWin::Invalidate() {
+ ::InvalidateRect(hwnd(), NULL, FALSE);
+}
+
+void NativeWidgetWin::InvalidateRect(const gfx::Rect& invalid_rect) {
+ // InvalidateRect() expects client coordinates.
+ RECT r = invalid_rect.ToRECT();
+ ::InvalidateRect(hwnd(), &r, FALSE);
+}
+
+void NativeWidgetWin::Paint() {
+ RECT r;
+ GetUpdateRect(hwnd(), &r, FALSE);
+ if (!IsRectEmpty(&r)) {
+ // TODO(beng): WS_EX_TRANSPARENT windows (see WidgetWin::opaque_)
+ // Paint child windows that are in a different process asynchronously.
+ // This prevents a hang in other processes from blocking this process.
+
+ // Calculate the invalid rect in screen coordinates before the first
+ // RedrawWindow() call to the parent HWND, since that will empty update_rect
+ // (which comes from a member variable) in the OnPaint call.
+ gfx::Rect screen_rect = GetWindowScreenBounds();
+ gfx::Rect invalid_screen_rect(r);
+ invalid_screen_rect.Offset(screen_rect.x(), screen_rect.y());
+
+ RedrawWindow(hwnd(), &r, NULL,
+ RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN);
+
+ LPARAM lparam = reinterpret_cast<LPARAM>(&invalid_screen_rect);
+ EnumChildWindows(hwnd(), EnumChildProcForRedraw, lparam);
+ }
+}
+
+void NativeWidgetWin::FocusNativeView(gfx::NativeView native_view) {
+ if (IsWindow(native_view)) {
+ if (GetFocus() != native_view)
+ SetFocus(native_view);
+ } else {
+ // NULL or invalid |native_view| passed, we consider this to be clearing
+ // focus. Keep the top level window focused so we continue to receive
+ // key events.
+ SetFocus(hwnd());
+ }
+}
+
+WidgetImpl* NativeWidgetWin::GetWidgetImpl() {
+ return listener_->GetWidgetImpl();
+}
+
+const WidgetImpl* NativeWidgetWin::GetWidgetImpl() const {
+ return listener_->GetWidgetImpl();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidetWin, MessageLoopForUI::Observer implementation
+
+void NativeWidgetWin::WillProcessMessage(const MSG& msg) {
+}
+
+void NativeWidgetWin::DidProcessMessage(const MSG& msg) {
+ // We need to add ourselves as a message loop observer so that we can repaint
+ // aggressively if the contents of our window become invalid. Unfortunately
+ // WM_PAINT messages are starved and we get flickery redrawing when resizing
+ // if we do not do this.
+ Paint();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetWin, message handlers:
+
+void NativeWidgetWin::OnActivate(UINT action, BOOL minimized, HWND window) {
+ SetMsgHandled(FALSE);
+}
+
+void NativeWidgetWin::OnActivateApp(BOOL active, DWORD thread_id) {
+ SetMsgHandled(FALSE);
+}
+
+LRESULT NativeWidgetWin::OnAppCommand(HWND window, short app_command,
+ WORD device, int keystate) {
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+void NativeWidgetWin::OnCancelMode() {
+}
+
+void NativeWidgetWin::OnCaptureChanged(HWND hwnd) {
+ has_capture_ = false;
+ listener_->OnMouseCaptureLost();
+}
+
+void NativeWidgetWin::OnClose() {
+ listener_->OnClose();
+}
+
+void NativeWidgetWin::OnCommand(UINT notification_code, int command_id,
+ HWND window) {
+ SetMsgHandled(FALSE);
+}
+
+LRESULT NativeWidgetWin::OnCreate(CREATESTRUCT* create_struct) {
+ SetNativeWindowProperty(kNativeWidgetKey, this);
+ listener_->OnNativeWidgetCreated();
+ MessageLoopForUI::current()->AddObserver(this);
+ return 0;
+}
+
+void NativeWidgetWin::OnDestroy() {
+ // TODO(beng): drop_target_
+ props_.reset();
+}
+
+void NativeWidgetWin::OnDisplayChange(UINT bits_per_pixel, CSize screen_size) {
+ listener_->OnDisplayChanged();
+}
+
+LRESULT NativeWidgetWin::OnDwmCompositionChanged(UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+void NativeWidgetWin::OnEndSession(BOOL ending, UINT logoff) {
+ SetMsgHandled(FALSE);
+}
+
+void NativeWidgetWin::OnEnterSizeMove() {
+ SetMsgHandled(FALSE);
+}
+
+LRESULT NativeWidgetWin::OnEraseBkgnd(HDC dc) {
+ // This is needed for magical win32 flicker ju-ju
+ return 1;
+}
+
+void NativeWidgetWin::OnExitMenuLoop(BOOL is_track_popup_menu) {
+ SetMsgHandled(FALSE);
+}
+
+void NativeWidgetWin::OnExitSizeMove() {
+ SetMsgHandled(FALSE);
+}
+
+LRESULT NativeWidgetWin::OnGetObject(UINT message, WPARAM w_param,
+ LPARAM l_param) {
+ return static_cast<LRESULT>(0L);
+}
+
+void NativeWidgetWin::OnGetMinMaxInfo(MINMAXINFO* minmax_info) {
+ SetMsgHandled(FALSE);
+}
+
+void NativeWidgetWin::OnHScroll(int scroll_type, short position,
+ HWND scrollbar) {
+ SetMsgHandled(FALSE);
+}
+
+void NativeWidgetWin::OnInitMenu(HMENU menu) {
+ SetMsgHandled(FALSE);
+}
+
+void NativeWidgetWin::OnInitMenuPopup(HMENU menu, UINT position,
+ BOOL is_system_menu) {
+ SetMsgHandled(FALSE);
+}
+
+LRESULT NativeWidgetWin::OnKeyDown(UINT message, WPARAM w_param,
+ LPARAM l_param) {
+ MSG msg;
+ MakeMSG(&msg, message, w_param, l_param);
+ SetMsgHandled(listener_->OnKeyEvent(KeyEvent(msg)));
+ return 0;
+}
+
+LRESULT NativeWidgetWin::OnKeyUp(UINT message, WPARAM w_param, LPARAM l_param) {
+ MSG msg;
+ MakeMSG(&msg, message, w_param, l_param);
+ SetMsgHandled(listener_->OnKeyEvent(KeyEvent(msg)));
+ return 0;
+}
+
+void NativeWidgetWin::OnKillFocus(HWND focused_window) {
+ listener_->OnNativeBlur(focused_window);
+ SetMsgHandled(FALSE);
+}
+
+LRESULT NativeWidgetWin::OnMouseActivate(HWND window, UINT hittest_code,
+ UINT message) {
+ SetMsgHandled(FALSE);
+ return MA_ACTIVATE;
+}
+
+LRESULT NativeWidgetWin::OnMouseLeave(UINT message, WPARAM w_param,
+ LPARAM l_param) {
+ // TODO(beng): tooltip
+ MSG msg;
+ MakeMSG(&msg, message, w_param, l_param);
+ //SetMsgHandled(listener_->OnMouseEvent(MouseEvent(msg)));
+
+ // Reset our tracking flag so that future mouse movement over this WidgetWin
+ // results in a new tracking session.
+ active_mouse_tracking_flags_ = 0;
+
+ return 0;
+}
+
+void NativeWidgetWin::OnMove(const CPoint& point) {
+ SetMsgHandled(FALSE);
+}
+
+void NativeWidgetWin::OnMoving(UINT param, LPRECT new_bounds) {
+}
+
+LRESULT NativeWidgetWin::OnMouseRange(UINT message, WPARAM w_param,
+ LPARAM l_param) {
+ // TODO(beng): tooltips
+ ProcessMouseRange(message, w_param, l_param, false);
+ return 0;
+}
+
+LRESULT NativeWidgetWin::OnNCActivate(BOOL active) {
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+LRESULT NativeWidgetWin::OnNCCalcSize(BOOL w_param, LPARAM l_param) {
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+LRESULT NativeWidgetWin::OnNCHitTest(UINT message, WPARAM w_param,
+ LPARAM l_param) {
+ LRESULT lr = DefWindowProc(hwnd(), message, w_param, l_param);
+ return lr;
+}
+
+LRESULT NativeWidgetWin::OnNCMouseRange(UINT message, WPARAM w_param,
+ LPARAM l_param) {
+ bool processed = ProcessMouseRange(message, w_param, l_param, true);
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+void NativeWidgetWin::OnNCPaint(HRGN rgn) {
+ SetMsgHandled(FALSE);
+}
+
+LRESULT NativeWidgetWin::OnNCUAHDrawCaption(UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+LRESULT NativeWidgetWin::OnNCUAHDrawFrame(UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+LRESULT NativeWidgetWin::OnNotify(int w_param, NMHDR* l_param) {
+ // TODO(beng): tooltips
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+void NativeWidgetWin::OnPaint(HDC dc) {
+ if (IsLayeredWindow()) {
+ // We need to clip to the dirty rect ourselves.
+ window_contents_->save(SkCanvas::kClip_SaveFlag);
+ RECT r;
+ GetUpdateRect(hwnd(), &r, FALSE);
+ window_contents_->ClipRectInt(r.left, r.top, r.right - r.left,
+ r.bottom - r.top);
+ listener_->OnPaint(window_contents_.get());
+ window_contents_->restore();
+
+ RECT wr;
+ GetWindowRect(hwnd(), &wr);
+ SIZE size = {wr.right - wr.left, wr.bottom - wr.top};
+ POINT position = {wr.left, wr.top};
+ HDC dib_dc = window_contents_->getTopPlatformDevice().getBitmapDC();
+ POINT zero = {0, 0};
+ BLENDFUNCTION blend = {AC_SRC_OVER, 0, 125, AC_SRC_ALPHA};
+ UpdateLayeredWindow(hwnd(), NULL, &position, &size, dib_dc, &zero,
+ RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA);
+ } else {
+ scoped_ptr<gfx::CanvasPaint> canvas(
+ gfx::CanvasPaint::CreateCanvasPaint(hwnd()));
+ listener_->OnPaint(canvas->AsCanvas());
+ }
+}
+
+LRESULT NativeWidgetWin::OnPowerBroadcast(DWORD power_event, DWORD data) {
+ ui::SystemMonitor* monitor = ui::SystemMonitor::Get();
+ if (monitor)
+ monitor->ProcessWmPowerBroadcastMessage(power_event);
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+LRESULT NativeWidgetWin::OnReflectedMessage(UINT message, WPARAM w_param,
+ LPARAM l_param) {
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+void NativeWidgetWin::OnSetFocus(HWND focused_window) {
+ listener_->OnNativeFocus(focused_window);
+ SetMsgHandled(FALSE);
+}
+
+LRESULT NativeWidgetWin::OnSetIcon(UINT size_type, HICON new_icon) {
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+LRESULT NativeWidgetWin::OnSetText(const wchar_t* text) {
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+void NativeWidgetWin::OnSettingChange(UINT flags, const wchar_t* section) {
+ if (flags == SPI_SETWORKAREA)
+ listener_->OnWorkAreaChanged();
+ SetMsgHandled(FALSE);
+}
+
+void NativeWidgetWin::OnSize(UINT param, const CSize& size) {
+ gfx::Size s(size.cx, size.cy);
+ listener_->OnSizeChanged(s);
+ if (IsLayeredWindow()) {
+ window_contents_.reset(
+ new gfx::CanvasSkia(s.width(), s.height(), false));
+ }
+}
+
+void NativeWidgetWin::OnSysCommand(UINT notification_code, CPoint click) {
+ SetMsgHandled(FALSE);
+}
+
+void NativeWidgetWin::OnThemeChanged() {
+ gfx::NativeTheme::instance()->CloseHandles();
+}
+
+void NativeWidgetWin::OnVScroll(int scroll_type, short position,
+ HWND scrollbar) {
+ SetMsgHandled(FALSE);
+}
+
+void NativeWidgetWin::OnWindowPosChanging(WINDOWPOS* window_pos) {
+ SetMsgHandled(FALSE);
+}
+
+void NativeWidgetWin::OnWindowPosChanged(WINDOWPOS* window_pos) {
+ SetMsgHandled(FALSE);
+}
+
+void NativeWidgetWin::OnFinalMessage(HWND window) {
+ delete this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetWin, WindowImpl overrides:
+
+HICON NativeWidgetWin::GetDefaultWindowIcon() const {
+ return NULL;
+}
+
+LRESULT NativeWidgetWin::OnWndProc(UINT message, WPARAM w_param,
+ LPARAM l_param) {
+ LRESULT result = 0;
+
+ // Otherwise we handle everything else.
+ if (!ProcessWindowMessage(hwnd(), message, w_param, l_param, result))
+ result = DefWindowProc(hwnd(), message, w_param, l_param);
+ if (message == WM_NCDESTROY) {
+ MessageLoopForUI::current()->RemoveObserver(this);
+ OnFinalMessage(hwnd());
+ }
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetWin, private:
+
+void NativeWidgetWin::TrackMouseEvents(DWORD mouse_tracking_flags) {
+ // Begin tracking mouse events for this HWND so that we get WM_MOUSELEAVE
+ // when the user moves the mouse outside this HWND's bounds.
+ if (active_mouse_tracking_flags_ == 0 || mouse_tracking_flags & TME_CANCEL) {
+ if (mouse_tracking_flags & TME_CANCEL) {
+ // We're about to cancel active mouse tracking, so empty out the stored
+ // state.
+ active_mouse_tracking_flags_ = 0;
+ } else {
+ active_mouse_tracking_flags_ = mouse_tracking_flags;
+ }
+
+ TRACKMOUSEEVENT tme;
+ tme.cbSize = sizeof(tme);
+ tme.dwFlags = mouse_tracking_flags;
+ tme.hwndTrack = hwnd();
+ tme.dwHoverTime = 0;
+ TrackMouseEvent(&tme);
+ } else if (mouse_tracking_flags != active_mouse_tracking_flags_) {
+ TrackMouseEvents(active_mouse_tracking_flags_ | TME_CANCEL);
+ TrackMouseEvents(mouse_tracking_flags);
+ }
+}
+
+bool NativeWidgetWin::ProcessMouseRange(UINT message, WPARAM w_param,
+ LPARAM l_param, bool non_client) {
+ MSG msg;
+ MakeMSG(&msg, message, w_param, l_param);
+ if (message == WM_MOUSEWHEEL) {
+ // Reroute the mouse-wheel to the window under the mouse pointer if
+ // applicable.
+ // TODO(beng):
+ //if (views::RerouteMouseWheel(hwnd(), w_param, l_param))
+ // return 0;
+ //return listener_->OnMouseWheelEvent(MouseWheelEvent(msg));
+ return 0;
+ }
+ // Windows only fires WM_MOUSELEAVE events if the application begins
+ // "tracking" mouse events for a given HWND during WM_MOUSEMOVE events.
+ // We need to call |TrackMouseEvents| to listen for WM_MOUSELEAVE.
+ if (!has_capture_)
+ TrackMouseEvents(non_client ? TME_NONCLIENT | TME_LEAVE : TME_LEAVE);
+ //return listener_->OnMouseEvent(MouseEvent(msg));
+ return 0;
+}
+
+void NativeWidgetWin::MakeMSG(MSG* msg, UINT message, WPARAM w_param,
+ LPARAM l_param) const {
+ msg->hwnd = hwnd();
+ msg->message = message;
+ msg->wParam = w_param;
+ msg->lParam = l_param;
+ msg->time = 0;
+ msg->pt.x = msg->pt.y = 0;
+}
+
+void NativeWidgetWin::CloseNow() {
+ DestroyWindow(hwnd());
+}
+
+bool NativeWidgetWin::IsLayeredWindow() const {
+ return !!(window_ex_style() & WS_EX_LAYERED);
+}
+
+} // namespace internal
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidget, public:
+
+// static
+NativeWidget* NativeWidget::CreateNativeWidget(
+ internal::NativeWidgetListener* listener) {
+ return new internal::NativeWidgetWin(listener);
+}
+
+// static
+NativeWidget* NativeWidget::GetNativeWidgetForNativeView(
+ gfx::NativeView native_view) {
+ if (!ui::WindowImpl::IsWindowImpl(native_view))
+ return NULL;
+ return reinterpret_cast<internal::NativeWidgetWin*>(
+ ui::ViewProp::GetValue(native_view, internal::kNativeWidgetKey));
+}
+
+// static
+NativeWidget* NativeWidget::GetNativeWidgetForNativeWindow(
+ gfx::NativeWindow native_window) {
+ return GetNativeWidgetForNativeView(native_window);
+}
+
+// static
+NativeWidget* NativeWidget::GetTopLevelNativeWidget(
+ gfx::NativeView native_view) {
+ // First, check if the top-level window is a Widget.
+ HWND root = ::GetAncestor(native_view, GA_ROOT);
+ if (!root)
+ return NULL;
+
+ NativeWidget* widget = GetNativeWidgetForNativeView(root);
+ if (widget)
+ return widget;
+
+ // Second, try to locate the last Widget window in the parent hierarchy.
+ HWND parent_hwnd = native_view;
+ NativeWidget* parent_widget;
+ do {
+ parent_widget = GetNativeWidgetForNativeView(parent_hwnd);
+ if (parent_widget) {
+ widget = parent_widget;
+ parent_hwnd = ::GetAncestor(parent_hwnd, GA_PARENT);
+ }
+ } while (parent_hwnd != NULL && parent_widget != NULL);
+
+ return widget;
+}
+
+} // namespace views
diff --git a/views/widget/native_widget_win.h b/views/widget/native_widget_win.h
new file mode 100644
index 0000000..dc3f239
--- /dev/null
+++ b/views/widget/native_widget_win.h
@@ -0,0 +1,274 @@
+// Copyright (c) 2011 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 VIEWS_WIDGET_NATIVE_WIDGET_WIN_H_
+#define VIEWS_WIDGET_NATIVE_WIDGET_WIN_H_
+
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/scoped_ptr.h"
+#include "base/scoped_vector.h"
+#include "ui/base/win/window_impl.h"
+#include "views/widget/native_widget.h"
+
+namespace gfx {
+class CanvasSkia;
+}
+
+namespace ui {
+class ViewProp;
+}
+
+namespace views {
+class WidgetImpl;
+
+namespace internal {
+
+// A Windows message reflected from other windows. This message is sent with the
+// following arguments:
+// HWND - Target window
+// MSG - kReflectedMessage
+// WPARAM - Should be 0
+// LPARAM - Pointer to MSG struct containing the original message.
+const int kReflectedMessage = WM_APP + 3;
+
+// These two messages aren't defined in winuser.h, but they are sent to windows
+// with captions. They appear to paint the window caption and frame.
+// Unfortunately if you override the standard non-client rendering as we do
+// with CustomFrameWindow, sometimes Windows (not deterministically
+// reproducibly but definitely frequently) will send these messages to the
+// window and paint the standard caption/title over the top of the custom one.
+// So we need to handle these messages in CustomFrameWindow to prevent this
+// from happening.
+const int WM_NCUAHDRAWCAPTION = 0xAE;
+const int WM_NCUAHDRAWFRAME = 0xAF;
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetWin class
+//
+// A NativeWidget implementation that wraps a Win32 HWND.
+//
+class NativeWidgetWin : public NativeWidget,
+ public ui::WindowImpl,
+ public MessageLoopForUI::Observer {
+ public:
+ explicit NativeWidgetWin(NativeWidgetListener* listener);
+ virtual ~NativeWidgetWin();
+
+ private:
+ typedef ScopedVector<ui::ViewProp> ViewProps;
+
+ // Overridden from NativeWidget:
+ virtual void InitWithNativeViewParent(gfx::NativeView parent,
+ const gfx::Rect& bounds);
+ virtual void SetNativeWindowProperty(const char* name, void* value);
+ virtual void* GetNativeWindowProperty(const char* name) const;
+ virtual gfx::Rect GetWindowScreenBounds() const;
+ virtual gfx::Rect GetClientAreaScreenBounds() const;
+ virtual void SetBounds(const gfx::Rect& bounds);
+ virtual void SetShape(const gfx::Path& shape);
+ virtual gfx::NativeView GetNativeView() const;
+ virtual void Show();
+ virtual void Hide();
+ virtual void Close();
+ virtual void MoveAbove(NativeWidget* other);
+ virtual void SetAlwaysOnTop(bool always_on_top);
+ virtual bool IsVisible() const;
+ virtual bool IsActive() const;
+ virtual void SetMouseCapture();
+ virtual void ReleaseMouseCapture();
+ virtual bool HasMouseCapture() const;
+ virtual bool ShouldReleaseCaptureOnMouseReleased() const;
+ virtual void Invalidate();
+ virtual void InvalidateRect(const gfx::Rect& invalid_rect);
+ virtual void Paint();
+ virtual void FocusNativeView(gfx::NativeView native_view);
+ virtual WidgetImpl* GetWidgetImpl();
+ virtual const WidgetImpl* GetWidgetImpl() const;
+
+ // Overridden from MessageLoop::Observer:
+ void WillProcessMessage(const MSG& msg);
+ virtual void DidProcessMessage(const MSG& msg);
+
+ // Message handlers
+ BEGIN_MSG_MAP_EX(NativeWidgetWin)
+ // Range handlers must go first!
+ MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange)
+ MESSAGE_RANGE_HANDLER_EX(WM_NCMOUSEMOVE, WM_NCMBUTTONDBLCLK, OnNCMouseRange)
+
+ // Reflected message handler
+ MESSAGE_HANDLER_EX(kReflectedMessage, OnReflectedMessage)
+
+ // CustomFrameWindow hacks
+ MESSAGE_HANDLER_EX(WM_NCUAHDRAWCAPTION, OnNCUAHDrawCaption)
+ MESSAGE_HANDLER_EX(WM_NCUAHDRAWFRAME, OnNCUAHDrawFrame)
+
+ // Vista and newer
+ MESSAGE_HANDLER_EX(WM_DWMCOMPOSITIONCHANGED, OnDwmCompositionChanged)
+
+ // Non-atlcrack.h handlers
+ MESSAGE_HANDLER_EX(WM_GETOBJECT, OnGetObject)
+ MESSAGE_HANDLER_EX(WM_NCMOUSELEAVE, OnMouseLeave)
+ MESSAGE_HANDLER_EX(WM_MOUSELEAVE, OnMouseLeave)
+
+ // Key events.
+ MESSAGE_HANDLER_EX(WM_KEYDOWN, OnKeyDown)
+ MESSAGE_HANDLER_EX(WM_KEYUP, OnKeyUp)
+ MESSAGE_HANDLER_EX(WM_SYSKEYDOWN, OnKeyDown);
+ MESSAGE_HANDLER_EX(WM_SYSKEYUP, OnKeyUp);
+
+ // This list is in _ALPHABETICAL_ order! OR I WILL HURT YOU.
+ MSG_WM_ACTIVATE(OnActivate)
+ MSG_WM_ACTIVATEAPP(OnActivateApp)
+ MSG_WM_APPCOMMAND(OnAppCommand)
+ MSG_WM_CANCELMODE(OnCancelMode)
+ MSG_WM_CAPTURECHANGED(OnCaptureChanged)
+ MSG_WM_CLOSE(OnClose)
+ MSG_WM_COMMAND(OnCommand)
+ MSG_WM_CREATE(OnCreate)
+ MSG_WM_DESTROY(OnDestroy)
+ MSG_WM_DISPLAYCHANGE(OnDisplayChange)
+ MSG_WM_ERASEBKGND(OnEraseBkgnd)
+ MSG_WM_ENDSESSION(OnEndSession)
+ MSG_WM_ENTERSIZEMOVE(OnEnterSizeMove)
+ MSG_WM_EXITMENULOOP(OnExitMenuLoop)
+ MSG_WM_EXITSIZEMOVE(OnExitSizeMove)
+ MSG_WM_GETMINMAXINFO(OnGetMinMaxInfo)
+ MSG_WM_HSCROLL(OnHScroll)
+ MSG_WM_INITMENU(OnInitMenu)
+ MSG_WM_INITMENUPOPUP(OnInitMenuPopup)
+ MSG_WM_KILLFOCUS(OnKillFocus)
+ MSG_WM_MOUSEACTIVATE(OnMouseActivate)
+ MSG_WM_MOVE(OnMove)
+ MSG_WM_MOVING(OnMoving)
+ MSG_WM_NCACTIVATE(OnNCActivate)
+ MSG_WM_NCCALCSIZE(OnNCCalcSize)
+ MESSAGE_HANDLER_EX(WM_NCHITTEST, OnNCHitTest)
+ MSG_WM_NCPAINT(OnNCPaint)
+ MSG_WM_NOTIFY(OnNotify)
+ MSG_WM_PAINT(OnPaint)
+ MSG_WM_POWERBROADCAST(OnPowerBroadcast)
+ MSG_WM_SETFOCUS(OnSetFocus)
+ MSG_WM_SETICON(OnSetIcon)
+ MSG_WM_SETTEXT(OnSetText)
+ MSG_WM_SETTINGCHANGE(OnSettingChange)
+ MSG_WM_SIZE(OnSize)
+ MSG_WM_SYSCOMMAND(OnSysCommand)
+ MSG_WM_THEMECHANGED(OnThemeChanged)
+ MSG_WM_VSCROLL(OnVScroll)
+ MSG_WM_WINDOWPOSCHANGING(OnWindowPosChanging)
+ MSG_WM_WINDOWPOSCHANGED(OnWindowPosChanged)
+ END_MSG_MAP()
+
+ virtual void OnActivate(UINT action, BOOL minimized, HWND window);
+ virtual void OnActivateApp(BOOL active, DWORD thread_id);
+ virtual LRESULT OnAppCommand(HWND window, short app_command, WORD device,
+ int keystate);
+ virtual void OnCancelMode();
+ virtual void OnCaptureChanged(HWND hwnd);
+ virtual void OnClose();
+ virtual void OnCommand(UINT notification_code, int command_id, HWND window);
+ virtual LRESULT OnCreate(CREATESTRUCT* create_struct);
+ // WARNING: If you override this be sure and invoke super, otherwise we'll
+ // leak a few things.
+ virtual void OnDestroy();
+ virtual void OnDisplayChange(UINT bits_per_pixel, CSize screen_size);
+ virtual LRESULT OnDwmCompositionChanged(UINT message,
+ WPARAM w_param,
+ LPARAM l_param);
+ virtual void OnEndSession(BOOL ending, UINT logoff);
+ virtual void OnEnterSizeMove();
+ virtual LRESULT OnEraseBkgnd(HDC dc);
+ virtual void OnExitMenuLoop(BOOL is_track_popup_menu);
+ virtual void OnExitSizeMove();
+ virtual LRESULT OnGetObject(UINT message, WPARAM w_param, LPARAM l_param);
+ virtual void OnGetMinMaxInfo(MINMAXINFO* minmax_info);
+ virtual void OnHScroll(int scroll_type, short position, HWND scrollbar);
+ virtual void OnInitMenu(HMENU menu);
+ virtual void OnInitMenuPopup(HMENU menu, UINT position, BOOL is_system_menu);
+ virtual LRESULT OnKeyDown(UINT message, WPARAM w_param, LPARAM l_param);
+ virtual LRESULT OnKeyUp(UINT message, WPARAM w_param, LPARAM l_param);
+ virtual void OnKillFocus(HWND focused_window);
+ virtual LRESULT OnMouseActivate(HWND window, UINT hittest_code, UINT message);
+ virtual LRESULT OnMouseLeave(UINT message, WPARAM w_param, LPARAM l_param);
+ virtual void OnMove(const CPoint& point);
+ virtual void OnMoving(UINT param, LPRECT new_bounds);
+ virtual LRESULT OnMouseRange(UINT message, WPARAM w_param, LPARAM l_param);
+ virtual LRESULT OnNCActivate(BOOL active);
+ virtual LRESULT OnNCCalcSize(BOOL w_param, LPARAM l_param);
+ virtual LRESULT OnNCHitTest(UINT message, WPARAM w_param, LPARAM l_param);
+ virtual LRESULT OnNCMouseRange(UINT message, WPARAM w_param, LPARAM l_param);
+ virtual void OnNCPaint(HRGN rgn);
+ virtual LRESULT OnNCUAHDrawCaption(UINT message,
+ WPARAM w_param,
+ LPARAM l_param);
+ virtual LRESULT OnNCUAHDrawFrame(UINT message, WPARAM w_param,
+ LPARAM l_param);
+ virtual LRESULT OnNotify(int w_param, NMHDR* l_param);
+ virtual void OnPaint(HDC dc);
+ virtual LRESULT OnPowerBroadcast(DWORD power_event, DWORD data);
+ virtual LRESULT OnReflectedMessage(UINT message, WPARAM w_param,
+ LPARAM l_param);
+ virtual void OnSetFocus(HWND focused_window);
+ virtual LRESULT OnSetIcon(UINT size_type, HICON new_icon);
+ virtual LRESULT OnSetText(const wchar_t* text);
+ virtual void OnSettingChange(UINT flags, const wchar_t* section);
+ virtual void OnSize(UINT param, const CSize& size);
+ virtual void OnSysCommand(UINT notification_code, CPoint click);
+ virtual void OnThemeChanged();
+ virtual void OnVScroll(int scroll_type, short position, HWND scrollbar);
+ virtual void OnWindowPosChanging(WINDOWPOS* window_pos);
+ virtual void OnWindowPosChanged(WINDOWPOS* window_pos);
+
+ // Deletes this window as it is destroyed, override to provide different
+ // behavior.
+ virtual void OnFinalMessage(HWND window);
+
+ // Overridden from WindowImpl:
+ virtual HICON GetDefaultWindowIcon() const;
+ virtual LRESULT OnWndProc(UINT message, WPARAM w_param, LPARAM l_param);
+
+ // Start tracking all mouse events so that this window gets sent mouse leave
+ // messages too.
+ void TrackMouseEvents(DWORD mouse_tracking_flags);
+
+ bool ProcessMouseRange(UINT message, WPARAM w_param, LPARAM l_param,
+ bool non_client);
+ void ProcessMouseMoved(const CPoint& point, UINT flags, bool is_nonclient);
+ void ProcessMouseExited();
+
+ // Fills out a MSG struct with the supplied values.
+ void MakeMSG(MSG* msg, UINT message, WPARAM w_param, LPARAM l_param) const;
+
+ void CloseNow();
+
+ bool IsLayeredWindow() const;
+
+ // A listener implementation that handles events received here.
+ NativeWidgetListener* listener_;
+
+ // The flags currently being used with TrackMouseEvent to track mouse
+ // messages. 0 if there is no active tracking. The value of this member is
+ // used when tracking is canceled.
+ DWORD active_mouse_tracking_flags_;
+
+ // True when the HWND has event capture.
+ bool has_capture_;
+
+ // A canvas that contains the window contents in the case of a layered
+ // window.
+ scoped_ptr<gfx::CanvasSkia> window_contents_;
+
+ // Properties associated with this NativeWidget implementation.
+ // TODO(beng): move to WidgetImpl.
+ ViewProps props_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeWidgetWin);
+};
+
+} // namespace internal
+} // namespace views
+
+#endif // VIEWS_WIDGET_NATIVE_WIDGET_WIN_H_
+
diff --git a/views/widget/native_widget_win_unittest.cc b/views/widget/native_widget_win_unittest.cc
new file mode 100644
index 0000000..b29d360
--- /dev/null
+++ b/views/widget/native_widget_win_unittest.cc
@@ -0,0 +1,90 @@
+// Copyright (c) 2011 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 "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/win/window_impl.h"
+#include "views/view.h"
+#include "views/widget/native_widget.h"
+#include "views/widget/widget_impl.h"
+#include "views/widget/widget_impl_test_util.h"
+
+namespace views {
+
+class NativeWidgetTest : public testing::Test {
+ public:
+ NativeWidgetTest() {}
+ virtual ~NativeWidgetTest() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NativeWidgetTest);
+};
+
+class TestWindowImpl : public ui::WindowImpl {
+ public:
+ TestWindowImpl() {}
+ virtual ~TestWindowImpl() {}
+
+ virtual BOOL ProcessWindowMessage(HWND window,
+ UINT message,
+ WPARAM w_param,
+ LPARAM l_param,
+ LRESULT& result,
+ DWORD msg_mad_id = 0) {
+ return FALSE;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestWindowImpl);
+};
+
+#if 0
+
+TEST_F(NativeWidgetTest, CreateNativeWidget) {
+ scoped_ptr<WidgetImpl> widget(internal::CreateWidgetImpl());
+ EXPECT_TRUE(widget->native_widget()->GetNativeView() != NULL);
+}
+
+TEST_F(NativeWidgetTest, GetNativeWidgetForNativeView) {
+ scoped_ptr<WidgetImpl> widget(internal::CreateWidgetImpl());
+ NativeWidget* a = widget->native_widget();
+ HWND nv = widget->native_widget()->GetNativeView();
+ NativeWidget* b = NativeWidget::GetNativeWidgetForNativeView(nv);
+ EXPECT_EQ(a, b);
+}
+
+// |widget| has the toplevel NativeWidget.
+TEST_F(NativeWidgetTest, GetTopLevelNativeWidget1) {
+ scoped_ptr<WidgetImpl> widget(internal::CreateWidgetImpl());
+ EXPECT_EQ(widget->native_widget(),
+ NativeWidget::GetTopLevelNativeWidget(
+ widget->native_widget()->GetNativeView()));
+}
+
+// |toplevel_widget| has the toplevel NativeWidget.
+TEST_F(NativeWidgetTest, GetTopLevelNativeWidget2) {
+ scoped_ptr<WidgetImpl> child_widget(internal::CreateWidgetImpl());
+ scoped_ptr<WidgetImpl> toplevel_widget(internal::CreateWidgetImpl());
+ SetParent(child_widget->native_widget()->GetNativeView(),
+ toplevel_widget->native_widget()->GetNativeView());
+ EXPECT_EQ(toplevel_widget->native_widget(),
+ NativeWidget::GetTopLevelNativeWidget(
+ child_widget->native_widget()->GetNativeView()));
+}
+
+// |child_widget| has the toplevel NativeWidget.
+TEST_F(NativeWidgetTest, GetTopLevelNativeWidget3) {
+ scoped_ptr<WidgetImpl> child_widget(internal::CreateWidgetImpl());
+
+ TestWindowImpl toplevel;
+ toplevel.Init(NULL, gfx::Rect(10, 10, 100, 100));
+
+ SetParent(child_widget->native_widget()->GetNativeView(), toplevel.hwnd());
+ EXPECT_EQ(child_widget->native_widget(),
+ NativeWidget::GetTopLevelNativeWidget(
+ child_widget->native_widget()->GetNativeView()));
+}
+
+#endif
+
+} // namespace views
diff --git a/views/widget/widget_impl.cc b/views/widget/widget_impl.cc
index c3292c9..0063a71 100644
--- a/views/widget/widget_impl.cc
+++ b/views/widget/widget_impl.cc
@@ -4,217 +4,412 @@
#include "views/widget/widget_impl.h"
+#include "base/compiler_specific.h"
+#include "base/message_loop.h"
+#include "views/focus/focus_manager.h"
+#include "views/view.h"
+#include "views/widget/native_widget.h"
+#include "views/widget/root_view.h"
+
namespace views {
-////////////////////////////////////////////////////////////////////////////////
-// WidgetImpl, public:
+namespace {
-WidgetImpl::WidgetImpl() {
+// TODO(beng): move to platform file
+int GetHorizontalDragThreshold() {
+ static int threshold = -1;
+#if defined(OS_WIN)
+ if (threshold == -1)
+ threshold = GetSystemMetrics(SM_CXDRAG) / 2;
+#endif
+ return threshold;
}
-WidgetImpl::~WidgetImpl() {
+// TODO(beng): move to platform file
+int GetVerticalDragThreshold() {
+ static int threshold = -1;
+#if defined(OS_WIN)
+ if (threshold == -1)
+ threshold = GetSystemMetrics(SM_CYDRAG) / 2;
+#endif
+ return threshold;
}
-////////////////////////////////////////////////////////////////////////////////
-// WidgetImpl, Widget implementation:
-
-void WidgetImpl::Init(gfx::NativeView parent, const gfx::Rect& bounds) {
+bool ExceededDragThreshold(int delta_x, int delta_y) {
+ return (abs(delta_x) > GetHorizontalDragThreshold() ||
+ abs(delta_y) > GetVerticalDragThreshold());
+}
}
-void WidgetImpl::InitWithWidget(Widget* parent, const gfx::Rect& bounds) {
+////////////////////////////////////////////////////////////////////////////////
+// WidgetImpl, public:
+WidgetImpl::WidgetImpl(View* contents_view)
+ : ALLOW_THIS_IN_INITIALIZER_LIST(
+ native_widget_(NativeWidget::CreateNativeWidget(this))),
+ ALLOW_THIS_IN_INITIALIZER_LIST(root_view_(new RootView(this))),
+ contents_view_(contents_view),
+ is_mouse_button_pressed_(false),
+ last_mouse_event_was_move_(false),
+ ALLOW_THIS_IN_INITIALIZER_LIST(close_widget_factory_(this)),
+ delete_on_destroy_(true) {
}
-WidgetDelegate* WidgetImpl::GetWidgetDelegate() {
- return NULL;
+WidgetImpl::~WidgetImpl() {
}
-void WidgetImpl::SetWidgetDelegate(WidgetDelegate* delegate) {
-
+void WidgetImpl::InitWithNativeViewParent(gfx::NativeView parent,
+ const gfx::Rect& bounds) {
+ native_widget_->InitWithNativeViewParent(parent, bounds);
}
-void WidgetImpl::SetContentsView(View* view) {
-
+WidgetImpl* WidgetImpl::GetTopLevelWidgetImpl() const {
+ NativeWidget* native_widget =
+ NativeWidget::GetTopLevelNativeWidget(native_widget_->GetNativeView());
+ return native_widget->GetWidgetImpl();
}
-void WidgetImpl::GetBounds(gfx::Rect* out, bool including_frame) const {
+gfx::Rect WidgetImpl::GetWindowScreenBounds() const {
+ return native_widget_->GetWindowScreenBounds();
+}
+gfx::Rect WidgetImpl::GetClientAreaScreenBounds() const {
+ return native_widget_->GetClientAreaScreenBounds();
}
void WidgetImpl::SetBounds(const gfx::Rect& bounds) {
-
+ native_widget_->SetBounds(bounds);
}
-void WidgetImpl::MoveAbove(Widget* other) {
-
+void WidgetImpl::SetShape(const gfx::Path& shape) {
+ native_widget_->SetShape(shape);
}
-void WidgetImpl::SetShape(gfx::NativeRegion region) {
+void WidgetImpl::Show() {
+ native_widget_->Show();
+}
+void WidgetImpl::Hide() {
+ native_widget_->Hide();
}
void WidgetImpl::Close() {
+ native_widget_->Hide();
+ if (close_widget_factory_.empty()) {
+ MessageLoop::current()->PostTask(FROM_HERE,
+ close_widget_factory_.NewRunnableMethod(&WidgetImpl::CloseNow));
+ }
}
-void WidgetImpl::CloseNow() {
-
+void WidgetImpl::MoveAbove(WidgetImpl* other) {
+ native_widget_->MoveAbove(other->native_widget());
}
-void WidgetImpl::Show() {
+void WidgetImpl::SetAlwaysOnTop(bool always_on_top) {
+ NOTIMPLEMENTED();
+}
+void WidgetImpl::InvalidateRect(const gfx::Rect& invalid_rect) {
+ native_widget_->InvalidateRect(invalid_rect);
}
-void WidgetImpl::Hide() {
+ThemeProvider* WidgetImpl::GetThemeProvider() const {
+ return NULL;
+}
+FocusManager* WidgetImpl::GetFocusManager() {
+ return GetTopLevelWidgetImpl()->focus_manager_.get();
}
-gfx::NativeView WidgetImpl::GetNativeView() const {
- return NULL;
+FocusTraversable* WidgetImpl::GetFocusTraversable() const {
+ return root_view_.get();
}
-void WidgetImpl::PaintNow(const gfx::Rect& update_rect) {
+////////////////////////////////////////////////////////////////////////////////
+// WidgetImpl, NativeWidgetListener implementation:
+void WidgetImpl::OnClose() {
+ Close();
}
-void WidgetImpl::SetOpacity(unsigned char opacity) {
+void WidgetImpl::OnDestroy() {
+ if (delete_on_destroy_)
+ delete this;
+}
+
+void WidgetImpl::OnDisplayChanged() {
+ // TODO(beng):
}
-void WidgetImpl::SetAlwaysOnTop(bool on_top) {
+bool WidgetImpl::OnKeyEvent(const KeyEvent& event) {
+ // find root view.
+ //return root_view_->OnKeyEvent(event);
+ return true;
}
-RootView* WidgetImpl::GetRootView() {
- return NULL;
+void WidgetImpl::OnMouseCaptureLost() {
+ if (native_widget_->HasMouseCapture()) {
+ if (is_mouse_button_pressed_) {
+ // TODO(beng): Rename to OnMouseCaptureLost();
+ root_view_->ProcessMouseDragCanceled();
+ }
+ is_mouse_button_pressed_ = false;
+ }
}
-Widget* WidgetImpl::GetRootWidget() const {
- return NULL;
+bool WidgetImpl::OnMouseEvent(const MouseEvent& event) {
+ last_mouse_event_was_move_ = false;
+ switch (event.type()) {
+ case ui::ET_MOUSE_PRESSED:
+ if (root_view_->OnMousePressed(event)) {
+ is_mouse_button_pressed_ = true;
+ if (!native_widget_->HasMouseCapture())
+ native_widget_->SetMouseCapture();
+ return true;
+ }
+ return false;
+ case ui::ET_MOUSE_RELEASED:
+ // TODO(beng): NativeWidgetGtk should not call this function if drag data
+ // exists, see comment in this function in WidgetGtk.
+ // Release the capture first, that way we don't get confused if
+ // OnMouseReleased blocks.
+ if (native_widget_->HasMouseCapture() &&
+ native_widget_->ShouldReleaseCaptureOnMouseReleased()) {
+ native_widget_->ReleaseMouseCapture();
+ }
+ is_mouse_button_pressed_ = false;
+ root_view_->OnMouseReleased(event, false);
+ return true;
+ case ui::ET_MOUSE_MOVED:
+ if (native_widget_->HasMouseCapture() && is_mouse_button_pressed_) {
+ last_mouse_event_was_move_ = false;
+ root_view_->OnMouseDragged(event);
+ } else {
+ gfx::Point screen_loc(event.location());
+ View::ConvertPointToScreen(root_view_.get(), &screen_loc);
+ if (last_mouse_event_was_move_ &&
+ last_mouse_event_position_ == screen_loc) {
+ // Don't generate a mouse event for the same location as the last.
+ return true;
+ }
+ last_mouse_event_position_ = screen_loc;
+ last_mouse_event_was_move_ = true;
+ root_view_->OnMouseMoved(event);
+ }
+ break;
+ case ui::ET_MOUSE_EXITED:
+ // TODO(beng): rename to OnMouseExited(event);
+ root_view_->ProcessOnMouseExited();
+ return true;
+ default:
+ break;
+ }
+ return true;
}
-bool WidgetImpl::IsVisible() const {
- return false;
+bool WidgetImpl::OnMouseWheelEvent(const MouseWheelEvent& event) {
+ // TODO(beng): rename to OnMouseWheel(event);
+ return !root_view_->ProcessMouseWheelEvent(event);
}
-bool WidgetImpl::IsActive() const {
- return false;
+void WidgetImpl::OnNativeWidgetCreated() {
+ root_view_->SetContentsView(contents_view_);
+ if (GetTopLevelWidgetImpl() == this)
+ focus_manager_.reset(new FocusManager(this));
}
-bool WidgetImpl::IsAccessibleWidget() const {
- return false;
+void WidgetImpl::OnPaint(gfx::Canvas* canvas) {
+ // TODO(beng): replace with root_view_->Paint(canvas);
+#if defined(OS_WIN)
+ root_view_->OnPaint(native_widget_->GetNativeView());
+#endif
}
-TooltipManager* WidgetImpl::GetTooltipManager() {
- return NULL;
+void WidgetImpl::OnSizeChanged(const gfx::Size& size) {
+ root_view_->SetSize(size);
}
-void WidgetImpl::GenerateMousePressedForView(View* view,
- const gfx::Point& point) {
+void WidgetImpl::OnNativeFocus(gfx::NativeView focused_view) {
+ GetFocusManager()->GetWidgetFocusManager()->OnWidgetFocusEvent(
+ focused_view, native_widget_->GetNativeView());
+}
+void WidgetImpl::OnNativeBlur(gfx::NativeView focused_view) {
+ GetFocusManager()->GetWidgetFocusManager()->OnWidgetFocusEvent(
+ native_widget_->GetNativeView(), focused_view);
}
-bool WidgetImpl::GetAccelerator(int cmd_id, ui::Accelerator* accelerator) {
- return false;
+void WidgetImpl::OnWorkAreaChanged() {
+
}
-Window* WidgetImpl::GetWindow() {
- return NULL;
+WidgetImpl* WidgetImpl::GetWidgetImpl() {
+ return const_cast<WidgetImpl*>(const_cast<const WidgetImpl*>(this));
}
-const Window* WidgetImpl::GetWindow() const {
- return NULL;
+const WidgetImpl* WidgetImpl::GetWidgetImpl() const {
+ return this;
}
-void WidgetImpl::SetNativeWindowProperty(const char* name, void* value) {
+////////////////////////////////////////////////////////////////////////////////
+// WidgetImpl, Widget implementation: (TEMPORARY, TEMPORARY, TEMPORARY!)
+void WidgetImpl::Init(gfx::NativeView parent, const gfx::Rect& bounds) {
+ InitWithNativeViewParent(parent, bounds);
}
-void* WidgetImpl::GetNativeWindowProperty(const char* name) {
- return NULL;
+void WidgetImpl::InitWithWidget(Widget* parent, const gfx::Rect& bounds) {
+ NOTIMPLEMENTED();
}
-ThemeProvider* WidgetImpl::GetThemeProvider() const {
+WidgetDelegate* WidgetImpl::GetWidgetDelegate() {
+ NOTIMPLEMENTED();
return NULL;
}
-ThemeProvider* WidgetImpl::GetDefaultThemeProvider() const {
- return NULL;
+void WidgetImpl::SetWidgetDelegate(WidgetDelegate* delegate) {
+ NOTIMPLEMENTED();
}
-FocusManager* WidgetImpl::GetFocusManager() {
- return NULL;
+void WidgetImpl::SetContentsView(View* view) {
+ NOTIMPLEMENTED();
}
-void WidgetImpl::ViewHierarchyChanged(bool is_add, View *parent,
- View *child) {
+void WidgetImpl::GetBounds(gfx::Rect* out, bool including_frame) const {
+ NOTIMPLEMENTED();
+}
+void WidgetImpl::MoveAbove(Widget* widget) {
+ NativeWidget* other =
+ NativeWidget::GetNativeWidgetForNativeView(widget->GetNativeView());
+ if (other)
+ native_widget_->MoveAbove(other);
}
-bool WidgetImpl::ContainsNativeView(gfx::NativeView native_view) {
- return false;
+void WidgetImpl::SetShape(gfx::NativeRegion region) {
+ NOTIMPLEMENTED();
}
-////////////////////////////////////////////////////////////////////////////////
-// WidgetImpl, NativeWidgetListener implementation:
+gfx::NativeView WidgetImpl::GetNativeView() const {
+ return native_widget_->GetNativeView();
+}
-void WidgetImpl::OnClose() {
+void WidgetImpl::PaintNow(const gfx::Rect& update_rect) {
+ NOTIMPLEMENTED();
+}
+void WidgetImpl::SetOpacity(unsigned char opacity) {
+ NOTIMPLEMENTED();
}
-void WidgetImpl::OnDestroy() {
+RootView* WidgetImpl::GetRootView() {
+ return root_view_.get();
+}
+Widget* WidgetImpl::GetRootWidget() const {
+ NOTIMPLEMENTED();
+ return NULL;
}
-void WidgetImpl::OnDisplayChanged() {
+bool WidgetImpl::IsVisible() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+bool WidgetImpl::IsActive() const {
+ NOTIMPLEMENTED();
+ return false;
}
-bool WidgetImpl::OnKeyEvent(const KeyEvent& event) {
+bool WidgetImpl::IsAccessibleWidget() const {
+ NOTIMPLEMENTED();
return false;
}
-void WidgetImpl::OnMouseCaptureLost() {
+TooltipManager* WidgetImpl::GetTooltipManager() {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+void WidgetImpl::GenerateMousePressedForView(View* view,
+ const gfx::Point& point) {
+ NOTIMPLEMENTED();
}
-bool WidgetImpl::OnMouseEvent(const MouseEvent& event) {
+bool WidgetImpl::GetAccelerator(int cmd_id, ui::Accelerator* accelerator) {
return false;
}
-bool WidgetImpl::OnMouseWheelEvent(const MouseWheelEvent& event) {
- return false;
+Window* WidgetImpl::GetWindow() {
+ return NULL;
}
-void WidgetImpl::OnNativeWidgetCreated() {
+const Window* WidgetImpl::GetWindow() const {
+ return NULL;
+}
+void WidgetImpl::SetNativeWindowProperty(const char* name, void* value) {
+ native_widget_->SetNativeWindowProperty(name, value);
}
-void WidgetImpl::OnPaint(gfx::Canvas* canvas) {
+void* WidgetImpl::GetNativeWindowProperty(const char* name) {
+ return native_widget_->GetNativeWindowProperty(name);
+}
+ThemeProvider* WidgetImpl::GetDefaultThemeProvider() const {
+ NOTIMPLEMENTED();
+ return NULL;
}
-void WidgetImpl::OnSizeChanged(const gfx::Size& size) {
+void WidgetImpl::ViewHierarchyChanged(bool is_add, View* parent, View* child) {
+ NOTIMPLEMENTED();
+}
+bool WidgetImpl::ContainsNativeView(gfx::NativeView native_view) {
+ NOTIMPLEMENTED();
+ return false;
}
-void WidgetImpl::OnNativeFocus(gfx::NativeView focused_view) {
+////////////////////////////////////////////////////////////////////////////////
+// WidgetImpl, private:
+void WidgetImpl::CloseNow() {
+ native_widget_->Close();
}
-void WidgetImpl::OnNativeBlur(gfx::NativeView focused_view) {
+#if !defined(OS_WIN)
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidget, public:
+
+// static
+NativeWidget* NativeWidget::CreateNativeWidget(
+ internal::NativeWidgetListener* listener) {
+ return NULL;
}
-void WidgetImpl::OnWorkAreaChanged() {
+// static
+NativeWidget* NativeWidget::GetNativeWidgetForNativeView(
+ gfx::NativeView native_view) {
+ return NULL;
+}
+// static
+NativeWidget* NativeWidget::GetNativeWidgetForNativeWindow(
+ gfx::NativeWindow native_window) {
+ return NULL;
}
-WidgetImpl* WidgetImpl::GetWidgetImpl() const {
+// static
+NativeWidget* NativeWidget::GetTopLevelNativeWidget(
+ gfx::NativeView native_view) {
return NULL;
}
-////////////////////////////////////////////////////////////////////////////////
-// WidgetImpl, private:
+#endif // !defined(OS_WIN)
} // namespace views
+
diff --git a/views/widget/widget_impl.h b/views/widget/widget_impl.h
index 8f00711..3327b5d 100644
--- a/views/widget/widget_impl.h
+++ b/views/widget/widget_impl.h
@@ -4,49 +4,134 @@
#ifndef VIEWS_WIDGET_WIDGET_IMPL_H_
#define VIEWS_WIDGET_WIDGET_IMPL_H_
-#pragma once
+#include "base/logging.h"
+#include "base/scoped_ptr.h"
+#include "base/task.h"
+#include "ui/gfx/point.h"
+#include "views/native_types.h"
+#include "views/focus/focus_manager.h"
#include "views/widget/native_widget_listener.h"
#include "views/widget/widget.h"
-namespace views {
+namespace gfx {
+class Canvas;
+class Path;
+class Rect;
+class Size;
+}
+
+namespace ui {
+ class ThemeProvider;
+}
+namespace views {
+class FocusManager;
+class KeyEvent;
+class MouseEvent;
+class MouseWheelEvent;
class NativeWidget;
+class RootView;
+class View;
////////////////////////////////////////////////////////////////////////////////
// WidgetImpl class
//
-// An object that represents a native widget that hosts a view hierarchy.
-// A WidgetImpl is owned by a NativeWidget implementation.
+// Encapsulates the platform-specific rendering, event receiving and widget
+// management aspects of the UI framework.
//
-// TODO(beng): This class should be renamed Widget after the transition to the
-// V2 API is complete.
+// Owns a RootView and thus a View hierarchy. Can contain child WidgetImpls.
+// WidgetImpl is a platform-independent type that communicates with a platform
+// or context specific NativeWidget implementation.
//
-class WidgetImpl : public Widget,
- internal::NativeWidgetListener {
+// TODO(beng): Consider ownership of this object vs. NativeWidget.
+class WidgetImpl : public internal::NativeWidgetListener,
+ public Widget {
public:
- WidgetImpl();
+ explicit WidgetImpl(View* contents_view);
virtual ~WidgetImpl();
+ void set_delete_on_destroy(bool delete_on_destroy) {
+ delete_on_destroy_ = delete_on_destroy;
+ }
+
+ // Initialization.
+ void InitWithNativeViewParent(gfx::NativeView parent,
+ const gfx::Rect& bounds);
+
+ // Returns the topmost WidgetImpl in a hierarchy.
+ WidgetImpl* GetTopLevelWidgetImpl() const;
+
+ // Returns the bounding rect of the Widget in screen coordinates.
+ gfx::Rect GetWindowScreenBounds() const;
+
+ // Returns the bounding rect of the Widget's client area, in screen
+ // coordinates.
+ gfx::Rect GetClientAreaScreenBounds() const;
+
+ // Sets the bounding rect of the Widget, in the coordinate system of its
+ // parent.
+ void SetBounds(const gfx::Rect& bounds);
+
+ void SetShape(const gfx::Path& shape);
+
+ void Show();
+ void Hide();
+
+ void Close();
+
+ void MoveAbove(WidgetImpl* other);
+ void SetAlwaysOnTop(bool always_on_top);
+
+ // Causes the specified rectangle to be added to the invalid rectangle for the
+ // WidgetImpl.
+ void InvalidateRect(const gfx::Rect& invalid_rect);
+
+ // Returns a ThemeProvider that can be used to provide resources when
+ // rendering Views associated with this WidgetImpl.
+ ThemeProvider* GetThemeProvider() const;
+
+ // Returns the FocusManager for this WidgetImpl. Only top-level WidgetImpls
+ // have FocusManagers.
+ FocusManager* GetFocusManager();
+
+ FocusTraversable* GetFocusTraversable() const;
+
+ NativeWidget* native_widget() const { return native_widget_.get(); }
+
private:
+ // Overridden from internal::NativeWidgetListener:
+ virtual void OnClose();
+ virtual void OnDestroy();
+ virtual void OnDisplayChanged();
+ virtual bool OnKeyEvent(const KeyEvent& event);
+ virtual void OnMouseCaptureLost();
+ virtual bool OnMouseEvent(const MouseEvent& event);
+ virtual bool OnMouseWheelEvent(const MouseWheelEvent& event);
+ virtual void OnNativeWidgetCreated();
+ virtual void OnPaint(gfx::Canvas* canvas);
+ virtual void OnSizeChanged(const gfx::Size& size);
+ virtual void OnNativeFocus(gfx::NativeView focused_view);
+ virtual void OnNativeBlur(gfx::NativeView focused_view);
+ virtual void OnWorkAreaChanged();
+ virtual WidgetImpl* GetWidgetImpl();
+ virtual const WidgetImpl* GetWidgetImpl() const;
+
// Overridden from Widget:
+ // TODO(beng): THIS IS TEMPORARY, and excludes methods duplicated above in
+ // new WidgetImpl API.
+ // TODO(beng): Remove/Merge with WidgetImpl API above.
virtual void Init(gfx::NativeView parent, const gfx::Rect& bounds);
virtual void InitWithWidget(Widget* parent, const gfx::Rect& bounds);
virtual WidgetDelegate* GetWidgetDelegate();
virtual void SetWidgetDelegate(WidgetDelegate* delegate);
virtual void SetContentsView(View* view);
virtual void GetBounds(gfx::Rect* out, bool including_frame) const;
- virtual void SetBounds(const gfx::Rect& bounds);
- virtual void MoveAbove(Widget* other);
+ virtual void MoveAbove(Widget* widget);
virtual void SetShape(gfx::NativeRegion region);
- virtual void Close();
- virtual void CloseNow();
- virtual void Show();
- virtual void Hide();
virtual gfx::NativeView GetNativeView() const;
virtual void PaintNow(const gfx::Rect& update_rect);
virtual void SetOpacity(unsigned char opacity);
- virtual void SetAlwaysOnTop(bool on_top);
virtual RootView* GetRootView();
virtual Widget* GetRootWidget() const;
virtual bool IsVisible() const;
@@ -60,35 +145,45 @@ class WidgetImpl : public Widget,
virtual const Window* GetWindow() const;
virtual void SetNativeWindowProperty(const char* name, void* value);
virtual void* GetNativeWindowProperty(const char* name);
- virtual ThemeProvider* GetThemeProvider() const;
virtual ThemeProvider* GetDefaultThemeProvider() const;
- virtual FocusManager* GetFocusManager();
virtual void ViewHierarchyChanged(bool is_add, View *parent,
View *child);
virtual bool ContainsNativeView(gfx::NativeView native_view);
- // Overridden from NativeWidgetListener:
- virtual void OnClose();
- virtual void OnDestroy();
- virtual void OnDisplayChanged();
- virtual bool OnKeyEvent(const KeyEvent& event);
- virtual void OnMouseCaptureLost();
- virtual bool OnMouseEvent(const MouseEvent& event);
- virtual bool OnMouseWheelEvent(const MouseWheelEvent& event);
- virtual void OnNativeWidgetCreated();
- virtual void OnPaint(gfx::Canvas* canvas);
- virtual void OnSizeChanged(const gfx::Size& size);
- virtual void OnNativeFocus(gfx::NativeView focused_view);
- virtual void OnNativeBlur(gfx::NativeView focused_view);
- virtual void OnWorkAreaChanged();
- virtual WidgetImpl* GetWidgetImpl() const;
+ // Causes the Widget to be destroyed immediately.
+ void CloseNow();
+
+ // A NativeWidget implementation. This can be changed dynamically to a
+ // different implementation during the lifetime of the Widget.
+ scoped_ptr<NativeWidget> native_widget_;
- // Weak.
- NativeWidget* native_widget_;
+ // A RootView that owns the View hierarchy within this Widget.
+ scoped_ptr<RootView> root_view_;
+ // TODO(beng): Remove once we upgrade RootView.
+ View* contents_view_;
+
+ // True when any mouse button is pressed.
+ bool is_mouse_button_pressed_;
+
+ // The following are used to detect duplicate mouse move events and not
+ // deliver them. Displaying a window may result in the system generating
+ // duplicate move events even though the mouse hasn't moved.
+ bool last_mouse_event_was_move_;
+ gfx::Point last_mouse_event_position_;
+
+ // Handles closing the Widget after a return to the message loop to allow the
+ // stack to unwind.
+ ScopedRunnableMethodFactory<WidgetImpl> close_widget_factory_;
+
+ // True if the Widget should be automatically deleted when it is destroyed.
+ bool delete_on_destroy_;
+
+ scoped_ptr<FocusManager> focus_manager_;
DISALLOW_COPY_AND_ASSIGN(WidgetImpl);
};
} // namespace views
-#endif // VIEWS_WIDGET_WIDGET_H_
+#endif // VIEWS_WIDGET_WIDGET_IMPL_H_
+
diff --git a/views/widget/widget_impl_test_util.cc b/views/widget/widget_impl_test_util.cc
new file mode 100644
index 0000000..4339e7e
--- /dev/null
+++ b/views/widget/widget_impl_test_util.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 2011 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 "views/widget/widget_impl_test_util.h"
+
+#include "views/view.h"
+#include "views/widget/native_widget.h"
+#include "views/widget/widget_impl.h"
+
+namespace views {
+namespace internal {
+
+WidgetImpl* CreateWidgetImpl() {
+ return CreateWidgetImplWithContents(new View);
+}
+
+WidgetImpl* CreateWidgetImplWithContents(View* contents_view) {
+ WidgetImpl* widget = new WidgetImpl(contents_view);
+ widget->set_delete_on_destroy(false);
+ widget->InitWithNativeViewParent(NULL, gfx::Rect(10, 10, 200, 200));
+ return widget;
+}
+
+WidgetImpl* CreateWidgetImplWithParent(WidgetImpl* parent) {
+ WidgetImpl* widget = new WidgetImpl(new View);
+ widget->set_delete_on_destroy(false);
+ widget->InitWithNativeViewParent(parent->native_widget()->GetNativeView(),
+ gfx::Rect(10, 10, 200, 200));
+ return widget;
+}
+
+} // namespace internal
+} // namespace views
diff --git a/views/widget/widget_impl_test_util.h b/views/widget/widget_impl_test_util.h
new file mode 100644
index 0000000..5609397
--- /dev/null
+++ b/views/widget/widget_impl_test_util.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2011 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 VIEWS_WIDGET_WIDGET_IMPL_TEST_UTIL_H_
+#define VIEWS_WIDGET_WIDGET_IMPL_TEST_UTIL_H_
+#pragma once
+
+namespace views {
+class View;
+class WidgetImpl;
+namespace internal {
+
+// Create dummy WidgetImpls for use in testing.
+WidgetImpl* CreateWidgetImpl();
+WidgetImpl* CreateWidgetImplWithContents(View* contents_view);
+WidgetImpl* CreateWidgetImplWithParent(WidgetImpl* parent);
+
+} // namespace internal
+} // namespace views
+
+#endif // VIEWS_WIDGET_WIDGET_IMPL_TEST_UTIL_H_
diff --git a/views/widget/widget_impl_unittest.cc b/views/widget/widget_impl_unittest.cc
new file mode 100644
index 0000000..057ed1d
--- /dev/null
+++ b/views/widget/widget_impl_unittest.cc
@@ -0,0 +1,38 @@
+// Copyright (c) 2011 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/logging.h"
+#include "base/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "views/focus/focus_manager.h"
+#include "views/widget/native_widget.h"
+#include "views/widget/widget_impl.h"
+#include "views/widget/widget_impl_test_util.h"
+
+namespace views {
+
+class WidgetTest : public testing::Test {
+ public:
+ WidgetTest() {}
+ virtual ~WidgetTest() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WidgetTest);
+};
+
+TEST_F(WidgetTest, FocusManagerInit_Basic) {
+ scoped_ptr<WidgetImpl> widget(internal::CreateWidgetImpl());
+ EXPECT_TRUE(widget->GetFocusManager() != NULL);
+}
+
+TEST_F(WidgetTest, FocusManagerInit_Nested) {
+ scoped_ptr<WidgetImpl> parent(internal::CreateWidgetImpl());
+ scoped_ptr<WidgetImpl> child(
+ internal::CreateWidgetImplWithParent(parent.get()));
+
+ EXPECT_EQ(parent->GetFocusManager(), child->GetFocusManager());
+}
+
+} // namespace views
+