[M120 Migration][MM] Fix EME AD insert issue
[platform/framework/web/chromium-efl.git] / ash / focus_cycler.cc
1 // Copyright 2012 The Chromium Authors
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/focus_cycler.h"
6
7 #include "ash/shell.h"
8 #include "ash/wm/mru_window_tracker.h"
9 #include "ash/wm/window_state.h"
10 #include "ash/wm/window_util.h"
11 #include "base/ranges/algorithm.h"
12 #include "ui/views/accessible_pane_view.h"
13 #include "ui/views/focus/focus_search.h"
14 #include "ui/views/widget/widget.h"
15 #include "ui/views/widget/widget_delegate.h"
16 #include "ui/wm/public/activation_client.h"
17
18 namespace ash {
19
20 namespace {
21
22 bool HasFocusableWindow() {
23   return !Shell::Get()
24               ->mru_window_tracker()
25               ->BuildMruWindowList(kActiveDesk)
26               .empty();
27 }
28
29 }  // namespace
30
31 FocusCycler::FocusCycler() : widget_activating_(nullptr) {}
32
33 FocusCycler::~FocusCycler() = default;
34
35 void FocusCycler::AddWidget(views::Widget* widget) {
36   widgets_.push_back(widget);
37 }
38
39 void FocusCycler::RemoveWidget(views::Widget* widget) {
40   auto iter = base::ranges::find(widgets_, widget);
41   if (iter != widgets_.end())
42     widgets_.erase(iter);
43 }
44
45 void FocusCycler::RotateFocus(Direction direction, bool move_onto_next_widget) {
46   if (aura::Window* window = window_util::GetActiveWindow(); window) {
47     views::Widget* widget = views::Widget::GetWidgetForNativeView(window);
48     // First try to rotate focus within the active widget. If that succeeds,
49     // we're done.
50     if (widget && !move_onto_next_widget &&
51         widget->GetFocusManager()->RotatePaneFocus(
52             direction == BACKWARD ? views::FocusManager::Direction::kBackward
53                                   : views::FocusManager::Direction::kForward,
54             views::FocusManager::FocusCycleWrapping::kDisabled)) {
55       return;
56     }
57   }
58
59   const bool has_window = HasFocusableWindow();
60   int index = 0;
61   int count = static_cast<int>(widgets_.size());
62   int browser_index = has_window ? count : -1;
63
64   for (; index < count; ++index) {
65     if (widgets_[index]->IsActive())
66       break;
67   }
68
69   int start_index = index;
70
71   if (has_window)
72     ++count;
73
74   for (;;) {
75     if (direction == FORWARD)
76       index = (index + 1) % count;
77     else
78       index = ((index - 1) + count) % count;
79
80     // Ensure that we don't loop more than once.
81     if (index == start_index)
82       break;
83
84     if (index == browser_index) {
85       // Activate the most recently active browser window.
86       MruWindowTracker::WindowList mru_windows(
87           Shell::Get()->mru_window_tracker()->BuildMruWindowList(kActiveDesk));
88       if (mru_windows.empty())
89         break;
90       auto* window = mru_windows.front();
91       WindowState::Get(window)->Activate();
92       views::Widget* widget = views::Widget::GetWidgetForNativeView(window);
93       if (!widget)
94         break;
95       views::FocusManager* focus_manager = widget->GetFocusManager();
96       focus_manager->ClearFocus();
97       focus_manager->RotatePaneFocus(
98           direction == BACKWARD ? views::FocusManager::Direction::kBackward
99                                 : views::FocusManager::Direction::kForward,
100           views::FocusManager::FocusCycleWrapping::kEnabled);
101       break;
102     } else {
103       if (FocusWidget(widgets_[index]))
104         break;
105     }
106   }
107 }
108
109 bool FocusCycler::FocusWidget(views::Widget* widget) {
110   // If the target is PIP window, temporarily make it activatable.
111   if (WindowState::Get(widget->GetNativeWindow())->IsPip())
112     widget->widget_delegate()->SetCanActivate(true);
113
114   // Note: It is not necessary to set the focus directly to the pane since that
115   // will be taken care of by the widget activation.
116   widget_activating_ = widget;
117   widget->Activate();
118   widget_activating_ = nullptr;
119   return widget->IsActive();
120 }
121
122 views::Widget* FocusCycler::FindWidget(
123     base::RepeatingCallback<bool(views::Widget*)> callback) {
124   for (auto* widget : widgets_) {
125     if (callback.Run(widget))
126       return widget;
127   }
128   return nullptr;
129 }
130
131 }  // namespace ash