- add sources.
[platform/framework/web/crosswalk.git] / src / ui / views / controls / native_control_win.cc
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