diff options
-rw-r--r-- | chrome/browser/ui/views/tabs/tab_drag_controller.cc | 10 | ||||
-rw-r--r-- | ui/views/view.cc | 10 | ||||
-rw-r--r-- | ui/views/view.h | 5 | ||||
-rw-r--r-- | ui/views/view_unittest.cc | 13 | ||||
-rw-r--r-- | ui/views/widget/native_widget_aura.cc | 5 | ||||
-rw-r--r-- | ui/views/widget/native_widget_aura_unittest.cc | 131 | ||||
-rw-r--r-- | ui/views/widget/native_widget_private.h | 3 | ||||
-rw-r--r-- | ui/views/widget/native_widget_win.cc | 7 | ||||
-rw-r--r-- | ui/views/widget/root_view.cc | 58 | ||||
-rw-r--r-- | ui/views/widget/root_view.h | 2 | ||||
-rw-r--r-- | ui/views/widget/widget.cc | 33 | ||||
-rw-r--r-- | ui/views/widget/widget.h | 15 |
12 files changed, 250 insertions, 42 deletions
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc index ac75312..c3e7ea9 100644 --- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc +++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc @@ -778,7 +778,7 @@ TabDragController::DragBrowserToNewTabStrip( target_tabstrip->OwnDragController(this); // Disable animations so that we don't see a close animation on aero. browser_widget->SetVisibilityChangedAnimationsEnabled(false); - browser_widget->ReleaseMouseCapture(); + browser_widget->ReleaseCapture(); // EndMoveLoop is going to snap the window back to its original location. // Hide it so users don't see this. browser_widget->Hide(); @@ -1118,7 +1118,7 @@ void TabDragController::Attach(TabStrip* attached_tabstrip, // window has mouse capture. This is important so that if activation changes // the drag isn't prematurely canceled. if (detach_into_browser_) { - attached_tabstrip_->GetWidget()->SetMouseCapture(attached_tabstrip_); + attached_tabstrip_->GetWidget()->SetCapture(attached_tabstrip_); attached_tabstrip_->OwnDragController(this); } @@ -1136,7 +1136,7 @@ void TabDragController::Detach() { // reattach ownership is transfered. if (detach_into_browser_) { attached_tabstrip_->ReleaseDragController(); - attached_tabstrip_->GetWidget()->ReleaseMouseCapture(); + attached_tabstrip_->GetWidget()->ReleaseCapture(); } mouse_move_direction_ = kMovedMouseLeft | kMovedMouseRight; @@ -1253,7 +1253,7 @@ void TabDragController::RunMoveLoop() { // destroying the drag loop. Release mouse capture ourself before this while // the DragController isn't owned by the TabStrip. attached_tabstrip_->ReleaseDragController(); - attached_tabstrip_->GetWidget()->ReleaseMouseCapture(); + attached_tabstrip_->GetWidget()->ReleaseCapture(); attached_tabstrip_->OwnDragController(this); views::Widget::MoveLoopResult result = move_loop_widget_->RunMoveLoop(); content::NotificationService::current()->Notify( @@ -1284,7 +1284,7 @@ void TabDragController::RunMoveLoop() { tab_strip_to_attach_to_after_exit_ = NULL; } DCHECK(attached_tabstrip_); - attached_tabstrip_->GetWidget()->SetMouseCapture(attached_tabstrip_); + attached_tabstrip_->GetWidget()->SetCapture(attached_tabstrip_); } else if (active_) { EndDrag(result == views::Widget::MOVE_LOOP_CANCELED); } diff --git a/ui/views/view.cc b/ui/views/view.cc index 45fbf7c..631deec 100644 --- a/ui/views/view.cc +++ b/ui/views/view.cc @@ -829,8 +829,8 @@ ui::GestureStatus View::OnGestureEvent(const GestureEvent& event) { return ui::GESTURE_STATUS_UNKNOWN; } -void View::SetMouseHandler(View *new_mouse_handler) { - // It is valid for new_mouse_handler to be NULL +void View::SetMouseHandler(View* new_mouse_handler) { + // |new_mouse_handler| may be NULL. if (parent_) parent_->SetMouseHandler(new_mouse_handler); } @@ -856,12 +856,6 @@ InputMethod* View::GetInputMethod() { return widget ? widget->GetInputMethod() : NULL; } -ui::GestureStatus View::ProcessGestureEvent(const GestureEvent& event) { - // TODO(Gajen): Implement a grab scheme similar to as as is found in - // MousePressed. - return OnGestureEvent(event); -} - // Accelerators ---------------------------------------------------------------- void View::AddAccelerator(const ui::Accelerator& accelerator) { diff --git a/ui/views/view.h b/ui/views/view.h index 3f59881..0fd781b 100644 --- a/ui/views/view.h +++ b/ui/views/view.h @@ -600,6 +600,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, // Note: if the mouse handler is no longer connected to a // view hierarchy, events won't be sent. // + // TODO(sky): rename this. virtual void SetMouseHandler(View* new_mouse_handler); // Invoked when a key is pressed or released. @@ -1273,10 +1274,6 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, // of OnTouchEvent. ui::TouchStatus ProcessTouchEvent(const TouchEvent& event); - // RootView will invoke this with incoming GestureEvents. Returns the result - // of OnGestureEvent. - ui::GestureStatus ProcessGestureEvent(const GestureEvent& event); - // Accelerators -------------------------------------------------------------- // Registers this view's keyboard accelerators that are not registered to diff --git a/ui/views/view_unittest.cc b/ui/views/view_unittest.cc index 8acd0bb..70e6cee 100644 --- a/ui/views/view_unittest.cc +++ b/ui/views/view_unittest.cc @@ -602,6 +602,10 @@ TEST_F(ViewTest, GestureEvent) { EXPECT_EQ(gfx::Point(10, 10), v2->location_); EXPECT_EQ(ui::ET_UNKNOWN, v1->last_gesture_event_type_); + // Simulate an up so that RootView is no longer targetting |v3|. + GestureEventForTest g1_up(ui::ET_GESTURE_TAP_UP, 110, 110, 0); + root->OnGestureEvent(g1_up); + v1->Reset(); v2->Reset(); v3->Reset(); @@ -613,6 +617,15 @@ TEST_F(ViewTest, GestureEvent) { EXPECT_EQ(gfx::Point(80, 80), v1->location_); EXPECT_EQ(ui::ET_UNKNOWN, v2->last_gesture_event_type_); + // Send event |g1| again. Even though the coordinates target |v3| it should go + // to |v1| as that is the view the touch was initially down on. + v1->last_gesture_event_type_ = ui::ET_UNKNOWN; + v3->last_gesture_event_type_ = ui::ET_UNKNOWN; + root->OnGestureEvent(g1); + EXPECT_EQ(ui::ET_GESTURE_TAP, v1->last_gesture_event_type_); + EXPECT_EQ(ui::ET_UNKNOWN, v3->last_gesture_event_type_); + EXPECT_EQ("110,110", v1->location_.ToString()); + widget->CloseNow(); } diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc index be27dc0e0..67254d1 100644 --- a/ui/views/widget/native_widget_aura.cc +++ b/ui/views/widget/native_widget_aura.cc @@ -985,5 +985,10 @@ bool NativeWidgetPrivate::IsMouseButtonDown() { return aura::Env::GetInstance()->is_mouse_button_down(); } +// static +bool NativeWidgetPrivate::IsTouchDown() { + return aura::Env::GetInstance()->is_touch_down(); +} + } // namespace internal } // namespace views diff --git a/ui/views/widget/native_widget_aura_unittest.cc b/ui/views/widget/native_widget_aura_unittest.cc index ca10d97..baae5310 100644 --- a/ui/views/widget/native_widget_aura_unittest.cc +++ b/ui/views/widget/native_widget_aura_unittest.cc @@ -5,10 +5,13 @@ #include "ui/views/widget/native_widget_aura.h" #include "base/basictypes.h" +#include "base/command_line.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/aura/aura_switches.h" #include "ui/aura/env.h" +#include "ui/aura/event.h" #include "ui/aura/layout_manager.h" #include "ui/aura/monitor_manager.h" #include "ui/aura/root_window.h" @@ -16,6 +19,7 @@ #include "ui/aura/test/aura_test_helper.h" #include "ui/aura/window.h" #include "ui/gfx/screen.h" +#include "ui/views/layout/fill_layout.h" #include "ui/views/widget/root_view.h" #include "ui/views/widget/widget_delegate.h" @@ -177,5 +181,132 @@ TEST_F(NativeWidgetAuraTest, GetClientAreaScreenBounds) { EXPECT_EQ(400, client_bounds.height()); } +namespace { + +// View subclass that tracks whether it has gotten a gesture event. +class GestureTrackingView : public views::View { + public: + GestureTrackingView() + : got_gesture_event_(false), + consume_gesture_event_(true) {} + + void set_consume_gesture_event(bool value) { + consume_gesture_event_ = value; + } + + void clear_got_gesture_event() { + got_gesture_event_ = false; + } + bool got_gesture_event() const { + return got_gesture_event_; + } + + // View overrides: + virtual ui::GestureStatus OnGestureEvent(const GestureEvent& event) OVERRIDE { + got_gesture_event_ = true; + return consume_gesture_event_ ? ui::GESTURE_STATUS_CONSUMED : + ui::GESTURE_STATUS_UNKNOWN; + } + + private: + // Was OnGestureEvent() invoked? + bool got_gesture_event_; + + // Dictates what OnGestureEvent() returns. + bool consume_gesture_event_; + + DISALLOW_COPY_AND_ASSIGN(GestureTrackingView); +}; + +} // namespace + +// Verifies a capture isn't set on touch press and that the view that gets +// the press gets the release. +TEST_F(NativeWidgetAuraTest, DontCaptureOnGesture) { + CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kAuraDisableMouseEventsFromTouch); + // Create two views (both sized the same). |child| is configured not to + // consume the gesture event. + GestureTrackingView* view = new GestureTrackingView(); + GestureTrackingView* child = new GestureTrackingView(); + child->set_consume_gesture_event(false); + view->SetLayoutManager(new FillLayout); + view->AddChildView(child); + scoped_ptr<TestWidget> widget(new TestWidget()); + Widget::InitParams params(Widget::InitParams::TYPE_WINDOW); + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.bounds = gfx::Rect(0, 0, 100, 200); + widget->Init(params); + widget->SetContentsView(view); + widget->Show(); + + aura::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(41, 51), 1, + base::TimeDelta()); + root_window()->DispatchTouchEvent(&press); + // Both views should get the press. + EXPECT_TRUE(view->got_gesture_event()); + EXPECT_TRUE(child->got_gesture_event()); + view->clear_got_gesture_event(); + child->clear_got_gesture_event(); + // Touch events should not automatically grab capture. + EXPECT_FALSE(widget->HasCapture()); + + // Release touch. Only |view| should get the release since that it consumed + // the press. + aura::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(250, 251), 1, + base::TimeDelta()); + root_window()->DispatchTouchEvent(&release); + EXPECT_TRUE(view->got_gesture_event()); + EXPECT_FALSE(child->got_gesture_event()); + view->clear_got_gesture_event(); + + // Work around for bug in NativeWidgetAura. + // TODO: fix bug and remove this. + widget->Close(); +} + +TEST_F(NativeWidgetAuraTest, ReleaseCaptureOnTouchRelease) { + CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kAuraDisableMouseEventsFromTouch); + GestureTrackingView* view = new GestureTrackingView(); + scoped_ptr<TestWidget> widget(new TestWidget()); + Widget::InitParams params(Widget::InitParams::TYPE_WINDOW); + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.bounds = gfx::Rect(0, 0, 100, 200); + widget->Init(params); + widget->SetContentsView(view); + widget->Show(); + + aura::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(41, 51), 1, + base::TimeDelta()); + root_window()->DispatchTouchEvent(&press); + EXPECT_TRUE(view->got_gesture_event()); + view->clear_got_gesture_event(); + // Set the capture. + widget->SetCapture(view); + EXPECT_TRUE(widget->HasCapture()); + + // Press outside the bounds of the widget, it should still go to |view| since + // it set the capture. + aura::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(241, 251), 2, + base::TimeDelta()); + root_window()->DispatchTouchEvent(&press2); + EXPECT_TRUE(view->got_gesture_event()); + view->clear_got_gesture_event(); + EXPECT_TRUE(widget->HasCapture()); + + // Generate a release, this should trigger releasing capture. + aura::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(241, 251), 2, + base::TimeDelta()); + root_window()->DispatchTouchEvent(&release); + EXPECT_TRUE(view->got_gesture_event()); + view->clear_got_gesture_event(); + EXPECT_FALSE(widget->HasCapture()); + + // Work around for bug in NativeWidgetAura. + // TODO: fix bug and remove this. + widget->Close(); +} + } // namespace } // namespace views diff --git a/ui/views/widget/native_widget_private.h b/ui/views/widget/native_widget_private.h index 7eb8606..c4caa17 100644 --- a/ui/views/widget/native_widget_private.h +++ b/ui/views/widget/native_widget_private.h @@ -68,6 +68,9 @@ class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget, // Returns true if any mouse button is currently down. static bool IsMouseButtonDown(); + // Returns true if any touch device is currently down. + static bool IsTouchDown(); + // Initializes the NativeWidget. virtual void InitNativeWidget(const Widget::InitParams& params) = 0; diff --git a/ui/views/widget/native_widget_win.cc b/ui/views/widget/native_widget_win.cc index 117e99a..a9499f3 100644 --- a/ui/views/widget/native_widget_win.cc +++ b/ui/views/widget/native_widget_win.cc @@ -2723,6 +2723,13 @@ bool NativeWidgetPrivate::IsMouseButtonDown() { (GetKeyState(VK_XBUTTON2) & 0x80); } +// static +bool NativeWidgetPrivate::IsTouchDown() { + // This currently isn't necessary because we're not generating touch events on + // windows. When we do, this will need to be updated. + return false; +} + } // namespace internal } // namespace views diff --git a/ui/views/widget/root_view.cc b/ui/views/widget/root_view.cc index f2025c6..6b6c14b 100644 --- a/ui/views/widget/root_view.cc +++ b/ui/views/widget/root_view.cc @@ -66,7 +66,7 @@ RootView::RootView(Widget* widget) last_mouse_event_x_(-1), last_mouse_event_y_(-1), touch_pressed_handler_(NULL), - gesture_handling_view_(NULL), + gesture_handler_(NULL), ALLOW_THIS_IN_INITIALIZER_LIST(focus_search_(this, false, false)), focus_traversable_parent_(NULL), focus_traversable_parent_view_(NULL) { @@ -300,16 +300,24 @@ void RootView::OnMouseReleased(const MouseEvent& event) { } void RootView::OnMouseCaptureLost() { - if (mouse_pressed_handler_) { + // TODO: this likely needs to reset touch handler too. + + if (mouse_pressed_handler_ || gesture_handler_) { // Synthesize a release event for UpdateCursor. - MouseEvent release_event(ui::ET_MOUSE_RELEASED, last_mouse_event_x_, - last_mouse_event_y_, last_mouse_event_flags_); - UpdateCursor(release_event); + if (mouse_pressed_handler_) { + MouseEvent release_event(ui::ET_MOUSE_RELEASED, last_mouse_event_x_, + last_mouse_event_y_, last_mouse_event_flags_); + UpdateCursor(release_event); + } // We allow the view to delete us from OnMouseCaptureLost. As such, // configure state such that we're done first, then call View. View* mouse_pressed_handler = mouse_pressed_handler_; + View* gesture_handler = gesture_handler_; SetMouseHandler(NULL); - mouse_pressed_handler->OnMouseCaptureLost(); + if (mouse_pressed_handler) + mouse_pressed_handler->OnMouseCaptureLost(); + else + gesture_handler->OnMouseCaptureLost(); // WARNING: we may have been deleted. } } @@ -374,6 +382,10 @@ bool RootView::OnMouseWheel(const MouseWheelEvent& event) { } ui::TouchStatus RootView::OnTouchEvent(const TouchEvent& event) { + // TODO: this looks all wrong. On a TOUCH_PRESSED we should figure out the + // view and target that view with all touches with the same id until the + // release (or keep it if captured). + TouchEvent e(event, this); // If touch_pressed_handler_ is non null, we are currently processing @@ -433,23 +445,33 @@ ui::GestureStatus RootView::OnGestureEvent(const GestureEvent& event) { GestureEvent e(event, this); ui::GestureStatus status = ui::GESTURE_STATUS_UNKNOWN; + if (gesture_handler_) { + // Allow |gesture_handler_| to delete this during processing. + View* handler = gesture_handler_; + GestureEvent handler_event(event, this, gesture_handler_); + // TODO: should only do this for the last touch id that goes up. + if (event.type() == ui::ET_GESTURE_TAP_UP) + gesture_handler_ = NULL; + return handler->OnGestureEvent(handler_event); + } + // Walk up the tree until we find a view that wants the gesture event. - for (gesture_handling_view_ = GetEventHandlerForPoint(e.location()); - gesture_handling_view_ && (gesture_handling_view_ != this); - gesture_handling_view_ = gesture_handling_view_->parent()) { - if (!gesture_handling_view_->enabled()) { + for (gesture_handler_ = GetEventHandlerForPoint(e.location()); + gesture_handler_ && (gesture_handler_ != this); + gesture_handler_ = gesture_handler_->parent()) { + if (!gesture_handler_->enabled()) { // Disabled views eat events but are treated as not handled. return ui::GESTURE_STATUS_UNKNOWN; } // See if this view wants to handle the Gesture. - GestureEvent gesture_event(e, this, gesture_handling_view_); - status = gesture_handling_view_->ProcessGestureEvent(gesture_event); + GestureEvent gesture_event(e, this, gesture_handler_); + status = gesture_handler_->OnGestureEvent(gesture_event); // The view could have removed itself from the tree when handling // OnGestureEvent(). So handle as per OnMousePressed. NB: we // assume that the RootView itself cannot be so removed. - if (!gesture_handling_view_) + if (!gesture_handler_) return ui::GESTURE_STATUS_UNKNOWN; // The gesture event wasn't processed. Go up the view hierarchy and @@ -461,13 +483,17 @@ ui::GestureStatus RootView::OnGestureEvent(const GestureEvent& event) { else return ui::GESTURE_STATUS_UNKNOWN; } + + gesture_handler_ = NULL; + return status; } -void RootView::SetMouseHandler(View *new_mh) { +void RootView::SetMouseHandler(View* new_mh) { // If we're clearing the mouse handler, clear explicit_mouse_handler_ as well. explicit_mouse_handler_ = (new_mh != NULL); mouse_pressed_handler_ = new_mh; + gesture_handler_ = new_mh; drag_info_.Reset(); } @@ -492,8 +518,8 @@ void RootView::ViewHierarchyChanged(bool is_add, View* parent, View* child) { mouse_move_handler_ = NULL; if (touch_pressed_handler_ == child) touch_pressed_handler_ = NULL; - if (gesture_handling_view_ == child) - gesture_handling_view_ = NULL; + if (gesture_handler_ == child) + gesture_handler_ = NULL; } } diff --git a/ui/views/widget/root_view.h b/ui/views/widget/root_view.h index 7ae1316..9ffd601 100644 --- a/ui/views/widget/root_view.h +++ b/ui/views/widget/root_view.h @@ -170,7 +170,7 @@ class VIEWS_EXPORT RootView : public View, public FocusTraversable { View* touch_pressed_handler_; // The view currently handling gesture events. - View* gesture_handling_view_; + View* gesture_handler_; // Focus --------------------------------------------------------------------- diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc index e238c67..7626e96 100644 --- a/ui/views/widget/widget.cc +++ b/ui/views/widget/widget.cc @@ -169,6 +169,7 @@ Widget::Widget() native_widget_initialized_(false), native_widget_destroyed_(false), is_mouse_button_pressed_(false), + is_touch_down_(false), last_mouse_event_was_move_(false) { } @@ -824,18 +825,25 @@ NativeWidget* Widget::native_widget() { return native_widget_; } -void Widget::SetMouseCapture(views::View* view) { - is_mouse_button_pressed_ = true; +void Widget::SetCapture(views::View* view) { + if (internal::NativeWidgetPrivate::IsMouseButtonDown()) + is_mouse_button_pressed_ = true; + if (internal::NativeWidgetPrivate::IsTouchDown()) + is_touch_down_ = true; root_view_->SetMouseHandler(view); if (!native_widget_->HasCapture()) native_widget_->SetCapture(); } -void Widget::ReleaseMouseCapture() { +void Widget::ReleaseCapture() { if (native_widget_->HasCapture()) native_widget_->ReleaseCapture(); } +bool Widget::HasCapture() { + return native_widget_->HasCapture(); +} + const Event* Widget::GetCurrentEvent() { return event_stack_.empty() ? NULL : event_stack_.top()->event(); } @@ -1087,8 +1095,9 @@ bool Widget::OnMouseEvent(const MouseEvent& event) { } void Widget::OnMouseCaptureLost() { - if (is_mouse_button_pressed_) + if (is_mouse_button_pressed_ || is_touch_down_) GetRootView()->OnMouseCaptureLost(); + is_touch_down_ = false; is_mouse_button_pressed_ = false; } @@ -1099,6 +1108,22 @@ ui::TouchStatus Widget::OnTouchEvent(const TouchEvent& event) { ui::GestureStatus Widget::OnGestureEvent(const GestureEvent& event) { ScopedEvent scoped(this, event); + switch (event.type()) { + case ui::ET_GESTURE_TAP_DOWN: + is_touch_down_ = true; + // We explicitly don't capture here. Not capturing enables multiple + // widgets to get tap events at the same time. Views (such as tab + // dragging) may explicitly capture. + break; + + case ui::ET_GESTURE_TAP_UP: + is_touch_down_ = false; + ReleaseCapture(); + break; + + default: + break; + } return GetRootView()->OnGestureEvent(event); } diff --git a/ui/views/widget/widget.h b/ui/views/widget/widget.h index c754e95..e0ab7bf 100644 --- a/ui/views/widget/widget.h +++ b/ui/views/widget/widget.h @@ -566,11 +566,15 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, return native_widget_; } - // Sets mouse capture on the specified view. - void SetMouseCapture(views::View* view); + // Sets capture to the specified view. This makes it so that all mouse, touch + // and gesture events go to |view|. + void SetCapture(views::View* view); - // Releases mouse capture. - void ReleaseMouseCapture(); + // Releases capture. + void ReleaseCapture(); + + // Returns true if the widget has capture. + bool HasCapture(); // Returns the current event being processed. If there are multiple events // being processed at the same time (e.g. one event triggers another event), @@ -773,6 +777,9 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, // If true, the mouse is currently down. bool is_mouse_button_pressed_; + // If true, a touch device is currently down. + bool is_touch_down_; + // TODO(beng): Remove NativeWidgetGtk's dependence on these: // The following are used to detect duplicate mouse move events and not // deliver them. Displaying a window may result in the system generating |