1 // Copyright 2020 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. 4 5 #include "ash/display/display_highlight_controller.h" 6 7 #include "ash/display/window_tree_host_manager.h" 8 #include "ash/magnifier/magnification_controller.h" 9 #include "ash/public/cpp/shell_window_ids.h" 10 #include "ash/session/session_controller_impl.h" 11 #include "ash/shell.h" 12 #include "ui/compositor/layer.h" 13 #include "ui/compositor/layer_type.h" 14 #include "ui/compositor/paint_recorder.h" 15 #include "ui/display/manager/display_manager.h" 16 #include "ui/gfx/color_palette.h" 17 #include "ui/views/border.h" 18 #include "ui/wm/core/window_animations.h" 19 20 namespace ash { 21 22 namespace { 23 24 constexpr SkColor kHighlightColor = gfx::kGoogleBlue600; 25 constexpr int kHighlightSizeFactor = 128; 26 CreateHighlightWidget(const display::Display & display)27std::unique_ptr<views::Widget> CreateHighlightWidget( 28 const display::Display& display) { 29 const int64_t display_id = display.id(); 30 31 DCHECK_NE(display_id, display::kInvalidDisplayId); 32 33 views::Widget::InitParams params( 34 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); 35 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 36 params.activatable = views::Widget::InitParams::ACTIVATABLE_NO; 37 params.accept_events = false; 38 params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent; 39 40 aura::Window* root = Shell::GetRootWindowForDisplayId(display_id); 41 42 params.parent = root->GetChildById(kShellWindowId_ScreenAnimationContainer); 43 params.bounds = root->GetBoundsInRootWindow(); 44 params.name = "DisplayIdentificationHighlight"; 45 46 std::unique_ptr<views::Widget> highlight_widget = 47 std::make_unique<views::Widget>(); 48 49 const int highlight_thickness = 50 std::max(params.bounds.width(), params.bounds.height()) / 51 kHighlightSizeFactor; 52 53 highlight_widget->Init(std::move(params)); 54 55 highlight_widget->GetRootView()->SetBorder( 56 views::CreateSolidBorder(highlight_thickness, kHighlightColor)); 57 58 auto* window = highlight_widget->GetNativeWindow(); 59 window->set_id(kShellWindowId_DisplayIdentificationHighlightWindow); 60 ::wm::SetWindowVisibilityAnimationTransition(window, ::wm::ANIMATE_NONE); 61 62 MagnificationController* magnification_controller = 63 Shell::Get()->magnification_controller(); 64 65 // Forces a redraw of full-screen magnification in order to reverse 66 // magnification on display highlight window performed in 67 // MagnificationController::ReDraw(). If redraw is not forced, then the 68 // highlight may not show up around the edges of the display properly until 69 // the next redraw. 70 if (magnification_controller->IsEnabled()) { 71 magnification_controller->MoveWindow( 72 magnification_controller->GetWindowPosition(), false); 73 } 74 75 highlight_widget->Show(); 76 77 return highlight_widget; 78 } 79 80 } // namespace 81 DisplayHighlightController()82DisplayHighlightController::DisplayHighlightController() { 83 Shell* shell = Shell::Get(); 84 SessionControllerImpl* session_controller = shell->session_controller(); 85 86 session_controller->AddObserver(this); 87 shell->window_tree_host_manager()->AddObserver(this); 88 89 is_locked_ = session_controller->IsScreenLocked(); 90 } 91 ~DisplayHighlightController()92DisplayHighlightController::~DisplayHighlightController() { 93 Shell* shell = Shell::Get(); 94 95 shell->window_tree_host_manager()->RemoveObserver(this); 96 shell->session_controller()->RemoveObserver(this); 97 } 98 UpdateDisplayIdentificationHighlight()99void DisplayHighlightController::UpdateDisplayIdentificationHighlight() { 100 if (selected_display_id_ == display::kInvalidDisplayId) { 101 highlight_widget_.reset(); 102 return; 103 } 104 105 display::DisplayManager* display_manager = Shell::Get()->display_manager(); 106 107 // If |selected_display_id_| does not correspond to an active display, we 108 // cannot display highlights. 109 if (!display_manager->IsActiveDisplayId(selected_display_id_)) { 110 highlight_widget_.reset(); 111 return; 112 } 113 114 // If there is only one display, we don't need to show a special highlight for 115 // it since there is only one place for the user to look. 116 if (display_manager->GetNumDisplays() == 1) { 117 highlight_widget_.reset(); 118 return; 119 } 120 121 // Don't show a highlight if the device is locked to ensure that the highlight 122 // does not appear on the login screen. 123 if (is_locked_) { 124 highlight_widget_.reset(); 125 return; 126 } 127 128 highlight_widget_ = CreateHighlightWidget( 129 display_manager->GetDisplayForId(selected_display_id_)); 130 } 131 OnLockStateChanged(bool locked)132void DisplayHighlightController::OnLockStateChanged(bool locked) { 133 is_locked_ = locked; 134 UpdateDisplayIdentificationHighlight(); 135 } 136 OnDisplayConfigurationChanged()137void DisplayHighlightController::OnDisplayConfigurationChanged() { 138 UpdateDisplayIdentificationHighlight(); 139 } 140 OnDisplaysInitialized()141void DisplayHighlightController::OnDisplaysInitialized() { 142 UpdateDisplayIdentificationHighlight(); 143 } 144 SetHighlightedDisplay(int64_t display_id)145void DisplayHighlightController::SetHighlightedDisplay(int64_t display_id) { 146 if (selected_display_id_ != display_id) { 147 selected_display_id_ = display_id; 148 UpdateDisplayIdentificationHighlight(); 149 } 150 } 151 152 } // namespace ash 153