diff options
author | jamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-14 04:04:35 +0000 |
---|---|---|
committer | jamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-14 04:04:35 +0000 |
commit | bbb59f8114092ee4761598966c5ec8c3fb1c9d68 (patch) | |
tree | 02fad3de3ce27f3832caadfd20a45b4c7f78aba8 | |
parent | 2ebf05cb61a5019289a982ba2fd2318debe0d02b (diff) | |
download | chromium_src-bbb59f8114092ee4761598966c5ec8c3fb1c9d68.zip chromium_src-bbb59f8114092ee4761598966c5ec8c3fb1c9d68.tar.gz chromium_src-bbb59f8114092ee4761598966c5ec8c3fb1c9d68.tar.bz2 |
Reland: Ash: Allow resize along 1 pixel edge inside window content
The mocks call for resize handles to function along a single pixel edge inside the window, overlapping the web content. Refactored aura::Window::set_hit_test_bounds_inset() into SetHitTestBoundsOverride() to make hover/click events along that border pass through to the non-client area of the window frames. This also allows windows to be resized when they are flush against the top/left/right edges of the screen.
BUG=117542
TEST=aura_shell_unittests ShelfLayoutManager, manually resize window from left/right/bottom/top edges
Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=126539
Reverted: http://src.chromium.org/viewvc/chrome?view=rev&revision=126544
Review URL: https://chromiumcodereview.appspot.com/9694012
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@126554 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | ash/launcher/launcher.h | 3 | ||||
-rw-r--r-- | ash/wm/frame_painter.cc | 41 | ||||
-rw-r--r-- | ash/wm/frame_painter.h | 3 | ||||
-rw-r--r-- | ash/wm/shelf_layout_manager.cc | 6 | ||||
-rw-r--r-- | ash/wm/shelf_layout_manager.h | 8 | ||||
-rw-r--r-- | ash/wm/shelf_layout_manager_unittest.cc | 6 | ||||
-rw-r--r-- | chrome/browser/ui/views/frame/browser_frame_aura.cc | 2 | ||||
-rw-r--r-- | chrome/browser/ui/views/tab_contents/native_tab_contents_view_aura.cc | 1 | ||||
-rw-r--r-- | ui/aura/window.cc | 29 | ||||
-rw-r--r-- | ui/aura/window.h | 16 | ||||
-rw-r--r-- | ui/aura/window_unittest.cc | 19 | ||||
-rw-r--r-- | ui/oak/oak_aura_window_display.cc | 4 |
12 files changed, 99 insertions, 39 deletions
diff --git a/ash/launcher/launcher.h b/ash/launcher/launcher.h index 9404d2b..dea112c 100644 --- a/ash/launcher/launcher.h +++ b/ash/launcher/launcher.h @@ -55,8 +55,7 @@ class ASH_EXPORT Launcher { scoped_ptr<LauncherModel> model_; - // Widget hosting the view. May be hidden if we're not using a launcher, - // e.g. Aura compact window mode. + // Widget hosting the view. scoped_ptr<views::Widget> widget_; aura::Window* window_container_; diff --git a/ash/wm/frame_painter.cc b/ash/wm/frame_painter.cc index 9492cfc..f61baad 100644 --- a/ash/wm/frame_painter.cc +++ b/ash/wm/frame_painter.cc @@ -28,8 +28,12 @@ const int kTopThickness = 1; // TODO(jamescook): Border is specified to be a single pixel overlapping // the web content and may need to be built into the shadow layers instead. const int kBorderThickness = 0; -// Number of pixels outside the window frame to look for resize events. -const int kResizeAreaOutsideBounds = 6; +// Ash windows do not have a traditional visible window frame. Window content +// extends to the edge of the window. We consider a small region outside the +// window bounds and an even smaller region overlapping the window to be the +// "non-client" area and use it for resizing. +const int kResizeOutsideBoundsSize = 6; +const int kResizeInsideBoundsSize = 1; // In the window corners, the resize areas don't actually expand bigger, but the // 16 px at the end of each edge triggers diagonal resizing. const int kResizeAreaCornerSize = 16; @@ -137,8 +141,8 @@ void FramePainter::Init(views::Widget* frame, rb.GetImageNamed(IDR_AURA_WINDOW_HEADER_SHADE_RIGHT).ToSkBitmap(); // Ensure we get resize cursors for a few pixels outside our bounds. - frame_->GetNativeWindow()->set_hit_test_bounds_inset( - -kResizeAreaOutsideBounds); + frame_->GetNativeWindow()->SetHitTestBoundsOverride(kResizeOutsideBoundsSize, + kResizeInsideBoundsSize); } gfx::Rect FramePainter::GetBoundsForClientView( @@ -163,13 +167,26 @@ gfx::Rect FramePainter::GetWindowBoundsForClientBounds( int FramePainter::NonClientHitTest(views::NonClientFrameView* view, const gfx::Point& point) { gfx::Rect expanded_bounds = view->bounds(); - expanded_bounds.Inset(-kResizeAreaOutsideBounds, -kResizeAreaOutsideBounds); + expanded_bounds.Inset(-kResizeOutsideBoundsSize, -kResizeOutsideBoundsSize); if (!expanded_bounds.Contains(point)) return HTNOWHERE; // No avatar button. - // Check the client view first, as it overlaps the window caption area. + // Check the frame first, as we allow a small area overlapping the contents + // to be used for resize handles. + bool can_resize = frame_->widget_delegate() ? + frame_->widget_delegate()->CanResize() : + false; + int frame_component = view->GetHTComponentForFrame(point, + kResizeInsideBoundsSize, + kResizeInsideBoundsSize, + kResizeAreaCornerSize, + kResizeAreaCornerSize, + can_resize); + if (frame_component != HTNOWHERE) + return frame_component; + int client_component = frame_->client_view()->NonClientHitTest(point); if (client_component != HTNOWHERE) return client_component; @@ -182,18 +199,6 @@ int FramePainter::NonClientHitTest(views::NonClientFrameView* view, maximize_button_->GetMirroredBounds().Contains(point)) return HTMAXBUTTON; - bool can_resize = frame_->widget_delegate() ? - frame_->widget_delegate()->CanResize() : - false; - int frame_component = view->GetHTComponentForFrame(point, - kTopThickness, - kBorderThickness, - kResizeAreaCornerSize, - kResizeAreaCornerSize, - can_resize); - if (frame_component != HTNOWHERE) - return frame_component; - // Caption is a safe default. return HTCAPTION; } diff --git a/ash/wm/frame_painter.h b/ash/wm/frame_painter.h index 2cf474d..5be8ca1 100644 --- a/ash/wm/frame_painter.h +++ b/ash/wm/frame_painter.h @@ -27,7 +27,8 @@ class Widget; namespace ash { // Helper class for painting window frames. Exists to share code between -// various implementations of views::NonClientFrameView. +// various implementations of views::NonClientFrameView. Canonical source of +// layout constants for Ash window frames. class ASH_EXPORT FramePainter { public: FramePainter(); diff --git a/ash/wm/shelf_layout_manager.cc b/ash/wm/shelf_layout_manager.cc index eca4c40c..fff8c19 100644 --- a/ash/wm/shelf_layout_manager.cc +++ b/ash/wm/shelf_layout_manager.cc @@ -26,6 +26,9 @@ ui::Layer* GetLayer(views::Widget* widget) { } // namespace +// static +const int ShelfLayoutManager::kWorkspaceAreaBottomInset = 2; + //////////////////////////////////////////////////////////////////////////////// // ShelfLayoutManager, public: @@ -144,7 +147,8 @@ void ShelfLayoutManager::CalculateTargetBounds(bool visible, available_bounds.width(), launcher_bounds.height()); if (visible) - target_bounds->work_area_insets = gfx::Insets(0, 0, max_height_, 0); + target_bounds->work_area_insets = gfx::Insets( + 0, 0, max_height_ + kWorkspaceAreaBottomInset, 0); } void ShelfLayoutManager::OnImplicitAnimationsCompleted() { diff --git a/ash/wm/shelf_layout_manager.h b/ash/wm/shelf_layout_manager.h index 8d69cc6..5c4b6dd 100644 --- a/ash/wm/shelf_layout_manager.h +++ b/ash/wm/shelf_layout_manager.h @@ -30,6 +30,14 @@ namespace internal { class ASH_EXPORT ShelfLayoutManager : public aura::LayoutManager, public ui::ImplicitAnimationObserver { public: + // We reserve a small area at the bottom of the workspace area to ensure that + // the bottom-of-window resize handle can be hit. + // TODO(jamescook): Some day we may want the workspace area to be an even + // multiple of the size of the grid (currently 8 pixels), which will require + // removing this and finding a way for hover and click events to pass through + // the invisible parts of the launcher. + static const int kWorkspaceAreaBottomInset; + ShelfLayoutManager(views::Widget* launcher, views::Widget* status); virtual ~ShelfLayoutManager(); diff --git a/ash/wm/shelf_layout_manager_unittest.cc b/ash/wm/shelf_layout_manager_unittest.cc index fbf924d..bfedd5a 100644 --- a/ash/wm/shelf_layout_manager_unittest.cc +++ b/ash/wm/shelf_layout_manager_unittest.cc @@ -54,7 +54,8 @@ TEST_F(ShelfLayoutManagerTest, MAYBE_SetVisible) { const ash::ScreenAsh* screen = Shell::GetInstance()->screen(); ASSERT_TRUE(screen); // Bottom inset should be the max of widget heights. - EXPECT_EQ(shelf->max_height(), screen->work_area_insets().bottom()); + EXPECT_EQ(shelf->max_height() + ShelfLayoutManager::kWorkspaceAreaBottomInset, + screen->work_area_insets().bottom()); // Hide the shelf. shelf->SetVisible(false); @@ -76,7 +77,8 @@ TEST_F(ShelfLayoutManagerTest, MAYBE_SetVisible) { StepWidgetLayerAnimatorToEnd(shelf->launcher()); StepWidgetLayerAnimatorToEnd(shelf->status()); EXPECT_TRUE(shelf->visible()); - EXPECT_EQ(shelf->max_height(), screen->work_area_insets().bottom()); + EXPECT_EQ(shelf->max_height() + ShelfLayoutManager::kWorkspaceAreaBottomInset, + screen->work_area_insets().bottom()); // Make sure the bounds of the two widgets changed. gfx::Rect launcher_bounds(shelf->launcher()->GetNativeView()->bounds()); diff --git a/chrome/browser/ui/views/frame/browser_frame_aura.cc b/chrome/browser/ui/views/frame/browser_frame_aura.cc index b6a2062..7e98186 100644 --- a/chrome/browser/ui/views/frame/browser_frame_aura.cc +++ b/chrome/browser/ui/views/frame/browser_frame_aura.cc @@ -22,7 +22,7 @@ class BrowserFrameAura::WindowPropertyWatcher : public aura::WindowObserver { virtual void OnWindowPropertyChanged(aura::Window* window, const void* key, - intptr_t old) { + intptr_t old) OVERRIDE { if (key != aura::client::kShowStateKey) return; diff --git a/chrome/browser/ui/views/tab_contents/native_tab_contents_view_aura.cc b/chrome/browser/ui/views/tab_contents/native_tab_contents_view_aura.cc index 9302846..dd1c65f 100644 --- a/chrome/browser/ui/views/tab_contents/native_tab_contents_view_aura.cc +++ b/chrome/browser/ui/views/tab_contents/native_tab_contents_view_aura.cc @@ -163,6 +163,7 @@ void NativeTabContentsViewAura::InitNativeTabContentsView() { params.parent = NULL; params.can_activate = true; GetWidget()->Init(params); + GetNativeWindow()->SetName("NativeTabContentsViewAura"); #if defined(USE_ASH) ash::SetChildWindowVisibilityChangesAnimated(GetWidget()->GetNativeView()); #else diff --git a/ui/aura/window.cc b/ui/aura/window.cc index 71fedda..206a5c0 100644 --- a/ui/aura/window.cc +++ b/ui/aura/window.cc @@ -55,7 +55,8 @@ Window::Window(WindowDelegate* delegate) user_data_(NULL), stops_event_propagation_(false), ignore_events_(false), - hit_test_bounds_inset_(0) { + hit_test_bounds_override_outer_(0), + hit_test_bounds_override_inner_(0) { } Window::~Window() { @@ -372,6 +373,13 @@ void Window::RemoveObserver(WindowObserver* observer) { observers_.RemoveObserver(observer); } +void Window::SetHitTestBoundsOverride(int outer, int inner) { + DCHECK(outer >= 0); + DCHECK(inner >= 0); + hit_test_bounds_override_outer_ = outer; + hit_test_bounds_override_inner_ = inner; +} + bool Window::ContainsPointInRoot(const gfx::Point& point_in_root) { Window* root_window = GetRootWindow(); if (!root_window) @@ -387,8 +395,11 @@ bool Window::ContainsPoint(const gfx::Point& local_point) { } bool Window::HitTest(const gfx::Point& local_point) { + // Expand my bounds for hit testing (override is usually zero but it's + // probably cheaper to do the math every time than to branch). gfx::Rect local_bounds(gfx::Point(), bounds().size()); - local_bounds.Inset(hit_test_bounds_inset_, hit_test_bounds_inset_); + local_bounds.Inset(-hit_test_bounds_override_outer_, + -hit_test_bounds_override_outer_); // TODO(beng): hittest masks. return local_bounds.Contains(local_point); } @@ -616,6 +627,20 @@ Window* Window::GetWindowForPoint(const gfx::Point& local_point, (!for_event_handling && !ContainsPoint(local_point))) return NULL; + // Check if I should claim this event and not pass it to my children because + // the location is inside my hit test override area. For details, see + // SetHitTestBoundsOverride(). + if (for_event_handling && hit_test_bounds_override_inner_ != 0) { + gfx::Rect inset_local_bounds(gfx::Point(), bounds().size()); + inset_local_bounds.Inset(hit_test_bounds_override_inner_, + hit_test_bounds_override_inner_); + // We know we're inside the normal local bounds, so if we're outside the + // inset bounds we must be in the special hit test override area. + DCHECK(HitTest(local_point)); + if (!inset_local_bounds.Contains(local_point)) + return delegate_ ? this : NULL; + } + if (!return_tightest && delegate_) return this; diff --git a/ui/aura/window.h b/ui/aura/window.h index ebd3f13..6f6ea8b 100644 --- a/ui/aura/window.h +++ b/ui/aura/window.h @@ -229,11 +229,12 @@ class AURA_EXPORT Window : public ui::LayerDelegate { void set_ignore_events(bool ignore_events) { ignore_events_ = ignore_events; } - // When non-zero insets the window's bounds by |inset| when performing hit - // tests for event handling. Pass a negative value for |inset| to respond to - // events that occur slightly outside a window's bounds. - void set_hit_test_bounds_inset(int inset) { hit_test_bounds_inset_ = inset; } - int hit_test_bounds_inset() const { return hit_test_bounds_inset_; } + // Sets the window to grab hits for an area extending |outer| pixels outside + // its bounds and |inner| pixels inside its bounds (even if that inner region + // overlaps a child window). This can be used to create an invisible non- + // client area, for example if your windows have no visible frames but still + // need to have resize edges. Both |outer| and |inner| must be >= 0. + void SetHitTestBoundsOverride(int outer, int inner); // Returns true if the |point_in_root| in root window's coordinate falls // within this window's bounds. Returns false if the window is detached @@ -440,8 +441,9 @@ class AURA_EXPORT Window : public ui::LayerDelegate { // Makes the window pass all events through to any windows behind it. bool ignore_events_; - // Inset the window bounds by this amount when doing hit testing for events. - int hit_test_bounds_inset_; + // See SetHitTestBoundsOverride(). + int hit_test_bounds_override_outer_; + int hit_test_bounds_override_inner_; ObserverList<WindowObserver> observers_; diff --git a/ui/aura/window_unittest.cc b/ui/aura/window_unittest.cc index ee3aeaf..e4c9def 100644 --- a/ui/aura/window_unittest.cc +++ b/ui/aura/window_unittest.cc @@ -282,7 +282,7 @@ TEST_F(WindowTest, HitTest) { EXPECT_FALSE(w1.HitTest(gfx::Point(-1, -1))); // We can expand the bounds slightly to track events outside our border. - w1.set_hit_test_bounds_inset(-1); + w1.SetHitTestBoundsOverride(1, 0); EXPECT_TRUE(w1.HitTest(gfx::Point(-1, -1))); EXPECT_FALSE(w1.HitTest(gfx::Point(-2, -2))); @@ -318,6 +318,23 @@ TEST_F(WindowTest, GetEventHandlerForPoint) { EXPECT_EQ(w13.get(), root->GetEventHandlerForPoint(gfx::Point(26, 481))); } +TEST_F(WindowTest, GetEventHandlerForPointWithOverride) { + // If our child is flush to our top-left corner he gets events just inside the + // window edges. + scoped_ptr<Window> parent( + CreateTestWindow(SK_ColorWHITE, 1, gfx::Rect(10, 20, 400, 500), NULL)); + scoped_ptr<Window> child( + CreateTestWindow(SK_ColorRED, 2, gfx::Rect(0, 0, 60, 70), parent.get())); + EXPECT_EQ(child.get(), parent->GetEventHandlerForPoint(gfx::Point(0, 0))); + EXPECT_EQ(child.get(), parent->GetEventHandlerForPoint(gfx::Point(1, 1))); + + // We can override the hit test bounds of the parent to make the parent grab + // events along that edge. + parent->SetHitTestBoundsOverride(0, 1); + EXPECT_EQ(parent.get(), parent->GetEventHandlerForPoint(gfx::Point(0, 0))); + EXPECT_EQ(child.get(), parent->GetEventHandlerForPoint(gfx::Point(1, 1))); +} + TEST_F(WindowTest, GetTopWindowContainingPoint) { Window* root = root_window(); root->SetBounds(gfx::Rect(0, 0, 300, 300)); diff --git a/ui/oak/oak_aura_window_display.cc b/ui/oak/oak_aura_window_display.cc index 153685a..afaeb70 100644 --- a/ui/oak/oak_aura_window_display.cc +++ b/ui/oak/oak_aura_window_display.cc @@ -33,7 +33,6 @@ ROW_TRANSIENTPARENT, ROW_USERDATA, ROW_STOPSEVENTPROPAGATION, ROW_IGNOREEVENTS, -ROW_HITTESTBOUNDSINSET, ROW_CANFOCUS, ROW_COUNT }; @@ -142,9 +141,6 @@ string16 OakAuraWindowDisplay::GetText(int row, int column_id) { case ROW_IGNOREEVENTS: return PropertyWithBool("Can receive events: ", window_->CanReceiveEvents()); - case ROW_HITTESTBOUNDSINSET: - return PropertyWithInteger("Hit-test bounds inset: ", - window_->hit_test_bounds_inset()); case ROW_CANFOCUS: return PropertyWithBool("Can Focus: ", window_->CanFocus()); default: |