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/message_loop/message_pump_dispatcher.h"
17 #include "base/observer_list.h"
18 #include "base/timer/timer.h"
19 #include "chromeos/chromeos_export.h"
20 #include "third_party/cros_system_api/dbus/service_constants.h"
22 // Forward declarations for Xlib and Xrandr.
23 // This is so unused X definitions don't pollute the namespace.
24 typedef unsigned long XID;
31 // Used to describe the state of a multi-display configuration.
40 // Video output types.
43 OUTPUT_TYPE_UNKNOWN = 1 << 0,
44 OUTPUT_TYPE_INTERNAL = 1 << 1,
45 OUTPUT_TYPE_VGA = 1 << 2,
46 OUTPUT_TYPE_HDMI = 1 << 3,
47 OUTPUT_TYPE_DVI = 1 << 4,
48 OUTPUT_TYPE_DISPLAYPORT = 1 << 5,
49 OUTPUT_TYPE_NETWORK = 1 << 6,
52 // Content protection methods applied on video output.
53 enum OutputProtectionMethod {
54 OUTPUT_PROTECTION_METHOD_NONE = 0,
55 OUTPUT_PROTECTION_METHOD_HDCP = 1 << 0,
58 // HDCP protection state.
65 // This class interacts directly with the underlying Xrandr API to manipulate
67 class CHROMEOS_EXPORT OutputConfigurator
68 : public base::MessagePumpDispatcher,
69 public base::MessagePumpObserver {
71 typedef uint64_t OutputProtectionClientId;
72 static const OutputProtectionClientId kInvalidClientId = 0;
76 ModeInfo(int width, int height, bool interlaced, float refresh_rate);
84 typedef std::map<RRMode, ModeInfo> ModeInfoMap;
86 struct CoordinateTransformation {
87 // Initialized to the identity transformation.
88 CoordinateTransformation();
96 // Information about an output's current state.
97 struct OutputSnapshot {
103 // CRTC that should be used for this output. Not necessarily the CRTC
104 // that XRandR reports is currently being used.
107 // Mode currently being used by the output.
110 // "Best" mode supported by the output.
113 // Mode used when displaying the same desktop on multiple outputs.
116 // User-selected mode for the output.
117 RRMode selected_mode;
119 // Output's origin on the framebuffer.
123 // Output's physical dimensions.
127 bool is_aspect_preserving_scaling;
129 // The type of output.
132 // Map from mode IDs to details about the corresponding modes.
133 ModeInfoMap mode_infos;
135 // XInput device ID or 0 if this output isn't a touchscreen.
138 CoordinateTransformation transform;
140 // Display id for this output.
145 // This output's index in the array returned by XRandR. Stable even as
146 // outputs are connected or disconnected.
152 virtual ~Observer() {}
154 // Called after the display mode has been changed. |output| contains the
155 // just-applied configuration. Note that the X server is no longer grabbed
156 // when this method is called, so the actual configuration could've changed
158 virtual void OnDisplayModeChanged(
159 const std::vector<OutputSnapshot>& outputs) {}
161 // Called after a display mode change attempt failed. |failed_new_state| is
162 // the new state which the system failed to enter.
163 virtual void OnDisplayModeChangeFailed(OutputState failed_new_state) {}
166 // Interface for classes that make decisions about which output state
168 class StateController {
170 virtual ~StateController() {}
172 // Called when displays are detected.
173 virtual OutputState GetStateForDisplayIds(
174 const std::vector<int64>& display_ids) const = 0;
176 // Queries the resolution (|width|x|height|) in pixels
177 // to select output mode for the given display id.
178 virtual bool GetResolutionForDisplayId(int64 display_id,
180 int* height) const = 0;
183 // Interface for classes that implement software based mirroring.
184 class SoftwareMirroringController {
186 virtual ~SoftwareMirroringController() {}
188 // Called when the hardware mirroring failed.
189 virtual void SetSoftwareMirroring(bool enabled) = 0;
192 // Interface for classes that perform actions on behalf of OutputController.
195 virtual ~Delegate() {}
197 // Initializes the XRandR extension, saving the base event ID to
199 virtual void InitXRandRExtension(int* event_base) = 0;
201 // Tells XRandR to update its configuration in response to |event|, an
202 // RRScreenChangeNotify event.
203 virtual void UpdateXRandRConfiguration(const base::NativeEvent& event) = 0;
205 // Grabs the X server and refreshes XRandR-related resources. While
206 // the server is grabbed, other clients are blocked. Must be balanced
207 // by a call to UngrabServer().
208 virtual void GrabServer() = 0;
210 // Ungrabs the server and frees XRandR-related resources.
211 virtual void UngrabServer() = 0;
213 // Flushes all pending requests and waits for replies.
214 virtual void SyncWithServer() = 0;
216 // Sets the window's background color to |color_argb|.
217 virtual void SetBackgroundColor(uint32 color_argb) = 0;
219 // Enables DPMS and forces it to the "on" state.
220 virtual void ForceDPMSOn() = 0;
222 // Returns information about the current outputs. This method may block for
223 // 60 milliseconds or more. The returned outputs are not fully initialized;
224 // the rest of the work happens in
225 // OutputConfigurator::UpdateCachedOutputs().
226 virtual std::vector<OutputSnapshot> GetOutputs() = 0;
228 // Adds |mode| to |output|.
229 virtual void AddOutputMode(RROutput output, RRMode mode) = 0;
231 // Calls XRRSetCrtcConfig() with the given options but some of our default
232 // output count and rotation arguments. Returns true on success.
233 virtual bool ConfigureCrtc(RRCrtc crtc,
239 // Called to set the frame buffer (underlying XRR "screen") size. Has
240 // a side-effect of disabling all CRTCs.
241 virtual void CreateFrameBuffer(
244 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) = 0;
246 // Configures XInput's Coordinate Transformation Matrix property.
247 // |touch_device_id| the ID of the touchscreen device to configure.
248 // |ctm| contains the desired transformation parameters. The offsets
249 // in it should be normalized so that 1 corresponds to the X or Y axis
250 // size for the corresponding offset.
251 virtual void ConfigureCTM(int touch_device_id,
252 const CoordinateTransformation& ctm) = 0;
254 // Sends a D-Bus message to the power manager telling it that the
255 // machine is or is not projecting.
256 virtual void SendProjectingStateToPowerManager(bool projecting) = 0;
258 // Gets HDCP state of output.
259 virtual bool GetHDCPState(RROutput id, HDCPState* state) = 0;
261 // Sets HDCP state of output.
262 virtual bool SetHDCPState(RROutput id, HDCPState state) = 0;
265 // Helper class used by tests.
268 TestApi(OutputConfigurator* configurator, int xrandr_event_base)
269 : configurator_(configurator),
270 xrandr_event_base_(xrandr_event_base) {}
273 const std::vector<OutputSnapshot>& cached_outputs() const {
274 return configurator_->cached_outputs_;
277 // Dispatches an RRScreenChangeNotify event to |configurator_|.
278 void SendScreenChangeEvent();
280 // Dispatches an RRNotify_OutputChange event to |configurator_|.
281 void SendOutputChangeEvent(RROutput output,
286 // If |configure_timer_| is started, stops the timer, runs
287 // ConfigureOutputs(), and returns true; returns false otherwise.
288 bool TriggerConfigureTimeout();
291 OutputConfigurator* configurator_; // not owned
293 int xrandr_event_base_;
295 DISALLOW_COPY_AND_ASSIGN(TestApi);
298 // Flags that can be passed to SetDisplayPower().
299 static const int kSetDisplayPowerNoFlags = 0;
300 // Configure displays even if the passed-in state matches |power_state_|.
301 static const int kSetDisplayPowerForceProbe = 1 << 0;
302 // Do not change the state if multiple displays are connected or if the
303 // only connected display is external.
304 static const int kSetDisplayPowerOnlyIfSingleInternalDisplay = 1 << 1;
306 // Gap between screens so cursor at bottom of active display doesn't
307 // partially appear on top of inactive display. Higher numbers guard
308 // against larger cursors, but also waste more memory.
309 // For simplicity, this is hard-coded to avoid the complexity of always
310 // determining the DPI of the screen and rationalizing which screen we
311 // need to use for the DPI calculation.
312 // See crbug.com/130188 for initial discussion.
313 static const int kVerticalGap = 60;
315 // Returns a pointer to the ModeInfo struct in |output| corresponding to
316 // |mode|, or NULL if the struct isn't present.
317 static const ModeInfo* GetModeInfo(const OutputSnapshot& output,
320 // Returns the mode within |output| that matches the given size with highest
321 // refresh rate. Returns None if no matching output was found.
322 static RRMode FindOutputModeMatchingSize(const OutputSnapshot& output,
326 OutputConfigurator();
327 virtual ~OutputConfigurator();
329 OutputState output_state() const { return output_state_; }
330 DisplayPowerState power_state() const { return power_state_; }
332 void set_state_controller(StateController* controller) {
333 state_controller_ = controller;
335 void set_mirroring_controller(SoftwareMirroringController* controller) {
336 mirroring_controller_ = controller;
339 // Replaces |delegate_| with |delegate| and sets |configure_display_| to
340 // true. Should be called before Init().
341 void SetDelegateForTesting(scoped_ptr<Delegate> delegate);
343 // Sets the initial value of |power_state_|. Must be called before Start().
344 void SetInitialDisplayPower(DisplayPowerState power_state);
346 // Initialization, must be called right after constructor.
347 // |is_panel_fitting_enabled| indicates hardware panel fitting support.
348 void Init(bool is_panel_fitting_enabled);
350 // Does initial configuration of displays during startup.
351 // If |background_color_argb| is non zero and there are multiple displays,
352 // OutputConfigurator sets the background color of X's RootWindow to this
354 void Start(uint32 background_color_argb);
356 // Stop handling display configuration events/requests.
359 // Called when powerd notifies us that some set of displays should be turned
360 // on or off. This requires enabling or disabling the CRTC associated with
361 // the display(s) in question so that the low power state is engaged.
362 // |flags| contains bitwise-or-ed kSetDisplayPower* values.
363 bool SetDisplayPower(DisplayPowerState power_state, int flags);
365 // Force switching the display mode to |new_state|. Returns false if
366 // switching failed (possibly because |new_state| is invalid for the
367 // current set of connected outputs).
368 bool SetDisplayMode(OutputState new_state);
370 // Called when an RRNotify event is received. The implementation is
371 // interested in the cases of RRNotify events which correspond to output
372 // add/remove events. Note that Output add/remove events are sent in response
373 // to our own reconfiguration operations so spurious events are common.
374 // Spurious events will have no effect.
375 virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
377 // Overridden from base::MessagePumpObserver:
378 virtual base::EventStatus WillProcessEvent(
379 const base::NativeEvent& event) OVERRIDE;
380 virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE;
382 // Called when a casting session is started or stopped.
383 void OnCastingSessionStartedOrStopped(bool started);
385 void AddObserver(Observer* observer);
386 void RemoveObserver(Observer* observer);
388 // Sets all the displays into pre-suspend mode; usually this means
389 // configure them for their resume state. This allows faster resume on
390 // machines where display configuration is slow.
391 void SuspendDisplays();
393 // Reprobes displays to handle changes made while the system was
395 void ResumeDisplays();
397 const std::map<int, float>& GetMirroredDisplayAreaRatioMap() {
398 return mirrored_display_area_ratio_map_;
401 // Configure outputs with |kConfigureDelayMs| delay,
402 // so that time-consuming ConfigureOutputs() won't be called multiple times.
403 void ScheduleConfigureOutputs();
405 // Registers a client for output protection and requests a client id. Returns
406 // 0 if requesting failed.
407 OutputProtectionClientId RegisterOutputProtectionClient();
409 // Unregisters the client.
410 void UnregisterOutputProtectionClient(OutputProtectionClientId client_id);
412 // Queries link status and protection status.
413 // |link_mask| is the type of connected output links, which is a bitmask of
414 // OutputType values. |protection_mask| is the desired protection methods,
415 // which is a bitmask of the OutputProtectionMethod values.
416 // Returns true on success.
417 bool QueryOutputProtectionStatus(
418 OutputProtectionClientId client_id,
421 uint32_t* protection_mask);
423 // Requests the desired protection methods.
424 // |protection_mask| is the desired protection methods, which is a bitmask
425 // of the OutputProtectionMethod values.
426 // Returns true when the protection request has been made.
427 bool EnableOutputProtection(
428 OutputProtectionClientId client_id,
430 uint32_t desired_protection_mask);
433 // Mapping a display_id to a protection request bitmask.
434 typedef std::map<int64, uint32_t> DisplayProtections;
435 // Mapping a client to its protection request.
436 typedef std::map<OutputProtectionClientId,
437 DisplayProtections> ProtectionRequests;
439 // Updates |cached_outputs_| to contain currently-connected outputs. Calls
440 // |delegate_->GetOutputs()| and then does additional work, like finding the
441 // mirror mode and setting user-preferred modes. Note that the server must be
442 // grabbed via |delegate_->GrabServer()| first.
443 void UpdateCachedOutputs();
445 // Helper method for UpdateCachedOutputs() that initializes the passed-in
446 // outputs' |mirror_mode| fields by looking for a mode in |internal_output|
447 // and |external_output| having the same resolution. Returns false if a shared
448 // mode wasn't found or created.
450 // |try_panel_fitting| allows creating a panel-fitting mode for
451 // |internal_output| instead of only searching for a matching mode (note that
452 // it may lead to a crash if |internal_info| is not capable of panel fitting).
454 // |preserve_aspect| limits the search/creation only to the modes having the
455 // native aspect ratio of |external_output|.
456 bool FindMirrorMode(OutputSnapshot* internal_output,
457 OutputSnapshot* external_output,
458 bool try_panel_fitting,
459 bool preserve_aspect);
461 // Configures outputs.
462 void ConfigureOutputs();
464 // Notifies observers about an attempted state change.
465 void NotifyObservers(bool success, OutputState attempted_state);
467 // Switches to the state specified in |output_state| and |power_state|.
468 // If the hardware mirroring failed and |mirroring_controller_| is set,
469 // it switches to |STATE_DUAL_EXTENDED| and calls |SetSoftwareMirroring()|
470 // to enable software based mirroring.
471 // On success, updates |output_state_|, |power_state_|, and |cached_outputs_|
473 bool EnterStateOrFallBackToSoftwareMirroring(
474 OutputState output_state,
475 DisplayPowerState power_state);
477 // Switches to the state specified in |output_state| and |power_state|.
478 // On success, updates |output_state_|, |power_state_|, and
479 // |cached_outputs_| and returns true.
480 bool EnterState(OutputState output_state, DisplayPowerState power_state);
482 // Returns the output state that should be used with |cached_outputs_| while
484 OutputState ChooseOutputState(DisplayPowerState power_state) const;
486 // Computes the relevant transformation for mirror mode.
487 // |output| is the output on which mirror mode is being applied.
488 // Returns the transformation or identity if computations fail.
489 CoordinateTransformation GetMirrorModeCTM(
490 const OutputConfigurator::OutputSnapshot& output);
492 // Computes the relevant transformation for extended mode.
493 // |output| is the output on which extended mode is being applied.
494 // |width| and |height| are the width and height of the combined framebuffer.
495 // Returns the transformation or identity if computations fail.
496 CoordinateTransformation GetExtendedModeCTM(
497 const OutputConfigurator::OutputSnapshot& output,
498 int framebuffer_width,
499 int frame_buffer_height);
501 // Returns the ratio between mirrored mode area and native mode area:
502 // (mirror_mode_width * mirrow_mode_height) / (native_width * native_height)
503 float GetMirroredDisplayAreaRatio(
504 const OutputConfigurator::OutputSnapshot& output);
506 // Applies output protections according to requests.
507 bool ApplyProtections(const DisplayProtections& requests);
509 // Sends the current projecting state to power manager.
510 void SendProjectingStateToPowerManager();
512 StateController* state_controller_;
513 SoftwareMirroringController* mirroring_controller_;
514 scoped_ptr<Delegate> delegate_;
516 // Used to enable modes which rely on panel fitting.
517 bool is_panel_fitting_enabled_;
519 // Key of the map is the touch display's id, and the value of the map is the
520 // touch display's area ratio in mirror mode defined as :
521 // mirror_mode_area / native_mode_area.
522 // This is used for scaling touch event's radius when the touch display is in
524 // new_touch_radius = sqrt(area_ratio) * old_touch_radius
525 std::map<int, float> mirrored_display_area_ratio_map_;
527 // This is detected by the constructor to determine whether or not we should
528 // be enabled. If we aren't running on ChromeOS, we can't assume that the
529 // Xrandr X11 extension is supported.
530 // If this flag is set to false, any attempts to change the output
531 // configuration to immediately fail without changing the state.
532 bool configure_display_;
534 // The base of the event numbers used to represent XRandr events used in
535 // decoding events regarding output add/remove.
536 int xrandr_event_base_;
538 // The current display state.
539 OutputState output_state_;
541 // The current power state.
542 DisplayPowerState power_state_;
544 // Most-recently-used output configuration. Note that the actual
545 // configuration changes asynchronously.
546 std::vector<OutputSnapshot> cached_outputs_;
548 ObserverList<Observer> observers_;
550 // The timer to delay configuring outputs. See also the comments in
552 scoped_ptr<base::OneShotTimer<OutputConfigurator> > configure_timer_;
554 // Id for next output protection client.
555 OutputProtectionClientId next_output_protection_client_id_;
557 // Output protection requests of each client.
558 ProtectionRequests client_protection_requests_;
560 // Number of outstanding casting sessions.
561 int casting_session_count_;
563 DISALLOW_COPY_AND_ASSIGN(OutputConfigurator);
566 typedef std::vector<OutputConfigurator::OutputSnapshot> OutputSnapshotList;
568 } // namespace chromeos
570 #endif // CHROMEOS_DISPLAY_OUTPUT_CONFIGURATOR_H_