diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-21 16:32:50 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-21 16:32:50 +0000 |
commit | fdbafc367cea40b38b2e7a0424242e73979ca12f (patch) | |
tree | b6ac57ad80b2200fddc7e5aac4b5a51c9069ee99 /ui/aura | |
parent | 37c645b3b3642a224ebc910cc24a095d53bbad1b (diff) | |
download | chromium_src-fdbafc367cea40b38b2e7a0424242e73979ca12f.zip chromium_src-fdbafc367cea40b38b2e7a0424242e73979ca12f.tar.gz chromium_src-fdbafc367cea40b38b2e7a0424242e73979ca12f.tar.bz2 |
Wires up mouse capture code for aura.
BUG=none
TEST=none
R=ben@chromium.org
Review URL: http://codereview.chromium.org/7976020
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@102115 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/aura')
-rw-r--r-- | ui/aura/root_window.cc | 49 | ||||
-rw-r--r-- | ui/aura/root_window.h | 21 | ||||
-rw-r--r-- | ui/aura/window.cc | 42 | ||||
-rw-r--r-- | ui/aura/window.h | 20 | ||||
-rw-r--r-- | ui/aura/window_delegate.h | 3 | ||||
-rw-r--r-- | ui/aura/window_unittest.cc | 81 |
6 files changed, 203 insertions, 13 deletions
diff --git a/ui/aura/root_window.cc b/ui/aura/root_window.cc index f6b6b02..f4b0c29 100644 --- a/ui/aura/root_window.cc +++ b/ui/aura/root_window.cc @@ -17,7 +17,8 @@ namespace internal { RootWindow::RootWindow() : Window(NULL), mouse_pressed_handler_(NULL), - ALLOW_THIS_IN_INITIALIZER_LIST(focus_manager_(new FocusManager(this))) { + ALLOW_THIS_IN_INITIALIZER_LIST(focus_manager_(new FocusManager(this))), + capture_window_(NULL) { set_name(ASCIIToUTF16("RootWindow")); } @@ -25,7 +26,8 @@ RootWindow::~RootWindow() { } bool RootWindow::HandleMouseEvent(const MouseEvent& event) { - Window* target = mouse_pressed_handler_; + Window* target = + mouse_pressed_handler_ ? mouse_pressed_handler_ : capture_window_; if (!target) target = GetEventHandlerForPoint(event.location()); if (event.type() == ui::ET_MOUSE_PRESSED && !mouse_pressed_handler_) @@ -48,9 +50,52 @@ bool RootWindow::HandleKeyEvent(const KeyEvent& event) { return false; } +void RootWindow::SetCapture(Window* window) { + if (capture_window_ == window) + return; + + if (capture_window_ && capture_window_->delegate()) + capture_window_->delegate()->OnCaptureLost(); + capture_window_ = window; + + if (capture_window_ && mouse_pressed_handler_) { + // Make all subsequent mouse events go to the capture window. We shouldn't + // need to send an event here as OnCaptureLost should take care of that. + mouse_pressed_handler_ = capture_window_; + } +} + +void RootWindow::ReleaseCapture(Window* window) { + if (capture_window_ != window) + return; + + if (capture_window_ && capture_window_->delegate()) + capture_window_->delegate()->OnCaptureLost(); + capture_window_ = NULL; +} + +void RootWindow::WindowDestroying(Window* window) { + // Update the FocusManager if the window was focused. + internal::FocusManager* focus_manager = GetFocusManager(); + if (focus_manager && focus_manager->focused_window() == window) + focus_manager->SetFocusedWindow(NULL); + + // When a window is being destroyed it's likely that the WindowDelegate won't + // want events, so we reset the mouse_pressed_handler_ and capture_window_ and + // don't sent it release/capture lost events. + if (mouse_pressed_handler_ == window) + mouse_pressed_handler_ = NULL; + if (capture_window_ == window) + capture_window_ = NULL; +} + FocusManager* RootWindow::GetFocusManager() { return focus_manager_.get(); } +internal::RootWindow* RootWindow::GetRoot() { + return this; +} + } // namespace internal } // namespace aura diff --git a/ui/aura/root_window.h b/ui/aura/root_window.h index d709ce3..5d3de84 100644 --- a/ui/aura/root_window.h +++ b/ui/aura/root_window.h @@ -26,12 +26,33 @@ class RootWindow : public Window { // Handles a key event. Returns true if handled. bool HandleKeyEvent(const KeyEvent& event); + // Sets capture to the specified window. + void SetCapture(Window* window); + + // If |window| has mouse capture, the current capture window is set to NULL. + void ReleaseCapture(Window* window); + + // Returns the window that has mouse capture. + Window* capture_window() { return capture_window_; } + + // Invoked when a child window is destroyed. Cleans up any references to the + // Window. + void WindowDestroying(Window* window); + + // Current handler for mouse events. + Window* mouse_pressed_handler() { return mouse_pressed_handler_; } + // Overridden from Window: virtual FocusManager* GetFocusManager() OVERRIDE; + protected: + // Overridden from Window: + virtual internal::RootWindow* GetRoot() OVERRIDE; + private: Window* mouse_pressed_handler_; scoped_ptr<FocusManager> focus_manager_; + Window* capture_window_; DISALLOW_COPY_AND_ASSIGN(RootWindow); }; diff --git a/ui/aura/window.cc b/ui/aura/window.cc index 6ccf808..e9d5b30 100644 --- a/ui/aura/window.cc +++ b/ui/aura/window.cc @@ -19,6 +19,8 @@ namespace aura { +using internal::RootWindow; + Window::Window(WindowDelegate* delegate) : delegate_(delegate), visibility_(VISIBILITY_HIDDEN), @@ -32,12 +34,10 @@ Window::~Window() { if (delegate_) delegate_->OnWindowDestroying(); - // Update the FocusManager in case we were focused. This must be done before - // we are removed from the hierarchy otherwise we won't be able to find the - // FocusManager. - internal::FocusManager* focus_manager = GetFocusManager(); - if (focus_manager && focus_manager->focused_window() == this) - focus_manager->SetFocusedWindow(NULL); + // Let the root know so that it can remove any references to us. + RootWindow* root = GetRoot(); + if (root) + root->WindowDestroying(this); // Then destroy the children. while (!children_.empty()) { @@ -70,6 +70,8 @@ void Window::SetVisibility(Visibility visibility) { layer_->set_visible(visibility_ != VISIBILITY_HIDDEN); if (layer_->visible()) SchedulePaint(); + if (visibility_ != VISIBILITY_SHOWN) + ReleaseCapture(); } void Window::SetLayoutManager(LayoutManager* layout_manager) { @@ -199,6 +201,34 @@ internal::FocusManager* Window::GetFocusManager() { return parent_ ? parent_->GetFocusManager() : NULL; } +void Window::SetCapture() { + if (visibility_ != VISIBILITY_SHOWN) + return; + + RootWindow* root = GetRoot(); + if (!root) + return; + + root->SetCapture(this); +} + +void Window::ReleaseCapture() { + RootWindow* root = GetRoot(); + if (!root) + return; + + root->ReleaseCapture(this); +} + +bool Window::HasCapture() { + RootWindow* root = GetRoot(); + return root && root->capture_window() == this; +} + +internal::RootWindow* Window::GetRoot() { + return parent_ ? parent_->GetRoot() : NULL; +} + void Window::SchedulePaint() { SchedulePaintInRect(gfx::Rect(0, 0, bounds_.width(), bounds_.height())); } diff --git a/ui/aura/window.h b/ui/aura/window.h index 15573f4..17971d7 100644 --- a/ui/aura/window.h +++ b/ui/aura/window.h @@ -25,14 +25,15 @@ class Layer; namespace aura { class Desktop; +class EventFilter; class KeyEvent; class LayoutManager; class MouseEvent; class WindowDelegate; -class EventFilter; namespace internal { class FocusManager; +class RootWindow; } // Aura window implementation. Interesting events are sent to the @@ -140,10 +141,21 @@ class AURA_EXPORT Window : public ui::LayerDelegate { void set_user_data(void* user_data) { user_data_ = user_data; } void* user_data() const { return user_data_; } - private: - // If SchedulePaint has been invoked on the Window the delegate is notified. - void UpdateLayerCanvas(); + // Does a mouse capture on the window. This does nothing if the window isn't + // showing (VISIBILITY_SHOWN) or isn't contained in a valid window hierarchy. + void SetCapture(); + + // Releases a mouse capture. + void ReleaseCapture(); + // Returns true if this window has a mouse capture. + bool HasCapture(); + + protected: + // Returns the RootWindow or NULL if we don't yet have a RootWindow. + virtual internal::RootWindow* GetRoot(); + + private: // Schedules a paint for the Window's entire bounds. void SchedulePaint(); diff --git a/ui/aura/window_delegate.h b/ui/aura/window_delegate.h index 956763b..8a0c19f 100644 --- a/ui/aura/window_delegate.h +++ b/ui/aura/window_delegate.h @@ -36,6 +36,9 @@ class WindowDelegate { virtual bool OnMouseEvent(MouseEvent* event) = 0; + // Invoked when mouse capture is lost on the window. + virtual void OnCaptureLost() = 0; + // Asks the delegate to paint window contents into the supplied canvas. virtual void OnPaint(gfx::Canvas* canvas) = 0; diff --git a/ui/aura/window_unittest.cc b/ui/aura/window_unittest.cc index 2c8918f..59d5dd1 100644 --- a/ui/aura/window_unittest.cc +++ b/ui/aura/window_unittest.cc @@ -42,6 +42,7 @@ class WindowDelegateImpl : public WindowDelegate { return HTCLIENT; } virtual bool OnMouseEvent(MouseEvent* event) OVERRIDE { return false; } + virtual void OnCaptureLost() OVERRIDE {} virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {} virtual void OnWindowDestroying() OVERRIDE {} virtual void OnWindowDestroyed() OVERRIDE {} @@ -106,6 +107,34 @@ class ChildWindowDelegateImpl : public DestroyTrackingDelegateImpl { DISALLOW_COPY_AND_ASSIGN(ChildWindowDelegateImpl); }; +// Used in verifying mouse capture. +class CaptureWindowDelegateImpl : public WindowDelegateImpl { + public: + explicit CaptureWindowDelegateImpl() + : capture_lost_count_(0), + mouse_event_count_(0) { + } + + int capture_lost_count() const { return capture_lost_count_; } + void set_capture_lost_count(int value) { capture_lost_count_ = value; } + int mouse_event_count() const { return mouse_event_count_; } + void set_mouse_event_count(int value) { mouse_event_count_ = value; } + + virtual bool OnMouseEvent(MouseEvent* event) OVERRIDE { + mouse_event_count_++; + return false; + } + virtual void OnCaptureLost() OVERRIDE { + capture_lost_count_++; + } + + private: + int capture_lost_count_; + int mouse_event_count_; + + DISALLOW_COPY_AND_ASSIGN(CaptureWindowDelegateImpl); +}; + // A simple WindowDelegate implementation for these tests. It owns itself // (deletes itself when the Window it is attached to is destroyed). class TestWindowDelegate : public WindowDelegateImpl { @@ -305,6 +334,56 @@ TEST_F(WindowTest, MoveChildToFront) { EXPECT_EQ(child2.layer(), parent.layer()->children()[0]); } +// Various destruction assertions. +TEST_F(WindowTest, CaptureTests) { + Desktop* desktop = Desktop::GetInstance(); + CaptureWindowDelegateImpl delegate; + scoped_ptr<Window> window(CreateTestWindowWithDelegate( + &delegate, 0, gfx::Rect(0, 0, 20, 20), NULL)); + EXPECT_FALSE(window->HasCapture()); + + // Do a capture. + window->SetCapture(); + EXPECT_TRUE(window->HasCapture()); + EXPECT_EQ(0, delegate.capture_lost_count()); + + desktop->OnMouseEvent(MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(50, 50), + ui::EF_LEFT_BUTTON_DOWN)); + EXPECT_EQ(1, delegate.mouse_event_count()); + desktop->OnMouseEvent(MouseEvent(ui::ET_MOUSE_RELEASED, gfx::Point(50, 50), + ui::EF_LEFT_BUTTON_DOWN)); + EXPECT_EQ(2, delegate.mouse_event_count()); + delegate.set_mouse_event_count(0); + + window->ReleaseCapture(); + EXPECT_FALSE(window->HasCapture()); + EXPECT_EQ(1, delegate.capture_lost_count()); + + desktop->OnMouseEvent(MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(50, 50), + ui::EF_LEFT_BUTTON_DOWN)); + EXPECT_EQ(0, delegate.mouse_event_count()); +} + +// Verifies capture is reset when a window is destroyed. +TEST_F(WindowTest, ReleaseCaptureOnDestroy) { + Desktop* desktop = Desktop::GetInstance(); + RootWindow* root = static_cast<RootWindow*>(desktop->window()); + CaptureWindowDelegateImpl delegate; + scoped_ptr<Window> window(CreateTestWindowWithDelegate( + &delegate, 0, gfx::Rect(0, 0, 20, 20), NULL)); + EXPECT_FALSE(window->HasCapture()); + + // Do a capture. + window->SetCapture(); + EXPECT_TRUE(window->HasCapture()); + + // Destroy the window. + window.reset(); + + // Make sure the root doesn't reference the window anymore. + EXPECT_EQ(NULL, root->mouse_pressed_handler()); + EXPECT_EQ(NULL, root->capture_window()); +} + } // namespace internal } // namespace aura - |