blob: 8f69ce7433058fbf1d3a6df6f10046f76f694433 [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
220class OutputConfiguratorTest : public testing::Test {
221 public:
222 OutputConfiguratorTest()
223 : test_api_(&configurator_, TestDelegate::kXRandREventBase) {}
224 virtual ~OutputConfiguratorTest() {}
225
226 virtual void SetUp() OVERRIDE {
227 delegate_ = new TestDelegate();
228 configurator_.SetDelegateForTesting(
229 scoped_ptr<OutputConfigurator::Delegate>(delegate_));
230 configurator_.set_state_controller(&state_controller_);
231
232 OutputConfigurator::OutputSnapshot* o = &outputs_[0];
233 o->output = 1;
234 o->crtc = 10;
235 o->current_mode = kSmallModeId;
236 o->native_mode = kSmallModeId;
237 o->mirror_mode = kSmallModeId;
238 o->y = 0;
239 o->height = kSmallModeHeight;
240 o->is_internal = true;
241 o->is_aspect_preserving_scaling = true;
242 o->touch_device_id = 0;
[email protected]2c8a0aa72013-05-16 06:24:48243 o->has_display_id = true;
[email protected]acb217ed2013-04-09 21:52:36244
245 o = &outputs_[1];
246 o->output = 2;
247 o->crtc = 11;
248 o->current_mode = kBigModeId;
249 o->native_mode = kBigModeId;
250 o->mirror_mode = kSmallModeId;
251 o->y = 0;
252 o->height = kBigModeHeight;
253 o->is_internal = false;
254 o->is_aspect_preserving_scaling = true;
255 o->touch_device_id = 0;
[email protected]2c8a0aa72013-05-16 06:24:48256 o->has_display_id = true;
[email protected]acb217ed2013-04-09 21:52:36257
258 UpdateOutputs(2);
259 delegate_->AddMode(kSmallModeId, kSmallModeWidth, kSmallModeHeight, false);
260 delegate_->AddMode(kBigModeId, kBigModeWidth, kBigModeHeight, false);
261 }
262
263 protected:
264 // Predefined modes that can be used by outputs.
265 static const int kSmallModeId = 20;
266 static const int kSmallModeWidth = 1366;
267 static const int kSmallModeHeight = 768;
268
269 static const int kBigModeId = 21;
270 static const int kBigModeWidth = 2560;
271 static const int kBigModeHeight = 1600;
272
273 // Configures |delegate_| to return the first |num_outputs| entries from
274 // |outputs_|.
275 virtual void UpdateOutputs(size_t num_outputs) {
276 ASSERT_LE(num_outputs, arraysize(outputs_));
277 std::vector<OutputConfigurator::OutputSnapshot> outputs;
278 for (size_t i = 0; i < num_outputs; ++i)
279 outputs.push_back(outputs_[i]);
280 delegate_->set_outputs(outputs);
281 }
282
283 // Initializes |configurator_| with a single internal display.
284 virtual void InitWithSingleOutput() {
285 UpdateOutputs(1);
286 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
287 configurator_.Init(false, 0);
288 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL),
289 delegate_->GetActionsAndClear());
290 configurator_.Start();
291 EXPECT_EQ(JoinActions(kGrab, kInitXRandR,
292 GetFramebufferAction(kSmallModeWidth,
293 kSmallModeHeight, outputs_[0].crtc, 0).c_str(),
294 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
295 outputs_[0].output).c_str(),
296 kForceDPMS, kUngrab, kProjectingOff, NULL),
297 delegate_->GetActionsAndClear());
298 }
299
300 base::MessageLoop message_loop_;
301 TestStateController state_controller_;
302 OutputConfigurator configurator_;
303 TestDelegate* delegate_; // not owned
304 OutputConfigurator::TestApi test_api_;
305
306 OutputConfigurator::OutputSnapshot outputs_[2];
307
308 private:
309 DISALLOW_COPY_AND_ASSIGN(OutputConfiguratorTest);
310};
311
312} // namespace
[email protected]6d980bc2012-09-10 19:28:45313
[email protected]acb217ed2013-04-09 21:52:36314TEST_F(OutputConfiguratorTest, ConnectSecondOutput) {
315 InitWithSingleOutput();
316
317 // Connect a second output and check that the configurator enters
318 // extended mode.
319 UpdateOutputs(2);
320 const int kDualHeight =
321 kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight;
322 state_controller_.set_state(STATE_DUAL_EXTENDED);
323 EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
324 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
325 GetFramebufferAction(kBigModeWidth, kDualHeight,
326 outputs_[0].crtc, outputs_[1].crtc).c_str(),
327 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
328 outputs_[0].output).c_str(),
329 GetCrtcAction(outputs_[1].crtc, 0,
330 kSmallModeHeight + OutputConfigurator::kVerticalGap,
331 kBigModeId, outputs_[1].output).c_str(),
332 kUngrab, kProjectingOn, NULL),
333 delegate_->GetActionsAndClear());
334
335 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
336 EXPECT_EQ(JoinActions(kGrab,
337 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
338 outputs_[0].crtc, outputs_[1].crtc).c_str(),
339 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
340 outputs_[0].output).c_str(),
341 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
342 outputs_[1].output).c_str(),
343 kUngrab, NULL),
344 delegate_->GetActionsAndClear());
345
346 // Disconnect the second output.
347 UpdateOutputs(1);
348 EXPECT_TRUE(test_api_.SendOutputChangeEvents(false));
349 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
350 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
351 outputs_[0].crtc, 0).c_str(),
352 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
353 outputs_[0].output).c_str(),
354 kUngrab, kProjectingOff, NULL),
355 delegate_->GetActionsAndClear());
356}
357
358TEST_F(OutputConfiguratorTest, SetDisplayPower) {
359 InitWithSingleOutput();
360
361 UpdateOutputs(2);
362 state_controller_.set_state(STATE_DUAL_MIRROR);
363 EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
364 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
365 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
366 outputs_[0].crtc, outputs_[1].crtc).c_str(),
367 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
368 outputs_[0].output).c_str(),
369 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
370 outputs_[1].output).c_str(),
371 kUngrab, kProjectingOn, NULL),
372 delegate_->GetActionsAndClear());
373
374 // Turning off the internal display should switch the external display to
375 // its native mode.
376 configurator_.SetDisplayPower(DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
377 OutputConfigurator::kSetDisplayPowerNoFlags);
378 EXPECT_EQ(JoinActions(kGrab,
379 GetFramebufferAction(kBigModeWidth, kBigModeHeight,
380 outputs_[0].crtc, outputs_[1].crtc).c_str(),
381 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
382 outputs_[0].output).c_str(),
383 GetCrtcAction(outputs_[1].crtc, 0, 0, kBigModeId,
384 outputs_[1].output).c_str(),
385 kForceDPMS, kUngrab, NULL),
386 delegate_->GetActionsAndClear());
387
388 // When all displays are turned off, the framebuffer should switch back
389 // to the mirrored size.
390 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
391 OutputConfigurator::kSetDisplayPowerNoFlags);
392 EXPECT_EQ(JoinActions(kGrab,
393 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
394 outputs_[0].crtc, outputs_[1].crtc).c_str(),
395 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
396 outputs_[0].output).c_str(),
397 GetCrtcAction(outputs_[1].crtc, 0, 0, 0,
398 outputs_[1].output).c_str(),
399 kUngrab, NULL),
400 delegate_->GetActionsAndClear());
401
402 // Turn all displays on and check that mirroring is still used.
403 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
404 OutputConfigurator::kSetDisplayPowerNoFlags);
405 EXPECT_EQ(JoinActions(kGrab,
406 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
407 outputs_[0].crtc, outputs_[1].crtc).c_str(),
408 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
409 outputs_[0].output).c_str(),
410 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
411 outputs_[1].output).c_str(),
412 kForceDPMS, kUngrab, NULL),
413 delegate_->GetActionsAndClear());
414}
415
416TEST_F(OutputConfiguratorTest, SuspendAndResume) {
417 InitWithSingleOutput();
418
419 // No preparation is needed before suspending when the display is already
420 // on. The configurator should still reprobe on resume in case a display
421 // was connected while suspended.
422 configurator_.SuspendDisplays();
423 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
424 configurator_.ResumeDisplays();
425 EXPECT_EQ(JoinActions(kGrab,
426 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
427 outputs_[0].crtc, 0).c_str(),
428 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
429 outputs_[0].output).c_str(),
430 kForceDPMS, kUngrab, NULL),
431 delegate_->GetActionsAndClear());
432
433 // Now turn the display off before suspending and check that the
434 // configurator turns it back on and syncs with the server.
435 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
436 OutputConfigurator::kSetDisplayPowerNoFlags);
437 EXPECT_EQ(JoinActions(kGrab,
438 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
439 outputs_[0].crtc, 0).c_str(),
440 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
441 outputs_[0].output).c_str(),
442 kUngrab, NULL),
443 delegate_->GetActionsAndClear());
444
445 configurator_.SuspendDisplays();
446 EXPECT_EQ(JoinActions(kGrab,
447 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
448 outputs_[0].crtc, 0).c_str(),
449 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
450 outputs_[0].output).c_str(),
451 kForceDPMS, kUngrab, kSync, NULL),
452 delegate_->GetActionsAndClear());
453
454 configurator_.ResumeDisplays();
455 EXPECT_EQ(JoinActions(kGrab,
456 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
457 outputs_[0].crtc, 0).c_str(),
458 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
459 outputs_[0].output).c_str(),
460 kForceDPMS, kUngrab, NULL),
461 delegate_->GetActionsAndClear());
462
463 // If a second, external display is connected, the displays shouldn't be
464 // powered back on before suspending.
465 UpdateOutputs(2);
466 state_controller_.set_state(STATE_DUAL_MIRROR);
467 EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
468 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
469 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
470 outputs_[0].crtc, outputs_[1].crtc).c_str(),
471 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
472 outputs_[0].output).c_str(),
473 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
474 outputs_[1].output).c_str(),
475 kUngrab, kProjectingOn, NULL),
476 delegate_->GetActionsAndClear());
477
478 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
479 OutputConfigurator::kSetDisplayPowerNoFlags);
480 EXPECT_EQ(JoinActions(kGrab,
481 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
482 outputs_[0].crtc, outputs_[1].crtc).c_str(),
483 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
484 outputs_[0].output).c_str(),
485 GetCrtcAction(outputs_[1].crtc, 0, 0, 0,
486 outputs_[1].output).c_str(),
487 kUngrab, NULL),
488 delegate_->GetActionsAndClear());
489
490 configurator_.SuspendDisplays();
491 EXPECT_EQ(JoinActions(kGrab, kUngrab, kSync, NULL),
492 delegate_->GetActionsAndClear());
493
494 // If a display is disconnected while resuming, the configurator should
495 // pick up the change.
496 UpdateOutputs(1);
497 configurator_.ResumeDisplays();
498 EXPECT_EQ(JoinActions(kGrab,
499 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
500 outputs_[0].crtc, 0).c_str(),
501 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
502 outputs_[0].output).c_str(),
503 kUngrab, NULL),
504 delegate_->GetActionsAndClear());
505}
506
507TEST_F(OutputConfiguratorTest, Headless) {
508 UpdateOutputs(0);
509 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
510 configurator_.Init(false, 0);
511 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), delegate_->GetActionsAndClear());
512 configurator_.Start();
513 EXPECT_EQ(JoinActions(kGrab, kInitXRandR, kForceDPMS, kUngrab,
514 kProjectingOff, NULL),
515 delegate_->GetActionsAndClear());
516
517 // Not much should happen when the display power state is changed while
518 // no displays are connected.
519 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
520 OutputConfigurator::kSetDisplayPowerNoFlags);
521 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), delegate_->GetActionsAndClear());
522 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
523 OutputConfigurator::kSetDisplayPowerNoFlags);
524 EXPECT_EQ(JoinActions(kGrab, kForceDPMS, kUngrab, NULL),
525 delegate_->GetActionsAndClear());
526
527 // Connect an external display and check that it's configured correctly.
528 outputs_[0].is_internal = false;
529 outputs_[0].native_mode = kBigModeId;
530 UpdateOutputs(1);
531 EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
532 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
533 GetFramebufferAction(kBigModeWidth, kBigModeHeight,
534 outputs_[0].crtc, 0).c_str(),
535 GetCrtcAction(outputs_[0].crtc, 0, 0, kBigModeId,
536 outputs_[0].output).c_str(),
537 kUngrab, kProjectingOff, NULL),
538 delegate_->GetActionsAndClear());
539}
540
541TEST_F(OutputConfiguratorTest, StartWithTwoOutputs) {
542 UpdateOutputs(2);
543 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
544 configurator_.Init(false, 0);
545 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), delegate_->GetActionsAndClear());
546
547 state_controller_.set_state(STATE_DUAL_MIRROR);
548 configurator_.Start();
549 EXPECT_EQ(JoinActions(kGrab, kInitXRandR,
550 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
551 outputs_[0].crtc, outputs_[1].crtc).c_str(),
552 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
553 outputs_[0].output).c_str(),
554 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
555 outputs_[1].output).c_str(),
556 kForceDPMS, kUngrab, kProjectingOn, NULL),
557 delegate_->GetActionsAndClear());
558}
559
560TEST_F(OutputConfiguratorTest, InvalidOutputStates) {
561 UpdateOutputs(0);
562 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
563 configurator_.Init(false, 0);
564 configurator_.Start();
565 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_HEADLESS));
566 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_SINGLE));
567 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
568 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
569
570 UpdateOutputs(1);
571 EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
572 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_HEADLESS));
573 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_SINGLE));
574 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
575 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
576
577 UpdateOutputs(2);
578 state_controller_.set_state(STATE_DUAL_EXTENDED);
579 EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
580 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_HEADLESS));
581 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_SINGLE));
582 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
583 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
584}
585
[email protected]2c8a0aa72013-05-16 06:24:48586TEST_F(OutputConfiguratorTest, GetOutputStateForDisplays) {
587 outputs_[0].has_display_id = false;
588 UpdateOutputs(2);
589
590 configurator_.Init(false, 0);
591 configurator_.Start();
592
593 state_controller_.set_state(STATE_DUAL_MIRROR);
594 test_api_.SendOutputChangeEvents(true);
595 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
596
597 outputs_[0].has_display_id = true;
598 UpdateOutputs(2);
599 test_api_.SendOutputChangeEvents(true);
600 EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
601}
602
[email protected]6d980bc2012-09-10 19:28:45603} // namespace chromeos