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 ¤t_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