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_window_state.h"
6
7#include "base/command_line.h"
8#include "base/prefs/pref_service.h"
9#include "base/prefs/scoped_user_pref_update.h"
10#include "base/strings/string_number_conversions.h"
11#include "chrome/browser/defaults.h"
12#include "chrome/browser/profiles/profile.h"
13#include "chrome/browser/sessions/session_service.h"
14#include "chrome/browser/sessions/session_service_factory.h"
15#include "chrome/browser/ui/browser.h"
16#include "chrome/browser/ui/window_sizer/window_sizer.h"
17#include "chrome/common/chrome_switches.h"
18#include "chrome/common/pref_names.h"
19
20namespace chrome {
21namespace {
22
23// Parse two comma-separated integers from str. Return true on success.
24bool ParseCommaSeparatedIntegers(const std::string& str,
25                                 int* ret_num1,
26                                 int* ret_num2) {
27  size_t num1_size = str.find_first_of(',');
28  if (num1_size == std::string::npos)
29    return false;
30
31  size_t num2_pos = num1_size + 1;
32  size_t num2_size = str.size() - num2_pos;
33  int num1 = 0;
34  int num2 = 0;
35  if (!base::StringToInt(str.substr(0, num1_size), &num1) ||
36      !base::StringToInt(str.substr(num2_pos, num2_size), &num2))
37    return false;
38
39  *ret_num1 = num1;
40  *ret_num2 = num2;
41  return true;
42}
43
44class WindowPlacementPrefUpdate : public DictionaryPrefUpdate {
45 public:
46  WindowPlacementPrefUpdate(PrefService* service,
47                            const std::string& window_name)
48      : DictionaryPrefUpdate(service, prefs::kAppWindowPlacement),
49        window_name_(window_name) {}
50
51  virtual ~WindowPlacementPrefUpdate() {}
52
53  virtual base::DictionaryValue* Get() OVERRIDE {
54    base::DictionaryValue* all_apps_dict = DictionaryPrefUpdate::Get();
55    base::DictionaryValue* this_app_dict = NULL;
56    if (!all_apps_dict->GetDictionary(window_name_, &this_app_dict)) {
57      this_app_dict = new base::DictionaryValue;
58      all_apps_dict->Set(window_name_, this_app_dict);
59    }
60    return this_app_dict;
61  }
62
63 private:
64  const std::string window_name_;
65
66  DISALLOW_COPY_AND_ASSIGN(WindowPlacementPrefUpdate);
67};
68
69}  // namespace
70
71std::string GetWindowName(const Browser* browser) {
72  if (browser->app_name().empty()) {
73    return browser->is_type_popup() ?
74        prefs::kBrowserWindowPlacementPopup : prefs::kBrowserWindowPlacement;
75  }
76  return browser->app_name();
77}
78
79scoped_ptr<DictionaryPrefUpdate> GetWindowPlacementDictionaryReadWrite(
80    const std::string& window_name,
81    PrefService* prefs) {
82  DCHECK(!window_name.empty());
83  // A normal DictionaryPrefUpdate will suffice for non-app windows.
84  if (prefs->FindPreference(window_name.c_str())) {
85    return make_scoped_ptr(
86        new DictionaryPrefUpdate(prefs, window_name.c_str()));
87  }
88  return scoped_ptr<DictionaryPrefUpdate>(
89      new WindowPlacementPrefUpdate(prefs, window_name));
90}
91
92const base::DictionaryValue* GetWindowPlacementDictionaryReadOnly(
93    const std::string& window_name,
94    PrefService* prefs) {
95  DCHECK(!window_name.empty());
96  if (prefs->FindPreference(window_name.c_str()))
97    return prefs->GetDictionary(window_name.c_str());
98
99  const base::DictionaryValue* app_windows =
100      prefs->GetDictionary(prefs::kAppWindowPlacement);
101  if (!app_windows)
102    return NULL;
103  const base::DictionaryValue* to_return = NULL;
104  app_windows->GetDictionary(window_name, &to_return);
105  return to_return;
106}
107
108bool ShouldSaveWindowPlacement(const Browser* browser) {
109  // Only save the window placement of popups if the window is from a trusted
110  // source (v1 app, devtools, or system window).
111  return (browser->type() == Browser::TYPE_TABBED) ||
112    ((browser->type() == Browser::TYPE_POPUP) && browser->is_trusted_source());
113}
114
115void SaveWindowPlacement(const Browser* browser,
116                         const gfx::Rect& bounds,
117                         ui::WindowShowState show_state) {
118  // Save to the session storage service, used when reloading a past session.
119  // Note that we don't want to be the ones who cause lazy initialization of
120  // the session service. This function gets called during initial window
121  // showing, and we don't want to bring in the session service this early.
122  SessionService* session_service =
123      SessionServiceFactory::GetForProfileIfExisting(browser->profile());
124  if (session_service)
125    session_service->SetWindowBounds(browser->session_id(), bounds, show_state);
126}
127
128void GetSavedWindowBoundsAndShowState(const Browser* browser,
129                                      gfx::Rect* bounds,
130                                      ui::WindowShowState* show_state) {
131  DCHECK(browser);
132  DCHECK(bounds);
133  DCHECK(show_state);
134  *bounds = browser->override_bounds();
135  WindowSizer::GetBrowserWindowBoundsAndShowState(browser->app_name(),
136                                                  *bounds,
137                                                  browser,
138                                                  bounds,
139                                                  show_state);
140
141  const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
142  bool record_mode = parsed_command_line.HasSwitch(switches::kRecordMode);
143  bool playback_mode = parsed_command_line.HasSwitch(switches::kPlaybackMode);
144  if (record_mode || playback_mode) {
145    // In playback/record mode we always fix the size of the browser and
146    // move it to (0,0).  The reason for this is two reasons:  First we want
147    // resize/moves in the playback to still work, and Second we want
148    // playbacks to work (as much as possible) on machines w/ different
149    // screen sizes.
150    *bounds = gfx::Rect(0, 0, 800, 600);
151  }
152
153  // The following options override playback/record.
154  if (parsed_command_line.HasSwitch(switches::kWindowSize)) {
155    std::string str =
156        parsed_command_line.GetSwitchValueASCII(switches::kWindowSize);
157    int width, height;
158    if (ParseCommaSeparatedIntegers(str, &width, &height))
159      bounds->set_size(gfx::Size(width, height));
160  }
161  if (parsed_command_line.HasSwitch(switches::kWindowPosition)) {
162    std::string str =
163        parsed_command_line.GetSwitchValueASCII(switches::kWindowPosition);
164    int x, y;
165    if (ParseCommaSeparatedIntegers(str, &x, &y))
166      bounds->set_origin(gfx::Point(x, y));
167  }
168}
169
170}  // namespace chrome
171