blob: d02c3b3b31032cdb174297b7aa27f98d68620f25 [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/webui/options/chromeos/display_options_handler.h"
#include <string>
#include "ash/display/display_controller.h"
#include "ash/display/display_manager.h"
#include "ash/display/output_configurator_animation.h"
#include "ash/display/resolution_notification_controller.h"
#include "ash/screen_ash.h"
#include "ash/shell.h"
#include "base/bind.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "chrome/browser/chromeos/display/display_preferences.h"
#include "chromeos/display/output_configurator.h"
#include "content/public/browser/web_ui.h"
#include "grit/ash_strings.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/display.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/size_conversions.h"
using ash::internal::DisplayManager;
namespace chromeos {
namespace options {
namespace {
DisplayManager* GetDisplayManager() {
return ash::Shell::GetInstance()->display_manager();
}
int64 GetDisplayId(const base::ListValue* args) {
// Assumes the display ID is specified as the first argument.
std::string id_value;
if (!args->GetString(0, &id_value)) {
LOG(ERROR) << "Can't find ID";
return gfx::Display::kInvalidDisplayID;
}
int64 display_id = gfx::Display::kInvalidDisplayID;
if (!base::StringToInt64(id_value, &display_id)) {
LOG(ERROR) << "Invalid display id: " << id_value;
return gfx::Display::kInvalidDisplayID;
}
return display_id;
}
bool CompareResolution(ash::internal::Resolution r1,
ash::internal::Resolution r2) {
return r1.size.GetArea() < r2.size.GetArea();
}
} // namespace
DisplayOptionsHandler::DisplayOptionsHandler() {
ash::Shell::GetInstance()->display_controller()->AddObserver(this);
}
DisplayOptionsHandler::~DisplayOptionsHandler() {
ash::Shell::GetInstance()->display_controller()->RemoveObserver(this);
}
void DisplayOptionsHandler::GetLocalizedValues(
DictionaryValue* localized_strings) {
DCHECK(localized_strings);
RegisterTitle(localized_strings, "displayOptionsPage",
IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_TAB_TITLE);
localized_strings->SetString(
"selectedDisplayTitleOptions", l10n_util::GetStringUTF16(
IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_OPTIONS));
localized_strings->SetString(
"selectedDisplayTitleResolution", l10n_util::GetStringUTF16(
IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_RESOLUTION));
localized_strings->SetString(
"selectedDisplayTitleOrientation", l10n_util::GetStringUTF16(
IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_ORIENTATION));
localized_strings->SetString(
"selectedDisplayTitleOverscan", l10n_util::GetStringUTF16(
IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_OVERSCAN));
localized_strings->SetString("startMirroring", l10n_util::GetStringUTF16(
IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_START_MIRRORING));
localized_strings->SetString("stopMirroring", l10n_util::GetStringUTF16(
IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_STOP_MIRRORING));
localized_strings->SetString("mirroringDisplay", l10n_util::GetStringUTF16(
IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_MIRRORING_DISPLAY_NAME));
localized_strings->SetString("setPrimary", l10n_util::GetStringUTF16(
IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_SET_PRIMARY));
localized_strings->SetString("annotateBest", l10n_util::GetStringUTF16(
IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_RESOLUTION_ANNOTATION_BEST));
localized_strings->SetString("orientation0", l10n_util::GetStringUTF16(
IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_STANDARD_ORIENTATION));
localized_strings->SetString("orientation90", l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90));
localized_strings->SetString("orientation180", l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_180));
localized_strings->SetString("orientation270", l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_270));
localized_strings->SetString(
"startCalibratingOverscan", l10n_util::GetStringUTF16(
IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_START_CALIBRATING_OVERSCAN));
}
void DisplayOptionsHandler::InitializePage() {
DCHECK(web_ui());
}
void DisplayOptionsHandler::RegisterMessages() {
web_ui()->RegisterMessageCallback(
"getDisplayInfo",
base::Bind(&DisplayOptionsHandler::HandleDisplayInfo,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"setMirroring",
base::Bind(&DisplayOptionsHandler::HandleMirroring,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"setPrimary",
base::Bind(&DisplayOptionsHandler::HandleSetPrimary,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"setDisplayLayout",
base::Bind(&DisplayOptionsHandler::HandleDisplayLayout,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"setUIScale",
base::Bind(&DisplayOptionsHandler::HandleSetUIScale,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"setResolution",
base::Bind(&DisplayOptionsHandler::HandleSetResolution,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"setOrientation",
base::Bind(&DisplayOptionsHandler::HandleSetOrientation,
base::Unretained(this)));
}
void DisplayOptionsHandler::OnDisplayConfigurationChanging() {
}
void DisplayOptionsHandler::OnDisplayConfigurationChanged() {
SendAllDisplayInfo();
}
void DisplayOptionsHandler::SendAllDisplayInfo() {
DisplayManager* display_manager = GetDisplayManager();
std::vector<gfx::Display> displays;
for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
displays.push_back(display_manager->GetDisplayAt(i));
}
SendDisplayInfo(displays);
}
void DisplayOptionsHandler::SendDisplayInfo(
const std::vector<gfx::Display>& displays) {
DisplayManager* display_manager = GetDisplayManager();
ash::DisplayController* display_controller =
ash::Shell::GetInstance()->display_controller();
base::FundamentalValue mirroring(display_manager->IsMirrored());
int64 primary_id = ash::Shell::GetScreen()->GetPrimaryDisplay().id();
base::ListValue js_displays;
for (size_t i = 0; i < displays.size(); ++i) {
const gfx::Display& display = displays[i];
const ash::internal::DisplayInfo& display_info =
display_manager->GetDisplayInfo(display.id());
const gfx::Rect& bounds = display.bounds();
base::DictionaryValue* js_display = new base::DictionaryValue();
js_display->SetString("id", base::Int64ToString(display.id()));
js_display->SetInteger("x", bounds.x());
js_display->SetInteger("y", bounds.y());
js_display->SetInteger("width", bounds.width());
js_display->SetInteger("height", bounds.height());
js_display->SetString("name",
display_manager->GetDisplayNameForId(display.id()));
js_display->SetBoolean("isPrimary", display.id() == primary_id);
js_display->SetBoolean("isInternal", display.IsInternal());
js_display->SetInteger("orientation",
static_cast<int>(display_info.rotation()));
std::vector<ash::internal::Resolution> resolutions;
std::vector<float> ui_scales;
if (display.IsInternal()) {
ui_scales = DisplayManager::GetScalesForDisplay(display_info);
gfx::SizeF base_size = display_info.bounds_in_pixel().size();
base_size.Scale(1.0f / display.device_scale_factor());
if (display_info.rotation() == gfx::Display::ROTATE_90 ||
display_info.rotation() == gfx::Display::ROTATE_270) {
float tmp = base_size.width();
base_size.set_width(base_size.height());
base_size.set_height(tmp);
}
for (size_t i = 0; i < ui_scales.size(); ++i) {
gfx::SizeF new_size = base_size;
new_size.Scale(ui_scales[i]);
resolutions.push_back(ash::internal::Resolution(
gfx::ToFlooredSize(new_size), false /* interlaced */));
}
} else {
for (size_t i = 0; i < display_info.resolutions().size(); ++i)
resolutions.push_back(display_info.resolutions()[i]);
}
std::sort(resolutions.begin(), resolutions.end(), CompareResolution);
base::ListValue* js_resolutions = new base::ListValue();
gfx::Size current_size(bounds.width() * display.device_scale_factor(),
bounds.height() * display.device_scale_factor());
for (size_t i = 0; i < resolutions.size(); ++i) {
base::DictionaryValue* resolution_info = new base::DictionaryValue();
if (!ui_scales.empty()) {
resolution_info->SetDouble("scale", ui_scales[i]);
if (ui_scales[i] == 1.0f)
resolution_info->SetBoolean("isBest", true);
resolution_info->SetBoolean(
"selected", display_info.ui_scale() == ui_scales[i]);
} else {
// Picks the largest one as the "best", which is the last element
// because |resolutions| is sorted by its area.
if (i == resolutions.size() - 1)
resolution_info->SetBoolean("isBest", true);
resolution_info->SetBoolean(
"selected", (resolutions[i].size == current_size));
}
resolution_info->SetInteger("width", resolutions[i].size.width());
resolution_info->SetInteger("height",resolutions[i].size.height());
js_resolutions->Append(resolution_info);
}
js_display->Set("resolutions", js_resolutions);
js_displays.Append(js_display);
}
scoped_ptr<base::Value> layout_value(base::Value::CreateNullValue());
scoped_ptr<base::Value> offset_value(base::Value::CreateNullValue());
if (display_manager->GetNumDisplays() > 1) {
const ash::DisplayLayout layout =
display_controller->GetCurrentDisplayLayout();
layout_value.reset(new base::FundamentalValue(layout.position));
offset_value.reset(new base::FundamentalValue(layout.offset));
}
web_ui()->CallJavascriptFunction(
"options.DisplayOptions.setDisplayInfo",
mirroring, js_displays, *layout_value.get(), *offset_value.get());
}
void DisplayOptionsHandler::OnFadeOutForMirroringFinished(bool is_mirroring) {
ash::Shell::GetInstance()->display_manager()->SetMirrorMode(is_mirroring);
// Not necessary to start fade-in animation. OutputConfigurator will do that.
}
void DisplayOptionsHandler::OnFadeOutForDisplayLayoutFinished(
int position, int offset) {
SetCurrentDisplayLayout(
ash::DisplayLayout::FromInts(position, offset));
ash::Shell::GetInstance()->output_configurator_animation()->
StartFadeInAnimation();
}
void DisplayOptionsHandler::HandleDisplayInfo(
const base::ListValue* unused_args) {
SendAllDisplayInfo();
}
void DisplayOptionsHandler::HandleMirroring(const base::ListValue* args) {
DCHECK(!args->empty());
bool is_mirroring = false;
args->GetBoolean(0, &is_mirroring);
ash::Shell::GetInstance()->output_configurator_animation()->
StartFadeOutAnimation(base::Bind(
&DisplayOptionsHandler::OnFadeOutForMirroringFinished,
base::Unretained(this),
is_mirroring));
}
void DisplayOptionsHandler::HandleSetPrimary(const base::ListValue* args) {
DCHECK(!args->empty());
int64 display_id = GetDisplayId(args);
if (display_id == gfx::Display::kInvalidDisplayID)
return;
ash::Shell::GetInstance()->display_controller()->
SetPrimaryDisplayId(display_id);
}
void DisplayOptionsHandler::HandleDisplayLayout(const base::ListValue* args) {
double layout = -1;
double offset = -1;
if (!args->GetDouble(0, &layout) || !args->GetDouble(1, &offset)) {
LOG(ERROR) << "Invalid parameter";
SendAllDisplayInfo();
return;
}
DCHECK_LE(ash::DisplayLayout::TOP, layout);
DCHECK_GE(ash::DisplayLayout::LEFT, layout);
ash::Shell::GetInstance()->output_configurator_animation()->
StartFadeOutAnimation(base::Bind(
&DisplayOptionsHandler::OnFadeOutForDisplayLayoutFinished,
base::Unretained(this),
static_cast<int>(layout),
static_cast<int>(offset)));
}
void DisplayOptionsHandler::HandleSetUIScale(const base::ListValue* args) {
DCHECK(!args->empty());
int64 display_id = GetDisplayId(args);
if (display_id == gfx::Display::kInvalidDisplayID)
return;
double ui_scale = 0.0f;
if (!args->GetDouble(1, &ui_scale) || ui_scale == 0.0f) {
LOG(ERROR) << "Can't find new ui_scale";
return;
}
GetDisplayManager()->SetDisplayUIScale(display_id, ui_scale);
}
void DisplayOptionsHandler::HandleSetResolution(const base::ListValue* args) {
DCHECK(!args->empty());
int64 display_id = GetDisplayId(args);
if (display_id == gfx::Display::kInvalidDisplayID)
return;
double width = 0.0f;
double height = 0.0f;
if (!args->GetDouble(1, &width) || width == 0.0f) {
LOG(ERROR) << "Can't find new width";
return;
}
if (!args->GetDouble(2, &height) || height == 0.0f) {
LOG(ERROR) << "Can't find new height";
return;
}
const ash::internal::DisplayInfo& display_info =
GetDisplayManager()->GetDisplayInfo(display_id);
gfx::Size new_resolution = gfx::ToFlooredSize(gfx::SizeF(width, height));
gfx::Size old_resolution = display_info.size_in_pixel();
bool has_new_resolution = false;
bool has_old_resolution = false;
for (size_t i = 0; i < display_info.resolutions().size(); ++i) {
ash::internal::Resolution resolution = display_info.resolutions()[i];
if (resolution.size == new_resolution)
has_new_resolution = true;
if (resolution.size == old_resolution)
has_old_resolution = true;
}
if (!has_new_resolution) {
LOG(ERROR) << "No new resolution " << new_resolution.ToString()
<< " is found in the display info " << display_info.ToString();
return;
}
if (!has_old_resolution) {
LOG(ERROR) << "No old resolution " << old_resolution.ToString()
<< " is found in the display info " << display_info.ToString();
return;
}
ash::Shell::GetInstance()->resolution_notification_controller()->
SetDisplayResolutionAndNotify(
display_id, old_resolution, new_resolution,
base::Bind(&StoreDisplayPrefs));
}
void DisplayOptionsHandler::HandleSetOrientation(const base::ListValue* args) {
DCHECK(!args->empty());
int64 display_id = GetDisplayId(args);
if (display_id == gfx::Display::kInvalidDisplayID)
return;
std::string rotation_value;
gfx::Display::Rotation new_rotation = gfx::Display::ROTATE_0;
if (!args->GetString(1, &rotation_value)) {
LOG(ERROR) << "Can't find new orientation";
return;
}
if (rotation_value == "90")
new_rotation = gfx::Display::ROTATE_90;
else if (rotation_value == "180")
new_rotation = gfx::Display::ROTATE_180;
else if (rotation_value == "270")
new_rotation = gfx::Display::ROTATE_270;
else if (rotation_value != "0")
LOG(ERROR) << "Invalid rotation: " << rotation_value << " Falls back to 0";
GetDisplayManager()->SetDisplayRotation(display_id, new_rotation);
}
} // namespace options
} // namespace chromeos