blob: 6deae54dccb6f5a9f9c94ae918a2902369c28d2c [file] [log] [blame]
[email protected]6d980bc2012-09-10 19:28:451// 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#include "chromeos/display/output_configurator.h"
6
[email protected]acb217ed2013-04-09 21:52:367#include <cstdarg>
8#include <map>
[email protected]6d980bc2012-09-10 19:28:459#include <string>
[email protected]acb217ed2013-04-09 21:52:3610#include <vector>
[email protected]6d980bc2012-09-10 19:28:4511
[email protected]acb217ed2013-04-09 21:52:3612#include "base/basictypes.h"
13#include "base/compiler_specific.h"
14#include "base/message_loop.h"
15#include "base/stringprintf.h"
[email protected]6d980bc2012-09-10 19:28:4516#include "testing/gtest/include/gtest/gtest.h"
17
18namespace chromeos {
19
[email protected]acb217ed2013-04-09 21:52:3620namespace {
21
22// Strings returned by TestDelegate::GetActionsAndClear() to describe various
23// actions that were performed.
24const char kInitXRandR[] = "init";
25const char kUpdateXRandR[] = "update";
26const char kGrab[] = "grab";
27const char kUngrab[] = "ungrab";
28const char kSync[] = "sync";
29const char kForceDPMS[] = "dpms";
30const char kProjectingOn[] = "projecting";
31const char kProjectingOff[] = "not_projecting";
32
33// String returned by TestDelegate::GetActionsAndClear() if no actions were
34// requested.
35const char kNoActions[] = "";
36
37// Returns a string describing a TestDelegate::SetBackgroundColor() call.
38std::string GetBackgroundAction(uint32 color_argb) {
39 return base::StringPrintf("background(0x%x)", color_argb);
40}
41
42// Returns a string describing a TestDelegate::ConfigureCrtc() call.
43std::string GetCrtcAction(RRCrtc crtc,
44 int x,
45 int y,
46 RRMode mode,
47 RROutput output) {
48 return base::StringPrintf("crtc(crtc=%lu,x=%d,y=%d,mode=%lu,output=%lu)",
49 crtc, x, y, mode, output);
50}
51
52// Returns a string describing a TestDelegate::CreateFramebuffer() call.
53std::string GetFramebufferAction(int width,
54 int height,
55 RRCrtc crtc1,
56 RRCrtc crtc2) {
57 return base::StringPrintf(
58 "framebuffer(width=%d,height=%d,crtc1=%lu,crtc2=%lu)",
59 width, height, crtc1, crtc2);
60}
61
62// Returns a string describing a TestDelegate::ConfigureCTM() call.
63std::string GetCTMAction(
64 int device_id,
65 const OutputConfigurator::CoordinateTransformation& ctm) {
66 return base::StringPrintf("ctm(id=%d,transform=(%f,%f,%f,%f))", device_id,
67 ctm.x_scale, ctm.x_offset, ctm.y_scale, ctm.y_offset);
68}
69
70// Joins a sequence of strings describing actions (e.g. kScreenDim) such
71// that they can be compared against a string returned by
72// TestDelegate::GetActionsAndClear(). The list of actions must be
73// terminated by a NULL pointer.
74std::string JoinActions(const char* action, ...) {
75 std::string actions;
76
77 va_list arg_list;
78 va_start(arg_list, action);
79 while (action) {
80 if (!actions.empty())
81 actions += ",";
82 actions += action;
83 action = va_arg(arg_list, const char*);
84 }
85 va_end(arg_list);
86 return actions;
87}
88
89class TestDelegate : public OutputConfigurator::Delegate {
90 public:
91 static const int kXRandREventBase = 10;
92
93 TestDelegate() {}
94 virtual ~TestDelegate() {}
95
96 void set_outputs(
97 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) {
98 outputs_ = outputs;
99 }
100
101 // Returns a comma-separated string describing the actions that were
102 // requested since the previous call to GetActionsAndClear() (i.e.
103 // results are non-repeatable).
104 std::string GetActionsAndClear() {
105 std::string actions = actions_;
106 actions_.clear();
107 return actions;
108 }
109
110 // Adds a mode to be returned by GetModeDetails().
111 void AddMode(RRMode mode, int width, int height, bool interlaced) {
112 modes_[mode] = ModeDetails(width, height, interlaced);
113 }
114
115 // OutputConfigurator::Delegate overrides:
116 virtual void SetPanelFittingEnabled(bool enabled) OVERRIDE {}
117 virtual void InitXRandRExtension(int* event_base) OVERRIDE {
118 AppendAction(kInitXRandR);
119 *event_base = kXRandREventBase;
120 }
121 virtual void UpdateXRandRConfiguration(
122 const base::NativeEvent& event) OVERRIDE { AppendAction(kUpdateXRandR); }
123 virtual void GrabServer() OVERRIDE { AppendAction(kGrab); }
124 virtual void UngrabServer() OVERRIDE { AppendAction(kUngrab); }
125 virtual void SyncWithServer() OVERRIDE { AppendAction(kSync); }
126 virtual void SetBackgroundColor(uint32 color_argb) OVERRIDE {
127 AppendAction(GetBackgroundAction(color_argb));
128 }
129 virtual void ForceDPMSOn() OVERRIDE { AppendAction(kForceDPMS); }
130 virtual std::vector<OutputConfigurator::OutputSnapshot> GetOutputs()
131 OVERRIDE {
132 return outputs_;
133 }
134 virtual bool GetModeDetails(
135 RRMode mode,
136 int* width,
137 int* height,
138 bool* interlaced) OVERRIDE {
139 std::map<RRMode, ModeDetails>::const_iterator it = modes_.find(mode);
140 if (it == modes_.end())
141 return false;
142
143 if (width)
144 *width = it->second.width;
145 if (height)
146 *height = it->second.height;
147 if (interlaced)
148 *interlaced = it->second.interlaced;
149 return true;
150 }
151 virtual void ConfigureCrtc(OutputConfigurator::CrtcConfig* config) OVERRIDE {
152 AppendAction(GetCrtcAction(config->crtc, config->x, config->y, config->mode,
153 config->output));
154 }
155 virtual void CreateFrameBuffer(
156 int width,
157 int height,
[email protected]42091902013-05-02 02:24:12158 const std::vector<OutputConfigurator::CrtcConfig>& configs) OVERRIDE {
159 AppendAction(
160 GetFramebufferAction(width,
161 height,
162 configs.size() >= 1 ? configs[0].crtc : 0,
163 configs.size() >= 2 ? configs[1].crtc : 0));
[email protected]acb217ed2013-04-09 21:52:36164 }
165 virtual void ConfigureCTM(
166 int touch_device_id,
167 const OutputConfigurator::CoordinateTransformation& ctm) OVERRIDE {
168 AppendAction(GetCTMAction(touch_device_id, ctm));
169 }
170 virtual void SendProjectingStateToPowerManager(bool projecting) OVERRIDE {
171 AppendAction(projecting ? kProjectingOn : kProjectingOff);
172 }
173
174 private:
175 struct ModeDetails {
176 ModeDetails() : width(0), height(0), interlaced(false) {}
177 ModeDetails(int width, int height, bool interlaced)
178 : width(width),
179 height(height),
180 interlaced(interlaced) {}
181
182 int width;
183 int height;
184 bool interlaced;
185 };
186
187 void AppendAction(const std::string& action) {
188 if (!actions_.empty())
189 actions_ += ",";
190 actions_ += action;
191 }
192
193 std::map<RRMode, ModeDetails> modes_;
194
195 // Outputs to be returned by GetOutputs().
196 std::vector<OutputConfigurator::OutputSnapshot> outputs_;
197
198 std::string actions_;
199
200 DISALLOW_COPY_AND_ASSIGN(TestDelegate);
201};
202
203class TestStateController : public OutputConfigurator::StateController {
204 public:
205 TestStateController() : state_(STATE_DUAL_EXTENDED) {}
[email protected]42091902013-05-02 02:24:12206 virtual ~TestStateController() {}
[email protected]acb217ed2013-04-09 21:52:36207
208 void set_state(OutputState state) { state_ = state; }
209
210 // OutputConfigurator::StateController overrides:
[email protected]2c8a0aa72013-05-16 06:24:48211 virtual OutputState GetStateForDisplayIds(
212 const std::vector<int64>& outputs) const OVERRIDE { return state_; }
[email protected]acb217ed2013-04-09 21:52:36213
214 private:
215 OutputState state_;
216
217 DISALLOW_COPY_AND_ASSIGN(TestStateController);
218};
219
[email protected]c1f30dc2013-05-22 17:27:45220class TestMirroringController
221 : public OutputConfigurator::SoftwareMirroringController {
222 public:
223 TestMirroringController() : software_mirroring_enabled_(false) {}
224 virtual ~TestMirroringController() {}
225
226 virtual void SetSoftwareMirroring(bool enabled) OVERRIDE {
227 software_mirroring_enabled_ = enabled;
228 }
229
230 bool software_mirroring_enabled() const {
231 return software_mirroring_enabled_;
232 }
233
234 private:
235 bool software_mirroring_enabled_;
236
237 DISALLOW_COPY_AND_ASSIGN(TestMirroringController);
238};
239
[email protected]acb217ed2013-04-09 21:52:36240class OutputConfiguratorTest : public testing::Test {
241 public:
242 OutputConfiguratorTest()
243 : test_api_(&configurator_, TestDelegate::kXRandREventBase) {}
244 virtual ~OutputConfiguratorTest() {}
245
246 virtual void SetUp() OVERRIDE {
247 delegate_ = new TestDelegate();
248 configurator_.SetDelegateForTesting(
249 scoped_ptr<OutputConfigurator::Delegate>(delegate_));
250 configurator_.set_state_controller(&state_controller_);
[email protected]c1f30dc2013-05-22 17:27:45251 configurator_.set_mirroring_controller(&mirroring_controller_);
[email protected]acb217ed2013-04-09 21:52:36252
253 OutputConfigurator::OutputSnapshot* o = &outputs_[0];
254 o->output = 1;
255 o->crtc = 10;
256 o->current_mode = kSmallModeId;
257 o->native_mode = kSmallModeId;
258 o->mirror_mode = kSmallModeId;
259 o->y = 0;
260 o->height = kSmallModeHeight;
261 o->is_internal = true;
262 o->is_aspect_preserving_scaling = true;
263 o->touch_device_id = 0;
[email protected]2c8a0aa72013-05-16 06:24:48264 o->has_display_id = true;
[email protected]acb217ed2013-04-09 21:52:36265
266 o = &outputs_[1];
267 o->output = 2;
268 o->crtc = 11;
269 o->current_mode = kBigModeId;
270 o->native_mode = kBigModeId;
271 o->mirror_mode = kSmallModeId;
272 o->y = 0;
273 o->height = kBigModeHeight;
274 o->is_internal = false;
275 o->is_aspect_preserving_scaling = true;
276 o->touch_device_id = 0;
[email protected]2c8a0aa72013-05-16 06:24:48277 o->has_display_id = true;
[email protected]acb217ed2013-04-09 21:52:36278
279 UpdateOutputs(2);
280 delegate_->AddMode(kSmallModeId, kSmallModeWidth, kSmallModeHeight, false);
281 delegate_->AddMode(kBigModeId, kBigModeWidth, kBigModeHeight, false);
282 }
283
[email protected]c1f30dc2013-05-22 17:27:45284 void DisableNativeMirroring() {
285 outputs_[0].mirror_mode = outputs_[1].mirror_mode = 0L;
286 }
287
[email protected]acb217ed2013-04-09 21:52:36288 protected:
289 // Predefined modes that can be used by outputs.
290 static const int kSmallModeId = 20;
291 static const int kSmallModeWidth = 1366;
292 static const int kSmallModeHeight = 768;
293
294 static const int kBigModeId = 21;
295 static const int kBigModeWidth = 2560;
296 static const int kBigModeHeight = 1600;
297
298 // Configures |delegate_| to return the first |num_outputs| entries from
299 // |outputs_|.
300 virtual void UpdateOutputs(size_t num_outputs) {
301 ASSERT_LE(num_outputs, arraysize(outputs_));
302 std::vector<OutputConfigurator::OutputSnapshot> outputs;
303 for (size_t i = 0; i < num_outputs; ++i)
304 outputs.push_back(outputs_[i]);
305 delegate_->set_outputs(outputs);
306 }
307
308 // Initializes |configurator_| with a single internal display.
309 virtual void InitWithSingleOutput() {
310 UpdateOutputs(1);
311 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
312 configurator_.Init(false, 0);
313 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL),
314 delegate_->GetActionsAndClear());
315 configurator_.Start();
316 EXPECT_EQ(JoinActions(kGrab, kInitXRandR,
317 GetFramebufferAction(kSmallModeWidth,
318 kSmallModeHeight, outputs_[0].crtc, 0).c_str(),
319 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
320 outputs_[0].output).c_str(),
321 kForceDPMS, kUngrab, kProjectingOff, NULL),
322 delegate_->GetActionsAndClear());
323 }
324
325 base::MessageLoop message_loop_;
326 TestStateController state_controller_;
[email protected]c1f30dc2013-05-22 17:27:45327 TestMirroringController mirroring_controller_;
[email protected]acb217ed2013-04-09 21:52:36328 OutputConfigurator configurator_;
329 TestDelegate* delegate_; // not owned
330 OutputConfigurator::TestApi test_api_;
331
332 OutputConfigurator::OutputSnapshot outputs_[2];
333
334 private:
335 DISALLOW_COPY_AND_ASSIGN(OutputConfiguratorTest);
336};
337
338} // namespace
[email protected]6d980bc2012-09-10 19:28:45339
[email protected]acb217ed2013-04-09 21:52:36340TEST_F(OutputConfiguratorTest, ConnectSecondOutput) {
341 InitWithSingleOutput();
342
343 // Connect a second output and check that the configurator enters
344 // extended mode.
345 UpdateOutputs(2);
346 const int kDualHeight =
347 kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight;
348 state_controller_.set_state(STATE_DUAL_EXTENDED);
349 EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
350 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
351 GetFramebufferAction(kBigModeWidth, kDualHeight,
352 outputs_[0].crtc, outputs_[1].crtc).c_str(),
353 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
354 outputs_[0].output).c_str(),
355 GetCrtcAction(outputs_[1].crtc, 0,
356 kSmallModeHeight + OutputConfigurator::kVerticalGap,
357 kBigModeId, outputs_[1].output).c_str(),
358 kUngrab, kProjectingOn, NULL),
359 delegate_->GetActionsAndClear());
[email protected]c1f30dc2013-05-22 17:27:45360 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
[email protected]acb217ed2013-04-09 21:52:36361
362 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
363 EXPECT_EQ(JoinActions(kGrab,
364 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
365 outputs_[0].crtc, outputs_[1].crtc).c_str(),
366 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
367 outputs_[0].output).c_str(),
368 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
369 outputs_[1].output).c_str(),
370 kUngrab, NULL),
371 delegate_->GetActionsAndClear());
[email protected]c1f30dc2013-05-22 17:27:45372 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
[email protected]acb217ed2013-04-09 21:52:36373
374 // Disconnect the second output.
375 UpdateOutputs(1);
376 EXPECT_TRUE(test_api_.SendOutputChangeEvents(false));
377 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
378 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
379 outputs_[0].crtc, 0).c_str(),
380 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
381 outputs_[0].output).c_str(),
382 kUngrab, kProjectingOff, NULL),
383 delegate_->GetActionsAndClear());
[email protected]c1f30dc2013-05-22 17:27:45384 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
385
386 // Software Mirroring
387 DisableNativeMirroring();
388 UpdateOutputs(2);
389 state_controller_.set_state(STATE_DUAL_EXTENDED);
390 EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
391 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
392 GetFramebufferAction(kBigModeWidth, kDualHeight,
393 outputs_[0].crtc, outputs_[1].crtc).c_str(),
394 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
395 outputs_[0].output).c_str(),
396 GetCrtcAction(outputs_[1].crtc, 0,
397 kSmallModeHeight + OutputConfigurator::kVerticalGap,
398 kBigModeId, outputs_[1].output).c_str(),
399 kUngrab, kProjectingOn, NULL),
400 delegate_->GetActionsAndClear());
401 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
402
403 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
404 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL),
405 delegate_->GetActionsAndClear());
406 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
407 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
408
[email protected]57bed4d2013-06-08 20:54:18409 // Setting STATE_DUAL_MIRROR should try to reconfigure
410 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
411 EXPECT_EQ(JoinActions(NULL), delegate_->GetActionsAndClear());
412 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
413
414 // Set back to software mirror mode.
415 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
416 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL),
417 delegate_->GetActionsAndClear());
418 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
419 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
420
[email protected]c1f30dc2013-05-22 17:27:45421 // Disconnect the second output.
422 UpdateOutputs(1);
423 EXPECT_TRUE(test_api_.SendOutputChangeEvents(false));
424 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
425 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
426 outputs_[0].crtc, 0).c_str(),
427 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
428 outputs_[0].output).c_str(),
429 kUngrab, kProjectingOff, NULL),
430 delegate_->GetActionsAndClear());
431 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
[email protected]acb217ed2013-04-09 21:52:36432}
433
434TEST_F(OutputConfiguratorTest, SetDisplayPower) {
435 InitWithSingleOutput();
436
437 UpdateOutputs(2);
438 state_controller_.set_state(STATE_DUAL_MIRROR);
439 EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
440 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
441 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
442 outputs_[0].crtc, outputs_[1].crtc).c_str(),
443 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
444 outputs_[0].output).c_str(),
445 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
446 outputs_[1].output).c_str(),
447 kUngrab, kProjectingOn, NULL),
448 delegate_->GetActionsAndClear());
[email protected]c1f30dc2013-05-22 17:27:45449 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
[email protected]acb217ed2013-04-09 21:52:36450
451 // Turning off the internal display should switch the external display to
452 // its native mode.
453 configurator_.SetDisplayPower(DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
454 OutputConfigurator::kSetDisplayPowerNoFlags);
455 EXPECT_EQ(JoinActions(kGrab,
456 GetFramebufferAction(kBigModeWidth, kBigModeHeight,
457 outputs_[0].crtc, outputs_[1].crtc).c_str(),
458 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
459 outputs_[0].output).c_str(),
460 GetCrtcAction(outputs_[1].crtc, 0, 0, kBigModeId,
461 outputs_[1].output).c_str(),
462 kForceDPMS, kUngrab, NULL),
463 delegate_->GetActionsAndClear());
[email protected]c1f30dc2013-05-22 17:27:45464 EXPECT_EQ(STATE_SINGLE, configurator_.output_state());
[email protected]acb217ed2013-04-09 21:52:36465
466 // When all displays are turned off, the framebuffer should switch back
467 // to the mirrored size.
468 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
469 OutputConfigurator::kSetDisplayPowerNoFlags);
470 EXPECT_EQ(JoinActions(kGrab,
471 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
472 outputs_[0].crtc, outputs_[1].crtc).c_str(),
473 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
474 outputs_[0].output).c_str(),
475 GetCrtcAction(outputs_[1].crtc, 0, 0, 0,
476 outputs_[1].output).c_str(),
477 kUngrab, NULL),
478 delegate_->GetActionsAndClear());
[email protected]c1f30dc2013-05-22 17:27:45479 EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
480 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
[email protected]acb217ed2013-04-09 21:52:36481
482 // Turn all displays on and check that mirroring is still used.
483 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
484 OutputConfigurator::kSetDisplayPowerNoFlags);
485 EXPECT_EQ(JoinActions(kGrab,
486 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
487 outputs_[0].crtc, outputs_[1].crtc).c_str(),
488 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
489 outputs_[0].output).c_str(),
490 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
491 outputs_[1].output).c_str(),
492 kForceDPMS, kUngrab, NULL),
493 delegate_->GetActionsAndClear());
[email protected]c1f30dc2013-05-22 17:27:45494 EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
495 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
496
497 // Software Mirroring
498 DisableNativeMirroring();
499 UpdateOutputs(2);
500
501 const int kDualHeight =
502 kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight;
503
504 state_controller_.set_state(STATE_DUAL_MIRROR);
505 EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
506 // Move to extended
507 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
508 GetFramebufferAction(kBigModeWidth, kDualHeight,
509 outputs_[0].crtc, outputs_[1].crtc).c_str(),
510 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
511 outputs_[0].output).c_str(),
512 GetCrtcAction(outputs_[1].crtc, 0,
513 kSmallModeHeight + OutputConfigurator::kVerticalGap,
514 kBigModeId, outputs_[1].output).c_str(),
515 kUngrab, kProjectingOn, NULL),
516 delegate_->GetActionsAndClear());
517 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
518 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
519
520 // Turning off the internal display should switch the external display to
521 // its native mode.
522 configurator_.SetDisplayPower(DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
523 OutputConfigurator::kSetDisplayPowerNoFlags);
524 EXPECT_EQ(JoinActions(kGrab,
525 GetFramebufferAction(kBigModeWidth, kBigModeHeight,
526 outputs_[0].crtc, outputs_[1].crtc).c_str(),
527 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
528 outputs_[0].output).c_str(),
529 GetCrtcAction(outputs_[1].crtc, 0, 0, kBigModeId,
530 outputs_[1].output).c_str(),
531 kForceDPMS, kUngrab, NULL),
532 delegate_->GetActionsAndClear());
533 EXPECT_EQ(STATE_SINGLE, configurator_.output_state());
534 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
535
536 // When all displays are turned off, the framebuffer should switch back
537 // to the extended + software mirroring.
538 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
539 OutputConfigurator::kSetDisplayPowerNoFlags);
540 EXPECT_EQ(JoinActions(kGrab,
541 GetFramebufferAction(kBigModeWidth, kDualHeight,
542 outputs_[0].crtc, outputs_[1].crtc).c_str(),
543 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
544 outputs_[0].output).c_str(),
545 GetCrtcAction(outputs_[1].crtc, 0,
546 kSmallModeHeight + OutputConfigurator::kVerticalGap,
547 0, outputs_[1].output).c_str(),
548 kUngrab, NULL),
549 delegate_->GetActionsAndClear());
550 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
551 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
552
553 // Turn all displays on and check that mirroring is still used.
554 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
555 OutputConfigurator::kSetDisplayPowerNoFlags);
556 EXPECT_EQ(JoinActions(kGrab,
557 GetFramebufferAction(kBigModeWidth, kDualHeight,
558 outputs_[0].crtc, outputs_[1].crtc).c_str(),
559 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
560 outputs_[0].output).c_str(),
561 GetCrtcAction(outputs_[1].crtc, 0,
562 kSmallModeHeight + OutputConfigurator::kVerticalGap,
563 kBigModeId, outputs_[1].output).c_str(),
564 kForceDPMS, kUngrab, NULL),
565 delegate_->GetActionsAndClear());
566 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
567 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
568
[email protected]acb217ed2013-04-09 21:52:36569}
570
571TEST_F(OutputConfiguratorTest, SuspendAndResume) {
572 InitWithSingleOutput();
573
574 // No preparation is needed before suspending when the display is already
575 // on. The configurator should still reprobe on resume in case a display
576 // was connected while suspended.
577 configurator_.SuspendDisplays();
578 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
579 configurator_.ResumeDisplays();
580 EXPECT_EQ(JoinActions(kGrab,
581 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
582 outputs_[0].crtc, 0).c_str(),
583 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
584 outputs_[0].output).c_str(),
585 kForceDPMS, kUngrab, NULL),
586 delegate_->GetActionsAndClear());
587
588 // Now turn the display off before suspending and check that the
589 // configurator turns it back on and syncs with the server.
590 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
591 OutputConfigurator::kSetDisplayPowerNoFlags);
592 EXPECT_EQ(JoinActions(kGrab,
593 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
594 outputs_[0].crtc, 0).c_str(),
595 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
596 outputs_[0].output).c_str(),
597 kUngrab, NULL),
598 delegate_->GetActionsAndClear());
599
600 configurator_.SuspendDisplays();
601 EXPECT_EQ(JoinActions(kGrab,
602 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
603 outputs_[0].crtc, 0).c_str(),
604 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
605 outputs_[0].output).c_str(),
606 kForceDPMS, kUngrab, kSync, NULL),
607 delegate_->GetActionsAndClear());
608
609 configurator_.ResumeDisplays();
610 EXPECT_EQ(JoinActions(kGrab,
611 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
612 outputs_[0].crtc, 0).c_str(),
613 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
614 outputs_[0].output).c_str(),
615 kForceDPMS, kUngrab, NULL),
616 delegate_->GetActionsAndClear());
617
618 // If a second, external display is connected, the displays shouldn't be
619 // powered back on before suspending.
620 UpdateOutputs(2);
621 state_controller_.set_state(STATE_DUAL_MIRROR);
622 EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
623 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
624 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
625 outputs_[0].crtc, outputs_[1].crtc).c_str(),
626 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
627 outputs_[0].output).c_str(),
628 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
629 outputs_[1].output).c_str(),
630 kUngrab, kProjectingOn, NULL),
631 delegate_->GetActionsAndClear());
632
633 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
634 OutputConfigurator::kSetDisplayPowerNoFlags);
635 EXPECT_EQ(JoinActions(kGrab,
636 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
637 outputs_[0].crtc, outputs_[1].crtc).c_str(),
638 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
639 outputs_[0].output).c_str(),
640 GetCrtcAction(outputs_[1].crtc, 0, 0, 0,
641 outputs_[1].output).c_str(),
642 kUngrab, NULL),
643 delegate_->GetActionsAndClear());
644
645 configurator_.SuspendDisplays();
646 EXPECT_EQ(JoinActions(kGrab, kUngrab, kSync, NULL),
647 delegate_->GetActionsAndClear());
648
649 // If a display is disconnected while resuming, the configurator should
650 // pick up the change.
651 UpdateOutputs(1);
652 configurator_.ResumeDisplays();
653 EXPECT_EQ(JoinActions(kGrab,
654 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
655 outputs_[0].crtc, 0).c_str(),
656 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
657 outputs_[0].output).c_str(),
658 kUngrab, NULL),
659 delegate_->GetActionsAndClear());
660}
661
662TEST_F(OutputConfiguratorTest, Headless) {
663 UpdateOutputs(0);
664 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
665 configurator_.Init(false, 0);
666 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), delegate_->GetActionsAndClear());
667 configurator_.Start();
668 EXPECT_EQ(JoinActions(kGrab, kInitXRandR, kForceDPMS, kUngrab,
669 kProjectingOff, NULL),
670 delegate_->GetActionsAndClear());
671
672 // Not much should happen when the display power state is changed while
673 // no displays are connected.
674 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
675 OutputConfigurator::kSetDisplayPowerNoFlags);
676 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), delegate_->GetActionsAndClear());
677 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
678 OutputConfigurator::kSetDisplayPowerNoFlags);
679 EXPECT_EQ(JoinActions(kGrab, kForceDPMS, kUngrab, NULL),
680 delegate_->GetActionsAndClear());
681
682 // Connect an external display and check that it's configured correctly.
683 outputs_[0].is_internal = false;
684 outputs_[0].native_mode = kBigModeId;
685 UpdateOutputs(1);
686 EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
687 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
688 GetFramebufferAction(kBigModeWidth, kBigModeHeight,
689 outputs_[0].crtc, 0).c_str(),
690 GetCrtcAction(outputs_[0].crtc, 0, 0, kBigModeId,
691 outputs_[0].output).c_str(),
692 kUngrab, kProjectingOff, NULL),
693 delegate_->GetActionsAndClear());
694}
695
696TEST_F(OutputConfiguratorTest, StartWithTwoOutputs) {
697 UpdateOutputs(2);
698 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
699 configurator_.Init(false, 0);
700 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), delegate_->GetActionsAndClear());
701
702 state_controller_.set_state(STATE_DUAL_MIRROR);
703 configurator_.Start();
704 EXPECT_EQ(JoinActions(kGrab, kInitXRandR,
705 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
706 outputs_[0].crtc, outputs_[1].crtc).c_str(),
707 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
708 outputs_[0].output).c_str(),
709 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
710 outputs_[1].output).c_str(),
711 kForceDPMS, kUngrab, kProjectingOn, NULL),
712 delegate_->GetActionsAndClear());
713}
714
715TEST_F(OutputConfiguratorTest, InvalidOutputStates) {
716 UpdateOutputs(0);
717 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
718 configurator_.Init(false, 0);
719 configurator_.Start();
720 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_HEADLESS));
721 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_SINGLE));
722 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
723 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
724
725 UpdateOutputs(1);
726 EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
727 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_HEADLESS));
728 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_SINGLE));
729 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
730 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
731
732 UpdateOutputs(2);
733 state_controller_.set_state(STATE_DUAL_EXTENDED);
734 EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
735 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_HEADLESS));
736 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_SINGLE));
737 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
738 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
739}
740
[email protected]2c8a0aa72013-05-16 06:24:48741TEST_F(OutputConfiguratorTest, GetOutputStateForDisplays) {
742 outputs_[0].has_display_id = false;
743 UpdateOutputs(2);
744
745 configurator_.Init(false, 0);
746 configurator_.Start();
747
748 state_controller_.set_state(STATE_DUAL_MIRROR);
749 test_api_.SendOutputChangeEvents(true);
750 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
751
752 outputs_[0].has_display_id = true;
753 UpdateOutputs(2);
754 test_api_.SendOutputChangeEvents(true);
755 EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
756}
757
[email protected]6d980bc2012-09-10 19:28:45758} // namespace chromeos