123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- // Copyright 2022 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/shelf/login_shelf_widget.h"
- #include "ash/focus_cycler.h"
- #include "ash/root_window_controller.h"
- #include "ash/shelf/login_shelf_view.h"
- #include "ash/shelf/shelf.h"
- #include "ash/shelf/shelf_layout_manager.h"
- #include "ash/shelf/shelf_widget.h"
- #include "ui/views/accessible_pane_view.h"
- #include "ui/views/focus/focus_search.h"
- #include "ui/views/layout/fill_layout.h"
- namespace ash {
- // LoginShelfWidget::LoginShelfWidgetDelegate ----------------------------------
- // The delegate of the login shelf widget.
- class LoginShelfWidget::LoginShelfWidgetDelegate
- : public views::AccessiblePaneView,
- public views::WidgetDelegate {
- public:
- explicit LoginShelfWidgetDelegate(Shelf* shelf) : shelf_(shelf) {
- SetOwnedByWidget(true);
- set_allow_deactivate_on_esc(true);
- SetLayoutManager(std::make_unique<views::FillLayout>());
- }
- LoginShelfWidgetDelegate(const LoginShelfWidgetDelegate&) = delete;
- LoginShelfWidgetDelegate& operator=(const LoginShelfWidgetDelegate&) = delete;
- ~LoginShelfWidgetDelegate() override = default;
- // views::View:
- views::View* GetDefaultFocusableChild() override {
- // `login_shelf_view` is added to the widget delegate as a child when the
- // login shelf widget is constructed and is removed when the widget is
- // destructed. Therefore, `login_shelf_view` is not null here.
- views::View* login_shelf_view = children()[0];
- views::FocusSearch search(login_shelf_view, default_last_focusable_child_,
- /*accessibility_mode=*/false);
- views::FocusTraversable* dummy_focus_traversable;
- views::View* dummy_focus_traversable_view;
- return search.FindNextFocusableView(
- login_shelf_view,
- default_last_focusable_child_
- ? views::FocusSearch::SearchDirection::kBackwards
- : views::FocusSearch::SearchDirection::kForwards,
- views::FocusSearch::TraversalDirection::kDown,
- views::FocusSearch::StartingViewPolicy::kSkipStartingView,
- views::FocusSearch::AnchoredDialogPolicy::kCanGoIntoAnchoredDialog,
- &dummy_focus_traversable, &dummy_focus_traversable_view);
- }
- // views::WidgetDelegate:
- bool CanActivate() const override {
- // We don't want mouse clicks to activate us, but we need to allow
- // activation when the user is using the keyboard (FocusCycler).
- bool can_active = Shell::Get()->focus_cycler()->widget_activating() ==
- views::View::GetWidget();
- return can_active;
- }
- void ChildPreferredSizeChanged(views::View* child) override {
- shelf_->shelf_layout_manager()->LayoutShelf(/*animate=*/false);
- }
- void set_default_last_focusable_child(bool reverse) {
- default_last_focusable_child_ = reverse;
- }
- private:
- const base::raw_ptr<Shelf> shelf_ = nullptr;
- // When true, the default focus of the shelf is the last focusable child.
- bool default_last_focusable_child_ = false;
- };
- // LoginShelfWidget ------------------------------------------------------------
- LoginShelfWidget::LoginShelfWidget(Shelf* shelf, aura::Window* container)
- : shelf_(shelf),
- delegate_(new LoginShelfWidgetDelegate(shelf)),
- scoped_session_observer_(this) {
- DCHECK(container);
- login_shelf_view_ = delegate_->AddChildView(std::make_unique<LoginShelfView>(
- RootWindowController::ForWindow(container)
- ->lock_screen_action_background_controller()));
- views::Widget::InitParams params(
- views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
- params.name = "LoginShelfWidget";
- params.delegate = delegate_;
- params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
- params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.parent = container;
- Init(std::move(params));
- SetContentsView(delegate_);
- // Hide the login shelf by default.
- Hide();
- // TODO(https://crbug.com/1343114): currently, some logics in shelf check the
- // login shelf view's visibility. Update them to check whether the login shelf
- // view is drawn or the widget's visibility. Then remove this line.
- login_shelf_view_->SetVisible(false);
- }
- LoginShelfWidget::~LoginShelfWidget() = default;
- void LoginShelfWidget::SetDefaultLastFocusableChild(bool reverse) {
- delegate_->set_default_last_focusable_child(reverse);
- }
- void LoginShelfWidget::SetLoginShelfButtonOpacity(float target_opacity) {
- login_shelf_view_->SetButtonOpacity(target_opacity);
- }
- void LoginShelfWidget::HandleLocaleChange() {
- login_shelf_view_->HandleLocaleChange();
- }
- void LoginShelfWidget::CalculateTargetBounds() {
- const gfx::Point shelf_origin =
- shelf_->shelf_widget()->GetTargetBounds().origin();
- gfx::Point origin = gfx::Point(shelf_origin.x(), shelf_origin.y());
- const int target_bounds_width = delegate_->GetPreferredSize().width();
- if (shelf_->IsHorizontalAlignment() && base::i18n::IsRTL()) {
- origin.set_x(shelf_->shelf_widget()->GetTargetBounds().size().width() -
- target_bounds_width);
- }
- target_bounds_ =
- gfx::Rect(origin, {target_bounds_width,
- shelf_->shelf_widget()->GetTargetBounds().height()});
- }
- gfx::Rect LoginShelfWidget::GetTargetBounds() const {
- return target_bounds_;
- }
- void LoginShelfWidget::UpdateLayout(bool animate) {
- if (GetNativeView()->bounds() == target_bounds_)
- return;
- SetBounds(target_bounds_);
- }
- bool LoginShelfWidget::OnNativeWidgetActivationChanged(bool active) {
- if (!Widget::OnNativeWidgetActivationChanged(active))
- return false;
- if (active)
- delegate_->SetPaneFocusAndFocusDefault();
- return true;
- }
- void LoginShelfWidget::OnSessionStateChanged(
- session_manager::SessionState state) {
- // The login shelf should be hidden if:
- // 1. the user session is active; or
- // 2. the RMA app is active. The login shelf should be hidden to avoid
- // blocking the RMA app controls or intercepting UI events.
- bool hide_for_session_state =
- (state == session_manager::SessionState::ACTIVE ||
- state == session_manager::SessionState::RMA);
- // The visibility of `login_shelf_view_` is accessed in different places.
- // Therefore, ensure the consistency between the widget's visibility and the
- // view's visibility.
- if (!hide_for_session_state && !shelf_->ShouldHideOnSecondaryDisplay(state)) {
- if (!IsVisible()) {
- Show();
- login_shelf_view_->SetVisible(true);
- }
- } else if (IsVisible()) {
- Hide();
- login_shelf_view_->SetVisible(false);
- }
- login_shelf_view_->UpdateAfterSessionChange();
- }
- void LoginShelfWidget::OnUserSessionAdded(const AccountId& account_id) {
- login_shelf_view_->UpdateAfterSessionChange();
- }
- } // namespace ash
|