1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROMEOS_DISPLAY_OUTPUT_CONFIGURATOR_H_ 6 #define CHROMEOS_DISPLAY_OUTPUT_CONFIGURATOR_H_ 7 8 #include <map> 9 #include <string> 10 #include <vector> 11 12 #include "base/basictypes.h" 13 #include "base/event_types.h" 14 #include "base/memory/scoped_ptr.h" 15 #include "base/message_loop/message_loop.h" 16 #include "base/observer_list.h" 17 #include "base/timer/timer.h" 18 #include "chromeos/chromeos_export.h" 19 #include "third_party/cros_system_api/dbus/service_constants.h" 20 21 // Forward declarations for Xlib and Xrandr. 22 // This is so unused X definitions don't pollute the namespace. 23 typedef unsigned long XID; 24 typedef XID RROutput; 25 typedef XID RRCrtc; 26 typedef XID RRMode; 27 28 namespace chromeos { 29 30 // Used to describe the state of a multi-display configuration. 31 enum OutputState { 32 STATE_INVALID, 33 STATE_HEADLESS, 34 STATE_SINGLE, 35 STATE_DUAL_MIRROR, 36 STATE_DUAL_EXTENDED, 37 }; 38 39 // Video output types. 40 enum OutputType { 41 OUTPUT_TYPE_NONE = 0, 42 OUTPUT_TYPE_UNKNOWN = 1 << 0, 43 OUTPUT_TYPE_INTERNAL = 1 << 1, 44 OUTPUT_TYPE_VGA = 1 << 2, 45 OUTPUT_TYPE_HDMI = 1 << 3, 46 OUTPUT_TYPE_DVI = 1 << 4, 47 OUTPUT_TYPE_DISPLAYPORT = 1 << 5, 48 OUTPUT_TYPE_NETWORK = 1 << 6, 49 }; 50 51 // Content protection methods applied on video output. 52 enum OutputProtectionMethod { 53 OUTPUT_PROTECTION_METHOD_NONE = 0, 54 OUTPUT_PROTECTION_METHOD_HDCP = 1 << 0, 55 }; 56 57 // HDCP protection state. 58 enum HDCPState { 59 HDCP_STATE_UNDESIRED, 60 HDCP_STATE_DESIRED, 61 HDCP_STATE_ENABLED 62 }; 63 64 // This class interacts directly with the underlying Xrandr API to manipulate 65 // CTRCs and Outputs. 66 class CHROMEOS_EXPORT OutputConfigurator 67 : public base::MessageLoop::Dispatcher, 68 public base::MessagePumpObserver { 69 public: 70 typedef uint64_t OutputProtectionClientId; 71 static const OutputProtectionClientId kInvalidClientId = 0; 72 73 struct ModeInfo { 74 ModeInfo(); 75 ModeInfo(int width, int height, bool interlaced, float refresh_rate); 76 77 int width; 78 int height; 79 bool interlaced; 80 float refresh_rate; 81 }; 82 83 typedef std::map<RRMode, ModeInfo> ModeInfoMap; 84 85 struct CoordinateTransformation { 86 // Initialized to the identity transformation. 87 CoordinateTransformation(); 88 89 float x_scale; 90 float x_offset; 91 float y_scale; 92 float y_offset; 93 }; 94 95 // Information about an output's current state. 96 struct OutputSnapshot { 97 OutputSnapshot(); 98 ~OutputSnapshot(); 99 100 RROutput output; 101 102 // CRTC that should be used for this output. Not necessarily the CRTC 103 // that XRandR reports is currently being used. 104 RRCrtc crtc; 105 106 // Mode currently being used by the output. 107 RRMode current_mode; 108 109 // "Best" mode supported by the output. 110 RRMode native_mode; 111 112 // Mode used when displaying the same desktop on multiple outputs. 113 RRMode mirror_mode; 114 115 // User-selected mode for the output. 116 RRMode selected_mode; 117 118 // Output's origin on the framebuffer. 119 int x; 120 int y; 121 122 // Output's physical dimensions. 123 uint64 width_mm; 124 uint64 height_mm; 125 126 // TODO(kcwu): Remove this. Check type == OUTPUT_TYPE_INTERNAL instead. 127 bool is_internal; 128 bool is_aspect_preserving_scaling; 129 130 // The type of output. 131 OutputType type; 132 133 // Map from mode IDs to details about the corresponding modes. 134 ModeInfoMap mode_infos; 135 136 // XInput device ID or 0 if this output isn't a touchscreen. 137 int touch_device_id; 138 139 CoordinateTransformation transform; 140 141 // Display id for this output. 142 int64 display_id; 143 144 bool has_display_id; 145 146 // This output's index in the array returned by XRandR. Stable even as 147 // outputs are connected or disconnected. 148 int index; 149 }; 150 151 class Observer { 152 public: ~Observer()153 virtual ~Observer() {} 154 155 // Called after the display mode has been changed. |output| contains the 156 // just-applied configuration. Note that the X server is no longer grabbed 157 // when this method is called, so the actual configuration could've changed 158 // already. OnDisplayModeChanged(const std::vector<OutputSnapshot> & outputs)159 virtual void OnDisplayModeChanged( 160 const std::vector<OutputSnapshot>& outputs) {} 161 162 // Called after a display mode change attempt failed. |failed_new_state| is 163 // the new state which the system failed to enter. OnDisplayModeChangeFailed(OutputState failed_new_state)164 virtual void OnDisplayModeChangeFailed(OutputState failed_new_state) {} 165 }; 166 167 // Interface for classes that make decisions about which output state 168 // should be used. 169 class StateController { 170 public: ~StateController()171 virtual ~StateController() {} 172 173 // Called when displays are detected. 174 virtual OutputState GetStateForDisplayIds( 175 const std::vector<int64>& display_ids) const = 0; 176 177 // Queries the resolution (|width|x|height|) in pixels 178 // to select output mode for the given display id. 179 virtual bool GetResolutionForDisplayId(int64 display_id, 180 int* width, 181 int* height) const = 0; 182 }; 183 184 // Interface for classes that implement software based mirroring. 185 class SoftwareMirroringController { 186 public: ~SoftwareMirroringController()187 virtual ~SoftwareMirroringController() {} 188 189 // Called when the hardware mirroring failed. 190 virtual void SetSoftwareMirroring(bool enabled) = 0; 191 }; 192 193 // Interface for classes that perform actions on behalf of OutputController. 194 class Delegate { 195 public: ~Delegate()196 virtual ~Delegate() {} 197 198 // Initializes the XRandR extension, saving the base event ID to 199 // |event_base|. 200 virtual void InitXRandRExtension(int* event_base) = 0; 201 202 // Tells XRandR to update its configuration in response to |event|, an 203 // RRScreenChangeNotify event. 204 virtual void UpdateXRandRConfiguration(const base::NativeEvent& event) = 0; 205 206 // Grabs the X server and refreshes XRandR-related resources. While 207 // the server is grabbed, other clients are blocked. Must be balanced 208 // by a call to UngrabServer(). 209 virtual void GrabServer() = 0; 210 211 // Ungrabs the server and frees XRandR-related resources. 212 virtual void UngrabServer() = 0; 213 214 // Flushes all pending requests and waits for replies. 215 virtual void SyncWithServer() = 0; 216 217 // Sets the window's background color to |color_argb|. 218 virtual void SetBackgroundColor(uint32 color_argb) = 0; 219 220 // Enables DPMS and forces it to the "on" state. 221 virtual void ForceDPMSOn() = 0; 222 223 // Returns information about the current outputs. This method may block for 224 // 60 milliseconds or more. The returned outputs are not fully initialized; 225 // the rest of the work happens in 226 // OutputConfigurator::UpdateCachedOutputs(). 227 virtual std::vector<OutputSnapshot> GetOutputs() = 0; 228 229 // Adds |mode| to |output|. 230 virtual void AddOutputMode(RROutput output, RRMode mode) = 0; 231 232 // Calls XRRSetCrtcConfig() with the given options but some of our default 233 // output count and rotation arguments. Returns true on success. 234 virtual bool ConfigureCrtc(RRCrtc crtc, 235 RRMode mode, 236 RROutput output, 237 int x, 238 int y) = 0; 239 240 // Called to set the frame buffer (underlying XRR "screen") size. Has 241 // a side-effect of disabling all CRTCs. 242 virtual void CreateFrameBuffer( 243 int width, 244 int height, 245 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) = 0; 246 247 // Configures XInput's Coordinate Transformation Matrix property. 248 // |touch_device_id| the ID of the touchscreen device to configure. 249 // |ctm| contains the desired transformation parameters. The offsets 250 // in it should be normalized so that 1 corresponds to the X or Y axis 251 // size for the corresponding offset. 252 virtual void ConfigureCTM(int touch_device_id, 253 const CoordinateTransformation& ctm) = 0; 254 255 // Sends a D-Bus message to the power manager telling it that the 256 // machine is or is not projecting. 257 virtual void SendProjectingStateToPowerManager(bool projecting) = 0; 258 259 // Gets HDCP state of output. 260 virtual bool GetHDCPState(RROutput id, HDCPState* state) = 0; 261 262 // Sets HDCP state of output. 263 virtual bool SetHDCPState(RROutput id, HDCPState state) = 0; 264 }; 265 266 // Helper class used by tests. 267 class TestApi { 268 public: TestApi(OutputConfigurator * configurator,int xrandr_event_base)269 TestApi(OutputConfigurator* configurator, int xrandr_event_base) 270 : configurator_(configurator), 271 xrandr_event_base_(xrandr_event_base) {} ~TestApi()272 ~TestApi() {} 273 cached_outputs()274 const std::vector<OutputSnapshot>& cached_outputs() const { 275 return configurator_->cached_outputs_; 276 } 277 278 // Dispatches an RRScreenChangeNotify event to |configurator_|. 279 void SendScreenChangeEvent(); 280 281 // Dispatches an RRNotify_OutputChange event to |configurator_|. 282 void SendOutputChangeEvent(RROutput output, 283 RRCrtc crtc, 284 RRMode mode, 285 bool connected); 286 287 // If |configure_timer_| is started, stops the timer, runs 288 // ConfigureOutputs(), and returns true; returns false otherwise. 289 bool TriggerConfigureTimeout(); 290 291 private: 292 OutputConfigurator* configurator_; // not owned 293 294 int xrandr_event_base_; 295 296 DISALLOW_COPY_AND_ASSIGN(TestApi); 297 }; 298 299 // Flags that can be passed to SetDisplayPower(). 300 static const int kSetDisplayPowerNoFlags = 0; 301 // Configure displays even if the passed-in state matches |power_state_|. 302 static const int kSetDisplayPowerForceProbe = 1 << 0; 303 // Do not change the state if multiple displays are connected or if the 304 // only connected display is external. 305 static const int kSetDisplayPowerOnlyIfSingleInternalDisplay = 1 << 1; 306 307 // Gap between screens so cursor at bottom of active display doesn't 308 // partially appear on top of inactive display. Higher numbers guard 309 // against larger cursors, but also waste more memory. 310 // For simplicity, this is hard-coded to avoid the complexity of always 311 // determining the DPI of the screen and rationalizing which screen we 312 // need to use for the DPI calculation. 313 // See crbug.com/130188 for initial discussion. 314 static const int kVerticalGap = 60; 315 316 // Returns a pointer to the ModeInfo struct in |output| corresponding to 317 // |mode|, or NULL if the struct isn't present. 318 static const ModeInfo* GetModeInfo(const OutputSnapshot& output, 319 RRMode mode); 320 321 // Returns the mode within |output| that matches the given size with highest 322 // refresh rate. Returns None if no matching output was found. 323 static RRMode FindOutputModeMatchingSize(const OutputSnapshot& output, 324 int width, 325 int height); 326 327 OutputConfigurator(); 328 virtual ~OutputConfigurator(); 329 output_state()330 OutputState output_state() const { return output_state_; } power_state()331 DisplayPowerState power_state() const { return power_state_; } 332 set_state_controller(StateController * controller)333 void set_state_controller(StateController* controller) { 334 state_controller_ = controller; 335 } set_mirroring_controller(SoftwareMirroringController * controller)336 void set_mirroring_controller(SoftwareMirroringController* controller) { 337 mirroring_controller_ = controller; 338 } 339 340 // Replaces |delegate_| with |delegate| and sets |configure_display_| to 341 // true. Should be called before Init(). 342 void SetDelegateForTesting(scoped_ptr<Delegate> delegate); 343 344 // Sets the initial value of |power_state_|. Must be called before Start(). 345 void SetInitialDisplayPower(DisplayPowerState power_state); 346 347 // Initialization, must be called right after constructor. 348 // |is_panel_fitting_enabled| indicates hardware panel fitting support. 349 void Init(bool is_panel_fitting_enabled); 350 351 // Does initial configuration of displays during startup. 352 // If |background_color_argb| is non zero and there are multiple displays, 353 // OutputConfigurator sets the background color of X's RootWindow to this 354 // color. 355 void Start(uint32 background_color_argb); 356 357 // Stop handling display configuration events/requests. 358 void Stop(); 359 360 // Called when powerd notifies us that some set of displays should be turned 361 // on or off. This requires enabling or disabling the CRTC associated with 362 // the display(s) in question so that the low power state is engaged. 363 // |flags| contains bitwise-or-ed kSetDisplayPower* values. 364 bool SetDisplayPower(DisplayPowerState power_state, int flags); 365 366 // Force switching the display mode to |new_state|. Returns false if 367 // switching failed (possibly because |new_state| is invalid for the 368 // current set of connected outputs). 369 bool SetDisplayMode(OutputState new_state); 370 371 // Called when an RRNotify event is received. The implementation is 372 // interested in the cases of RRNotify events which correspond to output 373 // add/remove events. Note that Output add/remove events are sent in response 374 // to our own reconfiguration operations so spurious events are common. 375 // Spurious events will have no effect. 376 virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE; 377 378 // Overridden from base::MessagePumpObserver: 379 virtual base::EventStatus WillProcessEvent( 380 const base::NativeEvent& event) OVERRIDE; 381 virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE; 382 383 void AddObserver(Observer* observer); 384 void RemoveObserver(Observer* observer); 385 386 // Sets all the displays into pre-suspend mode; usually this means 387 // configure them for their resume state. This allows faster resume on 388 // machines where display configuration is slow. 389 void SuspendDisplays(); 390 391 // Reprobes displays to handle changes made while the system was 392 // suspended. 393 void ResumeDisplays(); 394 GetMirroredDisplayAreaRatioMap()395 const std::map<int, float>& GetMirroredDisplayAreaRatioMap() { 396 return mirrored_display_area_ratio_map_; 397 } 398 399 // Configure outputs with |kConfigureDelayMs| delay, 400 // so that time-consuming ConfigureOutputs() won't be called multiple times. 401 void ScheduleConfigureOutputs(); 402 403 // Registers a client for output protection and requests a client id. Returns 404 // 0 if requesting failed. 405 OutputProtectionClientId RegisterOutputProtectionClient(); 406 407 // Unregisters the client. 408 void UnregisterOutputProtectionClient(OutputProtectionClientId client_id); 409 410 // Queries link status and protection status. 411 // |link_mask| is the type of connected output links, which is a bitmask of 412 // OutputType values. |protection_mask| is the desired protection methods, 413 // which is a bitmask of the OutputProtectionMethod values. 414 // Returns true on success. 415 bool QueryOutputProtectionStatus( 416 OutputProtectionClientId client_id, 417 int64 display_id, 418 uint32_t* link_mask, 419 uint32_t* protection_mask); 420 421 // Requests the desired protection methods. 422 // |protection_mask| is the desired protection methods, which is a bitmask 423 // of the OutputProtectionMethod values. 424 // Returns true when the protection request has been made. 425 bool EnableOutputProtection( 426 OutputProtectionClientId client_id, 427 int64 display_id, 428 uint32_t desired_protection_mask); 429 430 private: 431 // Mapping a display_id to a protection request bitmask. 432 typedef std::map<int64, uint32_t> DisplayProtections; 433 // Mapping a client to its protection request. 434 typedef std::map<OutputProtectionClientId, 435 DisplayProtections> ProtectionRequests; 436 437 // Updates |cached_outputs_| to contain currently-connected outputs. Calls 438 // |delegate_->GetOutputs()| and then does additional work, like finding the 439 // mirror mode and setting user-preferred modes. Note that the server must be 440 // grabbed via |delegate_->GrabServer()| first. 441 void UpdateCachedOutputs(); 442 443 // Helper method for UpdateCachedOutputs() that initializes the passed-in 444 // outputs' |mirror_mode| fields by looking for a mode in |internal_output| 445 // and |external_output| having the same resolution. Returns false if a shared 446 // mode wasn't found or created. 447 // 448 // |try_panel_fitting| allows creating a panel-fitting mode for 449 // |internal_output| instead of only searching for a matching mode (note that 450 // it may lead to a crash if |internal_info| is not capable of panel fitting). 451 // 452 // |preserve_aspect| limits the search/creation only to the modes having the 453 // native aspect ratio of |external_output|. 454 bool FindMirrorMode(OutputSnapshot* internal_output, 455 OutputSnapshot* external_output, 456 bool try_panel_fitting, 457 bool preserve_aspect); 458 459 // Configures outputs. 460 void ConfigureOutputs(); 461 462 // Notifies observers about an attempted state change. 463 void NotifyObservers(bool success, OutputState attempted_state); 464 465 // Switches to the state specified in |output_state| and |power_state|. 466 // If the hardware mirroring failed and |mirroring_controller_| is set, 467 // it switches to |STATE_DUAL_EXTENDED| and calls |SetSoftwareMirroring()| 468 // to enable software based mirroring. 469 // On success, updates |output_state_|, |power_state_|, and |cached_outputs_| 470 // and returns true. 471 bool EnterStateOrFallBackToSoftwareMirroring( 472 OutputState output_state, 473 DisplayPowerState power_state); 474 475 // Switches to the state specified in |output_state| and |power_state|. 476 // On success, updates |output_state_|, |power_state_|, and 477 // |cached_outputs_| and returns true. 478 bool EnterState(OutputState output_state, DisplayPowerState power_state); 479 480 // Returns the output state that should be used with |cached_outputs_| while 481 // in |power_state|. 482 OutputState ChooseOutputState(DisplayPowerState power_state) const; 483 484 // Computes the relevant transformation for mirror mode. 485 // |output| is the output on which mirror mode is being applied. 486 // Returns the transformation or identity if computations fail. 487 CoordinateTransformation GetMirrorModeCTM( 488 const OutputConfigurator::OutputSnapshot& output); 489 490 // Computes the relevant transformation for extended mode. 491 // |output| is the output on which extended mode is being applied. 492 // |width| and |height| are the width and height of the combined framebuffer. 493 // Returns the transformation or identity if computations fail. 494 CoordinateTransformation GetExtendedModeCTM( 495 const OutputConfigurator::OutputSnapshot& output, 496 int framebuffer_width, 497 int frame_buffer_height); 498 499 // Returns the ratio between mirrored mode area and native mode area: 500 // (mirror_mode_width * mirrow_mode_height) / (native_width * native_height) 501 float GetMirroredDisplayAreaRatio( 502 const OutputConfigurator::OutputSnapshot& output); 503 504 // Applies output protections according to requests. 505 bool ApplyProtections(const DisplayProtections& requests); 506 507 StateController* state_controller_; 508 SoftwareMirroringController* mirroring_controller_; 509 scoped_ptr<Delegate> delegate_; 510 511 // Used to enable modes which rely on panel fitting. 512 bool is_panel_fitting_enabled_; 513 514 // Key of the map is the touch display's id, and the value of the map is the 515 // touch display's area ratio in mirror mode defined as : 516 // mirror_mode_area / native_mode_area. 517 // This is used for scaling touch event's radius when the touch display is in 518 // mirror mode : 519 // new_touch_radius = sqrt(area_ratio) * old_touch_radius 520 std::map<int, float> mirrored_display_area_ratio_map_; 521 522 // This is detected by the constructor to determine whether or not we should 523 // be enabled. If we aren't running on ChromeOS, we can't assume that the 524 // Xrandr X11 extension is supported. 525 // If this flag is set to false, any attempts to change the output 526 // configuration to immediately fail without changing the state. 527 bool configure_display_; 528 529 // The base of the event numbers used to represent XRandr events used in 530 // decoding events regarding output add/remove. 531 int xrandr_event_base_; 532 533 // The current display state. 534 OutputState output_state_; 535 536 // The current power state. 537 DisplayPowerState power_state_; 538 539 // Most-recently-used output configuration. Note that the actual 540 // configuration changes asynchronously. 541 std::vector<OutputSnapshot> cached_outputs_; 542 543 ObserverList<Observer> observers_; 544 545 // The timer to delay configuring outputs. See also the comments in 546 // Dispatch(). 547 scoped_ptr<base::OneShotTimer<OutputConfigurator> > configure_timer_; 548 549 // Id for next output protection client. 550 OutputProtectionClientId next_output_protection_client_id_; 551 552 // Output protection requests of each client. 553 ProtectionRequests client_protection_requests_; 554 555 DISALLOW_COPY_AND_ASSIGN(OutputConfigurator); 556 }; 557 558 typedef std::vector<OutputConfigurator::OutputSnapshot> OutputSnapshotList; 559 560 } // namespace chromeos 561 562 #endif // CHROMEOS_DISPLAY_OUTPUT_CONFIGURATOR_H_ 563