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