blob: de8b5a0c153b3e5e0f6309b5565326446f2389eb [file] [log] [blame]
// Copyright (c) 2012 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 "chrome/browser/ui/browser_window_state.h"
#include <stddef.h>
#include <utility>
#include "base/command_line.h"
#include "base/strings/string_number_conversions.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/buildflags.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/profiles/profile.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"
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) {
size_t num1_size = str.find_first_of(',');
if (num1_size == std::string::npos)
return false;
size_t num2_pos = num1_size + 1;
size_t num2_size = str.size() - num2_pos;
int num1 = 0;
int num2 = 0;
if (!base::StringToInt(str.substr(0, num1_size), &num1) ||
!base::StringToInt(str.substr(num2_pos, num2_size), &num2))
return false;
*ret_num1 = num1;
*ret_num2 = num2;
return true;
}
class WindowPlacementPrefUpdate : public DictionaryPrefUpdate {
public:
WindowPlacementPrefUpdate(PrefService* service,
const std::string& window_name)
: DictionaryPrefUpdate(service, prefs::kAppWindowPlacement),
window_name_(window_name) {}
WindowPlacementPrefUpdate(const WindowPlacementPrefUpdate&) = delete;
WindowPlacementPrefUpdate& operator=(const WindowPlacementPrefUpdate&) =
delete;
~WindowPlacementPrefUpdate() override {}
base::Value* Get() override {
base::Value* all_apps_dict = DictionaryPrefUpdate::Get();
base::Value* this_app_dict = all_apps_dict->FindDictPath(window_name_);
if (!this_app_dict) {
this_app_dict = all_apps_dict->SetPath(
window_name_, base::Value(base::Value::Type::DICTIONARY));
}
return this_app_dict;
}
private:
const std::string window_name_;
};
} // namespace
std::string GetWindowName(const Browser* browser) {
switch (browser->type()) {
case Browser::TYPE_NORMAL:
#if BUILDFLAG(IS_CHROMEOS_ASH)
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";
}
}
std::unique_ptr<DictionaryPrefUpdate> GetWindowPlacementDictionaryReadWrite(
const std::string& window_name,
PrefService* prefs) {
DCHECK(!window_name.empty());
// A normal DictionaryPrefUpdate will suffice for non-app windows.
if (prefs->FindPreference(window_name)) {
return std::make_unique<DictionaryPrefUpdate>(prefs, window_name);
}
return std::make_unique<WindowPlacementPrefUpdate>(prefs, window_name);
}
const base::Value* GetWindowPlacementDictionaryReadOnly(
const std::string& window_name,
PrefService* prefs) {
DCHECK(!window_name.empty());
if (prefs->FindPreference(window_name))
return prefs->GetDictionary(window_name);
const base::Value* app_windows =
prefs->GetDictionary(prefs::kAppWindowPlacement);
if (!app_windows)
return nullptr;
return app_windows->FindDictKey(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::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::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::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::SHOW_STATE_NORMAL;
}
}
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::SHOW_STATE_NORMAL;
}
}
}
} // namespace internal
} // namespace chrome