blob: 074dc56bd36077335e8c33cda42b4c42f5735d76 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/browser_window_state.h"
#include <stddef.h>
#include <string_view>
#include <utility>
#include "base/command_line.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/buildflags.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/sessions/session_service_base.h"
#include "chrome/browser/sessions/session_service_lookup.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/web_applications/app_browser_controller.h"
#include "chrome/browser/ui/window_sizer/window_sizer.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "ui/base/mojom/window_show_state.mojom.h"
namespace chrome {
namespace {
// Parse two comma-separated integers from str. Return true on success.
bool ParseCommaSeparatedIntegers(const std::string& str,
int* ret_num1,
int* ret_num2) {
const size_t comma = str.find(',');
if (comma == std::string::npos) {
return false;
}
auto view = std::string_view(str);
return base::StringToInt(view.substr(0, comma), ret_num1) &&
base::StringToInt(view.substr(comma + 1), ret_num2);
}
} // namespace
std::string GetWindowName(const Browser* browser) {
switch (browser->type()) {
case Browser::TYPE_NORMAL:
#if BUILDFLAG(IS_CHROMEOS)
case Browser::TYPE_CUSTOM_TAB:
#endif
return prefs::kBrowserWindowPlacement;
case Browser::TYPE_POPUP:
case Browser::TYPE_PICTURE_IN_PICTURE:
return prefs::kBrowserWindowPlacementPopup;
case Browser::TYPE_APP:
case Browser::TYPE_DEVTOOLS:
return browser->app_name();
case Browser::TYPE_APP_POPUP:
return browser->app_name() + "_popup";
}
}
base::Value::Dict& GetWindowPlacementDictionaryReadWrite(
const std::string& window_name,
PrefService* prefs,
std::unique_ptr<ScopedDictPrefUpdate>& scoped_update) {
DCHECK(!window_name.empty());
// Non-app window placements each use their own per-window-name dictionary
// preference, so can make a ScopedDictPrefUpdate for the relevant preference,
// and return its dictionary directly.
if (prefs->FindPreference(window_name)) {
scoped_update = std::make_unique<ScopedDictPrefUpdate>(prefs, window_name);
return scoped_update->Get();
}
// The window placements for all apps are stored in a single dictionary
// preference, with per-window-name nested dictionaries, so need to make
// ScopedDictPrefUpdate and then find the relevant dictionary within it, based
// on window name.
scoped_update =
std::make_unique<ScopedDictPrefUpdate>(prefs, prefs::kAppWindowPlacement);
base::Value::Dict* this_app_dict =
(*scoped_update)->FindDictByDottedPath(window_name);
if (this_app_dict) {
return *this_app_dict;
}
return (*scoped_update)
->SetByDottedPath(window_name, base::Value::Dict())
->GetDict();
}
const base::Value::Dict* GetWindowPlacementDictionaryReadOnly(
const std::string& window_name,
PrefService* prefs) {
DCHECK(!window_name.empty());
if (prefs->FindPreference(window_name)) {
return &prefs->GetDict(window_name);
}
const base::Value::Dict& app_windows =
prefs->GetDict(prefs::kAppWindowPlacement);
return app_windows.FindDict(window_name);
}
bool ShouldSaveWindowPlacement(const Browser* browser) {
// Never track app windows that do not have a trusted source (i.e. windows
// spawned by an app). See similar code in
// SessionServiceBase::ShouldTrackBrowser().
return !(browser->is_type_app() || browser->is_type_app_popup()) ||
browser->is_trusted_source();
}
bool SavedBoundsAreContentBounds(const Browser* browser) {
// Applications other than web apps (such as devtools) save their window size.
// Web apps, on the other hand, have the same behavior as popups, and save
// their content bounds.
return !browser->is_type_normal() && !browser->is_type_devtools() &&
!browser->is_trusted_source();
}
void SaveWindowPlacement(const Browser* browser,
const gfx::Rect& bounds,
ui::mojom::WindowShowState show_state) {
// Save to the session storage service, used when reloading a past session.
// Note that we don't want to be the ones who cause lazy initialization of
// the session service. This function gets called during initial window
// showing, and we don't want to bring in the session service this early.
SessionServiceBase* service = GetAppropriateSessionServiceIfExisting(browser);
if (service) {
service->SetWindowBounds(browser->session_id(), bounds, show_state);
}
}
void SaveWindowWorkspace(const Browser* browser, const std::string& workspace) {
SessionServiceBase* service = GetAppropriateSessionServiceIfExisting(browser);
if (service) {
service->SetWindowWorkspace(browser->session_id(), workspace);
}
}
void SaveWindowVisibleOnAllWorkspaces(const Browser* browser,
bool visible_on_all_workspaces) {
SessionServiceBase* service = GetAppropriateSessionServiceIfExisting(browser);
if (service) {
service->SetWindowVisibleOnAllWorkspaces(browser->session_id(),
visible_on_all_workspaces);
}
}
void GetSavedWindowBoundsAndShowState(const Browser* browser,
gfx::Rect* bounds,
ui::mojom::WindowShowState* show_state) {
DCHECK(browser);
DCHECK(bounds);
DCHECK(show_state);
*bounds = browser->override_bounds();
WindowSizer::GetBrowserWindowBoundsAndShowState(*bounds, browser, bounds,
show_state);
const base::CommandLine& parsed_command_line =
*base::CommandLine::ForCurrentProcess();
internal::UpdateWindowBoundsAndShowStateFromCommandLine(parsed_command_line,
bounds, show_state);
}
namespace internal {
void UpdateWindowBoundsAndShowStateFromCommandLine(
const base::CommandLine& command_line,
gfx::Rect* bounds,
ui::mojom::WindowShowState* show_state) {
// Allow command-line flags to override the window size and position. If
// either of these is specified then set the show state to NORMAL so that
// they are immediately respected.
if (command_line.HasSwitch(switches::kWindowSize)) {
std::string str = command_line.GetSwitchValueASCII(switches::kWindowSize);
int width, height;
if (ParseCommaSeparatedIntegers(str, &width, &height)) {
bounds->set_size(gfx::Size(width, height));
*show_state = ui::mojom::WindowShowState::kNormal;
}
}
if (command_line.HasSwitch(switches::kWindowPosition)) {
std::string str =
command_line.GetSwitchValueASCII(switches::kWindowPosition);
int x, y;
if (ParseCommaSeparatedIntegers(str, &x, &y)) {
bounds->set_origin(gfx::Point(x, y));
*show_state = ui::mojom::WindowShowState::kNormal;
}
}
}
} // namespace internal
} // namespace chrome