summaryrefslogtreecommitdiffstats
path: root/views/controls/native_control_win.cc
diff options
context:
space:
mode:
Diffstat (limited to 'views/controls/native_control_win.cc')
-rw-r--r--views/controls/native_control_win.cc201
1 files changed, 201 insertions, 0 deletions
diff --git a/views/controls/native_control_win.cc b/views/controls/native_control_win.cc
new file mode 100644
index 0000000..0c1baf8
--- /dev/null
+++ b/views/controls/native_control_win.cc
@@ -0,0 +1,201 @@
+// Copyright (c) 2009 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/controls/native_control_win.h"
+
+#include "app/l10n_util_win.h"
+#include "base/logging.h"
+#include "base/win_util.h"
+
+namespace views {
+
+// static
+const wchar_t* NativeControlWin::kNativeControlWinKey =
+ L"__NATIVE_CONTROL_WIN__";
+
+static const wchar_t* kNativeControlOriginalWndProcKey =
+ L"__NATIVE_CONTROL_ORIGINAL_WNDPROC__";
+
+// static
+WNDPROC NativeControlWin::original_wndproc_ = NULL;
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeControlWin, public:
+
+NativeControlWin::NativeControlWin() : HWNDView() {
+}
+
+NativeControlWin::~NativeControlWin() {
+ HWND hwnd = GetHWND();
+ if (hwnd) {
+ // Destroy the hwnd if it still exists. Otherwise we won't have shut things
+ // down correctly, leading to leaking and crashing if another message
+ // comes in for the hwnd.
+ Detach();
+ DestroyWindow(hwnd);
+ }
+}
+
+bool NativeControlWin::ProcessMessage(UINT message, WPARAM w_param,
+ LPARAM l_param, LRESULT* result) {
+ switch (message) {
+ case WM_CONTEXTMENU:
+ ShowContextMenu(gfx::Point(LOWORD(l_param), HIWORD(l_param)));
+ *result = 0;
+ return true;
+ case WM_CTLCOLORBTN:
+ case WM_CTLCOLORSTATIC:
+ *result = GetControlColor(message, reinterpret_cast<HDC>(w_param),
+ GetHWND());
+ return true;
+ }
+ return false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeControlWin, View overrides:
+
+void NativeControlWin::SetEnabled(bool enabled) {
+ if (IsEnabled() != enabled) {
+ View::SetEnabled(enabled);
+ if (GetHWND())
+ EnableWindow(GetHWND(), IsEnabled());
+ }
+}
+
+void NativeControlWin::ViewHierarchyChanged(bool is_add, View* parent,
+ View* child) {
+ // Create the HWND when we're added to a valid Widget. Many controls need a
+ // parent HWND to function properly.
+ if (is_add && GetWidget() && !GetHWND())
+ CreateNativeControl();
+
+ // Call the base class to hide the view if we're being removed.
+ HWNDView::ViewHierarchyChanged(is_add, parent, child);
+}
+
+void NativeControlWin::VisibilityChanged(View* starting_from, bool is_visible) {
+ if (!is_visible) {
+ // We destroy the child control HWND when we become invisible because of the
+ // performance cost of maintaining many HWNDs.
+ HWND hwnd = GetHWND();
+ Detach();
+ DestroyWindow(hwnd);
+ } else if (!GetHWND()) {
+ CreateNativeControl();
+ }
+}
+
+void NativeControlWin::Focus() {
+ DCHECK(GetHWND());
+ SetFocus(GetHWND());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeControlWin, protected:
+
+void NativeControlWin::ShowContextMenu(const gfx::Point& location) {
+ if (!GetContextMenuController())
+ return;
+
+ int x = location.x();
+ int y = location.y();
+ bool is_mouse = true;
+ if (x == -1 && y == -1) {
+ gfx::Point point = GetKeyboardContextMenuLocation();
+ x = point.x();
+ y = point.y();
+ is_mouse = false;
+ }
+ View::ShowContextMenu(x, y, is_mouse);
+}
+
+void NativeControlWin::NativeControlCreated(HWND native_control) {
+ TRACK_HWND_CREATION(native_control);
+
+ // Associate this object with the control's HWND so that WidgetWin can find
+ // this object when it receives messages from it.
+ SetProp(native_control, kNativeControlWinKey, this);
+
+ // Subclass the window so we can monitor for key presses.
+ original_wndproc_ =
+ win_util::SetWindowProc(native_control,
+ &NativeControlWin::NativeControlWndProc);
+ SetProp(native_control, kNativeControlOriginalWndProcKey, original_wndproc_);
+
+ Attach(native_control);
+ // GetHWND() is now valid.
+
+ // Update the newly created HWND with any resident enabled state.
+ EnableWindow(GetHWND(), IsEnabled());
+
+ // This message ensures that the focus border is shown.
+ SendMessage(GetHWND(), WM_CHANGEUISTATE,
+ MAKEWPARAM(UIS_CLEAR, UISF_HIDEFOCUS), 0);
+}
+
+DWORD NativeControlWin::GetAdditionalExStyle() const {
+ // If the UI for the view is mirrored, we should make sure we add the
+ // extended window style for a right-to-left layout so the subclass creates
+ // a mirrored HWND for the underlying control.
+ DWORD ex_style = 0;
+ if (UILayoutIsRightToLeft())
+ ex_style |= l10n_util::GetExtendedStyles();
+
+ return ex_style;
+}
+
+DWORD NativeControlWin::GetAdditionalRTLStyle() const {
+ // If the UI for the view is mirrored, we should make sure we add the
+ // extended window style for a right-to-left layout so the subclass creates
+ // a mirrored HWND for the underlying control.
+ DWORD ex_style = 0;
+ if (UILayoutIsRightToLeft())
+ ex_style |= l10n_util::GetExtendedTooltipStyles();
+
+ return ex_style;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeControlWin, private:
+
+LRESULT NativeControlWin::GetControlColor(UINT message, HDC dc, HWND sender) {
+ View *ancestor = this;
+ while (ancestor) {
+ const Background* background = ancestor->background();
+ if (background) {
+ HBRUSH brush = background->GetNativeControlBrush();
+ if (brush)
+ return reinterpret_cast<LRESULT>(brush);
+ }
+ ancestor = ancestor->GetParent();
+ }
+
+ // COLOR_BTNFACE is the default for dialog box backgrounds.
+ return reinterpret_cast<LRESULT>(GetSysColorBrush(COLOR_BTNFACE));
+}
+
+// static
+LRESULT NativeControlWin::NativeControlWndProc(HWND window,
+ UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ NativeControlWin* native_control =
+ static_cast<NativeControlWin*>(GetProp(window, kNativeControlWinKey));
+ DCHECK(native_control);
+
+ if (message == WM_KEYDOWN && native_control->NotifyOnKeyDown()) {
+ if (native_control->OnKeyDown(static_cast<int>(w_param)))
+ return 0;
+ } else if (message == WM_DESTROY) {
+ win_util::SetWindowProc(window, native_control->original_wndproc_);
+ RemoveProp(window, kNativeControlWinKey);
+ TRACK_HWND_DESTRUCTION(window);
+ }
+
+ return CallWindowProc(native_control->original_wndproc_, window, message,
+ w_param, l_param);
+}
+
+} // namespace views