1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ash/wm/frame_border_hit_test_controller.h"
7 #include "ash/ash_constants.h"
8 #include "ash/wm/header_painter.h"
9 #include "ash/wm/window_state.h"
10 #include "ui/aura/env.h"
11 #include "ui/aura/window.h"
12 #include "ui/base/hit_test.h"
13 #include "ui/views/widget/widget.h"
14 #include "ui/views/widget/widget_delegate.h"
15 #include "ui/views/window/non_client_view.h"
19 FrameBorderHitTestController::FrameBorderHitTestController(views::Widget
* frame
)
20 : frame_window_(frame
->GetNativeWindow()) {
21 gfx::Insets
mouse_outer_insets(-kResizeOutsideBoundsSize
,
22 -kResizeOutsideBoundsSize
,
23 -kResizeOutsideBoundsSize
,
24 -kResizeOutsideBoundsSize
);
25 gfx::Insets touch_outer_insets
= mouse_outer_insets
.Scale(
26 kResizeOutsideBoundsScaleForTouch
);
27 // Ensure we get resize cursors for a few pixels outside our bounds.
28 frame_window_
->SetHitTestBoundsOverrideOuter(mouse_outer_insets
,
30 // Ensure we get resize cursors just inside our bounds as well.
31 UpdateHitTestBoundsOverrideInner();
33 frame_window_
->AddObserver(this);
34 ash::wm::GetWindowState(frame_window_
)->AddObserver(this);
37 FrameBorderHitTestController::~FrameBorderHitTestController() {
39 frame_window_
->RemoveObserver(this);
40 ash::wm::GetWindowState(frame_window_
)->RemoveObserver(this);
45 int FrameBorderHitTestController::NonClientHitTest(
46 views::NonClientFrameView
* view
,
47 HeaderPainter
* header_painter
,
48 const gfx::Point
& point
) {
49 gfx::Rect expanded_bounds
= view
->bounds();
50 int outside_bounds
= kResizeOutsideBoundsSize
;
52 if (aura::Env::GetInstance()->is_touch_down())
53 outside_bounds
*= kResizeOutsideBoundsScaleForTouch
;
54 expanded_bounds
.Inset(-outside_bounds
, -outside_bounds
);
56 if (!expanded_bounds
.Contains(point
))
59 // Check the frame first, as we allow a small area overlapping the contents
60 // to be used for resize handles.
61 views::Widget
* frame
= view
->GetWidget();
62 bool can_ever_resize
= frame
->widget_delegate()->CanResize();
63 // Don't allow overlapping resize handles when the window is maximized or
64 // fullscreen, as it can't be resized in those states.
66 frame
->IsMaximized() || frame
->IsFullscreen() ? 0 :
67 kResizeInsideBoundsSize
;
68 int frame_component
= view
->GetHTComponentForFrame(point
,
71 kResizeAreaCornerSize
,
72 kResizeAreaCornerSize
,
74 if (frame_component
!= HTNOWHERE
)
75 return frame_component
;
77 int client_component
= frame
->client_view()->NonClientHitTest(point
);
78 if (client_component
!= HTNOWHERE
)
79 return client_component
;
81 return header_painter
->NonClientHitTest(point
);
84 void FrameBorderHitTestController::UpdateHitTestBoundsOverrideInner() {
85 // Maximized and fullscreen windows don't want resize handles overlapping the
86 // content area, because when the user moves the cursor to the right screen
87 // edge we want them to be able to hit the scroll bar.
88 if (wm::GetWindowState(frame_window_
)->IsMaximizedOrFullscreen()) {
89 frame_window_
->set_hit_test_bounds_override_inner(gfx::Insets());
91 frame_window_
->set_hit_test_bounds_override_inner(
92 gfx::Insets(kResizeInsideBoundsSize
, kResizeInsideBoundsSize
,
93 kResizeInsideBoundsSize
, kResizeInsideBoundsSize
));
97 void FrameBorderHitTestController::OnWindowShowTypeChanged(
98 wm::WindowState
* window_state
,
99 wm::WindowShowType old_type
) {
100 UpdateHitTestBoundsOverrideInner();
103 void FrameBorderHitTestController::OnWindowDestroying(aura::Window
* window
) {
104 frame_window_
->RemoveObserver(this);
105 ash::wm::GetWindowState(frame_window_
)->RemoveObserver(this);
106 frame_window_
= NULL
;