Move HasInternalDisplay to gfx::Display
[chromium-blink-merge.git] / chrome / browser / ui / webui / options / chromeos / display_options_handler.cc
blobca4cc50c06a734f0552dd017ff069dd3543ca2df
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.
5 #include "chrome/browser/ui/webui/options/chromeos/display_options_handler.h"
7 #include <string>
9 #include "ash/display/display_configurator_animation.h"
10 #include "ash/display/display_controller.h"
11 #include "ash/display/display_manager.h"
12 #include "ash/display/resolution_notification_controller.h"
13 #include "ash/rotator/screen_rotation_animator.h"
14 #include "ash/shell.h"
15 #include "base/bind.h"
16 #include "base/logging.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/stringprintf.h"
19 #include "base/values.h"
20 #include "chrome/browser/chromeos/display/display_preferences.h"
21 #include "chrome/grit/generated_resources.h"
22 #include "content/public/browser/user_metrics.h"
23 #include "content/public/browser/web_ui.h"
24 #include "grit/ash_strings.h"
25 #include "ui/base/l10n/l10n_util.h"
26 #include "ui/gfx/display.h"
27 #include "ui/gfx/geometry/rect.h"
28 #include "ui/gfx/geometry/size_conversions.h"
29 #include "ui/gfx/screen.h"
31 using ash::DisplayManager;
33 namespace chromeos {
34 namespace options {
35 namespace {
37 DisplayManager* GetDisplayManager() {
38 return ash::Shell::GetInstance()->display_manager();
41 int64 GetDisplayId(const base::ListValue* args) {
42 // Assumes the display ID is specified as the first argument.
43 std::string id_value;
44 if (!args->GetString(0, &id_value)) {
45 LOG(ERROR) << "Can't find ID";
46 return gfx::Display::kInvalidDisplayID;
49 int64 display_id = gfx::Display::kInvalidDisplayID;
50 if (!base::StringToInt64(id_value, &display_id)) {
51 LOG(ERROR) << "Invalid display id: " << id_value;
52 return gfx::Display::kInvalidDisplayID;
55 return display_id;
58 base::string16 GetColorProfileName(ui::ColorCalibrationProfile profile) {
59 switch (profile) {
60 case ui::COLOR_PROFILE_STANDARD:
61 return l10n_util::GetStringUTF16(
62 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_COLOR_PROFILE_STANDARD);
63 case ui::COLOR_PROFILE_DYNAMIC:
64 return l10n_util::GetStringUTF16(
65 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_COLOR_PROFILE_DYNAMIC);
66 case ui::COLOR_PROFILE_MOVIE:
67 return l10n_util::GetStringUTF16(
68 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_COLOR_PROFILE_MOVIE);
69 case ui::COLOR_PROFILE_READING:
70 return l10n_util::GetStringUTF16(
71 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_COLOR_PROFILE_READING);
72 case ui::NUM_COLOR_PROFILES:
73 break;
76 NOTREACHED();
77 return base::string16();
80 int GetIntOrDouble(const base::DictionaryValue* dict,
81 const std::string& field) {
82 double double_result = 0;
83 if (dict->GetDouble(field, &double_result))
84 return static_cast<int>(double_result);
86 int result = 0;
87 dict->GetInteger(field, &result);
88 return result;
91 bool GetFloat(const base::DictionaryValue* dict,
92 const std::string& field,
93 float* result) {
94 double double_result = 0;
95 if (dict->GetDouble(field, &double_result)) {
96 *result = static_cast<float>(double_result);
97 return true;
99 return false;
102 bool ConvertValueToDisplayMode(const base::DictionaryValue* dict,
103 ash::DisplayMode* mode) {
104 mode->size.set_width(GetIntOrDouble(dict, "originalWidth"));
105 mode->size.set_height(GetIntOrDouble(dict, "originalHeight"));
106 if (mode->size.IsEmpty()) {
107 LOG(ERROR) << "missing width or height.";
108 return false;
110 if (!GetFloat(dict, "refreshRate", &mode->refresh_rate)) {
111 LOG(ERROR) << "missing refreshRate.";
112 return false;
114 if (!GetFloat(dict, "scale", &mode->ui_scale)) {
115 LOG(ERROR) << "missing ui-scale.";
116 return false;
118 if (!GetFloat(dict, "deviceScaleFactor", &mode->device_scale_factor)) {
119 LOG(ERROR) << "missing deviceScaleFactor.";
120 return false;
122 return true;
125 base::DictionaryValue* ConvertDisplayModeToValue(int64 display_id,
126 const ash::DisplayMode& mode) {
127 bool is_internal = gfx::Display::InternalDisplayId() == display_id;
128 base::DictionaryValue* result = new base::DictionaryValue();
129 gfx::Size size_dip = mode.GetSizeInDIP(is_internal);
130 result->SetInteger("width", size_dip.width());
131 result->SetInteger("height", size_dip.height());
132 result->SetInteger("originalWidth", mode.size.width());
133 result->SetInteger("originalHeight", mode.size.height());
134 result->SetDouble("deviceScaleFactor", mode.device_scale_factor);
135 result->SetDouble("scale", mode.ui_scale);
136 result->SetDouble("refreshRate", mode.refresh_rate);
137 result->SetBoolean(
138 "isBest", is_internal ? (mode.ui_scale == 1.0f) : mode.native);
139 result->SetBoolean("isNative", mode.native);
140 result->SetBoolean(
141 "selected", mode.IsEquivalent(
142 GetDisplayManager()->GetActiveModeForDisplayId(display_id)));
143 return result;
146 } // namespace
148 DisplayOptionsHandler::DisplayOptionsHandler() {
149 // ash::Shell doesn't exist in Athena.
150 // See: http://crbug.com/416961
151 ash::Shell::GetInstance()->display_controller()->AddObserver(this);
154 DisplayOptionsHandler::~DisplayOptionsHandler() {
155 // ash::Shell doesn't exist in Athena.
156 ash::Shell::GetInstance()->display_controller()->RemoveObserver(this);
159 void DisplayOptionsHandler::GetLocalizedValues(
160 base::DictionaryValue* localized_strings) {
161 DCHECK(localized_strings);
162 RegisterTitle(localized_strings, "displayOptionsPage",
163 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_TAB_TITLE);
165 localized_strings->SetString(
166 "selectedDisplayTitleOptions", l10n_util::GetStringUTF16(
167 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_OPTIONS));
168 localized_strings->SetString(
169 "selectedDisplayTitleResolution", l10n_util::GetStringUTF16(
170 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_RESOLUTION));
171 localized_strings->SetString(
172 "selectedDisplayTitleOrientation", l10n_util::GetStringUTF16(
173 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_ORIENTATION));
174 localized_strings->SetString(
175 "selectedDisplayTitleOverscan", l10n_util::GetStringUTF16(
176 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_OVERSCAN));
178 localized_strings->SetString("startMirroring", l10n_util::GetStringUTF16(
179 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_START_MIRRORING));
180 localized_strings->SetString("stopMirroring", l10n_util::GetStringUTF16(
181 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_STOP_MIRRORING));
182 localized_strings->SetString("mirroringDisplay", l10n_util::GetStringUTF16(
183 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_MIRRORING_DISPLAY_NAME));
184 localized_strings->SetString("setPrimary", l10n_util::GetStringUTF16(
185 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_SET_PRIMARY));
186 localized_strings->SetString("annotateBest", l10n_util::GetStringUTF16(
187 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_RESOLUTION_ANNOTATION_BEST));
188 localized_strings->SetString("annotateNative", l10n_util::GetStringUTF16(
189 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_RESOLUTION_ANNOTATION_NATIVE));
190 localized_strings->SetString("orientation0", l10n_util::GetStringUTF16(
191 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_STANDARD_ORIENTATION));
192 localized_strings->SetString("orientation90", l10n_util::GetStringUTF16(
193 IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90));
194 localized_strings->SetString("orientation180", l10n_util::GetStringUTF16(
195 IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_180));
196 localized_strings->SetString("orientation270", l10n_util::GetStringUTF16(
197 IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_270));
198 localized_strings->SetString(
199 "startCalibratingOverscan", l10n_util::GetStringUTF16(
200 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_START_CALIBRATING_OVERSCAN));
201 localized_strings->SetString(
202 "selectedDisplayColorProfile", l10n_util::GetStringUTF16(
203 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_COLOR_PROFILE));
206 void DisplayOptionsHandler::InitializePage() {
207 DCHECK(web_ui());
208 UpdateDisplaySettingsEnabled();
211 void DisplayOptionsHandler::RegisterMessages() {
212 web_ui()->RegisterMessageCallback(
213 "getDisplayInfo",
214 base::Bind(&DisplayOptionsHandler::HandleDisplayInfo,
215 base::Unretained(this)));
216 web_ui()->RegisterMessageCallback(
217 "setMirroring",
218 base::Bind(&DisplayOptionsHandler::HandleMirroring,
219 base::Unretained(this)));
220 web_ui()->RegisterMessageCallback(
221 "setPrimary",
222 base::Bind(&DisplayOptionsHandler::HandleSetPrimary,
223 base::Unretained(this)));
224 web_ui()->RegisterMessageCallback(
225 "setDisplayLayout",
226 base::Bind(&DisplayOptionsHandler::HandleDisplayLayout,
227 base::Unretained(this)));
228 web_ui()->RegisterMessageCallback(
229 "setDisplayMode",
230 base::Bind(&DisplayOptionsHandler::HandleSetDisplayMode,
231 base::Unretained(this)));
232 web_ui()->RegisterMessageCallback(
233 "setOrientation",
234 base::Bind(&DisplayOptionsHandler::HandleSetOrientation,
235 base::Unretained(this)));
236 web_ui()->RegisterMessageCallback(
237 "setColorProfile",
238 base::Bind(&DisplayOptionsHandler::HandleSetColorProfile,
239 base::Unretained(this)));
242 void DisplayOptionsHandler::OnDisplayConfigurationChanging() {
245 void DisplayOptionsHandler::OnDisplayConfigurationChanged() {
246 UpdateDisplaySettingsEnabled();
247 SendAllDisplayInfo();
250 void DisplayOptionsHandler::SendAllDisplayInfo() {
251 DisplayManager* display_manager = GetDisplayManager();
253 std::vector<gfx::Display> displays;
254 for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
255 displays.push_back(display_manager->GetDisplayAt(i));
257 SendDisplayInfo(displays);
260 void DisplayOptionsHandler::SendDisplayInfo(
261 const std::vector<gfx::Display>& displays) {
262 DisplayManager* display_manager = GetDisplayManager();
263 base::FundamentalValue mirroring(display_manager->IsInMirrorMode());
265 int64 primary_id = ash::Shell::GetScreen()->GetPrimaryDisplay().id();
266 base::ListValue js_displays;
267 for (const gfx::Display& display : displays) {
268 const ash::DisplayInfo& display_info =
269 display_manager->GetDisplayInfo(display.id());
270 const gfx::Rect& bounds = display.bounds();
271 base::DictionaryValue* js_display = new base::DictionaryValue();
272 js_display->SetString("id", base::Int64ToString(display.id()));
273 js_display->SetInteger("x", bounds.x());
274 js_display->SetInteger("y", bounds.y());
275 js_display->SetInteger("width", bounds.width());
276 js_display->SetInteger("height", bounds.height());
277 js_display->SetString("name",
278 display_manager->GetDisplayNameForId(display.id()));
279 js_display->SetBoolean("isPrimary", display.id() == primary_id);
280 js_display->SetBoolean("isInternal", display.IsInternal());
281 js_display->SetInteger("orientation",
282 static_cast<int>(display_info.rotation()));
284 base::ListValue* js_resolutions = new base::ListValue();
285 for (const ash::DisplayMode& display_mode : display_info.display_modes()) {
286 js_resolutions->Append(
287 ConvertDisplayModeToValue(display.id(), display_mode));
289 js_display->Set("resolutions", js_resolutions);
291 js_display->SetInteger("colorProfile", display_info.color_profile());
292 base::ListValue* available_color_profiles = new base::ListValue();
293 for (const auto& color_profile : display_info.available_color_profiles()) {
294 const base::string16 profile_name = GetColorProfileName(color_profile);
295 if (profile_name.empty())
296 continue;
297 base::DictionaryValue* color_profile_dict = new base::DictionaryValue();
298 color_profile_dict->SetInteger("profileId", color_profile);
299 color_profile_dict->SetString("name", profile_name);
300 available_color_profiles->Append(color_profile_dict);
302 js_display->Set("availableColorProfiles", available_color_profiles);
303 js_displays.Append(js_display);
306 scoped_ptr<base::Value> layout_value(base::Value::CreateNullValue());
307 scoped_ptr<base::Value> offset_value(base::Value::CreateNullValue());
308 if (display_manager->GetNumDisplays() > 1) {
309 const ash::DisplayLayout layout =
310 display_manager->GetCurrentDisplayLayout();
311 layout_value.reset(new base::FundamentalValue(layout.position));
312 offset_value.reset(new base::FundamentalValue(layout.offset));
315 web_ui()->CallJavascriptFunction(
316 "options.DisplayOptions.setDisplayInfo",
317 mirroring, js_displays, *layout_value.get(), *offset_value.get());
320 void DisplayOptionsHandler::UpdateDisplaySettingsEnabled() {
321 bool enabled = GetDisplayManager()->num_connected_displays() <= 2;
322 web_ui()->CallJavascriptFunction(
323 "options.BrowserOptions.enableDisplaySettings",
324 base::FundamentalValue(enabled));
327 void DisplayOptionsHandler::OnFadeOutForMirroringFinished(bool is_mirroring) {
328 ash::Shell::GetInstance()->display_manager()->SetMirrorMode(is_mirroring);
329 // Not necessary to start fade-in animation. DisplayConfigurator will do that.
332 void DisplayOptionsHandler::OnFadeOutForDisplayLayoutFinished(
333 int position, int offset) {
334 SetCurrentDisplayLayout(
335 ash::DisplayLayout::FromInts(position, offset));
336 ash::Shell::GetInstance()->display_configurator_animation()->
337 StartFadeInAnimation();
340 void DisplayOptionsHandler::HandleDisplayInfo(
341 const base::ListValue* unused_args) {
342 SendAllDisplayInfo();
345 void DisplayOptionsHandler::HandleMirroring(const base::ListValue* args) {
346 DCHECK(!args->empty());
347 content::RecordAction(
348 base::UserMetricsAction("Options_DisplayToggleMirroring"));
349 bool is_mirroring = false;
350 args->GetBoolean(0, &is_mirroring);
351 ash::Shell::GetInstance()->display_configurator_animation()->
352 StartFadeOutAnimation(base::Bind(
353 &DisplayOptionsHandler::OnFadeOutForMirroringFinished,
354 base::Unretained(this),
355 is_mirroring));
358 void DisplayOptionsHandler::HandleSetPrimary(const base::ListValue* args) {
359 DCHECK(!args->empty());
360 int64 display_id = GetDisplayId(args);
361 if (display_id == gfx::Display::kInvalidDisplayID)
362 return;
364 content::RecordAction(base::UserMetricsAction("Options_DisplaySetPrimary"));
365 ash::Shell::GetInstance()->display_controller()->
366 SetPrimaryDisplayId(display_id);
369 void DisplayOptionsHandler::HandleDisplayLayout(const base::ListValue* args) {
370 double layout = -1;
371 double offset = -1;
372 if (!args->GetDouble(0, &layout) || !args->GetDouble(1, &offset)) {
373 LOG(ERROR) << "Invalid parameter";
374 SendAllDisplayInfo();
375 return;
377 DCHECK_LE(ash::DisplayLayout::TOP, layout);
378 DCHECK_GE(ash::DisplayLayout::LEFT, layout);
379 content::RecordAction(base::UserMetricsAction("Options_DisplayRearrange"));
380 ash::Shell::GetInstance()->display_configurator_animation()->
381 StartFadeOutAnimation(base::Bind(
382 &DisplayOptionsHandler::OnFadeOutForDisplayLayoutFinished,
383 base::Unretained(this),
384 static_cast<int>(layout),
385 static_cast<int>(offset)));
388 void DisplayOptionsHandler::HandleSetDisplayMode(const base::ListValue* args) {
389 DCHECK(!args->empty());
391 int64 display_id = GetDisplayId(args);
392 if (display_id == gfx::Display::kInvalidDisplayID)
393 return;
395 const base::DictionaryValue* mode_data = nullptr;
396 if (!args->GetDictionary(1, &mode_data)) {
397 LOG(ERROR) << "Failed to get mode data";
398 return;
401 ash::DisplayMode mode;
402 if (!ConvertValueToDisplayMode(mode_data, &mode))
403 return;
405 content::RecordAction(
406 base::UserMetricsAction("Options_DisplaySetResolution"));
407 ash::DisplayManager* display_manager = GetDisplayManager();
408 ash::DisplayMode current_mode =
409 display_manager->GetActiveModeForDisplayId(display_id);
410 if (display_manager->SetDisplayMode(display_id, mode)) {
411 ash::Shell::GetInstance()->resolution_notification_controller()->
412 PrepareNotification(
413 display_id, current_mode, mode, base::Bind(&StoreDisplayPrefs));
417 void DisplayOptionsHandler::HandleSetOrientation(const base::ListValue* args) {
418 DCHECK(!args->empty());
420 int64 display_id = GetDisplayId(args);
421 if (display_id == gfx::Display::kInvalidDisplayID)
422 return;
424 std::string rotation_value;
425 gfx::Display::Rotation new_rotation = gfx::Display::ROTATE_0;
426 if (!args->GetString(1, &rotation_value)) {
427 LOG(ERROR) << "Can't find new orientation";
428 return;
430 if (rotation_value == "90")
431 new_rotation = gfx::Display::ROTATE_90;
432 else if (rotation_value == "180")
433 new_rotation = gfx::Display::ROTATE_180;
434 else if (rotation_value == "270")
435 new_rotation = gfx::Display::ROTATE_270;
436 else if (rotation_value != "0")
437 LOG(ERROR) << "Invalid rotation: " << rotation_value << " Falls back to 0";
439 content::RecordAction(
440 base::UserMetricsAction("Options_DisplaySetOrientation"));
441 ash::ScreenRotationAnimator(display_id).Rotate(new_rotation);
444 void DisplayOptionsHandler::HandleSetColorProfile(const base::ListValue* args) {
445 DCHECK(!args->empty());
446 int64 display_id = GetDisplayId(args);
447 if (display_id == gfx::Display::kInvalidDisplayID)
448 return;
450 std::string profile_value;
451 if (!args->GetString(1, &profile_value)) {
452 LOG(ERROR) << "Invalid profile_value";
453 return;
456 int profile_id;
457 if (!base::StringToInt(profile_value, &profile_id)) {
458 LOG(ERROR) << "Invalid profile: " << profile_value;
459 return;
462 if (profile_id < ui::COLOR_PROFILE_STANDARD ||
463 profile_id > ui::COLOR_PROFILE_READING) {
464 LOG(ERROR) << "Invalid profile_id: " << profile_id;
465 return;
468 GetDisplayManager()->SetColorCalibrationProfile(
469 display_id, static_cast<ui::ColorCalibrationProfile>(profile_id));
470 SendAllDisplayInfo();
473 } // namespace options
474 } // namespace chromeos