blob: 882a8a81c9c1be9ab6e594da688e5269acde9599 [file] [log] [blame]
Ben Murdochc5cede92014-04-10 11:22:14 +01001// 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"
Ben Murdochc5cede92014-04-10 11:22:14 +010019#include "ui/display/display_export.h"
Ben Murdocha02191e2014-04-16 11:17:03 +010020#include "ui/display/types/chromeos/native_display_observer.h"
21#include "ui/display/types/display_constants.h"
Torne (Richard Coles)cedac222014-06-03 10:58:34 +010022#include "ui/gfx/geometry/size.h"
Ben Murdochc5cede92014-04-10 11:22:14 +010023
24namespace gfx {
25class Point;
26class Size;
27}
28
29namespace ui {
30class DisplayMode;
31class DisplaySnapshot;
32class NativeDisplayDelegate;
33
34// This class interacts directly with the system display configurator.
35class DISPLAY_EXPORT DisplayConfigurator : public NativeDisplayObserver {
36 public:
37 typedef uint64_t ContentProtectionClientId;
38 static const ContentProtectionClientId kInvalidClientId = 0;
39
Ben Murdochc5cede92014-04-10 11:22:14 +010040 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
Ben Murdochc5cede92014-04-10 11:22:14 +010048 // 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;
Torne (Richard Coles)cedac222014-06-03 10:58:34 +010097 virtual bool SoftwareMirroringEnabled() const = 0;
Ben Murdochc5cede92014-04-10 11:22:14 +010098 };
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;
Ben Murdochc5cede92014-04-10 11:22:14 +0100110 };
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_; }
Torne (Richard Coles)cedac222014-06-03 10:58:34 +0100156 const gfx::Size framebuffer_size() const { return framebuffer_size_; }
Ben Murdochc5cede92014-04-10 11:22:14 +0100157 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
Ben Murdocha02191e2014-04-16 11:17:03 +0100168 // 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);
Ben Murdochc5cede92014-04-10 11:22:14 +0100174
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
Ben Murdocha02191e2014-04-16 11:17:03 +0100262 // 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
Ben Murdochc5cede92014-04-10 11:22:14 +0100271 // 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
Ben Murdochc5cede92014-04-10 11:22:14 +0100321 // 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
Torne (Richard Coles)cedac222014-06-03 10:58:34 +0100325 // Returns true if in either hardware or software mirroring mode.
326 bool IsMirroring() const;
327
Ben Murdochc5cede92014-04-10 11:22:14 +0100328 // 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
Torne (Richard Coles)cedac222014-06-03 10:58:34 +0100357 gfx::Size framebuffer_size_;
358
Ben Murdochc5cede92014-04-10 11:22:14 +0100359 // 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_