summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-18 20:40:34 +0000
committerben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-18 20:40:34 +0000
commit420949ff13d309c7bbc56173bca33ee4ffafd1b3 (patch)
tree58b0c60202bddd3e034882a13f2bfe8e61be42b6 /chrome
parent33f8e3dfcc9c04c4aaa19757d8994161b650e040 (diff)
downloadchromium_src-420949ff13d309c7bbc56173bca33ee4ffafd1b3.zip
chromium_src-420949ff13d309c7bbc56173bca33ee4ffafd1b3.tar.gz
chromium_src-420949ff13d309c7bbc56173bca33ee4ffafd1b3.tar.bz2
New native control helpers. Built but not run by anyone just yet. See design doc
http://dev.chromium.org/developers/design-documents/native-controls Review URL: http://codereview.chromium.org/48094 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@12008 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/views/controls/button/native_button_win.cc264
-rw-r--r--chrome/views/controls/button/native_button_win.h111
-rw-r--r--chrome/views/controls/button/native_button_wrapper.h69
-rw-r--r--chrome/views/controls/native_control_win.cc175
-rw-r--r--chrome/views/controls/native_control_win.h94
-rw-r--r--chrome/views/views.vcproj20
-rw-r--r--chrome/views/widget/widget_win.cc61
7 files changed, 794 insertions, 0 deletions
diff --git a/chrome/views/controls/button/native_button_win.cc b/chrome/views/controls/button/native_button_win.cc
new file mode 100644
index 0000000..35472cd
--- /dev/null
+++ b/chrome/views/controls/button/native_button_win.cc
@@ -0,0 +1,264 @@
+// 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 "chrome/views/controls/button/native_button_win.h"
+
+#include "chrome/common/l10n_util.h"
+#include "chrome/views/widget/widget.h"
+
+namespace views {
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeButtonWin, public:
+
+NativeButtonWin::NativeButtonWin(NativeButtonWrapperListener* listener)
+ : NativeControlWin(),
+ listener_(listener),
+ is_default_(false),
+ ignore_minimum_size_(false),
+ min_dlu_size_(50, 14) {
+ // The min size in DLUs comes from
+ // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwue/html/ch14e.asp
+}
+
+NativeButtonWin::~NativeButtonWin() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeButtonWin, NativeButtonWrapper implementation:
+
+void NativeButtonWin::SetLabel(const std::wstring& label) {
+ label_ = label;
+
+ // Even though we create a flipped HWND for a native button when the locale
+ // is right-to-left, Windows does not render text for the button using a
+ // right-to-left context (perhaps because the parent HWND is not flipped).
+ // The result is that RTL strings containing punctuation marks are not
+ // displayed properly. For example, the string "...ABC" (where A, B and C are
+ // Hebrew characters) is displayed as "ABC..." which is incorrect.
+ //
+ // In order to overcome this problem, we mark the localized Hebrew strings as
+ // RTL strings explicitly (using the appropriate Unicode formatting) so that
+ // Windows displays the text correctly regardless of the HWND hierarchy.
+ std::wstring localized_label;
+ if (l10n_util::AdjustStringForLocaleDirection(label_, &localized_label))
+ label_ = localized_label;
+
+ // SetLabel can be called before the view is attached to a view hierarchy, so
+ // we check the HWND before attempting to do anything with it.
+ if (IsWindow(GetHWND()))
+ SetWindowText(GetHWND(), label_.c_str());
+}
+
+std::wstring NativeButtonWin::GetLabel() const {
+ return label_;
+}
+
+void NativeButtonWin::SetFont(const ChromeFont& font) {
+ font_ = font;
+}
+
+void NativeButtonWin::SetDefaultButton(bool is_default) {
+ if (is_default == is_default_)
+ return;
+ is_default_ = is_default;
+
+ // SetDefaultButton can be called before the view is attached to a view
+ // hierarchy, so we check the HWND before attempting to modify its style.
+ if (IsWindow(GetHWND())) {
+ SendMessage(GetHWND(), BM_SETSTYLE,
+ is_default_ ? BS_DEFPUSHBUTTON : BS_PUSHBUTTON, true);
+ }
+}
+
+bool NativeButtonWin::IsDefaultButton() const {
+ return is_default_;
+}
+
+void NativeButtonWin::SetMinimumSizeInPlatformUnits(
+ const gfx::Size& minimum_size) {
+ min_dlu_size_ = minimum_size;
+}
+
+void NativeButtonWin::SetIgnoreMinimumSize(bool ignore_minimum_size) {
+ ignore_minimum_size_ = ignore_minimum_size;
+}
+
+View* NativeButtonWin::GetView() {
+ return this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeButtonWin, View overrides:
+
+gfx::Size NativeButtonWin::GetPreferredSize() {
+ if (!GetHWND())
+ return gfx::Size();
+
+ SIZE sz = {0};
+ SendMessage(GetHWND(), BCM_GETIDEALSIZE, 0, reinterpret_cast<LPARAM>(&sz));
+
+ if (!ignore_minimum_size_) {
+ if (min_dlu_size_.width()) {
+ sz.cx = std::max(static_cast<int>(sz.cx),
+ font_.horizontal_dlus_to_pixels(min_dlu_size_.width()));
+ }
+ if (min_dlu_size_.height()) {
+ sz.cy = std::max(static_cast<int>(sz.cy),
+ font_.vertical_dlus_to_pixels(min_dlu_size_.height()));
+ }
+ }
+ return gfx::Size(sz.cx, sz.cy);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeButtonWin, NativeControlWin overrides:
+
+LRESULT NativeButtonWin::ProcessMessage(UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ if (message == WM_COMMAND && HIWORD(w_param) == BN_CLICKED) {
+ listener_->ButtonPressed();
+ return 0;
+ }
+ return NativeControlWin::ProcessMessage(message, w_param, l_param);
+}
+
+bool NativeButtonWin::OnKeyDown(int vkey) {
+ bool enter_pressed = vkey == VK_RETURN;
+ if (enter_pressed)
+ listener_->ButtonPressed();
+ return enter_pressed;
+}
+
+bool NativeButtonWin::NotifyOnKeyDown() const {
+ return true;
+}
+
+void NativeButtonWin::CreateNativeControl() {
+ DWORD flags = WS_CHILD | BS_PUSHBUTTON;
+ if (is_default_)
+ flags |= BS_DEFPUSHBUTTON;
+ HWND control_hwnd = CreateWindowEx(GetAdditionalExStyle(), L"BUTTON", L"",
+ flags, 0, 0, width(), height(),
+ GetWidget()->GetNativeView(), NULL, NULL,
+ NULL);
+ NativeControlCreated(control_hwnd);
+}
+
+void NativeButtonWin::NativeControlCreated(HWND control_hwnd) {
+ NativeControlWin::NativeControlCreated(control_hwnd);
+
+ SendMessage(control_hwnd, WM_SETFONT, reinterpret_cast<WPARAM>(font_.hfont()),
+ FALSE);
+ SetLabel(GetLabel());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeCheckboxWin, public:
+
+NativeCheckboxWin::NativeCheckboxWin(NativeButtonWrapperListener* listener)
+ : NativeButtonWin(listener),
+ selected_(false) {
+}
+
+NativeCheckboxWin::~NativeCheckboxWin() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeCheckboxWin, NativeButtonWrapper implementation:
+
+void NativeCheckboxWin::SetSelected(bool selected) {
+ if (selected == selected_)
+ return;
+
+ selected_ = selected;
+ if (GetHWND()) {
+ SendMessage(GetHWND(), BM_SETCHECK, selected ? BST_CHECKED : BST_UNCHECKED,
+ 0);
+ }
+}
+
+bool NativeCheckboxWin::IsSelected() const {
+ return selected_;
+}
+
+void NativeCheckboxWin::SetHighlight(bool highlight) {
+ SendMessage(GetHWND(), BM_SETSTATE, highlight, 0);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeCheckboxWin, NativeButtonWin overrides:
+
+LRESULT NativeCheckboxWin::ProcessMessage(UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ if (message == WM_COMMAND && HIWORD(w_param) == BN_CLICKED) {
+ SetSelected(!IsSelected());
+ // Fall through to the NativeButtonWin's handler, which will send the
+ // clicked notification to the listener...
+ }
+ return NativeButtonWin::ProcessMessage(message, w_param, l_param);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeCheckboxWin, protected:
+
+void NativeCheckboxWin::CreateNativeControl() {
+ HWND control_hwnd = CreateWindowEx(WS_EX_TRANSPARENT | GetAdditionalExStyle(),
+ L"BUTTON", L"",
+ WS_CHILD | BS_CHECKBOX | WS_VISIBLE,
+ 0, 0, width(), height(),
+ GetWidget()->GetNativeView(), NULL, NULL,
+ NULL);
+ NativeControlCreated(control_hwnd);
+}
+
+void NativeCheckboxWin::NativeControlCreated(HWND control_hwnd) {
+ NativeButtonWin::NativeControlCreated(control_hwnd);
+ SetSelected(IsSelected());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeRadioButtonWin, public:
+
+NativeRadioButtonWin::NativeRadioButtonWin(
+ NativeButtonWrapperListener* listener)
+ : NativeCheckboxWin(listener) {
+}
+
+NativeRadioButtonWin::~NativeRadioButtonWin() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeRaidoButotnWin, NativeCheckboxWin overrides:
+
+void NativeRadioButtonWin::CreateNativeControl() {
+ HWND control_hwnd = CreateWindowEx(GetAdditionalExStyle(), L"BUTTON",
+ L"", WS_CHILD | BS_RADIOBUTTON,
+ 0, 0, width(), height(),
+ GetWidget()->GetNativeView(), NULL, NULL,
+ NULL);
+ NativeControlCreated(control_hwnd);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeButtonWrapper, public:
+
+// static
+NativeButtonWrapper* NativeButtonWrapper::CreateNativeButtonWrapper(
+ NativeButtonWrapperListener* listener, Type type) {
+ switch (type) {
+ case TYPE_BUTTON:
+ return new NativeButtonWin(listener);
+ case TYPE_CHECKBOX:
+ return new NativeCheckboxWin(listener);
+ case TYPE_RADIOBUTTON:
+ return new NativeRadioButtonWin(listener);
+ }
+ NOTREACHED() << "Invalid button type!";
+ return NULL;
+}
+
+} // namespace views
diff --git a/chrome/views/controls/button/native_button_win.h b/chrome/views/controls/button/native_button_win.h
new file mode 100644
index 0000000..b711537
--- /dev/null
+++ b/chrome/views/controls/button/native_button_win.h
@@ -0,0 +1,111 @@
+// 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.
+
+#ifndef CHROME_VIEWS_CONTROLS_BUTTON_NATIVE_BUTTON_WIN_H_
+#define CHROME_VIEWS_CONTROLS_BUTTON_NATIVE_BUTTON_WIN_H_
+
+#include "chrome/common/gfx/chrome_font.h"
+#include "chrome/views/controls/native_control_win.h"
+#include "chrome/views/controls/button/native_button_wrapper.h"
+
+namespace views {
+
+// A View that hosts a native Windows button.
+class NativeButtonWin : public NativeControlWin,
+ public NativeButtonWrapper {
+ public:
+ explicit NativeButtonWin(NativeButtonWrapperListener* listener);
+ virtual ~NativeButtonWin();
+
+ // Overridden from NativeButtonWrapper:
+ virtual void SetLabel(const std::wstring& label);
+ virtual std::wstring GetLabel() const;
+ virtual void SetFont(const ChromeFont& font);
+ virtual void SetDefaultButton(bool is_default);
+ virtual bool IsDefaultButton() const;
+ virtual void SetMinimumSizeInPlatformUnits(const gfx::Size& minimum_size);
+ virtual void SetIgnoreMinimumSize(bool ignore_minimum_size);
+ virtual View* GetView();
+
+ // Overridden from View:
+ virtual gfx::Size GetPreferredSize();
+
+ // Overridden from NativeControlWin:
+ virtual LRESULT ProcessMessage(UINT message,
+ WPARAM w_param,
+ LPARAM l_param);
+ virtual bool OnKeyDown(int vkey);
+
+ protected:
+ virtual bool NotifyOnKeyDown() const;
+ virtual void CreateNativeControl();
+ virtual void NativeControlCreated(HWND control_hwnd);
+
+ private:
+ // Our listener.
+ NativeButtonWrapperListener* listener_;
+
+ // The button label.
+ std::wstring label_;
+
+ // True if the button is the default button in its context.
+ bool is_default_;
+
+ // The font used to render the button label.
+ ChromeFont font_;
+
+ // True if the button should ignore the minimum size for the platform. Default
+ // is false.
+ bool ignore_minimum_size_;
+
+ // Minimum size, in dlus (see SetMinimumSizeInPlatformUnits).
+ gfx::Size min_dlu_size_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeButtonWin);
+};
+
+// A View that hosts a native Windows checkbox.
+class NativeCheckboxWin : public NativeButtonWin {
+ public:
+ explicit NativeCheckboxWin(NativeButtonWrapperListener* listener);
+ virtual ~NativeCheckboxWin();
+
+ // Overridden from NativeButtonWrapper:
+ virtual void SetSelected(bool selected);
+ virtual bool IsSelected() const;
+ virtual void SetHighlight(bool highlight);
+
+ // Overridden from NativeControlWin:
+ virtual LRESULT ProcessMessage(UINT message,
+ WPARAM w_param,
+ LPARAM l_param);
+
+ protected:
+ virtual void CreateNativeControl();
+ virtual void NativeControlCreated(HWND control_hwnd);
+
+ private:
+ // True if this checkbox is checked.
+ bool selected_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeCheckboxWin);
+};
+
+// A View that hosts a native Windows radio button.
+class NativeRadioButtonWin : public NativeCheckboxWin {
+ public:
+ explicit NativeRadioButtonWin(NativeButtonWrapperListener* listener);
+ virtual ~NativeRadioButtonWin();
+
+ protected:
+ // Overridden from NativeCheckboxWin:
+ virtual void CreateNativeControl();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NativeRadioButtonWin);
+};
+
+} // namespace views
+
+#endif // #ifndef CHROME_VIEWS_CONTROLS_BUTTON_NATIVE_BUTTON_WIN_H_
diff --git a/chrome/views/controls/button/native_button_wrapper.h b/chrome/views/controls/button/native_button_wrapper.h
new file mode 100644
index 0000000..f530b83
--- /dev/null
+++ b/chrome/views/controls/button/native_button_wrapper.h
@@ -0,0 +1,69 @@
+// 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.
+
+#ifndef CHROME_VIEWS_CONTROLS_BUTTON_NATIVE_BUTTON_WRAPPER_H_
+#define CHROME_VIEWS_CONTROLS_BUTTON_NATIVE_BUTTON_WRAPPER_H_
+
+class ChromeFont;
+
+namespace views {
+
+// An interface implemented by the view that owns the NativeButtonWrapper that
+// allows it to be notified when the button is pressed.
+class NativeButtonWrapperListener {
+ public:
+ virtual void ButtonPressed() = 0;
+};
+
+// A specialization of NativeControlWrapper that hosts a platform-native button.
+class NativeButtonWrapper {
+ public:
+ // Sets/Gets the button's label.
+ virtual void SetLabel(const std::wstring& label) = 0;
+ virtual std::wstring GetLabel() const = 0;
+
+ // Sets the font used by this button.
+ virtual void SetFont(const ChromeFont& font) = 0;
+
+ // Sets whether or not the button should have the default appearance and
+ // action in its setting.
+ virtual void SetDefaultButton(bool is_default) = 0;
+ virtual bool IsDefaultButton() const = 0;
+
+ // Sets the minimum size of the button from the specified size in native
+ // dialog units. The definition of this unit may vary from platform to
+ // platform. If the width/height is non-zero, the preferred size of the button
+ // will not be less than this value when the dialog units are converted to
+ // pixels.
+ virtual void SetMinimumSizeInPlatformUnits(const gfx::Size& minimum_size) = 0;
+
+ // Call to have the button ignore its minimum size. Use this if you want
+ // buttons narrower than the defined minimum size.
+ virtual void SetIgnoreMinimumSize(bool ignore_minimum_size) = 0;
+
+ // Sets/Gets the selected state of button. Valid only for checkboxes and radio
+ // buttons.
+ virtual void SetSelected(bool is_selected) {}
+ virtual bool IsSelected(bool is_selected) { return false; }
+
+ // Shows the hover state for the button if |highlight| is true.
+ virtual void SetHighlight(bool highlight) {};
+
+ // Retrieves the views::View that hosts the native control.
+ virtual View* GetView() = 0;
+
+ enum Type {
+ TYPE_BUTTON,
+ TYPE_CHECKBOX,
+ TYPE_RADIOBUTTON
+ };
+
+ // Creates an appropriate NativeButtonWrapper for the platform.
+ static NativeButtonWrapper* CreateNativeButtonWrapper(
+ NativeButtonWrapperListener* listener, Type type);
+};
+
+} // namespace views
+
+#endif // #ifndef CHROME_VIEWS_CONTROLS_BUTTON_NATIVE_BUTTON_WRAPPER_H_
diff --git a/chrome/views/controls/native_control_win.cc b/chrome/views/controls/native_control_win.cc
new file mode 100644
index 0000000..f60b93c
--- /dev/null
+++ b/chrome/views/controls/native_control_win.cc
@@ -0,0 +1,175 @@
+// #ifndef CHROME_VIEWS_NATIVE_CONTROL_WIN_H_// 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 "chrome/views/controls/native_control_win.h"
+
+#include "base/logging.h"
+#include "base/win_util.h"
+#include "chrome/common/l10n_util_win.h"
+
+namespace views {
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeControlWin, public:
+
+// static
+const wchar_t* NativeControlWin::kNativeControlWinKey =
+ L"__NATIVE_CONTROL_WIN__";
+
+NativeControlWin::NativeControlWin() : HWNDView() {
+}
+
+NativeControlWin::~NativeControlWin() {
+}
+
+LRESULT NativeControlWin::ProcessMessage(UINT message, WPARAM w_param,
+ LPARAM l_param) {
+ switch (message) {
+ case WM_CONTEXTMENU:
+ ShowContextMenu(gfx::Point(LOWORD(l_param), HIWORD(l_param)));
+ break;
+ case WM_CTLCOLORBTN:
+ case WM_CTLCOLORSTATIC:
+ return GetControlColor(message, reinterpret_cast<HDC>(w_param),
+ GetHWND());
+ }
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// 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();
+}
+
+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) {
+ // 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);
+
+ Attach(native_control);
+ // GetHWND() is now valid.
+
+ // Subclass the window so we can monitor for key presses.
+ win_util::Subclass(GetHWND(), &NativeControlWin::NativeControlWndProc);
+
+ // 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::Unsubclass(window, &NativeControlWin::NativeControlWndProc);
+ TRACK_HWND_DESTRUCTION(window);
+ }
+
+ return DefWindowProc(window, message, w_param, l_param);
+}
+
+} // namespace views
diff --git a/chrome/views/controls/native_control_win.h b/chrome/views/controls/native_control_win.h
new file mode 100644
index 0000000..c2ecb41
--- /dev/null
+++ b/chrome/views/controls/native_control_win.h
@@ -0,0 +1,94 @@
+// 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.
+
+#ifndef CHROME_VIEWS_CONTROLS_NATIVE_CONTROL_WIN_H_
+#define CHROME_VIEWS_CONTROLS_NATIVE_CONTROL_WIN_H_
+
+#include "chrome/views/controls/hwnd_view.h"
+
+namespace views {
+
+// A View that hosts a native Windows control.
+class NativeControlWin : public HWNDView {
+ public:
+ static const wchar_t* kNativeControlWinKey;
+
+ NativeControlWin();
+ virtual ~NativeControlWin();
+
+ // Called by the containing WidgetWin when a message is received from the HWND
+ // created by an object derived from NativeControlWin. Derived classes MUST
+ // call _this_ version of the function if they override it and do not handle
+ // all of the messages listed in widget_win.cc ProcessNativeControlWinMessage.
+ virtual LRESULT ProcessMessage(UINT message,
+ WPARAM w_param,
+ LPARAM l_param);
+
+ // Called by our subclassed window procedure when a WM_KEYDOWN message is
+ // received by the HWND created by an object derived from NativeControlWin.
+ // Returns true if the key was processed, false otherwise.
+ virtual bool OnKeyDown(int vkey) { return false; }
+
+ // Overridden from View:
+ virtual void SetEnabled(bool enabled);
+
+ protected:
+ virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child);
+ virtual void VisibilityChanged(View* starting_from, bool is_visible);
+ virtual void Focus();
+
+ // Called by the containing WidgetWin when a WM_CONTEXTMENU message is
+ // received from the HWND created by an object derived from NativeControlWin.
+ virtual void ShowContextMenu(const gfx::Point& location);
+
+ // Derived classes interested in receiving key down notification should
+ // override this method and return true. In which case OnKeyDown is called
+ // when a key down message is sent to the control.
+ // Note that this method is called at the time of the control creation: the
+ // behavior will not change if the returned value changes after the control
+ // has been created.
+ virtual bool NotifyOnKeyDown() const { return false; }
+
+ // Called when the NativeControlWin is attached to a View hierarchy with a
+ // valid Widget. The NativeControlWin should use this opportunity to create
+ // its associated HWND.
+ virtual void CreateNativeControl() = 0;
+
+ // MUST be called by the subclass implementation of |CreateNativeControl|
+ // immediately after creating the control HWND, otherwise it won't be attached
+ // to the HWNDView and will be effectively orphaned.
+ virtual void NativeControlCreated(HWND native_control);
+
+ // Returns additional extended style flags. When subclasses call
+ // CreateWindowEx in order to create the underlying control, they must OR the
+ // ExStyle parameter with the value returned by this function.
+ //
+ // We currently use this method in order to add flags such as WS_EX_LAYOUTRTL
+ // to the HWND for views with right-to-left UI layout.
+ DWORD GetAdditionalExStyle() const;
+
+ // TODO(xji): we use the following temporary function as we transition the
+ // various native controls to use the right set of RTL flags. This function
+ // will go away (and be replaced by GetAdditionalExStyle()) once all the
+ // controls are properly transitioned.
+ DWORD GetAdditionalRTLStyle() const;
+
+ private:
+ // Called by the containing WidgetWin when a message of type WM_CTLCOLORBTN or
+ // WM_CTLCOLORSTATIC is sent from the HWND created by an object dreived from
+ // NativeControlWin.
+ LRESULT GetControlColor(UINT message, HDC dc, HWND sender);
+
+ // Our subclass window procedure for the attached control.
+ static LRESULT CALLBACK NativeControlWndProc(HWND window,
+ UINT message,
+ WPARAM w_param,
+ LPARAM l_param);
+
+ DISALLOW_COPY_AND_ASSIGN(NativeControlWin);
+};
+
+} // namespace views
+
+#endif // #ifndef CHROME_VIEWS_CONTROLS_NATIVE_CONTROL_WIN_H_
diff --git a/chrome/views/views.vcproj b/chrome/views/views.vcproj
index 784f440..bb0ecad6 100644
--- a/chrome/views/views.vcproj
+++ b/chrome/views/views.vcproj
@@ -499,6 +499,14 @@
>
</File>
<File
+ RelativePath=".\controls\native_control_win.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\controls\native_control_win.h"
+ >
+ </File>
+ <File
RelativePath=".\controls\scroll_view.cc"
>
</File>
@@ -606,6 +614,18 @@
>
</File>
<File
+ RelativePath=".\controls\button\native_button_win.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\controls\button\native_button_win.h"
+ >
+ </File>
+ <File
+ RelativePath=".\controls\button\native_button_wrapper.h"
+ >
+ </File>
+ <File
RelativePath=".\controls\button\radio_button.cc"
>
</File>
diff --git a/chrome/views/widget/widget_win.cc b/chrome/views/widget/widget_win.cc
index 047313d..16f510c 100644
--- a/chrome/views/widget/widget_win.cc
+++ b/chrome/views/widget/widget_win.cc
@@ -12,6 +12,7 @@
#include "chrome/common/notification_service.h"
#include "chrome/common/win_util.h"
#include "chrome/views/accessibility/view_accessibility.h"
+#include "chrome/views/controls/native_control_win.h"
#include "chrome/views/widget/aero_tooltip_manager.h"
#include "chrome/views/widget/hwnd_notification_source.h"
#include "chrome/views/widget/root_view.h"
@@ -34,6 +35,11 @@ RootView* GetRootViewForHWND(HWND hwnd) {
return reinterpret_cast<RootView*>(::GetProp(hwnd, kRootViewWindowProperty));
}
+NativeControlWin* GetNativeControlWinForHWND(HWND hwnd) {
+ return reinterpret_cast<NativeControlWin*>(
+ ::GetProp(hwnd, NativeControlWin::kNativeControlWinKey));
+}
+
// Used to locate the WidgetWin issuing the current Create. Only valid for the
// life of Create.
//
@@ -928,6 +934,51 @@ std::wstring WidgetWin::GetWindowClassName() {
return name;
}
+// 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.
+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;
+}
+
+// Some messages may be sent to us by a child HWND managed by
+// NativeControlWin. 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 NativeControlWin, 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.
+bool ProcessNativeControlMessage(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)) {
+ NativeControlWin* wrapper = GetNativeControlWinForHWND(control_hwnd);
+ if (wrapper) {
+ *l_result = wrapper->ProcessMessage(message, w_param, l_param);
+ return true;
+ }
+ }
+
+ return false;
+}
+
// static
LRESULT CALLBACK WidgetWin::WndProc(HWND window, UINT message,
WPARAM w_param, LPARAM l_param) {
@@ -939,11 +990,21 @@ LRESULT CALLBACK WidgetWin::WndProc(HWND window, UINT message,
widget->hwnd_ = window;
return TRUE;
}
+
WidgetWin* widget = reinterpret_cast<WidgetWin*>(
win_util::GetWindowUserData(window));
if (!widget)
return 0;
+
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 (ProcessNativeControlMessage(message, w_param, l_param, &result))
+ return result;
+
+ // Otherwise we handle everything else.
if (!widget->ProcessWindowMessage(window, message, w_param, l_param, result))
result = DefWindowProc(window, message, w_param, l_param);
if (message == WM_NCDESTROY) {