// 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 "ash/wm/frame_border_hit_test_controller.h" #include "ash/ash_constants.h" #include "ash/wm/header_painter.h" #include "ash/wm/window_state.h" #include "ui/aura/env.h" #include "ui/aura/window.h" #include "ui/base/hit_test.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_delegate.h" #include "ui/views/window/non_client_view.h" namespace ash { FrameBorderHitTestController::FrameBorderHitTestController(views::Widget* frame) : frame_window_(frame->GetNativeWindow()) { gfx::Insets mouse_outer_insets(-kResizeOutsideBoundsSize, -kResizeOutsideBoundsSize, -kResizeOutsideBoundsSize, -kResizeOutsideBoundsSize); gfx::Insets touch_outer_insets = mouse_outer_insets.Scale( kResizeOutsideBoundsScaleForTouch); // Ensure we get resize cursors for a few pixels outside our bounds. frame_window_->SetHitTestBoundsOverrideOuter(mouse_outer_insets, touch_outer_insets); // Ensure we get resize cursors just inside our bounds as well. UpdateHitTestBoundsOverrideInner(); frame_window_->AddObserver(this); ash::wm::GetWindowState(frame_window_)->AddObserver(this); } FrameBorderHitTestController::~FrameBorderHitTestController() { if (frame_window_) { frame_window_->RemoveObserver(this); ash::wm::GetWindowState(frame_window_)->RemoveObserver(this); } } // static int FrameBorderHitTestController::NonClientHitTest( views::NonClientFrameView* view, HeaderPainter* header_painter, const gfx::Point& point) { gfx::Rect expanded_bounds = view->bounds(); int outside_bounds = kResizeOutsideBoundsSize; if (aura::Env::GetInstance()->is_touch_down()) outside_bounds *= kResizeOutsideBoundsScaleForTouch; expanded_bounds.Inset(-outside_bounds, -outside_bounds); if (!expanded_bounds.Contains(point)) return HTNOWHERE; // Check the frame first, as we allow a small area overlapping the contents // to be used for resize handles. views::Widget* frame = view->GetWidget(); bool can_ever_resize = frame->widget_delegate()->CanResize(); // Don't allow overlapping resize handles when the window is maximized or // fullscreen, as it can't be resized in those states. int resize_border = frame->IsMaximized() || frame->IsFullscreen() ? 0 : kResizeInsideBoundsSize; int frame_component = view->GetHTComponentForFrame(point, resize_border, resize_border, kResizeAreaCornerSize, kResizeAreaCornerSize, can_ever_resize); if (frame_component != HTNOWHERE) return frame_component; int client_component = frame->client_view()->NonClientHitTest(point); if (client_component != HTNOWHERE) return client_component; return header_painter->NonClientHitTest(point); } void FrameBorderHitTestController::UpdateHitTestBoundsOverrideInner() { // Maximized and fullscreen windows don't want resize handles overlapping the // content area, because when the user moves the cursor to the right screen // edge we want them to be able to hit the scroll bar. if (wm::GetWindowState(frame_window_)->IsMaximizedOrFullscreen()) { frame_window_->set_hit_test_bounds_override_inner(gfx::Insets()); } else { frame_window_->set_hit_test_bounds_override_inner( gfx::Insets(kResizeInsideBoundsSize, kResizeInsideBoundsSize, kResizeInsideBoundsSize, kResizeInsideBoundsSize)); } } void FrameBorderHitTestController::OnWindowShowTypeChanged( wm::WindowState* window_state, wm::WindowShowType old_type) { UpdateHitTestBoundsOverrideInner(); } void FrameBorderHitTestController::OnWindowDestroying(aura::Window* window) { frame_window_->RemoveObserver(this); ash::wm::GetWindowState(frame_window_)->RemoveObserver(this); frame_window_ = NULL; } } // namespace ash