1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/views/controls/native_control_win.h"
9 #include "base/logging.h"
10 #include "ui/base/accessibility/accessibility_types.h"
11 #include "ui/base/l10n/l10n_util_win.h"
12 #include "ui/base/view_prop.h"
13 #include "ui/gfx/win/hwnd_util.h"
14 #include "ui/views/controls/combobox/combobox.h"
15 #include "ui/views/focus/focus_manager.h"
16 #include "ui/views/widget/widget.h"
20 const char kNativeControlWinKey[] = "__NATIVE_CONTROL_WIN__";
24 ////////////////////////////////////////////////////////////////////////////////
25 // NativeControlWin, public:
27 NativeControlWin::NativeControlWin() : original_wndproc_(NULL) {
30 NativeControlWin::~NativeControlWin() {
31 HWND hwnd = native_view();
33 // Destroy the hwnd if it still exists. Otherwise we won't have shut things
34 // down correctly, leading to leaking and crashing if another message
35 // comes in for the hwnd.
41 bool NativeControlWin::ProcessMessage(UINT message,
47 ShowContextMenu(gfx::Point(GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param)));
51 case WM_CTLCOLORSTATIC:
52 *result = GetControlColor(message, reinterpret_cast<HDC>(w_param),
59 ////////////////////////////////////////////////////////////////////////////////
60 // NativeControlWin, View overrides:
62 void NativeControlWin::OnEnabledChanged() {
63 View::OnEnabledChanged();
65 EnableWindow(native_view(), enabled());
68 void NativeControlWin::ViewHierarchyChanged(
69 const ViewHierarchyChangedDetails& details) {
70 // Call the base class to hide the view if we're being removed.
71 NativeViewHost::ViewHierarchyChanged(details);
73 // Create the HWND when we're added to a valid Widget. Many controls need a
74 // parent HWND to function properly.
75 if (details.is_add && GetWidget() && !native_view())
76 CreateNativeControl();
79 void NativeControlWin::VisibilityChanged(View* starting_from, bool is_visible) {
80 // We might get called due to visibility changes at any point in the
81 // hierarchy, lets check whether we are really visible or not.
82 bool is_drawn = IsDrawn();
83 if (!is_drawn && native_view()) {
84 // We destroy the child control HWND when we become invisible because of the
85 // performance cost of maintaining many HWNDs.
86 HWND hwnd = native_view();
89 } else if (is_drawn && !native_view()) {
91 CreateNativeControl();
94 // The view becomes visible after native control is created.
100 void NativeControlWin::OnFocus() {
101 DCHECK(native_view());
102 SetFocus(native_view());
104 // Since we are being wrapped by a view, accessibility should receive
105 // the super class as the focused view.
106 View* parent_view = parent();
108 // Due to some controls not behaving as expected without having
109 // a native win32 control, we don't always send a native (MSAA)
110 // focus notification.
111 bool send_native_event =
112 strcmp(parent_view->GetClassName(), Combobox::kViewClassName) &&
113 parent_view->HasFocus();
115 // Send the accessibility focus notification.
116 parent_view->NotifyAccessibilityEvent(
117 ui::AccessibilityTypes::EVENT_FOCUS, send_native_event);
120 ////////////////////////////////////////////////////////////////////////////////
121 // NativeControlWin, protected:
123 void NativeControlWin::ShowContextMenu(const gfx::Point& location) {
124 if (!context_menu_controller())
127 if (location.x() == -1 && location.y() == -1) {
128 View::ShowContextMenu(GetKeyboardContextMenuLocation(),
129 ui::MENU_SOURCE_KEYBOARD);
131 View::ShowContextMenu(location, ui::MENU_SOURCE_MOUSE);
135 void NativeControlWin::NativeControlCreated(HWND native_control) {
136 // Associate this object with the control's HWND so that NativeWidgetWin can
137 // find this object when it receives messages from it.
138 props_.push_back(new ViewProp(native_control, kNativeControlWinKey, this));
139 props_.push_back(ChildWindowMessageProcessor::Register(native_control, this));
141 // Subclass so we get WM_KEYDOWN and WM_SETFOCUS messages.
142 original_wndproc_ = gfx::SetWindowProc(
143 native_control, &NativeControlWin::NativeControlWndProc);
145 Attach(native_control);
146 // native_view() is now valid.
148 // Update the newly created HWND with any resident enabled state.
149 EnableWindow(native_view(), enabled());
151 // This message ensures that the focus border is shown.
152 SendMessage(native_view(), WM_CHANGEUISTATE,
153 MAKEWPARAM(UIS_CLEAR, UISF_HIDEFOCUS), 0);
156 DWORD NativeControlWin::GetAdditionalExStyle() const {
157 // If the UI for the view is mirrored, we should make sure we add the
158 // extended window style for a right-to-left layout so the subclass creates
159 // a mirrored HWND for the underlying control.
161 if (base::i18n::IsRTL())
162 ex_style |= l10n_util::GetExtendedStyles();
167 DWORD NativeControlWin::GetAdditionalRTLStyle() const {
168 // If the UI for the view is mirrored, we should make sure we add the
169 // extended window style for a right-to-left layout so the subclass creates
170 // a mirrored HWND for the underlying control.
172 if (base::i18n::IsRTL())
173 ex_style |= l10n_util::GetExtendedTooltipStyles();
178 ////////////////////////////////////////////////////////////////////////////////
179 // NativeControlWin, private:
181 LRESULT NativeControlWin::GetControlColor(UINT message, HDC dc, HWND sender) {
182 View *ancestor = this;
184 const Background* background = ancestor->background();
186 HBRUSH brush = background->GetNativeControlBrush();
188 return reinterpret_cast<LRESULT>(brush);
190 ancestor = ancestor->parent();
193 // COLOR_BTNFACE is the default for dialog box backgrounds.
194 return reinterpret_cast<LRESULT>(GetSysColorBrush(COLOR_BTNFACE));
198 LRESULT NativeControlWin::NativeControlWndProc(HWND window,
202 NativeControlWin* native_control = reinterpret_cast<NativeControlWin*>(
203 ViewProp::GetValue(window, kNativeControlWinKey));
204 DCHECK(native_control);
206 if (message == WM_KEYDOWN &&
207 native_control->OnKeyDown(static_cast<int>(w_param))) {
209 } else if (message == WM_SETFOCUS) {
210 // Let the focus manager know that the focus changed.
211 FocusManager* focus_manager = native_control->GetFocusManager();
213 focus_manager->SetFocusedView(native_control->focus_view());
217 } else if (message == WM_DESTROY) {
218 native_control->props_.clear();
219 gfx::SetWindowProc(window, native_control->original_wndproc_);
222 return CallWindowProc(native_control->original_wndproc_, window, message,