Home | History | Annotate | Download | only in chromeos
      1 // Copyright 2014 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 UI_DISPLAY_CHROMEOS_DISPLAY_CONFIGURATOR_H_
      6 #define UI_DISPLAY_CHROMEOS_DISPLAY_CONFIGURATOR_H_
      7 
      8 #include <stdint.h>
      9 
     10 #include <map>
     11 #include <string>
     12 #include <vector>
     13 
     14 #include "base/event_types.h"
     15 #include "base/memory/scoped_ptr.h"
     16 #include "base/observer_list.h"
     17 #include "base/timer/timer.h"
     18 #include "third_party/cros_system_api/dbus/service_constants.h"
     19 #include "ui/display/display_export.h"
     20 #include "ui/display/types/display_constants.h"
     21 #include "ui/display/types/native_display_observer.h"
     22 #include "ui/gfx/geometry/size.h"
     23 
     24 namespace gfx {
     25 class Point;
     26 class Size;
     27 }
     28 
     29 namespace ui {
     30 class DisplayMode;
     31 class DisplaySnapshot;
     32 class NativeDisplayDelegate;
     33 
     34 // This class interacts directly with the system display configurator.
     35 class DISPLAY_EXPORT DisplayConfigurator : public NativeDisplayObserver {
     36  public:
     37   typedef uint64_t ContentProtectionClientId;
     38   static const ContentProtectionClientId kInvalidClientId = 0;
     39 
     40   struct DisplayState {
     41     DisplayState();
     42 
     43     DisplaySnapshot* display;  // Not owned.
     44 
     45     // User-selected mode for the display.
     46     const DisplayMode* selected_mode;
     47 
     48     // Mode used when displaying the same desktop on multiple displays.
     49     const DisplayMode* mirror_mode;
     50   };
     51 
     52   typedef std::vector<DisplayState> DisplayStateList;
     53 
     54   class Observer {
     55    public:
     56     virtual ~Observer() {}
     57 
     58     // Called after the display mode has been changed. |display| contains the
     59     // just-applied configuration. Note that the X server is no longer grabbed
     60     // when this method is called, so the actual configuration could've changed
     61     // already.
     62     virtual void OnDisplayModeChanged(
     63         const std::vector<DisplayState>& displays) {}
     64 
     65     // Called after a display mode change attempt failed. |failed_new_state| is
     66     // the new state which the system failed to enter.
     67     virtual void OnDisplayModeChangeFailed(
     68         MultipleDisplayState failed_new_state) {}
     69   };
     70 
     71   // Interface for classes that make decisions about which display state
     72   // should be used.
     73   class StateController {
     74    public:
     75     virtual ~StateController() {}
     76 
     77     // Called when displays are detected.
     78     virtual MultipleDisplayState GetStateForDisplayIds(
     79         const std::vector<int64_t>& display_ids) const = 0;
     80 
     81     // Queries the resolution (|size|) in pixels to select display mode for the
     82     // given display id.
     83     virtual bool GetResolutionForDisplayId(int64_t display_id,
     84                                            gfx::Size* size) const = 0;
     85   };
     86 
     87   // Interface for classes that implement software based mirroring.
     88   class SoftwareMirroringController {
     89    public:
     90     virtual ~SoftwareMirroringController() {}
     91 
     92     // Called when the hardware mirroring failed.
     93     virtual void SetSoftwareMirroring(bool enabled) = 0;
     94     virtual bool SoftwareMirroringEnabled() const = 0;
     95   };
     96 
     97   // Helper class used by tests.
     98   class TestApi {
     99    public:
    100     TestApi(DisplayConfigurator* configurator) : configurator_(configurator) {}
    101     ~TestApi() {}
    102 
    103     // If |configure_timer_| is started, stops the timer, runs
    104     // ConfigureDisplays(), and returns true; returns false otherwise.
    105     bool TriggerConfigureTimeout() WARN_UNUSED_RESULT;
    106 
    107    private:
    108     DisplayConfigurator* configurator_;  // not owned
    109 
    110     DISALLOW_COPY_AND_ASSIGN(TestApi);
    111   };
    112 
    113   // Flags that can be passed to SetDisplayPower().
    114   static const int kSetDisplayPowerNoFlags;
    115   // Configure displays even if the passed-in state matches |power_state_|.
    116   static const int kSetDisplayPowerForceProbe;
    117   // Do not change the state if multiple displays are connected or if the
    118   // only connected display is external.
    119   static const int kSetDisplayPowerOnlyIfSingleInternalDisplay;
    120 
    121   // Gap between screens so cursor at bottom of active display doesn't
    122   // partially appear on top of inactive display. Higher numbers guard
    123   // against larger cursors, but also waste more memory.
    124   // For simplicity, this is hard-coded to avoid the complexity of always
    125   // determining the DPI of the screen and rationalizing which screen we
    126   // need to use for the DPI calculation.
    127   // See crbug.com/130188 for initial discussion.
    128   static const int kVerticalGap = 60;
    129 
    130   // Returns the mode within |display| that matches the given size with highest
    131   // refresh rate. Returns None if no matching display was found.
    132   static const DisplayMode* FindDisplayModeMatchingSize(
    133       const DisplaySnapshot& display,
    134       const gfx::Size& size);
    135 
    136   DisplayConfigurator();
    137   virtual ~DisplayConfigurator();
    138 
    139   MultipleDisplayState display_state() const { return display_state_; }
    140   chromeos::DisplayPowerState requested_power_state() const {
    141     return requested_power_state_;
    142   }
    143   const gfx::Size framebuffer_size() const { return framebuffer_size_; }
    144   const std::vector<DisplayState>& cached_displays() const {
    145     return cached_displays_;
    146   }
    147 
    148   void set_state_controller(StateController* controller) {
    149     state_controller_ = controller;
    150   }
    151   void set_mirroring_controller(SoftwareMirroringController* controller) {
    152     mirroring_controller_ = controller;
    153   }
    154 
    155   // Replaces |native_display_delegate_| with the delegate passed in and sets
    156   // |configure_display_| to true. Should be called before Init().
    157   void SetDelegateForTesting(
    158       scoped_ptr<NativeDisplayDelegate> display_delegate);
    159 
    160   // Sets the initial value of |power_state_|.  Must be called before Start().
    161   void SetInitialDisplayPower(chromeos::DisplayPowerState power_state);
    162 
    163   // Initialization, must be called right after constructor.
    164   // |is_panel_fitting_enabled| indicates hardware panel fitting support.
    165   void Init(bool is_panel_fitting_enabled);
    166 
    167   // Does initial configuration of displays during startup.
    168   // If |background_color_argb| is non zero and there are multiple displays,
    169   // DisplayConfigurator sets the background color of X's RootWindow to this
    170   // color.
    171   void ForceInitialConfigure(uint32_t background_color_argb);
    172 
    173   // Stop handling display configuration events/requests.
    174   void PrepareForExit();
    175 
    176   // Called when powerd notifies us that some set of displays should be turned
    177   // on or off.  This requires enabling or disabling the CRTC associated with
    178   // the display(s) in question so that the low power state is engaged.
    179   // |flags| contains bitwise-or-ed kSetDisplayPower* values. Returns true if
    180   // the system successfully enters (or was already in) |power_state|.
    181   bool SetDisplayPower(chromeos::DisplayPowerState power_state, int flags);
    182 
    183   // Force switching the display mode to |new_state|. Returns false if
    184   // switching failed (possibly because |new_state| is invalid for the
    185   // current set of connected displays).
    186   bool SetDisplayMode(MultipleDisplayState new_state);
    187 
    188   // NativeDisplayDelegate::Observer overrides:
    189   virtual void OnConfigurationChanged() OVERRIDE;
    190 
    191   void AddObserver(Observer* observer);
    192   void RemoveObserver(Observer* observer);
    193 
    194   // Sets all the displays into pre-suspend mode; usually this means
    195   // configure them for their resume state. This allows faster resume on
    196   // machines where display configuration is slow.
    197   void SuspendDisplays();
    198 
    199   // Reprobes displays to handle changes made while the system was
    200   // suspended.
    201   void ResumeDisplays();
    202 
    203   // Registers a client for display protection and requests a client id. Returns
    204   // 0 if requesting failed.
    205   ContentProtectionClientId RegisterContentProtectionClient();
    206 
    207   // Unregisters the client.
    208   void UnregisterContentProtectionClient(ContentProtectionClientId client_id);
    209 
    210   // Queries link status and protection status.
    211   // |link_mask| is the type of connected display links, which is a bitmask of
    212   // DisplayConnectionType values. |protection_mask| is the desired protection
    213   // methods, which is a bitmask of the ContentProtectionMethod values.
    214   // Returns true on success.
    215   bool QueryContentProtectionStatus(ContentProtectionClientId client_id,
    216                                     int64_t display_id,
    217                                     uint32_t* link_mask,
    218                                     uint32_t* protection_mask);
    219 
    220   // Requests the desired protection methods.
    221   // |protection_mask| is the desired protection methods, which is a bitmask
    222   // of the ContentProtectionMethod values.
    223   // Returns true when the protection request has been made.
    224   bool EnableContentProtection(ContentProtectionClientId client_id,
    225                                int64_t display_id,
    226                                uint32_t desired_protection_mask);
    227 
    228   // Checks the available color profiles for |display_id| and fills the result
    229   // into |profiles|.
    230   std::vector<ui::ColorCalibrationProfile> GetAvailableColorCalibrationProfiles(
    231       int64_t display_id);
    232 
    233   // Updates the color calibration to |new_profile|.
    234   bool SetColorCalibrationProfile(int64_t display_id,
    235                                   ui::ColorCalibrationProfile new_profile);
    236 
    237  private:
    238   // Mapping a display_id to a protection request bitmask.
    239   typedef std::map<int64_t, uint32_t> ContentProtections;
    240   // Mapping a client to its protection request.
    241   typedef std::map<ContentProtectionClientId, ContentProtections>
    242       ProtectionRequests;
    243 
    244   // Performs platform specific delegate initialization.
    245   scoped_ptr<NativeDisplayDelegate> CreatePlatformNativeDisplayDelegate();
    246 
    247   // Updates |cached_displays_| to contain currently-connected displays. Calls
    248   // |delegate_->GetDisplays()| and then does additional work, like finding the
    249   // mirror mode and setting user-preferred modes. Note that the server must be
    250   // grabbed via |delegate_->GrabServer()| first.
    251   void UpdateCachedDisplays();
    252 
    253   // Helper method for UpdateCachedDisplays() that initializes the passed-in
    254   // displays' |mirror_mode| fields by looking for a mode in |internal_display|
    255   // and |external_display| having the same resolution. Returns false if a
    256   // shared
    257   // mode wasn't found or created.
    258   //
    259   // |try_panel_fitting| allows creating a panel-fitting mode for
    260   // |internal_display| instead of only searching for a matching mode (note that
    261   // it may lead to a crash if |internal_info| is not capable of panel fitting).
    262   //
    263   // |preserve_aspect| limits the search/creation only to the modes having the
    264   // native aspect ratio of |external_display|.
    265   bool FindMirrorMode(DisplayState* internal_display,
    266                       DisplayState* external_display,
    267                       bool try_panel_fitting,
    268                       bool preserve_aspect);
    269 
    270   // Configures displays.
    271   void ConfigureDisplays();
    272 
    273   // Notifies observers about an attempted state change.
    274   void NotifyObservers(bool success, MultipleDisplayState attempted_state);
    275 
    276   // Switches to the state specified in |display_state| and |power_state|.
    277   // If the hardware mirroring failed and |mirroring_controller_| is set,
    278   // it switches to |STATE_DUAL_EXTENDED| and calls |SetSoftwareMirroring()|
    279   // to enable software based mirroring.
    280   // On success, updates |display_state_|, |power_state_|, and
    281   // |cached_displays_| and returns true.
    282   bool EnterStateOrFallBackToSoftwareMirroring(
    283       MultipleDisplayState display_state,
    284       chromeos::DisplayPowerState power_state);
    285 
    286   // Switches to the state specified in |display_state| and |power_state|.
    287   // On success, updates |display_state_|, |power_state_|, and
    288   // |cached_displays_| and returns true.
    289   bool EnterState(MultipleDisplayState display_state,
    290                   chromeos::DisplayPowerState power_state);
    291 
    292   // Returns the display state that should be used with |cached_displays_| while
    293   // in |power_state|.
    294   MultipleDisplayState ChooseDisplayState(
    295       chromeos::DisplayPowerState power_state) const;
    296 
    297   // Returns the ratio between mirrored mode area and native mode area:
    298   // (mirror_mode_width * mirrow_mode_height) / (native_width * native_height)
    299   float GetMirroredDisplayAreaRatio(const DisplayState& display);
    300 
    301   // Returns true if in either hardware or software mirroring mode.
    302   bool IsMirroring() const;
    303 
    304   // Applies display protections according to requests.
    305   bool ApplyProtections(const ContentProtections& requests);
    306 
    307   StateController* state_controller_;
    308   SoftwareMirroringController* mirroring_controller_;
    309   scoped_ptr<NativeDisplayDelegate> native_display_delegate_;
    310 
    311   // Used to enable modes which rely on panel fitting.
    312   bool is_panel_fitting_enabled_;
    313 
    314   // This is detected by the constructor to determine whether or not we should
    315   // be enabled.  If we aren't running on ChromeOS, we can't assume that the
    316   // Xrandr X11 extension is supported.
    317   // If this flag is set to false, any attempts to change the display
    318   // configuration to immediately fail without changing the state.
    319   bool configure_display_;
    320 
    321   // The current display state.
    322   MultipleDisplayState display_state_;
    323 
    324   gfx::Size framebuffer_size_;
    325 
    326   // The last-requested and current power state. These may differ if
    327   // configuration fails: SetDisplayMode() needs the last-requested state while
    328   // SetDisplayPower() needs the current state.
    329   chromeos::DisplayPowerState requested_power_state_;
    330   chromeos::DisplayPowerState current_power_state_;
    331 
    332   // Most-recently-used display configuration. Note that the actual
    333   // configuration changes asynchronously.
    334   DisplayStateList cached_displays_;
    335 
    336   ObserverList<Observer> observers_;
    337 
    338   // The timer to delay configuring displays. This is used to aggregate multiple
    339   // display configuration events when they are reported in short time spans.
    340   // See comment for NativeDisplayEventDispatcherX11 for more details.
    341   base::OneShotTimer<DisplayConfigurator> configure_timer_;
    342 
    343   // Id for next display protection client.
    344   ContentProtectionClientId next_display_protection_client_id_;
    345 
    346   // Display protection requests of each client.
    347   ProtectionRequests client_protection_requests_;
    348 
    349   DISALLOW_COPY_AND_ASSIGN(DisplayConfigurator);
    350 };
    351 
    352 }  // namespace ui
    353 
    354 #endif  // UI_DISPLAY_CHROMEOS_DISPLAY_CONFIGURATOR_H_
    355