15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/wm/workspace/workspace_event_handler.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/screen_ash.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/shell.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/shell_delegate.h" 10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ash/touch/touch_uma.h" 11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ash/wm/coordinate_conversion.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/wm/property_util.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/wm/window_util.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/wm/workspace/workspace_window_resizer.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/client/aura_constants.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/window.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/window_delegate.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/events/event.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/events/event_utils.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/hit_test.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/compositor/scoped_layer_animation_settings.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/screen.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace ash { 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void SingleAxisMaximize(aura::Window* window, 28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const gfx::Rect& maximize_rect_in_screen) { 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect bounds_in_screen = 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScreenAsh::ConvertRectToScreen(window->parent(), window->bounds()); 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetRestoreBoundsInScreen(window, bounds_in_screen); 32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) gfx::Rect bounds_in_parent = 33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ScreenAsh::ConvertRectFromScreen(window->parent(), 34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) maximize_rect_in_screen); 35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) window->SetBounds(bounds_in_parent); 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SingleAxisUnmaximize(aura::Window* window, 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::Rect& restore_bounds_in_screen) { 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect restore_bounds = ScreenAsh::ConvertRectFromScreen( 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window->parent(), restore_bounds_in_screen); 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window->SetBounds(restore_bounds); 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ClearRestoreBounds(window); 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ToggleMaximizedState(aura::Window* window) { 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GetRestoreBoundsInScreen(window)) { 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (window->GetProperty(aura::client::kShowStateKey) == 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::SHOW_STATE_NORMAL) { 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window->SetBounds(GetRestoreBoundsInParent(window)); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ClearRestoreBounds(window); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (wm::CanMaximizeWindow(window)) { 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace internal { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WorkspaceEventHandler::WorkspaceEventHandler(aura::Window* owner) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : ToplevelWindowEventHandler(owner), 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) destroyed_(NULL) { 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WorkspaceEventHandler::~WorkspaceEventHandler() { 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (destroyed_) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *destroyed_ = true; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WorkspaceEventHandler::OnMouseEvent(ui::MouseEvent* event) { 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) aura::Window* target = static_cast<aura::Window*>(event->target()); 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (event->type()) { 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::ET_MOUSE_MOVED: { 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int component = 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target->delegate()->GetNonClientComponent(event->location()); 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) multi_window_resize_controller_.Show(target, component, 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event->location()); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::ET_MOUSE_ENTERED: 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::ET_MOUSE_CAPTURE_CHANGED: 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::ET_MOUSE_EXITED: 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ui::ET_MOUSE_PRESSED: { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Maximize behavior is implemented as post-target handling so the target 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // can cancel it. 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (ui::EventCanceledDefaultHandling(*event)) { 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ToplevelWindowEventHandler::OnMouseEvent(event); 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event->flags() & ui::EF_IS_DOUBLE_CLICK && 983240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch event->IsOnlyLeftMouseButton() && 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target->delegate()->GetNonClientComponent(event->location()) == 100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) HTCAPTION && 101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) !ash::Shell::IsForcedMaximizeMode()) { 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool destroyed = false; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) destroyed_ = &destroyed; 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ash::Shell::GetInstance()->delegate()->RecordUserMetricsAction( 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ash::UMA_TOGGLE_MAXIMIZE_CAPTION_CLICK); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ToggleMaximizedState(target); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (destroyed) 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) destroyed_ = NULL; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) multi_window_resize_controller_.Hide(); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleVerticalResizeDoubleClick(target, event); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ToplevelWindowEventHandler::OnMouseEvent(event); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WorkspaceEventHandler::OnGestureEvent(ui::GestureEvent* event) { 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) aura::Window* target = static_cast<aura::Window*>(event->target()); 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (event->type() == ui::ET_GESTURE_TAP && 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target->delegate()->GetNonClientComponent(event->location()) == 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HTCAPTION) { 126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (event->details().tap_count() == 2) { 127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ash::Shell::GetInstance()->delegate()->RecordUserMetricsAction( 128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ash::UMA_TOGGLE_MAXIMIZE_CAPTION_GESTURE); 129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Note: TouchUMA::GESTURE_FRAMEVIEW_TAP is counted twice each time 130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // TouchUMA::GESTURE_MAXIMIZE_DOUBLETAP is counted once. 131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch TouchUMA::GetInstance()->RecordGestureAction( 132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch TouchUMA::GESTURE_MAXIMIZE_DOUBLETAP); 133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ToggleMaximizedState(target); // |this| may be destroyed from here. 134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch event->StopPropagation(); 135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return; 136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else { 137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Note: TouchUMA::GESTURE_FRAMEVIEW_TAP is counted twice for each tap. 138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch TouchUMA::GetInstance()->RecordGestureAction( 139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch TouchUMA::GESTURE_FRAMEVIEW_TAP); 140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ToplevelWindowEventHandler::OnGestureEvent(event); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WorkspaceEventHandler::HandleVerticalResizeDoubleClick( 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) aura::Window* target, 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::MouseEvent* event) { 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Rect max_size(target->delegate()->GetMaximumSize()); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event->flags() & ui::EF_IS_DOUBLE_CLICK && 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !wm::IsWindowMaximized(target)) { 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int component = 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target->delegate()->GetNonClientComponent(event->location()); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect work_area = 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Shell::GetScreen()->GetDisplayNearestWindow(target).work_area(); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::Rect* restore_bounds = 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GetRestoreBoundsInScreen(target); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (component == HTBOTTOM || component == HTTOP) { 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Don't maximize vertically if the window has a max height defined. 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (max_size.height() != 0) 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (restore_bounds && 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (target->bounds().height() == work_area.height() && 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target->bounds().y() == work_area.y())) { 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SingleAxisUnmaximize(target, *restore_bounds); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) gfx::Point origin = target->bounds().origin(); 167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wm::ConvertPointToScreen(target->parent(), &origin); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SingleAxisMaximize(target, 169868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) gfx::Rect(origin.x(), 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) work_area.y(), 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target->bounds().width(), 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) work_area.height())); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (component == HTLEFT || component == HTRIGHT) { 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Don't maximize horizontally if the window has a max width defined. 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (max_size.width() != 0) 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (restore_bounds && 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (target->bounds().width() == work_area.width() && 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target->bounds().x() == work_area.x())) { 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SingleAxisUnmaximize(target, *restore_bounds); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) gfx::Point origin = target->bounds().origin(); 184868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wm::ConvertPointToScreen(target->parent(), &origin); 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SingleAxisMaximize(target, 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect(work_area.x(), 187868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) origin.y(), 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) work_area.width(), 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target->bounds().height())); 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace internal 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace ash 197