| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #include "ui/views/controls/native_control_win.h" | |
| 6 | |
| 7 #include <windowsx.h> | |
| 8 | |
| 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" | |
| 17 | |
| 18 using ui::ViewProp; | |
| 19 | |
| 20 const char kNativeControlWinKey[] = "__NATIVE_CONTROL_WIN__"; | |
| 21 | |
| 22 namespace views { | |
| 23 | |
| 24 //////////////////////////////////////////////////////////////////////////////// | |
| 25 // NativeControlWin, public: | |
| 26 | |
| 27 NativeControlWin::NativeControlWin() : original_wndproc_(NULL) { | |
| 28 } | |
| 29 | |
| 30 NativeControlWin::~NativeControlWin() { | |
| 31 HWND hwnd = native_view(); | |
| 32 if (hwnd) { | |
| 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. | |
| 36 Detach(); | |
| 37 DestroyWindow(hwnd); | |
| 38 } | |
| 39 } | |
| 40 | |
| 41 bool NativeControlWin::ProcessMessage(UINT message, | |
| 42 WPARAM w_param, | |
| 43 LPARAM l_param, | |
| 44 LRESULT* result) { | |
| 45 switch (message) { | |
| 46 case WM_CONTEXTMENU: | |
| 47 ShowContextMenu(gfx::Point(GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param))); | |
| 48 *result = 0; | |
| 49 return true; | |
| 50 case WM_CTLCOLORBTN: | |
| 51 case WM_CTLCOLORSTATIC: | |
| 52 *result = GetControlColor(message, reinterpret_cast<HDC>(w_param), | |
| 53 native_view()); | |
| 54 return true; | |
| 55 } | |
| 56 return false; | |
| 57 } | |
| 58 | |
| 59 //////////////////////////////////////////////////////////////////////////////// | |
| 60 // NativeControlWin, View overrides: | |
| 61 | |
| 62 void NativeControlWin::OnEnabledChanged() { | |
| 63 View::OnEnabledChanged(); | |
| 64 if (native_view()) | |
| 65 EnableWindow(native_view(), enabled()); | |
| 66 } | |
| 67 | |
| 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); | |
| 72 | |
| 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(); | |
| 77 } | |
| 78 | |
| 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(); | |
| 87 Detach(); | |
| 88 DestroyWindow(hwnd); | |
| 89 } else if (is_drawn && !native_view()) { | |
| 90 if (GetWidget()) | |
| 91 CreateNativeControl(); | |
| 92 } | |
| 93 if (is_drawn) { | |
| 94 // The view becomes visible after native control is created. | |
| 95 // Layout now. | |
| 96 Layout(); | |
| 97 } | |
| 98 } | |
| 99 | |
| 100 void NativeControlWin::OnFocus() { | |
| 101 DCHECK(native_view()); | |
| 102 SetFocus(native_view()); | |
| 103 | |
| 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(); | |
| 107 | |
| 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(); | |
| 114 | |
| 115 // Send the accessibility focus notification. | |
| 116 parent_view->NotifyAccessibilityEvent( | |
| 117 ui::AccessibilityTypes::EVENT_FOCUS, send_native_event); | |
| 118 } | |
| 119 | |
| 120 //////////////////////////////////////////////////////////////////////////////// | |
| 121 // NativeControlWin, protected: | |
| 122 | |
| 123 void NativeControlWin::ShowContextMenu(const gfx::Point& location) { | |
| 124 if (!context_menu_controller()) | |
| 125 return; | |
| 126 | |
| 127 if (location.x() == -1 && location.y() == -1) { | |
| 128 View::ShowContextMenu(GetKeyboardContextMenuLocation(), | |
| 129 ui::MENU_SOURCE_KEYBOARD); | |
| 130 } else { | |
| 131 View::ShowContextMenu(location, ui::MENU_SOURCE_MOUSE); | |
| 132 } | |
| 133 } | |
| 134 | |
| 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)); | |
| 140 | |
| 141 // Subclass so we get WM_KEYDOWN and WM_SETFOCUS messages. | |
| 142 original_wndproc_ = gfx::SetWindowProc( | |
| 143 native_control, &NativeControlWin::NativeControlWndProc); | |
| 144 | |
| 145 Attach(native_control); | |
| 146 // native_view() is now valid. | |
| 147 | |
| 148 // Update the newly created HWND with any resident enabled state. | |
| 149 EnableWindow(native_view(), enabled()); | |
| 150 | |
| 151 // This message ensures that the focus border is shown. | |
| 152 SendMessage(native_view(), WM_CHANGEUISTATE, | |
| 153 MAKEWPARAM(UIS_CLEAR, UISF_HIDEFOCUS), 0); | |
| 154 } | |
| 155 | |
| 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. | |
| 160 DWORD ex_style = 0; | |
| 161 if (base::i18n::IsRTL()) | |
| 162 ex_style |= l10n_util::GetExtendedStyles(); | |
| 163 | |
| 164 return ex_style; | |
| 165 } | |
| 166 | |
| 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. | |
| 171 DWORD ex_style = 0; | |
| 172 if (base::i18n::IsRTL()) | |
| 173 ex_style |= l10n_util::GetExtendedTooltipStyles(); | |
| 174 | |
| 175 return ex_style; | |
| 176 } | |
| 177 | |
| 178 //////////////////////////////////////////////////////////////////////////////// | |
| 179 // NativeControlWin, private: | |
| 180 | |
| 181 LRESULT NativeControlWin::GetControlColor(UINT message, HDC dc, HWND sender) { | |
| 182 View *ancestor = this; | |
| 183 while (ancestor) { | |
| 184 const Background* background = ancestor->background(); | |
| 185 if (background) { | |
| 186 HBRUSH brush = background->GetNativeControlBrush(); | |
| 187 if (brush) | |
| 188 return reinterpret_cast<LRESULT>(brush); | |
| 189 } | |
| 190 ancestor = ancestor->parent(); | |
| 191 } | |
| 192 | |
| 193 // COLOR_BTNFACE is the default for dialog box backgrounds. | |
| 194 return reinterpret_cast<LRESULT>(GetSysColorBrush(COLOR_BTNFACE)); | |
| 195 } | |
| 196 | |
| 197 // static | |
| 198 LRESULT NativeControlWin::NativeControlWndProc(HWND window, | |
| 199 UINT message, | |
| 200 WPARAM w_param, | |
| 201 LPARAM l_param) { | |
| 202 NativeControlWin* native_control = reinterpret_cast<NativeControlWin*>( | |
| 203 ViewProp::GetValue(window, kNativeControlWinKey)); | |
| 204 DCHECK(native_control); | |
| 205 | |
| 206 if (message == WM_KEYDOWN && | |
| 207 native_control->OnKeyDown(static_cast<int>(w_param))) { | |
| 208 return 0; | |
| 209 } else if (message == WM_SETFOCUS) { | |
| 210 // Let the focus manager know that the focus changed. | |
| 211 FocusManager* focus_manager = native_control->GetFocusManager(); | |
| 212 if (focus_manager) { | |
| 213 focus_manager->SetFocusedView(native_control->focus_view()); | |
| 214 } else { | |
| 215 NOTREACHED(); | |
| 216 } | |
| 217 } else if (message == WM_DESTROY) { | |
| 218 native_control->props_.clear(); | |
| 219 gfx::SetWindowProc(window, native_control->original_wndproc_); | |
| 220 } | |
| 221 | |
| 222 return CallWindowProc(native_control->original_wndproc_, window, message, | |
| 223 w_param, l_param); | |
| 224 } | |
| 225 | |
| 226 } // namespace views | |
| OLD | NEW |