Home | History | Annotate | Download | only in display
      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.
      4 
      5 #ifndef CHROMEOS_DISPLAY_OUTPUT_CONFIGURATOR_H_
      6 #define CHROMEOS_DISPLAY_OUTPUT_CONFIGURATOR_H_
      7 
      8 #include <map>
      9 #include <string>
     10 #include <vector>
     11 
     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/observer_list.h"
     17 #include "base/timer/timer.h"
     18 #include "chromeos/chromeos_export.h"
     19 #include "third_party/cros_system_api/dbus/service_constants.h"
     20 
     21 // Forward declarations for Xlib and Xrandr.
     22 // This is so unused X definitions don't pollute the namespace.
     23 typedef unsigned long XID;
     24 typedef XID RROutput;
     25 typedef XID RRCrtc;
     26 typedef XID RRMode;
     27 
     28 namespace chromeos {
     29 
     30 // Used to describe the state of a multi-display configuration.
     31 enum OutputState {
     32   STATE_INVALID,
     33   STATE_HEADLESS,
     34   STATE_SINGLE,
     35   STATE_DUAL_MIRROR,
     36   STATE_DUAL_EXTENDED,
     37 };
     38 
     39 // This class interacts directly with the underlying Xrandr API to manipulate
     40 // CTRCs and Outputs.
     41 class CHROMEOS_EXPORT OutputConfigurator
     42     : public base::MessageLoop::Dispatcher,
     43       public base::MessagePumpObserver {
     44  public:
     45   struct CoordinateTransformation {
     46     // Initialized to the identity transformation.
     47     CoordinateTransformation();
     48 
     49     float x_scale;
     50     float x_offset;
     51     float y_scale;
     52     float y_offset;
     53   };
     54 
     55   // Information about an output's current state.
     56   struct OutputSnapshot {
     57     OutputSnapshot();
     58 
     59     RROutput output;
     60 
     61     // CRTC that should be used for this output. Not necessarily the CRTC
     62     // that XRandR reports is currently being used.
     63     RRCrtc crtc;
     64 
     65     // Mode currently being used by the output.
     66     RRMode current_mode;
     67 
     68     // "Best" mode supported by the output.
     69     RRMode native_mode;
     70 
     71     // Mode used when displaying the same desktop on multiple outputs.
     72     RRMode mirror_mode;
     73 
     74     // User-selected mode for the output.
     75     RRMode selected_mode;
     76 
     77     // Output's origin on the framebuffer.
     78     int x;
     79     int y;
     80 
     81     bool is_internal;
     82     bool is_aspect_preserving_scaling;
     83 
     84     // XInput device ID or 0 if this output isn't a touchscreen.
     85     int touch_device_id;
     86 
     87     CoordinateTransformation transform;
     88 
     89     // Display id for this output.
     90     int64 display_id;
     91 
     92     bool has_display_id;
     93   };
     94 
     95   class Observer {
     96    public:
     97     virtual ~Observer() {}
     98 
     99     // Called when the change of the display mode finished.  It will usually
    100     // start the fading in the displays.
    101     virtual void OnDisplayModeChanged() {}
    102 
    103     // Called when the change of the display mode is issued but failed.
    104     // |failed_new_state| is the new state which the system failed to enter.
    105     virtual void OnDisplayModeChangeFailed(OutputState failed_new_state) {}
    106   };
    107 
    108   // Interface for classes that make decisions about which output state
    109   // should be used.
    110   class StateController {
    111    public:
    112     virtual ~StateController() {}
    113 
    114     // Called when displays are detected.
    115     virtual OutputState GetStateForDisplayIds(
    116         const std::vector<int64>& display_ids) const = 0;
    117 
    118     // Queries the resolution (|width|x|height|) in pixels
    119     // to select output mode for the given display id.
    120     virtual bool GetResolutionForDisplayId(int64 display_id,
    121                                            int* width,
    122                                            int* height) const = 0;
    123   };
    124 
    125   // Interface for classes that implement software based mirroring.
    126   class SoftwareMirroringController {
    127    public:
    128     virtual ~SoftwareMirroringController() {}
    129 
    130     // Called when the hardware mirroring failed.
    131     virtual void SetSoftwareMirroring(bool enabled) = 0;
    132   };
    133 
    134   // Interface for classes that perform actions on behalf of OutputController.
    135   class Delegate {
    136    public:
    137     virtual ~Delegate() {}
    138 
    139     virtual void SetPanelFittingEnabled(bool enabled) = 0;
    140 
    141     // Initializes the XRandR extension, saving the base event ID to
    142     // |event_base|.
    143     virtual void InitXRandRExtension(int* event_base) = 0;
    144 
    145     // Tells XRandR to update its configuration in response to |event|, an
    146     // RRScreenChangeNotify event.
    147     virtual void UpdateXRandRConfiguration(const base::NativeEvent& event) = 0;
    148 
    149     // Grabs the X server and refreshes XRandR-related resources.  While
    150     // the server is grabbed, other clients are blocked.  Must be balanced
    151     // by a call to UngrabServer().
    152     virtual void GrabServer() = 0;
    153 
    154     // Ungrabs the server and frees XRandR-related resources.
    155     virtual void UngrabServer() = 0;
    156 
    157     // Flushes all pending requests and waits for replies.
    158     virtual void SyncWithServer() = 0;
    159 
    160     // Sets the window's background color to |color_argb|.
    161     virtual void SetBackgroundColor(uint32 color_argb) = 0;
    162 
    163     // Enables DPMS and forces it to the "on" state.
    164     virtual void ForceDPMSOn() = 0;
    165 
    166     // Returns information about the current outputs.
    167     // This method may block for 60 milliseconds or more.
    168     virtual std::vector<OutputSnapshot> GetOutputs(
    169         const StateController* state_controller) = 0;
    170 
    171     // Gets details corresponding to |mode|.  Parameters may be NULL.
    172     // Returns true on success.
    173     virtual bool GetModeDetails(RRMode mode,
    174                                 int* width,
    175                                 int* height,
    176                                 bool* interlaced) = 0;
    177 
    178     // Calls XRRSetCrtcConfig() with the given options but some of our default
    179     // output count and rotation arguments. Returns true on success.
    180     virtual bool ConfigureCrtc(RRCrtc crtc,
    181                                RRMode mode,
    182                                RROutput output,
    183                                int x,
    184                                int y) = 0;
    185 
    186     // Called to set the frame buffer (underlying XRR "screen") size.  Has
    187     // a side-effect of disabling all CRTCs.
    188     virtual void CreateFrameBuffer(
    189         int width,
    190         int height,
    191         const std::vector<OutputConfigurator::OutputSnapshot>& outputs) = 0;
    192 
    193     // Configures XInput's Coordinate Transformation Matrix property.
    194     // |touch_device_id| the ID of the touchscreen device to configure.
    195     // |ctm| contains the desired transformation parameters.  The offsets
    196     // in it should be normalized so that 1 corresponds to the X or Y axis
    197     // size for the corresponding offset.
    198     virtual void ConfigureCTM(int touch_device_id,
    199                               const CoordinateTransformation& ctm) = 0;
    200 
    201     // Sends a D-Bus message to the power manager telling it that the
    202     // machine is or is not projecting.
    203     virtual void SendProjectingStateToPowerManager(bool projecting) = 0;
    204   };
    205 
    206   // Helper class used by tests.
    207   class TestApi {
    208    public:
    209     TestApi(OutputConfigurator* configurator, int xrandr_event_base)
    210         : configurator_(configurator),
    211           xrandr_event_base_(xrandr_event_base) {}
    212     ~TestApi() {}
    213 
    214     // Dispatches RRScreenChangeNotify and RRNotify_OutputChange events to
    215     // |configurator_| and runs ConfigureOutputs().  Returns false if
    216     // |configure_timer_| wasn't started.
    217     bool SendOutputChangeEvents(bool connected);
    218 
    219    private:
    220     OutputConfigurator* configurator_;  // not owned
    221 
    222     int xrandr_event_base_;
    223 
    224     DISALLOW_COPY_AND_ASSIGN(TestApi);
    225   };
    226 
    227   // Flags that can be passed to SetDisplayPower().
    228   static const int kSetDisplayPowerNoFlags                     = 0;
    229   // Configure displays even if the passed-in state matches |power_state_|.
    230   static const int kSetDisplayPowerForceProbe                  = 1 << 0;
    231   // Do not change the state if multiple displays are connected or if the
    232   // only connected display is external.
    233   static const int kSetDisplayPowerOnlyIfSingleInternalDisplay = 1 << 1;
    234 
    235   // Gap between screens so cursor at bottom of active display doesn't
    236   // partially appear on top of inactive display. Higher numbers guard
    237   // against larger cursors, but also waste more memory.
    238   // For simplicity, this is hard-coded to avoid the complexity of always
    239   // determining the DPI of the screen and rationalizing which screen we
    240   // need to use for the DPI calculation.
    241   // See crbug.com/130188 for initial discussion.
    242   static const int kVerticalGap = 60;
    243 
    244   OutputConfigurator();
    245   virtual ~OutputConfigurator();
    246 
    247   OutputState output_state() const { return output_state_; }
    248   DisplayPowerState power_state() const { return power_state_; }
    249 
    250   void set_state_controller(StateController* controller) {
    251     state_controller_ = controller;
    252   }
    253   void set_mirroring_controller(SoftwareMirroringController* controller) {
    254     mirroring_controller_ = controller;
    255   }
    256 
    257   // Replaces |delegate_| with |delegate| and sets |configure_display_| to
    258   // true.  Should be called before Init().
    259   void SetDelegateForTesting(scoped_ptr<Delegate> delegate);
    260 
    261   // Sets the initial value of |power_state_|.  Must be called before Start().
    262   void SetInitialDisplayPower(DisplayPowerState power_state);
    263 
    264   // Initialization, must be called right after constructor.
    265   // |is_panel_fitting_enabled| indicates hardware panel fitting support.
    266   void Init(bool is_panel_fitting_enabled);
    267 
    268   // Does initial configuration of displays during startup.
    269   // If |background_color_argb| is non zero and there are multiple displays,
    270   // OutputConfigurator sets the background color of X's RootWindow to this
    271   // color.
    272   void Start(uint32 background_color_argb);
    273 
    274   // Stop handling display configuration events/requests.
    275   void Stop();
    276 
    277   // Called when powerd notifies us that some set of displays should be turned
    278   // on or off.  This requires enabling or disabling the CRTC associated with
    279   // the display(s) in question so that the low power state is engaged.
    280   // |flags| contains bitwise-or-ed kSetDisplayPower* values.
    281   bool SetDisplayPower(DisplayPowerState power_state, int flags);
    282 
    283   // Force switching the display mode to |new_state|. Returns false if
    284   // switching failed (possibly because |new_state| is invalid for the
    285   // current set of connected outputs).
    286   bool SetDisplayMode(OutputState new_state);
    287 
    288   // Called when an RRNotify event is received.  The implementation is
    289   // interested in the cases of RRNotify events which correspond to output
    290   // add/remove events.  Note that Output add/remove events are sent in response
    291   // to our own reconfiguration operations so spurious events are common.
    292   // Spurious events will have no effect.
    293   virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
    294 
    295   // Overridden from base::MessagePumpObserver:
    296   virtual base::EventStatus WillProcessEvent(
    297       const base::NativeEvent& event) OVERRIDE;
    298   virtual void DidProcessEvent(
    299       const base::NativeEvent& event) OVERRIDE;
    300 
    301   void AddObserver(Observer* observer);
    302   void RemoveObserver(Observer* observer);
    303 
    304   // Sets all the displays into pre-suspend mode; usually this means
    305   // configure them for their resume state. This allows faster resume on
    306   // machines where display configuration is slow.
    307   void SuspendDisplays();
    308 
    309   // Reprobes displays to handle changes made while the system was
    310   // suspended.
    311   void ResumeDisplays();
    312 
    313   const std::map<int, float>& GetMirroredDisplayAreaRatioMap() {
    314     return mirrored_display_area_ratio_map_;
    315   }
    316 
    317   // Configure outputs with |kConfigureDelayMs| delay,
    318   // so that time-consuming ConfigureOutputs() won't be called multiple times.
    319   void ScheduleConfigureOutputs();
    320 
    321  private:
    322   // Configure outputs.
    323   void ConfigureOutputs();
    324 
    325   // Fires OnDisplayModeChanged() event to the observers.
    326   void NotifyOnDisplayChanged();
    327 
    328   // Switches to the state specified in |output_state| and |power_state|.
    329   // If the hardware mirroring failed and |mirroring_controller_| is set,
    330   // it switches to |STATE_DUAL_EXTENDED| and calls |SetSoftwareMirroring()|
    331   // to enable software based mirroring.
    332   // On success, updates |output_state_|, |power_state_|, and |cached_outputs_|
    333   // and returns true.
    334   bool EnterStateOrFallBackToSoftwareMirroring(
    335       OutputState output_state,
    336       DisplayPowerState power_state,
    337       const std::vector<OutputSnapshot>& outputs);
    338 
    339   // Switches to the state specified in |output_state| and |power_state|.
    340   // On success, updates |output_state_|, |power_state_|, and
    341   // |cached_outputs_| and returns true.
    342   bool EnterState(OutputState output_state,
    343                   DisplayPowerState power_state,
    344                   const std::vector<OutputSnapshot>& outputs);
    345 
    346   // Returns the output state that should be used with |outputs| connected
    347   // while in |power_state|.
    348   OutputState GetOutputState(const std::vector<OutputSnapshot>& outputs,
    349                              DisplayPowerState power_state) const;
    350 
    351   // Computes the relevant transformation for mirror mode.
    352   // |output| is the output on which mirror mode is being applied.
    353   // Returns the transformation or identity if computations fail.
    354   CoordinateTransformation GetMirrorModeCTM(
    355       const OutputConfigurator::OutputSnapshot* output);
    356 
    357   // Returns the ratio between mirrored mode area and native mode area:
    358   // (mirror_mode_width * mirrow_mode_height) / (native_width * native_height)
    359   float GetMirroredDisplayAreaRatio(
    360       const OutputConfigurator::OutputSnapshot* output);
    361 
    362   StateController* state_controller_;
    363   SoftwareMirroringController* mirroring_controller_;
    364   scoped_ptr<Delegate> delegate_;
    365 
    366   // Key of the map is the touch display's id, and the value of the map is the
    367   // touch display's area ratio in mirror mode defined as :
    368   // mirror_mode_area / native_mode_area.
    369   // This is used for scaling touch event's radius when the touch display is in
    370   // mirror mode :
    371   // new_touch_radius = sqrt(area_ratio) * old_touch_radius
    372   std::map<int, float> mirrored_display_area_ratio_map_;
    373 
    374   // This is detected by the constructor to determine whether or not we should
    375   // be enabled.  If we aren't running on ChromeOS, we can't assume that the
    376   // Xrandr X11 extension is supported.
    377   // If this flag is set to false, any attempts to change the output
    378   // configuration to immediately fail without changing the state.
    379   bool configure_display_;
    380 
    381   // The base of the event numbers used to represent XRandr events used in
    382   // decoding events regarding output add/remove.
    383   int xrandr_event_base_;
    384 
    385   // The current display state.
    386   OutputState output_state_;
    387 
    388   // The current power state.
    389   DisplayPowerState power_state_;
    390 
    391   // Most-recently-used output configuration. Note that the actual
    392   // configuration changes asynchronously.
    393   std::vector<OutputSnapshot> cached_outputs_;
    394 
    395   ObserverList<Observer> observers_;
    396 
    397   // The timer to delay configuring outputs. See also the comments in
    398   // Dispatch().
    399   scoped_ptr<base::OneShotTimer<OutputConfigurator> > configure_timer_;
    400 
    401   DISALLOW_COPY_AND_ASSIGN(OutputConfigurator);
    402 };
    403 
    404 typedef std::vector<OutputConfigurator::OutputSnapshot> OutputSnapshotList;
    405 
    406 }  // namespace chromeos
    407 
    408 #endif  // CHROMEOS_DISPLAY_OUTPUT_CONFIGURATOR_H_
    409