1 // Copyright (c) 2012 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 "chrome/browser/ui/browser_finder.h"
6
7 #include <stdint.h>
8
9 #include <algorithm>
10
11 #include "build/build_config.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/ui/browser_list.h"
14 #include "chrome/browser/ui/browser_window.h"
15 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
16 #include "chrome/browser/ui/tabs/tab_group_model.h"
17 #include "chrome/browser/ui/tabs/tab_strip_model.h"
18 #include "components/tab_groups/tab_group_id.h"
19 #include "content/public/browser/navigation_controller.h"
20 #include "ui/display/display.h"
21 #include "ui/display/screen.h"
22
23 #if defined(OS_CHROMEOS)
24 #include "ash/public/cpp/multi_user_window_manager.h"
25 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
26 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_helper.h"
27 #include "components/account_id/account_id.h"
28 #endif
29
30 using content::WebContents;
31
32 namespace {
33
34 // Type used to indicate to match anything.
35 const uint32_t kMatchAny = 0;
36
37 // See BrowserMatches for details.
38 const uint32_t kMatchOriginalProfile = 1 << 0;
39 const uint32_t kMatchCanSupportWindowFeature = 1 << 1;
40 const uint32_t kMatchNormal = 1 << 2;
41 const uint32_t kMatchDisplayId = 1 << 3;
42 #if defined(OS_WIN) || defined(OS_CHROMEOS)
43 const uint32_t kMatchCurrentWorkspace = 1 << 4;
44 #endif
45
46 // Returns true if the specified |browser| matches the specified arguments.
47 // |match_types| is a bitmask dictating what parameters to match:
48 // . If it contains kMatchOriginalProfile then the original profile of the
49 // browser must match |profile->GetOriginalProfile()|. This is used to match
50 // incognito windows.
51 // . If it contains kMatchCanSupportWindowFeature
52 // |CanSupportWindowFeature(window_feature)| must return true.
53 // . If it contains kMatchNormal, the browser must be a normal tabbed browser.
BrowserMatches(Browser * browser,Profile * profile,Browser::WindowFeature window_feature,uint32_t match_types,int64_t display_id)54 bool BrowserMatches(Browser* browser,
55 Profile* profile,
56 Browser::WindowFeature window_feature,
57 uint32_t match_types,
58 int64_t display_id) {
59 if ((match_types & kMatchCanSupportWindowFeature) &&
60 !browser->CanSupportWindowFeature(window_feature)) {
61 return false;
62 }
63
64 #if defined(OS_CHROMEOS)
65 // Get the profile on which the window is currently shown.
66 // MultiUserWindowManagerHelper might be NULL under test scenario.
67 ash::MultiUserWindowManager* const multi_user_window_manager =
68 MultiUserWindowManagerHelper::GetWindowManager();
69 Profile* shown_profile = nullptr;
70 if (multi_user_window_manager) {
71 const AccountId& shown_account_id =
72 multi_user_window_manager->GetUserPresentingWindow(
73 browser->window()->GetNativeWindow());
74 shown_profile =
75 shown_account_id.is_valid()
76 ? multi_user_util::GetProfileFromAccountId(shown_account_id)
77 : nullptr;
78 }
79 #endif
80
81 if (match_types & kMatchOriginalProfile) {
82 if (browser->profile()->GetOriginalProfile() !=
83 profile->GetOriginalProfile())
84 return false;
85 #if defined(OS_CHROMEOS)
86 if (shown_profile &&
87 shown_profile->GetOriginalProfile() != profile->GetOriginalProfile()) {
88 return false;
89 }
90 #endif
91 } else {
92 if (browser->profile() != profile)
93 return false;
94 #if defined(OS_CHROMEOS)
95 if (shown_profile && shown_profile != profile)
96 return false;
97 #endif
98 }
99
100 if ((match_types & kMatchNormal) && !browser->is_type_normal())
101 return false;
102
103 #if defined(OS_WIN) || defined(OS_CHROMEOS)
104 // Note that |browser->window()| might be nullptr in tests.
105 if ((match_types & kMatchCurrentWorkspace) &&
106 (!browser->window() || !browser->window()->IsOnCurrentWorkspace())) {
107 return false;
108 }
109 #endif // OS_WIN
110
111 if (match_types & kMatchDisplayId) {
112 return display::Screen::GetScreen()
113 ->GetDisplayNearestWindow(browser->window()->GetNativeWindow())
114 .id() == display_id;
115 }
116
117 return true;
118 }
119
120 // Returns the first browser in the specified iterator that returns true from
121 // |BrowserMatches|, or null if no browsers match the arguments. See
122 // |BrowserMatches| for details on the arguments.
123 template <class T>
FindBrowserMatching(const T & begin,const T & end,Profile * profile,Browser::WindowFeature window_feature,uint32_t match_types,int64_t display_id=display::kInvalidDisplayId)124 Browser* FindBrowserMatching(const T& begin,
125 const T& end,
126 Profile* profile,
127 Browser::WindowFeature window_feature,
128 uint32_t match_types,
129 int64_t display_id = display::kInvalidDisplayId) {
130 for (T i = begin; i != end; ++i) {
131 if (BrowserMatches(*i, profile, window_feature, match_types, display_id))
132 return *i;
133 }
134 return NULL;
135 }
136
FindBrowserWithTabbedOrAnyType(Profile * profile,bool match_tabbed,bool match_original_profiles,bool match_current_workspace,int64_t display_id=display::kInvalidDisplayId)137 Browser* FindBrowserWithTabbedOrAnyType(
138 Profile* profile,
139 bool match_tabbed,
140 bool match_original_profiles,
141 bool match_current_workspace,
142 int64_t display_id = display::kInvalidDisplayId) {
143 BrowserList* browser_list_impl = BrowserList::GetInstance();
144 if (!browser_list_impl)
145 return NULL;
146 uint32_t match_types = kMatchAny;
147 if (match_tabbed)
148 match_types |= kMatchNormal;
149 if (match_original_profiles)
150 match_types |= kMatchOriginalProfile;
151 if (display_id != display::kInvalidDisplayId)
152 match_types |= kMatchDisplayId;
153 #if defined(OS_WIN) || defined(OS_CHROMEOS)
154 if (match_current_workspace)
155 match_types |= kMatchCurrentWorkspace;
156 #endif
157 Browser* browser =
158 FindBrowserMatching(browser_list_impl->begin_last_active(),
159 browser_list_impl->end_last_active(), profile,
160 Browser::FEATURE_NONE, match_types, display_id);
161 // Fall back to a forward scan of all Browsers if no active one was found.
162 return browser ? browser
163 : FindBrowserMatching(
164 browser_list_impl->begin(), browser_list_impl->end(),
165 profile, Browser::FEATURE_NONE, match_types, display_id);
166 }
167
GetBrowserCountImpl(Profile * profile,uint32_t match_types,int64_t display_id=display::kInvalidDisplayId)168 size_t GetBrowserCountImpl(Profile* profile,
169 uint32_t match_types,
170 int64_t display_id = display::kInvalidDisplayId) {
171 BrowserList* browser_list_impl = BrowserList::GetInstance();
172 size_t count = 0;
173 if (browser_list_impl) {
174 for (auto i = browser_list_impl->begin(); i != browser_list_impl->end();
175 ++i) {
176 if (BrowserMatches(*i, profile, Browser::FEATURE_NONE, match_types,
177 display_id))
178 count++;
179 }
180 }
181 return count;
182 }
183
184 } // namespace
185
186 namespace chrome {
187
FindTabbedBrowser(Profile * profile,bool match_original_profiles,int64_t display_id)188 Browser* FindTabbedBrowser(Profile* profile,
189 bool match_original_profiles,
190 int64_t display_id) {
191 return FindBrowserWithTabbedOrAnyType(profile, true, match_original_profiles,
192 /*match_current_workspace=*/true,
193 display_id);
194 }
195
FindAnyBrowser(Profile * profile,bool match_original_profiles)196 Browser* FindAnyBrowser(Profile* profile, bool match_original_profiles) {
197 return FindBrowserWithTabbedOrAnyType(profile, false, match_original_profiles,
198 /*match_current_workspace=*/false);
199 }
200
FindBrowserWithProfile(Profile * profile)201 Browser* FindBrowserWithProfile(Profile* profile) {
202 return FindBrowserWithTabbedOrAnyType(profile, false, false,
203 /*match_current_workspace=*/false);
204 }
205
FindBrowserWithID(SessionID desired_id)206 Browser* FindBrowserWithID(SessionID desired_id) {
207 for (auto* browser : *BrowserList::GetInstance()) {
208 if (browser->session_id() == desired_id)
209 return browser;
210 }
211 return NULL;
212 }
213
FindBrowserWithWindow(gfx::NativeWindow window)214 Browser* FindBrowserWithWindow(gfx::NativeWindow window) {
215 if (!window)
216 return NULL;
217 for (auto* browser : *BrowserList::GetInstance()) {
218 if (browser->window() && browser->window()->GetNativeWindow() == window)
219 return browser;
220 }
221 return NULL;
222 }
223
FindBrowserWithActiveWindow()224 Browser* FindBrowserWithActiveWindow() {
225 Browser* browser = BrowserList::GetInstance()->GetLastActive();
226 return browser && browser->window()->IsActive() ? browser : nullptr;
227 }
228
FindBrowserWithWebContents(const WebContents * web_contents)229 Browser* FindBrowserWithWebContents(const WebContents* web_contents) {
230 DCHECK(web_contents);
231 auto& all_tabs = AllTabContentses();
232 auto it = std::find(all_tabs.begin(), all_tabs.end(), web_contents);
233
234 return (it == all_tabs.end()) ? nullptr : it.browser();
235 }
236
FindBrowserWithGroup(tab_groups::TabGroupId group,Profile * profile)237 Browser* FindBrowserWithGroup(tab_groups::TabGroupId group, Profile* profile) {
238 for (auto* browser : *BrowserList::GetInstance()) {
239 if ((!profile || browser->profile() == profile) &&
240 browser->tab_strip_model() &&
241 browser->tab_strip_model()->group_model()->ContainsTabGroup(group)) {
242 return browser;
243 }
244 }
245 return nullptr;
246 }
247
FindLastActiveWithProfile(Profile * profile)248 Browser* FindLastActiveWithProfile(Profile* profile) {
249 BrowserList* list = BrowserList::GetInstance();
250 // We are only interested in last active browsers, so we don't fall back to
251 // all browsers like FindBrowserWith* do.
252 return FindBrowserMatching(list->begin_last_active(), list->end_last_active(),
253 profile, Browser::FEATURE_NONE, kMatchAny);
254 }
255
FindLastActive()256 Browser* FindLastActive() {
257 BrowserList* browser_list_impl = BrowserList::GetInstance();
258 if (browser_list_impl)
259 return browser_list_impl->GetLastActive();
260 return NULL;
261 }
262
GetTotalBrowserCount()263 size_t GetTotalBrowserCount() {
264 return BrowserList::GetInstance()->size();
265 }
266
GetBrowserCount(Profile * profile)267 size_t GetBrowserCount(Profile* profile) {
268 return GetBrowserCountImpl(profile, kMatchAny);
269 }
270
GetTabbedBrowserCount(Profile * profile)271 size_t GetTabbedBrowserCount(Profile* profile) {
272 return GetBrowserCountImpl(profile, kMatchNormal);
273 }
274
275 } // namespace chrome
276