1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef UI_DISPLAY_CHROMEOS_DISPLAY_CONFIGURATOR_H_ 6 #define UI_DISPLAY_CHROMEOS_DISPLAY_CONFIGURATOR_H_ 7 8 #include <stdint.h> 9 10 #include <map> 11 #include <string> 12 #include <vector> 13 14 #include "base/event_types.h" 15 #include "base/memory/scoped_ptr.h" 16 #include "base/observer_list.h" 17 #include "base/timer/timer.h" 18 #include "third_party/cros_system_api/dbus/service_constants.h" 19 #include "ui/display/display_export.h" 20 #include "ui/display/types/display_constants.h" 21 #include "ui/display/types/native_display_observer.h" 22 #include "ui/gfx/geometry/size.h" 23 24 namespace gfx { 25 class Point; 26 class Size; 27 } 28 29 namespace ui { 30 class DisplayMode; 31 class DisplaySnapshot; 32 class NativeDisplayDelegate; 33 34 // This class interacts directly with the system display configurator. 35 class DISPLAY_EXPORT DisplayConfigurator : public NativeDisplayObserver { 36 public: 37 typedef uint64_t ContentProtectionClientId; 38 static const ContentProtectionClientId kInvalidClientId = 0; 39 40 struct DisplayState { 41 DisplayState(); 42 43 DisplaySnapshot* display; // Not owned. 44 45 // User-selected mode for the display. 46 const DisplayMode* selected_mode; 47 48 // Mode used when displaying the same desktop on multiple displays. 49 const DisplayMode* mirror_mode; 50 }; 51 52 typedef std::vector<DisplayState> DisplayStateList; 53 54 class Observer { 55 public: ~Observer()56 virtual ~Observer() {} 57 58 // Called after the display mode has been changed. |display| contains the 59 // just-applied configuration. Note that the X server is no longer grabbed 60 // when this method is called, so the actual configuration could've changed 61 // already. OnDisplayModeChanged(const std::vector<DisplayState> & displays)62 virtual void OnDisplayModeChanged( 63 const std::vector<DisplayState>& displays) {} 64 65 // Called after a display mode change attempt failed. |failed_new_state| is 66 // the new state which the system failed to enter. OnDisplayModeChangeFailed(MultipleDisplayState failed_new_state)67 virtual void OnDisplayModeChangeFailed( 68 MultipleDisplayState failed_new_state) {} 69 }; 70 71 // Interface for classes that make decisions about which display state 72 // should be used. 73 class StateController { 74 public: ~StateController()75 virtual ~StateController() {} 76 77 // Called when displays are detected. 78 virtual MultipleDisplayState GetStateForDisplayIds( 79 const std::vector<int64_t>& display_ids) const = 0; 80 81 // Queries the resolution (|size|) in pixels to select display mode for the 82 // given display id. 83 virtual bool GetResolutionForDisplayId(int64_t display_id, 84 gfx::Size* size) const = 0; 85 }; 86 87 // Interface for classes that implement software based mirroring. 88 class SoftwareMirroringController { 89 public: ~SoftwareMirroringController()90 virtual ~SoftwareMirroringController() {} 91 92 // Called when the hardware mirroring failed. 93 virtual void SetSoftwareMirroring(bool enabled) = 0; 94 virtual bool SoftwareMirroringEnabled() const = 0; 95 }; 96 97 // Helper class used by tests. 98 class TestApi { 99 public: TestApi(DisplayConfigurator * configurator)100 TestApi(DisplayConfigurator* configurator) : configurator_(configurator) {} ~TestApi()101 ~TestApi() {} 102 103 // If |configure_timer_| is started, stops the timer, runs 104 // ConfigureDisplays(), and returns true; returns false otherwise. 105 bool TriggerConfigureTimeout() WARN_UNUSED_RESULT; 106 107 private: 108 DisplayConfigurator* configurator_; // not owned 109 110 DISALLOW_COPY_AND_ASSIGN(TestApi); 111 }; 112 113 // Flags that can be passed to SetDisplayPower(). 114 static const int kSetDisplayPowerNoFlags; 115 // Configure displays even if the passed-in state matches |power_state_|. 116 static const int kSetDisplayPowerForceProbe; 117 // Do not change the state if multiple displays are connected or if the 118 // only connected display is external. 119 static const int kSetDisplayPowerOnlyIfSingleInternalDisplay; 120 121 // Gap between screens so cursor at bottom of active display doesn't 122 // partially appear on top of inactive display. Higher numbers guard 123 // against larger cursors, but also waste more memory. 124 // For simplicity, this is hard-coded to avoid the complexity of always 125 // determining the DPI of the screen and rationalizing which screen we 126 // need to use for the DPI calculation. 127 // See crbug.com/130188 for initial discussion. 128 static const int kVerticalGap = 60; 129 130 // Returns the mode within |display| that matches the given size with highest 131 // refresh rate. Returns None if no matching display was found. 132 static const DisplayMode* FindDisplayModeMatchingSize( 133 const DisplaySnapshot& display, 134 const gfx::Size& size); 135 136 DisplayConfigurator(); 137 virtual ~DisplayConfigurator(); 138 display_state()139 MultipleDisplayState display_state() const { return display_state_; } requested_power_state()140 chromeos::DisplayPowerState requested_power_state() const { 141 return requested_power_state_; 142 } framebuffer_size()143 const gfx::Size framebuffer_size() const { return framebuffer_size_; } cached_displays()144 const std::vector<DisplayState>& cached_displays() const { 145 return cached_displays_; 146 } 147 set_state_controller(StateController * controller)148 void set_state_controller(StateController* controller) { 149 state_controller_ = controller; 150 } set_mirroring_controller(SoftwareMirroringController * controller)151 void set_mirroring_controller(SoftwareMirroringController* controller) { 152 mirroring_controller_ = controller; 153 } 154 155 // Replaces |native_display_delegate_| with the delegate passed in and sets 156 // |configure_display_| to true. Should be called before Init(). 157 void SetDelegateForTesting( 158 scoped_ptr<NativeDisplayDelegate> display_delegate); 159 160 // Sets the initial value of |power_state_|. Must be called before Start(). 161 void SetInitialDisplayPower(chromeos::DisplayPowerState power_state); 162 163 // Initialization, must be called right after constructor. 164 // |is_panel_fitting_enabled| indicates hardware panel fitting support. 165 void Init(bool is_panel_fitting_enabled); 166 167 // Does initial configuration of displays during startup. 168 // If |background_color_argb| is non zero and there are multiple displays, 169 // DisplayConfigurator sets the background color of X's RootWindow to this 170 // color. 171 void ForceInitialConfigure(uint32_t background_color_argb); 172 173 // Stop handling display configuration events/requests. 174 void PrepareForExit(); 175 176 // Called when powerd notifies us that some set of displays should be turned 177 // on or off. This requires enabling or disabling the CRTC associated with 178 // the display(s) in question so that the low power state is engaged. 179 // |flags| contains bitwise-or-ed kSetDisplayPower* values. Returns true if 180 // the system successfully enters (or was already in) |power_state|. 181 bool SetDisplayPower(chromeos::DisplayPowerState power_state, int flags); 182 183 // Force switching the display mode to |new_state|. Returns false if 184 // switching failed (possibly because |new_state| is invalid for the 185 // current set of connected displays). 186 bool SetDisplayMode(MultipleDisplayState new_state); 187 188 // NativeDisplayDelegate::Observer overrides: 189 virtual void OnConfigurationChanged() OVERRIDE; 190 191 void AddObserver(Observer* observer); 192 void RemoveObserver(Observer* observer); 193 194 // Sets all the displays into pre-suspend mode; usually this means 195 // configure them for their resume state. This allows faster resume on 196 // machines where display configuration is slow. 197 void SuspendDisplays(); 198 199 // Reprobes displays to handle changes made while the system was 200 // suspended. 201 void ResumeDisplays(); 202 203 // Registers a client for display protection and requests a client id. Returns 204 // 0 if requesting failed. 205 ContentProtectionClientId RegisterContentProtectionClient(); 206 207 // Unregisters the client. 208 void UnregisterContentProtectionClient(ContentProtectionClientId client_id); 209 210 // Queries link status and protection status. 211 // |link_mask| is the type of connected display links, which is a bitmask of 212 // DisplayConnectionType values. |protection_mask| is the desired protection 213 // methods, which is a bitmask of the ContentProtectionMethod values. 214 // Returns true on success. 215 bool QueryContentProtectionStatus(ContentProtectionClientId client_id, 216 int64_t display_id, 217 uint32_t* link_mask, 218 uint32_t* protection_mask); 219 220 // Requests the desired protection methods. 221 // |protection_mask| is the desired protection methods, which is a bitmask 222 // of the ContentProtectionMethod values. 223 // Returns true when the protection request has been made. 224 bool EnableContentProtection(ContentProtectionClientId client_id, 225 int64_t display_id, 226 uint32_t desired_protection_mask); 227 228 // Checks the available color profiles for |display_id| and fills the result 229 // into |profiles|. 230 std::vector<ui::ColorCalibrationProfile> GetAvailableColorCalibrationProfiles( 231 int64_t display_id); 232 233 // Updates the color calibration to |new_profile|. 234 bool SetColorCalibrationProfile(int64_t display_id, 235 ui::ColorCalibrationProfile new_profile); 236 237 private: 238 // Mapping a display_id to a protection request bitmask. 239 typedef std::map<int64_t, uint32_t> ContentProtections; 240 // Mapping a client to its protection request. 241 typedef std::map<ContentProtectionClientId, ContentProtections> 242 ProtectionRequests; 243 244 // Performs platform specific delegate initialization. 245 scoped_ptr<NativeDisplayDelegate> CreatePlatformNativeDisplayDelegate(); 246 247 // Updates |cached_displays_| to contain currently-connected displays. Calls 248 // |delegate_->GetDisplays()| and then does additional work, like finding the 249 // mirror mode and setting user-preferred modes. Note that the server must be 250 // grabbed via |delegate_->GrabServer()| first. 251 void UpdateCachedDisplays(); 252 253 // Helper method for UpdateCachedDisplays() that initializes the passed-in 254 // displays' |mirror_mode| fields by looking for a mode in |internal_display| 255 // and |external_display| having the same resolution. Returns false if a 256 // shared 257 // mode wasn't found or created. 258 // 259 // |try_panel_fitting| allows creating a panel-fitting mode for 260 // |internal_display| instead of only searching for a matching mode (note that 261 // it may lead to a crash if |internal_info| is not capable of panel fitting). 262 // 263 // |preserve_aspect| limits the search/creation only to the modes having the 264 // native aspect ratio of |external_display|. 265 bool FindMirrorMode(DisplayState* internal_display, 266 DisplayState* external_display, 267 bool try_panel_fitting, 268 bool preserve_aspect); 269 270 // Configures displays. 271 void ConfigureDisplays(); 272 273 // Notifies observers about an attempted state change. 274 void NotifyObservers(bool success, MultipleDisplayState attempted_state); 275 276 // Switches to the state specified in |display_state| and |power_state|. 277 // If the hardware mirroring failed and |mirroring_controller_| is set, 278 // it switches to |STATE_DUAL_EXTENDED| and calls |SetSoftwareMirroring()| 279 // to enable software based mirroring. 280 // On success, updates |display_state_|, |power_state_|, and 281 // |cached_displays_| and returns true. 282 bool EnterStateOrFallBackToSoftwareMirroring( 283 MultipleDisplayState display_state, 284 chromeos::DisplayPowerState power_state); 285 286 // Switches to the state specified in |display_state| and |power_state|. 287 // On success, updates |display_state_|, |power_state_|, and 288 // |cached_displays_| and returns true. 289 bool EnterState(MultipleDisplayState display_state, 290 chromeos::DisplayPowerState power_state); 291 292 // Returns the display state that should be used with |cached_displays_| while 293 // in |power_state|. 294 MultipleDisplayState ChooseDisplayState( 295 chromeos::DisplayPowerState power_state) const; 296 297 // Returns the ratio between mirrored mode area and native mode area: 298 // (mirror_mode_width * mirrow_mode_height) / (native_width * native_height) 299 float GetMirroredDisplayAreaRatio(const DisplayState& display); 300 301 // Returns true if in either hardware or software mirroring mode. 302 bool IsMirroring() const; 303 304 // Applies display protections according to requests. 305 bool ApplyProtections(const ContentProtections& requests); 306 307 StateController* state_controller_; 308 SoftwareMirroringController* mirroring_controller_; 309 scoped_ptr<NativeDisplayDelegate> native_display_delegate_; 310 311 // Used to enable modes which rely on panel fitting. 312 bool is_panel_fitting_enabled_; 313 314 // This is detected by the constructor to determine whether or not we should 315 // be enabled. If we aren't running on ChromeOS, we can't assume that the 316 // Xrandr X11 extension is supported. 317 // If this flag is set to false, any attempts to change the display 318 // configuration to immediately fail without changing the state. 319 bool configure_display_; 320 321 // The current display state. 322 MultipleDisplayState display_state_; 323 324 gfx::Size framebuffer_size_; 325 326 // The last-requested and current power state. These may differ if 327 // configuration fails: SetDisplayMode() needs the last-requested state while 328 // SetDisplayPower() needs the current state. 329 chromeos::DisplayPowerState requested_power_state_; 330 chromeos::DisplayPowerState current_power_state_; 331 332 // Most-recently-used display configuration. Note that the actual 333 // configuration changes asynchronously. 334 DisplayStateList cached_displays_; 335 336 ObserverList<Observer> observers_; 337 338 // The timer to delay configuring displays. This is used to aggregate multiple 339 // display configuration events when they are reported in short time spans. 340 // See comment for NativeDisplayEventDispatcherX11 for more details. 341 base::OneShotTimer<DisplayConfigurator> configure_timer_; 342 343 // Id for next display protection client. 344 ContentProtectionClientId next_display_protection_client_id_; 345 346 // Display protection requests of each client. 347 ProtectionRequests client_protection_requests_; 348 349 DISALLOW_COPY_AND_ASSIGN(DisplayConfigurator); 350 }; 351 352 } // namespace ui 353 354 #endif // UI_DISPLAY_CHROMEOS_DISPLAY_CONFIGURATOR_H_ 355