blob: 175d95ae58f2211aac03ed428869489e3e9d5e86 [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/macros.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_service.h"
#include "chrome/browser/sessions/session_service_factory.h"
#include "chrome/browser/ui/browser.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() override {}
base::DictionaryValue* Get() override {
base::DictionaryValue* all_apps_dict = DictionaryPrefUpdate::Get();
base::DictionaryValue* this_app_dict_weak = NULL;
if (!all_apps_dict->GetDictionary(window_name_, &this_app_dict_weak)) {
auto this_app_dict = std::make_unique<base::DictionaryValue>();
this_app_dict_weak = this_app_dict.get();
all_apps_dict->Set(window_name_, std::move(this_app_dict));
}
return this_app_dict_weak;
}
private:
const std::string window_name_;
DISALLOW_COPY_AND_ASSIGN(WindowPlacementPrefUpdate);
};
} // namespace
std::string GetWindowName(const Browser* browser) {
if (browser->app_name().empty()) {
return browser->is_type_popup() ?
prefs::kBrowserWindowPlacementPopup : prefs::kBrowserWindowPlacement;
}
return browser->app_name();
}
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::unique_ptr<DictionaryPrefUpdate>(
new WindowPlacementPrefUpdate(prefs, window_name));
}
const base::DictionaryValue* GetWindowPlacementDictionaryReadOnly(
const std::string& window_name,
PrefService* prefs) {
DCHECK(!window_name.empty());
if (prefs->FindPreference(window_name))
return prefs->GetDictionary(window_name);
const base::DictionaryValue* app_windows =
prefs->GetDictionary(prefs::kAppWindowPlacement);
if (!app_windows)
return NULL;
const base::DictionaryValue* to_return = NULL;
app_windows->GetDictionary(window_name, &to_return);
return to_return;
}
bool ShouldSaveWindowPlacement(const Browser* browser) {
// Only save the window placement of popups if the window is from a trusted
// source (v1 app, devtools, or system window).
return (browser->type() == Browser::TYPE_TABBED) ||
((browser->type() == Browser::TYPE_POPUP) && browser->is_trusted_source());
}
bool SavedBoundsAreContentBounds(const Browser* browser) {
// Pop ups such as devtools or bookmark app windows should behave as per other
// windows with persisted sizes - treating the saved bounds as window bounds.
return browser->is_type_popup() && !browser->is_app() &&
!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.
SessionService* session_service =
SessionServiceFactory::GetForProfileIfExisting(browser->profile());
if (session_service)
session_service->SetWindowBounds(browser->session_id(), bounds, show_state);
}
void SaveWindowWorkspace(const Browser* browser, const std::string& workspace) {
SessionService* session_service =
SessionServiceFactory::GetForProfileIfExisting(browser->profile());
if (session_service)
session_service->SetWindowWorkspace(browser->session_id(), workspace);
}
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(browser->app_name(),
*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