• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/display/resolution_notification_controller.h"
13 #include "ash/screen_ash.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 "chromeos/display/output_configurator.h"
22 #include "content/public/browser/web_ui.h"
23 #include "grit/ash_strings.h"
24 #include "grit/generated_resources.h"
25 #include "ui/base/l10n/l10n_util.h"
26 #include "ui/gfx/display.h"
27 #include "ui/gfx/rect.h"
28 #include "ui/gfx/screen.h"
29 #include "ui/gfx/size_conversions.h"
30 
31 using ash::internal::DisplayManager;
32 
33 namespace chromeos {
34 namespace options {
35 namespace {
36 
GetDisplayManager()37 DisplayManager* GetDisplayManager() {
38   return ash::Shell::GetInstance()->display_manager();
39 }
40 
GetDisplayId(const base::ListValue * args)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;
47   }
48 
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;
53   }
54 
55   return display_id;
56 }
57 
CompareResolution(ash::internal::Resolution r1,ash::internal::Resolution r2)58 bool CompareResolution(ash::internal::Resolution r1,
59                        ash::internal::Resolution r2) {
60   return r1.size.GetArea() < r2.size.GetArea();
61 }
62 
63 }  // namespace
64 
DisplayOptionsHandler()65 DisplayOptionsHandler::DisplayOptionsHandler() {
66   ash::Shell::GetInstance()->display_controller()->AddObserver(this);
67 }
68 
~DisplayOptionsHandler()69 DisplayOptionsHandler::~DisplayOptionsHandler() {
70   ash::Shell::GetInstance()->display_controller()->RemoveObserver(this);
71 }
72 
GetLocalizedValues(DictionaryValue * localized_strings)73 void DisplayOptionsHandler::GetLocalizedValues(
74     DictionaryValue* localized_strings) {
75   DCHECK(localized_strings);
76   RegisterTitle(localized_strings, "displayOptionsPage",
77                 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_TAB_TITLE);
78 
79   localized_strings->SetString(
80       "selectedDisplayTitleOptions", l10n_util::GetStringUTF16(
81           IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_OPTIONS));
82   localized_strings->SetString(
83       "selectedDisplayTitleResolution", l10n_util::GetStringUTF16(
84           IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_RESOLUTION));
85   localized_strings->SetString(
86       "selectedDisplayTitleOrientation", l10n_util::GetStringUTF16(
87           IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_ORIENTATION));
88   localized_strings->SetString(
89       "selectedDisplayTitleOverscan", l10n_util::GetStringUTF16(
90           IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_OVERSCAN));
91 
92   localized_strings->SetString("startMirroring", l10n_util::GetStringUTF16(
93       IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_START_MIRRORING));
94   localized_strings->SetString("stopMirroring", l10n_util::GetStringUTF16(
95       IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_STOP_MIRRORING));
96   localized_strings->SetString("mirroringDisplay", l10n_util::GetStringUTF16(
97       IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_MIRRORING_DISPLAY_NAME));
98   localized_strings->SetString("setPrimary", l10n_util::GetStringUTF16(
99       IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_SET_PRIMARY));
100   localized_strings->SetString("annotateBest", l10n_util::GetStringUTF16(
101       IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_RESOLUTION_ANNOTATION_BEST));
102   localized_strings->SetString("orientation0", l10n_util::GetStringUTF16(
103       IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_STANDARD_ORIENTATION));
104   localized_strings->SetString("orientation90", l10n_util::GetStringUTF16(
105       IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90));
106   localized_strings->SetString("orientation180", l10n_util::GetStringUTF16(
107       IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_180));
108   localized_strings->SetString("orientation270", l10n_util::GetStringUTF16(
109       IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_270));
110   localized_strings->SetString(
111       "startCalibratingOverscan", l10n_util::GetStringUTF16(
112           IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_START_CALIBRATING_OVERSCAN));
113 }
114 
InitializePage()115 void DisplayOptionsHandler::InitializePage() {
116   DCHECK(web_ui());
117 }
118 
RegisterMessages()119 void DisplayOptionsHandler::RegisterMessages() {
120   web_ui()->RegisterMessageCallback(
121       "getDisplayInfo",
122       base::Bind(&DisplayOptionsHandler::HandleDisplayInfo,
123                  base::Unretained(this)));
124   web_ui()->RegisterMessageCallback(
125       "setMirroring",
126       base::Bind(&DisplayOptionsHandler::HandleMirroring,
127                  base::Unretained(this)));
128   web_ui()->RegisterMessageCallback(
129       "setPrimary",
130       base::Bind(&DisplayOptionsHandler::HandleSetPrimary,
131                  base::Unretained(this)));
132   web_ui()->RegisterMessageCallback(
133       "setDisplayLayout",
134       base::Bind(&DisplayOptionsHandler::HandleDisplayLayout,
135                  base::Unretained(this)));
136   web_ui()->RegisterMessageCallback(
137       "setUIScale",
138       base::Bind(&DisplayOptionsHandler::HandleSetUIScale,
139                  base::Unretained(this)));
140   web_ui()->RegisterMessageCallback(
141       "setResolution",
142       base::Bind(&DisplayOptionsHandler::HandleSetResolution,
143                  base::Unretained(this)));
144   web_ui()->RegisterMessageCallback(
145       "setOrientation",
146       base::Bind(&DisplayOptionsHandler::HandleSetOrientation,
147                  base::Unretained(this)));
148 }
149 
OnDisplayConfigurationChanging()150 void DisplayOptionsHandler::OnDisplayConfigurationChanging() {
151 }
152 
OnDisplayConfigurationChanged()153 void DisplayOptionsHandler::OnDisplayConfigurationChanged() {
154   SendAllDisplayInfo();
155 }
156 
SendAllDisplayInfo()157 void DisplayOptionsHandler::SendAllDisplayInfo() {
158   DisplayManager* display_manager = GetDisplayManager();
159 
160   std::vector<gfx::Display> displays;
161   for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
162     displays.push_back(display_manager->GetDisplayAt(i));
163   }
164   SendDisplayInfo(displays);
165 }
166 
SendDisplayInfo(const std::vector<gfx::Display> & displays)167 void DisplayOptionsHandler::SendDisplayInfo(
168     const std::vector<gfx::Display>& displays) {
169   DisplayManager* display_manager = GetDisplayManager();
170   base::FundamentalValue mirroring(display_manager->IsMirrored());
171 
172   int64 primary_id = ash::Shell::GetScreen()->GetPrimaryDisplay().id();
173   base::ListValue js_displays;
174   for (size_t i = 0; i < displays.size(); ++i) {
175     const gfx::Display& display = displays[i];
176     const ash::internal::DisplayInfo& display_info =
177         display_manager->GetDisplayInfo(display.id());
178     const gfx::Rect& bounds = display.bounds();
179     base::DictionaryValue* js_display = new base::DictionaryValue();
180     js_display->SetString("id", base::Int64ToString(display.id()));
181     js_display->SetInteger("x", bounds.x());
182     js_display->SetInteger("y", bounds.y());
183     js_display->SetInteger("width", bounds.width());
184     js_display->SetInteger("height", bounds.height());
185     js_display->SetString("name",
186                           display_manager->GetDisplayNameForId(display.id()));
187     js_display->SetBoolean("isPrimary", display.id() == primary_id);
188     js_display->SetBoolean("isInternal", display.IsInternal());
189     js_display->SetInteger("orientation",
190                            static_cast<int>(display_info.rotation()));
191     std::vector<ash::internal::Resolution> resolutions;
192     std::vector<float> ui_scales;
193     if (display.IsInternal()) {
194       ui_scales = DisplayManager::GetScalesForDisplay(display_info);
195       gfx::SizeF base_size = display_info.bounds_in_native().size();
196       base_size.Scale(1.0f / display.device_scale_factor());
197       if (display_info.rotation() == gfx::Display::ROTATE_90 ||
198           display_info.rotation() == gfx::Display::ROTATE_270) {
199         float tmp = base_size.width();
200         base_size.set_width(base_size.height());
201         base_size.set_height(tmp);
202       }
203       for (size_t i = 0; i < ui_scales.size(); ++i) {
204         gfx::SizeF new_size = base_size;
205         new_size.Scale(ui_scales[i]);
206         resolutions.push_back(ash::internal::Resolution(
207             gfx::ToFlooredSize(new_size), false /* interlaced */));
208       }
209     } else {
210       for (size_t i = 0; i < display_info.resolutions().size(); ++i)
211         resolutions.push_back(display_info.resolutions()[i]);
212     }
213     std::sort(resolutions.begin(), resolutions.end(), CompareResolution);
214 
215     base::ListValue* js_resolutions = new base::ListValue();
216     gfx::Size current_size = display_info.bounds_in_native().size();
217     gfx::Insets current_overscan = display_info.GetOverscanInsetsInPixel();
218     for (size_t i = 0; i < resolutions.size(); ++i) {
219       base::DictionaryValue* resolution_info = new base::DictionaryValue();
220       gfx::Size resolution = resolutions[i].size;
221       if (!ui_scales.empty()) {
222         resolution_info->SetDouble("scale", ui_scales[i]);
223         if (ui_scales[i] == 1.0f)
224           resolution_info->SetBoolean("isBest", true);
225         resolution_info->SetBoolean(
226             "selected", display_info.configured_ui_scale() == ui_scales[i]);
227       } else {
228         // Picks the largest one as the "best", which is the last element
229         // because |resolutions| is sorted by its area.
230         if (i == resolutions.size() - 1)
231           resolution_info->SetBoolean("isBest", true);
232         resolution_info->SetBoolean("selected", (resolution == current_size));
233         resolution.Enlarge(
234             -current_overscan.width(), -current_overscan.height());
235       }
236       resolution_info->SetInteger("width", resolution.width());
237       resolution_info->SetInteger("height", resolution.height());
238       js_resolutions->Append(resolution_info);
239     }
240     js_display->Set("resolutions", js_resolutions);
241     js_displays.Append(js_display);
242   }
243 
244   scoped_ptr<base::Value> layout_value(base::Value::CreateNullValue());
245   scoped_ptr<base::Value> offset_value(base::Value::CreateNullValue());
246   if (display_manager->GetNumDisplays() > 1) {
247     const ash::DisplayLayout layout =
248         display_manager->GetCurrentDisplayLayout();
249     layout_value.reset(new base::FundamentalValue(layout.position));
250     offset_value.reset(new base::FundamentalValue(layout.offset));
251   }
252 
253   web_ui()->CallJavascriptFunction(
254       "options.DisplayOptions.setDisplayInfo",
255       mirroring, js_displays, *layout_value.get(), *offset_value.get());
256 }
257 
OnFadeOutForMirroringFinished(bool is_mirroring)258 void DisplayOptionsHandler::OnFadeOutForMirroringFinished(bool is_mirroring) {
259   ash::Shell::GetInstance()->display_manager()->SetMirrorMode(is_mirroring);
260   // Not necessary to start fade-in animation.  OutputConfigurator will do that.
261 }
262 
OnFadeOutForDisplayLayoutFinished(int position,int offset)263 void DisplayOptionsHandler::OnFadeOutForDisplayLayoutFinished(
264     int position, int offset) {
265   SetCurrentDisplayLayout(
266       ash::DisplayLayout::FromInts(position, offset));
267   ash::Shell::GetInstance()->output_configurator_animation()->
268       StartFadeInAnimation();
269 }
270 
HandleDisplayInfo(const base::ListValue * unused_args)271 void DisplayOptionsHandler::HandleDisplayInfo(
272     const base::ListValue* unused_args) {
273   SendAllDisplayInfo();
274 }
275 
HandleMirroring(const base::ListValue * args)276 void DisplayOptionsHandler::HandleMirroring(const base::ListValue* args) {
277   DCHECK(!args->empty());
278   bool is_mirroring = false;
279   args->GetBoolean(0, &is_mirroring);
280   ash::Shell::GetInstance()->output_configurator_animation()->
281       StartFadeOutAnimation(base::Bind(
282           &DisplayOptionsHandler::OnFadeOutForMirroringFinished,
283           base::Unretained(this),
284           is_mirroring));
285 }
286 
HandleSetPrimary(const base::ListValue * args)287 void DisplayOptionsHandler::HandleSetPrimary(const base::ListValue* args) {
288   DCHECK(!args->empty());
289   int64 display_id = GetDisplayId(args);
290   if (display_id == gfx::Display::kInvalidDisplayID)
291     return;
292 
293   ash::Shell::GetInstance()->display_controller()->
294       SetPrimaryDisplayId(display_id);
295 }
296 
HandleDisplayLayout(const base::ListValue * args)297 void DisplayOptionsHandler::HandleDisplayLayout(const base::ListValue* args) {
298   double layout = -1;
299   double offset = -1;
300   if (!args->GetDouble(0, &layout) || !args->GetDouble(1, &offset)) {
301     LOG(ERROR) << "Invalid parameter";
302     SendAllDisplayInfo();
303     return;
304   }
305   DCHECK_LE(ash::DisplayLayout::TOP, layout);
306   DCHECK_GE(ash::DisplayLayout::LEFT, layout);
307   ash::Shell::GetInstance()->output_configurator_animation()->
308       StartFadeOutAnimation(base::Bind(
309           &DisplayOptionsHandler::OnFadeOutForDisplayLayoutFinished,
310           base::Unretained(this),
311           static_cast<int>(layout),
312           static_cast<int>(offset)));
313 }
314 
HandleSetUIScale(const base::ListValue * args)315 void DisplayOptionsHandler::HandleSetUIScale(const base::ListValue* args) {
316   DCHECK(!args->empty());
317 
318   int64 display_id = GetDisplayId(args);
319   if (display_id == gfx::Display::kInvalidDisplayID)
320     return;
321 
322   double ui_scale = 0.0f;
323   if (!args->GetDouble(1, &ui_scale) || ui_scale == 0.0f) {
324     LOG(ERROR) << "Can't find new ui_scale";
325     return;
326   }
327 
328   GetDisplayManager()->SetDisplayUIScale(display_id, ui_scale);
329 }
330 
HandleSetResolution(const base::ListValue * args)331 void DisplayOptionsHandler::HandleSetResolution(const base::ListValue* args) {
332   DCHECK(!args->empty());
333   int64 display_id = GetDisplayId(args);
334   if (display_id == gfx::Display::kInvalidDisplayID)
335     return;
336 
337   double width = 0.0f;
338   double height = 0.0f;
339   if (!args->GetDouble(1, &width) || width == 0.0f) {
340     LOG(ERROR) << "Can't find new width";
341     return;
342   }
343   if (!args->GetDouble(2, &height) || height == 0.0f) {
344     LOG(ERROR) << "Can't find new height";
345     return;
346   }
347 
348   const ash::internal::DisplayInfo& display_info =
349       GetDisplayManager()->GetDisplayInfo(display_id);
350   gfx::Insets current_overscan = display_info.GetOverscanInsetsInPixel();
351   gfx::Size new_resolution = gfx::ToFlooredSize(gfx::SizeF(width, height));
352   new_resolution.Enlarge(current_overscan.width(), current_overscan.height());
353   gfx::Size old_resolution = display_info.bounds_in_native().size();
354   bool has_new_resolution = false;
355   bool has_old_resolution = false;
356   for (size_t i = 0; i < display_info.resolutions().size(); ++i) {
357     ash::internal::Resolution resolution = display_info.resolutions()[i];
358     if (resolution.size == new_resolution)
359       has_new_resolution = true;
360     if (resolution.size == old_resolution)
361       has_old_resolution = true;
362   }
363   if (!has_new_resolution) {
364     LOG(ERROR) << "No new resolution " << new_resolution.ToString()
365                << " is found in the display info " << display_info.ToString();
366     return;
367   }
368   if (!has_old_resolution) {
369     LOG(ERROR) << "No old resolution " << old_resolution.ToString()
370                << " is found in the display info " << display_info.ToString();
371     return;
372   }
373 
374   ash::Shell::GetInstance()->resolution_notification_controller()->
375       SetDisplayResolutionAndNotify(
376           display_id, old_resolution, new_resolution,
377           base::Bind(&StoreDisplayPrefs));
378 }
379 
HandleSetOrientation(const base::ListValue * args)380 void DisplayOptionsHandler::HandleSetOrientation(const base::ListValue* args) {
381   DCHECK(!args->empty());
382 
383   int64 display_id = GetDisplayId(args);
384   if (display_id == gfx::Display::kInvalidDisplayID)
385     return;
386 
387   std::string rotation_value;
388   gfx::Display::Rotation new_rotation = gfx::Display::ROTATE_0;
389   if (!args->GetString(1, &rotation_value)) {
390     LOG(ERROR) << "Can't find new orientation";
391     return;
392   }
393   if (rotation_value == "90")
394     new_rotation = gfx::Display::ROTATE_90;
395   else if (rotation_value == "180")
396     new_rotation = gfx::Display::ROTATE_180;
397   else if (rotation_value == "270")
398     new_rotation = gfx::Display::ROTATE_270;
399   else if (rotation_value != "0")
400     LOG(ERROR) << "Invalid rotation: " << rotation_value << " Falls back to 0";
401 
402   GetDisplayManager()->SetDisplayRotation(display_id, new_rotation);
403 }
404 
405 }  // namespace options
406 }  // namespace chromeos
407