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.
5 #ifndef CHROMEOS_DISPLAY_OUTPUT_CONFIGURATOR_H_
6 #define CHROMEOS_DISPLAY_OUTPUT_CONFIGURATOR_H_
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"
21 // Forward declarations for Xlib and Xrandr.
22 // This is so unused X definitions don't pollute the namespace.
23 typedef unsigned long XID
;
30 // Used to describe the state of a multi-display configuration.
39 // Video output types.
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,
51 // Content protection methods applied on video output.
52 enum OutputProtectionMethod
{
53 OUTPUT_PROTECTION_METHOD_NONE
= 0,
54 OUTPUT_PROTECTION_METHOD_HDCP
= 1 << 0,
57 // HDCP protection state.
64 // This class interacts directly with the underlying Xrandr API to manipulate
66 class CHROMEOS_EXPORT OutputConfigurator
67 : public base::MessageLoop::Dispatcher
,
68 public base::MessagePumpObserver
{
70 typedef uint64_t OutputProtectionClientId
;
71 static const OutputProtectionClientId kInvalidClientId
= 0;
75 ModeInfo(int width
, int height
, bool interlaced
, float refresh_rate
);
83 typedef std::map
<RRMode
, ModeInfo
> ModeInfoMap
;
85 struct CoordinateTransformation
{
86 // Initialized to the identity transformation.
87 CoordinateTransformation();
95 // Information about an output's current state.
96 struct OutputSnapshot
{
102 // CRTC that should be used for this output. Not necessarily the CRTC
103 // that XRandR reports is currently being used.
106 // Mode currently being used by the output.
109 // "Best" mode supported by the output.
112 // Mode used when displaying the same desktop on multiple outputs.
115 // User-selected mode for the output.
116 RRMode selected_mode
;
118 // Output's origin on the framebuffer.
122 // Output's physical dimensions.
126 // TODO(kcwu): Remove this. Check type == OUTPUT_TYPE_INTERNAL instead.
128 bool is_aspect_preserving_scaling
;
130 // The type of output.
133 // Map from mode IDs to details about the corresponding modes.
134 ModeInfoMap mode_infos
;
136 // XInput device ID or 0 if this output isn't a touchscreen.
139 CoordinateTransformation transform
;
141 // Display id for this output.
146 // This output's index in the array returned by XRandR. Stable even as
147 // outputs are connected or disconnected.
153 virtual ~Observer() {}
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
159 virtual void OnDisplayModeChanged(
160 const std::vector
<OutputSnapshot
>& outputs
) {}
162 // Called after a display mode change attempt failed. |failed_new_state| is
163 // the new state which the system failed to enter.
164 virtual void OnDisplayModeChangeFailed(OutputState failed_new_state
) {}
167 // Interface for classes that make decisions about which output state
169 class StateController
{
171 virtual ~StateController() {}
173 // Called when displays are detected.
174 virtual OutputState
GetStateForDisplayIds(
175 const std::vector
<int64
>& display_ids
) const = 0;
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
,
181 int* height
) const = 0;
184 // Interface for classes that implement software based mirroring.
185 class SoftwareMirroringController
{
187 virtual ~SoftwareMirroringController() {}
189 // Called when the hardware mirroring failed.
190 virtual void SetSoftwareMirroring(bool enabled
) = 0;
193 // Interface for classes that perform actions on behalf of OutputController.
196 virtual ~Delegate() {}
198 // Initializes the XRandR extension, saving the base event ID to
200 virtual void InitXRandRExtension(int* event_base
) = 0;
202 // Tells XRandR to update its configuration in response to |event|, an
203 // RRScreenChangeNotify event.
204 virtual void UpdateXRandRConfiguration(const base::NativeEvent
& event
) = 0;
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;
211 // Ungrabs the server and frees XRandR-related resources.
212 virtual void UngrabServer() = 0;
214 // Flushes all pending requests and waits for replies.
215 virtual void SyncWithServer() = 0;
217 // Sets the window's background color to |color_argb|.
218 virtual void SetBackgroundColor(uint32 color_argb
) = 0;
220 // Enables DPMS and forces it to the "on" state.
221 virtual void ForceDPMSOn() = 0;
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;
229 // Adds |mode| to |output|.
230 virtual void AddOutputMode(RROutput output
, RRMode mode
) = 0;
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
,
240 // Called to set the frame buffer (underlying XRR "screen") size. Has
241 // a side-effect of disabling all CRTCs.
242 virtual void CreateFrameBuffer(
245 const std::vector
<OutputConfigurator::OutputSnapshot
>& outputs
) = 0;
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;
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;
259 // Gets HDCP state of output.
260 virtual bool GetHDCPState(RROutput id
, HDCPState
* state
) = 0;
262 // Sets HDCP state of output.
263 virtual bool SetHDCPState(RROutput id
, HDCPState state
) = 0;
266 // Helper class used by tests.
269 TestApi(OutputConfigurator
* configurator
, int xrandr_event_base
)
270 : configurator_(configurator
),
271 xrandr_event_base_(xrandr_event_base
) {}
274 const std::vector
<OutputSnapshot
>& cached_outputs() const {
275 return configurator_
->cached_outputs_
;
278 // Dispatches an RRScreenChangeNotify event to |configurator_|.
279 void SendScreenChangeEvent();
281 // Dispatches an RRNotify_OutputChange event to |configurator_|.
282 void SendOutputChangeEvent(RROutput output
,
287 // If |configure_timer_| is started, stops the timer, runs
288 // ConfigureOutputs(), and returns true; returns false otherwise.
289 bool TriggerConfigureTimeout();
292 OutputConfigurator
* configurator_
; // not owned
294 int xrandr_event_base_
;
296 DISALLOW_COPY_AND_ASSIGN(TestApi
);
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;
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;
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
,
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
,
327 OutputConfigurator();
328 virtual ~OutputConfigurator();
330 OutputState
output_state() const { return output_state_
; }
331 DisplayPowerState
power_state() const { return power_state_
; }
333 void set_state_controller(StateController
* controller
) {
334 state_controller_
= controller
;
336 void set_mirroring_controller(SoftwareMirroringController
* controller
) {
337 mirroring_controller_
= controller
;
340 // Replaces |delegate_| with |delegate| and sets |configure_display_| to
341 // true. Should be called before Init().
342 void SetDelegateForTesting(scoped_ptr
<Delegate
> delegate
);
344 // Sets the initial value of |power_state_|. Must be called before Start().
345 void SetInitialDisplayPower(DisplayPowerState power_state
);
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
);
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
355 void Start(uint32 background_color_argb
);
357 // Stop handling display configuration events/requests.
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
);
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
);
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
;
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
;
383 void AddObserver(Observer
* observer
);
384 void RemoveObserver(Observer
* observer
);
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();
391 // Reprobes displays to handle changes made while the system was
393 void ResumeDisplays();
395 const std::map
<int, float>& GetMirroredDisplayAreaRatioMap() {
396 return mirrored_display_area_ratio_map_
;
399 // Configure outputs with |kConfigureDelayMs| delay,
400 // so that time-consuming ConfigureOutputs() won't be called multiple times.
401 void ScheduleConfigureOutputs();
403 // Registers a client for output protection and requests a client id. Returns
404 // 0 if requesting failed.
405 OutputProtectionClientId
RegisterOutputProtectionClient();
407 // Unregisters the client.
408 void UnregisterOutputProtectionClient(OutputProtectionClientId client_id
);
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
,
419 uint32_t* protection_mask
);
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
,
428 uint32_t desired_protection_mask
);
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
;
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();
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.
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).
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
);
459 // Configures outputs.
460 void ConfigureOutputs();
462 // Notifies observers about an attempted state change.
463 void NotifyObservers(bool success
, OutputState attempted_state
);
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_|
471 bool EnterStateOrFallBackToSoftwareMirroring(
472 OutputState output_state
,
473 DisplayPowerState power_state
);
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
);
480 // Returns the output state that should be used with |cached_outputs_| while
482 OutputState
ChooseOutputState(DisplayPowerState power_state
) const;
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
);
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
);
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
);
504 // Applies output protections according to requests.
505 bool ApplyProtections(const DisplayProtections
& requests
);
507 StateController
* state_controller_
;
508 SoftwareMirroringController
* mirroring_controller_
;
509 scoped_ptr
<Delegate
> delegate_
;
511 // Used to enable modes which rely on panel fitting.
512 bool is_panel_fitting_enabled_
;
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
519 // new_touch_radius = sqrt(area_ratio) * old_touch_radius
520 std::map
<int, float> mirrored_display_area_ratio_map_
;
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_
;
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_
;
533 // The current display state.
534 OutputState output_state_
;
536 // The current power state.
537 DisplayPowerState power_state_
;
539 // Most-recently-used output configuration. Note that the actual
540 // configuration changes asynchronously.
541 std::vector
<OutputSnapshot
> cached_outputs_
;
543 ObserverList
<Observer
> observers_
;
545 // The timer to delay configuring outputs. See also the comments in
547 scoped_ptr
<base::OneShotTimer
<OutputConfigurator
> > configure_timer_
;
549 // Id for next output protection client.
550 OutputProtectionClientId next_output_protection_client_id_
;
552 // Output protection requests of each client.
553 ProtectionRequests client_protection_requests_
;
555 DISALLOW_COPY_AND_ASSIGN(OutputConfigurator
);
558 typedef std::vector
<OutputConfigurator::OutputSnapshot
> OutputSnapshotList
;
560 } // namespace chromeos
562 #endif // CHROMEOS_DISPLAY_OUTPUT_CONFIGURATOR_H_