1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 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)
5c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ui/display/chromeos/display_configurator.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
8e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "base/command_line.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/strings/stringprintf.h"
124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/sys_info.h"
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
14e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "ui/display/display_switches.h"
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/display/types/display_mode.h"
161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/display/types/display_snapshot.h"
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/display/types/native_display_delegate.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace ui {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)typedef std::vector<const DisplayMode*> DisplayModeList;
2423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// The delay to perform configuration after RRNotify. See the comment for
266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// |configure_timer_|.
27effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochconst int kConfigureDelayMs = 500;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// The delay spent before reading the display configuration after coming out of
306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// suspend. While coming out of suspend the display state may be updating. This
316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// is used to wait until the hardware had a chance to update the display state
326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// such that we read an up to date state.
336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)const int kResumeDelayMs = 500;
346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Returns a string describing |state|.
36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)std::string DisplayPowerStateToString(chromeos::DisplayPowerState state) {
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  switch (state) {
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    case chromeos::DISPLAY_POWER_ALL_ON:
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return "ALL_ON";
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    case chromeos::DISPLAY_POWER_ALL_OFF:
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return "ALL_OFF";
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    case chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON:
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return "INTERNAL_OFF_EXTERNAL_ON";
44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    case chromeos::DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF:
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return "INTERNAL_ON_EXTERNAL_OFF";
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return "unknown (" + base::IntToString(state) + ")";
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Returns a string describing |state|.
52c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochstd::string DisplayStateToString(MultipleDisplayState state) {
5390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  switch (state) {
54c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    case MULTIPLE_DISPLAY_STATE_INVALID:
5590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return "INVALID";
56c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    case MULTIPLE_DISPLAY_STATE_HEADLESS:
5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return "HEADLESS";
58c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    case MULTIPLE_DISPLAY_STATE_SINGLE:
5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return "SINGLE";
60c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    case MULTIPLE_DISPLAY_STATE_DUAL_MIRROR:
6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return "DUAL_MIRROR";
62c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    case MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED:
6390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return "DUAL_EXTENDED";
6490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  NOTREACHED() << "Unknown state " << state;
6690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return "INVALID";
6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
69c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Returns the number of displays in |displays| that should be turned on, per
70c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// |state|.  If |display_power| is non-NULL, it is updated to contain the
71c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// on/off state of each corresponding entry in |displays|.
72c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochint GetDisplayPower(
73c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const std::vector<DisplayConfigurator::DisplayState>& display_states,
74c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    chromeos::DisplayPowerState state,
75c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    std::vector<bool>* display_power) {
76c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  int num_on_displays = 0;
77c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (display_power)
78c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    display_power->resize(display_states.size());
79c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
80c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  for (size_t i = 0; i < display_states.size(); ++i) {
81c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    bool internal =
82c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        display_states[i].display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    bool on =
84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        state == chromeos::DISPLAY_POWER_ALL_ON ||
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        (state == chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON &&
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)         !internal) ||
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        (state == chromeos::DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF && internal);
88c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if (display_power)
89c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      (*display_power)[i] = on;
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (on)
91c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      num_on_displays++;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
93c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return num_on_displays;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)const int DisplayConfigurator::kSetDisplayPowerNoFlags = 0;
1006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)const int DisplayConfigurator::kSetDisplayPowerForceProbe = 1 << 0;
1016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)const int
1026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)DisplayConfigurator::kSetDisplayPowerOnlyIfSingleInternalDisplay = 1 << 1;
1036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
104c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochDisplayConfigurator::DisplayState::DisplayState()
10523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    : display(NULL),
10623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      selected_mode(NULL),
10723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      mirror_mode(NULL) {}
1083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
109c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool DisplayConfigurator::TestApi::TriggerConfigureTimeout() {
1106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (configurator_->configure_timer_.IsRunning()) {
1116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    configurator_->configure_timer_.user_task().Run();
1126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    configurator_->configure_timer_.Stop();
1133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return true;
1143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  } else {
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// static
120c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst DisplayMode* DisplayConfigurator::FindDisplayModeMatchingSize(
121c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const DisplaySnapshot& display,
12223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    const gfx::Size& size) {
12323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  const DisplayMode* best_mode = NULL;
124c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  for (DisplayModeList::const_iterator it = display.modes().begin();
125c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch       it != display.modes().end();
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       ++it) {
12723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    const DisplayMode* mode = *it;
128d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
12923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if (mode->size() != size)
13023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      continue;
131d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
13223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if (!best_mode) {
13323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      best_mode = mode;
13423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      continue;
135d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
13623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
13723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if (mode->is_interlaced()) {
13823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      if (!best_mode->is_interlaced())
13923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        continue;
14023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    } else {
14123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      // Reset the best rate if the non interlaced is
14223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      // found the first time.
14323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      if (best_mode->is_interlaced()) {
14423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        best_mode = mode;
14523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        continue;
14623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      }
14723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
14823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if (mode->refresh_rate() < best_mode->refresh_rate())
14923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      continue;
15023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
15123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    best_mode = mode;
152d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
15323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
15423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return best_mode;
155d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
156d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
157c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochDisplayConfigurator::DisplayConfigurator()
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : state_controller_(NULL),
15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      mirroring_controller_(NULL),
160d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      is_panel_fitting_enabled_(false),
1614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      configure_display_(base::SysInfo::IsRunningOnChromeOS()),
162c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      display_state_(MULTIPLE_DISPLAY_STATE_INVALID),
1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      requested_power_state_(chromeos::DISPLAY_POWER_ALL_ON),
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      current_power_state_(chromeos::DISPLAY_POWER_ALL_ON),
165c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      next_display_protection_client_id_(1) {}
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
167c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochDisplayConfigurator::~DisplayConfigurator() {
168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (native_display_delegate_)
169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    native_display_delegate_->RemoveObserver(this);
170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid DisplayConfigurator::SetDelegateForTesting(
1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    scoped_ptr<NativeDisplayDelegate> display_delegate) {
174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(!native_display_delegate_);
175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
176116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  native_display_delegate_ = display_delegate.Pass();
177a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  configure_display_ = true;
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
180c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid DisplayConfigurator::SetInitialDisplayPower(
181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    chromeos::DisplayPowerState power_state) {
182c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DCHECK_EQ(display_state_, MULTIPLE_DISPLAY_STATE_INVALID);
1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  requested_power_state_ = current_power_state_ = power_state;
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
186c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid DisplayConfigurator::Init(bool is_panel_fitting_enabled) {
187d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  is_panel_fitting_enabled_ = is_panel_fitting_enabled;
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!configure_display_)
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // If the delegate is already initialized don't update it (For example, tests
1921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // set their own delegates).
193116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!native_display_delegate_) {
194116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    native_display_delegate_ = CreatePlatformNativeDisplayDelegate();
195a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    native_display_delegate_->AddObserver(this);
196effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
199c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid DisplayConfigurator::ForceInitialConfigure(
200c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    uint32_t background_color_argb) {
201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!configure_display_)
202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  native_display_delegate_->GrabServer();
205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  native_display_delegate_->Initialize();
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
207c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  UpdateCachedDisplays();
208c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (cached_displays_.size() > 1 && background_color_argb)
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    native_display_delegate_->SetBackgroundColor(background_color_argb);
2101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const MultipleDisplayState new_state = ChooseDisplayState(
2111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      requested_power_state_);
2121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const bool success = EnterStateOrFallBackToSoftwareMirroring(
2131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      new_state, requested_power_state_);
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Force the DPMS on chrome startup as the driver doesn't always detect
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that all displays are on when signing out.
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  native_display_delegate_->ForceDPMSOn();
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  native_display_delegate_->UngrabServer();
2193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  NotifyObservers(success, new_state);
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
222cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool DisplayConfigurator::IsMirroring() const {
223cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return display_state_ == MULTIPLE_DISPLAY_STATE_DUAL_MIRROR ||
224cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      (mirroring_controller_ &&
225cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)       mirroring_controller_->SoftwareMirroringEnabled());
226cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
227cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
228c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool DisplayConfigurator::ApplyProtections(const ContentProtections& requests) {
229c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  for (DisplayStateList::const_iterator it = cached_displays_.begin();
230c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch       it != cached_displays_.end();
231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       ++it) {
2320f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    uint32_t all_desired = 0;
233cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
234cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // In mirror mode, protection request of all displays need to be fulfilled.
235cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // In non-mirror mode, only request of client's display needs to be
236cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // fulfilled.
237cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ContentProtections::const_iterator request_it;
238cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (IsMirroring()) {
239cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      for (request_it = requests.begin();
240cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)           request_it != requests.end();
241cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)           ++request_it)
242cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        all_desired |= request_it->second;
243cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    } else {
244cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      request_it = requests.find(it->display->display_id());
245cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (request_it != requests.end())
246cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        all_desired = request_it->second;
247cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
24923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    switch (it->display->type()) {
250c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      case DISPLAY_CONNECTION_TYPE_UNKNOWN:
2510f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        return false;
2520f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      // DisplayPort, DVI, and HDMI all support HDCP.
253c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      case DISPLAY_CONNECTION_TYPE_DISPLAYPORT:
254c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      case DISPLAY_CONNECTION_TYPE_DVI:
255c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      case DISPLAY_CONNECTION_TYPE_HDMI: {
2561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        HDCPState current_state;
2571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        // Need to poll the driver for updates since other applications may
2581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        // have updated the state.
2591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        if (!native_display_delegate_->GetHDCPState(*it->display,
2601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                                    &current_state))
2610f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          return false;
2621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        bool current_desired = (current_state != HDCP_STATE_UNDESIRED);
2631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        bool new_desired = (all_desired & CONTENT_PROTECTION_METHOD_HDCP);
2641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        // Don't enable again if HDCP is already active. Some buggy drivers
2651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        // may disable and enable if setting "desired" in active state.
2661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        if (current_desired != new_desired) {
2671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          HDCPState new_state =
2681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              new_desired ? HDCP_STATE_DESIRED : HDCP_STATE_UNDESIRED;
2691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          if (!native_display_delegate_->SetHDCPState(*it->display, new_state))
2701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            return false;
2711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        }
2720f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        break;
2730f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      }
274c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      case DISPLAY_CONNECTION_TYPE_INTERNAL:
275c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      case DISPLAY_CONNECTION_TYPE_VGA:
276c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      case DISPLAY_CONNECTION_TYPE_NETWORK:
2770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        // No protections for these types. Do nothing.
2780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        break;
279c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      case DISPLAY_CONNECTION_TYPE_NONE:
2800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        NOTREACHED();
2810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        break;
2820f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    }
2830f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
2840f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2850f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return true;
2860f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
2870f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
288c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochDisplayConfigurator::ContentProtectionClientId
289c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochDisplayConfigurator::RegisterContentProtectionClient() {
2904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!configure_display_)
2910f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return kInvalidClientId;
2924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
293c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return next_display_protection_client_id_++;
2944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
296c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid DisplayConfigurator::UnregisterContentProtectionClient(
297c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    ContentProtectionClientId client_id) {
2980f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  client_protection_requests_.erase(client_id);
2990f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
300c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ContentProtections protections;
3010f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  for (ProtectionRequests::const_iterator it =
3020f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)           client_protection_requests_.begin();
3030f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)       it != client_protection_requests_.end();
3040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)       ++it) {
305c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    for (ContentProtections::const_iterator it2 = it->second.begin();
306a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)         it2 != it->second.end();
307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)         ++it2) {
3080f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      protections[it2->first] |= it2->second;
3090f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    }
3100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
3110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
3120f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  ApplyProtections(protections);
3134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
315c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool DisplayConfigurator::QueryContentProtectionStatus(
316c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    ContentProtectionClientId client_id,
317effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    int64_t display_id,
3184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    uint32_t* link_mask,
3194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    uint32_t* protection_mask) {
3204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!configure_display_)
3214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return false;
3224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  uint32_t enabled = 0;
3244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  uint32_t unfulfilled = 0;
3254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  *link_mask = 0;
326c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  for (DisplayStateList::const_iterator it = cached_displays_.begin();
327c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch       it != cached_displays_.end();
328a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       ++it) {
329cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Query display if it is in mirror mode or client on the same display.
330cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!IsMirroring() && it->display->display_id() != display_id)
3310f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      continue;
332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
33323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    *link_mask |= it->display->type();
33423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    switch (it->display->type()) {
335c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      case DISPLAY_CONNECTION_TYPE_UNKNOWN:
3364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        return false;
3374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      // DisplayPort, DVI, and HDMI all support HDCP.
338c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      case DISPLAY_CONNECTION_TYPE_DISPLAYPORT:
339c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      case DISPLAY_CONNECTION_TYPE_DVI:
340c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      case DISPLAY_CONNECTION_TYPE_HDMI: {
341a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        HDCPState state;
34223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        if (!native_display_delegate_->GetHDCPState(*it->display, &state))
3434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          return false;
344a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        if (state == HDCP_STATE_ENABLED)
345c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          enabled |= CONTENT_PROTECTION_METHOD_HDCP;
3464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        else
347c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          unfulfilled |= CONTENT_PROTECTION_METHOD_HDCP;
3484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        break;
3494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      }
350c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      case DISPLAY_CONNECTION_TYPE_INTERNAL:
351c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      case DISPLAY_CONNECTION_TYPE_VGA:
352c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      case DISPLAY_CONNECTION_TYPE_NETWORK:
3534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        // No protections for these types. Do nothing.
3544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        break;
355c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      case DISPLAY_CONNECTION_TYPE_NONE:
3564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        NOTREACHED();
3574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        break;
3584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
3594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
3604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Don't reveal protections requested by other clients.
3624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ProtectionRequests::iterator it = client_protection_requests_.find(client_id);
3634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (it != client_protection_requests_.end()) {
3640f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    uint32_t requested_mask = 0;
3650f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    if (it->second.find(display_id) != it->second.end())
3660f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      requested_mask = it->second[display_id];
3674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    *protection_mask = enabled & ~unfulfilled & requested_mask;
3684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  } else {
3694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    *protection_mask = 0;
3704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
3714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return true;
3724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
374c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool DisplayConfigurator::EnableContentProtection(
375c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    ContentProtectionClientId client_id,
376effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    int64_t display_id,
3774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    uint32_t desired_method_mask) {
3784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!configure_display_)
3794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return false;
3804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
381c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ContentProtections protections;
3824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for (ProtectionRequests::const_iterator it =
3834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)           client_protection_requests_.begin();
3844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       it != client_protection_requests_.end();
3854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       ++it) {
386c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    for (ContentProtections::const_iterator it2 = it->second.begin();
387a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)         it2 != it->second.end();
388a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)         ++it2) {
3890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      if (it->first == client_id && it2->first == display_id)
3900f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        continue;
3910f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      protections[it2->first] |= it2->second;
3920f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    }
3934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
3940f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  protections[display_id] |= desired_method_mask;
3954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3960f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!ApplyProtections(protections))
3970f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return false;
3980f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
399c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (desired_method_mask == CONTENT_PROTECTION_METHOD_NONE) {
4000f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    if (client_protection_requests_.find(client_id) !=
4010f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        client_protection_requests_.end()) {
4020f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      client_protection_requests_[client_id].erase(display_id);
4030f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      if (client_protection_requests_[client_id].size() == 0)
4040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        client_protection_requests_.erase(client_id);
4054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
4060f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  } else {
4070f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    client_protection_requests_[client_id][display_id] = desired_method_mask;
4084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return true;
4114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
4124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
413effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstd::vector<ui::ColorCalibrationProfile>
414c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochDisplayConfigurator::GetAvailableColorCalibrationProfiles(int64_t display_id) {
415e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
416e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch          switches::kDisableDisplayColorCalibration)) {
417c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    for (size_t i = 0; i < cached_displays_.size(); ++i) {
418c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      if (cached_displays_[i].display &&
419c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          cached_displays_[i].display->display_id() == display_id) {
420e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        return native_display_delegate_->GetAvailableColorCalibrationProfiles(
421c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            *cached_displays_[i].display);
422e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      }
423effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
424effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
425effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
426effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return std::vector<ui::ColorCalibrationProfile>();
427effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
428effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
429c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool DisplayConfigurator::SetColorCalibrationProfile(
430effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    int64_t display_id,
43123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    ui::ColorCalibrationProfile new_profile) {
432c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  for (size_t i = 0; i < cached_displays_.size(); ++i) {
433c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if (cached_displays_[i].display &&
434c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        cached_displays_[i].display->display_id() == display_id) {
43523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      return native_display_delegate_->SetColorCalibrationProfile(
436c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          *cached_displays_[i].display, new_profile);
43723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
43823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
43923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
44023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return false;
44123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
44223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
443c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid DisplayConfigurator::PrepareForExit() {
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  configure_display_ = false;
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
447c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool DisplayConfigurator::SetDisplayPower(
448a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    chromeos::DisplayPowerState power_state,
449a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    int flags) {
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!configure_display_)
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
452c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
453c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  VLOG(1) << "SetDisplayPower: power_state="
4544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          << DisplayPowerStateToString(power_state) << " flags=" << flags
4554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          << ", configure timer="
4566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          << (configure_timer_.IsRunning() ? "Running" : "Stopped");
4571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (power_state == current_power_state_ &&
4581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      !(flags & kSetDisplayPowerForceProbe))
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  native_display_delegate_->GrabServer();
462c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  UpdateCachedDisplays();
463c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
464c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  const MultipleDisplayState new_state = ChooseDisplayState(power_state);
4653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  bool attempted_change = false;
4663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  bool success = false;
4673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
468c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool only_if_single_internal_display =
469c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      flags & kSetDisplayPowerOnlyIfSingleInternalDisplay;
47068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  bool single_internal_display =
471c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      cached_displays_.size() == 1 &&
472c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      cached_displays_[0].display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
4733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (single_internal_display || !only_if_single_internal_display) {
47468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    success = EnterStateOrFallBackToSoftwareMirroring(new_state, power_state);
4753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    attempted_change = true;
4763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Force the DPMS on since the driver doesn't always detect that it
4783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // should turn on. This is needed when coming back from idle suspend.
479a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (success && power_state != chromeos::DISPLAY_POWER_ALL_OFF)
4805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      native_display_delegate_->ForceDPMSOn();
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  native_display_delegate_->UngrabServer();
4843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (attempted_change)
4853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    NotifyObservers(success, new_state);
4861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return success;
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
489c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool DisplayConfigurator::SetDisplayMode(MultipleDisplayState new_state) {
490c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!configure_display_)
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
493c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  VLOG(1) << "SetDisplayMode: state=" << DisplayStateToString(new_state);
494c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (display_state_ == new_state) {
495868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Cancel software mirroring if the state is moving from
496c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED to
497c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED.
498c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if (mirroring_controller_ &&
499c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        new_state == MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED)
500868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      mirroring_controller_->SetSoftwareMirroring(false);
5013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    NotifyObservers(true, new_state);
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
503868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  native_display_delegate_->GrabServer();
506c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  UpdateCachedDisplays();
5071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const bool success = EnterStateOrFallBackToSoftwareMirroring(
5081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      new_state, requested_power_state_);
5095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  native_display_delegate_->UngrabServer();
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  NotifyObservers(success, new_state);
512c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return success;
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid DisplayConfigurator::OnConfigurationChanged() {
516c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Configure displays with |kConfigureDelayMs| delay,
517c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // so that time-consuming ConfigureDisplays() won't be called multiple times.
5186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (configure_timer_.IsRunning()) {
5196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // Note: when the timer is running it is possible that a different task
5206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // (SetDisplayPower()) is scheduled. In these cases, prefer the already
5216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // scheduled task to ConfigureDisplays() since ConfigureDisplays() performs
5226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // only basic configuration while SetDisplayPower() will perform additional
5236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // operations.
5246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    configure_timer_.Reset();
525a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else {
5266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    configure_timer_.Start(
527a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        FROM_HERE,
528a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::TimeDelta::FromMilliseconds(kConfigureDelayMs),
529a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        this,
530c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        &DisplayConfigurator::ConfigureDisplays);
531558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
532558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
533558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
534c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid DisplayConfigurator::AddObserver(Observer* observer) {
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_.AddObserver(observer);
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
538c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid DisplayConfigurator::RemoveObserver(Observer* observer) {
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_.RemoveObserver(observer);
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
542c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid DisplayConfigurator::SuspendDisplays() {
543c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If the display is off due to user inactivity and there's only a single
544c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // internal display connected, switch to the all-on state before
545c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // suspending.  This shouldn't be very noticeable to the user since the
546c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // backlight is off at this point, and doing this lets us resume directly
547c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // into the "on" state, which greatly reduces resume times.
5481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (requested_power_state_ == chromeos::DISPLAY_POWER_ALL_OFF) {
549a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON,
550c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    kSetDisplayPowerOnlyIfSingleInternalDisplay);
551c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
552c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // We need to make sure that the monitor configuration we just did actually
553c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // completes before we return, because otherwise the X message could be
554c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // racing with the HandleSuspendReadiness message.
5555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    native_display_delegate_->SyncWithServer();
556c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
559c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid DisplayConfigurator::ResumeDisplays() {
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Force probing to ensure that we pick up any changes that were made
5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // while the system was suspended.
5626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  configure_timer_.Start(
5636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      FROM_HERE,
5646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(kResumeDelayMs),
5656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      base::Bind(base::IgnoreResult(&DisplayConfigurator::SetDisplayPower),
5666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                 base::Unretained(this),
5671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 requested_power_state_,
5686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                 kSetDisplayPowerForceProbe));
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
571c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid DisplayConfigurator::UpdateCachedDisplays() {
57223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  std::vector<DisplaySnapshot*> snapshots =
573c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      native_display_delegate_->GetDisplays();
57423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
575c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  cached_displays_.clear();
57623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  for (size_t i = 0; i < snapshots.size(); ++i) {
57723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    DisplayState display_state;
57823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    display_state.display = snapshots[i];
579c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    cached_displays_.push_back(display_state);
58023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
58123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
582d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Set |selected_mode| fields.
583c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  for (size_t i = 0; i < cached_displays_.size(); ++i) {
584c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    DisplayState* display_state = &cached_displays_[i];
585c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if (display_state->display->has_proper_display_id()) {
58623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      gfx::Size size;
587c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      if (state_controller_ &&
588c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          state_controller_->GetResolutionForDisplayId(
589c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch              display_state->display->display_id(), &size)) {
590c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        display_state->selected_mode =
591c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            FindDisplayModeMatchingSize(*display_state->display, size);
592d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      }
593d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
594d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Fall back to native mode.
595c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if (!display_state->selected_mode)
596c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      display_state->selected_mode = display_state->display->native_mode();
597d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
598d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
599d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Set |mirror_mode| fields.
600c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (cached_displays_.size() == 2) {
60123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    bool one_is_internal =
602c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        cached_displays_[0].display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
60323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    bool two_is_internal =
604c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        cached_displays_[1].display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
605c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    int internal_displays =
606a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        (one_is_internal ? 1 : 0) + (two_is_internal ? 1 : 0);
607c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    DCHECK_LT(internal_displays, 2);
608c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    LOG_IF(WARNING, internal_displays == 2)
609c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        << "Two internal displays detected.";
610d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
611d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    bool can_mirror = false;
612d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    for (int attempt = 0; !can_mirror && attempt < 2; ++attempt) {
613c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      // Try preserving external display's aspect ratio on the first attempt.
614d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      // If that fails, fall back to the highest matching resolution.
615d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      bool preserve_aspect = attempt == 0;
616d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
617c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      if (internal_displays == 1) {
618d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if (one_is_internal) {
619c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          can_mirror = FindMirrorMode(&cached_displays_[0],
620c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      &cached_displays_[1],
621a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                      is_panel_fitting_enabled_,
622a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                      preserve_aspect);
623d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        } else {
624d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          DCHECK(two_is_internal);
625c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          can_mirror = FindMirrorMode(&cached_displays_[1],
626c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      &cached_displays_[0],
627a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                      is_panel_fitting_enabled_,
628a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                      preserve_aspect);
629d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        }
630c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      } else {  // if (internal_displays == 0)
631c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        // No panel fitting for external displays, so fall back to exact match.
632a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        can_mirror = FindMirrorMode(
633c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            &cached_displays_[0], &cached_displays_[1], false, preserve_aspect);
634d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if (!can_mirror && preserve_aspect) {
635d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          // FindMirrorMode() will try to preserve aspect ratio of what it
636d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          // thinks is external display, so if it didn't succeed with one, maybe
637d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          // it will succeed with the other.  This way we will have the correct
638d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          // aspect ratio on at least one of them.
639c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          can_mirror = FindMirrorMode(&cached_displays_[1],
640c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      &cached_displays_[0],
641c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      false,
642c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      preserve_aspect);
643d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        }
644d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      }
645d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
646d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
647d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
648d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
649c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool DisplayConfigurator::FindMirrorMode(DisplayState* internal_display,
650c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                         DisplayState* external_display,
651c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                         bool try_panel_fitting,
652c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                         bool preserve_aspect) {
65323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  const DisplayMode* internal_native_info =
654c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      internal_display->display->native_mode();
65523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  const DisplayMode* external_native_info =
656c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      external_display->display->native_mode();
657d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (!internal_native_info || !external_native_info)
658d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return false;
659d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
660c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Check if some external display resolution can be mirrored on internal.
661c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Prefer the modes in the order they're present in DisplaySnapshot, assuming
662c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // this is the order in which they look better on the monitor.
66323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  for (DisplayModeList::const_iterator external_it =
664c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch           external_display->display->modes().begin();
665c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch       external_it != external_display->display->modes().end();
666a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       ++external_it) {
66723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    const DisplayMode& external_info = **external_it;
668d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    bool is_native_aspect_ratio =
66923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        external_native_info->size().width() * external_info.size().height() ==
67023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        external_native_info->size().height() * external_info.size().width();
671d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (preserve_aspect && !is_native_aspect_ratio)
672d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      continue;  // Allow only aspect ratio preserving modes for mirroring.
673d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
674d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Try finding an exact match.
67523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    for (DisplayModeList::const_iterator internal_it =
676c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch             internal_display->display->modes().begin();
677c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch         internal_it != internal_display->display->modes().end();
678a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)         ++internal_it) {
67923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      const DisplayMode& internal_info = **internal_it;
68023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      if (internal_info.size().width() == external_info.size().width() &&
68123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          internal_info.size().height() == external_info.size().height() &&
68223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          internal_info.is_interlaced() == external_info.is_interlaced()) {
683c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        internal_display->mirror_mode = *internal_it;
684c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        external_display->mirror_mode = *external_it;
685d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        return true;  // Mirror mode found.
686d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      }
687d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
688d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
689c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // Try to create a matching internal display mode by panel fitting.
690d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (try_panel_fitting) {
691d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      // We can downscale by 1.125, and upscale indefinitely. Downscaling looks
692d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      // ugly, so, can fit == can upscale. Also, internal panels don't support
693d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      // fitting interlaced modes.
69423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      bool can_fit = internal_native_info->size().width() >=
69523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                         external_info.size().width() &&
69623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                     internal_native_info->size().height() >=
69723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                         external_info.size().height() &&
69823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                     !external_info.is_interlaced();
699d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      if (can_fit) {
700c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        native_display_delegate_->AddMode(*internal_display->display,
70123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                                          *external_it);
702c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        internal_display->display->add_mode(*external_it);
703c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        internal_display->mirror_mode = *external_it;
704c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        external_display->mirror_mode = *external_it;
705d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        return true;  // Mirror mode created.
706d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      }
707d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
708d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
709d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
710d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return false;
711d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
712d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
713c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid DisplayConfigurator::ConfigureDisplays() {
714a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!configure_display_)
715a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
716a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
7175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  native_display_delegate_->GrabServer();
718c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  UpdateCachedDisplays();
7191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const MultipleDisplayState new_state = ChooseDisplayState(
7201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      requested_power_state_);
7211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const bool success = EnterStateOrFallBackToSoftwareMirroring(
7221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      new_state, requested_power_state_);
7235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  native_display_delegate_->UngrabServer();
7242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  NotifyObservers(success, new_state);
7262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
728c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid DisplayConfigurator::NotifyObservers(
729c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    bool success,
730c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    MultipleDisplayState attempted_state) {
7313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (success) {
732a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    FOR_EACH_OBSERVER(
733c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        Observer, observers_, OnDisplayModeChanged(cached_displays_));
7343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  } else {
735a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    FOR_EACH_OBSERVER(
736a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        Observer, observers_, OnDisplayModeChangeFailed(attempted_state));
7373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
740c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool DisplayConfigurator::EnterStateOrFallBackToSoftwareMirroring(
741c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    MultipleDisplayState display_state,
742a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    chromeos::DisplayPowerState power_state) {
743c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  bool success = EnterState(display_state, power_state);
74490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (mirroring_controller_) {
74590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    bool enable_software_mirroring = false;
746c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if (!success && display_state == MULTIPLE_DISPLAY_STATE_DUAL_MIRROR) {
747c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      if (display_state_ != MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED ||
7481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          current_power_state_ != power_state)
749c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        EnterState(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED, power_state);
75090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      enable_software_mirroring = success =
751c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          display_state_ == MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED;
75290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
75390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    mirroring_controller_->SetSoftwareMirroring(enable_software_mirroring);
75490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
75590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return success;
75690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
75790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
758c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool DisplayConfigurator::EnterState(MultipleDisplayState display_state,
759c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                     chromeos::DisplayPowerState power_state) {
760c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  std::vector<bool> display_power;
761c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  int num_on_displays =
762c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      GetDisplayPower(cached_displays_, power_state, &display_power);
763c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  VLOG(1) << "EnterState: display=" << DisplayStateToString(display_state)
76490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          << " power=" << DisplayPowerStateToString(power_state);
765ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
7661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Save the requested state so we'll try to use it next time even if we fail.
7671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  requested_power_state_ = power_state;
7681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
769ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // Framebuffer dimensions.
77023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  gfx::Size size;
77123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
772c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  std::vector<gfx::Point> new_origins(cached_displays_.size(), gfx::Point());
77323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  std::vector<const DisplayMode*> new_mode;
774c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  for (size_t i = 0; i < cached_displays_.size(); ++i)
775c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    new_mode.push_back(cached_displays_[i].display->current_mode());
776ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
777c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  switch (display_state) {
778c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    case MULTIPLE_DISPLAY_STATE_INVALID:
779ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      NOTREACHED() << "Ignoring request to enter invalid state with "
780c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                   << cached_displays_.size() << " connected display(s)";
781ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      return false;
782c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    case MULTIPLE_DISPLAY_STATE_HEADLESS:
783c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      if (cached_displays_.size() != 0) {
784c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        LOG(WARNING) << "Ignoring request to enter headless mode with "
785c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                     << cached_displays_.size() << " connected display(s)";
786c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return false;
787c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
7882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
789c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    case MULTIPLE_DISPLAY_STATE_SINGLE: {
790c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      // If there are multiple displays connected, only one should be turned on.
791c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      if (cached_displays_.size() != 1 && num_on_displays != 1) {
792c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        LOG(WARNING) << "Ignoring request to enter single mode with "
793c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                     << cached_displays_.size() << " connected displays and "
794c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                     << num_on_displays << " turned on";
7952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return false;
7962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
7972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
798c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      for (size_t i = 0; i < cached_displays_.size(); ++i) {
799c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        DisplayState* state = &cached_displays_[i];
800c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        new_mode[i] = display_power[i] ? state->selected_mode : NULL;
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
802c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        if (display_power[i] || cached_displays_.size() == 1) {
803c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          const DisplayMode* mode_info = state->selected_mode;
8045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          if (!mode_info) {
8055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            LOG(WARNING) << "No selected mode when configuring display: "
8065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                         << state->display->ToString();
807ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch            return false;
8085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          }
80923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          if (mode_info->size() == gfx::Size(1024, 768)) {
8104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            VLOG(1) << "Potentially misdetecting display(1024x768):"
811c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                    << " displays size=" << cached_displays_.size()
812c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                    << ", num_on_displays=" << num_on_displays
81323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                    << ", current size:" << size.width() << "x" << size.height()
814c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                    << ", i=" << i << ", display=" << state->display->ToString()
81523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                    << ", display_mode=" << mode_info->ToString();
8164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          }
81723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          size = mode_info->size();
818c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
8192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
8202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
822c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    case MULTIPLE_DISPLAY_STATE_DUAL_MIRROR: {
823c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      if (cached_displays_.size() != 2 ||
824c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          (num_on_displays != 0 && num_on_displays != 2)) {
825c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        LOG(WARNING) << "Ignoring request to enter mirrored mode with "
826c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                     << cached_displays_.size() << " connected display(s) and "
827c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                     << num_on_displays << " turned on";
828c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return false;
829c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
8302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
831c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      const DisplayMode* mode_info = cached_displays_[0].mirror_mode;
8325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (!mode_info) {
8335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        LOG(WARNING) << "No mirror mode when configuring display: "
8345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                     << cached_displays_[0].display->ToString();
835c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return false;
8365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
83723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      size = mode_info->size();
83823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
839c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      for (size_t i = 0; i < cached_displays_.size(); ++i) {
840c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        DisplayState* state = &cached_displays_[i];
841c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        new_mode[i] = display_power[i] ? state->mirror_mode : NULL;
842c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
843c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      break;
844c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
845c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    case MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED: {
846c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      if (cached_displays_.size() != 2 ||
847c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          (num_on_displays != 0 && num_on_displays != 2)) {
848c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        LOG(WARNING) << "Ignoring request to enter extended mode with "
849c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                     << cached_displays_.size() << " connected display(s) and "
850c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                     << num_on_displays << " turned on";
851c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return false;
852c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
854c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      for (size_t i = 0; i < cached_displays_.size(); ++i) {
855c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        DisplayState* state = &cached_displays_[i];
85623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        new_origins[i].set_y(size.height() ? size.height() + kVerticalGap : 0);
857c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        new_mode[i] = display_power[i] ? state->selected_mode : NULL;
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
859c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        // Retain the full screen size even if all displays are off so the
860c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        // same desktop configuration can be restored when the displays are
861c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // turned back on.
862c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        const DisplayMode* mode_info = cached_displays_[i].selected_mode;
8635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (!mode_info) {
8645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          LOG(WARNING) << "No selected mode when configuring display: "
8655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                       << state->display->ToString();
8663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          return false;
8675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
86823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
86923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        size.set_width(std::max<int>(size.width(), mode_info->size().width()));
87023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        size.set_height(size.height() + (size.height() ? kVerticalGap : 0) +
87123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        mode_info->size().height());
872c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
8732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
875ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
876ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
877ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // Finally, apply the desired changes.
8785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool all_succeeded = true;
879c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!cached_displays_.empty()) {
88023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    native_display_delegate_->CreateFrameBuffer(size);
881c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    for (size_t i = 0; i < cached_displays_.size(); ++i) {
882c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      const DisplayState& state = cached_displays_[i];
883a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      bool configure_succeeded = false;
8845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      while (true) {
886a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        if (native_display_delegate_->Configure(
887c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                *state.display, new_mode[i], new_origins[i])) {
888c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          state.display->set_current_mode(new_mode[i]);
889c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          state.display->set_origin(new_origins[i]);
89023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
8915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          configure_succeeded = true;
8925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          break;
8935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
8945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
89523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        const DisplayMode* mode_info = new_mode[i];
8965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (!mode_info)
8975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          break;
8985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // Find the mode with the next-best resolution and see if that can
9005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // be set.
9015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        int best_mode_pixels = 0;
9025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
90323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        int current_mode_pixels = mode_info->size().GetArea();
90423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        for (DisplayModeList::const_iterator it =
905c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 state.display->modes().begin();
906c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch             it != state.display->modes().end();
907a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)             it++) {
90823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          int pixel_count = (*it)->size().GetArea();
9095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          if ((pixel_count < current_mode_pixels) &&
9105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              (pixel_count > best_mode_pixels)) {
91123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            new_mode[i] = *it;
9125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            best_mode_pixels = pixel_count;
9135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          }
9145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
9155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (best_mode_pixels == 0)
9175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          break;
918ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      }
9195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
920cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (!configure_succeeded)
9215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        all_succeeded = false;
9225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // If we are trying to set mirror mode and one of the modesets fails,
9245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // then the two monitors will be mis-matched.  In this case, return
9255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // false to let the observers be aware.
926c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      if (display_state == MULTIPLE_DISPLAY_STATE_DUAL_MIRROR &&
927c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          display_power[i] &&
928c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          state.display->current_mode() != state.mirror_mode)
9295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        all_succeeded = false;
930ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    }
9312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
933a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (all_succeeded) {
934c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    display_state_ = display_state;
9351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    current_power_state_ = power_state;
936cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    framebuffer_size_ = size;
9375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
9385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return all_succeeded;
9392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
941c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochMultipleDisplayState DisplayConfigurator::ChooseDisplayState(
942a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    chromeos::DisplayPowerState power_state) const {
943c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  int num_on_displays = GetDisplayPower(cached_displays_, power_state, NULL);
944c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  switch (cached_displays_.size()) {
9452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case 0:
946c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      return MULTIPLE_DISPLAY_STATE_HEADLESS;
9472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case 1:
948c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      return MULTIPLE_DISPLAY_STATE_SINGLE;
9492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case 2: {
950c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      if (num_on_displays == 1) {
951c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        // If only one display is currently turned on, return the "single"
952c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // state so that its native mode will be used.
953c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        return MULTIPLE_DISPLAY_STATE_SINGLE;
954c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      } else {
955effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        if (!state_controller_)
956c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          return MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED;
957c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        // With either both displays on or both displays off, use one of the
958c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // dual modes.
959effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        std::vector<int64_t> display_ids;
960c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        for (size_t i = 0; i < cached_displays_.size(); ++i) {
96190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          // If display id isn't available, switch to extended mode.
962c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          if (!cached_displays_[i].display->has_proper_display_id())
963c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            return MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED;
964c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          display_ids.push_back(cached_displays_[i].display->display_id());
96590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        }
96690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        return state_controller_->GetStateForDisplayIds(display_ids);
9672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
9682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
9692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    default:
970c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      NOTREACHED();
9712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
972c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return MULTIPLE_DISPLAY_STATE_INVALID;
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace ui
976