blob: 9fa5b41b987fccc7c31d10713fcacbf0944b6d8b [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 <memory>
#include <queue>
#include <string>
#include <vector>
#include "base/event_types.h"
#include "base/macros.h"
#include "base/memory/scoped_vector.h"
#include "base/memory/weak_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/chromeos/display_snapshot_virtual.h"
#include "ui/display/chromeos/query_content_protection_task.h"
#include "ui/display/display_export.h"
#include "ui/display/types/display_constants.h"
#include "ui/display/types/native_display_observer.h"
#include "ui/display/util/display_util.h"
#include "ui/gfx/geometry/size.h"
namespace gfx {
class Point;
class Size;
namespace ui {
struct DisplayConfigureRequest;
struct GammaRampRGBEntry;
class DisplayLayoutManager;
class DisplayMode;
class DisplaySnapshot;
class NativeDisplayDelegate;
class UpdateDisplayConfigurationTask;
// This class interacts directly with the system display configurator.
class DISPLAY_EXPORT DisplayConfigurator : public NativeDisplayObserver {
typedef uint64_t ContentProtectionClientId;
static const ContentProtectionClientId kInvalidClientId = 0;
typedef base::Callback<void(bool /* success */)> ConfigurationCallback;
typedef base::Callback<void(bool /* success */)> EnableProtectionCallback;
struct QueryProtectionResponse {
// True if the query succeeded, false otherwise.
bool success = false;
// The type of connected display links, which is a bitmask of
// DisplayConnectionType values.
uint32_t link_mask = 0;
// The desired protection methods, which is a bitmask of the
// ContentProtectionMethod values.
uint32_t protection_mask = 0;
typedef base::Callback<void(const QueryProtectionResponse&)>
typedef base::Callback<void(bool /* success */)> DisplayControlCallback;
typedef std::vector<DisplaySnapshot*> DisplayStateList;
// Mapping a display_id to a protection request bitmask.
typedef std::map<int64_t, uint32_t> ContentProtections;
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 DisplayStateList& displays) {}
// Called after a display mode change attempt failed. |displays| contains
// displays that are detected when failed.
// |failed_new_state| is the new state which the system failed to enter.
virtual void OnDisplayModeChangeFailed(
const DisplayStateList& displays,
MultipleDisplayState failed_new_state) {}
// Called after the power state has been changed. |power_state| contains
// the just-applied power state.
virtual void OnPowerStateChanged(
chromeos::DisplayPowerState power_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 ui::DisplayConfigurator::DisplayStateList& outputs) 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;
virtual bool SoftwareMirroringEnabled() const = 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() WARN_UNUSED_RESULT;
DisplayConfigurator* configurator_; // not owned
// Flags that can be passed to SetDisplayPower().
static const int kSetDisplayPowerNoFlags;
// Configure displays even if the passed-in state matches |power_state_|.
static const int kSetDisplayPowerForceProbe;
// Do not change the state if multiple displays are connected or if the
// only connected display is external.
static const int kSetDisplayPowerOnlyIfSingleInternalDisplay;
// 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);
~DisplayConfigurator() override;
MultipleDisplayState display_state() const { return current_display_state_; }
chromeos::DisplayPowerState requested_power_state() const {
return requested_power_state_;
const gfx::Size framebuffer_size() const { return framebuffer_size_; }
const std::vector<DisplaySnapshot*>& cached_displays() const {
return cached_displays_;
// Called when an external process no longer needs to control the display
// and Chrome can take control.
void TakeControl(const DisplayControlCallback& callback);
// Called when an external process needs to control the display and thus
// Chrome should relinquish it.
void RelinquishControl(const DisplayControlCallback& callback);
void set_state_controller(StateController* controller) {
state_controller_ = controller;
void set_mirroring_controller(SoftwareMirroringController* controller) {
mirroring_controller_ = controller;
// Replaces |native_display_delegate_| with the delegate passed in and sets
// |configure_display_| to true. Should be called before Init().
void SetDelegateForTesting(
std::unique_ptr<NativeDisplayDelegate> display_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(std::unique_ptr<NativeDisplayDelegate> delegate,
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. After the
// configuration finishes |callback| is called with the status of the
// operation.
void SetDisplayPower(chromeos::DisplayPowerState power_state,
int flags,
const ConfigurationCallback& callback);
// 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).
void SetDisplayMode(MultipleDisplayState new_state);
// NativeDisplayDelegate::Observer overrides:
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. On completion of the display
// configuration |callback| is executed.
void SuspendDisplays(const ConfigurationCallback& callback);
// Reprobes displays to handle changes made while the system was
// suspended.
void ResumeDisplays();
// 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. |callback| is used to respond
// to the query.
void QueryContentProtectionStatus(ContentProtectionClientId client_id,
int64_t display_id,
const QueryProtectionCallback& callback);
// 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.
void EnableContentProtection(ContentProtectionClientId client_id,
int64_t display_id,
uint32_t protection_mask,
const EnableProtectionCallback& callback);
// 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);
// Enables/disables virtual display.
int64_t AddVirtualDisplay(const gfx::Size& display_size);
bool RemoveVirtualDisplay(int64_t display_id);
// Returns true if there is at least one display on.
bool IsDisplayOn() const;
void set_configure_display(bool configure_display) {
configure_display_ = configure_display;
// Sets the gamma, degamma and correction matrix for |display_id| to the
// values in |degamma_lut|, |gamma_lut| and |correction_matrix|.
bool SetColorCorrection(int64_t display_id,
const std::vector<GammaRampRGBEntry>& degamma_lut,
const std::vector<GammaRampRGBEntry>& gamma_lut,
const std::vector<float>& correction_matrix);
class DisplayLayoutManagerImpl;
// Mapping a client to its protection request.
typedef std::map<ContentProtectionClientId, ContentProtections>
// Updates |pending_*| members and applies the passed-in state. |callback| is
// invoked (perhaps synchronously) on completion.
void SetDisplayPowerInternal(chromeos::DisplayPowerState power_state,
int flags,
const ConfigurationCallback& callback);
// Configures displays. Invoked by |configure_timer_|.
void ConfigureDisplays();
// Notifies observers about an attempted state change.
void NotifyDisplayStateObservers(bool success,
MultipleDisplayState attempted_state);
// Notifies observers about a power state change.
void NotifyPowerStateObservers();
// Returns the display state that should be used with |cached_displays_| while
// in |power_state|.
MultipleDisplayState ChooseDisplayState(
chromeos::DisplayPowerState power_state) const;
// Applies display protections according to requests.
bool ApplyProtections(const ContentProtections& requests);
// If |configuration_task_| isn't initialized, initializes it and starts the
// configuration task.
void RunPendingConfiguration();
// Callback for |configuration_taks_|. When the configuration process finishes
// this is called with the result (|success|) and the updated display state.
void OnConfigured(bool success,
const std::vector<DisplaySnapshot*>& displays,
const gfx::Size& framebuffer_size,
MultipleDisplayState new_display_state,
chromeos::DisplayPowerState new_power_state);
// Helps in identifying if a configuration task needs to be scheduled.
// Return true if any of the |requested_*| parameters have been updated. False
// otherwise.
bool ShouldRunConfigurationTask() const;
// Helper functions which will call the callbacks in
// |in_progress_configuration_callbacks_| and
// |queued_configuration_callbacks_| and clear the lists after. |success| is
// the configuration status used when calling the callbacks.
void CallAndClearInProgressCallbacks(bool success);
void CallAndClearQueuedCallbacks(bool success);
// Content protection callbacks called by the tasks when they finish. These
// are responsible for destroying the task, replying to the caller that made
// the task and starting the a new content protection task if one is queued.
void OnContentProtectionQueried(
ContentProtectionClientId client_id,
int64_t display_id,
QueryContentProtectionTask::Response response);
void OnContentProtectionEnabled(ContentProtectionClientId client_id,
int64_t display_id,
uint32_t desired_method_mask,
bool success);
void OnContentProtectionClientUnregistered(bool success);
// Callbacks used to signal when the native platform has released/taken
// display control.
void OnDisplayControlTaken(const DisplayControlCallback& callback,
bool success);
void OnDisplayControlRelinquished(const DisplayControlCallback& callback,
bool success);
StateController* state_controller_;
SoftwareMirroringController* mirroring_controller_;
std::unique_ptr<NativeDisplayDelegate> native_display_delegate_;
// Used to enable modes which rely on panel fitting.
bool is_panel_fitting_enabled_;
// This is detected by the constructor to determine whether or not we should
// be enabled. If we aren't running on Chrome OS, we can't assume that the
// Xrandr X11 extension or the Ozone underlying display hotplug system are
// 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_;
// Current configuration state.
MultipleDisplayState current_display_state_;
chromeos::DisplayPowerState current_power_state_;
// Pending requests. These values are used when triggering the next display
// configuration.
// Stores the user requested state or INVALID if nothing was requested.
MultipleDisplayState requested_display_state_;
// Stores the requested power state.
chromeos::DisplayPowerState requested_power_state_;
// The power state used by RunPendingConfiguration(). May be
// |requested_power_state_| or DISPLAY_POWER_ALL_OFF for suspend.
chromeos::DisplayPowerState pending_power_state_;
// True if |pending_power_state_| has been changed.
bool has_pending_power_state_;
// Bitwise-or value of the |kSetDisplayPower*| flags defined above.
int pending_power_flags_;
// List of callbacks from callers waiting for the display configuration to
// start/finish. Note these callbacks belong to the pending request, not a
// request currently active.
std::vector<ConfigurationCallback> queued_configuration_callbacks_;
// List of callbacks belonging to the currently running display configuration
// task.
std::vector<ConfigurationCallback> in_progress_configuration_callbacks_;
std::queue<base::Closure> content_protection_tasks_;
std::queue<QueryProtectionCallback> query_protection_callbacks_;
std::queue<EnableProtectionCallback> enable_protection_callbacks_;
// True if the caller wants to force the display configuration process.
bool force_configure_;
// Most-recently-used display configuration. Note that the actual
// configuration changes asynchronously.
DisplayStateList cached_displays_;
// Most-recently-used framebuffer size.
gfx::Size framebuffer_size_;
base::ObserverList<Observer> observers_;
// The timer to delay configuring displays. This is used to aggregate multiple
// display configuration events when they are reported in short time spans.
// See comment for NativeDisplayEventDispatcherX11 for more details.
base::OneShotTimer configure_timer_;
// Id for next display protection client.
ContentProtectionClientId next_display_protection_client_id_;
// Display protection requests of each client.
ProtectionRequests client_protection_requests_;
// Display controlled by an external entity.
bool display_externally_controlled_;
// True if a TakeControl or RelinquishControl has been called but the response
// hasn't arrived yet.
bool display_control_changing_;
// Whether the displays are currently suspended.
bool displays_suspended_;
// Virtual display control.
ScopedVector<DisplaySnapshot> virtual_display_snapshots_;
// Last used virtual display id.
uint8_t last_virtual_display_id_ = 0;
std::unique_ptr<DisplayLayoutManager> layout_manager_;
std::unique_ptr<UpdateDisplayConfigurationTask> configuration_task_;
// This must be the last variable.
base::WeakPtrFactory<DisplayConfigurator> weak_ptr_factory_;
} // namespace ui