15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_window_state.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/prefs/scoped_user_pref_update.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/defaults.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sessions/session_service.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sessions/session_service_factory.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/window_sizer/window_sizer.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace chrome {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Parse two comma-separated integers from str. Return true on success.
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ParseCommaSeparatedIntegers(const std::string& str,
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 int* ret_num1,
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 int* ret_num2) {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t num1_size = str.find_first_of(',');
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (num1_size == std::string::npos)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t num2_pos = num1_size + 1;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t num2_size = str.size() - num2_pos;
33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  int num1 = 0;
34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  int num2 = 0;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!base::StringToInt(str.substr(0, num1_size), &num1) ||
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !base::StringToInt(str.substr(num2_pos, num2_size), &num2))
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *ret_num1 = num1;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *ret_num2 = num2;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass WindowPlacementPrefUpdate : public DictionaryPrefUpdate {
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public:
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  WindowPlacementPrefUpdate(PrefService* service,
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            const std::string& window_name)
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      : DictionaryPrefUpdate(service, prefs::kAppWindowPlacement),
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        window_name_(window_name) {}
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual ~WindowPlacementPrefUpdate() {}
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual base::DictionaryValue* Get() OVERRIDE {
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    base::DictionaryValue* all_apps_dict = DictionaryPrefUpdate::Get();
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    base::DictionaryValue* this_app_dict = NULL;
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (!all_apps_dict->GetDictionary(window_name_, &this_app_dict)) {
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      this_app_dict = new base::DictionaryValue;
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      all_apps_dict->Set(window_name_, this_app_dict);
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return this_app_dict;
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private:
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const std::string window_name_;
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DISALLOW_COPY_AND_ASSIGN(WindowPlacementPrefUpdate);
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci};
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistd::string GetWindowName(const Browser* browser) {
72116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (browser->app_name().empty()) {
73116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return browser->is_type_popup() ?
74116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        prefs::kBrowserWindowPlacementPopup : prefs::kBrowserWindowPlacement;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return browser->app_name();
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciscoped_ptr<DictionaryPrefUpdate> GetWindowPlacementDictionaryReadWrite(
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::string& window_name,
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    PrefService* prefs) {
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(!window_name.empty());
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // A normal DictionaryPrefUpdate will suffice for non-app windows.
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (prefs->FindPreference(window_name.c_str())) {
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return make_scoped_ptr(
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        new DictionaryPrefUpdate(prefs, window_name.c_str()));
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return scoped_ptr<DictionaryPrefUpdate>(
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      new WindowPlacementPrefUpdate(prefs, window_name));
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst base::DictionaryValue* GetWindowPlacementDictionaryReadOnly(
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::string& window_name,
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    PrefService* prefs) {
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(!window_name.empty());
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (prefs->FindPreference(window_name.c_str()))
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return prefs->GetDictionary(window_name.c_str());
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const base::DictionaryValue* app_windows =
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      prefs->GetDictionary(prefs::kAppWindowPlacement);
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!app_windows)
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return NULL;
1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const base::DictionaryValue* to_return = NULL;
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  app_windows->GetDictionary(window_name, &to_return);
1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return to_return;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShouldSaveWindowPlacement(const Browser* browser) {
109116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Only save the window placement of popups if the window is from a trusted
110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // source (v1 app, devtools, or system window).
111116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return (browser->type() == Browser::TYPE_TABBED) ||
112116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ((browser->type() == Browser::TYPE_POPUP) && browser->is_trusted_source());
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SaveWindowPlacement(const Browser* browser,
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const gfx::Rect& bounds,
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         ui::WindowShowState show_state) {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Save to the session storage service, used when reloading a past session.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that we don't want to be the ones who cause lazy initialization of
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the session service. This function gets called during initial window
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // showing, and we don't want to bring in the session service this early.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SessionService* session_service =
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SessionServiceFactory::GetForProfileIfExisting(browser->profile());
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (session_service)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    session_service->SetWindowBounds(browser->session_id(), bounds, show_state);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GetSavedWindowBoundsAndShowState(const Browser* browser,
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      gfx::Rect* bounds,
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      ui::WindowShowState* show_state) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(browser);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(bounds);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(show_state);
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *bounds = browser->override_bounds();
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WindowSizer::GetBrowserWindowBoundsAndShowState(browser->app_name(),
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  *bounds,
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  browser,
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  bounds,
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  show_state);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool record_mode = parsed_command_line.HasSwitch(switches::kRecordMode);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool playback_mode = parsed_command_line.HasSwitch(switches::kPlaybackMode);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (record_mode || playback_mode) {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // In playback/record mode we always fix the size of the browser and
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // move it to (0,0).  The reason for this is two reasons:  First we want
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // resize/moves in the playback to still work, and Second we want
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // playbacks to work (as much as possible) on machines w/ different
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // screen sizes.
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *bounds = gfx::Rect(0, 0, 800, 600);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The following options override playback/record.
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parsed_command_line.HasSwitch(switches::kWindowSize)) {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string str =
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        parsed_command_line.GetSwitchValueASCII(switches::kWindowSize);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int width, height;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ParseCommaSeparatedIntegers(str, &width, &height))
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bounds->set_size(gfx::Size(width, height));
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parsed_command_line.HasSwitch(switches::kWindowPosition)) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string str =
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        parsed_command_line.GetSwitchValueASCII(switches::kWindowPosition);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int x, y;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ParseCommaSeparatedIntegers(str, &x, &y))
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bounds->set_origin(gfx::Point(x, y));
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace chrome
171