summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-14 20:53:42 +0000
committerben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-14 20:53:42 +0000
commite2df0cd2aa14016fc5d10f964b94aafe5cac8246 (patch)
tree56a30c3fb05782f9ce698e6c4a4abdb5b8033a84
parentfbbaad5f3cc19ff3cc06bcadb5390064d1a4b077 (diff)
downloadchromium_src-e2df0cd2aa14016fc5d10f964b94aafe5cac8246.zip
chromium_src-e2df0cd2aa14016fc5d10f964b94aafe5cac8246.tar.gz
chromium_src-e2df0cd2aa14016fc5d10f964b94aafe5cac8246.tar.bz2
fix bustage'
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@74851 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--views/widget/widget_win.cc1405
-rw-r--r--views/widget/widget_win.h612
-rw-r--r--views/widget/widget_win_unittest.cc82
3 files changed, 2099 insertions, 0 deletions
diff --git a/views/widget/widget_win.cc b/views/widget/widget_win.cc
new file mode 100644
index 0000000..162d69f
--- /dev/null
+++ b/views/widget/widget_win.cc
@@ -0,0 +1,1405 @@
+// 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_win.h"
+
+#include <dwmapi.h>
+
+#include "base/string_util.h"
+#include "base/win/windows_version.h"
+#include "ui/base/keycodes/keyboard_code_conversion_win.h"
+#include "ui/base/l10n/l10n_util_win.h"
+#include "ui/base/system_monitor/system_monitor.h"
+#include "ui/base/theme_provider.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/accessibility/view_accessibility.h"
+#include "views/controls/native_control_win.h"
+#include "views/focus/accelerator_handler.h"
+#include "views/focus/focus_util_win.h"
+#include "views/views_delegate.h"
+#include "views/widget/aero_tooltip_manager.h"
+#include "views/widget/child_window_message_processor.h"
+#include "views/widget/default_theme_provider.h"
+#include "views/widget/drop_target_win.h"
+#include "views/widget/root_view.h"
+#include "views/widget/widget_delegate.h"
+#include "views/widget/widget_utils.h"
+#include "views/window/window_win.h"
+
+#pragma comment(lib, "dwmapi.lib")
+
+using ui::ViewProp;
+
+namespace {
+
+// Returns whether the specified window is the current active window.
+bool IsWindowActive(HWND hwnd) {
+ WINDOWINFO info;
+ return ::GetWindowInfo(hwnd, &info) &&
+ ((info.dwWindowStatus & WS_ACTIVECAPTION) != 0);
+}
+
+} // namespace
+
+namespace views {
+
+// Property used to link the HWND to its RootView.
+static const char* const kRootViewWindowProperty = "__ROOT_VIEW__";
+
+// Links the HWND to it's Widget (as a Widget, not a WidgetWin).
+static const char* const kWidgetKey = "__VIEWS_WIDGET__";
+
+// static
+bool WidgetWin::screen_reader_active_ = false;
+
+// A custom MSAA object id used to determine if a screen reader is actively
+// listening for MSAA events.
+#define OBJID_CUSTOM 1
+
+RootView* GetRootViewForHWND(HWND hwnd) {
+ return reinterpret_cast<RootView*>(
+ ViewProp::GetValue(hwnd, kRootViewWindowProperty));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// WidgetWin, public
+
+WidgetWin::WidgetWin()
+ : close_widget_factory_(this),
+ active_mouse_tracking_flags_(0),
+ has_capture_(false),
+ use_layered_buffer_(true),
+ layered_alpha_(255),
+ delete_on_destroy_(true),
+ can_update_layered_window_(true),
+ last_mouse_event_was_move_(false),
+ is_mouse_down_(false),
+ is_window_(false),
+ restore_focus_when_enabled_(false),
+ delegate_(NULL),
+ accessibility_view_events_index_(-1),
+ accessibility_view_events_(kMaxAccessibilityViewEvents) {
+}
+
+WidgetWin::~WidgetWin() {
+}
+
+// static
+WidgetWin* WidgetWin::GetWidget(HWND hwnd) {
+ // TODO(jcivelli): http://crbug.com/44499 We need a way to test that hwnd is
+ // associated with a WidgetWin (it might be a pure
+ // WindowImpl).
+ if (!WindowImpl::IsWindowImpl(hwnd))
+ return NULL;
+ return reinterpret_cast<WidgetWin*>(ui::GetWindowUserData(hwnd));
+}
+
+// static
+WidgetWin* WidgetWin::GetRootWidget(HWND hwnd) {
+ // First, check if the top-level window is a Widget.
+ HWND root = ::GetAncestor(hwnd, GA_ROOT);
+ if (!root)
+ return NULL;
+
+ WidgetWin* widget = WidgetWin::GetWidget(root);
+ if (widget)
+ return widget;
+
+ // Second, try to locate the last Widget window in the parent hierarchy.
+ HWND parent_hwnd = hwnd;
+ WidgetWin* parent_widget;
+ do {
+ parent_widget = WidgetWin::GetWidget(parent_hwnd);
+ if (parent_widget) {
+ widget = parent_widget;
+ parent_hwnd = ::GetAncestor(parent_hwnd, GA_PARENT);
+ }
+ } while (parent_hwnd != NULL && parent_widget != NULL);
+
+ return widget;
+}
+
+// static
+bool WidgetWin::IsAeroGlassEnabled() {
+ if (base::win::GetVersion() < base::win::VERSION_VISTA)
+ return false;
+ // If composition is not enabled, we behave like on XP.
+ BOOL enabled = FALSE;
+ return SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled;
+}
+
+void WidgetWin::SetUseLayeredBuffer(bool use_layered_buffer) {
+ if (use_layered_buffer_ == use_layered_buffer)
+ return;
+
+ use_layered_buffer_ = use_layered_buffer;
+ if (!hwnd())
+ return;
+
+ if (use_layered_buffer_)
+ LayoutRootView();
+ else
+ contents_.reset(NULL);
+}
+
+View* WidgetWin::GetAccessibilityViewEventAt(int id) {
+ // Convert from MSAA child id.
+ id = -(id + 1);
+ DCHECK(id >= 0 && id < kMaxAccessibilityViewEvents);
+ return accessibility_view_events_[id];
+}
+
+int WidgetWin::AddAccessibilityViewEvent(View* view) {
+ accessibility_view_events_index_ =
+ (accessibility_view_events_index_ + 1) % kMaxAccessibilityViewEvents;
+ accessibility_view_events_[accessibility_view_events_index_] = view;
+
+ // Convert to MSAA child id.
+ return -(accessibility_view_events_index_ + 1);
+}
+
+void WidgetWin::ClearAccessibilityViewEvent(View* view) {
+ for (std::vector<View*>::iterator it = accessibility_view_events_.begin();
+ it != accessibility_view_events_.end();
+ ++it) {
+ if (*it == view)
+ *it = NULL;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Widget implementation:
+
+void WidgetWin::Init(gfx::NativeView parent, const gfx::Rect& bounds) {
+ // Force creation of the RootView; otherwise, we may get a WM_SIZE after the
+ // window is created and before the root view is set up.
+ GetRootView();
+
+ // Create the window.
+ WindowImpl::Init(parent, bounds);
+
+ // Attempt to detect screen readers by sending an event with our custom id.
+ if (!IsAccessibleWidget())
+ NotifyWinEvent(EVENT_SYSTEM_ALERT, hwnd(), OBJID_CUSTOM, CHILDID_SELF);
+
+ // See if the style has been overridden.
+ opaque_ = !(window_ex_style() & WS_EX_TRANSPARENT);
+ use_layered_buffer_ = (use_layered_buffer_ &&
+ !!(window_ex_style() & WS_EX_LAYERED));
+
+ default_theme_provider_.reset(new DefaultThemeProvider());
+
+ props_.push_back(SetWindowSupportsRerouteMouseWheel(hwnd()));
+
+ drop_target_ = new DropTargetWin(root_view_.get());
+
+ if ((window_style() & WS_CHILD) == 0 ||
+ (WidgetWin::GetRootWidget(parent) == NULL &&
+ parent != GetDesktopWindow())) {
+ // Top-level widgets and child widgets who do not have a top-level widget
+ // ancestor get a FocusManager. Child widgets parented to the desktop do not
+ // get a FocusManager because parenting to the desktop is the technique used
+ // to intentionally exclude a widget from the FocusManager hierarchy.
+ focus_manager_.reset(new FocusManager(this));
+ }
+
+ // Sets the RootView as a property, so the automation can introspect windows.
+ SetNativeWindowProperty(kRootViewWindowProperty, root_view_.get());
+
+ MessageLoopForUI::current()->AddObserver(this);
+
+ // Windows special DWM window frame requires a special tooltip manager so
+ // that window controls in Chrome windows don't flicker when you move your
+ // mouse over them. See comment in aero_tooltip_manager.h.
+ if (GetThemeProvider()->ShouldUseNativeFrame()) {
+ tooltip_manager_.reset(new AeroTooltipManager(this));
+ } else {
+ tooltip_manager_.reset(new TooltipManagerWin(this));
+ }
+
+ // This message initializes the window so that focus border are shown for
+ // windows.
+ SendMessage(hwnd(),
+ WM_CHANGEUISTATE,
+ MAKELPARAM(UIS_CLEAR, UISF_HIDEFOCUS),
+ 0);
+
+ // Bug 964884: detach the IME attached to this window.
+ // We should attach IMEs only when we need to input CJK strings.
+ ImmAssociateContextEx(hwnd(), NULL, 0);
+}
+
+void WidgetWin::InitWithWidget(Widget* parent, const gfx::Rect& bounds) {
+ Init(parent->GetNativeView(), bounds);
+}
+
+WidgetDelegate* WidgetWin::GetWidgetDelegate() {
+ return delegate_;
+}
+
+void WidgetWin::SetWidgetDelegate(WidgetDelegate* delegate) {
+ delegate_ = delegate;
+}
+
+void WidgetWin::SetContentsView(View* view) {
+ root_view_->SetContentsView(view);
+}
+
+void WidgetWin::GetBounds(gfx::Rect* out, bool including_frame) const {
+ CRect crect;
+ if (including_frame) {
+ GetWindowRect(&crect);
+ *out = gfx::Rect(crect);
+ return;
+ }
+
+ GetClientRect(&crect);
+ POINT p = {0, 0};
+ ClientToScreen(hwnd(), &p);
+ out->SetRect(crect.left + p.x, crect.top + p.y,
+ crect.Width(), crect.Height());
+}
+
+void WidgetWin::SetBounds(const gfx::Rect& bounds) {
+ LONG style = GetWindowLong(GWL_STYLE);
+ if (style & WS_MAXIMIZE)
+ SetWindowLong(GWL_STYLE, style & ~WS_MAXIMIZE);
+ SetWindowPos(NULL, bounds.x(), bounds.y(), bounds.width(), bounds.height(),
+ SWP_NOACTIVATE | SWP_NOZORDER);
+}
+
+void WidgetWin::MoveAbove(Widget* other) {
+ gfx::Rect bounds;
+ GetBounds(&bounds, false);
+ SetWindowPos(other->GetNativeView(), bounds.x(), bounds.y(),
+ bounds.width(), bounds.height(), SWP_NOACTIVATE);
+}
+
+void WidgetWin::SetShape(gfx::NativeRegion region) {
+ SetWindowRgn(region, TRUE);
+}
+
+void WidgetWin::Close() {
+ if (!IsWindow())
+ return; // No need to do anything.
+
+ // Let's hide ourselves right away.
+ Hide();
+
+ if (close_widget_factory_.empty()) {
+ // And we delay the close so that if we are called from an ATL callback,
+ // we don't destroy the window before the callback returned (as the caller
+ // may delete ourselves on destroy and the ATL callback would still
+ // dereference us when the callback returns).
+ MessageLoop::current()->PostTask(FROM_HERE,
+ close_widget_factory_.NewRunnableMethod(
+ &WidgetWin::CloseNow));
+ }
+}
+
+void WidgetWin::CloseNow() {
+ // We may already have been destroyed if the selection resulted in a tab
+ // switch which will have reactivated the browser window and closed us, so
+ // we need to check to see if we're still a window before trying to destroy
+ // ourself.
+ if (IsWindow())
+ DestroyWindow(hwnd());
+}
+
+void WidgetWin::Show() {
+ if (IsWindow())
+ ShowWindow(SW_SHOWNOACTIVATE);
+}
+
+void WidgetWin::Hide() {
+ if (IsWindow()) {
+ // 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(NULL, 0, 0, 0, 0,
+ SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE |
+ SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER);
+ }
+}
+
+gfx::NativeView WidgetWin::GetNativeView() const {
+ return WindowImpl::hwnd();
+}
+
+static 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;
+}
+
+void WidgetWin::PaintNow(const gfx::Rect& update_rect) {
+ if (use_layered_buffer_) {
+ PaintLayeredWindow();
+ } else if (root_view_->NeedsPainting(false) && IsWindow()) {
+ if (!opaque_ && GetParent()) {
+ // We're transparent. Need to force painting to occur from our parent.
+ CRect parent_update_rect = update_rect.ToRECT();
+ POINT location_in_parent = { 0, 0 };
+ ClientToScreen(hwnd(), &location_in_parent);
+ ScreenToClient(GetParent(), &location_in_parent);
+ parent_update_rect.OffsetRect(location_in_parent);
+ RedrawWindow(GetParent(), parent_update_rect, NULL,
+ RDW_UPDATENOW | RDW_INVALIDATE | RDW_ALLCHILDREN);
+ } else {
+ // 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.
+ CRect screen_rect_temp;
+ GetWindowRect(&screen_rect_temp);
+ gfx::Rect screen_rect(screen_rect_temp);
+ gfx::Rect invalid_screen_rect = update_rect;
+ invalid_screen_rect.Offset(screen_rect.x(), screen_rect.y());
+
+ RedrawWindow(hwnd(), &update_rect.ToRECT(), NULL,
+ RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN);
+
+ LPARAM lparam = reinterpret_cast<LPARAM>(&invalid_screen_rect);
+ EnumChildWindows(hwnd(), EnumChildProcForRedraw, lparam);
+ }
+ // As we were created with a style of WS_CLIPCHILDREN redraw requests may
+ // result in an empty paint rect in WM_PAINT (this'll happen if a
+ // child HWND completely contains the update _rect). In such a scenario
+ // RootView would never get a ProcessPaint and always think it needs to
+ // be painted (leading to a steady stream of RedrawWindow requests on every
+ // event). For this reason we tell RootView it doesn't need to paint
+ // here.
+ root_view_->ClearPaintRect();
+ }
+}
+
+void WidgetWin::SetOpacity(unsigned char opacity) {
+ layered_alpha_ = static_cast<BYTE>(opacity);
+}
+
+void WidgetWin::SetAlwaysOnTop(bool on_top) {
+ if (on_top)
+ set_window_ex_style(window_ex_style() | WS_EX_TOPMOST);
+ else
+ set_window_ex_style(window_ex_style() & ~WS_EX_TOPMOST);
+}
+
+RootView* WidgetWin::GetRootView() {
+ if (!root_view_.get()) {
+ // First time the root view is being asked for, create it now.
+ root_view_.reset(CreateRootView());
+ }
+ return root_view_.get();
+}
+
+Widget* WidgetWin::GetRootWidget() const {
+ return GetRootWidget(hwnd());
+}
+
+bool WidgetWin::IsVisible() const {
+ return !!::IsWindowVisible(hwnd());
+}
+
+bool WidgetWin::IsActive() const {
+ return IsWindowActive(hwnd());
+}
+
+bool WidgetWin::IsAccessibleWidget() const {
+ return screen_reader_active_;
+}
+
+TooltipManager* WidgetWin::GetTooltipManager() {
+ return tooltip_manager_.get();
+}
+
+void WidgetWin::GenerateMousePressedForView(View* view,
+ const gfx::Point& point) {
+ gfx::Point point_in_widget(point);
+ View::ConvertPointToWidget(view, &point_in_widget);
+ root_view_->SetMouseHandler(view);
+ ProcessMousePressed(point_in_widget.ToPOINT(), MK_LBUTTON, false, false);
+}
+
+bool WidgetWin::GetAccelerator(int cmd_id, ui::Accelerator* accelerator) {
+ return false;
+}
+
+Window* WidgetWin::GetWindow() {
+ return GetWindowImpl(hwnd());
+}
+
+const Window* WidgetWin::GetWindow() const {
+ return GetWindowImpl(hwnd());
+}
+
+void WidgetWin::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 ViewProp(hwnd(), name, value));
+}
+
+void* WidgetWin::GetNativeWindowProperty(const char* name) {
+ return ViewProp::GetValue(hwnd(), name);
+}
+
+ThemeProvider* WidgetWin::GetThemeProvider() const {
+ return GetWidgetThemeProvider(this);
+}
+
+ThemeProvider* WidgetWin::GetDefaultThemeProvider() const {
+ return default_theme_provider_.get();
+}
+
+FocusManager* WidgetWin::GetFocusManager() {
+ if (focus_manager_.get())
+ return focus_manager_.get();
+
+ WidgetWin* widget = static_cast<WidgetWin*>(GetRootWidget());
+ if (widget && widget != this) {
+ // WidgetWin subclasses may override GetFocusManager(), for example for
+ // dealing with cases where the widget has been unparented.
+ return widget->GetFocusManager();
+ }
+ return NULL;
+}
+
+void WidgetWin::ViewHierarchyChanged(bool is_add, View *parent,
+ View *child) {
+ if (drop_target_.get())
+ drop_target_->ResetTargetViewIfEquals(child);
+
+ if (!is_add)
+ ClearAccessibilityViewEvent(child);
+}
+
+
+bool WidgetWin::ContainsNativeView(gfx::NativeView native_view) {
+ if (hwnd() == native_view)
+ return true;
+
+ // Traverse the set of parents of the given view to determine if native_view
+ // is a descendant of this window.
+ HWND parent_window = ::GetParent(native_view);
+ HWND previous_child = native_view;
+ while (parent_window && parent_window != previous_child) {
+ if (hwnd() == parent_window)
+ return true;
+ previous_child = parent_window;
+ parent_window = ::GetParent(parent_window);
+ }
+
+ // A views::NativeViewHost may contain the given native view, without it being
+ // an ancestor of hwnd(), so traverse the views::View hierarchy looking for
+ // such views.
+ return GetRootView()->ContainsNativeView(native_view);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// MessageLoop::Observer
+
+void WidgetWin::WillProcessMessage(const MSG& msg) {
+}
+
+void WidgetWin::DidProcessMessage(const MSG& msg) {
+ if (root_view_->NeedsPainting(true))
+ PaintNow(root_view_->GetScheduledPaintRect());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// FocusTraversable
+
+FocusSearch* WidgetWin::GetFocusSearch() {
+ return root_view_->GetFocusSearch();
+}
+
+FocusTraversable* WidgetWin::GetFocusTraversableParent() {
+ // We are a proxy to the root view, so we should be bypassed when traversing
+ // up and as a result this should not be called.
+ NOTREACHED();
+ return NULL;
+}
+
+void WidgetWin::SetFocusTraversableParent(FocusTraversable* parent) {
+ root_view_->SetFocusTraversableParent(parent);
+}
+
+View* WidgetWin::GetFocusTraversableParentView() {
+ // We are a proxy to the root view, so we should be bypassed when traversing
+ // up and as a result this should not be called.
+ NOTREACHED();
+ return NULL;
+}
+
+void WidgetWin::SetFocusTraversableParentView(View* parent_view) {
+ root_view_->SetFocusTraversableParentView(parent_view);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Message handlers
+
+void WidgetWin::OnActivate(UINT action, BOOL minimized, HWND window) {
+ SetMsgHandled(FALSE);
+}
+
+void WidgetWin::OnActivateApp(BOOL active, DWORD thread_id) {
+ SetMsgHandled(FALSE);
+}
+
+LRESULT WidgetWin::OnAppCommand(HWND window, short app_command, WORD device,
+ int keystate) {
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+void WidgetWin::OnCancelMode() {
+}
+
+void WidgetWin::OnCaptureChanged(HWND hwnd) {
+ if (has_capture_) {
+ if (is_mouse_down_)
+ root_view_->ProcessMouseDragCanceled();
+ is_mouse_down_ = false;
+ has_capture_ = false;
+ }
+}
+
+void WidgetWin::OnClose() {
+ Close();
+}
+
+void WidgetWin::OnCommand(UINT notification_code, int command_id, HWND window) {
+ SetMsgHandled(FALSE);
+}
+
+LRESULT WidgetWin::OnCreate(CREATESTRUCT* create_struct) {
+ // Widget::GetWidgetFromNativeView expects the contents of this property
+ // to be of type Widget, so the cast is necessary.
+ SetNativeWindowProperty(kWidgetKey, static_cast<Widget*>(this));
+ return 0;
+}
+
+void WidgetWin::OnDestroy() {
+ if (drop_target_.get()) {
+ RevokeDragDrop(hwnd());
+ drop_target_ = NULL;
+ }
+
+ props_.reset();
+}
+
+void WidgetWin::OnDisplayChange(UINT bits_per_pixel, CSize screen_size) {
+ if (GetWidgetDelegate())
+ GetWidgetDelegate()->DisplayChanged();
+}
+
+LRESULT WidgetWin::OnDwmCompositionChanged(UINT msg,
+ WPARAM w_param,
+ LPARAM l_param) {
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+void WidgetWin::OnEndSession(BOOL ending, UINT logoff) {
+ SetMsgHandled(FALSE);
+}
+
+void WidgetWin::OnEnterSizeMove() {
+ SetMsgHandled(FALSE);
+}
+
+LRESULT WidgetWin::OnEraseBkgnd(HDC dc) {
+ // This is needed for magical win32 flicker ju-ju
+ return 1;
+}
+
+void WidgetWin::OnExitMenuLoop(BOOL is_track_popup_menu) {
+ SetMsgHandled(FALSE);
+}
+
+void WidgetWin::OnExitSizeMove() {
+ SetMsgHandled(FALSE);
+}
+
+LRESULT WidgetWin::OnGetObject(UINT uMsg, WPARAM w_param, LPARAM l_param) {
+ LRESULT reference_result = static_cast<LRESULT>(0L);
+
+ // Accessibility readers will send an OBJID_CLIENT message
+ if (OBJID_CLIENT == l_param) {
+ // Retrieve MSAA dispatch object for the root view.
+ base::win::ScopedComPtr<IAccessible> root(
+ ViewAccessibility::GetAccessibleForView(GetRootView()));
+
+ // Create a reference that MSAA will marshall to the client.
+ reference_result = LresultFromObject(IID_IAccessible, w_param,
+ static_cast<IAccessible*>(root.Detach()));
+ }
+
+ if (OBJID_CUSTOM == l_param) {
+ // An MSAA client requestes our custom id. Assume that we have detected an
+ // active windows screen reader.
+ OnScreenReaderDetected();
+
+ // Return with failure.
+ return static_cast<LRESULT>(0L);
+ }
+
+ return reference_result;
+}
+
+void WidgetWin::OnGetMinMaxInfo(MINMAXINFO* minmax_info) {
+ SetMsgHandled(FALSE);
+}
+
+void WidgetWin::OnHScroll(int scroll_type, short position, HWND scrollbar) {
+ SetMsgHandled(FALSE);
+}
+
+void WidgetWin::OnInitMenu(HMENU menu) {
+ SetMsgHandled(FALSE);
+}
+
+void WidgetWin::OnInitMenuPopup(HMENU menu,
+ UINT position,
+ BOOL is_system_menu) {
+ SetMsgHandled(FALSE);
+}
+
+LRESULT WidgetWin::OnKeyDown(UINT message, WPARAM w_param, LPARAM l_param) {
+ RootView* root_view = GetFocusedViewRootView();
+ if (!root_view)
+ root_view = root_view_.get();
+
+ MSG msg;
+ MakeMSG(&msg, message, w_param, l_param);
+ SetMsgHandled(root_view->ProcessKeyEvent(KeyEvent(msg)));
+ return 0;
+}
+
+LRESULT WidgetWin::OnKeyUp(UINT message, WPARAM w_param, LPARAM l_param) {
+ RootView* root_view = GetFocusedViewRootView();
+ if (!root_view)
+ root_view = root_view_.get();
+
+ MSG msg;
+ MakeMSG(&msg, message, w_param, l_param);
+ SetMsgHandled(root_view->ProcessKeyEvent(KeyEvent(msg)));
+ return 0;
+}
+
+void WidgetWin::OnKillFocus(HWND focused_window) {
+ GetFocusManager()->GetWidgetFocusManager()->OnWidgetFocusEvent(
+ this->GetNativeView(),
+ focused_window);
+ SetMsgHandled(FALSE);
+}
+
+// TODO(pkasting): ORing the pressed/released button into the flags is _wrong_.
+// It makes it impossible to tell which button was modified when multiple
+// buttons are/were held down. We need to instead put the modified button into
+// a separate member on the MouseEvent, then audit all consumers of MouseEvents
+// to fix them to use the resulting values correctly.
+
+void WidgetWin::OnLButtonDown(UINT flags, const CPoint& point) {
+ ProcessMousePressed(point, flags | MK_LBUTTON, false, false);
+}
+
+void WidgetWin::OnLButtonUp(UINT flags, const CPoint& point) {
+ ProcessMouseReleased(point, flags | MK_LBUTTON);
+}
+
+void WidgetWin::OnLButtonDblClk(UINT flags, const CPoint& point) {
+ ProcessMousePressed(point, flags | MK_LBUTTON, true, false);
+}
+
+void WidgetWin::OnMButtonDown(UINT flags, const CPoint& point) {
+ ProcessMousePressed(point, flags | MK_MBUTTON, false, false);
+}
+
+void WidgetWin::OnMButtonUp(UINT flags, const CPoint& point) {
+ ProcessMouseReleased(point, flags | MK_MBUTTON);
+}
+
+void WidgetWin::OnMButtonDblClk(UINT flags, const CPoint& point) {
+ ProcessMousePressed(point, flags | MK_MBUTTON, true, false);
+}
+
+LRESULT WidgetWin::OnMouseActivate(HWND window, UINT hittest_code,
+ UINT message) {
+ SetMsgHandled(FALSE);
+ return MA_ACTIVATE;
+}
+
+void WidgetWin::OnMouseMove(UINT flags, const CPoint& point) {
+ ProcessMouseMoved(point, flags, false);
+}
+
+LRESULT WidgetWin::OnMouseLeave(UINT message, WPARAM w_param, LPARAM l_param) {
+ tooltip_manager_->OnMouseLeave();
+ ProcessMouseExited();
+ return 0;
+}
+
+LRESULT WidgetWin::OnMouseWheel(UINT message, WPARAM w_param, LPARAM l_param) {
+ // Reroute the mouse-wheel to the window under the mouse pointer if
+ // applicable.
+ if (message == WM_MOUSEWHEEL &&
+ views::RerouteMouseWheel(hwnd(), w_param, l_param)) {
+ return 0;
+ }
+
+ int flags = GET_KEYSTATE_WPARAM(w_param);
+ short distance = GET_WHEEL_DELTA_WPARAM(w_param);
+ int x = GET_X_LPARAM(l_param);
+ int y = GET_Y_LPARAM(l_param);
+ MouseWheelEvent e(distance, x, y, Event::ConvertWindowsFlags(flags));
+ return root_view_->ProcessMouseWheelEvent(e) ? 0 : 1;
+}
+
+void WidgetWin::OnMove(const CPoint& point) {
+ SetMsgHandled(FALSE);
+}
+
+void WidgetWin::OnMoving(UINT param, const LPRECT new_bounds) {
+}
+
+LRESULT WidgetWin::OnMouseRange(UINT msg, WPARAM w_param, LPARAM l_param) {
+ tooltip_manager_->OnMouse(msg, w_param, l_param);
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+LRESULT WidgetWin::OnNCActivate(BOOL active) {
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+LRESULT WidgetWin::OnNCCalcSize(BOOL w_param, LPARAM l_param) {
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+LRESULT WidgetWin::OnNCHitTest(const CPoint& pt) {
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+void WidgetWin::OnNCLButtonDblClk(UINT flags, const CPoint& point) {
+ SetMsgHandled(ProcessMousePressed(point, flags | MK_LBUTTON, true, true));
+}
+
+void WidgetWin::OnNCLButtonDown(UINT flags, const CPoint& point) {
+ SetMsgHandled(ProcessMousePressed(point, flags | MK_LBUTTON, false, true));
+}
+
+void WidgetWin::OnNCLButtonUp(UINT flags, const CPoint& point) {
+ SetMsgHandled(FALSE);
+}
+
+void WidgetWin::OnNCMButtonDblClk(UINT flags, const CPoint& point) {
+ SetMsgHandled(ProcessMousePressed(point, flags | MK_MBUTTON, true, true));
+}
+
+void WidgetWin::OnNCMButtonDown(UINT flags, const CPoint& point) {
+ SetMsgHandled(ProcessMousePressed(point, flags | MK_MBUTTON, false, true));
+}
+
+void WidgetWin::OnNCMButtonUp(UINT flags, const CPoint& point) {
+ SetMsgHandled(FALSE);
+}
+
+LRESULT WidgetWin::OnNCMouseLeave(UINT uMsg, WPARAM w_param, LPARAM l_param) {
+ ProcessMouseExited();
+ return 0;
+}
+
+LRESULT WidgetWin::OnNCMouseMove(UINT flags, const CPoint& point) {
+ // NC points are in screen coordinates.
+ CPoint temp = point;
+ MapWindowPoints(HWND_DESKTOP, hwnd(), &temp, 1);
+ ProcessMouseMoved(temp, 0, true);
+
+ // We need to process this message to stop Windows from drawing the window
+ // controls as the mouse moves over the title bar area when the window is
+ // maximized.
+ return 0;
+}
+
+void WidgetWin::OnNCPaint(HRGN rgn) {
+ SetMsgHandled(FALSE);
+}
+
+void WidgetWin::OnNCRButtonDblClk(UINT flags, const CPoint& point) {
+ SetMsgHandled(ProcessMousePressed(point, flags | MK_RBUTTON, true, true));
+}
+
+void WidgetWin::OnNCRButtonDown(UINT flags, const CPoint& point) {
+ SetMsgHandled(ProcessMousePressed(point, flags | MK_RBUTTON, false, true));
+}
+
+void WidgetWin::OnNCRButtonUp(UINT flags, const CPoint& point) {
+ SetMsgHandled(FALSE);
+}
+
+LRESULT WidgetWin::OnNCUAHDrawCaption(UINT msg,
+ WPARAM w_param,
+ LPARAM l_param) {
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+LRESULT WidgetWin::OnNCUAHDrawFrame(UINT msg, WPARAM w_param, LPARAM l_param) {
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+LRESULT WidgetWin::OnNotify(int w_param, NMHDR* l_param) {
+ // We can be sent this message before the tooltip manager is created, if a
+ // subclass overrides OnCreate and creates some kind of Windows control there
+ // that sends WM_NOTIFY messages.
+ if (tooltip_manager_.get()) {
+ bool handled;
+ LRESULT result = tooltip_manager_->OnNotify(w_param, l_param, &handled);
+ SetMsgHandled(handled);
+ return result;
+ }
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+void WidgetWin::OnPaint(HDC dc) {
+ root_view_->OnPaint(hwnd());
+}
+
+LRESULT WidgetWin::OnPowerBroadcast(DWORD power_event, DWORD data) {
+ ui::SystemMonitor* monitor = ui::SystemMonitor::Get();
+ if (monitor)
+ monitor->ProcessWmPowerBroadcastMessage(power_event);
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+void WidgetWin::OnRButtonDown(UINT flags, const CPoint& point) {
+ ProcessMousePressed(point, flags | MK_RBUTTON, false, false);
+}
+
+void WidgetWin::OnRButtonUp(UINT flags, const CPoint& point) {
+ ProcessMouseReleased(point, flags | MK_RBUTTON);
+}
+
+void WidgetWin::OnRButtonDblClk(UINT flags, const CPoint& point) {
+ ProcessMousePressed(point, flags | MK_RBUTTON, true, false);
+}
+
+LRESULT WidgetWin::OnReflectedMessage(UINT msg,
+ WPARAM w_param,
+ LPARAM l_param) {
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+void WidgetWin::OnSetFocus(HWND focused_window) {
+ GetFocusManager()->GetWidgetFocusManager()->OnWidgetFocusEvent(
+ focused_window,
+ this->GetNativeView());
+ SetMsgHandled(FALSE);
+}
+
+LRESULT WidgetWin::OnSetIcon(UINT size_type, HICON new_icon) {
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+LRESULT WidgetWin::OnSetText(const wchar_t* text) {
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+void WidgetWin::OnSettingChange(UINT flags, const wchar_t* section) {
+ if (flags == SPI_SETWORKAREA && GetWidgetDelegate())
+ GetWidgetDelegate()->WorkAreaChanged();
+ SetMsgHandled(FALSE);
+}
+
+void WidgetWin::OnSize(UINT param, const CSize& size) {
+ LayoutRootView();
+}
+
+void WidgetWin::OnSysCommand(UINT notification_code, CPoint click) {
+}
+
+void WidgetWin::OnThemeChanged() {
+ // Notify NativeTheme.
+ gfx::NativeTheme::instance()->CloseHandles();
+}
+
+void WidgetWin::OnFinalMessage(HWND window) {
+ if (delete_on_destroy_)
+ delete this;
+}
+
+void WidgetWin::OnVScroll(int scroll_type, short position, HWND scrollbar) {
+ SetMsgHandled(FALSE);
+}
+
+void WidgetWin::OnWindowPosChanging(WINDOWPOS* window_pos) {
+ SetMsgHandled(FALSE);
+}
+
+void WidgetWin::OnWindowPosChanged(WINDOWPOS* window_pos) {
+ SetMsgHandled(FALSE);
+}
+
+gfx::Size WidgetWin::GetRootViewSize() const {
+ CRect rect;
+ if (use_layered_buffer_)
+ GetWindowRect(&rect);
+ else
+ GetClientRect(&rect);
+
+ return gfx::Size(rect.Width(), rect.Height());
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// WidgetWin, protected:
+
+void WidgetWin::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 WidgetWin::ProcessMousePressed(const CPoint& point,
+ UINT flags,
+ bool dbl_click,
+ bool non_client) {
+ last_mouse_event_was_move_ = false;
+ // Windows gives screen coordinates for nonclient events, while the RootView
+ // expects window coordinates; convert if necessary.
+ gfx::Point converted_point(point);
+ if (non_client)
+ View::ConvertPointToView(NULL, root_view_.get(), &converted_point);
+ MouseEvent mouse_pressed(ui::ET_MOUSE_PRESSED,
+ converted_point.x(),
+ converted_point.y(),
+ (dbl_click ? ui::EF_IS_DOUBLE_CLICK : 0) |
+ (non_client ? ui::EF_IS_NON_CLIENT : 0) |
+ Event::ConvertWindowsFlags(flags));
+ if (root_view_->OnMousePressed(mouse_pressed)) {
+ is_mouse_down_ = true;
+ if (!has_capture_) {
+ SetCapture();
+ has_capture_ = true;
+ }
+ return true;
+ }
+ return false;
+}
+
+void WidgetWin::ProcessMouseDragged(const CPoint& point, UINT flags) {
+ last_mouse_event_was_move_ = false;
+ MouseEvent mouse_drag(ui::ET_MOUSE_DRAGGED,
+ point.x,
+ point.y,
+ Event::ConvertWindowsFlags(flags));
+ root_view_->OnMouseDragged(mouse_drag);
+}
+
+void WidgetWin::ProcessMouseReleased(const CPoint& point, UINT flags) {
+ last_mouse_event_was_move_ = false;
+ MouseEvent mouse_up(ui::ET_MOUSE_RELEASED,
+ point.x,
+ point.y,
+ Event::ConvertWindowsFlags(flags));
+ // Release the capture first, that way we don't get confused if
+ // OnMouseReleased blocks.
+ if (has_capture_ && ReleaseCaptureOnMouseReleased()) {
+ has_capture_ = false;
+ ReleaseCapture();
+ }
+ is_mouse_down_ = false;
+ root_view_->OnMouseReleased(mouse_up, false);
+}
+
+void WidgetWin::ProcessMouseMoved(const CPoint &point, UINT flags,
+ bool is_nonclient) {
+ // 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(is_nonclient ? TME_NONCLIENT | TME_LEAVE : TME_LEAVE);
+ if (has_capture_ && is_mouse_down_) {
+ ProcessMouseDragged(point, flags);
+ } else {
+ gfx::Point screen_loc(point);
+ View::ConvertPointToScreen(root_view_.get(), &screen_loc);
+ if (last_mouse_event_was_move_ && last_mouse_move_x_ == screen_loc.x() &&
+ last_mouse_move_y_ == screen_loc.y()) {
+ // Don't generate a mouse event for the same location as the last.
+ return;
+ }
+ last_mouse_move_x_ = screen_loc.x();
+ last_mouse_move_y_ = screen_loc.y();
+ last_mouse_event_was_move_ = true;
+ MouseEvent mouse_move(ui::ET_MOUSE_MOVED,
+ point.x,
+ point.y,
+ Event::ConvertWindowsFlags(flags));
+ root_view_->OnMouseMoved(mouse_move);
+ }
+}
+
+void WidgetWin::ProcessMouseExited() {
+ last_mouse_event_was_move_ = false;
+ root_view_->ProcessOnMouseExited();
+ // Reset our tracking flag so that future mouse movement over this WidgetWin
+ // results in a new tracking session.
+ active_mouse_tracking_flags_ = 0;
+}
+
+void WidgetWin::LayoutRootView() {
+ gfx::Size size(GetRootViewSize());
+
+ if (use_layered_buffer_)
+ SizeContents(size);
+
+ // Resizing changes the size of the view hierarchy and thus forces a
+ // complete relayout.
+ root_view_->SetBounds(0, 0, size.width(), size.height());
+ root_view_->SchedulePaint();
+
+ if (use_layered_buffer_)
+ PaintNow(gfx::Rect(0, 0, size.width(), size.height()));
+}
+
+void WidgetWin::OnScreenReaderDetected() {
+ screen_reader_active_ = true;
+}
+
+bool WidgetWin::ReleaseCaptureOnMouseReleased() {
+ return true;
+}
+
+RootView* WidgetWin::CreateRootView() {
+ return new RootView(this);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// WidgetWin, private:
+
+// static
+Window* WidgetWin::GetWindowImpl(HWND hwnd) {
+ // NOTE: we can't use GetAncestor here as constrained windows are a Window,
+ // but not a top level window.
+ HWND parent = hwnd;
+ while (parent) {
+ WidgetWin* widget =
+ reinterpret_cast<WidgetWin*>(ui::GetWindowUserData(parent));
+ if (widget && widget->is_window_)
+ return static_cast<WindowWin*>(widget);
+ parent = ::GetParent(parent);
+ }
+ return NULL;
+}
+
+void WidgetWin::SizeContents(const gfx::Size& window_size) {
+ contents_.reset(new gfx::CanvasSkia(window_size.width(),
+ window_size.height(),
+ false));
+}
+
+void WidgetWin::PaintLayeredWindow() {
+ // Painting monkeys with our cliprect, so we need to save it so that the
+ // call to UpdateLayeredWindow updates the entire window, not just the
+ // cliprect.
+ contents_->save(SkCanvas::kClip_SaveFlag);
+ gfx::Rect dirty_rect = root_view_->GetScheduledPaintRect();
+ contents_->ClipRectInt(dirty_rect.x(), dirty_rect.y(), dirty_rect.width(),
+ dirty_rect.height());
+ root_view_->ProcessPaint(contents_.get());
+ contents_->restore();
+
+ UpdateWindowFromContents(contents_->getTopPlatformDevice().getBitmapDC());
+}
+
+void WidgetWin::UpdateWindowFromContents(HDC dib_dc) {
+ DCHECK(use_layered_buffer_);
+ if (can_update_layered_window_) {
+ CRect wr;
+ GetWindowRect(&wr);
+ CSize size(wr.right - wr.left, wr.bottom - wr.top);
+ CPoint zero_origin(0, 0);
+ CPoint window_position = wr.TopLeft();
+
+ BLENDFUNCTION blend = {AC_SRC_OVER, 0, layered_alpha_, AC_SRC_ALPHA};
+ UpdateLayeredWindow(
+ hwnd(), NULL, &window_position, &size, dib_dc, &zero_origin,
+ RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA);
+ }
+}
+
+RootView* WidgetWin::GetFocusedViewRootView() {
+ FocusManager* focus_manager = GetFocusManager();
+ if (!focus_manager) {
+ NOTREACHED();
+ return NULL;
+ }
+ View* focused_view = focus_manager->GetFocusedView();
+ if (!focused_view)
+ return NULL;
+ return focused_view->GetRootView();
+}
+
+// Get the source HWND of the specified message. Depending on the message, the
+// source HWND is encoded in either the WPARAM or the LPARAM value.
+static HWND GetControlHWNDForMessage(UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ // Each of the following messages can be sent by a child HWND and must be
+ // forwarded to its associated NativeControlWin for handling.
+ switch (message) {
+ case WM_NOTIFY:
+ return reinterpret_cast<NMHDR*>(l_param)->hwndFrom;
+ case WM_COMMAND:
+ return reinterpret_cast<HWND>(l_param);
+ case WM_CONTEXTMENU:
+ return reinterpret_cast<HWND>(w_param);
+ case WM_CTLCOLORBTN:
+ case WM_CTLCOLORSTATIC:
+ return reinterpret_cast<HWND>(l_param);
+ }
+ return NULL;
+}
+
+HICON WidgetWin::GetDefaultWindowIcon() const {
+ if (ViewsDelegate::views_delegate)
+ return ViewsDelegate::views_delegate->GetDefaultWindowIcon();
+ return NULL;
+}
+
+// Some messages may be sent to us by a child HWND. If this is the case, this
+// function will forward those messages on to the object associated with the
+// source HWND and return true, in which case the window procedure must not do
+// any further processing of the message. If there is no associated
+// ChildWindowMessageProcessor, the return value will be false and the WndProc
+// can continue processing the message normally. |l_result| contains the result
+// of the message processing by the control and must be returned by the WndProc
+// if the return value is true.
+static bool ProcessChildWindowMessage(UINT message,
+ WPARAM w_param,
+ LPARAM l_param,
+ LRESULT* l_result) {
+ *l_result = 0;
+
+ HWND control_hwnd = GetControlHWNDForMessage(message, w_param, l_param);
+ if (IsWindow(control_hwnd)) {
+ ChildWindowMessageProcessor* processor =
+ ChildWindowMessageProcessor::Get(control_hwnd);
+ if (processor)
+ return processor->ProcessMessage(message, w_param, l_param, l_result);
+ }
+
+ return false;
+}
+
+LRESULT WidgetWin::OnWndProc(UINT message, WPARAM w_param, LPARAM l_param) {
+ HWND window = hwnd();
+ LRESULT result = 0;
+
+ // First allow messages sent by child controls to be processed directly by
+ // their associated views. If such a view is present, it will handle the
+ // message *instead of* this WidgetWin.
+ if (ProcessChildWindowMessage(message, w_param, l_param, &result))
+ return result;
+
+ // Otherwise we handle everything else.
+ if (!ProcessWindowMessage(window, message, w_param, l_param, result))
+ result = DefWindowProc(window, message, w_param, l_param);
+ if (message == WM_NCDESTROY) {
+ MessageLoopForUI::current()->RemoveObserver(this);
+ OnFinalMessage(window);
+ }
+ if (message == WM_ACTIVATE)
+ PostProcessActivateMessage(this, LOWORD(w_param));
+ if (message == WM_ENABLE && restore_focus_when_enabled_) {
+ restore_focus_when_enabled_ = false;
+ focus_manager_->RestoreFocusedView();
+ }
+ return result;
+}
+
+// static
+void WidgetWin::PostProcessActivateMessage(WidgetWin* widget,
+ int activation_state) {
+ if (!widget->focus_manager_.get()) {
+ NOTREACHED();
+ return;
+ }
+ if (WA_INACTIVE == activation_state) {
+ // We might get activated/inactivated without being enabled, so we need to
+ // clear restore_focus_when_enabled_.
+ widget->restore_focus_when_enabled_ = false;
+ widget->focus_manager_->StoreFocusedView();
+ } else {
+ // We must restore the focus after the message has been DefProc'ed as it
+ // does set the focus to the last focused HWND.
+ // Note that if the window is not enabled, we cannot restore the focus as
+ // calling ::SetFocus on a child of the non-enabled top-window would fail.
+ // This is the case when showing a modal dialog (such as 'open file',
+ // 'print'...) from a different thread.
+ // In that case we delay the focus restoration to when the window is enabled
+ // again.
+ if (!IsWindowEnabled(widget->GetNativeView())) {
+ DCHECK(!widget->restore_focus_when_enabled_);
+ widget->restore_focus_when_enabled_ = true;
+ return;
+ }
+ widget->focus_manager_->RestoreFocusedView();
+ }
+}
+
+void WidgetWin::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;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Widget, public:
+
+// static
+Widget* Widget::CreatePopupWidget(TransparencyParam transparent,
+ EventsParam accept_events,
+ DeleteParam delete_on_destroy,
+ MirroringParam mirror_in_rtl) {
+ WidgetWin* popup = new WidgetWin;
+ DWORD ex_style = WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE;
+ if (mirror_in_rtl == MirrorOriginInRTL)
+ ex_style |= l10n_util::GetExtendedTooltipStyles();
+ if (transparent == Transparent)
+ ex_style |= WS_EX_LAYERED;
+ if (accept_events != AcceptEvents)
+ ex_style |= WS_EX_TRANSPARENT;
+ popup->set_window_style(WS_POPUP);
+ popup->set_window_ex_style(ex_style);
+ popup->set_delete_on_destroy(delete_on_destroy == DeleteOnDestroy);
+ return popup;
+}
+
+static BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM l_param) {
+ RootView* root_view = GetRootViewForHWND(hwnd);
+ if (root_view) {
+ *reinterpret_cast<RootView**>(l_param) = root_view;
+ return FALSE; // Stop enumerating.
+ }
+ return TRUE; // Keep enumerating.
+}
+
+// static
+RootView* Widget::FindRootView(HWND hwnd) {
+ RootView* root_view = GetRootViewForHWND(hwnd);
+ if (root_view)
+ return root_view;
+
+ // Enumerate all children and check if they have a RootView.
+ EnumChildWindows(hwnd, EnumChildProc, reinterpret_cast<LPARAM>(&root_view));
+
+ return root_view;
+}
+
+// Enumerate child windows as they could have RootView distinct from
+// the HWND's root view.
+BOOL CALLBACK EnumAllRootViewsChildProc(HWND hwnd, LPARAM l_param) {
+ RootView* root_view = GetRootViewForHWND(hwnd);
+ if (root_view) {
+ std::set<RootView*>* root_views_set =
+ reinterpret_cast<std::set<RootView*>*>(l_param);
+ root_views_set->insert(root_view);
+ }
+ return TRUE; // Keep enumerating.
+}
+
+void Widget::FindAllRootViews(HWND window,
+ std::vector<RootView*>* root_views) {
+ RootView* root_view = GetRootViewForHWND(window);
+ std::set<RootView*> root_views_set;
+ if (root_view)
+ root_views_set.insert(root_view);
+ // Enumerate all children and check if they have a RootView.
+ EnumChildWindows(window, EnumAllRootViewsChildProc,
+ reinterpret_cast<LPARAM>(&root_views_set));
+ root_views->clear();
+ root_views->reserve(root_views_set.size());
+ for (std::set<RootView*>::iterator it = root_views_set.begin();
+ it != root_views_set.end();
+ ++it)
+ root_views->push_back(*it);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Widget, public:
+
+// static
+Widget* Widget::GetWidgetFromNativeView(gfx::NativeView native_view) {
+ return IsWindow(native_view) ?
+ reinterpret_cast<Widget*>(ViewProp::GetValue(native_view, kWidgetKey)) :
+ NULL;
+}
+
+// static
+Widget* Widget::GetWidgetFromNativeWindow(gfx::NativeWindow native_window) {
+ return Widget::GetWidgetFromNativeView(native_window);
+}
+
+// static
+void Widget::NotifyLocaleChanged() {
+ NOTIMPLEMENTED();
+}
+
+} // namespace views
diff --git a/views/widget/widget_win.h b/views/widget/widget_win.h
new file mode 100644
index 0000000..c93db90
--- /dev/null
+++ b/views/widget/widget_win.h
@@ -0,0 +1,612 @@
+// 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_WIN_H_
+#define VIEWS_WIDGET_WIDGET_WIN_H_
+#pragma once
+
+#include <atlbase.h>
+#include <atlapp.h>
+#include <atlcrack.h>
+#include <atlmisc.h>
+
+#include <string>
+#include <vector>
+
+#include "base/message_loop.h"
+#include "base/scoped_ptr.h"
+#include "base/scoped_vector.h"
+#include "base/win/scoped_comptr.h"
+#include "ui/base/win/window_impl.h"
+#include "views/focus/focus_manager.h"
+#include "views/layout/layout_manager.h"
+#include "views/widget/widget.h"
+
+namespace ui {
+class ViewProp;
+}
+
+namespace gfx {
+class CanvasSkia;
+class Rect;
+}
+
+namespace views {
+
+class DefaultThemeProvider;
+class DropTargetWin;
+class FocusSearch;
+class RootView;
+class TooltipManagerWin;
+class Window;
+
+RootView* GetRootViewForHWND(HWND hwnd);
+
+// A Windows message reflected from other windows. This message is sent
+// with the following arguments:
+// hWnd - Target window
+// uMsg - 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;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// WidgetWin
+// A Widget for a views hierarchy used to represent anything that can be
+// contained within an HWND, e.g. a control, a window, etc. Specializations
+// suitable for specific tasks, e.g. top level window, are derived from this.
+//
+// This Widget contains a RootView which owns the hierarchy of views within it.
+// As long as views are part of this tree, they will be deleted automatically
+// when the RootView is destroyed. If you remove a view from the tree, you are
+// then responsible for cleaning up after it.
+//
+///////////////////////////////////////////////////////////////////////////////
+class WidgetWin : public ui::WindowImpl,
+ public Widget,
+ public MessageLoopForUI::Observer,
+ public FocusTraversable {
+ public:
+ WidgetWin();
+ virtual ~WidgetWin();
+
+ // Returns the Widget associated with the specified HWND (if any).
+ static WidgetWin* GetWidget(HWND hwnd);
+
+ // Returns the root Widget associated with the specified HWND (if any).
+ static WidgetWin* GetRootWidget(HWND hwnd);
+
+ // Returns true if we are on Windows Vista or greater and composition is
+ // enabled.
+ static bool IsAeroGlassEnabled();
+
+ void set_delete_on_destroy(bool delete_on_destroy) {
+ delete_on_destroy_ = delete_on_destroy;
+ }
+
+ // See description of use_layered_buffer_ for details.
+ void SetUseLayeredBuffer(bool use_layered_buffer);
+
+ // Disable Layered Window updates by setting to false.
+ void set_can_update_layered_window(bool can_update_layered_window) {
+ can_update_layered_window_ = can_update_layered_window;
+ }
+
+ // Obtain the view event with the given MSAA child id. Used in
+ // ViewAccessibility::get_accChild to support requests for children of
+ // windowless controls. May return NULL (see ViewHierarchyChanged).
+ View* GetAccessibilityViewEventAt(int id);
+
+ // Add a view that has recently fired an accessibility event. Returns a MSAA
+ // child id which is generated by: -(index of view in vector + 1) which
+ // guarantees a negative child id. This distinguishes the view from
+ // positive MSAA child id's which are direct leaf children of views that have
+ // associated hWnd's (e.g. WidgetWin).
+ int AddAccessibilityViewEvent(View* view);
+
+ // Clear a view that has recently been removed on a hierarchy change.
+ void ClearAccessibilityViewEvent(View* view);
+
+ BEGIN_MSG_MAP_EX(WidgetWin)
+ // Range handlers must go first!
+ MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange)
+ MESSAGE_RANGE_HANDLER_EX(WM_NCMOUSEMOVE, WM_NCMOUSEMOVE, OnMouseRange)
+
+ // 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, OnNCMouseLeave)
+ MESSAGE_HANDLER_EX(WM_MOUSELEAVE, OnMouseLeave)
+ MESSAGE_HANDLER_EX(WM_MOUSEWHEEL, OnMouseWheel)
+
+ // 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_LBUTTONDBLCLK(OnLButtonDblClk)
+ MSG_WM_LBUTTONDOWN(OnLButtonDown)
+ MSG_WM_LBUTTONUP(OnLButtonUp)
+ MSG_WM_MBUTTONDOWN(OnMButtonDown)
+ MSG_WM_MBUTTONUP(OnMButtonUp)
+ MSG_WM_MBUTTONDBLCLK(OnMButtonDblClk)
+ MSG_WM_MOUSEACTIVATE(OnMouseActivate)
+ MSG_WM_MOUSEMOVE(OnMouseMove)
+ MSG_WM_MOVE(OnMove)
+ MSG_WM_MOVING(OnMoving)
+ MSG_WM_NCACTIVATE(OnNCActivate)
+ MSG_WM_NCCALCSIZE(OnNCCalcSize)
+ MSG_WM_NCHITTEST(OnNCHitTest)
+ MSG_WM_NCMOUSEMOVE(OnNCMouseMove)
+ MSG_WM_NCLBUTTONDBLCLK(OnNCLButtonDblClk)
+ MSG_WM_NCLBUTTONDOWN(OnNCLButtonDown)
+ MSG_WM_NCLBUTTONUP(OnNCLButtonUp)
+ MSG_WM_NCMBUTTONDBLCLK(OnNCMButtonDblClk)
+ MSG_WM_NCMBUTTONDOWN(OnNCMButtonDown)
+ MSG_WM_NCMBUTTONUP(OnNCMButtonUp)
+ MSG_WM_NCPAINT(OnNCPaint)
+ MSG_WM_NCRBUTTONDBLCLK(OnNCRButtonDblClk)
+ MSG_WM_NCRBUTTONDOWN(OnNCRButtonDown)
+ MSG_WM_NCRBUTTONUP(OnNCRButtonUp)
+ MSG_WM_NOTIFY(OnNotify)
+ MSG_WM_PAINT(OnPaint)
+ MSG_WM_POWERBROADCAST(OnPowerBroadcast)
+ MSG_WM_RBUTTONDBLCLK(OnRButtonDblClk)
+ MSG_WM_RBUTTONDOWN(OnRButtonDown)
+ MSG_WM_RBUTTONUP(OnRButtonUp)
+ 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()
+
+ // Overridden from Widget:
+ 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 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;
+ virtual bool IsActive() const;
+ virtual bool IsAccessibleWidget() const;
+ virtual TooltipManager* GetTooltipManager();
+ virtual void GenerateMousePressedForView(View* view,
+ const gfx::Point& point);
+ virtual bool GetAccelerator(int cmd_id, ui::Accelerator* accelerator);
+ virtual Window* GetWindow();
+ 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 MessageLoop::Observer:
+ void WillProcessMessage(const MSG& msg);
+ virtual void DidProcessMessage(const MSG& msg);
+
+ // Overridden from FocusTraversable:
+ virtual FocusSearch* GetFocusSearch();
+ virtual FocusTraversable* GetFocusTraversableParent();
+ virtual View* GetFocusTraversableParentView();
+
+ void SetFocusTraversableParent(FocusTraversable* parent);
+ void SetFocusTraversableParentView(View* parent_view);
+
+ BOOL IsWindow() const {
+ return ::IsWindow(GetNativeView());
+ }
+
+ BOOL ShowWindow(int command) {
+ DCHECK(::IsWindow(GetNativeView()));
+ return ::ShowWindow(GetNativeView(), command);
+ }
+
+ HWND SetCapture() {
+ DCHECK(::IsWindow(GetNativeView()));
+ return ::SetCapture(GetNativeView());
+ }
+
+ HWND GetParent() const {
+ return ::GetParent(GetNativeView());
+ }
+
+ LONG GetWindowLong(int index) {
+ DCHECK(::IsWindow(GetNativeView()));
+ return ::GetWindowLong(GetNativeView(), index);
+ }
+
+ BOOL GetWindowRect(RECT* rect) const {
+ return ::GetWindowRect(GetNativeView(), rect);
+ }
+
+ LONG SetWindowLong(int index, LONG new_long) {
+ DCHECK(::IsWindow(GetNativeView()));
+ return ::SetWindowLong(GetNativeView(), index, new_long);
+ }
+
+ BOOL SetWindowPos(HWND hwnd_after, int x, int y, int cx, int cy, UINT flags) {
+ DCHECK(::IsWindow(GetNativeView()));
+ return ::SetWindowPos(GetNativeView(), hwnd_after, x, y, cx, cy, flags);
+ }
+
+ BOOL IsZoomed() const {
+ DCHECK(::IsWindow(GetNativeView()));
+ return ::IsZoomed(GetNativeView());
+ }
+
+ BOOL MoveWindow(int x, int y, int width, int height) {
+ return MoveWindow(x, y, width, height, TRUE);
+ }
+
+ BOOL MoveWindow(int x, int y, int width, int height, BOOL repaint) {
+ DCHECK(::IsWindow(GetNativeView()));
+ return ::MoveWindow(GetNativeView(), x, y, width, height, repaint);
+ }
+
+ int SetWindowRgn(HRGN region, BOOL redraw) {
+ DCHECK(::IsWindow(GetNativeView()));
+ return ::SetWindowRgn(GetNativeView(), region, redraw);
+ }
+
+ BOOL GetClientRect(RECT* rect) const {
+ DCHECK(::IsWindow(GetNativeView()));
+ return ::GetClientRect(GetNativeView(), rect);
+ }
+
+ // Resets the last move flag so that we can go around the optimization
+ // that disregards duplicate mouse moves when ending animation requires
+ // a new hit-test to do some highlighting as in TabStrip::RemoveTabAnimation
+ // to cause the close button to highlight.
+ void ResetLastMouseMoveFlag() {
+ last_mouse_event_was_move_ = false;
+ }
+
+ protected:
+ // Overridden from WindowImpl:
+ virtual HICON GetDefaultWindowIcon() const;
+ virtual LRESULT OnWndProc(UINT message, WPARAM w_param, LPARAM l_param);
+
+ // Message Handlers
+ // These are all virtual so that specialized Widgets can modify or augment
+ // processing.
+ // This list is in _ALPHABETICAL_ order!
+ // Note: in the base class these functions must do nothing but convert point
+ // coordinates to client coordinates (if necessary) and forward the
+ // handling to the appropriate Process* function. This is so that
+ // subclasses can easily override these methods to do different things
+ // and have a convenient function to call to get the default behavior.
+ 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 msg,
+ 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 uMsg, 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 void OnLButtonDblClk(UINT flags, const CPoint& point);
+ virtual void OnLButtonDown(UINT flags, const CPoint& point);
+ virtual void OnLButtonUp(UINT flags, const CPoint& point);
+ virtual void OnMButtonDblClk(UINT flags, const CPoint& point);
+ virtual void OnMButtonDown(UINT flags, const CPoint& point);
+ virtual void OnMButtonUp(UINT flags, const CPoint& point);
+ virtual LRESULT OnMouseActivate(HWND window, UINT hittest_code, UINT message);
+ virtual void OnMouseMove(UINT flags, const CPoint& point);
+ virtual LRESULT OnMouseLeave(UINT message, WPARAM w_param, LPARAM l_param);
+ virtual LRESULT OnMouseWheel(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 msg, WPARAM w_param, LPARAM l_param);
+ virtual LRESULT OnNCActivate(BOOL active);
+ virtual LRESULT OnNCCalcSize(BOOL w_param, LPARAM l_param);
+ virtual LRESULT OnNCHitTest(const CPoint& pt);
+ virtual void OnNCLButtonDblClk(UINT flags, const CPoint& point);
+ virtual void OnNCLButtonDown(UINT flags, const CPoint& point);
+ virtual void OnNCLButtonUp(UINT flags, const CPoint& point);
+ virtual void OnNCMButtonDblClk(UINT flags, const CPoint& point);
+ virtual void OnNCMButtonDown(UINT flags, const CPoint& point);
+ virtual void OnNCMButtonUp(UINT flags, const CPoint& point);
+ virtual LRESULT OnNCMouseLeave(UINT uMsg, WPARAM w_param, LPARAM l_param);
+ virtual LRESULT OnNCMouseMove(UINT flags, const CPoint& point);
+ virtual void OnNCPaint(HRGN rgn);
+ virtual void OnNCRButtonDblClk(UINT flags, const CPoint& point);
+ virtual void OnNCRButtonDown(UINT flags, const CPoint& point);
+ virtual void OnNCRButtonUp(UINT flags, const CPoint& point);
+ virtual LRESULT OnNCUAHDrawCaption(UINT msg,
+ WPARAM w_param,
+ LPARAM l_param);
+ virtual LRESULT OnNCUAHDrawFrame(UINT msg, 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 void OnRButtonDblClk(UINT flags, const CPoint& point);
+ virtual void OnRButtonDown(UINT flags, const CPoint& point);
+ virtual void OnRButtonUp(UINT flags, const CPoint& point);
+ virtual LRESULT OnReflectedMessage(UINT msg, 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);
+
+ // Returns the size that the RootView should be set to in LayoutRootView().
+ virtual gfx::Size GetRootViewSize() const;
+
+ // Start tracking all mouse events so that this window gets sent mouse leave
+ // messages too.
+ void TrackMouseEvents(DWORD mouse_tracking_flags);
+
+ // Actually handle mouse events. These functions are called by subclasses who
+ // override the message handlers above to do the actual real work of handling
+ // the event in the View system.
+ bool ProcessMousePressed(const CPoint& point,
+ UINT flags,
+ bool dbl_click,
+ bool non_client);
+ void ProcessMouseDragged(const CPoint& point, UINT flags);
+ void ProcessMouseReleased(const CPoint& point, UINT flags);
+ void ProcessMouseMoved(const CPoint& point, UINT flags, bool is_nonclient);
+ void ProcessMouseExited();
+
+ // Lays out the root view to fit the appropriate area within the widget.
+ // Called when the window size or non client metrics change.
+ void LayoutRootView();
+
+ // Called when a MSAA screen reader cleint is detected.
+ virtual void OnScreenReaderDetected();
+
+ // Returns whether capture should be released on mouse release. The default
+ // is true.
+ virtual bool ReleaseCaptureOnMouseReleased();
+
+ // Creates the RootView to be used within this Widget. Can be overridden to
+ // create specialized RootView implementations.
+ virtual RootView* CreateRootView();
+
+ // Returns true if this WidgetWin is opaque.
+ bool opaque() const { return opaque_; }
+
+ // The TooltipManager.
+ // WARNING: RootView's destructor calls into the TooltipManager. As such, this
+ // must be destroyed AFTER root_view_.
+ scoped_ptr<TooltipManagerWin> tooltip_manager_;
+
+ scoped_refptr<DropTargetWin> drop_target_;
+
+ // The focus manager keeping track of focus for this Widget and any of its
+ // children. NULL for non top-level widgets.
+ // WARNING: RootView's destructor calls into the FocusManager. As such, this
+ // must be destroyed AFTER root_view_.
+ scoped_ptr<FocusManager> focus_manager_;
+
+ // The root of the View hierarchy attached to this window.
+ // WARNING: see warning in tooltip_manager_ for ordering dependencies with
+ // this and tooltip_manager_.
+ scoped_ptr<RootView> root_view_;
+
+ // Whether or not we have capture the mouse.
+ bool has_capture_;
+
+ // If true, the mouse is currently down.
+ bool is_mouse_down_;
+
+ // Are a subclass of WindowWin?
+ bool is_window_;
+
+ private:
+ typedef ScopedVector<ui::ViewProp> ViewProps;
+
+ // Implementation of GetWindow. Ascends the parents of |hwnd| returning the
+ // first ancestor that is a Window.
+ static Window* GetWindowImpl(HWND hwnd);
+
+ // Resize the bitmap used to contain the contents of the layered window. This
+ // recreates the entire bitmap.
+ void SizeContents(const gfx::Size& window_size);
+
+ // Paint into a DIB and then update the layered window with its contents.
+ void PaintLayeredWindow();
+
+ // In layered mode, update the layered window. |dib_dc| represents a handle
+ // to a device context that contains the contents of the window.
+ void UpdateWindowFromContents(HDC dib_dc);
+
+ // Invoked from WM_DESTROY. Does appropriate cleanup and invokes OnDestroy
+ // so that subclasses can do any cleanup they need to.
+ // void OnDestroyImpl();
+
+ // Returns the RootView that contains the focused view, or NULL if there is no
+ // focused view.
+ RootView* GetFocusedViewRootView();
+
+ // Called after the WM_ACTIVATE message has been processed by the default
+ // windows procedure.
+ static void PostProcessActivateMessage(WidgetWin* widget,
+ int activation_state);
+
+ // Fills out a MSG struct with the supplied values.
+ void MakeMSG(MSG* msg, UINT message, WPARAM w_param, LPARAM l_param) const;
+
+ // The following factory is used for calls to close the WidgetWin
+ // instance.
+ ScopedRunnableMethodFactory<WidgetWin> close_widget_factory_;
+
+ // 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_;
+
+ bool opaque_;
+
+ // Should we keep an offscreen buffer? This is initially true and if the
+ // window has WS_EX_LAYERED then it remains true. You can set this to false
+ // at any time to ditch the buffer, and similarly set back to true to force
+ // creation of the buffer.
+ //
+ // NOTE: this is intended to be used with a layered window (a window with an
+ // extended window style of WS_EX_LAYERED). If you are using a layered window
+ // and NOT changing the layered alpha or anything else, then leave this value
+ // alone. OTOH if you are invoking SetLayeredWindowAttributes then you'll
+ // must likely want to set this to false, or after changing the alpha toggle
+ // the extended style bit to false than back to true. See MSDN for more
+ // details.
+ bool use_layered_buffer_;
+
+ // The default alpha to be applied to the layered window.
+ BYTE layered_alpha_;
+
+ // A canvas that contains the window contents in the case of a layered
+ // window.
+ scoped_ptr<gfx::CanvasSkia> contents_;
+
+ // Whether or not the window should delete itself when it is destroyed.
+ // Set this to false via its setter for stack allocated instances.
+ bool delete_on_destroy_;
+
+ // True if we are allowed to update the layered window from the DIB backing
+ // store if necessary.
+ bool can_update_layered_window_;
+
+ // 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.
+
+ // If true, the last event was a mouse move event.
+ bool last_mouse_event_was_move_;
+
+ // Coordinates of the last mouse move event, in screen coordinates.
+ int last_mouse_move_x_;
+ int last_mouse_move_y_;
+
+ // Whether the focus should be restored next time we get enabled. Needed to
+ // restore focus correctly when Windows modal dialogs are displayed.
+ bool restore_focus_when_enabled_;
+
+ // Instance of accessibility information and handling for MSAA root
+ base::win::ScopedComPtr<IAccessible> accessibility_root_;
+
+ scoped_ptr<DefaultThemeProvider> default_theme_provider_;
+
+ // Non owned pointer to optional delegate. May be NULL if no delegate is
+ // being used.
+ WidgetDelegate* delegate_;
+
+ // Value determines whether the Widget is customized for accessibility.
+ static bool screen_reader_active_;
+
+ // The maximum number of view events in our vector below.
+ static const int kMaxAccessibilityViewEvents = 20;
+
+ // A vector used to access views for which we have sent notifications to
+ // accessibility clients. It is used as a circular queue.
+ std::vector<View*> accessibility_view_events_;
+
+ // The current position of the view events vector. When incrementing,
+ // we always mod this value with the max view events above .
+ int accessibility_view_events_index_;
+
+ ViewProps props_;
+
+ DISALLOW_COPY_AND_ASSIGN(WidgetWin);
+};
+
+} // namespace views
+
+#endif // VIEWS_WIDGET_WIDGET_WIN_H_
diff --git a/views/widget/widget_win_unittest.cc b/views/widget/widget_win_unittest.cc
new file mode 100644
index 0000000..d0cb4e4
--- /dev/null
+++ b/views/widget/widget_win_unittest.cc
@@ -0,0 +1,82 @@
+// 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_win.h"
+
+#include "base/basictypes.h"
+#include "base/message_loop.h"
+#include "base/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using namespace views;
+
+class WidgetWinTest : public testing::Test {
+ public:
+ WidgetWinTest() {
+ OleInitialize(NULL);
+ }
+
+ ~WidgetWinTest() {
+ OleUninitialize();
+ }
+
+ virtual void TearDown() {
+ // Flush the message loop because we have pending release tasks
+ // and these tasks if un-executed would upset Valgrind.
+ RunPendingMessages();
+ }
+
+ // Create a simple widget win. The caller is responsible for taking ownership
+ // of the returned value.
+ WidgetWin* CreateWidgetWin();
+
+ void RunPendingMessages() {
+ message_loop_.RunAllPending();
+ }
+
+ private:
+ MessageLoopForUI message_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(WidgetWinTest);
+};
+
+
+WidgetWin* WidgetWinTest::CreateWidgetWin() {
+ scoped_ptr<WidgetWin> window(new WidgetWin());
+ window->set_delete_on_destroy(false);
+ window->set_window_style(WS_OVERLAPPEDWINDOW);
+ window->Init(NULL, gfx::Rect(50, 50, 650, 650));
+ return window.release();
+}
+
+TEST_F(WidgetWinTest, ZoomWindow) {
+ scoped_ptr<WidgetWin> window(CreateWidgetWin());
+ window->ShowWindow(SW_HIDE);
+ EXPECT_FALSE(window->IsActive());
+ window->ShowWindow(SW_MAXIMIZE);
+ EXPECT_TRUE(window->IsZoomed());
+ window->CloseNow();
+}
+
+TEST_F(WidgetWinTest, SetBoundsForZoomedWindow) {
+ scoped_ptr<WidgetWin> window(CreateWidgetWin());
+ window->ShowWindow(SW_MAXIMIZE);
+ EXPECT_TRUE(window->IsZoomed());
+
+ // Create another window, so that it will be active.
+ scoped_ptr<WidgetWin> window2(CreateWidgetWin());
+ window2->ShowWindow(SW_MAXIMIZE);
+ EXPECT_TRUE(window2->IsActive());
+ EXPECT_FALSE(window->IsActive());
+
+ // Verify that setting the bounds of a zoomed window will unzoom it and not
+ // cause it to be activated.
+ window->SetBounds(gfx::Rect(50, 50, 650, 650));
+ EXPECT_FALSE(window->IsZoomed());
+ EXPECT_FALSE(window->IsActive());
+
+ // Cleanup.
+ window->CloseNow();
+ window2->CloseNow();
+}