display_options_handler.cc revision ca12bfac764ba476d6cd062bf1dde12cc64c3f40
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/webui/options/chromeos/display_options_handler.h"
6
7#include <string>
8
9#include "ash/display/display_controller.h"
10#include "ash/display/display_manager.h"
11#include "ash/display/output_configurator_animation.h"
12#include "ash/screen_ash.h"
13#include "ash/shell.h"
14#include "base/bind.h"
15#include "base/logging.h"
16#include "base/strings/string_number_conversions.h"
17#include "base/strings/stringprintf.h"
18#include "base/values.h"
19#include "chrome/browser/chromeos/display/display_preferences.h"
20#include "chromeos/display/output_configurator.h"
21#include "content/public/browser/web_ui.h"
22#include "grit/generated_resources.h"
23#include "ui/base/l10n/l10n_util.h"
24#include "ui/gfx/display.h"
25#include "ui/gfx/rect.h"
26#include "ui/gfx/safe_integer_conversions.h"
27#include "ui/gfx/screen.h"
28
29using ash::internal::DisplayManager;
30
31namespace chromeos {
32namespace options {
33namespace {
34
35DisplayManager* GetDisplayManager() {
36  return ash::Shell::GetInstance()->display_manager();
37}
38
39int64 GetDisplayId(const base::ListValue* args) {
40  // Assumes the display ID is specified as the first argument.
41  std::string id_value;
42  if (!args->GetString(0, &id_value)) {
43    LOG(ERROR) << "Can't find ID";
44    return gfx::Display::kInvalidDisplayID;
45  }
46
47  int64 display_id = gfx::Display::kInvalidDisplayID;
48  if (!base::StringToInt64(id_value, &display_id)) {
49    LOG(ERROR) << "Invalid display id: " << id_value;
50    return gfx::Display::kInvalidDisplayID;
51  }
52
53  return display_id;
54}
55
56}  // namespace
57
58DisplayOptionsHandler::DisplayOptionsHandler() {
59  ash::Shell::GetInstance()->display_controller()->AddObserver(this);
60}
61
62DisplayOptionsHandler::~DisplayOptionsHandler() {
63  ash::Shell::GetInstance()->display_controller()->RemoveObserver(this);
64}
65
66void DisplayOptionsHandler::GetLocalizedValues(
67    DictionaryValue* localized_strings) {
68  DCHECK(localized_strings);
69  RegisterTitle(localized_strings, "displayOptionsPage",
70                IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_TAB_TITLE);
71
72  localized_strings->SetString(
73      "selectedDisplayTitleOptions", l10n_util::GetStringUTF16(
74          IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_OPTIONS));
75  localized_strings->SetString(
76      "selectedDisplayTitleResolution", l10n_util::GetStringUTF16(
77          IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_RESOLUTION));
78  localized_strings->SetString(
79      "selectedDisplayTitleOrientation", l10n_util::GetStringUTF16(
80          IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_ORIENTATION));
81  localized_strings->SetString(
82      "selectedDisplayTitleOverscan", l10n_util::GetStringUTF16(
83          IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_OVERSCAN));
84
85  localized_strings->SetString("startMirroring", l10n_util::GetStringUTF16(
86      IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_START_MIRRORING));
87  localized_strings->SetString("stopMirroring", l10n_util::GetStringUTF16(
88      IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_STOP_MIRRORING));
89  localized_strings->SetString("mirroringDisplay", l10n_util::GetStringUTF16(
90      IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_MIRRORING_DISPLAY_NAME));
91  localized_strings->SetString("setPrimary", l10n_util::GetStringUTF16(
92      IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_SET_PRIMARY));
93  localized_strings->SetString("annotateBest", l10n_util::GetStringUTF16(
94      IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_RESOLUTION_ANNOTATION_BEST));
95  localized_strings->SetString("orientation0", l10n_util::GetStringUTF16(
96      IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_STANDARD_ORIENTATION));
97  localized_strings->SetString("orientation90", l10n_util::GetStringUTF16(
98      IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_ORIENTATION_90));
99  localized_strings->SetString("orientation180", l10n_util::GetStringUTF16(
100      IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_ORIENTATION_180));
101  localized_strings->SetString("orientation270", l10n_util::GetStringUTF16(
102      IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_ORIENTATION_270));
103  localized_strings->SetString(
104      "startCalibratingOverscan", l10n_util::GetStringUTF16(
105          IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_START_CALIBRATING_OVERSCAN));
106}
107
108void DisplayOptionsHandler::InitializePage() {
109  DCHECK(web_ui());
110}
111
112void DisplayOptionsHandler::RegisterMessages() {
113  web_ui()->RegisterMessageCallback(
114      "getDisplayInfo",
115      base::Bind(&DisplayOptionsHandler::HandleDisplayInfo,
116                 base::Unretained(this)));
117  web_ui()->RegisterMessageCallback(
118      "setMirroring",
119      base::Bind(&DisplayOptionsHandler::HandleMirroring,
120                 base::Unretained(this)));
121  web_ui()->RegisterMessageCallback(
122      "setPrimary",
123      base::Bind(&DisplayOptionsHandler::HandleSetPrimary,
124                 base::Unretained(this)));
125  web_ui()->RegisterMessageCallback(
126      "setDisplayLayout",
127      base::Bind(&DisplayOptionsHandler::HandleDisplayLayout,
128                 base::Unretained(this)));
129  web_ui()->RegisterMessageCallback(
130      "setUIScale",
131      base::Bind(&DisplayOptionsHandler::HandleSetUIScale,
132                 base::Unretained(this)));
133  web_ui()->RegisterMessageCallback(
134      "setOrientation",
135      base::Bind(&DisplayOptionsHandler::HandleSetOrientation,
136                 base::Unretained(this)));
137}
138
139void DisplayOptionsHandler::OnDisplayConfigurationChanging() {
140}
141
142void DisplayOptionsHandler::OnDisplayConfigurationChanged() {
143  SendAllDisplayInfo();
144}
145
146void DisplayOptionsHandler::SendAllDisplayInfo() {
147  DisplayManager* display_manager = GetDisplayManager();
148
149  std::vector<gfx::Display> displays;
150  for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
151    displays.push_back(display_manager->GetDisplayAt(i));
152  }
153  SendDisplayInfo(displays);
154}
155
156void DisplayOptionsHandler::SendDisplayInfo(
157    const std::vector<gfx::Display>& displays) {
158  DisplayManager* display_manager = GetDisplayManager();
159  ash::DisplayController* display_controller =
160      ash::Shell::GetInstance()->display_controller();
161  base::FundamentalValue mirroring(display_manager->IsMirrored());
162
163  int64 primary_id = ash::Shell::GetScreen()->GetPrimaryDisplay().id();
164  base::ListValue js_displays;
165  for (size_t i = 0; i < displays.size(); ++i) {
166    const gfx::Display& display = displays[i];
167    const ash::internal::DisplayInfo& display_info =
168        display_manager->GetDisplayInfo(display.id());
169    const gfx::Rect& bounds = display.bounds();
170    base::DictionaryValue* js_display = new base::DictionaryValue();
171    js_display->SetString("id", base::Int64ToString(display.id()));
172    js_display->SetInteger("x", bounds.x());
173    js_display->SetInteger("y", bounds.y());
174    js_display->SetInteger("width", bounds.width());
175    js_display->SetInteger("height", bounds.height());
176    js_display->SetString("name",
177                          display_manager->GetDisplayNameForId(display.id()));
178    js_display->SetBoolean("isPrimary", display.id() == primary_id);
179    js_display->SetBoolean("isInternal", display.IsInternal());
180    js_display->SetInteger("orientation",
181                           static_cast<int>(display_info.rotation()));
182    std::vector<float> ui_scales = DisplayManager::GetScalesForDisplay(
183        display_info);
184    base::ListValue* js_scales = new base::ListValue();
185    gfx::SizeF base_size = display_info.bounds_in_pixel().size();
186    base_size.Scale(1.0f / display.device_scale_factor());
187    if (display_info.rotation() == gfx::Display::ROTATE_90 ||
188        display_info.rotation() == gfx::Display::ROTATE_270) {
189      float tmp = base_size.width();
190      base_size.set_width(base_size.height());
191      base_size.set_height(tmp);
192    }
193
194    for (size_t i = 0; i < ui_scales.size(); ++i) {
195      base::DictionaryValue* scale_info = new base::DictionaryValue();
196      scale_info->SetDouble("scale", ui_scales[i]);
197      scale_info->SetInteger(
198          "width", gfx::ToFlooredInt(base_size.width() * ui_scales[i]));
199      scale_info->SetInteger(
200          "height", gfx::ToFlooredInt(base_size.height() * ui_scales[i]));
201      scale_info->SetBoolean("selected",
202                             display_info.ui_scale() == ui_scales[i]);
203      js_scales->Append(scale_info);
204    }
205    js_display->Set("uiScales", js_scales);
206    js_displays.Append(js_display);
207  }
208
209  scoped_ptr<base::Value> layout_value(base::Value::CreateNullValue());
210  scoped_ptr<base::Value> offset_value(base::Value::CreateNullValue());
211  if (display_manager->GetNumDisplays() > 1) {
212    const ash::DisplayLayout layout =
213        display_controller->GetCurrentDisplayLayout();
214    layout_value.reset(new base::FundamentalValue(layout.position));
215    offset_value.reset(new base::FundamentalValue(layout.offset));
216  }
217
218  web_ui()->CallJavascriptFunction(
219      "options.DisplayOptions.setDisplayInfo",
220      mirroring, js_displays, *layout_value.get(), *offset_value.get());
221}
222
223void DisplayOptionsHandler::OnFadeOutForMirroringFinished(bool is_mirroring) {
224  ash::Shell::GetInstance()->display_manager()->SetMirrorMode(is_mirroring);
225  // Not necessary to start fade-in animation.  OutputConfigurator will do that.
226}
227
228void DisplayOptionsHandler::OnFadeOutForDisplayLayoutFinished(
229    int position, int offset) {
230  SetCurrentDisplayLayout(
231      ash::DisplayLayout::FromInts(position, offset));
232  ash::Shell::GetInstance()->output_configurator_animation()->
233      StartFadeInAnimation();
234}
235
236void DisplayOptionsHandler::HandleDisplayInfo(
237    const base::ListValue* unused_args) {
238  SendAllDisplayInfo();
239}
240
241void DisplayOptionsHandler::HandleMirroring(const base::ListValue* args) {
242  DCHECK(!args->empty());
243  bool is_mirroring = false;
244  args->GetBoolean(0, &is_mirroring);
245  ash::Shell::GetInstance()->output_configurator_animation()->
246      StartFadeOutAnimation(base::Bind(
247          &DisplayOptionsHandler::OnFadeOutForMirroringFinished,
248          base::Unretained(this),
249          is_mirroring));
250}
251
252void DisplayOptionsHandler::HandleSetPrimary(const base::ListValue* args) {
253  DCHECK(!args->empty());
254  int64 display_id = GetDisplayId(args);
255  if (display_id == gfx::Display::kInvalidDisplayID)
256    return;
257
258  ash::Shell::GetInstance()->display_controller()->
259      SetPrimaryDisplayId(display_id);
260}
261
262void DisplayOptionsHandler::HandleDisplayLayout(const base::ListValue* args) {
263  double layout = -1;
264  double offset = -1;
265  if (!args->GetDouble(0, &layout) || !args->GetDouble(1, &offset)) {
266    LOG(ERROR) << "Invalid parameter";
267    SendAllDisplayInfo();
268    return;
269  }
270  DCHECK_LE(ash::DisplayLayout::TOP, layout);
271  DCHECK_GE(ash::DisplayLayout::LEFT, layout);
272  ash::Shell::GetInstance()->output_configurator_animation()->
273      StartFadeOutAnimation(base::Bind(
274          &DisplayOptionsHandler::OnFadeOutForDisplayLayoutFinished,
275          base::Unretained(this),
276          static_cast<int>(layout),
277          static_cast<int>(offset)));
278}
279
280void DisplayOptionsHandler::HandleSetUIScale(const base::ListValue* args) {
281  DCHECK(!args->empty());
282
283  int64 display_id = GetDisplayId(args);
284  if (display_id == gfx::Display::kInvalidDisplayID)
285    return;
286
287  std::string ui_scale_value;
288  double ui_scale = 0.0f;
289  if (!args->GetString(1, &ui_scale_value)) {
290    LOG(ERROR) << "Ca't find new ui_scale";
291    return;
292  }
293  if (!base::StringToDouble(ui_scale_value, &ui_scale)) {
294    LOG(ERROR) << "Invalid ui_scale: " << ui_scale_value;
295    return;
296  }
297
298  GetDisplayManager()->SetDisplayUIScale(display_id, ui_scale);
299}
300
301void DisplayOptionsHandler::HandleSetOrientation(const base::ListValue* args) {
302  DCHECK(!args->empty());
303
304  int64 display_id = GetDisplayId(args);
305  if (display_id == gfx::Display::kInvalidDisplayID)
306    return;
307
308  std::string rotation_value;
309  gfx::Display::Rotation new_rotation = gfx::Display::ROTATE_0;
310  if (!args->GetString(1, &rotation_value)) {
311    LOG(ERROR) << "Can't find new orientation";
312    return;
313  }
314  if (rotation_value == "90")
315    new_rotation = gfx::Display::ROTATE_90;
316  else if (rotation_value == "180")
317    new_rotation = gfx::Display::ROTATE_180;
318  else if (rotation_value == "270")
319    new_rotation = gfx::Display::ROTATE_270;
320  else if (rotation_value != "0")
321    LOG(ERROR) << "Invalid rotation: " << rotation_value << " Falls back to 0";
322
323  GetDisplayManager()->SetDisplayRotation(display_id, new_rotation);
324}
325
326}  // namespace options
327}  // namespace chromeos
328