| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/display/display_highlight_controller.h" |
| |
| #include "ash/accessibility/magnifier/fullscreen_magnifier_controller.h" |
| #include "ash/display/window_tree_host_manager.h" |
| #include "ash/public/cpp/shell_window_ids.h" |
| #include "ash/session/session_controller_impl.h" |
| #include "ash/shell.h" |
| #include "ui/compositor/layer.h" |
| #include "ui/compositor/layer_type.h" |
| #include "ui/compositor/paint_recorder.h" |
| #include "ui/display/manager/display_manager.h" |
| #include "ui/gfx/color_palette.h" |
| #include "ui/views/border.h" |
| #include "ui/wm/core/window_animations.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| constexpr SkColor kHighlightColor = gfx::kGoogleBlue600; |
| constexpr int kHighlightSizeFactor = 128; |
| |
| std::unique_ptr<views::Widget> CreateHighlightWidget( |
| const display::Display& display) { |
| const int64_t display_id = display.id(); |
| |
| DCHECK_NE(display_id, display::kInvalidDisplayId); |
| |
| views::Widget::InitParams params( |
| views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); |
| params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
| params.activatable = views::Widget::InitParams::Activatable::kNo; |
| params.accept_events = false; |
| params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent; |
| |
| aura::Window* root = Shell::GetRootWindowForDisplayId(display_id); |
| |
| params.parent = root->GetChildById(kShellWindowId_ScreenAnimationContainer); |
| params.bounds = root->GetBoundsInRootWindow(); |
| params.name = "DisplayIdentificationHighlight"; |
| |
| std::unique_ptr<views::Widget> highlight_widget = |
| std::make_unique<views::Widget>(); |
| |
| const int highlight_thickness = |
| std::max(params.bounds.width(), params.bounds.height()) / |
| kHighlightSizeFactor; |
| |
| highlight_widget->Init(std::move(params)); |
| |
| highlight_widget->GetRootView()->SetBorder( |
| views::CreateSolidBorder(highlight_thickness, kHighlightColor)); |
| |
| auto* window = highlight_widget->GetNativeWindow(); |
| window->SetId(kShellWindowId_DisplayIdentificationHighlightWindow); |
| ::wm::SetWindowVisibilityAnimationTransition(window, ::wm::ANIMATE_NONE); |
| |
| FullscreenMagnifierController* magnification_controller = |
| Shell::Get()->fullscreen_magnifier_controller(); |
| |
| // Forces a redraw of full-screen magnification in order to reverse |
| // magnification on display highlight window performed in |
| // FullscreenMagnifierController::ReDraw(). If redraw is not forced, then the |
| // highlight may not show up around the edges of the display properly until |
| // the next redraw. |
| if (magnification_controller->IsEnabled()) { |
| magnification_controller->MoveWindow( |
| magnification_controller->GetWindowPosition(), false); |
| } |
| |
| highlight_widget->Show(); |
| |
| return highlight_widget; |
| } |
| |
| } // namespace |
| |
| DisplayHighlightController::DisplayHighlightController() { |
| Shell* shell = Shell::Get(); |
| SessionControllerImpl* session_controller = shell->session_controller(); |
| |
| session_controller->AddObserver(this); |
| shell->window_tree_host_manager()->AddObserver(this); |
| |
| is_locked_ = session_controller->IsScreenLocked(); |
| } |
| |
| DisplayHighlightController::~DisplayHighlightController() { |
| Shell* shell = Shell::Get(); |
| |
| shell->window_tree_host_manager()->RemoveObserver(this); |
| shell->session_controller()->RemoveObserver(this); |
| } |
| |
| void DisplayHighlightController::UpdateDisplayIdentificationHighlight() { |
| if (selected_display_id_ == display::kInvalidDisplayId) { |
| highlight_widget_.reset(); |
| return; |
| } |
| |
| display::DisplayManager* display_manager = Shell::Get()->display_manager(); |
| |
| // If |selected_display_id_| does not correspond to an active display, we |
| // cannot display highlights. |
| if (!display_manager->IsActiveDisplayId(selected_display_id_)) { |
| highlight_widget_.reset(); |
| return; |
| } |
| |
| // If there is only one display, we don't need to show a special highlight for |
| // it since there is only one place for the user to look. |
| if (display_manager->GetNumDisplays() == 1) { |
| highlight_widget_.reset(); |
| return; |
| } |
| |
| // Don't show a highlight if the device is locked to ensure that the highlight |
| // does not appear on the login screen. |
| if (is_locked_) { |
| highlight_widget_.reset(); |
| return; |
| } |
| |
| highlight_widget_ = CreateHighlightWidget( |
| display_manager->GetDisplayForId(selected_display_id_)); |
| } |
| |
| void DisplayHighlightController::OnLockStateChanged(bool locked) { |
| is_locked_ = locked; |
| UpdateDisplayIdentificationHighlight(); |
| } |
| |
| void DisplayHighlightController::OnDisplayConfigurationChanged() { |
| UpdateDisplayIdentificationHighlight(); |
| } |
| |
| void DisplayHighlightController::OnDisplaysInitialized() { |
| UpdateDisplayIdentificationHighlight(); |
| } |
| |
| void DisplayHighlightController::SetHighlightedDisplay(int64_t display_id) { |
| if (selected_display_id_ != display_id) { |
| selected_display_id_ = display_id; |
| UpdateDisplayIdentificationHighlight(); |
| } |
| } |
| |
| } // namespace ash |