// Copyright (c) 2012 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/workspace/workspace_event_handler.h" #include "ash/metrics/user_metrics_recorder.h" #include "ash/screen_ash.h" #include "ash/shell.h" #include "ash/touch/touch_uma.h" #include "ash/wm/coordinate_conversion.h" #include "ash/wm/window_state.h" #include "ash/wm/window_util.h" #include "ash/wm/workspace/workspace_window_resizer.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" #include "ui/aura/window_delegate.h" #include "ui/base/hit_test.h" #include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/events/event.h" #include "ui/events/event_utils.h" #include "ui/gfx/screen.h" namespace ash { namespace { void SingleAxisMaximize(wm::WindowState* window_state, const gfx::Rect& maximize_rect_in_screen) { window_state->SaveCurrentBoundsForRestore(); window_state->SetBoundsInScreen(maximize_rect_in_screen); } void SingleAxisUnmaximize(wm::WindowState* window_state, const gfx::Rect& restore_bounds_in_screen) { window_state->SetBoundsInScreen(restore_bounds_in_screen); window_state->ClearRestoreBounds(); } void ToggleMaximizedState(wm::WindowState* window_state) { if (window_state->HasRestoreBounds()) { if (window_state->GetShowState() == ui::SHOW_STATE_NORMAL) { window_state->window()->SetBounds( window_state->GetRestoreBoundsInParent()); window_state->ClearRestoreBounds(); } else { window_state->Restore(); } } else if (window_state->CanMaximize()) { window_state->Maximize(); } } } // namespace namespace internal { WorkspaceEventHandler::WorkspaceEventHandler(aura::Window* owner) : ToplevelWindowEventHandler(owner) { } WorkspaceEventHandler::~WorkspaceEventHandler() { } void WorkspaceEventHandler::OnMouseEvent(ui::MouseEvent* event) { aura::Window* target = static_cast(event->target()); switch (event->type()) { case ui::ET_MOUSE_MOVED: { int component = target->delegate()->GetNonClientComponent(event->location()); multi_window_resize_controller_.Show(target, component, event->location()); break; } case ui::ET_MOUSE_ENTERED: break; case ui::ET_MOUSE_CAPTURE_CHANGED: case ui::ET_MOUSE_EXITED: break; case ui::ET_MOUSE_PRESSED: { // Maximize behavior is implemented as post-target handling so the target // can cancel it. if (ui::EventCanceledDefaultHandling(*event)) { ToplevelWindowEventHandler::OnMouseEvent(event); return; } wm::WindowState* target_state = wm::GetWindowState(target); if (event->flags() & ui::EF_IS_DOUBLE_CLICK && event->IsOnlyLeftMouseButton() && target->delegate()->GetNonClientComponent(event->location()) == HTCAPTION) { ash::Shell::GetInstance()->metrics()->RecordUserMetricsAction( ash::UMA_TOGGLE_MAXIMIZE_CAPTION_CLICK); ToggleMaximizedState(target_state); } multi_window_resize_controller_.Hide(); HandleVerticalResizeDoubleClick(target_state, event); break; } default: break; } ToplevelWindowEventHandler::OnMouseEvent(event); } void WorkspaceEventHandler::OnGestureEvent(ui::GestureEvent* event) { aura::Window* target = static_cast(event->target()); if (event->type() == ui::ET_GESTURE_TAP && target->delegate()->GetNonClientComponent(event->location()) == HTCAPTION) { if (event->details().tap_count() == 2) { ash::Shell::GetInstance()->metrics()->RecordUserMetricsAction( ash::UMA_TOGGLE_MAXIMIZE_CAPTION_GESTURE); // Note: TouchUMA::GESTURE_FRAMEVIEW_TAP is counted twice each time // TouchUMA::GESTURE_MAXIMIZE_DOUBLETAP is counted once. TouchUMA::GetInstance()->RecordGestureAction( TouchUMA::GESTURE_MAXIMIZE_DOUBLETAP); ToggleMaximizedState(wm::GetWindowState(target)); event->StopPropagation(); return; } else { // Note: TouchUMA::GESTURE_FRAMEVIEW_TAP is counted twice for each tap. TouchUMA::GetInstance()->RecordGestureAction( TouchUMA::GESTURE_FRAMEVIEW_TAP); } } ToplevelWindowEventHandler::OnGestureEvent(event); } void WorkspaceEventHandler::HandleVerticalResizeDoubleClick( wm::WindowState* target_state, ui::MouseEvent* event) { aura::Window* target = target_state->window(); gfx::Rect max_size(target->delegate()->GetMaximumSize()); if (event->flags() & ui::EF_IS_DOUBLE_CLICK && !target_state->IsMaximized()) { int component = target->delegate()->GetNonClientComponent(event->location()); gfx::Rect work_area = Shell::GetScreen()->GetDisplayNearestWindow( target).work_area(); if (component == HTBOTTOM || component == HTTOP) { // Don't maximize vertically if the window has a max height defined. if (max_size.height() != 0) return; if (target_state->HasRestoreBounds() && (target->bounds().height() == work_area.height() && target->bounds().y() == work_area.y())) { SingleAxisUnmaximize(target_state, target_state->GetRestoreBoundsInScreen()); } else { gfx::Point origin = target->bounds().origin(); wm::ConvertPointToScreen(target->parent(), &origin); SingleAxisMaximize(target_state, gfx::Rect(origin.x(), work_area.y(), target->bounds().width(), work_area.height())); } } else if (component == HTLEFT || component == HTRIGHT) { // Don't maximize horizontally if the window has a max width defined. if (max_size.width() != 0) return; if (target_state->HasRestoreBounds() && (target->bounds().width() == work_area.width() && target->bounds().x() == work_area.x())) { SingleAxisUnmaximize(target_state, target_state->GetRestoreBoundsInScreen()); } else { gfx::Point origin = target->bounds().origin(); wm::ConvertPointToScreen(target->parent(), &origin); SingleAxisMaximize(target_state, gfx::Rect(work_area.x(), origin.y(), work_area.width(), target->bounds().height())); } } } } } // namespace internal } // namespace ash