Merge lp:~afrantzis/unity-system-compositor/dbus-active-outputs into lp:unity-system-compositor
- dbus-active-outputs
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Alexandros Frantzis |
Approved revision: | 307 |
Merged at revision: | 307 |
Proposed branch: | lp:~afrantzis/unity-system-compositor/dbus-active-outputs |
Merge into: | lp:unity-system-compositor |
Diff against target: |
1233 lines (+794/-86) 13 files modified
src/com.canonical.Unity.Display.xml (+31/-1) src/mir_screen.cpp (+153/-19) src/mir_screen.h (+32/-6) src/screen.h (+23/-2) src/server.cpp (+6/-1) src/unity_display_service.cpp (+179/-12) src/unity_display_service.h (+9/-2) tests/include/usc/test/mock_screen.h (+3/-2) tests/include/usc/test/stub_display_configuration.h (+55/-7) tests/integration-tests/test_unity_display_service.cpp (+148/-9) tests/integration-tests/unity_display_dbus_client.cpp (+47/-2) tests/integration-tests/unity_display_dbus_client.h (+6/-2) tests/unit-tests/test_mir_screen.cpp (+102/-21) |
To merge this branch: | bzr merge lp:~afrantzis/unity-system-compositor/dbus-active-outputs |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mir CI Bot | continuous-integration | Approve | |
Unity System Compositor Development Team | Pending | ||
Review via email: mp+316443@code.launchpad.net |
Commit message
Update the Unity.Display DBus interface to support multiple outputs better
Description of the change
Update the Unity.Display DBus interface to support multiple outputs better
Mir CI Bot (mir-ci-bot) wrote : | # |
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:307
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Preview Diff
1 | === modified file 'src/com.canonical.Unity.Display.xml' |
2 | --- src/com.canonical.Unity.Display.xml 2016-04-15 08:40:54 +0000 |
3 | +++ src/com.canonical.Unity.Display.xml 2017-02-06 11:51:56 +0000 |
4 | @@ -2,9 +2,39 @@ |
5 | <node> |
6 | <interface name='com.canonical.Unity.Display'> |
7 | <method name='TurnOn'> |
8 | + <arg type="s" name="what" direction="in"/> |
9 | </method> |
10 | <method name='TurnOff'> |
11 | + <arg type="s" name="what" direction="in"/> |
12 | + </method> |
13 | + <property name='ActiveOutputs' type='(ii)' access='read'/> |
14 | + </interface> |
15 | + |
16 | + <interface name="org.freedesktop.DBus.Properties"> |
17 | + <method name="Get"> |
18 | + <arg type="s" name="interface_name" direction="in"/> |
19 | + <arg type="s" name="property_name" direction="in"/> |
20 | + <arg type="v" name="value" direction="out"/> |
21 | + </method> |
22 | + <method name="GetAll"> |
23 | + <arg type="s" name="interface_name" direction="in"/> |
24 | + <arg type="a{sv}" name="properties" direction="out"/> |
25 | + </method> |
26 | + <method name="Set"> |
27 | + <arg type="s" name="interface_name" direction="in"/> |
28 | + <arg type="s" name="property_name" direction="in"/> |
29 | + <arg type="v" name="value" direction="in"/> |
30 | + </method> |
31 | + <signal name="PropertiesChanged"> |
32 | + <arg type="s" name="interface_name"/> |
33 | + <arg type="a{sv}" name="changed_properties"/> |
34 | + <arg type="as" name="invalidated_properties"/> |
35 | + </signal> |
36 | + </interface> |
37 | + |
38 | + <interface name="org.freedesktop.DBus.Introspectable"> |
39 | + <method name="Introspect"> |
40 | + <arg type="s" name="xml_data" direction="out"/> |
41 | </method> |
42 | </interface> |
43 | </node> |
44 | - |
45 | |
46 | === modified file 'src/mir_screen.cpp' |
47 | --- src/mir_screen.cpp 2016-08-12 14:08:22 +0000 |
48 | +++ src/mir_screen.cpp 2017-02-06 11:51:56 +0000 |
49 | @@ -42,6 +42,82 @@ |
50 | mir::report_exception(buffer); |
51 | mir::log(::mir::logging::Severity::warning, "usc::MirScreen", warning_format, func, buffer.str().c_str()); |
52 | } |
53 | + |
54 | +bool is_external(mir::graphics::DisplayConfigurationOutputType type) |
55 | +{ |
56 | + using mir::graphics::DisplayConfigurationOutputType; |
57 | + |
58 | + return type == DisplayConfigurationOutputType::vga || |
59 | + type == DisplayConfigurationOutputType::dvii || |
60 | + type == DisplayConfigurationOutputType::dvid || |
61 | + type == DisplayConfigurationOutputType::dvia || |
62 | + type == DisplayConfigurationOutputType::composite || |
63 | + type == DisplayConfigurationOutputType::svideo || |
64 | + type == DisplayConfigurationOutputType::component || |
65 | + type == DisplayConfigurationOutputType::ninepindin || |
66 | + type == DisplayConfigurationOutputType::displayport || |
67 | + type == DisplayConfigurationOutputType::hdmia || |
68 | + type == DisplayConfigurationOutputType::hdmib || |
69 | + type == DisplayConfigurationOutputType::tv; |
70 | +} |
71 | + |
72 | +usc::ActiveOutputs count_active_outputs( |
73 | + mir::graphics::DisplayConfiguration const& display_configuration) |
74 | +{ |
75 | + usc::ActiveOutputs active_outputs{}; |
76 | + |
77 | + display_configuration.for_each_output( |
78 | + [&active_outputs](mir::graphics::DisplayConfigurationOutput const& output) |
79 | + { |
80 | + if (output.connected && |
81 | + output.used && |
82 | + output.power_mode == MirPowerMode::mir_power_mode_on) |
83 | + { |
84 | + if (is_external(output.type)) |
85 | + ++active_outputs.external; |
86 | + else |
87 | + ++active_outputs.internal; |
88 | + } |
89 | + }); |
90 | + |
91 | + return active_outputs; |
92 | +} |
93 | + |
94 | +bool has_active_outputs( |
95 | + mir::graphics::DisplayConfiguration const& display_configuration) |
96 | +{ |
97 | + auto const active_outputs = count_active_outputs(display_configuration); |
98 | + return active_outputs.internal + active_outputs.external > 0; |
99 | +} |
100 | + |
101 | +bool all_outputs_filter(mir::graphics::UserDisplayConfigurationOutput const&) |
102 | +{ |
103 | + return true; |
104 | +} |
105 | + |
106 | +bool internal_outputs_filter(mir::graphics::UserDisplayConfigurationOutput const& output) |
107 | +{ |
108 | + return !is_external(output.type); |
109 | +} |
110 | + |
111 | +bool external_outputs_filter(mir::graphics::UserDisplayConfigurationOutput const& output) |
112 | +{ |
113 | + return is_external(output.type); |
114 | +} |
115 | + |
116 | +auto get_power_mode_filter_for_output_filter(usc::OutputFilter output_filter) |
117 | +{ |
118 | + switch (output_filter) |
119 | + { |
120 | + case usc::OutputFilter::all: return all_outputs_filter; |
121 | + case usc::OutputFilter::internal: return internal_outputs_filter; |
122 | + case usc::OutputFilter::external: return external_outputs_filter; |
123 | + default: return all_outputs_filter; |
124 | + } |
125 | + |
126 | + return all_outputs_filter; |
127 | +} |
128 | + |
129 | } |
130 | |
131 | usc::MirScreen::MirScreen( |
132 | @@ -49,7 +125,7 @@ |
133 | std::shared_ptr<mir::graphics::Display> const& display) |
134 | : compositor{compositor}, |
135 | display{display}, |
136 | - current_power_mode{MirPowerMode::mir_power_mode_on} |
137 | + active_outputs_handler{[](ActiveOutputs const&){}} |
138 | { |
139 | try |
140 | { |
141 | @@ -69,27 +145,87 @@ |
142 | |
143 | usc::MirScreen::~MirScreen() = default; |
144 | |
145 | -void usc::MirScreen::turn_on() |
146 | -{ |
147 | - set_power_mode(MirPowerMode::mir_power_mode_on); |
148 | -} |
149 | - |
150 | -void usc::MirScreen::turn_off() |
151 | -{ |
152 | - set_power_mode(MirPowerMode::mir_power_mode_off); |
153 | -} |
154 | - |
155 | -void usc::MirScreen::set_power_mode(MirPowerMode mode) |
156 | +void usc::MirScreen::turn_on(OutputFilter output_filter) |
157 | +{ |
158 | + auto const filter_func = get_power_mode_filter_for_output_filter(output_filter); |
159 | + set_power_mode(MirPowerMode::mir_power_mode_on, filter_func); |
160 | +} |
161 | + |
162 | +void usc::MirScreen::turn_off(OutputFilter output_filter) |
163 | +{ |
164 | + auto const filter_func = get_power_mode_filter_for_output_filter(output_filter); |
165 | + set_power_mode(MirPowerMode::mir_power_mode_off, filter_func); |
166 | +} |
167 | + |
168 | +void usc::MirScreen::register_active_outputs_handler( |
169 | + ActiveOutputsHandler const& handler) |
170 | +{ |
171 | + // It's not ideal to call the handler under lock, but we need this to |
172 | + // guarantee that after this function returns no invocation of the old |
173 | + // handler will be in progress. Alternatively, we would need to implement |
174 | + // an event loop. |
175 | + std::lock_guard<std::mutex> lock{active_outputs_mutex}; |
176 | + active_outputs_handler = handler; |
177 | + active_outputs_handler(active_outputs); |
178 | +} |
179 | + |
180 | +void usc::MirScreen::initial_configuration( |
181 | + std::shared_ptr<mir::graphics::DisplayConfiguration const> const& display_configuration) |
182 | +{ |
183 | + std::lock_guard<std::mutex> lock{active_outputs_mutex}; |
184 | + active_outputs = count_active_outputs(*display_configuration); |
185 | + active_outputs_handler(active_outputs); |
186 | +} |
187 | + |
188 | +void usc::MirScreen::configuration_applied( |
189 | + std::shared_ptr<mir::graphics::DisplayConfiguration const> const& display_configuration) |
190 | +{ |
191 | + std::lock_guard<std::mutex> lock{active_outputs_mutex}; |
192 | + active_outputs = count_active_outputs(*display_configuration); |
193 | + active_outputs_handler(active_outputs); |
194 | +} |
195 | + |
196 | +void usc::MirScreen::base_configuration_updated( |
197 | + std::shared_ptr<mir::graphics::DisplayConfiguration const> const&) |
198 | +{ |
199 | +} |
200 | + |
201 | +void usc::MirScreen::session_configuration_applied( |
202 | + std::shared_ptr<mir::frontend::Session> const&, |
203 | + std::shared_ptr<mir::graphics::DisplayConfiguration> const&) |
204 | +{ |
205 | +} |
206 | + |
207 | +void usc::MirScreen::session_configuration_removed( |
208 | + std::shared_ptr<mir::frontend::Session> const&) |
209 | +{ |
210 | +} |
211 | + |
212 | +void usc::MirScreen::configuration_failed( |
213 | + std::shared_ptr<mir::graphics::DisplayConfiguration const> const&, |
214 | + std::exception const&) |
215 | +{ |
216 | +} |
217 | + |
218 | +void usc::MirScreen::catastrophic_configuration_error( |
219 | + std::shared_ptr<mir::graphics::DisplayConfiguration const> const&, |
220 | + std::exception const&) |
221 | +{ |
222 | +} |
223 | + |
224 | +void usc::MirScreen::set_power_mode(MirPowerMode mode, SetPowerModeFilter const& filter) |
225 | try |
226 | { |
227 | - if (current_power_mode == mode) |
228 | - return; |
229 | - |
230 | std::shared_ptr<mg::DisplayConfiguration> displayConfig = display->configuration(); |
231 | |
232 | displayConfig->for_each_output( |
233 | [&](const mg::UserDisplayConfigurationOutput displayConfigOutput) { |
234 | - displayConfigOutput.power_mode = mode; |
235 | + if (displayConfigOutput.connected && |
236 | + displayConfigOutput.used && |
237 | + filter(displayConfigOutput)) |
238 | + { |
239 | + displayConfigOutput.power_mode = mode; |
240 | + } |
241 | } |
242 | ); |
243 | |
244 | @@ -97,10 +233,8 @@ |
245 | |
246 | display->configure(*displayConfig.get()); |
247 | |
248 | - if (mode == MirPowerMode::mir_power_mode_on) |
249 | + if (has_active_outputs(*displayConfig)) |
250 | compositor->start(); |
251 | - |
252 | - current_power_mode = mode; |
253 | } |
254 | catch (std::exception const&) |
255 | { |
256 | |
257 | === modified file 'src/mir_screen.h' |
258 | --- src/mir_screen.h 2016-08-12 14:08:22 +0000 |
259 | +++ src/mir_screen.h 2017-02-06 11:51:56 +0000 |
260 | @@ -17,6 +17,7 @@ |
261 | #ifndef USC_MIR_SCREEN_H_ |
262 | #define USC_MIR_SCREEN_H_ |
263 | |
264 | +#include <mir/graphics/display_configuration_observer.h> |
265 | #include "screen.h" |
266 | |
267 | #include <chrono> |
268 | @@ -26,29 +27,54 @@ |
269 | namespace mir |
270 | { |
271 | namespace compositor { class Compositor; } |
272 | -namespace graphics {class Display;} |
273 | +namespace graphics {class Display; struct UserDisplayConfigurationOutput;} |
274 | } |
275 | |
276 | namespace usc |
277 | { |
278 | |
279 | -class MirScreen: public Screen |
280 | +class MirScreen: public Screen, public mir::graphics::DisplayConfigurationObserver |
281 | { |
282 | public: |
283 | MirScreen(std::shared_ptr<mir::compositor::Compositor> const& compositor, |
284 | std::shared_ptr<mir::graphics::Display> const& display); |
285 | ~MirScreen(); |
286 | |
287 | - void turn_on(); |
288 | - void turn_off(); |
289 | + // From Screen |
290 | + void turn_on(OutputFilter output_filter) override; |
291 | + void turn_off(OutputFilter output_filter) override; |
292 | + void register_active_outputs_handler(ActiveOutputsHandler const& handler) override; |
293 | + |
294 | + // From DisplayConfigurationObserver |
295 | + void initial_configuration( |
296 | + std::shared_ptr<mir::graphics::DisplayConfiguration const> const& display_configuration) override; |
297 | + void configuration_applied( |
298 | + std::shared_ptr<mir::graphics::DisplayConfiguration const> const& display_configuration) override; |
299 | + |
300 | + void base_configuration_updated( |
301 | + std::shared_ptr<mir::graphics::DisplayConfiguration const> const&) override; |
302 | + void session_configuration_applied( |
303 | + std::shared_ptr<mir::frontend::Session> const&, |
304 | + std::shared_ptr<mir::graphics::DisplayConfiguration> const&) override; |
305 | + void session_configuration_removed( |
306 | + std::shared_ptr<mir::frontend::Session> const&) override; |
307 | + void configuration_failed( |
308 | + std::shared_ptr<mir::graphics::DisplayConfiguration const> const&, |
309 | + std::exception const&) override; |
310 | + void catastrophic_configuration_error( |
311 | + std::shared_ptr<mir::graphics::DisplayConfiguration const> const&, |
312 | + std::exception const&) override; |
313 | |
314 | private: |
315 | - void set_power_mode(MirPowerMode mode); |
316 | + using SetPowerModeFilter = bool(*)(mir::graphics::UserDisplayConfigurationOutput const&); |
317 | + void set_power_mode(MirPowerMode mode, SetPowerModeFilter const& filter); |
318 | |
319 | std::shared_ptr<mir::compositor::Compositor> const compositor; |
320 | std::shared_ptr<mir::graphics::Display> const display; |
321 | |
322 | - MirPowerMode current_power_mode; |
323 | + std::mutex active_outputs_mutex; |
324 | + ActiveOutputsHandler active_outputs_handler; |
325 | + ActiveOutputs active_outputs; |
326 | }; |
327 | |
328 | } |
329 | |
330 | === modified file 'src/screen.h' |
331 | --- src/screen.h 2016-04-15 08:40:54 +0000 |
332 | +++ src/screen.h 2017-02-06 11:51:56 +0000 |
333 | @@ -23,13 +23,34 @@ |
334 | namespace usc |
335 | { |
336 | |
337 | +struct ActiveOutputs |
338 | +{ |
339 | + ActiveOutputs(int i, int e) : internal{i}, external{e} {} |
340 | + ActiveOutputs() : ActiveOutputs{0, 0} {} |
341 | + |
342 | + bool operator==(ActiveOutputs const& other) const |
343 | + { |
344 | + return internal == other.internal && |
345 | + external == other.external; |
346 | + } |
347 | + |
348 | + int internal; |
349 | + int external; |
350 | +}; |
351 | + |
352 | +using ActiveOutputsHandler = std::function<void(ActiveOutputs const&)>; |
353 | + |
354 | +enum class OutputFilter { all, internal, external }; |
355 | + |
356 | class Screen |
357 | { |
358 | public: |
359 | virtual ~Screen() = default; |
360 | |
361 | - virtual void turn_on() = 0; |
362 | - virtual void turn_off() = 0; |
363 | + virtual void turn_on(OutputFilter filter) = 0; |
364 | + virtual void turn_off(OutputFilter filter) = 0; |
365 | + virtual void register_active_outputs_handler( |
366 | + ActiveOutputsHandler const& handler) = 0; |
367 | |
368 | protected: |
369 | Screen() = default; |
370 | |
371 | === modified file 'src/server.cpp' |
372 | --- src/server.cpp 2016-11-09 19:12:16 +0000 |
373 | +++ src/server.cpp 2017-02-06 11:51:56 +0000 |
374 | @@ -43,6 +43,7 @@ |
375 | #include <mir/log.h> |
376 | #include <mir/abnormal_exit.h> |
377 | #include <mir/main_loop.h> |
378 | +#include <mir/observer_registrar.h> |
379 | |
380 | #include <boost/exception/all.hpp> |
381 | |
382 | @@ -292,9 +293,13 @@ |
383 | return screen( |
384 | [this] |
385 | { |
386 | - return std::make_shared<MirScreen>( |
387 | + auto mir_screen = std::make_shared<MirScreen>( |
388 | the_compositor(), |
389 | the_display()); |
390 | + |
391 | + the_display_configuration_observer_registrar()->register_interest(mir_screen); |
392 | + |
393 | + return mir_screen; |
394 | }); |
395 | } |
396 | |
397 | |
398 | === modified file 'src/unity_display_service.cpp' |
399 | --- src/unity_display_service.cpp 2016-04-15 08:40:54 +0000 |
400 | +++ src/unity_display_service.cpp 2017-02-06 11:51:56 +0000 |
401 | @@ -32,6 +32,48 @@ |
402 | char const* const dbus_display_path = "/com/canonical/Unity/Display"; |
403 | char const* const dbus_display_service_name = "com.canonical.Unity.Display"; |
404 | |
405 | +void usc_dbus_message_iter_append_active_outputs_variant( |
406 | + DBusMessageIter* iter, usc::ActiveOutputs const& active_outputs) |
407 | +{ |
408 | + DBusMessageIter iter_variant; |
409 | + dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "(ii)", &iter_variant); |
410 | + |
411 | + { |
412 | + DBusMessageIter iter_struct; |
413 | + dbus_message_iter_open_container(&iter_variant, DBUS_TYPE_STRUCT, nullptr, &iter_struct); |
414 | + |
415 | + dbus_message_iter_append_basic(&iter_struct, DBUS_TYPE_INT32, &active_outputs.internal); |
416 | + dbus_message_iter_append_basic(&iter_struct, DBUS_TYPE_INT32, &active_outputs.external); |
417 | + |
418 | + dbus_message_iter_close_container(&iter_variant, &iter_struct); |
419 | + } |
420 | + |
421 | + dbus_message_iter_close_container(iter, &iter_variant); |
422 | +} |
423 | + |
424 | +void usc_dbus_message_iter_append_active_outputs_dict_entry( |
425 | + DBusMessageIter* iter, usc::ActiveOutputs const& active_outputs) |
426 | +{ |
427 | + char const* key = "ActiveOutputs"; |
428 | + DBusMessageIter iter_entry; |
429 | + dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, nullptr, &iter_entry); |
430 | + |
431 | + dbus_message_iter_append_basic(&iter_entry, DBUS_TYPE_STRING, &key); |
432 | + usc_dbus_message_iter_append_active_outputs_variant(&iter_entry, active_outputs); |
433 | + |
434 | + dbus_message_iter_close_container(iter, &iter_entry); |
435 | +} |
436 | + |
437 | +usc::OutputFilter output_filter_from_string(std::string const& filter_str) |
438 | +{ |
439 | + if (filter_str == "internal") |
440 | + return usc::OutputFilter::internal; |
441 | + else if (filter_str == "external") |
442 | + return usc::OutputFilter::external; |
443 | + |
444 | + return usc::OutputFilter::all; |
445 | +} |
446 | + |
447 | } |
448 | |
449 | usc::UnityDisplayService::UnityDisplayService( |
450 | @@ -45,6 +87,22 @@ |
451 | loop->add_connection(connection); |
452 | connection->request_name(dbus_display_service_name); |
453 | connection->add_filter(handle_dbus_message_thunk, this); |
454 | + |
455 | + screen->register_active_outputs_handler( |
456 | + [this] (ActiveOutputs const& active_outputs_arg) |
457 | + { |
458 | + this->loop->enqueue( |
459 | + [this, active_outputs_arg] |
460 | + { |
461 | + active_outputs = active_outputs_arg; |
462 | + dbus_emit_ActiveOutputs(); |
463 | + }); |
464 | + }); |
465 | +} |
466 | + |
467 | +usc::UnityDisplayService::~UnityDisplayService() |
468 | +{ |
469 | + screen->register_active_outputs_handler([](ActiveOutputs const&){}); |
470 | } |
471 | |
472 | ::DBusHandlerResult usc::UnityDisplayService::handle_dbus_message_thunk( |
473 | @@ -70,16 +128,69 @@ |
474 | } |
475 | else if (dbus_message_is_method_call(message, dbus_display_interface, "TurnOn")) |
476 | { |
477 | - dbus_TurnOn(); |
478 | + char const* filter{""}; |
479 | + dbus_message_get_args( |
480 | + message, &args_error, |
481 | + DBUS_TYPE_STRING, &filter, |
482 | + DBUS_TYPE_INVALID); |
483 | + |
484 | + // For backward compatibility |
485 | + if (args_error) |
486 | + filter = "all"; |
487 | + |
488 | + dbus_TurnOn(filter); |
489 | |
490 | DBusMessageHandle reply{dbus_message_new_method_return(message)}; |
491 | dbus_connection_send(connection, reply, nullptr); |
492 | } |
493 | else if (dbus_message_is_method_call(message, dbus_display_interface, "TurnOff")) |
494 | { |
495 | - dbus_TurnOff(); |
496 | - |
497 | - DBusMessageHandle reply{dbus_message_new_method_return(message)}; |
498 | + char const* filter{""}; |
499 | + |
500 | + dbus_message_get_args( |
501 | + message, &args_error, |
502 | + DBUS_TYPE_STRING, &filter, |
503 | + DBUS_TYPE_INVALID); |
504 | + |
505 | + // For backward compatibility |
506 | + if (args_error) |
507 | + filter = "all"; |
508 | + |
509 | + dbus_TurnOff(filter); |
510 | + |
511 | + DBusMessageHandle reply{dbus_message_new_method_return(message)}; |
512 | + dbus_connection_send(connection, reply, nullptr); |
513 | + } |
514 | + else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Get")) |
515 | + { |
516 | + char const* interface{""}; |
517 | + char const* property{""}; |
518 | + dbus_message_get_args( |
519 | + message, &args_error, |
520 | + DBUS_TYPE_STRING, &interface, |
521 | + DBUS_TYPE_STRING, &property, |
522 | + DBUS_TYPE_INVALID); |
523 | + |
524 | + DBusMessageHandle reply{dbus_message_new_method_return(message)}; |
525 | + |
526 | + if (!args_error && std::string{interface} == dbus_display_interface) |
527 | + dbus_properties_Get(reply, property); |
528 | + |
529 | + dbus_connection_send(connection, reply, nullptr); |
530 | + } |
531 | + else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "GetAll")) |
532 | + { |
533 | + char const* interface{""}; |
534 | + dbus_message_get_args( |
535 | + message, &args_error, |
536 | + DBUS_TYPE_STRING, &interface, |
537 | + DBUS_TYPE_INVALID); |
538 | + |
539 | + DBusMessageHandle reply{dbus_message_new_method_return(message)}; |
540 | + |
541 | + if (!args_error && std::string{interface} == dbus_display_interface) |
542 | + dbus_properties_GetAll(reply); |
543 | + |
544 | dbus_connection_send(connection, reply, nullptr); |
545 | } |
546 | else if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL) |
547 | @@ -101,12 +212,68 @@ |
548 | return DBUS_HANDLER_RESULT_HANDLED; |
549 | } |
550 | |
551 | -void usc::UnityDisplayService::dbus_TurnOn() |
552 | -{ |
553 | - screen->turn_on(); |
554 | -} |
555 | - |
556 | -void usc::UnityDisplayService::dbus_TurnOff() |
557 | -{ |
558 | - screen->turn_off(); |
559 | +void usc::UnityDisplayService::dbus_TurnOn(std::string const& filter) |
560 | +{ |
561 | + screen->turn_on(output_filter_from_string(filter)); |
562 | +} |
563 | + |
564 | +void usc::UnityDisplayService::dbus_TurnOff(std::string const& filter) |
565 | +{ |
566 | + screen->turn_off(output_filter_from_string(filter)); |
567 | +} |
568 | + |
569 | +void usc::UnityDisplayService::dbus_emit_ActiveOutputs() |
570 | +{ |
571 | + DBusMessageHandle signal{ |
572 | + dbus_message_new_signal( |
573 | + dbus_display_path, |
574 | + "org.freedesktop.DBus.Properties", |
575 | + "PropertiesChanged")}; |
576 | + |
577 | + DBusMessageIter iter; |
578 | + dbus_message_iter_init_append(signal, &iter); |
579 | + |
580 | + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &dbus_display_interface); |
581 | + |
582 | + { |
583 | + DBusMessageIter iter_dict; |
584 | + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &iter_dict); |
585 | + |
586 | + usc_dbus_message_iter_append_active_outputs_dict_entry(&iter_dict, active_outputs); |
587 | + |
588 | + dbus_message_iter_close_container(&iter, &iter_dict); |
589 | + } |
590 | + |
591 | + { |
592 | + DBusMessageIter iter_array; |
593 | + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &iter_array); |
594 | + dbus_message_iter_close_container(&iter, &iter_array); |
595 | + } |
596 | + |
597 | + dbus_connection_send(*connection, signal, nullptr); |
598 | + dbus_connection_flush(*connection); |
599 | +} |
600 | + |
601 | +void usc::UnityDisplayService::dbus_properties_Get(DBusMessage* reply, std::string const& property) |
602 | +{ |
603 | + DBusMessageIter iter; |
604 | + dbus_message_iter_init_append(reply, &iter); |
605 | + |
606 | + if (property == "ActiveOutputs") |
607 | + usc_dbus_message_iter_append_active_outputs_variant(&iter, active_outputs); |
608 | +} |
609 | + |
610 | +void usc::UnityDisplayService::dbus_properties_GetAll(DBusMessage* reply) |
611 | +{ |
612 | + DBusMessageIter iter; |
613 | + dbus_message_iter_init_append(reply, &iter); |
614 | + |
615 | + { |
616 | + DBusMessageIter iter_dict; |
617 | + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &iter_dict); |
618 | + |
619 | + usc_dbus_message_iter_append_active_outputs_dict_entry(&iter_dict, active_outputs); |
620 | + |
621 | + dbus_message_iter_close_container(&iter, &iter_dict); |
622 | + } |
623 | } |
624 | |
625 | === modified file 'src/unity_display_service.h' |
626 | --- src/unity_display_service.h 2016-04-15 08:40:54 +0000 |
627 | +++ src/unity_display_service.h 2017-02-06 11:51:56 +0000 |
628 | @@ -20,8 +20,10 @@ |
629 | #define USC_UNITY_DISPLAY_SERVICE_H_ |
630 | |
631 | #include "dbus_connection_handle.h" |
632 | +#include "screen.h" |
633 | |
634 | #include <memory> |
635 | +#include <string> |
636 | |
637 | namespace usc |
638 | { |
639 | @@ -35,6 +37,7 @@ |
640 | std::shared_ptr<usc::DBusEventLoop> const& loop, |
641 | std::string const& address, |
642 | std::shared_ptr<usc::Screen> const& screen); |
643 | + ~UnityDisplayService(); |
644 | |
645 | private: |
646 | static ::DBusHandlerResult handle_dbus_message_thunk( |
647 | @@ -42,12 +45,16 @@ |
648 | ::DBusHandlerResult handle_dbus_message( |
649 | DBusConnection* connection, DBusMessage* message, void* user_data); |
650 | |
651 | - void dbus_TurnOn(); |
652 | - void dbus_TurnOff(); |
653 | + void dbus_TurnOn(std::string const& filter); |
654 | + void dbus_TurnOff(std::string const& filter); |
655 | + void dbus_emit_ActiveOutputs(); |
656 | + void dbus_properties_Get(DBusMessage* reply, std::string const& property); |
657 | + void dbus_properties_GetAll(DBusMessage* reply); |
658 | |
659 | std::shared_ptr<usc::Screen> const screen; |
660 | std::shared_ptr<DBusEventLoop> const loop; |
661 | std::shared_ptr<DBusConnectionHandle> connection; |
662 | + ActiveOutputs active_outputs; |
663 | }; |
664 | |
665 | } |
666 | |
667 | === modified file 'tests/include/usc/test/mock_screen.h' |
668 | --- tests/include/usc/test/mock_screen.h 2016-04-18 14:58:36 +0000 |
669 | +++ tests/include/usc/test/mock_screen.h 2017-02-06 11:51:56 +0000 |
670 | @@ -31,8 +31,9 @@ |
671 | |
672 | struct MockScreen : usc::Screen |
673 | { |
674 | - MOCK_METHOD0(turn_on, void()); |
675 | - MOCK_METHOD0(turn_off, void()); |
676 | + MOCK_METHOD1(turn_on, void(OutputFilter)); |
677 | + MOCK_METHOD1(turn_off, void(OutputFilter)); |
678 | + MOCK_METHOD1(register_active_outputs_handler, void(ActiveOutputsHandler const&)); |
679 | }; |
680 | |
681 | } |
682 | |
683 | === modified file 'tests/include/usc/test/stub_display_configuration.h' |
684 | --- tests/include/usc/test/stub_display_configuration.h 2015-11-12 14:21:24 +0000 |
685 | +++ tests/include/usc/test/stub_display_configuration.h 2017-02-06 11:51:56 +0000 |
686 | @@ -28,12 +28,36 @@ |
687 | { |
688 | StubDisplayConfiguration() |
689 | { |
690 | - conf_output.power_mode = MirPowerMode::mir_power_mode_on; |
691 | + internal_active_conf_output.power_mode = MirPowerMode::mir_power_mode_on; |
692 | + internal_active_conf_output.type = mir::graphics::DisplayConfigurationOutputType::lvds; |
693 | + internal_active_conf_output.used = true; |
694 | + internal_active_conf_output.connected = true; |
695 | + |
696 | + external_active_conf_output.power_mode = MirPowerMode::mir_power_mode_on; |
697 | + external_active_conf_output.type = mir::graphics::DisplayConfigurationOutputType::dvid; |
698 | + external_active_conf_output.used = true; |
699 | + external_active_conf_output.connected = true; |
700 | + |
701 | + inactive_conf_output.power_mode = MirPowerMode::mir_power_mode_off; |
702 | + inactive_conf_output.used = false; |
703 | + inactive_conf_output.connected = false; |
704 | + } |
705 | + |
706 | + StubDisplayConfiguration( |
707 | + int num_internal_active_outputs, |
708 | + int num_external_active_outputs, |
709 | + int num_inactive_outputs) |
710 | + : StubDisplayConfiguration{} |
711 | + { |
712 | + this->num_internal_active_outputs = num_internal_active_outputs; |
713 | + this->num_external_active_outputs = num_external_active_outputs; |
714 | + this->num_inactive_outputs = num_inactive_outputs; |
715 | } |
716 | |
717 | StubDisplayConfiguration(mir::graphics::DisplayConfigurationOutput const& output) |
718 | - : conf_output(output) |
719 | + : StubDisplayConfiguration{} |
720 | { |
721 | + internal_active_conf_output = output; |
722 | } |
723 | |
724 | void for_each_card(std::function<void(mir::graphics::DisplayConfigurationCard const&)>) const override |
725 | @@ -42,21 +66,45 @@ |
726 | |
727 | void for_each_output(std::function<void(mir::graphics::DisplayConfigurationOutput const&)> f) const override |
728 | { |
729 | - f(conf_output); |
730 | + for (int i = 0; i < num_internal_active_outputs; ++i) |
731 | + f(internal_active_conf_output); |
732 | + for (int i = 0; i < num_external_active_outputs; ++i) |
733 | + f(external_active_conf_output); |
734 | + for (int i = 0; i < num_inactive_outputs; ++i) |
735 | + f(inactive_conf_output); |
736 | } |
737 | |
738 | void for_each_output(std::function<void(mir::graphics::UserDisplayConfigurationOutput&)> f) |
739 | { |
740 | - mir::graphics::UserDisplayConfigurationOutput user{conf_output}; |
741 | - f(user); |
742 | + for (int i = 0; i < num_internal_active_outputs; ++i) |
743 | + { |
744 | + mir::graphics::UserDisplayConfigurationOutput user{internal_active_conf_output}; |
745 | + f(user); |
746 | + } |
747 | + for (int i = 0; i < num_external_active_outputs; ++i) |
748 | + { |
749 | + mir::graphics::UserDisplayConfigurationOutput user{external_active_conf_output}; |
750 | + f(user); |
751 | + } |
752 | + for (int i = 0; i < num_inactive_outputs; ++i) |
753 | + { |
754 | + mir::graphics::UserDisplayConfigurationOutput user{inactive_conf_output}; |
755 | + f(user); |
756 | + } |
757 | } |
758 | |
759 | std::unique_ptr<mir::graphics::DisplayConfiguration> clone() const override |
760 | { |
761 | - return std::make_unique<StubDisplayConfiguration>(conf_output); |
762 | + return std::make_unique<StubDisplayConfiguration>(internal_active_conf_output); |
763 | } |
764 | |
765 | - mir::graphics::DisplayConfigurationOutput conf_output; |
766 | + int num_internal_active_outputs{1}; |
767 | + int num_external_active_outputs{0}; |
768 | + int num_inactive_outputs{0}; |
769 | + |
770 | + mir::graphics::DisplayConfigurationOutput internal_active_conf_output; |
771 | + mir::graphics::DisplayConfigurationOutput external_active_conf_output; |
772 | + mir::graphics::DisplayConfigurationOutput inactive_conf_output; |
773 | }; |
774 | |
775 | } |
776 | |
777 | === modified file 'tests/integration-tests/test_unity_display_service.cpp' |
778 | --- tests/integration-tests/test_unity_display_service.cpp 2016-04-18 14:58:36 +0000 |
779 | +++ tests/integration-tests/test_unity_display_service.cpp 2017-02-06 11:51:56 +0000 |
780 | @@ -40,16 +40,34 @@ |
781 | namespace |
782 | { |
783 | |
784 | +struct FakeScreen : ut::MockScreen |
785 | +{ |
786 | + void register_active_outputs_handler(usc::ActiveOutputsHandler const& handler) |
787 | + { |
788 | + std::lock_guard<std::mutex> lock{active_outputs_mutex}; |
789 | + active_outputs_handler = handler; |
790 | + } |
791 | + |
792 | + void notify_active_outputs(usc::ActiveOutputs const& active_outputs) |
793 | + { |
794 | + std::lock_guard<std::mutex> lock{active_outputs_mutex}; |
795 | + active_outputs_handler(active_outputs); |
796 | + } |
797 | + |
798 | + std::mutex active_outputs_mutex; |
799 | + usc::ActiveOutputsHandler active_outputs_handler{[](usc::ActiveOutputs const&){}}; |
800 | +}; |
801 | + |
802 | struct AUnityDisplayService : testing::Test |
803 | { |
804 | ut::DBusBus bus; |
805 | |
806 | - std::shared_ptr<ut::MockScreen> const mock_screen = |
807 | - std::make_shared<testing::NiceMock<ut::MockScreen>>(); |
808 | + std::shared_ptr<FakeScreen> const fake_screen = |
809 | + std::make_shared<testing::NiceMock<FakeScreen>>(); |
810 | ut::UnityDisplayDBusClient client{bus.address()}; |
811 | std::shared_ptr<usc::DBusEventLoop> const dbus_loop = |
812 | std::make_shared<usc::DBusEventLoop>(); |
813 | - usc::UnityDisplayService service{dbus_loop, bus.address(), mock_screen}; |
814 | + usc::UnityDisplayService service{dbus_loop, bus.address(), fake_screen}; |
815 | std::shared_ptr<usc::DBusConnectionThread> const dbus_thread = |
816 | std::make_shared<usc::DBusConnectionThread>(dbus_loop); |
817 | }; |
818 | @@ -66,16 +84,137 @@ |
819 | |
820 | TEST_F(AUnityDisplayService, forwards_turn_on_request) |
821 | { |
822 | - EXPECT_CALL(*mock_screen, turn_on()); |
823 | - |
824 | - client.request_turn_on(); |
825 | + using namespace testing; |
826 | + |
827 | + InSequence s; |
828 | + EXPECT_CALL(*fake_screen, turn_on(usc::OutputFilter::all)); |
829 | + EXPECT_CALL(*fake_screen, turn_on(usc::OutputFilter::internal)); |
830 | + EXPECT_CALL(*fake_screen, turn_on(usc::OutputFilter::external)); |
831 | + |
832 | + client.request_turn_on("all"); |
833 | + client.request_turn_on("internal"); |
834 | + client.request_turn_on("external"); |
835 | } |
836 | |
837 | TEST_F(AUnityDisplayService, forwards_turn_off_request) |
838 | { |
839 | - EXPECT_CALL(*mock_screen, turn_off()); |
840 | - |
841 | - client.request_turn_off(); |
842 | + using namespace testing; |
843 | + |
844 | + InSequence s; |
845 | + EXPECT_CALL(*fake_screen, turn_off(usc::OutputFilter::all)); |
846 | + EXPECT_CALL(*fake_screen, turn_off(usc::OutputFilter::internal)); |
847 | + EXPECT_CALL(*fake_screen, turn_off(usc::OutputFilter::external)); |
848 | + |
849 | + client.request_turn_off("all"); |
850 | + client.request_turn_off("internal"); |
851 | + client.request_turn_off("external"); |
852 | +} |
853 | + |
854 | +TEST_F(AUnityDisplayService, emits_active_outputs_property_change) |
855 | +{ |
856 | + using namespace testing; |
857 | + |
858 | + usc::ActiveOutputs expected_active_outputs; |
859 | + expected_active_outputs.internal = 2; |
860 | + expected_active_outputs.external = 3; |
861 | + |
862 | + fake_screen->notify_active_outputs(expected_active_outputs); |
863 | + // Received messages are queued at the destination, so it doesn't |
864 | + // matter that we start listening after the signal has been sent |
865 | + auto message = client.listen_for_properties_changed(); |
866 | + |
867 | + DBusMessageIter iter; |
868 | + dbus_message_iter_init(message, &iter); |
869 | + dbus_message_iter_next(&iter); |
870 | + DBusMessageIter iter_properties; |
871 | + dbus_message_iter_recurse(&iter, &iter_properties); |
872 | + DBusMessageIter iter_property; |
873 | + dbus_message_iter_recurse(&iter_properties, &iter_property); |
874 | + |
875 | + char const* property_name{""}; |
876 | + usc::ActiveOutputs active_outputs{-1, -1}; |
877 | + |
878 | + dbus_message_iter_get_basic(&iter_property, &property_name); |
879 | + |
880 | + dbus_message_iter_next(&iter_property); |
881 | + DBusMessageIter iter_variant; |
882 | + DBusMessageIter iter_values; |
883 | + dbus_message_iter_recurse(&iter_property, &iter_variant); |
884 | + dbus_message_iter_recurse(&iter_variant, &iter_values); |
885 | + |
886 | + dbus_message_iter_get_basic(&iter_values, &active_outputs.internal); |
887 | + dbus_message_iter_next(&iter_values); |
888 | + dbus_message_iter_get_basic(&iter_values, &active_outputs.external); |
889 | + |
890 | + EXPECT_THAT(property_name, StrEq("ActiveOutputs")); |
891 | + EXPECT_THAT(active_outputs, Eq(expected_active_outputs)); |
892 | +} |
893 | + |
894 | +TEST_F(AUnityDisplayService, returns_active_outputs_property) |
895 | +{ |
896 | + using namespace testing; |
897 | + |
898 | + usc::ActiveOutputs expected_active_outputs; |
899 | + expected_active_outputs.internal = 2; |
900 | + expected_active_outputs.external = 3; |
901 | + |
902 | + fake_screen->notify_active_outputs(expected_active_outputs); |
903 | + |
904 | + auto message = client.request_active_outputs_property().get(); |
905 | + |
906 | + DBusMessageIter iter; |
907 | + dbus_message_iter_init(message, &iter); |
908 | + |
909 | + DBusMessageIter iter_variant; |
910 | + dbus_message_iter_recurse(&iter, &iter_variant); |
911 | + DBusMessageIter iter_values; |
912 | + dbus_message_iter_recurse(&iter_variant, &iter_values); |
913 | + |
914 | + usc::ActiveOutputs active_outputs{-1, -1}; |
915 | + |
916 | + dbus_message_iter_get_basic(&iter_values, &active_outputs.internal); |
917 | + dbus_message_iter_next(&iter_values); |
918 | + dbus_message_iter_get_basic(&iter_values, &active_outputs.external); |
919 | + |
920 | + EXPECT_THAT(active_outputs, Eq(expected_active_outputs)); |
921 | +} |
922 | + |
923 | +TEST_F(AUnityDisplayService, returns_all_properties) |
924 | +{ |
925 | + using namespace testing; |
926 | + |
927 | + usc::ActiveOutputs expected_active_outputs; |
928 | + expected_active_outputs.internal = 2; |
929 | + expected_active_outputs.external = 3; |
930 | + |
931 | + fake_screen->notify_active_outputs(expected_active_outputs); |
932 | + |
933 | + auto message = client.request_all_properties().get(); |
934 | + |
935 | + DBusMessageIter iter; |
936 | + dbus_message_iter_init(message, &iter); |
937 | + DBusMessageIter iter_properties; |
938 | + dbus_message_iter_recurse(&iter, &iter_properties); |
939 | + DBusMessageIter iter_property; |
940 | + dbus_message_iter_recurse(&iter_properties, &iter_property); |
941 | + |
942 | + char const* property_name{""}; |
943 | + usc::ActiveOutputs active_outputs{-1, -1}; |
944 | + |
945 | + dbus_message_iter_get_basic(&iter_property, &property_name); |
946 | + |
947 | + dbus_message_iter_next(&iter_property); |
948 | + DBusMessageIter iter_variant; |
949 | + DBusMessageIter iter_values; |
950 | + dbus_message_iter_recurse(&iter_property, &iter_variant); |
951 | + dbus_message_iter_recurse(&iter_variant, &iter_values); |
952 | + |
953 | + dbus_message_iter_get_basic(&iter_values, &active_outputs.internal); |
954 | + dbus_message_iter_next(&iter_values); |
955 | + dbus_message_iter_get_basic(&iter_values, &active_outputs.external); |
956 | + |
957 | + EXPECT_THAT(property_name, StrEq("ActiveOutputs")); |
958 | + EXPECT_THAT(active_outputs, Eq(expected_active_outputs)); |
959 | } |
960 | |
961 | TEST_F(AUnityDisplayService, returns_error_reply_for_unsupported_method) |
962 | |
963 | === modified file 'tests/integration-tests/unity_display_dbus_client.cpp' |
964 | --- tests/integration-tests/unity_display_dbus_client.cpp 2016-04-18 14:58:36 +0000 |
965 | +++ tests/integration-tests/unity_display_dbus_client.cpp 2017-02-06 11:51:56 +0000 |
966 | @@ -17,6 +17,7 @@ |
967 | */ |
968 | |
969 | #include "unity_display_dbus_client.h" |
970 | +#include "src/dbus_message_handle.h" |
971 | |
972 | namespace ut = usc::test; |
973 | |
974 | @@ -26,6 +27,9 @@ |
975 | "com.canonical.Unity.Display", |
976 | "/com/canonical/Unity/Display"} |
977 | { |
978 | + connection.add_match( |
979 | + "type='signal'," |
980 | + "interface='org.freedesktop.DBus.Properties'"); |
981 | } |
982 | |
983 | ut::DBusAsyncReplyString ut::UnityDisplayDBusClient::request_introspection() |
984 | @@ -35,17 +39,25 @@ |
985 | DBUS_TYPE_INVALID); |
986 | } |
987 | |
988 | -ut::DBusAsyncReplyVoid ut::UnityDisplayDBusClient::request_turn_on() |
989 | +ut::DBusAsyncReplyVoid ut::UnityDisplayDBusClient::request_turn_on( |
990 | + std::string const& filter) |
991 | { |
992 | + auto const filter_cstr = filter.c_str(); |
993 | + |
994 | return invoke_with_reply<ut::DBusAsyncReplyVoid>( |
995 | unity_display_interface, "TurnOn", |
996 | + DBUS_TYPE_STRING, &filter_cstr, |
997 | DBUS_TYPE_INVALID); |
998 | } |
999 | |
1000 | -ut::DBusAsyncReplyVoid ut::UnityDisplayDBusClient::request_turn_off() |
1001 | +ut::DBusAsyncReplyVoid ut::UnityDisplayDBusClient::request_turn_off( |
1002 | + std::string const& filter) |
1003 | { |
1004 | + auto const filter_cstr = filter.c_str(); |
1005 | + |
1006 | return invoke_with_reply<ut::DBusAsyncReplyVoid>( |
1007 | unity_display_interface, "TurnOff", |
1008 | + DBUS_TYPE_STRING, &filter_cstr, |
1009 | DBUS_TYPE_INVALID); |
1010 | } |
1011 | |
1012 | @@ -54,3 +66,36 @@ |
1013 | return invoke_with_reply<ut::DBusAsyncReply>( |
1014 | unity_display_interface, "invalidMethod", DBUS_TYPE_INVALID); |
1015 | } |
1016 | + |
1017 | +ut::DBusAsyncReply ut::UnityDisplayDBusClient::request_active_outputs_property() |
1018 | +{ |
1019 | + char const* const active_outputs_cstr = "ActiveOutputs"; |
1020 | + |
1021 | + return invoke_with_reply<ut::DBusAsyncReply>( |
1022 | + "org.freedesktop.DBus.Properties", "Get", |
1023 | + DBUS_TYPE_STRING, &unity_display_interface, |
1024 | + DBUS_TYPE_STRING, &active_outputs_cstr, |
1025 | + DBUS_TYPE_INVALID); |
1026 | +} |
1027 | + |
1028 | +ut::DBusAsyncReply ut::UnityDisplayDBusClient::request_all_properties() |
1029 | +{ |
1030 | + return invoke_with_reply<ut::DBusAsyncReply>( |
1031 | + "org.freedesktop.DBus.Properties", "GetAll", |
1032 | + DBUS_TYPE_STRING, &unity_display_interface, |
1033 | + DBUS_TYPE_INVALID); |
1034 | +} |
1035 | + |
1036 | +usc::DBusMessageHandle ut::UnityDisplayDBusClient::listen_for_properties_changed() |
1037 | +{ |
1038 | + while (true) |
1039 | + { |
1040 | + dbus_connection_read_write(connection, 1); |
1041 | + auto msg = usc::DBusMessageHandle{dbus_connection_pop_message(connection)}; |
1042 | + |
1043 | + if (msg && dbus_message_is_signal(msg, "org.freedesktop.DBus.Properties", "PropertiesChanged")) |
1044 | + { |
1045 | + return msg; |
1046 | + } |
1047 | + } |
1048 | +} |
1049 | |
1050 | === modified file 'tests/integration-tests/unity_display_dbus_client.h' |
1051 | --- tests/integration-tests/unity_display_dbus_client.h 2016-04-18 14:58:36 +0000 |
1052 | +++ tests/integration-tests/unity_display_dbus_client.h 2017-02-06 11:51:56 +0000 |
1053 | @@ -32,10 +32,14 @@ |
1054 | UnityDisplayDBusClient(std::string const& address); |
1055 | |
1056 | DBusAsyncReplyString request_introspection(); |
1057 | - DBusAsyncReplyVoid request_turn_on(); |
1058 | - DBusAsyncReplyVoid request_turn_off(); |
1059 | + DBusAsyncReplyVoid request_turn_on(std::string const& filter); |
1060 | + DBusAsyncReplyVoid request_turn_off(std::string const& filter); |
1061 | + DBusAsyncReply request_active_outputs_property(); |
1062 | + DBusAsyncReply request_all_properties(); |
1063 | DBusAsyncReply request_invalid_method(); |
1064 | |
1065 | + DBusMessageHandle listen_for_properties_changed(); |
1066 | + |
1067 | char const* const unity_display_interface = "com.canonical.Unity.Display"; |
1068 | }; |
1069 | |
1070 | |
1071 | === modified file 'tests/unit-tests/test_mir_screen.cpp' |
1072 | --- tests/unit-tests/test_mir_screen.cpp 2016-11-09 19:12:16 +0000 |
1073 | +++ tests/unit-tests/test_mir_screen.cpp 2017-02-06 11:51:56 +0000 |
1074 | @@ -19,6 +19,8 @@ |
1075 | #include "src/mir_screen.h" |
1076 | |
1077 | #include "usc/test/mock_display.h" |
1078 | +#include "usc/test/stub_display_configuration.h" |
1079 | +#include "fake_shared.h" |
1080 | |
1081 | #include <mir/compositor/compositor.h> |
1082 | #include <mir/graphics/display_configuration.h> |
1083 | @@ -40,17 +42,31 @@ |
1084 | MOCK_METHOD0(stop, void()); |
1085 | }; |
1086 | |
1087 | +struct MockDisplayWithExternalOutputs : ut::MockDisplay |
1088 | +{ |
1089 | + std::unique_ptr<mir::graphics::DisplayConfiguration> configuration() const override |
1090 | + { |
1091 | + return std::make_unique<usc::test::StubDisplayConfiguration>(2, 3, 1); |
1092 | + } |
1093 | +}; |
1094 | + |
1095 | struct AMirScreen : testing::Test |
1096 | { |
1097 | - void turn_screen_off() |
1098 | - { |
1099 | - mir_screen.turn_off(); |
1100 | - verify_and_clear_expectations(); |
1101 | - } |
1102 | - |
1103 | - void turn_screen_on() |
1104 | - { |
1105 | - mir_screen.turn_on(); |
1106 | + void turn_all_displays_off() |
1107 | + { |
1108 | + mir_screen->turn_off(usc::OutputFilter::all); |
1109 | + verify_and_clear_expectations(); |
1110 | + } |
1111 | + |
1112 | + void turn_all_displays_on() |
1113 | + { |
1114 | + mir_screen->turn_on(usc::OutputFilter::all); |
1115 | + verify_and_clear_expectations(); |
1116 | + } |
1117 | + |
1118 | + void turn_internal_displays_off() |
1119 | + { |
1120 | + mir_screen->turn_off(usc::OutputFilter::internal); |
1121 | verify_and_clear_expectations(); |
1122 | } |
1123 | |
1124 | @@ -60,14 +76,33 @@ |
1125 | Mock::VerifyAndClearExpectations(compositor.get()); |
1126 | } |
1127 | |
1128 | + void use_mir_screen_with_external_outputs() |
1129 | + { |
1130 | + display = std::make_shared<testing::NiceMock<MockDisplayWithExternalOutputs>>(); |
1131 | + mir_screen = std::make_shared<usc::MirScreen>(compositor, display); |
1132 | + } |
1133 | + |
1134 | std::shared_ptr<MockCompositor> compositor{ |
1135 | std::make_shared<testing::NiceMock<MockCompositor>>()}; |
1136 | std::shared_ptr<ut::MockDisplay> display{ |
1137 | std::make_shared<testing::NiceMock<ut::MockDisplay>>()}; |
1138 | |
1139 | - usc::MirScreen mir_screen{ |
1140 | - compositor, |
1141 | - display}; |
1142 | + usc::ActiveOutputs const config_active_outputs{1, 3}; |
1143 | + int const config_inactive_outputs = 2; |
1144 | + ut::StubDisplayConfiguration stub_display_configuration{ |
1145 | + config_active_outputs.internal, |
1146 | + config_active_outputs.external, |
1147 | + config_inactive_outputs}; |
1148 | + |
1149 | + usc::ActiveOutputs active_outputs{-1,-1}; |
1150 | + usc::ActiveOutputsHandler active_outputs_handler = |
1151 | + [this] (usc::ActiveOutputs const& active_outputs_arg) |
1152 | + { |
1153 | + active_outputs = active_outputs_arg; |
1154 | + }; |
1155 | + |
1156 | + std::shared_ptr<usc::MirScreen> mir_screen{ |
1157 | + std::make_shared<usc::MirScreen>(compositor, display)}; |
1158 | }; |
1159 | |
1160 | } |
1161 | @@ -78,17 +113,63 @@ |
1162 | EXPECT_CALL(*compositor, stop()); |
1163 | EXPECT_CALL(*display, configure(_)); |
1164 | |
1165 | - turn_screen_off(); |
1166 | + turn_all_displays_off(); |
1167 | } |
1168 | |
1169 | TEST_F(AMirScreen, starts_compositing_and_turns_on_display_when_turning_on) |
1170 | { |
1171 | - turn_screen_off(); |
1172 | - |
1173 | - InSequence s; |
1174 | - EXPECT_CALL(*compositor, stop()); |
1175 | - EXPECT_CALL(*display, configure(_)); |
1176 | - EXPECT_CALL(*compositor, start()); |
1177 | - |
1178 | - turn_screen_on(); |
1179 | + turn_all_displays_off(); |
1180 | + |
1181 | + InSequence s; |
1182 | + EXPECT_CALL(*compositor, stop()); |
1183 | + EXPECT_CALL(*display, configure(_)); |
1184 | + EXPECT_CALL(*compositor, start()); |
1185 | + |
1186 | + turn_all_displays_on(); |
1187 | +} |
1188 | + |
1189 | +TEST_F(AMirScreen, stops_compositing_and_turns_off_internal_when_only_internal) |
1190 | +{ |
1191 | + InSequence s; |
1192 | + EXPECT_CALL(*compositor, stop()); |
1193 | + EXPECT_CALL(*display, configure(_)); |
1194 | + |
1195 | + turn_internal_displays_off(); |
1196 | +} |
1197 | + |
1198 | +TEST_F(AMirScreen, restarts_compositing_after_turn_off_internal_if_active_outputs_remain) |
1199 | +{ |
1200 | + use_mir_screen_with_external_outputs(); |
1201 | + |
1202 | + InSequence s; |
1203 | + EXPECT_CALL(*compositor, stop()); |
1204 | + EXPECT_CALL(*display, configure(_)); |
1205 | + EXPECT_CALL(*compositor, start()); |
1206 | + |
1207 | + turn_internal_displays_off(); |
1208 | +} |
1209 | + |
1210 | +TEST_F(AMirScreen, registered_handler_is_called_immediately) |
1211 | +{ |
1212 | + mir_screen->register_active_outputs_handler(active_outputs_handler); |
1213 | + |
1214 | + EXPECT_THAT(active_outputs, Eq(usc::ActiveOutputs{})); |
1215 | +} |
1216 | + |
1217 | +TEST_F(AMirScreen, initial_configuration_calls_handler) |
1218 | +{ |
1219 | + mir_screen->register_active_outputs_handler(active_outputs_handler); |
1220 | + |
1221 | + mir_screen->initial_configuration(ut::fake_shared(stub_display_configuration)); |
1222 | + |
1223 | + EXPECT_THAT(active_outputs, Eq(config_active_outputs)); |
1224 | +} |
1225 | + |
1226 | +TEST_F(AMirScreen, configuration_applied_calls_handler) |
1227 | +{ |
1228 | + mir_screen->register_active_outputs_handler(active_outputs_handler); |
1229 | + |
1230 | + mir_screen->configuration_applied(ut::fake_shared(stub_display_configuration)); |
1231 | + |
1232 | + EXPECT_THAT(active_outputs, Eq(config_active_outputs)); |
1233 | } |
FAILED: Continuous integration, rev:307 /mir-jenkins. ubuntu. com/job/ usc-ci/ 49/ /mir-jenkins. ubuntu. com/job/ build-usc/ 70/console /mir-jenkins. ubuntu. com/job/ build-0- fetch/3983 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= vivid+overlay/ 3973 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= xenial+ overlay/ 3973 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= zesty/3973 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- usc/arch= amd64,release= xenial+ overlay/ 74/console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- usc/arch= amd64,release= zesty/74/ console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- usc/arch= armhf,release= vivid+overlay/ 74/console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- usc/arch= i386,release= xenial+ overlay/ 74/console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- usc/arch= i386,release= zesty/74/ console
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild: /mir-jenkins. ubuntu. com/job/ usc-ci/ 49/rebuild
https:/