blob: 028a902ef48535579157169f3f0e7c3a6fc77746 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdint.h>
#include <map>
#include <string>
#include <vector>
#include "base/event_types.h"
#include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
#include "base/timer/timer.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
#include "ui/display/display_export.h"
#include "ui/display/types/chromeos/native_display_observer.h"
#include "ui/display/types/display_constants.h"
namespace gfx {
class Point;
class Size;
namespace ui {
class DisplayMode;
class DisplaySnapshot;
class NativeDisplayDelegate;
// This class interacts directly with the system display configurator.
class DISPLAY_EXPORT DisplayConfigurator : public NativeDisplayObserver {
typedef uint64_t ContentProtectionClientId;
static const ContentProtectionClientId kInvalidClientId = 0;
struct CoordinateTransformation {
// Initialized to the identity transformation.
float x_scale;
float x_offset;
float y_scale;
float y_offset;
struct DisplayState {
DisplaySnapshot* display; // Not owned.
// XInput device ID or 0 if this display isn't a touchscreen.
int touch_device_id;
CoordinateTransformation transform;
// User-selected mode for the display.
const DisplayMode* selected_mode;
// Mode used when displaying the same desktop on multiple displays.
const DisplayMode* mirror_mode;
typedef std::vector<DisplayState> DisplayStateList;
class Observer {
virtual ~Observer() {}
// Called after the display mode has been changed. |display| contains the
// just-applied configuration. Note that the X server is no longer grabbed
// when this method is called, so the actual configuration could've changed
// already.
virtual void OnDisplayModeChanged(
const std::vector<DisplayState>& displays) {}
// Called after a display mode change attempt failed. |failed_new_state| is
// the new state which the system failed to enter.
virtual void OnDisplayModeChangeFailed(
MultipleDisplayState failed_new_state) {}
// Interface for classes that make decisions about which display state
// should be used.
class StateController {
virtual ~StateController() {}
// Called when displays are detected.
virtual MultipleDisplayState GetStateForDisplayIds(
const std::vector<int64_t>& display_ids) const = 0;
// Queries the resolution (|size|) in pixels to select display mode for the
// given display id.
virtual bool GetResolutionForDisplayId(int64_t display_id,
gfx::Size* size) const = 0;
// Interface for classes that implement software based mirroring.
class SoftwareMirroringController {
virtual ~SoftwareMirroringController() {}
// Called when the hardware mirroring failed.
virtual void SetSoftwareMirroring(bool enabled) = 0;
class TouchscreenDelegate {
virtual ~TouchscreenDelegate() {}
// Searches for touchscreens among input devices,
// and tries to match them up to screens in |displays|.
// |displays| is an array of detected screens.
// If a touchscreen with same resolution as a display's native mode
// is detected, its id will be stored in this display.
virtual void AssociateTouchscreens(std::vector<DisplayState>* displays) = 0;
// Configures XInput's Coordinate Transformation Matrix property.
// |touch_device_id| the ID of the touchscreen device to configure.
// |ctm| contains the desired transformation parameters. The offsets
// in it should be normalized so that 1 corresponds to the X or Y axis
// size for the corresponding offset.
virtual void ConfigureCTM(int touch_device_id,
const CoordinateTransformation& ctm) = 0;
// Helper class used by tests.
class TestApi {
TestApi(DisplayConfigurator* configurator) : configurator_(configurator) {}
~TestApi() {}
// If |configure_timer_| is started, stops the timer, runs
// ConfigureDisplays(), and returns true; returns false otherwise.
bool TriggerConfigureTimeout();
DisplayConfigurator* configurator_; // not owned
// Flags that can be passed to SetDisplayPower().
static const int kSetDisplayPowerNoFlags = 0;
// Configure displays even if the passed-in state matches |power_state_|.
static const int kSetDisplayPowerForceProbe = 1 << 0;
// Do not change the state if multiple displays are connected or if the
// only connected display is external.
static const int kSetDisplayPowerOnlyIfSingleInternalDisplay = 1 << 1;
// Gap between screens so cursor at bottom of active display doesn't
// partially appear on top of inactive display. Higher numbers guard
// against larger cursors, but also waste more memory.
// For simplicity, this is hard-coded to avoid the complexity of always
// determining the DPI of the screen and rationalizing which screen we
// need to use for the DPI calculation.
// See for initial discussion.
static const int kVerticalGap = 60;
// Returns the mode within |display| that matches the given size with highest
// refresh rate. Returns None if no matching display was found.
static const DisplayMode* FindDisplayModeMatchingSize(
const DisplaySnapshot& display,
const gfx::Size& size);
virtual ~DisplayConfigurator();
MultipleDisplayState display_state() const { return display_state_; }
chromeos::DisplayPowerState power_state() const { return power_state_; }
const std::vector<DisplayState>& cached_displays() const {
return cached_displays_;
void set_state_controller(StateController* controller) {
state_controller_ = controller;
void set_mirroring_controller(SoftwareMirroringController* controller) {
mirroring_controller_ = controller;
// Replaces |native_display_delegate_| and |touchscreen_delegate_| with the 2
// delegates passed in and sets |configure_display_| to true. Should be called
// before Init().
void SetDelegatesForTesting(
scoped_ptr<NativeDisplayDelegate> display_delegate,
scoped_ptr<TouchscreenDelegate> touchscreen_delegate);
// Sets the initial value of |power_state_|. Must be called before Start().
void SetInitialDisplayPower(chromeos::DisplayPowerState power_state);
// Initialization, must be called right after constructor.
// |is_panel_fitting_enabled| indicates hardware panel fitting support.
void Init(bool is_panel_fitting_enabled);
// Does initial configuration of displays during startup.
// If |background_color_argb| is non zero and there are multiple displays,
// DisplayConfigurator sets the background color of X's RootWindow to this
// color.
void ForceInitialConfigure(uint32_t background_color_argb);
// Stop handling display configuration events/requests.
void PrepareForExit();
// Called when powerd notifies us that some set of displays should be turned
// on or off. This requires enabling or disabling the CRTC associated with
// the display(s) in question so that the low power state is engaged.
// |flags| contains bitwise-or-ed kSetDisplayPower* values.
bool SetDisplayPower(chromeos::DisplayPowerState power_state, int flags);
// Force switching the display mode to |new_state|. Returns false if
// switching failed (possibly because |new_state| is invalid for the
// current set of connected displays).
bool SetDisplayMode(MultipleDisplayState new_state);
// NativeDisplayDelegate::Observer overrides:
virtual void OnConfigurationChanged() OVERRIDE;
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
// Sets all the displays into pre-suspend mode; usually this means
// configure them for their resume state. This allows faster resume on
// machines where display configuration is slow.
void SuspendDisplays();
// Reprobes displays to handle changes made while the system was
// suspended.
void ResumeDisplays();
const std::map<int, float>& GetMirroredDisplayAreaRatioMap() {
return mirrored_display_area_ratio_map_;
// Registers a client for display protection and requests a client id. Returns
// 0 if requesting failed.
ContentProtectionClientId RegisterContentProtectionClient();
// Unregisters the client.
void UnregisterContentProtectionClient(ContentProtectionClientId client_id);
// Queries link status and protection status.
// |link_mask| is the type of connected display links, which is a bitmask of
// DisplayConnectionType values. |protection_mask| is the desired protection
// methods, which is a bitmask of the ContentProtectionMethod values.
// Returns true on success.
bool QueryContentProtectionStatus(ContentProtectionClientId client_id,
int64_t display_id,
uint32_t* link_mask,
uint32_t* protection_mask);
// Requests the desired protection methods.
// |protection_mask| is the desired protection methods, which is a bitmask
// of the ContentProtectionMethod values.
// Returns true when the protection request has been made.
bool EnableContentProtection(ContentProtectionClientId client_id,
int64_t display_id,
uint32_t desired_protection_mask);
// Checks the available color profiles for |display_id| and fills the result
// into |profiles|.
std::vector<ui::ColorCalibrationProfile> GetAvailableColorCalibrationProfiles(
int64_t display_id);
// Updates the color calibration to |new_profile|.
bool SetColorCalibrationProfile(int64_t display_id,
ui::ColorCalibrationProfile new_profile);
// Mapping a display_id to a protection request bitmask.
typedef std::map<int64_t, uint32_t> ContentProtections;
// Mapping a client to its protection request.
typedef std::map<ContentProtectionClientId, ContentProtections>
// If |native_display_delegate_| and |touchscreen_delegate_| are not set, then
// set them to the passed in values.
void InitializeDelegates(
scoped_ptr<NativeDisplayDelegate> display_delegate,
scoped_ptr<TouchscreenDelegate> touchscreen_delegate);
// Performs platform specific delegate initialization.
void PlatformInitialize();
// Updates |cached_displays_| to contain currently-connected displays. Calls
// |delegate_->GetDisplays()| and then does additional work, like finding the
// mirror mode and setting user-preferred modes. Note that the server must be
// grabbed via |delegate_->GrabServer()| first.
void UpdateCachedDisplays();
// Helper method for UpdateCachedDisplays() that initializes the passed-in
// displays' |mirror_mode| fields by looking for a mode in |internal_display|
// and |external_display| having the same resolution. Returns false if a
// shared
// mode wasn't found or created.
// |try_panel_fitting| allows creating a panel-fitting mode for
// |internal_display| instead of only searching for a matching mode (note that
// it may lead to a crash if |internal_info| is not capable of panel fitting).
// |preserve_aspect| limits the search/creation only to the modes having the
// native aspect ratio of |external_display|.
bool FindMirrorMode(DisplayState* internal_display,
DisplayState* external_display,
bool try_panel_fitting,
bool preserve_aspect);
// Configures displays.
void ConfigureDisplays();
// Notifies observers about an attempted state change.
void NotifyObservers(bool success, MultipleDisplayState attempted_state);
// Switches to the state specified in |display_state| and |power_state|.
// If the hardware mirroring failed and |mirroring_controller_| is set,
// it switches to |STATE_DUAL_EXTENDED| and calls |SetSoftwareMirroring()|
// to enable software based mirroring.
// On success, updates |display_state_|, |power_state_|, and
// |cached_displays_| and returns true.
bool EnterStateOrFallBackToSoftwareMirroring(
MultipleDisplayState display_state,
chromeos::DisplayPowerState power_state);
// Switches to the state specified in |display_state| and |power_state|.
// On success, updates |display_state_|, |power_state_|, and
// |cached_displays_| and returns true.
bool EnterState(MultipleDisplayState display_state,
chromeos::DisplayPowerState power_state);
// Returns the display state that should be used with |cached_displays_| while
// in |power_state|.
MultipleDisplayState ChooseDisplayState(
chromeos::DisplayPowerState power_state) const;
// Computes the relevant transformation for mirror mode.
// |display| is the display on which mirror mode is being applied.
// Returns the transformation or identity if computations fail.
CoordinateTransformation GetMirrorModeCTM(const DisplayState& display);
// Computes the relevant transformation for extended mode. |display| is the
// display on which extended mode is being applied. |new_origin| is the
// position of the display on the framebuffer. |framebuffer_size| is the
// size of the combined framebuffer.
// Returns the transformation or identity if computations fail.
CoordinateTransformation GetExtendedModeCTM(
const DisplayState& display,
const gfx::Point& new_origin,
const gfx::Size& framebuffer_size);
// Returns the ratio between mirrored mode area and native mode area:
// (mirror_mode_width * mirrow_mode_height) / (native_width * native_height)
float GetMirroredDisplayAreaRatio(const DisplayState& display);
// Applies display protections according to requests.
bool ApplyProtections(const ContentProtections& requests);
StateController* state_controller_;
SoftwareMirroringController* mirroring_controller_;
scoped_ptr<NativeDisplayDelegate> native_display_delegate_;
scoped_ptr<TouchscreenDelegate> touchscreen_delegate_;
// Used to enable modes which rely on panel fitting.
bool is_panel_fitting_enabled_;
// Key of the map is the touch display's id, and the value of the map is the
// touch display's area ratio in mirror mode defined as :
// mirror_mode_area / native_mode_area.
// This is used for scaling touch event's radius when the touch display is in
// mirror mode :
// new_touch_radius = sqrt(area_ratio) * old_touch_radius
std::map<int, float> mirrored_display_area_ratio_map_;
// This is detected by the constructor to determine whether or not we should
// be enabled. If we aren't running on ChromeOS, we can't assume that the
// Xrandr X11 extension is supported.
// If this flag is set to false, any attempts to change the display
// configuration to immediately fail without changing the state.
bool configure_display_;
// The current display state.
MultipleDisplayState display_state_;
// The current power state.
chromeos::DisplayPowerState power_state_;
// Most-recently-used display configuration. Note that the actual
// configuration changes asynchronously.
DisplayStateList cached_displays_;
ObserverList<Observer> observers_;
// The timer to delay configuring displays. See also the comments in
// Dispatch().
scoped_ptr<base::OneShotTimer<DisplayConfigurator> > configure_timer_;
// Id for next display protection client.
ContentProtectionClientId next_display_protection_client_id_;
// Display protection requests of each client.
ProtectionRequests client_protection_requests_;
} // namespace ui