| // Copyright 2016 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/accelerators/accelerator_controller_delegate_aura.h" |
| |
| #include <algorithm> |
| #include <cmath> |
| #include <string> |
| #include <utility> |
| |
| #include "ash/accelerators/accelerator_commands_aura.h" |
| #include "ash/accelerators/debug_commands.h" |
| #include "ash/accessibility_types.h" |
| #include "ash/debug.h" |
| #include "ash/display/display_configuration_controller.h" |
| #include "ash/host/ash_window_tree_host.h" |
| #include "ash/magnifier/magnification_controller.h" |
| #include "ash/public/cpp/shell_window_ids.h" |
| #include "ash/root_window_controller.h" |
| #include "ash/screenshot_delegate.h" |
| #include "ash/shell.h" |
| #include "ash/system/system_notifier.h" |
| #include "ash/touch/touch_hud_debug.h" |
| #include "ash/utility/screenshot_controller.h" |
| #include "ash/wm/maximize_mode/maximize_mode_controller.h" |
| #include "ash/wm/power_button_controller.h" |
| #include "ash/wm/window_state.h" |
| #include "ash/wm/wm_event.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/metrics/user_metrics.h" |
| #include "base/sys_info.h" |
| #include "third_party/skia/include/core/SkColor.h" |
| #include "ui/base/accelerators/accelerator.h" |
| #include "ui/display/manager/display_manager.h" |
| #include "ui/display/screen.h" |
| #include "ui/events/event.h" |
| #include "ui/events/keycodes/keyboard_codes.h" |
| |
| namespace ash { |
| namespace { |
| |
| using base::UserMetricsAction; |
| |
| bool CanHandleMagnifyScreen() { |
| return Shell::Get()->magnification_controller()->IsEnabled(); |
| } |
| |
| // Magnify the screen |
| void HandleMagnifyScreen(int delta_index) { |
| if (Shell::Get()->magnification_controller()->IsEnabled()) { |
| // TODO(yoshiki): Move the following logic to MagnificationController. |
| float scale = Shell::Get()->magnification_controller()->GetScale(); |
| // Calculate rounded logarithm (base kMagnificationScaleFactor) of scale. |
| int scale_index = |
| std::floor(std::log(scale) / std::log(kMagnificationScaleFactor) + 0.5); |
| |
| int new_scale_index = std::max(0, std::min(8, scale_index + delta_index)); |
| |
| Shell::Get()->magnification_controller()->SetScale( |
| std::pow(kMagnificationScaleFactor, new_scale_index), true); |
| } |
| } |
| |
| display::Display::Rotation GetNextRotation(display::Display::Rotation current) { |
| switch (current) { |
| case display::Display::ROTATE_0: |
| return display::Display::ROTATE_90; |
| case display::Display::ROTATE_90: |
| return display::Display::ROTATE_180; |
| case display::Display::ROTATE_180: |
| return display::Display::ROTATE_270; |
| case display::Display::ROTATE_270: |
| return display::Display::ROTATE_0; |
| } |
| NOTREACHED() << "Unknown rotation:" << current; |
| return display::Display::ROTATE_0; |
| } |
| |
| // Rotates the screen. |
| void HandleRotateScreen() { |
| if (Shell::Get()->display_manager()->IsInUnifiedMode()) |
| return; |
| |
| base::RecordAction(UserMetricsAction("Accel_Rotate_Screen")); |
| gfx::Point point = display::Screen::GetScreen()->GetCursorScreenPoint(); |
| display::Display display = |
| display::Screen::GetScreen()->GetDisplayNearestPoint(point); |
| const display::ManagedDisplayInfo& display_info = |
| Shell::Get()->display_manager()->GetDisplayInfo(display.id()); |
| Shell::Get()->display_configuration_controller()->SetDisplayRotation( |
| display.id(), GetNextRotation(display_info.GetActiveRotation()), |
| display::Display::ROTATION_SOURCE_USER); |
| } |
| |
| void HandleTakeWindowScreenshot(ScreenshotDelegate* screenshot_delegate) { |
| base::RecordAction(UserMetricsAction("Accel_Take_Window_Screenshot")); |
| DCHECK(screenshot_delegate); |
| Shell::Get()->screenshot_controller()->StartWindowScreenshotSession( |
| screenshot_delegate); |
| } |
| |
| void HandleTakePartialScreenshot(ScreenshotDelegate* screenshot_delegate) { |
| base::RecordAction(UserMetricsAction("Accel_Take_Partial_Screenshot")); |
| DCHECK(screenshot_delegate); |
| Shell::Get()->screenshot_controller()->StartPartialScreenshotSession( |
| screenshot_delegate, true /* draw_overlay_immediately */); |
| } |
| |
| void HandleTakeScreenshot(ScreenshotDelegate* screenshot_delegate) { |
| base::RecordAction(UserMetricsAction("Accel_Take_Screenshot")); |
| DCHECK(screenshot_delegate); |
| if (screenshot_delegate->CanTakeScreenshot()) |
| screenshot_delegate->HandleTakeScreenshotForAllRootWindows(); |
| } |
| |
| bool CanHandleUnpin() { |
| // Returns true only for WINDOW_STATE_TYPE_PINNED. |
| // WINDOW_STATE_TYPE_TRUSTED_PINNED does not accept user's unpin operation. |
| wm::WindowState* window_state = wm::GetActiveWindowState(); |
| return window_state && |
| window_state->GetStateType() == wm::WINDOW_STATE_TYPE_PINNED; |
| } |
| |
| void HandleSwapPrimaryDisplay() { |
| base::RecordAction(UserMetricsAction("Accel_Swap_Primary_Display")); |
| |
| // TODO(rjkroege): This is not correct behaviour on devices with more than |
| // two screens. Behave the same as mirroring: fail and notify if there are |
| // three or more screens. |
| Shell::Get()->display_configuration_controller()->SetPrimaryDisplayId( |
| Shell::Get()->display_manager()->GetSecondaryDisplay().id()); |
| } |
| |
| void HandleToggleMirrorMode() { |
| base::RecordAction(UserMetricsAction("Accel_Toggle_Mirror_Mode")); |
| bool mirror = !Shell::Get()->display_manager()->IsInMirrorMode(); |
| Shell::Get()->display_configuration_controller()->SetMirrorMode(mirror); |
| } |
| |
| bool CanHandleTouchHud() { |
| return RootWindowController::ForTargetRootWindow()->touch_hud_debug(); |
| } |
| |
| void HandleTouchHudClear() { |
| RootWindowController::ForTargetRootWindow()->touch_hud_debug()->Clear(); |
| } |
| |
| void HandleTouchHudModeChange() { |
| RootWindowController* controller = |
| RootWindowController::ForTargetRootWindow(); |
| controller->touch_hud_debug()->ChangeToNextMode(); |
| } |
| |
| } // namespace |
| |
| AcceleratorControllerDelegateAura::AcceleratorControllerDelegateAura() {} |
| |
| AcceleratorControllerDelegateAura::~AcceleratorControllerDelegateAura() {} |
| |
| void AcceleratorControllerDelegateAura::SetScreenshotDelegate( |
| std::unique_ptr<ScreenshotDelegate> screenshot_delegate) { |
| screenshot_delegate_ = std::move(screenshot_delegate); |
| } |
| |
| bool AcceleratorControllerDelegateAura::HandlesAction( |
| AcceleratorAction action) { |
| // NOTE: When adding a new accelerator that only depends on //ash/common code, |
| // add it to accelerator_controller.cc instead. See class comment. |
| switch (action) { |
| case DEBUG_TOGGLE_DEVICE_SCALE_FACTOR: |
| case DEBUG_TOGGLE_SHOW_DEBUG_BORDERS: |
| case DEBUG_TOGGLE_SHOW_FPS_COUNTER: |
| case DEBUG_TOGGLE_SHOW_PAINT_RECTS: |
| case DEV_ADD_REMOVE_DISPLAY: |
| case DEV_TOGGLE_ROOT_WINDOW_FULL_SCREEN: |
| case DEV_TOGGLE_UNIFIED_DESKTOP: |
| case LOCK_PRESSED: |
| case LOCK_RELEASED: |
| case MAGNIFY_SCREEN_ZOOM_IN: |
| case MAGNIFY_SCREEN_ZOOM_OUT: |
| case POWER_PRESSED: |
| case POWER_RELEASED: |
| case ROTATE_SCREEN: |
| case SCALE_UI_DOWN: |
| case SCALE_UI_RESET: |
| case SCALE_UI_UP: |
| case SHOW_MESSAGE_CENTER_BUBBLE: |
| case SWAP_PRIMARY_DISPLAY: |
| case TAKE_PARTIAL_SCREENSHOT: |
| case TAKE_SCREENSHOT: |
| case TAKE_WINDOW_SCREENSHOT: |
| case TOGGLE_MIRROR_MODE: |
| case TOUCH_HUD_CLEAR: |
| case TOUCH_HUD_MODE_CHANGE: |
| case TOUCH_HUD_PROJECTION_TOGGLE: |
| case UNPIN: |
| return true; |
| |
| default: |
| break; |
| } |
| return false; |
| } |
| |
| bool AcceleratorControllerDelegateAura::CanPerformAction( |
| AcceleratorAction action, |
| const ui::Accelerator& accelerator, |
| const ui::Accelerator& previous_accelerator) { |
| switch (action) { |
| case DEBUG_TOGGLE_DEVICE_SCALE_FACTOR: |
| case DEBUG_TOGGLE_SHOW_DEBUG_BORDERS: |
| case DEBUG_TOGGLE_SHOW_FPS_COUNTER: |
| case DEBUG_TOGGLE_SHOW_PAINT_RECTS: |
| return debug::DebugAcceleratorsEnabled(); |
| case DEV_ADD_REMOVE_DISPLAY: |
| case DEV_TOGGLE_ROOT_WINDOW_FULL_SCREEN: |
| case DEV_TOGGLE_UNIFIED_DESKTOP: |
| return debug::DeveloperAcceleratorsEnabled(); |
| case MAGNIFY_SCREEN_ZOOM_IN: |
| case MAGNIFY_SCREEN_ZOOM_OUT: |
| return CanHandleMagnifyScreen(); |
| case SCALE_UI_DOWN: |
| case SCALE_UI_RESET: |
| case SCALE_UI_UP: |
| return accelerators::IsInternalDisplayZoomEnabled(); |
| case UNPIN: |
| return CanHandleUnpin(); |
| |
| // Following are always enabled: |
| case LOCK_PRESSED: |
| case LOCK_RELEASED: |
| case POWER_PRESSED: |
| case POWER_RELEASED: |
| case ROTATE_SCREEN: |
| case TAKE_PARTIAL_SCREENSHOT: |
| case TAKE_SCREENSHOT: |
| case TAKE_WINDOW_SCREENSHOT: |
| case TOGGLE_MIRROR_MODE: |
| case TOUCH_HUD_PROJECTION_TOGGLE: |
| return true; |
| |
| case SWAP_PRIMARY_DISPLAY: |
| return display::Screen::GetScreen()->GetNumDisplays() > 1; |
| case TOUCH_HUD_CLEAR: |
| case TOUCH_HUD_MODE_CHANGE: |
| return CanHandleTouchHud(); |
| |
| default: |
| NOTREACHED(); |
| break; |
| } |
| return false; |
| } |
| |
| void AcceleratorControllerDelegateAura::PerformAction( |
| AcceleratorAction action, |
| const ui::Accelerator& accelerator) { |
| switch (action) { |
| case DEBUG_TOGGLE_DEVICE_SCALE_FACTOR: |
| Shell::Get()->display_manager()->ToggleDisplayScaleFactor(); |
| break; |
| case DEBUG_TOGGLE_SHOW_DEBUG_BORDERS: |
| debug::ToggleShowDebugBorders(); |
| break; |
| case DEBUG_TOGGLE_SHOW_FPS_COUNTER: |
| debug::ToggleShowFpsCounter(); |
| break; |
| case DEBUG_TOGGLE_SHOW_PAINT_RECTS: |
| debug::ToggleShowPaintRects(); |
| break; |
| case DEV_ADD_REMOVE_DISPLAY: |
| Shell::Get()->display_manager()->AddRemoveDisplay(); |
| break; |
| case DEV_TOGGLE_ROOT_WINDOW_FULL_SCREEN: |
| Shell::GetPrimaryRootWindowController()->ash_host()->ToggleFullScreen(); |
| break; |
| case DEV_TOGGLE_UNIFIED_DESKTOP: |
| Shell::Get()->display_manager()->SetUnifiedDesktopEnabled( |
| !Shell::Get()->display_manager()->unified_desktop_enabled()); |
| break; |
| case LOCK_PRESSED: |
| case LOCK_RELEASED: |
| Shell::Get()->power_button_controller()->OnLockButtonEvent( |
| action == LOCK_PRESSED, base::TimeTicks()); |
| break; |
| case MAGNIFY_SCREEN_ZOOM_IN: |
| HandleMagnifyScreen(1); |
| break; |
| case MAGNIFY_SCREEN_ZOOM_OUT: |
| HandleMagnifyScreen(-1); |
| break; |
| case POWER_PRESSED: // fallthrough |
| case POWER_RELEASED: |
| if (!base::SysInfo::IsRunningOnChromeOS()) { |
| // There is no powerd, the Chrome OS power manager, in linux desktop, |
| // so call the PowerButtonController here. |
| Shell::Get()->power_button_controller()->OnPowerButtonEvent( |
| action == POWER_PRESSED, base::TimeTicks()); |
| } |
| // We don't do anything with these at present on the device, |
| // (power button events are reported to us from powerm via |
| // D-BUS), but we consume them to prevent them from getting |
| // passed to apps -- see http://crbug.com/146609. |
| break; |
| case ROTATE_SCREEN: |
| HandleRotateScreen(); |
| break; |
| case SCALE_UI_DOWN: |
| accelerators::ZoomInternalDisplay(false /* down */); |
| break; |
| case SCALE_UI_RESET: |
| accelerators::ResetInternalDisplayZoom(); |
| break; |
| case SCALE_UI_UP: |
| accelerators::ZoomInternalDisplay(true /* up */); |
| break; |
| case SWAP_PRIMARY_DISPLAY: |
| HandleSwapPrimaryDisplay(); |
| break; |
| case TAKE_PARTIAL_SCREENSHOT: |
| HandleTakePartialScreenshot(screenshot_delegate_.get()); |
| break; |
| case TAKE_SCREENSHOT: |
| HandleTakeScreenshot(screenshot_delegate_.get()); |
| break; |
| case TAKE_WINDOW_SCREENSHOT: |
| HandleTakeWindowScreenshot(screenshot_delegate_.get()); |
| break; |
| case TOGGLE_MIRROR_MODE: |
| HandleToggleMirrorMode(); |
| break; |
| case TOUCH_HUD_CLEAR: |
| HandleTouchHudClear(); |
| break; |
| case TOUCH_HUD_MODE_CHANGE: |
| HandleTouchHudModeChange(); |
| break; |
| case TOUCH_HUD_PROJECTION_TOGGLE: |
| accelerators::ToggleTouchHudProjection(); |
| break; |
| case UNPIN: |
| accelerators::Unpin(); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| } // namespace ash |