diff options
author | dbeam@chromium.org <dbeam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-28 09:51:44 +0000 |
---|---|---|
committer | dbeam@chromium.org <dbeam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-28 09:51:44 +0000 |
commit | 08a0073bb8b13399d112db41ed57c2c2aa87375d (patch) | |
tree | f03d1f652ebb7d2857b8093864cde19b5beb2a4e | |
parent | bba8921b1bbfb8da79bd8484df6c5b952363c367 (diff) | |
download | chromium_src-08a0073bb8b13399d112db41ed57c2c2aa87375d.zip chromium_src-08a0073bb8b13399d112db41ed57c2c2aa87375d.tar.gz chromium_src-08a0073bb8b13399d112db41ed57c2c2aa87375d.tar.bz2 |
Fix autofill popup stickiness.
Unhandled clicks while the autofill popup is showing should dismiss it.
Additionally, forward mouse events that aren't directly useful to the popup.
R=estade@chromium.org,sadrul@chromium.org,sky@chromium.org
BUG=259529
Review URL: https://chromiumcodereview.appspot.com/19458003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@219974 0039d316-1c4b-4281-b951-d872f2087c98
36 files changed, 407 insertions, 118 deletions
diff --git a/ash/screen_ash.cc b/ash/screen_ash.cc index 4ba2868..31c5bcc 100644 --- a/ash/screen_ash.cc +++ b/ash/screen_ash.cc @@ -118,8 +118,11 @@ gfx::Point ScreenAsh::GetCursorScreenPoint() { return aura::Env::GetInstance()->last_mouse_location(); } -gfx::NativeWindow ScreenAsh::GetWindowAtCursorScreenPoint() { - const gfx::Point point = Shell::GetScreen()->GetCursorScreenPoint(); +gfx::NativeWindow ScreenAsh::GetWindowUnderCursor() { + return GetWindowAtScreenPoint(Shell::GetScreen()->GetCursorScreenPoint()); +} + +gfx::NativeWindow ScreenAsh::GetWindowAtScreenPoint(const gfx::Point& point) { return wm::GetRootWindowAt(point)->GetTopWindowContainingPoint(point); } diff --git a/ash/screen_ash.h b/ash/screen_ash.h index 95869b0..6c07607 100644 --- a/ash/screen_ash.h +++ b/ash/screen_ash.h @@ -65,7 +65,9 @@ class ASH_EXPORT ScreenAsh : public gfx::Screen { // gfx::Screen overrides: virtual bool IsDIPEnabled() OVERRIDE; virtual gfx::Point GetCursorScreenPoint() OVERRIDE; - virtual gfx::NativeWindow GetWindowAtCursorScreenPoint() OVERRIDE; + virtual gfx::NativeWindow GetWindowUnderCursor() OVERRIDE; + virtual gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) + OVERRIDE; virtual int GetNumDisplays() const OVERRIDE; virtual std::vector<gfx::Display> GetAllDisplays() const OVERRIDE; virtual gfx::Display GetDisplayNearestWindow( diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc index 1429c6a..2c11343 100644 --- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc +++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc @@ -76,6 +76,7 @@ #include "grit/webkit_resources.h" #include "net/cert/cert_status_flags.h" #include "ui/base/base_window.h" +#include "ui/base/events/event.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/models/combobox_model.h" #include "ui/base/resource/resource_bundle.h" @@ -1769,6 +1770,7 @@ void AutofillDialogControllerImpl::UserEditedOrActivatedInput( content_bounds, base::i18n::IsRTL() ? base::i18n::RIGHT_TO_LEFT : base::i18n::LEFT_TO_RIGHT); + popup_controller_->set_hide_on_outside_click(true); popup_controller_->Show(popup_values, popup_labels, popup_icons, @@ -2021,6 +2023,12 @@ void AutofillDialogControllerImpl::OnPopupShown( void AutofillDialogControllerImpl::OnPopupHidden( content::RenderWidgetHost::KeyPressEventCallback* callback) {} +bool AutofillDialogControllerImpl::ShouldRepostEvent( + const ui::MouseEvent& event) { + // If the event would be reposted inside |input_showing_popup_|, just ignore. + return !view_->HitTestInput(*input_showing_popup_, event.location()); +} + void AutofillDialogControllerImpl::DidSelectSuggestion(int identifier) { // TODO(estade): implement. } diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h index 7513258..54fb490 100644 --- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h +++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h @@ -176,6 +176,7 @@ class AutofillDialogControllerImpl : public AutofillDialogViewDelegate, content::RenderWidgetHost::KeyPressEventCallback* callback) OVERRIDE; virtual void OnPopupHidden( content::RenderWidgetHost::KeyPressEventCallback* callback) OVERRIDE; + virtual bool ShouldRepostEvent(const ui::MouseEvent& event) OVERRIDE; virtual void DidSelectSuggestion(int identifier) OVERRIDE; virtual void DidAcceptSuggestion(const string16& value, int identifier) OVERRIDE; diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc index f7d8798..7947bf30 100644 --- a/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc +++ b/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc @@ -172,6 +172,10 @@ class TestAutofillDialogView : public AutofillDialogView { } virtual string16 GetCvc() OVERRIDE { return string16(); } + virtual bool HitTestInput(const DetailInput& input, + const gfx::Point& screen_point) OVERRIDE { + return false; + } virtual bool SaveDetailsLocally() OVERRIDE { return true; } virtual const content::NavigationController* ShowSignIn() OVERRIDE { return NULL; diff --git a/chrome/browser/ui/autofill/autofill_dialog_view.h b/chrome/browser/ui/autofill/autofill_dialog_view.h index 9466c0b..295f429 100644 --- a/chrome/browser/ui/autofill/autofill_dialog_view.h +++ b/chrome/browser/ui/autofill/autofill_dialog_view.h @@ -12,6 +12,7 @@ class NavigationController; } namespace gfx { +class Point; class Size; } @@ -78,6 +79,10 @@ class AutofillDialogView { // relevant. virtual string16 GetCvc() = 0; + // Whether or not |point| is within |input|'s bounds. + virtual bool HitTestInput(const DetailInput& input, + const gfx::Point& screen_point) = 0; + // Returns true if new or edited autofill details should be saved. virtual bool SaveDetailsLocally() = 0; diff --git a/chrome/browser/ui/autofill/autofill_popup_controller.h b/chrome/browser/ui/autofill/autofill_popup_controller.h index 63a7549..4b4f7c6 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller.h +++ b/chrome/browser/ui/autofill/autofill_popup_controller.h @@ -18,6 +18,10 @@ class Rect; class RectF; } +namespace ui { +class MouseEvent; +} + namespace autofill { // This interface provides data to an AutofillPopupView. @@ -41,6 +45,9 @@ class AutofillPopupController { // The user has moved the mouse outside of the popup. virtual void MouseExitedPopup() = 0; + // Whether |event| should be reposted to the native window management. + virtual bool ShouldRepostEvent(const ui::MouseEvent& event) = 0; + // Accepts the suggestion at |index|. virtual void AcceptSuggestion(size_t index) = 0; @@ -100,6 +107,9 @@ class AutofillPopupController { // hovered or has keyboard focus. virtual int selected_line() const = 0; + // Whether the view should be hidden on outside mouse presses. + virtual bool hide_on_outside_click() const = 0; + protected: virtual ~AutofillPopupController() {} }; diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc index f6ed33a..043e8c1 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc +++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc @@ -100,6 +100,7 @@ AutofillPopupControllerImpl::AutofillPopupControllerImpl( container_view_(container_view), element_bounds_(element_bounds), text_direction_(text_direction), + hide_on_outside_click_(false), weak_ptr_factory_(this), key_press_event_callback_( base::Bind(&AutofillPopupControllerImpl::HandleKeyPressEvent, @@ -305,6 +306,11 @@ void AutofillPopupControllerImpl::MouseExitedPopup() { SetSelectedLine(kNoSelection); } +bool AutofillPopupControllerImpl::ShouldRepostEvent( + const ui::MouseEvent& event) { + return delegate_->ShouldRepostEvent(event); +} + void AutofillPopupControllerImpl::AcceptSuggestion(size_t index) { delegate_->DidAcceptSuggestion(full_names_[index], identifiers_[index]); } @@ -366,6 +372,10 @@ bool AutofillPopupControllerImpl::IsRTL() const { return text_direction_ == base::i18n::RIGHT_TO_LEFT; } +bool AutofillPopupControllerImpl::hide_on_outside_click() const { + return hide_on_outside_click_; +} + const std::vector<string16>& AutofillPopupControllerImpl::names() const { return names_; } @@ -400,6 +410,11 @@ int AutofillPopupControllerImpl::selected_line() const { return selected_line_; } +void AutofillPopupControllerImpl::set_hide_on_outside_click( + bool hide_on_outside_click) { + hide_on_outside_click_ = hide_on_outside_click; +} + void AutofillPopupControllerImpl::SetSelectedLine(int selected_line) { if (selected_line_ == selected_line) return; diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.h b/chrome/browser/ui/autofill/autofill_popup_controller_impl.h index a7697c8..43f5a1d 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.h +++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.h @@ -66,6 +66,9 @@ class AutofillPopupControllerImpl : public AutofillPopupController { bool HandleKeyPressEvent(const content::NativeWebKeyboardEvent& event); + // Tells the view to capture mouse events. Must be called before |Show()|. + void set_hide_on_outside_click(bool hide_on_outside_click); + protected: FRIEND_TEST_ALL_PREFIXES(AutofillExternalDelegateBrowserTest, CloseWidgetAndNoLeaking); @@ -83,6 +86,7 @@ class AutofillPopupControllerImpl : public AutofillPopupController { virtual void MouseHovered(int x, int y) OVERRIDE; virtual void MouseClicked(int x, int y) OVERRIDE; virtual void MouseExitedPopup() OVERRIDE; + virtual bool ShouldRepostEvent(const ui::MouseEvent& event) OVERRIDE; virtual void AcceptSuggestion(size_t index) OVERRIDE; virtual int GetIconResourceID(const string16& resource_name) OVERRIDE; virtual bool CanDelete(size_t index) const OVERRIDE; @@ -103,6 +107,7 @@ class AutofillPopupControllerImpl : public AutofillPopupController { virtual const gfx::Font& subtext_font() const OVERRIDE; #endif virtual int selected_line() const OVERRIDE; + virtual bool hide_on_outside_click() const OVERRIDE; // Change which line is currently selected by the user. void SetSelectedLine(int selected_line); @@ -225,6 +230,9 @@ class AutofillPopupControllerImpl : public AutofillPopupController { // |kNoSelection| indicates that no line is currently selected. int selected_line_; + // Whether the popup view should hide on mouse presses outside of it. + bool hide_on_outside_click_; + base::WeakPtrFactory<AutofillPopupControllerImpl> weak_ptr_factory_; content::RenderWidgetHost::KeyPressEventCallback key_press_event_callback_; diff --git a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h index 077fb64..00149bc 100644 --- a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h +++ b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h @@ -54,6 +54,8 @@ class AutofillDialogCocoa : public AutofillDialogView, virtual void GetUserInput(DialogSection section, DetailOutputMap* output) OVERRIDE; virtual string16 GetCvc() OVERRIDE; + virtual bool HitTestInput(const DetailInput& input, + const gfx::Point& screen_point) OVERRIDE; virtual bool SaveDetailsLocally() OVERRIDE; virtual const content::NavigationController* ShowSignIn() OVERRIDE; virtual void HideSignIn() OVERRIDE; diff --git a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm index f048320..fc40da2 100644 --- a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm +++ b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm @@ -128,6 +128,12 @@ string16 AutofillDialogCocoa::GetCvc() { return string16(); } +bool AutofillDialogCocoa::HitTestInput(const DetailInput& input, + const gfx::Point& screen_point) { + // TODO(dbeam): implement. + return false; +} + bool AutofillDialogCocoa::SaveDetailsLocally() { return [sheet_delegate_ saveDetailsLocally]; } diff --git a/chrome/browser/ui/views/autofill/autofill_dialog_views.cc b/chrome/browser/ui/views/autofill/autofill_dialog_views.cc index 9ba8e46..c9be835 100644 --- a/chrome/browser/ui/views/autofill/autofill_dialog_views.cc +++ b/chrome/browser/ui/views/autofill/autofill_dialog_views.cc @@ -7,6 +7,7 @@ #include <utility> #include "base/bind.h" +#include "base/location.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/autofill/autofill_dialog_sign_in_delegate.h" @@ -32,6 +33,7 @@ #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/canvas.h" #include "ui/gfx/path.h" +#include "ui/gfx/point.h" #include "ui/gfx/skia_util.h" #include "ui/views/background.h" #include "ui/views/border.h" @@ -1429,6 +1431,22 @@ base::string16 AutofillDialogViews::GetCvc() { decorated_textfield()->text(); } +bool AutofillDialogViews::HitTestInput(const DetailInput& input, + const gfx::Point& screen_point) { + views::View* view = TextfieldForInput(input); + if (!view) + view = ComboboxForInput(input); + + if (view) { + gfx::Point target_point(screen_point); + views::View::ConvertPointFromScreen(view, &target_point); + return view->HitTestPoint(target_point); + } + + NOTREACHED(); + return false; +} + bool AutofillDialogViews::SaveDetailsLocally() { DCHECK(save_in_chrome_checkbox_->visible()); return save_in_chrome_checkbox_->checked(); @@ -2270,11 +2288,11 @@ void AutofillDialogViews::TextfieldEditedOrActivated( decorated = iter->second; if (decorated == textfield) { delegate_->UserEditedOrActivatedInput(group->section, - iter->first, - GetWidget()->GetNativeView(), - textfield->GetBoundsInScreen(), - textfield->text(), - was_edit); + iter->first, + GetWidget()->GetNativeView(), + textfield->GetBoundsInScreen(), + textfield->text(), + was_edit); type = iter->first->type; break; } diff --git a/chrome/browser/ui/views/autofill/autofill_dialog_views.h b/chrome/browser/ui/views/autofill/autofill_dialog_views.h index 1f660eb..c5b37c4 100644 --- a/chrome/browser/ui/views/autofill/autofill_dialog_views.h +++ b/chrome/browser/ui/views/autofill/autofill_dialog_views.h @@ -92,6 +92,8 @@ class AutofillDialogViews : public AutofillDialogView, virtual void GetUserInput(DialogSection section, DetailOutputMap* output) OVERRIDE; virtual base::string16 GetCvc() OVERRIDE; + virtual bool HitTestInput(const DetailInput& input, + const gfx::Point& screen_point) OVERRIDE; virtual bool SaveDetailsLocally() OVERRIDE; virtual const content::NavigationController* ShowSignIn() OVERRIDE; virtual void HideSignIn() OVERRIDE; diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc index 661ef09..2c725f5 100644 --- a/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc +++ b/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc @@ -11,9 +11,12 @@ #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/canvas.h" #include "ui/gfx/image/image.h" +#include "ui/gfx/native_widget_types.h" #include "ui/gfx/point.h" #include "ui/gfx/rect.h" +#include "ui/gfx/screen.h" #include "ui/views/border.h" +#include "ui/views/event_utils.h" #include "ui/views/widget/widget.h" using WebKit::WebAutofillClient; @@ -108,28 +111,61 @@ void AutofillPopupViewViews::OnMouseExited(const ui::MouseEvent& event) { } void AutofillPopupViewViews::OnMouseMoved(const ui::MouseEvent& event) { - if (controller_) + if (!controller_) + return; + + if (HitTestPoint(event.location())) controller_->MouseHovered(event.x(), event.y()); + else + controller_->MouseExitedPopup(); } bool AutofillPopupViewViews::OnMousePressed(const ui::MouseEvent& event) { - // We must return true in order to get the OnMouseReleased event later. - return true; + if (HitTestPoint(event.location())) + return true; + + if (controller_->hide_on_outside_click()) { + GetWidget()->ReleaseCapture(); + + gfx::Point screen_loc = event.location(); + views::View::ConvertPointToScreen(this, &screen_loc); + + ui::MouseEvent mouse_event = event; + mouse_event.set_location(screen_loc); + + if (controller_->ShouldRepostEvent(mouse_event)) { + gfx::NativeView native_view = GetWidget()->GetNativeView(); + gfx::Screen* screen = gfx::Screen::GetScreenFor(native_view); + gfx::NativeWindow window = screen->GetWindowAtScreenPoint(screen_loc); + views::RepostLocatedEvent(window, mouse_event); + } + + controller_->Hide(); + // |this| is now deleted. + } + + return false; } void AutofillPopupViewViews::OnMouseReleased(const ui::MouseEvent& event) { if (!controller_) return; + // Because this view can can be shown in response to a mouse press, it can + // receive an OnMouseReleased event just after showing. This breaks the mouse + // capture, so restart capturing here. + if (controller_->hide_on_outside_click() && GetWidget()) + GetWidget()->SetCapture(this); + // We only care about the left click. - if (event.IsOnlyLeftMouseButton() && - HitTestPoint(event.location())) + if (event.IsOnlyLeftMouseButton() && HitTestPoint(event.location())) controller_->MouseClicked(event.x(), event.y()); } void AutofillPopupViewViews::OnWidgetBoundsChanged( views::Widget* widget, const gfx::Rect& new_bounds) { + DCHECK_EQ(widget, observing_widget_); controller_->Hide(); } @@ -152,6 +188,9 @@ void AutofillPopupViewViews::Show() { UpdateBoundsAndRedrawPopup(); GetWidget()->Show(); + + if (controller_->hide_on_outside_click()) + GetWidget()->SetCapture(this); } void AutofillPopupViewViews::InvalidateRow(size_t row) { diff --git a/chrome/browser/ui/views/panels/panel_view.cc b/chrome/browser/ui/views/panels/panel_view.cc index d122392e..fb765f1 100644 --- a/chrome/browser/ui/views/panels/panel_view.cc +++ b/chrome/browser/ui/views/panels/panel_view.cc @@ -973,7 +973,7 @@ void PanelView::OnWidgetActivationChanged(views::Widget* widget, bool active) { if (focused_ && panel_->IsMinimized() && panel_->collection()->type() == PanelCollection::DOCKED && gfx::Screen::GetScreenFor(widget->GetNativeWindow())-> - GetWindowAtCursorScreenPoint() != widget->GetNativeWindow()) { + GetWindowUnderCursor() != widget->GetNativeWindow()) { panel_->Restore(); } #endif diff --git a/chrome/browser/ui/window_sizer/window_sizer_common_unittest.cc b/chrome/browser/ui/window_sizer/window_sizer_common_unittest.cc index 6f4bd8d..f0984a5 100644 --- a/chrome/browser/ui/window_sizer/window_sizer_common_unittest.cc +++ b/chrome/browser/ui/window_sizer/window_sizer_common_unittest.cc @@ -31,7 +31,13 @@ class TestScreen : public gfx::Screen { return gfx::Point(); } - virtual gfx::NativeWindow GetWindowAtCursorScreenPoint() OVERRIDE { + virtual gfx::NativeWindow GetWindowUnderCursor() OVERRIDE { + NOTREACHED(); + return NULL; + } + + virtual gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) + OVERRIDE { NOTREACHED(); return NULL; } diff --git a/components/autofill/core/browser/autofill_external_delegate.cc b/components/autofill/core/browser/autofill_external_delegate.cc index b5d38d4..ca6696e 100644 --- a/components/autofill/core/browser/autofill_external_delegate.cc +++ b/components/autofill/core/browser/autofill_external_delegate.cc @@ -186,6 +186,11 @@ void AutofillExternalDelegate::OnPopupHidden( registered_key_press_event_callback_with_ = NULL; } +bool AutofillExternalDelegate::ShouldRepostEvent(const ui::MouseEvent& event) { + NOTREACHED(); + return true; +} + void AutofillExternalDelegate::DidSelectSuggestion(int identifier) { ClearPreviewedForm(); diff --git a/components/autofill/core/browser/autofill_external_delegate.h b/components/autofill/core/browser/autofill_external_delegate.h index 433027e..0a0093e 100644 --- a/components/autofill/core/browser/autofill_external_delegate.h +++ b/components/autofill/core/browser/autofill_external_delegate.h @@ -51,6 +51,7 @@ class AutofillExternalDelegate content::RenderWidgetHost::KeyPressEventCallback* callback) OVERRIDE; virtual void OnPopupHidden( content::RenderWidgetHost::KeyPressEventCallback* callback) OVERRIDE; + virtual bool ShouldRepostEvent(const ui::MouseEvent& event) OVERRIDE; virtual void DidSelectSuggestion(int identifier) OVERRIDE; virtual void DidAcceptSuggestion(const base::string16& value, int identifier) OVERRIDE; diff --git a/components/autofill/core/browser/autofill_popup_delegate.h b/components/autofill/core/browser/autofill_popup_delegate.h index 0f2ab41..86b5eff 100644 --- a/components/autofill/core/browser/autofill_popup_delegate.h +++ b/components/autofill/core/browser/autofill_popup_delegate.h @@ -8,6 +8,10 @@ #include "base/strings/string16.h" #include "content/public/browser/render_view_host.h" +namespace ui { +class MouseEvent; +} + namespace autofill { // An interface for interaction with AutofillPopupController. Will be notified @@ -24,6 +28,10 @@ class AutofillPopupDelegate { virtual void OnPopupHidden( content::RenderWidgetHost::KeyPressEventCallback* callback) = 0; + // Called when the Autofill popup recieves a click outside of the popup view + // to determine if the event should be reposted to the native window manager. + virtual bool ShouldRepostEvent(const ui::MouseEvent& event) = 0; + // Called when the autofill suggestion indicated by |identifier| has been // temporarily selected (e.g., hovered). virtual void DidSelectSuggestion(int identifier) = 0; diff --git a/ui/aura/test/test_screen.cc b/ui/aura/test/test_screen.cc index 474ac29..c43ffb4 100644 --- a/ui/aura/test/test_screen.cc +++ b/ui/aura/test/test_screen.cc @@ -108,8 +108,11 @@ gfx::Point TestScreen::GetCursorScreenPoint() { return Env::GetInstance()->last_mouse_location(); } -gfx::NativeWindow TestScreen::GetWindowAtCursorScreenPoint() { - const gfx::Point point = GetCursorScreenPoint(); +gfx::NativeWindow TestScreen::GetWindowUnderCursor() { + return GetWindowAtScreenPoint(GetCursorScreenPoint()); +} + +gfx::NativeWindow TestScreen::GetWindowAtScreenPoint(const gfx::Point& point) { return root_window_->GetTopWindowContainingPoint(point); } diff --git a/ui/aura/test/test_screen.h b/ui/aura/test/test_screen.h index 00d684b..c958279 100644 --- a/ui/aura/test/test_screen.h +++ b/ui/aura/test/test_screen.h @@ -47,7 +47,9 @@ class TestScreen : public gfx::Screen, // gfx::Screen overrides: virtual bool IsDIPEnabled() OVERRIDE; virtual gfx::Point GetCursorScreenPoint() OVERRIDE; - virtual gfx::NativeWindow GetWindowAtCursorScreenPoint() OVERRIDE; + virtual gfx::NativeWindow GetWindowUnderCursor() OVERRIDE; + virtual gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) + OVERRIDE; virtual int GetNumDisplays() const OVERRIDE; virtual std::vector<gfx::Display> GetAllDisplays() const OVERRIDE; virtual gfx::Display GetDisplayNearestWindow( diff --git a/ui/gfx/screen.h b/ui/gfx/screen.h index 7958f65..d94e3e0 100644 --- a/ui/gfx/screen.h +++ b/ui/gfx/screen.h @@ -52,7 +52,10 @@ class UI_EXPORT Screen { virtual gfx::Point GetCursorScreenPoint() = 0; // Returns the window under the cursor. - virtual gfx::NativeWindow GetWindowAtCursorScreenPoint() = 0; + virtual gfx::NativeWindow GetWindowUnderCursor() = 0; + + // Returns the window at the given screen coordinate |point|. + virtual gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) = 0; // Returns the number of displays. // Mirrored displays are excluded; this method is intended to return the @@ -65,7 +68,7 @@ class UI_EXPORT Screen { // Returns the display nearest the specified window. virtual gfx::Display GetDisplayNearestWindow(NativeView view) const = 0; - // Returns the the display nearest the specified point. + // Returns the display nearest the specified point. virtual gfx::Display GetDisplayNearestPoint( const gfx::Point& point) const = 0; diff --git a/ui/gfx/screen_android.cc b/ui/gfx/screen_android.cc index 1376136..e90bb76 100644 --- a/ui/gfx/screen_android.cc +++ b/ui/gfx/screen_android.cc @@ -19,7 +19,13 @@ class ScreenAndroid : public Screen { virtual gfx::Point GetCursorScreenPoint() OVERRIDE { return gfx::Point(); } - virtual gfx::NativeWindow GetWindowAtCursorScreenPoint() OVERRIDE { + virtual gfx::NativeWindow GetWindowUnderCursor() OVERRIDE { + NOTIMPLEMENTED(); + return NULL; + } + + virtual gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) + OVERRIDE { NOTIMPLEMENTED(); return NULL; } diff --git a/ui/gfx/screen_gtk.cc b/ui/gfx/screen_gtk.cc index 5177dc9..16a7873 100644 --- a/ui/gfx/screen_gtk.cc +++ b/ui/gfx/screen_gtk.cc @@ -91,7 +91,7 @@ class ScreenGtk : public gfx::Screen { } // Returns the window under the cursor. - virtual gfx::NativeWindow GetWindowAtCursorScreenPoint() OVERRIDE { + virtual gfx::NativeWindow GetWindowUnderCursor() OVERRIDE { GdkWindow* window = gdk_window_at_pointer(NULL, NULL); if (!window) return NULL; @@ -105,6 +105,12 @@ class ScreenGtk : public gfx::Screen { return GTK_IS_WINDOW(widget) ? GTK_WINDOW(widget) : NULL; } + virtual gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) + OVERRIDE { + NOTIMPLEMENTED(); + return NULL; + } + // Returns the number of displays. // Mirrored displays are excluded; this method is intended to return the // number of distinct, usable displays. diff --git a/ui/gfx/screen_ios.mm b/ui/gfx/screen_ios.mm index 6450e14..a277029 100644 --- a/ui/gfx/screen_ios.mm +++ b/ui/gfx/screen_ios.mm @@ -21,7 +21,13 @@ class ScreenIos : public gfx::Screen { return gfx::Point(0, 0); } - virtual gfx::NativeWindow GetWindowAtCursorScreenPoint() OVERRIDE { + virtual gfx::NativeWindow GetWindowUnderCursor() OVERRIDE { + NOTIMPLEMENTED(); + return gfx::NativeWindow(); + } + + virtual gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) + OVERRIDE { NOTIMPLEMENTED(); return gfx::NativeWindow(); } diff --git a/ui/gfx/screen_mac.mm b/ui/gfx/screen_mac.mm index 8f85ae6..28707ca 100644 --- a/ui/gfx/screen_mac.mm +++ b/ui/gfx/screen_mac.mm @@ -84,7 +84,13 @@ class ScreenMac : public gfx::Screen { return gfx::Point(mouseLocation.x, mouseLocation.y); } - virtual gfx::NativeWindow GetWindowAtCursorScreenPoint() OVERRIDE { + virtual gfx::NativeWindow GetWindowUnderCursor() OVERRIDE { + NOTIMPLEMENTED(); + return gfx::NativeWindow(); + } + + virtual gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) + OVERRIDE { NOTIMPLEMENTED(); return gfx::NativeWindow(); } diff --git a/ui/gfx/screen_win.cc b/ui/gfx/screen_win.cc index 23dbc9d..95847c4 100644 --- a/ui/gfx/screen_win.cc +++ b/ui/gfx/screen_win.cc @@ -49,10 +49,14 @@ gfx::Point ScreenWin::GetCursorScreenPoint() { return gfx::Point(pt); } -gfx::NativeWindow ScreenWin::GetWindowAtCursorScreenPoint() { - POINT location; - HWND window_hwnd = GetCursorPos(&location) ? WindowFromPoint(location) : NULL; - return GetNativeWindowFromHWND(window_hwnd); +gfx::NativeWindow ScreenWin::GetWindowUnderCursor() { + POINT cursor_loc; + HWND hwnd = GetCursorPos(&cursor_loc) ? WindowFromPoint(cursor_loc) : NULL; + return GetNativeWindowFromHWND(hwnd); +} + +gfx::NativeWindow ScreenWin::GetWindowAtScreenPoint(const gfx::Point& point) { + return GetNativeWindowFromHWND(WindowFromPoint(point.ToPOINT())); } int ScreenWin::GetNumDisplays() const { diff --git a/ui/gfx/screen_win.h b/ui/gfx/screen_win.h index cc59352..8905d46 100644 --- a/ui/gfx/screen_win.h +++ b/ui/gfx/screen_win.h @@ -20,7 +20,9 @@ class UI_EXPORT ScreenWin : public gfx::Screen { // Overridden from gfx::Screen: virtual bool IsDIPEnabled() OVERRIDE; virtual gfx::Point GetCursorScreenPoint() OVERRIDE; - virtual gfx::NativeWindow GetWindowAtCursorScreenPoint() OVERRIDE; + virtual gfx::NativeWindow GetWindowUnderCursor() OVERRIDE; + virtual gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) + OVERRIDE; virtual int GetNumDisplays() const OVERRIDE; virtual std::vector<gfx::Display> GetAllDisplays() const OVERRIDE; virtual gfx::Display GetDisplayNearestWindow( diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc index 80eacad..b2a2574 100644 --- a/ui/views/controls/menu/menu_controller.cc +++ b/ui/views/controls/menu/menu_controller.cc @@ -20,6 +20,7 @@ #include "ui/base/keycodes/keyboard_codes.h" #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/canvas.h" +#include "ui/gfx/native_widget_types.h" #include "ui/gfx/screen.h" #include "ui/gfx/vector2d.h" #include "ui/native_theme/native_theme.h" @@ -30,6 +31,7 @@ #include "ui/views/controls/menu/menu_scroll_view_container.h" #include "ui/views/controls/menu/submenu_view.h" #include "ui/views/drag_utils.h" +#include "ui/views/event_utils.h" #include "ui/views/mouse_constants.h" #include "ui/views/view_constants.h" #include "ui/views/views_delegate.h" @@ -39,7 +41,6 @@ #if defined(USE_AURA) #include "ui/aura/env.h" #include "ui/aura/root_window.h" -#include "ui/aura/window.h" #endif #if defined(OS_WIN) @@ -890,9 +891,15 @@ void MenuController::SetSelectionOnPointerDown(SubmenuView* source, #if defined(OS_WIN) // We're going to close and we own the mouse capture. We need to repost the - // mouse down, otherwise the window the user clicked on won't get the - // event. - RepostEvent(source, event); + // mouse down, otherwise the window the user clicked on won't get the event. + if (!state_.item) { + // We some times get an event after closing all the menus. Ignore it. Make + // sure the menu is in fact not visible. If the menu is visible, then + // we're in a bad state where we think the menu isn't visibile but it is. + DCHECK(!source->GetWidget()->IsVisible()); + } else { + RepostEvent(source, event); + } #endif // And close. @@ -1253,8 +1260,7 @@ bool MenuController::ShowSiblingMenu(SubmenuView* source, return false; } - gfx::NativeWindow window_under_mouse = - GetScreen()->GetWindowAtCursorScreenPoint(); + gfx::NativeWindow window_under_mouse = GetScreen()->GetWindowUnderCursor(); // TODO(oshima): Replace with views only API. if (!owner_ || window_under_mouse != owner_->GetNativeWindow()) return false; @@ -2093,94 +2099,52 @@ bool MenuController::SelectByChar(char16 character) { return false; } -#if defined(OS_WIN) void MenuController::RepostEvent(SubmenuView* source, const ui::LocatedEvent& event) { - if (!state_.item) { - // We some times get an event after closing all the menus. Ignore it. - // Make sure the menu is in fact not visible. If the menu is visible, then - // we're in a bad state where we think the menu isn't visibile but it is. - DCHECK(!source->GetWidget()->IsVisible()); - return; - } - gfx::Point screen_loc(event.location()); View::ConvertPointToScreen(source->GetScrollViewContainer(), &screen_loc); - HWND window = WindowFromPoint(screen_loc.ToPOINT()); - if (window) { - // Release the capture. - SubmenuView* submenu = state_.item->GetRootMenuItem()->GetSubmenu(); - submenu->ReleaseCapture(); - - if (submenu->GetWidget()->GetNativeView() && - GetWindowThreadProcessId( - HWNDForNativeView(submenu->GetWidget()->GetNativeView()), NULL) != - GetWindowThreadProcessId(window, NULL)) { - // Even though we have mouse capture, windows generates a mouse event - // if the other window is in a separate thread. Don't generate an event in - // this case else the target window can get double events leading to bad - // behavior. - return; - } - // Convert the coordinates to the target window. - RECT window_bounds; - GetWindowRect(window, &window_bounds); - int window_x = screen_loc.x() - window_bounds.left; - int window_y = screen_loc.y() - window_bounds.top; - - // Determine whether the click was in the client area or not. - // NOTE: WM_NCHITTEST coordinates are relative to the screen. - LRESULT nc_hit_result = SendMessage(window, WM_NCHITTEST, 0, - MAKELPARAM(screen_loc.x(), - screen_loc.y())); - const bool in_client_area = (nc_hit_result == HTCLIENT); - - // TODO(sky): this isn't right. The event to generate should correspond - // with the event we just got. MouseEvent only tells us what is down, - // which may differ. Need to add ability to get changed button from - // MouseEvent. - int event_type; - int flags = event.flags(); - if (flags & ui::EF_LEFT_MOUSE_BUTTON) - event_type = in_client_area ? WM_LBUTTONDOWN : WM_NCLBUTTONDOWN; - else if (flags & ui::EF_MIDDLE_MOUSE_BUTTON) - event_type = in_client_area ? WM_MBUTTONDOWN : WM_NCMBUTTONDOWN; - else if (flags & ui::EF_RIGHT_MOUSE_BUTTON) - event_type = in_client_area ? WM_RBUTTONDOWN : WM_NCRBUTTONDOWN; - else - event_type = 0; // Unknown mouse press. + gfx::NativeView native_view = source->GetWidget()->GetNativeView(); + gfx::Screen* screen = gfx::Screen::GetScreenFor(native_view); + gfx::NativeWindow window = screen->GetWindowAtScreenPoint(screen_loc); - if (event_type) { - if (in_client_area) { - PostMessage(window, event_type, event.native_event().wParam, - MAKELPARAM(window_x, window_y)); - } else { - PostMessage(window, event_type, nc_hit_result, - MAKELPARAM(screen_loc.x(), screen_loc.y())); - } - } else if (event.type() == ui::ET_GESTURE_TAP_DOWN) { -#if defined(USE_AURA) - // Gesture events need to be posted to the target root window. In - // desktop chrome there could be multiple root windows. - aura::RootWindow* target_root = - aura::RootWindow::GetForAcceleratedWidget(window); - if (target_root) - target_root->RepostEvent(event); -#endif + if (!window) + return; + +#if defined(OS_WIN) + // Release the capture. + SubmenuView* submenu = state_.item->GetRootMenuItem()->GetSubmenu(); + submenu->ReleaseCapture(); + + gfx::NativeView view = submenu->GetWidget()->GetNativeView(); + if (view) { + DWORD view_tid = GetWindowThreadProcessId(HWNDForNativeView(view), NULL); + if (view_tid != GetWindowThreadProcessId(HWNDForNativeView(window), NULL)) { + // Even though we have mouse capture, windows generates a mouse event if + // the other window is in a separate thread. Only repost an event if + // |view| was created on the same thread, else the target window can get + // double events leading to bad behavior. + return; } } -} -#elif defined(USE_AURA) -void MenuController::RepostEvent(SubmenuView* source, - const ui::LocatedEvent& event) { - aura::RootWindow* root_window = - source->GetWidget()->GetNativeWindow()->GetRootWindow(); - DCHECK(root_window); - root_window->RepostEvent(event); -} #endif + scoped_ptr<ui::LocatedEvent> clone; + if (event.IsMouseEvent()) { + clone.reset(new ui::MouseEvent(static_cast<const ui::MouseEvent&>(event))); + } else if (event.IsGestureEvent()) { + const ui::GestureEvent& ge = static_cast<const ui::GestureEvent&>(event); + clone.reset(new ui::GestureEvent(ge)); + } else { + NOTREACHED(); + return; + } + clone->set_location(screen_loc); + + RepostLocatedEvent(window, *clone); +} + + void MenuController::SetDropMenuItem( MenuItemView* new_target, MenuDelegate::DropPosition new_position) { diff --git a/ui/views/event_utils.h b/ui/views/event_utils.h new file mode 100644 index 0000000..3527c50 --- /dev/null +++ b/ui/views/event_utils.h @@ -0,0 +1,25 @@ +// Copyright 2013 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 UI_VIEWS_EVENT_UTILS_H_ +#define UI_VIEWS_EVENT_UTILS_H_ + +#include "ui/gfx/native_widget_types.h" +#include "ui/views/views_export.h" + +namespace ui { +class LocatedEvent; +} + +namespace views { + +// Reposts a located event natively. Returns false when |event| could not be +// reposted. |event| should be in screen coordinates. |window| is the target +// window that the event will be forwarded to. Only some events are supported. +VIEWS_EXPORT bool RepostLocatedEvent(gfx::NativeWindow window, + const ui::LocatedEvent& event); + +} // namespace views + +#endif // UI_VIEWS_EVENT_UTILS_H_ diff --git a/ui/views/event_utils_aura.cc b/ui/views/event_utils_aura.cc new file mode 100644 index 0000000..37aeb88 --- /dev/null +++ b/ui/views/event_utils_aura.cc @@ -0,0 +1,49 @@ +// Copyright 2013 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 "ui/views/event_utils.h" + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "ui/aura/client/screen_position_client.h" +#include "ui/aura/root_window.h" +#include "ui/base/events/event.h" +#include "ui/gfx/point.h" + +using aura::client::ScreenPositionClient; + +namespace views { + +bool RepostLocatedEvent(gfx::NativeWindow window, + const ui::LocatedEvent& event) { + if (!window) + return false; + + aura::RootWindow* root_window = window->GetRootWindow(); + + gfx::Point root_loc(event.location()); + ScreenPositionClient* spc = GetScreenPositionClient(root_window); + if (!spc) + return false; + + spc->ConvertPointFromScreen(root_window, &root_loc); + + scoped_ptr<ui::LocatedEvent> relocated; + if (event.IsMouseEvent()) { + const ui::MouseEvent& orig = static_cast<const ui::MouseEvent&>(event); + relocated.reset(new ui::MouseEvent(orig)); + } else if (event.IsGestureEvent()) { + const ui::GestureEvent& orig = static_cast<const ui::GestureEvent&>(event); + relocated.reset(new ui::GestureEvent(orig)); + } else { + NOTREACHED(); + return false; + } + relocated->set_location(root_loc); + + root_window->RepostEvent(*relocated); + return true; +} + +} // namespace views diff --git a/ui/views/event_utils_win.cc b/ui/views/event_utils_win.cc new file mode 100644 index 0000000..d9417a2e --- /dev/null +++ b/ui/views/event_utils_win.cc @@ -0,0 +1,59 @@ +// Copyright 2013 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 "ui/views/event_utils.h" + +#include <windowsx.h> + +#include "base/logging.h" +#include "ui/base/events/event.h" +#include "ui/base/events/event_constants.h" +#include "ui/gfx/point.h" + +namespace views { + +bool RepostLocatedEvent(gfx::NativeWindow window, + const ui::LocatedEvent& event) { + if (!window) + return false; + + // Determine whether the click was in the client area or not. + // NOTE: WM_NCHITTEST coordinates are relative to the screen. + const gfx::Point screen_loc = event.location(); + LRESULT nc_hit_result = SendMessage(window, WM_NCHITTEST, 0, + MAKELPARAM(screen_loc.x(), + screen_loc.y())); + const bool in_client_area = nc_hit_result == HTCLIENT; + + // TODO(sky): this isn't right. The event to generate should correspond with + // the event we just got. MouseEvent only tells us what is down, which may + // differ. Need to add ability to get changed button from MouseEvent. + int event_type; + int flags = event.flags(); + if (flags & ui::EF_LEFT_MOUSE_BUTTON) { + event_type = in_client_area ? WM_LBUTTONDOWN : WM_NCLBUTTONDOWN; + } else if (flags & ui::EF_MIDDLE_MOUSE_BUTTON) { + event_type = in_client_area ? WM_MBUTTONDOWN : WM_NCMBUTTONDOWN; + } else if (flags & ui::EF_RIGHT_MOUSE_BUTTON) { + event_type = in_client_area ? WM_RBUTTONDOWN : WM_NCRBUTTONDOWN; + } else { + NOTREACHED(); + return false; + } + + int window_x = screen_loc.x(); + int window_y = screen_loc.y(); + if (in_client_area) { + RECT window_bounds; + GetWindowRect(window, &window_bounds); + window_x -= window_bounds.left; + window_y -= window_bounds.top; + } + + WPARAM target = in_client_area ? event.native_event().wParam : nc_hit_result; + PostMessage(window, event_type, target, MAKELPARAM(window_x, window_y)); + return true; +} + +} // namespace views diff --git a/ui/views/mouse_watcher_view_host.cc b/ui/views/mouse_watcher_view_host.cc index 1d420fa..54412cf 100644 --- a/ui/views/mouse_watcher_view_host.cc +++ b/ui/views/mouse_watcher_view_host.cc @@ -50,7 +50,7 @@ bool MouseWatcherViewHost::IsMouseOverWindow() { return false; return gfx::Screen::GetScreenFor(widget->GetNativeView())-> - GetWindowAtCursorScreenPoint() == widget->GetNativeWindow(); + GetWindowUnderCursor() == widget->GetNativeWindow(); } } // namespace views diff --git a/ui/views/views.gyp b/ui/views/views.gyp index 5fb9c19..7bf7666 100644 --- a/ui/views/views.gyp +++ b/ui/views/views.gyp @@ -275,6 +275,9 @@ 'drag_controller.h', 'drag_utils.cc', 'drag_utils.h', + 'event_utils.h', + 'event_utils_aura.cc', + 'event_utils_win.cc', 'focus/accelerator_handler.h', 'focus/accelerator_handler_aura.cc', 'focus/accelerator_handler_win.cc', diff --git a/ui/views/widget/desktop_aura/desktop_screen_x11.cc b/ui/views/widget/desktop_aura/desktop_screen_x11.cc index a462da7..e581b83 100644 --- a/ui/views/widget/desktop_aura/desktop_screen_x11.cc +++ b/ui/views/widget/desktop_aura/desktop_screen_x11.cc @@ -38,7 +38,9 @@ class DesktopScreenX11 : public gfx::Screen { // Overridden from gfx::Screen: virtual bool IsDIPEnabled() OVERRIDE; virtual gfx::Point GetCursorScreenPoint() OVERRIDE; - virtual gfx::NativeWindow GetWindowAtCursorScreenPoint() OVERRIDE; + virtual gfx::NativeWindow GetWindowUnderCursor() OVERRIDE; + virtual gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) + OVERRIDE; virtual int GetNumDisplays() const OVERRIDE; virtual std::vector<gfx::Display> GetAllDisplays() const OVERRIDE; virtual gfx::Display GetDisplayNearestWindow( @@ -90,12 +92,18 @@ gfx::Point DesktopScreenX11::GetCursorScreenPoint() { return gfx::Point(root_x, root_y); } -gfx::NativeWindow DesktopScreenX11::GetWindowAtCursorScreenPoint() { +gfx::NativeWindow DesktopScreenX11::GetWindowUnderCursor() { // TODO(erg): Implement using the discussion at // http://codereview.chromium.org/10279005/ return NULL; } +gfx::NativeWindow DesktopScreenX11::GetWindowAtScreenPoint( + const gfx::Point& point) { + NOTIMPLEMENTED(); + return NULL; +} + int DesktopScreenX11::GetNumDisplays() const { // TODO(erg): Figure this out with oshima or piman because I have no clue // about the XRandR implications here. diff --git a/ui/views/win/hwnd_message_handler.h b/ui/views/win/hwnd_message_handler.h index 8ae4619..80ad4aa 100644 --- a/ui/views/win/hwnd_message_handler.h +++ b/ui/views/win/hwnd_message_handler.h @@ -290,8 +290,8 @@ class VIEWS_EXPORT HWNDMessageHandler : MSG_WM_CREATE(OnCreate) MSG_WM_DESTROY(OnDestroy) MSG_WM_DISPLAYCHANGE(OnDisplayChange) - MSG_WM_ERASEBKGND(OnEraseBkgnd) MSG_WM_ENTERSIZEMOVE(OnEnterSizeMove) + MSG_WM_ERASEBKGND(OnEraseBkgnd) MSG_WM_EXITSIZEMOVE(OnExitSizeMove) MSG_WM_GETMINMAXINFO(OnGetMinMaxInfo) MSG_WM_INITMENU(OnInitMenu) @@ -311,8 +311,8 @@ class VIEWS_EXPORT HWNDMessageHandler : MSG_WM_SIZE(OnSize) MSG_WM_SYSCOMMAND(OnSysCommand) MSG_WM_THEMECHANGED(OnThemeChanged) - MSG_WM_WINDOWPOSCHANGING(OnWindowPosChanging) MSG_WM_WINDOWPOSCHANGED(OnWindowPosChanged) + MSG_WM_WINDOWPOSCHANGING(OnWindowPosChanging) END_MSG_MAP() // Message Handlers. |