Mir

Merge lp:~afrantzis/mir/vt-switching into lp:~mir-team/mir/trunk

Proposed by Alexandros Frantzis on 2013-04-10
Status: Superseded
Proposed branch: lp:~afrantzis/mir/vt-switching
Merge into: lp:~mir-team/mir/trunk
Diff against target: 2053 lines (+1049/-51)
44 files modified
include/server/mir/graphics/display.h (+3/-0)
include/server/mir/graphics/platform.h (+12/-1)
include/server/mir/server_configuration.h (+2/-0)
include/test/mir_test_doubles/mock_display.h (+2/-0)
include/test/mir_test_doubles/null_display.h (+2/-0)
include/test/mir_test_doubles/null_virtual_terminal.h (+47/-0)
src/server/display_server.cpp (+18/-1)
src/server/graphics/android/android_display.cpp (+8/-0)
src/server/graphics/android/android_display.h (+3/-0)
src/server/graphics/android/android_platform.cpp (+15/-0)
src/server/graphics/android/android_platform.h (+6/-0)
src/server/graphics/gbm/CMakeLists.txt (+1/-0)
src/server/graphics/gbm/gbm_display.cpp (+17/-3)
src/server/graphics/gbm/gbm_display.h (+7/-2)
src/server/graphics/gbm/gbm_display_buffer.cpp (+17/-2)
src/server/graphics/gbm/gbm_display_buffer.h (+4/-0)
src/server/graphics/gbm/gbm_display_helpers.cpp (+41/-0)
src/server/graphics/gbm/gbm_display_helpers.h (+3/-0)
src/server/graphics/gbm/gbm_platform.cpp (+27/-3)
src/server/graphics/gbm/gbm_platform.h (+12/-2)
src/server/graphics/gbm/linux_virtual_terminal.cpp (+180/-0)
src/server/graphics/gbm/linux_virtual_terminal.h (+67/-0)
src/server/graphics/gbm/virtual_terminal.h (+55/-0)
tests/behavior-tests/session_management_context.cpp (+3/-0)
tests/integration-tests/cucumber/test_session_management_context.cpp (+1/-0)
tests/integration-tests/graphics/gbm/test_buffer_integration.cpp (+9/-0)
tests/integration-tests/test_display_info.cpp (+8/-0)
tests/integration-tests/test_display_server_main_loop_events.cpp (+233/-0)
tests/integration-tests/test_drm_auth_magic.cpp (+9/-0)
tests/integration-tests/test_surfaceloop.cpp (+20/-0)
tests/mir_test_framework/testing_server_options.cpp (+12/-0)
tests/unit-tests/compositor/test_multi_threaded_compositor.cpp (+3/-0)
tests/unit-tests/frontend/test_session_mediator.cpp (+9/-0)
tests/unit-tests/frontend/test_session_mediator_android.cpp (+9/-0)
tests/unit-tests/frontend/test_session_mediator_gbm.cpp (+9/-0)
tests/unit-tests/graphics/gbm/mock_drm.cpp (+10/-0)
tests/unit-tests/graphics/gbm/mock_drm.h (+3/-0)
tests/unit-tests/graphics/gbm/test_gbm_buffer.cpp (+4/-1)
tests/unit-tests/graphics/gbm/test_gbm_buffer_allocator.cpp (+3/-1)
tests/unit-tests/graphics/gbm/test_gbm_display.cpp (+24/-16)
tests/unit-tests/graphics/gbm/test_gbm_display_configuration.cpp (+13/-6)
tests/unit-tests/graphics/gbm/test_gbm_display_multi_monitor.cpp (+12/-5)
tests/unit-tests/graphics/gbm/test_gbm_platform.cpp (+90/-5)
tests/unit-tests/graphics/test_graphics_platform.cpp (+16/-3)
To merge this branch: bzr merge lp:~afrantzis/mir/vt-switching
Reviewer Review Type Date Requested Status
Daniel van Vugt Needs Fixing on 2013-04-11
Robert Ancell Approve on 2013-04-11
Robert Carr (community) 2013-04-10 Needs Information on 2013-04-10
PS Jenkins bot (community) continuous-integration Approve on 2013-04-10
Review via email: mp+158096@code.launchpad.net

This proposal has been superseded by a proposal from 2013-04-11.

Commit message

server,gbm: Support VT switching

Since VT switching is a desktop specific concept at the moment, this branch
introduces it in more generic terms, as pause/resume in the high level
interfaces. Note that the mechanisms that implement pausing/resuming are
not tied to VT switching in particular. We can reuse them to pause/resume
arbitrarily.

In order for VT switching (pause/resume) to work properly, mir needs to be
run with root privileges, since this is required for drm{Drop,Set}Master().
However, if no VT switch (pause/resume) is performed, mir can be happily
run without root priveleges (as before, assuming appropriate device
permissions).

Description of the change

server,gbm: Support VT switching

Since VT switching is a desktop specific concept, this branch introduces it in more generic terms, as pause/resume in the high level interfaces. Note that the mechanisms that implement pausing/resuming are not tied to VT switching in particular. We can reuse them to pause/resume arbitrarily.

In order for VT switching (pause/resume) to work properly, mir needs to be run with root privileges, since this is required for drm{Drop,Set}Master(). However, if no VT switch (pause/resume) is performed, mir can be happily run without root priveleges (as before, assuming appropriate device permissions).

There is a bit of code churn in this branch because of the interface changes in mg::Display and mg::Platform, that caused a barrage of amendments to related stub and mock classes.

To post a comment you must log in.
Robert Carr (robertcarr) wrote :

Around + display->pause();

Do we need to pause input?

review: Needs Information
Alexandros Frantzis (afrantzis) wrote :

> Around + display->pause();
>
> Do we need to pause input?

Good question, we probably do, but I am not familiar with input details and how moving to another VT affects input. I guess from the perspective of pause/resume, it makes sense to stop processing/sending input events anyway when paused.

In any case, I'd rather leave it out of this MP (and let you implement it in an upcoming MP as needed ;))

Kevin DuBois (kdub) wrote :

The concepts of pause/resume (although not coded to do anything in android) are useful for what we'll want to do when the display is turned off on android, so I like the general idea

I kept thinking the pause/resume for the platform and the display could be consilidated, however I think its ok as it is

Alexandros Frantzis (afrantzis) wrote :

> I kept thinking the pause/resume for the platform and the display could be
> consilidated, however I think its ok as it is

This is doable, although less explicit, but on second thought I prefer it this way too.
We can also move register_pause_resume_handlers() to mg::Display too, thus leaving the mg::Platform interface unchanged.

review: Approve
Daniel van Vugt (vanvugt) wrote :

Text conflict in include/server/mir/graphics/platform.h
Text conflict in src/server/graphics/android/android_platform.h
Text conflict in src/server/graphics/gbm/gbm_platform.cpp
Text conflict in src/server/graphics/gbm/gbm_platform.h
Text conflict in tests/integration-tests/graphics/gbm/test_buffer_integration.cpp
Text conflict in tests/integration-tests/test_display_info.cpp
Text conflict in tests/integration-tests/test_drm_auth_magic.cpp
Text conflict in tests/integration-tests/test_surfaceloop.cpp
Text conflict in tests/mir_test_framework/testing_server_options.cpp
Text conflict in tests/unit-tests/frontend/test_session_mediator.cpp
Text conflict in tests/unit-tests/frontend/test_session_mediator_android.cpp
Text conflict in tests/unit-tests/frontend/test_session_mediator_gbm.cpp
Text conflict in tests/unit-tests/graphics/gbm/mock_drm.cpp
Text conflict in tests/unit-tests/graphics/gbm/mock_drm.h
14 conflicts encountered.

review: Needs Fixing

Unmerged revisions

581. By Alexandros Frantzis on 2013-04-10

server,gbm: Support vt switching

580. By Alexandros Frantzis on 2013-04-10

gbm: Add basic VT support

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/server/mir/graphics/display.h'
2--- include/server/mir/graphics/display.h 2013-03-13 04:54:15 +0000
3+++ include/server/mir/graphics/display.h 2013-04-10 12:56:24 +0000
4@@ -40,6 +40,9 @@
5
6 virtual std::shared_ptr<DisplayConfiguration> configuration() = 0;
7
8+ virtual void pause() = 0;
9+ virtual void resume() = 0;
10+
11 protected:
12 Display() = default;
13 ~Display() = default;
14
15=== modified file 'include/server/mir/graphics/platform.h'
16--- include/server/mir/graphics/platform.h 2013-03-21 03:32:59 +0000
17+++ include/server/mir/graphics/platform.h 2013-04-10 12:56:24 +0000
18@@ -21,10 +21,13 @@
19 #define MIR_GRAPHICS_PLATFORM_H_
20
21 #include <memory>
22-
23+#include <functional>
24
25 namespace mir
26 {
27+
28+class MainLoop;
29+
30 namespace compositor
31 {
32 class GraphicBufferAllocator;
33@@ -53,6 +56,14 @@
34 const std::shared_ptr<BufferInitializer>& buffer_initializer) = 0;
35 virtual std::shared_ptr<Display> create_display() = 0;
36 virtual std::shared_ptr<PlatformIPCPackage> get_ipc_package() = 0;
37+
38+ virtual void register_pause_resume_handlers(
39+ MainLoop& main_loop,
40+ std::function<void()> const& pause_handler,
41+ std::function<void()> const& resume_handler) = 0;
42+
43+ virtual void pause() = 0;
44+ virtual void resume() = 0;
45 };
46
47 // Create and return a new graphics platform.
48
49=== modified file 'include/server/mir/server_configuration.h'
50--- include/server/mir/server_configuration.h 2013-04-08 16:20:33 +0000
51+++ include/server/mir/server_configuration.h 2013-04-10 12:56:24 +0000
52@@ -33,6 +33,7 @@
53 }
54 namespace graphics
55 {
56+class Platform;
57 class Display;
58 }
59 namespace input
60@@ -48,6 +49,7 @@
61 public:
62 virtual std::shared_ptr<frontend::Communicator> the_communicator() = 0;
63 virtual std::shared_ptr<frontend::Shell> the_frontend_shell() = 0;
64+ virtual std::shared_ptr<graphics::Platform> the_graphics_platform() = 0;
65 virtual std::shared_ptr<graphics::Display> the_display() = 0;
66 virtual std::shared_ptr<compositor::Compositor> the_compositor() = 0;
67 virtual std::shared_ptr<input::InputManager> the_input_manager() = 0;
68
69=== modified file 'include/test/mir_test_doubles/mock_display.h'
70--- include/test/mir_test_doubles/mock_display.h 2013-03-13 04:54:15 +0000
71+++ include/test/mir_test_doubles/mock_display.h 2013-04-10 12:56:24 +0000
72@@ -35,6 +35,8 @@
73 MOCK_CONST_METHOD0(view_area, geometry::Rectangle ());
74 MOCK_METHOD1(for_each_display_buffer, void (std::function<void(graphics::DisplayBuffer&)> const&));
75 MOCK_METHOD0(configuration, std::shared_ptr<graphics::DisplayConfiguration>());
76+ MOCK_METHOD0(pause, void());
77+ MOCK_METHOD0(resume, void());
78 };
79
80 }
81
82=== modified file 'include/test/mir_test_doubles/null_display.h'
83--- include/test/mir_test_doubles/null_display.h 2013-03-13 04:54:15 +0000
84+++ include/test/mir_test_doubles/null_display.h 2013-04-10 12:56:24 +0000
85@@ -42,6 +42,8 @@
86 {
87 return std::shared_ptr<graphics::DisplayConfiguration>();
88 }
89+ void pause() {}
90+ void resume() {}
91 };
92
93 }
94
95=== added file 'include/test/mir_test_doubles/null_virtual_terminal.h'
96--- include/test/mir_test_doubles/null_virtual_terminal.h 1970-01-01 00:00:00 +0000
97+++ include/test/mir_test_doubles/null_virtual_terminal.h 2013-04-10 12:56:24 +0000
98@@ -0,0 +1,47 @@
99+/*
100+ * Copyright © 2013 Canonical Ltd.
101+ *
102+ * This program is free software: you can redistribute it and/or modify it
103+ * under the terms of the GNU Lesser General Public License version 3,
104+ * as published by the Free Software Foundation.
105+ *
106+ * This program is distributed in the hope that it will be useful,
107+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
108+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
109+ * GNU General Public License for more details.
110+ *
111+ * You should have received a copy of the GNU Lesser General Public License
112+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
113+ *
114+ * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
115+ */
116+
117+#ifndef MIR_TEST_DOUBLES_NULL_VIRTUAL_TERMINAL_H_
118+#define MIR_TEST_DOUBLES_NULL_VIRTUAL_TERMINAL_H_
119+
120+#include "src/server/graphics/gbm/virtual_terminal.h"
121+
122+namespace mir
123+{
124+namespace test
125+{
126+namespace doubles
127+{
128+
129+class NullVirtualTerminal : public graphics::gbm::VirtualTerminal
130+{
131+public:
132+ void set_graphics_mode() {}
133+
134+ void register_switch_handlers(MainLoop&,
135+ std::function<void()> const&,
136+ std::function<void()> const&)
137+ {
138+ }
139+};
140+
141+}
142+}
143+}
144+
145+#endif /* MIR_TEST_DOUBLES_NULL_VIRTUAL_TERMINAL_H_ */
146
147=== modified file 'src/server/display_server.cpp'
148--- src/server/display_server.cpp 2013-04-08 16:20:33 +0000
149+++ src/server/display_server.cpp 2013-04-10 12:56:24 +0000
150@@ -25,6 +25,7 @@
151 #include "mir/compositor/compositor.h"
152 #include "mir/frontend/shell.h"
153 #include "mir/frontend/communicator.h"
154+#include "mir/graphics/platform.h"
155 #include "mir/graphics/display.h"
156 #include "mir/input/input_manager.h"
157
158@@ -36,15 +37,31 @@
159 struct mir::DisplayServer::Private
160 {
161 Private(ServerConfiguration& config)
162- : display{config.the_display()},
163+ : graphics_platform{config.the_graphics_platform()},
164+ display{config.the_display()},
165 compositor{config.the_compositor()},
166 shell{config.the_frontend_shell()},
167 communicator{config.the_communicator()},
168 input_manager{config.the_input_manager()},
169 main_loop{config.the_main_loop()}
170 {
171+ graphics_platform->register_pause_resume_handlers(
172+ *main_loop,
173+ [this]
174+ {
175+ compositor->stop();
176+ display->pause();
177+ graphics_platform->pause();
178+ },
179+ [this]
180+ {
181+ graphics_platform->resume();
182+ display->resume();
183+ compositor->start();
184+ });
185 }
186
187+ std::shared_ptr<mg::Platform> graphics_platform;
188 std::shared_ptr<mg::Display> display;
189 std::shared_ptr<mc::Compositor> compositor;
190 std::shared_ptr<frontend::Shell> shell;
191
192=== modified file 'src/server/graphics/android/android_display.cpp'
193--- src/server/graphics/android/android_display.cpp 2013-03-21 03:32:59 +0000
194+++ src/server/graphics/android/android_display.cpp 2013-04-10 12:56:24 +0000
195@@ -142,6 +142,14 @@
196 return std::make_shared<NullDisplayConfiguration>();
197 }
198
199+void mga::AndroidDisplay::pause()
200+{
201+}
202+
203+void mga::AndroidDisplay::resume()
204+{
205+}
206+
207 void mga::AndroidDisplay::make_current()
208 {
209 if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context) == EGL_FALSE)
210
211=== modified file 'src/server/graphics/android/android_display.h'
212--- src/server/graphics/android/android_display.h 2013-03-22 18:33:51 +0000
213+++ src/server/graphics/android/android_display.h 2013-04-10 12:56:24 +0000
214@@ -50,6 +50,9 @@
215
216 std::shared_ptr<DisplayConfiguration> configuration();
217
218+ void pause();
219+ void resume();
220+
221 void make_current();
222 private:
223 std::shared_ptr<AndroidFramebufferWindowQuery> native_window;
224
225=== modified file 'src/server/graphics/android/android_platform.cpp'
226--- src/server/graphics/android/android_platform.cpp 2013-04-02 15:06:31 +0000
227+++ src/server/graphics/android/android_platform.cpp 2013-04-10 12:56:24 +0000
228@@ -52,3 +52,18 @@
229 {
230 return std::make_shared<mga::AndroidPlatform>();
231 }
232+
233+void mga::AndroidPlatform::register_pause_resume_handlers(
234+ MainLoop&,
235+ std::function<void()> const&,
236+ std::function<void()> const&)
237+{
238+}
239+
240+void mga::AndroidPlatform::pause()
241+{
242+}
243+
244+void mga::AndroidPlatform::resume()
245+{
246+}
247
248=== modified file 'src/server/graphics/android/android_platform.h'
249--- src/server/graphics/android/android_platform.h 2013-03-22 17:08:01 +0000
250+++ src/server/graphics/android/android_platform.h 2013-04-10 12:56:24 +0000
251@@ -36,6 +36,12 @@
252 const std::shared_ptr<BufferInitializer>& buffer_initializer);
253 std::shared_ptr<Display> create_display();
254 std::shared_ptr<PlatformIPCPackage> get_ipc_package();
255+ void register_pause_resume_handlers(
256+ MainLoop& main_loop,
257+ std::function<void()> const& pause_handler,
258+ std::function<void()> const& resume_handler);
259+ void pause();
260+ void resume();
261 };
262
263 }
264
265=== modified file 'src/server/graphics/gbm/CMakeLists.txt'
266--- src/server/graphics/gbm/CMakeLists.txt 2013-03-13 04:54:15 +0000
267+++ src/server/graphics/gbm/CMakeLists.txt 2013-04-10 12:56:24 +0000
268@@ -24,6 +24,7 @@
269 kms_output.cpp
270 kms_output_container.cpp
271 kms_page_flipper.cpp
272+ linux_virtual_terminal.cpp
273 )
274
275 target_link_libraries(
276
277=== modified file 'src/server/graphics/gbm/gbm_display.cpp'
278--- src/server/graphics/gbm/gbm_display.cpp 2013-03-13 04:54:15 +0000
279+++ src/server/graphics/gbm/gbm_display.cpp 2013-04-10 12:56:24 +0000
280@@ -43,6 +43,10 @@
281 shared_egl.make_current();
282 }
283
284+mgg::GBMDisplay::~GBMDisplay()
285+{
286+}
287+
288 geom::Rectangle mgg::GBMDisplay::view_area() const
289 {
290 return display_buffers[0]->view_area();
291@@ -92,8 +96,18 @@
292 max_size.height.as_uint32_t());
293
294 /* Create a single DisplayBuffer that displays the surface on all the outputs */
295- std::unique_ptr<DisplayBuffer> db{new GBMDisplayBuffer{platform, listener, enabled_outputs,
296- std::move(surface), max_size,
297- shared_egl.context()}};
298+ std::unique_ptr<GBMDisplayBuffer> db{new GBMDisplayBuffer{platform, listener, enabled_outputs,
299+ std::move(surface), max_size,
300+ shared_egl.context()}};
301 display_buffers.push_back(std::move(db));
302 }
303+
304+void mgg::GBMDisplay::pause()
305+{
306+}
307+
308+void mgg::GBMDisplay::resume()
309+{
310+ for (auto& db_ptr : display_buffers)
311+ db_ptr->schedule_set_crtc();
312+}
313
314=== modified file 'src/server/graphics/gbm/gbm_display.h'
315--- src/server/graphics/gbm/gbm_display.h 2013-03-21 03:32:59 +0000
316+++ src/server/graphics/gbm/gbm_display.h 2013-04-10 12:56:24 +0000
317@@ -20,7 +20,6 @@
318 #define MIR_GRAPHICS_GBM_GBM_DISPLAY_H_
319
320 #include "mir/graphics/display.h"
321-#include "mir/graphics/display_buffer.h"
322 #include "kms_output_container.h"
323 #include "gbm_display_helpers.h"
324
325@@ -36,31 +35,37 @@
326 {
327
328 class DisplayReport;
329+class DisplayBuffer;
330
331 namespace gbm
332 {
333
334 class GBMPlatform;
335 class KMSOutput;
336+class GBMDisplayBuffer;
337
338 class GBMDisplay : public Display
339 {
340 public:
341 GBMDisplay(std::shared_ptr<GBMPlatform> const& platform,
342 std::shared_ptr<DisplayReport> const& listener);
343+ ~GBMDisplay();
344
345 geometry::Rectangle view_area() const;
346 void for_each_display_buffer(std::function<void(DisplayBuffer&)> const& f);
347
348 std::shared_ptr<DisplayConfiguration> configuration();
349
350+ void pause();
351+ void resume();
352+
353 private:
354 void configure(std::shared_ptr<DisplayConfiguration> const& conf);
355
356 std::shared_ptr<GBMPlatform> const platform;
357 std::shared_ptr<DisplayReport> const listener;
358 helpers::EGLHelper shared_egl;
359- std::vector<std::unique_ptr<DisplayBuffer>> display_buffers;
360+ std::vector<std::unique_ptr<GBMDisplayBuffer>> display_buffers;
361 KMSOutputContainer output_container;
362 };
363
364
365=== modified file 'src/server/graphics/gbm/gbm_display_buffer.cpp'
366--- src/server/graphics/gbm/gbm_display_buffer.cpp 2013-03-21 03:32:59 +0000
367+++ src/server/graphics/gbm/gbm_display_buffer.cpp 2013-04-10 12:56:24 +0000
368@@ -105,7 +105,8 @@
369 drm(platform->drm),
370 outputs(outputs),
371 surface_gbm{std::move(surface_gbm_param)},
372- size(size)
373+ size(size),
374+ needs_set_crtc{false}
375 {
376 egl.setup(platform->gbm, surface_gbm.get(), shared_context);
377
378@@ -180,11 +181,20 @@
379 * If the flip fails, release the buffer object to make it available
380 * for future rendering.
381 */
382- if (!schedule_and_wait_for_page_flip(bufobj))
383+ if (!needs_set_crtc && !schedule_and_wait_for_page_flip(bufobj))
384 {
385 bufobj->release();
386 return false;
387 }
388+ else if (needs_set_crtc)
389+ {
390+ for (auto& output : outputs)
391+ {
392+ if (!output->set_crtc(bufobj->get_drm_fb_id()))
393+ BOOST_THROW_EXCEPTION(std::runtime_error("Failed to set DRM crtc"));
394+ }
395+ needs_set_crtc = false;
396+ }
397
398 /*
399 * Release the last flipped buffer object (which is not displayed anymore)
400@@ -265,3 +275,8 @@
401 BOOST_THROW_EXCEPTION(std::runtime_error("Failed to make EGL surface current"));
402 }
403 }
404+
405+void mgg::GBMDisplayBuffer::schedule_set_crtc()
406+{
407+ needs_set_crtc = true;
408+}
409
410=== modified file 'src/server/graphics/gbm/gbm_display_buffer.h'
411--- src/server/graphics/gbm/gbm_display_buffer.h 2013-03-13 04:54:15 +0000
412+++ src/server/graphics/gbm/gbm_display_buffer.h 2013-04-10 12:56:24 +0000
413@@ -24,6 +24,7 @@
414
415 #include <vector>
416 #include <memory>
417+#include <atomic>
418
419 namespace mir
420 {
421@@ -55,6 +56,8 @@
422 void clear();
423 bool post_update();
424
425+ void schedule_set_crtc();
426+
427 private:
428 BufferObject* get_front_buffer_object();
429 bool schedule_and_wait_for_page_flip(BufferObject* bufobj);
430@@ -68,6 +71,7 @@
431 GBMSurfaceUPtr surface_gbm;
432 helpers::EGLHelper egl;
433 geometry::Size size;
434+ std::atomic<bool> needs_set_crtc;
435 };
436
437 }
438
439=== modified file 'src/server/graphics/gbm/gbm_display_helpers.cpp'
440--- src/server/graphics/gbm/gbm_display_helpers.cpp 2013-03-13 04:54:15 +0000
441+++ src/server/graphics/gbm/gbm_display_helpers.cpp 2013-04-10 12:56:24 +0000
442@@ -96,6 +96,47 @@
443 }
444 }
445
446+void mggh::DRMHelper::drop_master() const
447+{
448+ /* We must have our own device fd first, so that it has become the DRM master */
449+ if (fd < 0)
450+ {
451+ BOOST_THROW_EXCEPTION(
452+ std::runtime_error("Tried to drop DRM master without a DRM device"));
453+ }
454+
455+ int ret = drmDropMaster(fd);
456+
457+ if (ret < 0)
458+ {
459+ BOOST_THROW_EXCEPTION(
460+ boost::enable_error_info(
461+ std::runtime_error("Failed to drop DRM master"))
462+ << boost::errinfo_errno(ret));
463+ }
464+}
465+
466+void mggh::DRMHelper::set_master() const
467+{
468+ /* We must have our own device fd first, so that it has become the DRM master */
469+ if (fd < 0)
470+ {
471+ BOOST_THROW_EXCEPTION(
472+ std::runtime_error("Tried to set DRM master without a DRM device"));
473+ }
474+
475+ int ret = drmSetMaster(fd);
476+
477+ if (ret < 0)
478+ {
479+ BOOST_THROW_EXCEPTION(
480+ boost::enable_error_info(
481+ std::runtime_error("Failed to set DRM master"))
482+ << boost::errinfo_errno(ret));
483+ }
484+}
485+
486+
487 int mggh::DRMHelper::open_drm_device()
488 {
489 static const char *drivers[] = {
490
491=== modified file 'src/server/graphics/gbm/gbm_display_helpers.h'
492--- src/server/graphics/gbm/gbm_display_helpers.h 2013-03-21 03:32:59 +0000
493+++ src/server/graphics/gbm/gbm_display_helpers.h 2013-04-10 12:56:24 +0000
494@@ -57,6 +57,9 @@
495 int get_authenticated_fd();
496 void auth_magic(drm_magic_t magic) const;
497
498+ void drop_master() const;
499+ void set_master() const;
500+
501 int fd;
502
503 private:
504
505=== modified file 'src/server/graphics/gbm/gbm_platform.cpp'
506--- src/server/graphics/gbm/gbm_platform.cpp 2013-03-13 04:54:15 +0000
507+++ src/server/graphics/gbm/gbm_platform.cpp 2013-04-10 12:56:24 +0000
508@@ -21,6 +21,7 @@
509 #include <boost/throw_exception.hpp>
510 #include "gbm_buffer_allocator.h"
511 #include "gbm_display.h"
512+#include "linux_virtual_terminal.h"
513 #include "mir/graphics/platform_ipc_package.h"
514 #include "mir/logging/logger.h"
515 #include "mir/logging/dumb_console_logger.h"
516@@ -52,9 +53,12 @@
517
518 }
519
520-mgg::GBMPlatform::GBMPlatform(std::shared_ptr<DisplayReport> const& listener) :
521- listener(listener)
522+mgg::GBMPlatform::GBMPlatform(std::shared_ptr<DisplayReport> const& listener,
523+ std::shared_ptr<VirtualTerminal> const& vt)
524+ : listener{listener},
525+ vt{vt}
526 {
527+ vt->set_graphics_mode();
528 drm.setup();
529 gbm.setup(drm);
530 }
531@@ -78,6 +82,24 @@
532 return std::make_shared<GBMPlatformIPCPackage>(drm.get_authenticated_fd());
533 }
534
535+void mgg::GBMPlatform::register_pause_resume_handlers(
536+ MainLoop& main_loop,
537+ std::function<void()> const& pause_handler,
538+ std::function<void()> const& resume_handler)
539+{
540+ vt->register_switch_handlers(main_loop, pause_handler, resume_handler);
541+}
542+
543+void mgg::GBMPlatform::pause()
544+{
545+ drm.drop_master();
546+}
547+
548+void mgg::GBMPlatform::resume()
549+{
550+ drm.set_master();
551+}
552+
553 void mgg::GBMPlatform::drm_auth_magic(drm_magic_t magic)
554 {
555 drm.auth_magic(magic);
556@@ -85,5 +107,7 @@
557
558 std::shared_ptr<mg::Platform> mg::create_platform(std::shared_ptr<DisplayReport> const& report)
559 {
560- return std::make_shared<mgg::GBMPlatform>(report);
561+ return std::make_shared<mgg::GBMPlatform>(
562+ report,
563+ std::make_shared<mgg::LinuxVirtualTerminal>());
564 }
565
566=== modified file 'src/server/graphics/gbm/gbm_platform.h'
567--- src/server/graphics/gbm/gbm_platform.h 2013-03-13 04:54:15 +0000
568+++ src/server/graphics/gbm/gbm_platform.h 2013-04-10 12:56:24 +0000
569@@ -30,18 +30,27 @@
570 namespace gbm
571 {
572
573+class VirtualTerminal;
574+
575 class GBMPlatform : public Platform,
576 public DRMAuthenticator,
577 public std::enable_shared_from_this<GBMPlatform>
578 {
579 public:
580- explicit GBMPlatform(std::shared_ptr<DisplayReport> const& reporter);
581+ explicit GBMPlatform(std::shared_ptr<DisplayReport> const& reporter,
582+ std::shared_ptr<VirtualTerminal> const& vt);
583
584 /* From Platform */
585 std::shared_ptr<compositor::GraphicBufferAllocator> create_buffer_allocator(
586 const std::shared_ptr<BufferInitializer>& buffer_initializer);
587 std::shared_ptr<Display> create_display();
588 std::shared_ptr<PlatformIPCPackage> get_ipc_package();
589+ void register_pause_resume_handlers(
590+ MainLoop& main_loop,
591+ std::function<void()> const& pause_handler,
592+ std::function<void()> const& resume_handler);
593+ void pause();
594+ void resume();
595
596 /* From DRMAuthenticator */
597 void drm_auth_magic(drm_magic_t magic);
598@@ -49,7 +58,8 @@
599 helpers::DRMHelper drm;
600 helpers::GBMHelper gbm;
601
602- std::shared_ptr<DisplayReport> listener;
603+ std::shared_ptr<DisplayReport> const listener;
604+ std::shared_ptr<VirtualTerminal> const vt;
605 };
606
607 }
608
609=== added file 'src/server/graphics/gbm/linux_virtual_terminal.cpp'
610--- src/server/graphics/gbm/linux_virtual_terminal.cpp 1970-01-01 00:00:00 +0000
611+++ src/server/graphics/gbm/linux_virtual_terminal.cpp 2013-04-10 12:56:24 +0000
612@@ -0,0 +1,180 @@
613+/*
614+ * Copyright © 2013 Canonical Ltd.
615+ *
616+ * This program is free software: you can redistribute it and/or modify it
617+ * under the terms of the GNU Lesser General Public License version 3,
618+ * as published by the Free Software Foundation.
619+ *
620+ * This program is distributed in the hope that it will be useful,
621+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
622+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
623+ * GNU General Public License for more details.
624+ *
625+ * You should have received a copy of the GNU Lesser General Public License
626+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
627+ *
628+ * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
629+ */
630+
631+#include "linux_virtual_terminal.h"
632+#include "mir/main_loop.h"
633+
634+#include <boost/throw_exception.hpp>
635+#include <boost/exception/errinfo_errno.hpp>
636+#include <boost/exception/errinfo_file_name.hpp>
637+
638+#include <vector>
639+#include <string>
640+#include <sstream>
641+#include <stdexcept>
642+#include <csignal>
643+
644+#include <fcntl.h>
645+#include <linux/vt.h>
646+#include <linux/kd.h>
647+#include <sys/ioctl.h>
648+
649+namespace mgg = mir::graphics::gbm;
650+
651+namespace
652+{
653+
654+int find_active_vt_number()
655+{
656+ static std::vector<std::string> const paths{"/dev/tty", "/dev/tty0"};
657+ int active_vt{-1};
658+
659+ for (auto& p : paths)
660+ {
661+ auto fd = open(p.c_str(), O_RDONLY, 0);
662+ if (fd < 0)
663+ fd = open(p.c_str(), O_WRONLY, 0);
664+
665+ if (fd >= 0)
666+ {
667+ struct vt_stat vts;
668+ auto status = ioctl(fd, VT_GETSTATE, &vts);
669+ close(fd);
670+
671+ if (status >= 0)
672+ {
673+ active_vt = vts.v_active;
674+ break;
675+ }
676+ }
677+ }
678+
679+ if (active_vt < 0)
680+ {
681+ BOOST_THROW_EXCEPTION(
682+ std::runtime_error("Failed to find the current VT"));
683+ }
684+
685+ return active_vt;
686+}
687+
688+int open_vt(int vt_number)
689+{
690+ std::stringstream vt_path_stream;
691+ vt_path_stream << "/dev/tty" << vt_number;
692+
693+ std::string const active_vt_path{vt_path_stream.str()};
694+
695+ auto vt_fd = open(active_vt_path.c_str(), O_RDONLY | O_NDELAY, 0);
696+
697+ if (vt_fd < 0)
698+ {
699+ BOOST_THROW_EXCEPTION(
700+ boost::enable_error_info(
701+ std::runtime_error("Failed to open current VT"))
702+ << boost::errinfo_file_name(active_vt_path)
703+ << boost::errinfo_errno(errno));
704+ }
705+
706+ return vt_fd;
707+}
708+
709+}
710+
711+mgg::LinuxVirtualTerminal::LinuxVirtualTerminal()
712+ : vt_fd{open_vt(find_active_vt_number())},
713+ prev_kd_mode{0},
714+ prev_vt_mode(),
715+ active{true}
716+{
717+ if (ioctl(vt_fd.fd(), KDGETMODE, &prev_kd_mode) < 0)
718+ {
719+ BOOST_THROW_EXCEPTION(
720+ boost::enable_error_info(
721+ std::runtime_error("Failed to get current VT mode"))
722+ << boost::errinfo_errno(errno));
723+ }
724+
725+ if (ioctl(vt_fd.fd(), VT_GETMODE, &prev_vt_mode) < 0)
726+ {
727+ BOOST_THROW_EXCEPTION(
728+ boost::enable_error_info(
729+ std::runtime_error("Failed to get the current VT")) << boost::errinfo_errno(errno));
730+ }
731+}
732+
733+mgg::LinuxVirtualTerminal::~LinuxVirtualTerminal() noexcept(true)
734+{
735+ if (vt_fd.fd() > 0)
736+ {
737+ ioctl(vt_fd.fd(), KDSETMODE, prev_kd_mode);
738+ ioctl(vt_fd.fd(), VT_SETMODE, &prev_vt_mode);
739+ }
740+}
741+
742+void mgg::LinuxVirtualTerminal::set_graphics_mode()
743+{
744+ if (ioctl(vt_fd.fd(), KDSETMODE, KD_GRAPHICS) < 0)
745+ {
746+ BOOST_THROW_EXCEPTION(
747+ boost::enable_error_info(
748+ std::runtime_error("Failed to set VT to graphics mode"))
749+ << boost::errinfo_errno(errno));
750+ }
751+}
752+
753+void mgg::LinuxVirtualTerminal::register_switch_handlers(
754+ MainLoop& main_loop,
755+ std::function<void()> const& switch_away,
756+ std::function<void()> const& switch_back)
757+{
758+ main_loop.register_signal_handler(
759+ {SIGUSR1},
760+ [this, switch_away, switch_back](int)
761+ {
762+ active = !active;
763+ if (active)
764+ {
765+ static int const allow_switch{2};
766+ switch_back();
767+ ioctl(vt_fd.fd(), VT_RELDISP, allow_switch);
768+ }
769+ else
770+ {
771+ switch_away();
772+ ioctl(vt_fd.fd(), VT_RELDISP, VT_ACKACQ);
773+ }
774+ });
775+
776+ struct vt_mode vtm
777+ {
778+ VT_PROCESS,
779+ 0,
780+ SIGUSR1,
781+ SIGUSR1,
782+ 0
783+ };
784+
785+ if (ioctl(vt_fd.fd(), VT_SETMODE, &vtm) < 0)
786+ {
787+ BOOST_THROW_EXCEPTION(
788+ boost::enable_error_info(
789+ std::runtime_error("Failed to set the current VT mode"))
790+ << boost::errinfo_errno(errno));
791+ }
792+}
793
794=== added file 'src/server/graphics/gbm/linux_virtual_terminal.h'
795--- src/server/graphics/gbm/linux_virtual_terminal.h 1970-01-01 00:00:00 +0000
796+++ src/server/graphics/gbm/linux_virtual_terminal.h 2013-04-10 12:56:24 +0000
797@@ -0,0 +1,67 @@
798+/*
799+ * Copyright © 2013 Canonical Ltd.
800+ *
801+ * This program is free software: you can redistribute it and/or modify it
802+ * under the terms of the GNU Lesser General Public License version 3,
803+ * as published by the Free Software Foundation.
804+ *
805+ * This program is distributed in the hope that it will be useful,
806+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
807+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
808+ * GNU General Public License for more details.
809+ *
810+ * You should have received a copy of the GNU Lesser General Public License
811+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
812+ *
813+ * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
814+ */
815+
816+#ifndef MIR_GRAPHICS_GBM_LINUX_VIRTUAL_TERMINAL_H_
817+#define MIR_GRAPHICS_GBM_LINUX_VIRTUAL_TERMINAL_H_
818+
819+#include "virtual_terminal.h"
820+
821+#include <linux/vt.h>
822+#include <unistd.h>
823+
824+namespace mir
825+{
826+namespace graphics
827+{
828+namespace gbm
829+{
830+
831+class LinuxVirtualTerminal : public VirtualTerminal
832+{
833+public:
834+ LinuxVirtualTerminal();
835+ ~LinuxVirtualTerminal() noexcept(true);
836+
837+ void set_graphics_mode();
838+ void register_switch_handlers(
839+ MainLoop& main_loop,
840+ std::function<void()> const& switch_away,
841+ std::function<void()> const& switch_back);
842+
843+private:
844+ class FDWrapper
845+ {
846+ public:
847+ FDWrapper(int fd) : fd_{fd} {}
848+ ~FDWrapper() { if (fd_ >= 0) close(fd_); }
849+ int fd() const { return fd_; }
850+ private:
851+ int const fd_;
852+ };
853+
854+ FDWrapper const vt_fd;
855+ int prev_kd_mode;
856+ struct vt_mode prev_vt_mode;
857+ bool active;
858+};
859+
860+}
861+}
862+}
863+
864+#endif /* MIR_GRAPHICS_GBM_LINUX_VIRTUAL_TERMINAL_H_ */
865
866=== added file 'src/server/graphics/gbm/virtual_terminal.h'
867--- src/server/graphics/gbm/virtual_terminal.h 1970-01-01 00:00:00 +0000
868+++ src/server/graphics/gbm/virtual_terminal.h 2013-04-10 12:56:24 +0000
869@@ -0,0 +1,55 @@
870+/*
871+ * Copyright © 2013 Canonical Ltd.
872+ *
873+ * This program is free software: you can redistribute it and/or modify it
874+ * under the terms of the GNU Lesser General Public License version 3,
875+ * as published by the Free Software Foundation.
876+ *
877+ * This program is distributed in the hope that it will be useful,
878+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
879+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
880+ * GNU General Public License for more details.
881+ *
882+ * You should have received a copy of the GNU Lesser General Public License
883+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
884+ *
885+ * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
886+ */
887+
888+#ifndef MIR_GRAPHICS_GBM_VIRTUAL_TERMINAL_H_
889+#define MIR_GRAPHICS_GBM_VIRTUAL_TERMINAL_H_
890+
891+#include <functional>
892+
893+namespace mir
894+{
895+
896+class MainLoop;
897+
898+namespace graphics
899+{
900+namespace gbm
901+{
902+
903+class VirtualTerminal
904+{
905+public:
906+ virtual ~VirtualTerminal() = default;
907+
908+ virtual void set_graphics_mode() = 0;
909+ virtual void register_switch_handlers(
910+ MainLoop& main_loop,
911+ std::function<void()> const& switch_away,
912+ std::function<void()> const& switch_back) = 0;
913+
914+protected:
915+ VirtualTerminal() = default;
916+ VirtualTerminal(VirtualTerminal const&) = delete;
917+ VirtualTerminal& operator=(VirtualTerminal const&) = delete;
918+};
919+
920+}
921+}
922+}
923+
924+#endif /* MIR_GRAPHICS_GBM_VIRTUAL_TERMINAL_H_ */
925
926=== modified file 'tests/behavior-tests/session_management_context.cpp'
927--- tests/behavior-tests/session_management_context.cpp 2013-03-29 16:51:35 +0000
928+++ tests/behavior-tests/session_management_context.cpp 2013-04-10 12:56:24 +0000
929@@ -105,6 +105,9 @@
930 return std::shared_ptr<mg::DisplayConfiguration>();
931 }
932
933+ void pause() {}
934+ void resume() {}
935+
936 geom::Rectangle area;
937 };
938
939
940=== modified file 'tests/integration-tests/cucumber/test_session_management_context.cpp'
941--- tests/integration-tests/cucumber/test_session_management_context.cpp 2013-04-08 16:20:33 +0000
942+++ tests/integration-tests/cucumber/test_session_management_context.cpp 2013-04-10 12:56:24 +0000
943@@ -53,6 +53,7 @@
944 MOCK_METHOD0(the_display, std::shared_ptr<mg::Display>());
945 MOCK_METHOD0(the_compositor, std::shared_ptr<mc::Compositor>());
946 MOCK_METHOD0(the_main_loop, std::shared_ptr<mir::MainLoop>());
947+ MOCK_METHOD0(the_graphics_platform, std::shared_ptr<mg::Platform>());
948 };
949
950 MATCHER_P(NamedWindowWithNoGeometry, name, "")
951
952=== modified file 'tests/integration-tests/graphics/gbm/test_buffer_integration.cpp'
953--- tests/integration-tests/graphics/gbm/test_buffer_integration.cpp 2013-03-13 08:09:52 +0000
954+++ tests/integration-tests/graphics/gbm/test_buffer_integration.cpp 2013-04-10 12:56:24 +0000
955@@ -99,6 +99,15 @@
956 {
957 return std::shared_ptr<mg::PlatformIPCPackage>();
958 }
959+
960+ virtual void register_pause_resume_handlers(mir::MainLoop&,
961+ std::function<void()> const&,
962+ std::function<void()> const&)
963+ {
964+ }
965+
966+ virtual void pause() {}
967+ virtual void resume() {}
968 };
969
970 class GBMBufferIntegration : public ::testing::Test
971
972=== modified file 'tests/integration-tests/test_display_info.cpp'
973--- tests/integration-tests/test_display_info.cpp 2013-03-22 10:34:16 +0000
974+++ tests/integration-tests/test_display_info.cpp 2013-04-10 12:56:24 +0000
975@@ -104,6 +104,14 @@
976 return std::make_shared<mg::PlatformIPCPackage>();
977 }
978
979+ void register_pause_resume_handlers(mir::MainLoop&,
980+ std::function<void()> const&,
981+ std::function<void()> const&)
982+ {
983+ }
984+
985+ void pause() {}
986+ void resume() {}
987 };
988
989 void connection_callback(MirConnection* connection, void* context)
990
991=== modified file 'tests/integration-tests/test_display_server_main_loop_events.cpp'
992--- tests/integration-tests/test_display_server_main_loop_events.cpp 2013-04-08 16:20:33 +0000
993+++ tests/integration-tests/test_display_server_main_loop_events.cpp 2013-04-10 12:56:24 +0000
994@@ -17,6 +17,9 @@
995 */
996
997 #include "mir/compositor/compositor.h"
998+#include "mir/graphics/platform.h"
999+#include "mir/graphics/display.h"
1000+#include "mir/main_loop.h"
1001
1002 #include "mir_test_framework/testing_server_configuration.h"
1003 #include "mir_test_doubles/mock_input_manager.h"
1004@@ -30,6 +33,7 @@
1005
1006 namespace mi = mir::input;
1007 namespace mc = mir::compositor;
1008+namespace mg = mir::graphics;
1009 namespace mtd = mir::test::doubles;
1010 namespace mtf = mir_test_framework;
1011
1012@@ -43,6 +47,85 @@
1013 MOCK_METHOD0(stop, void());
1014 };
1015
1016+class MockGraphicsPlatform : public mg::Platform
1017+{
1018+public:
1019+ MockGraphicsPlatform(std::shared_ptr<mg::Platform> const& platform,
1020+ int pause_signal, int resume_signal)
1021+ : platform{platform},
1022+ pause_signal{pause_signal},
1023+ resume_signal{resume_signal}
1024+ {
1025+ }
1026+
1027+ std::shared_ptr<mc::GraphicBufferAllocator> create_buffer_allocator(
1028+ std::shared_ptr<mg::BufferInitializer> const& buffer_initializer)
1029+ {
1030+ return platform->create_buffer_allocator(buffer_initializer);
1031+ }
1032+
1033+ std::shared_ptr<mg::Display> create_display()
1034+ {
1035+ return platform->create_display();
1036+ }
1037+
1038+ std::shared_ptr<mg::PlatformIPCPackage> get_ipc_package()
1039+ {
1040+ return platform->get_ipc_package();
1041+ }
1042+
1043+ void register_pause_resume_handlers(
1044+ mir::MainLoop& main_loop,
1045+ std::function<void()> const& pause_handler,
1046+ std::function<void()> const& resume_handler)
1047+ {
1048+ main_loop.register_signal_handler(
1049+ {pause_signal},
1050+ [pause_handler](int) { pause_handler(); });
1051+ main_loop.register_signal_handler(
1052+ {resume_signal},
1053+ [resume_handler](int) { resume_handler(); });
1054+ }
1055+
1056+ MOCK_METHOD0(pause, void());
1057+ MOCK_METHOD0(resume, void());
1058+
1059+private:
1060+ std::shared_ptr<mg::Platform> const platform;
1061+ int const pause_signal;
1062+ int const resume_signal;
1063+};
1064+
1065+class MockDisplay : public mg::Display
1066+{
1067+public:
1068+ MockDisplay(std::shared_ptr<mg::Display> const& display)
1069+ : display{display}
1070+ {
1071+ }
1072+
1073+ mir::geometry::Rectangle view_area() const
1074+ {
1075+ return display->view_area();
1076+ }
1077+
1078+ void for_each_display_buffer(std::function<void(mg::DisplayBuffer&)> const& f)
1079+ {
1080+ display->for_each_display_buffer(f);
1081+ }
1082+
1083+ std::shared_ptr<mg::DisplayConfiguration> configuration()
1084+ {
1085+ return display->configuration();
1086+ }
1087+
1088+ MOCK_METHOD0(pause, void());
1089+ MOCK_METHOD0(resume, void());
1090+
1091+private:
1092+ std::shared_ptr<mg::Display> const display;
1093+};
1094+
1095 class ServerConfig : public mtf::TestingServerConfiguration
1096 {
1097 public:
1098@@ -77,6 +160,84 @@
1099 std::shared_ptr<MockCompositor> mock_compositor;
1100 };
1101
1102+
1103+class PauseResumeServerConfig : public mtf::TestingServerConfiguration
1104+{
1105+public:
1106+ PauseResumeServerConfig()
1107+ : pause_signal{SIGUSR1}, resume_signal{SIGUSR2}
1108+ {
1109+ }
1110+
1111+ std::shared_ptr<mg::Platform> the_graphics_platform() override
1112+ {
1113+ if (!mock_graphics_platform)
1114+ {
1115+ auto graphics_platform = mtf::TestingServerConfiguration::the_graphics_platform();
1116+ mock_graphics_platform =
1117+ std::make_shared<MockGraphicsPlatform>(graphics_platform,
1118+ pause_signal,
1119+ resume_signal);
1120+ }
1121+
1122+ return mock_graphics_platform;
1123+ }
1124+
1125+ std::shared_ptr<mg::Display> the_display() override
1126+ {
1127+ if (!mock_display)
1128+ {
1129+ auto display = mtf::TestingServerConfiguration::the_display();
1130+ mock_display = std::make_shared<MockDisplay>(display);
1131+ }
1132+
1133+ return mock_display;
1134+ }
1135+
1136+ std::shared_ptr<mc::Compositor> the_compositor() override
1137+ {
1138+ if (!mock_compositor)
1139+ mock_compositor = std::make_shared<MockCompositor>();
1140+
1141+ return mock_compositor;
1142+ }
1143+
1144+ std::shared_ptr<MockGraphicsPlatform> the_mock_graphics_platform()
1145+ {
1146+ the_graphics_platform();
1147+ return mock_graphics_platform;
1148+ }
1149+
1150+ std::shared_ptr<MockDisplay> the_mock_display()
1151+ {
1152+ the_display();
1153+ return mock_display;
1154+ }
1155+
1156+ std::shared_ptr<MockCompositor> the_mock_compositor()
1157+ {
1158+ the_compositor();
1159+ return mock_compositor;
1160+ }
1161+
1162+ void emit_pause_event()
1163+ {
1164+ kill(getpid(), pause_signal);
1165+ }
1166+
1167+ void emit_resume_event()
1168+ {
1169+ kill(getpid(), resume_signal);
1170+ }
1171+private:
1172+ std::shared_ptr<MockGraphicsPlatform> mock_graphics_platform;
1173+ std::shared_ptr<MockCompositor> mock_compositor;
1174+ std::shared_ptr<MockDisplay> mock_display;
1175+
1176+ int const pause_signal;
1177+ int const resume_signal;
1178+};
1179+
1180 }
1181
1182 TEST(DisplayServerMainLoopEvents, display_server_shuts_down_properly_on_sigint)
1183@@ -100,3 +261,75 @@
1184 kill(getpid(), SIGTERM);
1185 });
1186 }
1187+
1188+TEST(DisplayServerMainLoopEvents, display_server_components_pause_and_resume)
1189+{
1190+ using namespace testing;
1191+
1192+ PauseResumeServerConfig server_config;
1193+
1194+ auto mock_compositor = server_config.the_mock_compositor();
1195+ auto mock_display = server_config.the_mock_display();
1196+ auto mock_graphics_platform = server_config.the_mock_graphics_platform();
1197+
1198+ {
1199+ InSequence s;
1200+
1201+ /* Start */
1202+ EXPECT_CALL(*mock_compositor, start()).Times(1);
1203+
1204+ /* Pause */
1205+ EXPECT_CALL(*mock_compositor, stop()).Times(1);
1206+ EXPECT_CALL(*mock_display, pause()).Times(1);
1207+ EXPECT_CALL(*mock_graphics_platform, pause()).Times(1);
1208+
1209+ /* Resume */
1210+ EXPECT_CALL(*mock_graphics_platform, resume()).Times(1);
1211+ EXPECT_CALL(*mock_display, resume()).Times(1);
1212+ EXPECT_CALL(*mock_compositor, start()).Times(1);
1213+
1214+ /* Stop */
1215+ EXPECT_CALL(*mock_compositor, stop()).Times(1);
1216+ }
1217+
1218+ mir::run_mir(server_config,
1219+ [&server_config](mir::DisplayServer&)
1220+ {
1221+ server_config.emit_pause_event();
1222+ server_config.emit_resume_event();
1223+ kill(getpid(), SIGTERM);
1224+ });
1225+}
1226+
1227+TEST(DisplayServerMainLoopEvents, display_server_quits_when_paused)
1228+{
1229+ using namespace testing;
1230+
1231+ PauseResumeServerConfig server_config;
1232+
1233+ auto mock_compositor = server_config.the_mock_compositor();
1234+ auto mock_display = server_config.the_mock_display();
1235+ auto mock_graphics_platform = server_config.the_mock_graphics_platform();
1236+
1237+ {
1238+ InSequence s;
1239+
1240+ /* Start */
1241+ EXPECT_CALL(*mock_compositor, start()).Times(1);
1242+
1243+ /* Pause */
1244+ EXPECT_CALL(*mock_compositor, stop()).Times(1);
1245+ EXPECT_CALL(*mock_display, pause()).Times(1);
1246+ EXPECT_CALL(*mock_graphics_platform, pause()).Times(1);
1247+
1248+ /* Stop */
1249+ EXPECT_CALL(*mock_compositor, stop()).Times(1);
1250+ }
1251+
1252+ mir::run_mir(server_config,
1253+ [&server_config](mir::DisplayServer&)
1254+ {
1255+ server_config.emit_pause_event();
1256+ kill(getpid(), SIGTERM);
1257+ });
1258+}
1259
1260=== modified file 'tests/integration-tests/test_drm_auth_magic.cpp'
1261--- tests/integration-tests/test_drm_auth_magic.cpp 2013-03-22 10:34:16 +0000
1262+++ tests/integration-tests/test_drm_auth_magic.cpp 2013-04-10 12:56:24 +0000
1263@@ -80,6 +80,15 @@
1264 return std::make_shared<mg::PlatformIPCPackage>();
1265 }
1266
1267+ void register_pause_resume_handlers(mir::MainLoop&,
1268+ std::function<void()> const&,
1269+ std::function<void()> const&)
1270+ {
1271+ }
1272+
1273+ void pause() {}
1274+ void resume() {}
1275+
1276 MOCK_METHOD1(drm_auth_magic, void(unsigned int));
1277 };
1278
1279
1280=== modified file 'tests/integration-tests/test_surfaceloop.cpp'
1281--- tests/integration-tests/test_surfaceloop.cpp 2013-04-08 04:03:40 +0000
1282+++ tests/integration-tests/test_surfaceloop.cpp 2013-04-10 12:56:24 +0000
1283@@ -133,6 +133,8 @@
1284 auto null_configuration = std::shared_ptr<mg::DisplayConfiguration>();
1285 return null_configuration;
1286 }
1287+ void pause() {}
1288+ void resume() {}
1289 };
1290
1291 struct SurfaceSync
1292@@ -346,6 +348,15 @@
1293 {
1294 return std::make_shared<mg::PlatformIPCPackage>();
1295 }
1296+
1297+ void register_pause_resume_handlers(mir::MainLoop&,
1298+ std::function<void()> const&,
1299+ std::function<void()> const&)
1300+ {
1301+ }
1302+
1303+ void pause() {}
1304+ void resume() {}
1305 };
1306
1307 std::shared_ptr<mg::Platform> the_graphics_platform()
1308@@ -473,6 +484,15 @@
1309 {
1310 return std::make_shared<mg::PlatformIPCPackage>();
1311 }
1312+
1313+ void register_pause_resume_handlers(mir::MainLoop&,
1314+ std::function<void()> const&,
1315+ std::function<void()> const&)
1316+ {
1317+ }
1318+
1319+ void pause() {}
1320+ void resume() {}
1321 };
1322
1323 std::shared_ptr<mg::Platform> the_graphics_platform()
1324
1325=== modified file 'tests/mir_test_framework/testing_server_options.cpp'
1326--- tests/mir_test_framework/testing_server_options.cpp 2013-03-29 16:51:35 +0000
1327+++ tests/mir_test_framework/testing_server_options.cpp 2013-04-10 12:56:24 +0000
1328@@ -86,6 +86,8 @@
1329 auto null_configuration = std::shared_ptr<mg::DisplayConfiguration>();
1330 return null_configuration;
1331 }
1332+ void pause() {}
1333+ void resume() {}
1334 };
1335
1336 class StubGraphicPlatform : public mg::Platform
1337@@ -105,6 +107,16 @@
1338 {
1339 return std::make_shared<mg::PlatformIPCPackage>();
1340 }
1341+
1342+ virtual void register_pause_resume_handlers(
1343+ mir::MainLoop&,
1344+ std::function<void()> const&,
1345+ std::function<void()> const&)
1346+ {
1347+ }
1348+
1349+ virtual void pause() {}
1350+ virtual void resume() {}
1351 };
1352
1353 class StubRenderer : public mg::Renderer
1354
1355=== modified file 'tests/unit-tests/compositor/test_multi_threaded_compositor.cpp'
1356--- tests/unit-tests/compositor/test_multi_threaded_compositor.cpp 2013-03-27 15:12:09 +0000
1357+++ tests/unit-tests/compositor/test_multi_threaded_compositor.cpp 2013-04-10 12:56:24 +0000
1358@@ -54,6 +54,9 @@
1359 return std::shared_ptr<mg::DisplayConfiguration>();
1360 }
1361
1362+ void pause() {}
1363+ void resume() {}
1364+
1365 private:
1366 std::vector<mtd::NullDisplayBuffer> buffers;
1367 };
1368
1369=== modified file 'tests/unit-tests/frontend/test_session_mediator.cpp'
1370--- tests/unit-tests/frontend/test_session_mediator.cpp 2013-03-29 16:51:35 +0000
1371+++ tests/unit-tests/frontend/test_session_mediator.cpp 2013-04-10 12:56:24 +0000
1372@@ -121,6 +121,15 @@
1373 {
1374 return std::make_shared<mg::PlatformIPCPackage>();
1375 }
1376+
1377+ void register_pause_resume_handlers(mir::MainLoop&,
1378+ std::function<void()> const&,
1379+ std::function<void()> const&)
1380+ {
1381+ }
1382+
1383+ void pause() {}
1384+ void resume() {}
1385 };
1386
1387 }
1388
1389=== modified file 'tests/unit-tests/frontend/test_session_mediator_android.cpp'
1390--- tests/unit-tests/frontend/test_session_mediator_android.cpp 2013-03-21 03:32:59 +0000
1391+++ tests/unit-tests/frontend/test_session_mediator_android.cpp 2013-04-10 12:56:24 +0000
1392@@ -78,6 +78,15 @@
1393 {
1394 return std::make_shared<mg::PlatformIPCPackage>();
1395 }
1396+
1397+ void register_pause_resume_handlers(mir::MainLoop&,
1398+ std::function<void()> const&,
1399+ std::function<void()> const&)
1400+ {
1401+ }
1402+
1403+ void pause() {}
1404+ void resume() {}
1405 };
1406
1407 }
1408
1409=== modified file 'tests/unit-tests/frontend/test_session_mediator_gbm.cpp'
1410--- tests/unit-tests/frontend/test_session_mediator_gbm.cpp 2013-03-21 03:32:59 +0000
1411+++ tests/unit-tests/frontend/test_session_mediator_gbm.cpp 2013-04-10 12:56:24 +0000
1412@@ -82,6 +82,15 @@
1413 return std::make_shared<mg::PlatformIPCPackage>();
1414 }
1415
1416+ void register_pause_resume_handlers(mir::MainLoop&,
1417+ std::function<void()> const&,
1418+ std::function<void()> const&)
1419+ {
1420+ }
1421+
1422+ void pause() {}
1423+ void resume() {}
1424+
1425 MOCK_METHOD1(drm_auth_magic, void(drm_magic_t));
1426 };
1427
1428
1429=== modified file 'tests/unit-tests/graphics/gbm/mock_drm.cpp'
1430--- tests/unit-tests/graphics/gbm/mock_drm.cpp 2013-02-05 16:18:10 +0000
1431+++ tests/unit-tests/graphics/gbm/mock_drm.cpp 2013-04-10 12:56:24 +0000
1432@@ -341,3 +341,13 @@
1433 {
1434 return global_mock->drmAuthMagic(fd, magic);
1435 }
1436+
1437+int drmSetMaster(int fd)
1438+{
1439+ return global_mock->drmSetMaster(fd);
1440+}
1441+
1442+int drmDropMaster(int fd)
1443+{
1444+ return global_mock->drmDropMaster(fd);
1445+}
1446
1447=== modified file 'tests/unit-tests/graphics/gbm/mock_drm.h'
1448--- tests/unit-tests/graphics/gbm/mock_drm.h 2013-02-05 16:18:10 +0000
1449+++ tests/unit-tests/graphics/gbm/mock_drm.h 2013-04-10 12:56:24 +0000
1450@@ -114,6 +114,9 @@
1451 MOCK_METHOD2(drmGetMagic, int(int fd, drm_magic_t *magic));
1452 MOCK_METHOD2(drmAuthMagic, int(int fd, drm_magic_t magic));
1453
1454+ MOCK_METHOD1(drmSetMaster, int(int fd));
1455+ MOCK_METHOD1(drmDropMaster, int(int fd));
1456+
1457 FakeDRMResources fake_drm;
1458 };
1459
1460
1461=== modified file 'tests/unit-tests/graphics/gbm/test_gbm_buffer.cpp'
1462--- tests/unit-tests/graphics/gbm/test_gbm_buffer.cpp 2013-03-13 08:09:52 +0000
1463+++ tests/unit-tests/graphics/gbm/test_gbm_buffer.cpp 2013-04-10 12:56:24 +0000
1464@@ -27,6 +27,7 @@
1465 #include "mir/graphics/buffer_initializer.h"
1466 #include "mir/compositor/buffer_ipc_package.h"
1467 #include "mir/compositor/buffer_properties.h"
1468+#include "mir_test_doubles/null_virtual_terminal.h"
1469
1470 #include "mir/graphics/null_display_report.h"
1471
1472@@ -42,6 +43,7 @@
1473 namespace mg=mir::graphics;
1474 namespace mgg=mir::graphics::gbm;
1475 namespace geom=mir::geometry;
1476+namespace mtd=mir::test::doubles;
1477
1478 class GBMGraphicBufferBasic : public ::testing::Test
1479 {
1480@@ -77,7 +79,8 @@
1481 ON_CALL(mock_egl, eglGetProcAddress(StrEq("glEGLImageTargetTexture2DOES")))
1482 .WillByDefault(Return(reinterpret_cast<func_ptr_t>(glEGLImageTargetTexture2DOES)));
1483
1484- platform = std::make_shared<mgg::GBMPlatform>(std::make_shared<mg::NullDisplayReport>());
1485+ platform = std::make_shared<mgg::GBMPlatform>(std::make_shared<mg::NullDisplayReport>(),
1486+ std::make_shared<mtd::NullVirtualTerminal>());
1487 null_init = std::make_shared<mg::NullBufferInitializer>();
1488 allocator.reset(new mgg::GBMBufferAllocator(platform, null_init));
1489 }
1490
1491=== modified file 'tests/unit-tests/graphics/gbm/test_gbm_buffer_allocator.cpp'
1492--- tests/unit-tests/graphics/gbm/test_gbm_buffer_allocator.cpp 2013-03-13 08:09:52 +0000
1493+++ tests/unit-tests/graphics/gbm/test_gbm_buffer_allocator.cpp 2013-04-10 12:56:24 +0000
1494@@ -27,6 +27,7 @@
1495 #include "mir_test/egl_mock.h"
1496 #include "mir_test/gl_mock.h"
1497 #include "mir_test_doubles/mock_buffer_initializer.h"
1498+#include "mir_test_doubles/null_virtual_terminal.h"
1499 #include "mir/graphics/null_display_report.h"
1500
1501 #include <memory>
1502@@ -67,7 +68,8 @@
1503 ON_CALL(mock_egl, eglGetProcAddress(StrEq("glEGLImageTargetTexture2DOES")))
1504 .WillByDefault(Return(reinterpret_cast<func_ptr_t>(glEGLImageTargetTexture2DOES)));
1505
1506- platform = std::make_shared<mgg::GBMPlatform>(std::make_shared<mg::NullDisplayReport>());
1507+ platform = std::make_shared<mgg::GBMPlatform>(std::make_shared<mg::NullDisplayReport>(),
1508+ std::make_shared<mtd::NullVirtualTerminal>());
1509 mock_buffer_initializer = std::make_shared<testing::NiceMock<mtd::MockBufferInitializer>>();
1510 allocator.reset(new mgg::GBMBufferAllocator(platform, mock_buffer_initializer));
1511 }
1512
1513=== modified file 'tests/unit-tests/graphics/gbm/test_gbm_display.cpp'
1514--- tests/unit-tests/graphics/gbm/test_gbm_display.cpp 2013-03-22 11:37:34 +0000
1515+++ tests/unit-tests/graphics/gbm/test_gbm_display.cpp 2013-04-10 12:56:24 +0000
1516@@ -20,11 +20,13 @@
1517 #include "src/server/graphics/gbm/gbm_display.h"
1518 #include "mir/logging/display_report.h"
1519 #include "mir/logging/logger.h"
1520+#include "mir/graphics/display_buffer.h"
1521
1522 #include "mir_test/egl_mock.h"
1523 #include "mir_test/gl_mock.h"
1524 #include "mir/graphics/null_display_report.h"
1525 #include "mir_test_doubles/mock_display_report.h"
1526+#include "mir_test_doubles/null_virtual_terminal.h"
1527
1528 #include "mock_drm.h"
1529 #include "mock_gbm.h"
1530@@ -78,6 +80,12 @@
1531 .Times(AtLeast(0));
1532 }
1533
1534+ std::shared_ptr<mgg::GBMPlatform> create_platform()
1535+ {
1536+ return std::make_shared<mgg::GBMPlatform>(
1537+ std::make_shared<mg::NullDisplayReport>(),
1538+ std::make_shared<mtd::NullVirtualTerminal>());
1539+ }
1540
1541 void setup_post_update_expectations()
1542 {
1543@@ -232,7 +240,7 @@
1544
1545 EXPECT_NO_THROW(
1546 {
1547- auto platform = std::make_shared<mgg::GBMPlatform>(std::make_shared<mg::NullDisplayReport>());
1548+ auto platform = create_platform();
1549 auto display = std::make_shared<mgg::GBMDisplay>(platform, mock_report);
1550 });
1551 }
1552@@ -273,7 +281,7 @@
1553
1554 EXPECT_NO_THROW(
1555 {
1556- auto platform = std::make_shared<mgg::GBMPlatform>(std::make_shared<mg::NullDisplayReport>());
1557+ auto platform = create_platform();
1558 auto display = std::make_shared<mgg::GBMDisplay>(platform, mock_report);
1559 });
1560 }
1561@@ -291,7 +299,7 @@
1562
1563 EXPECT_THROW(
1564 {
1565- auto platform = std::make_shared<mgg::GBMPlatform>(std::make_shared<mg::NullDisplayReport>());
1566+ auto platform = create_platform();
1567 auto display = std::make_shared<mgg::GBMDisplay>(platform, mock_report);
1568 }, std::runtime_error);
1569 }
1570@@ -310,7 +318,7 @@
1571 EXPECT_CALL(mock_drm, drmClose(_))
1572 .Times(Exactly(1));
1573
1574- auto platform = std::make_shared<mgg::GBMPlatform>(std::make_shared<mg::NullDisplayReport>());
1575+ auto platform = create_platform();
1576
1577 EXPECT_THROW({
1578 auto display = std::make_shared<mgg::GBMDisplay>(platform, mock_report);
1579@@ -332,8 +340,8 @@
1580 .Times(Exactly(1));
1581
1582 EXPECT_THROW({
1583- auto platform = std::make_shared<mgg::GBMPlatform>(std::make_shared<mg::NullDisplayReport>());
1584- }, std::runtime_error) << "Expected c'tor of GBMDisplay to throw an exception";
1585+ auto platform = create_platform();
1586+ }, std::runtime_error) << "Expected c'tor of GBMPlatform to throw an exception";
1587 }
1588
1589 namespace
1590@@ -394,7 +402,7 @@
1591
1592 EXPECT_NO_THROW(
1593 {
1594- auto platform = std::make_shared<mgg::GBMPlatform>(std::make_shared<mg::NullDisplayReport>());
1595+ auto platform = create_platform();
1596 auto display = std::make_shared<mgg::GBMDisplay>(platform, mock_report);
1597
1598 display->for_each_display_buffer([](mg::DisplayBuffer& db)
1599@@ -434,7 +442,7 @@
1600
1601 EXPECT_NO_THROW(
1602 {
1603- auto platform = std::make_shared<mgg::GBMPlatform>(std::make_shared<mg::NullDisplayReport>());
1604+ auto platform = create_platform();
1605 auto display = std::make_shared<mgg::GBMDisplay>(platform, mock_report);
1606
1607 display->for_each_display_buffer([](mg::DisplayBuffer& db)
1608@@ -469,7 +477,7 @@
1609
1610 EXPECT_NO_THROW(
1611 {
1612- auto platform = std::make_shared<mgg::GBMPlatform>(std::make_shared<mg::NullDisplayReport>());
1613+ auto platform = create_platform();
1614 auto display = std::make_shared<mgg::GBMDisplay>(platform, mock_report);
1615 });
1616 }
1617@@ -478,7 +486,7 @@
1618 {
1619 using namespace ::testing;
1620
1621- auto platform = std::make_shared<mgg::GBMPlatform>(std::make_shared<mg::NullDisplayReport>());
1622+ auto platform = create_platform();
1623 auto logger = std::make_shared<MockLogger>();
1624
1625 auto reporter = std::make_shared<ml::DisplayReport>(logger);
1626@@ -497,7 +505,7 @@
1627 {
1628 using namespace ::testing;
1629
1630- auto platform = std::make_shared<mgg::GBMPlatform>(std::make_shared<mg::NullDisplayReport>());
1631+ auto platform = create_platform();
1632 auto logger = std::make_shared<MockLogger>();
1633
1634 auto reporter = std::make_shared<ml::DisplayReport>(logger);
1635@@ -516,7 +524,7 @@
1636 {
1637 using namespace ::testing;
1638
1639- auto platform = std::make_shared<mgg::GBMPlatform>(std::make_shared<mg::NullDisplayReport>());
1640+ auto platform = create_platform();
1641 auto logger = std::make_shared<MockLogger>();
1642
1643 auto reporter = std::make_shared<ml::DisplayReport>(logger);
1644@@ -535,7 +543,7 @@
1645 {
1646 using namespace ::testing;
1647
1648- auto platform = std::make_shared<mgg::GBMPlatform>(std::make_shared<mg::NullDisplayReport>());
1649+ auto platform = create_platform();
1650 auto logger = std::make_shared<MockLogger>();
1651
1652 auto reporter = std::make_shared<ml::DisplayReport>(logger);
1653@@ -561,7 +569,7 @@
1654
1655 EXPECT_THROW(
1656 {
1657- auto platform = std::make_shared<mgg::GBMPlatform>(std::make_shared<mg::NullDisplayReport>());
1658+ auto platform = create_platform();
1659 auto display = std::make_shared<mgg::GBMDisplay>(platform, mock_report);
1660 }, std::runtime_error);
1661 }
1662@@ -577,7 +585,7 @@
1663
1664 EXPECT_THROW(
1665 {
1666- auto platform = std::make_shared<mgg::GBMPlatform>(std::make_shared<mg::NullDisplayReport>());
1667+ auto platform = create_platform();
1668 auto display = std::make_shared<mgg::GBMDisplay>(platform, mock_report);
1669 }, std::runtime_error);
1670 }
1671@@ -586,7 +594,7 @@
1672 {
1673 using namespace ::testing;
1674
1675- auto platform = std::make_shared<mgg::GBMPlatform>(std::make_shared<mg::NullDisplayReport>());
1676+ auto platform = create_platform();
1677 auto display = std::make_shared<mgg::GBMDisplay>(platform, mock_report);
1678
1679 int callback_count{0};
1680
1681=== modified file 'tests/unit-tests/graphics/gbm/test_gbm_display_configuration.cpp'
1682--- tests/unit-tests/graphics/gbm/test_gbm_display_configuration.cpp 2013-03-13 08:09:52 +0000
1683+++ tests/unit-tests/graphics/gbm/test_gbm_display_configuration.cpp 2013-04-10 12:56:24 +0000
1684@@ -25,6 +25,7 @@
1685 #include "mir_test/egl_mock.h"
1686 #include "mir_test/gl_mock.h"
1687 #include "mir/graphics/null_display_report.h"
1688+#include "mir_test_doubles/null_virtual_terminal.h"
1689
1690 #include "mock_drm.h"
1691 #include "mock_gbm.h"
1692@@ -37,6 +38,7 @@
1693 namespace mg = mir::graphics;
1694 namespace mgg = mir::graphics::gbm;
1695 namespace geom = mir::geometry;
1696+namespace mtd = mir::test::doubles;
1697
1698 namespace
1699 {
1700@@ -59,8 +61,7 @@
1701 class GBMDisplayConfigurationTest : public ::testing::Test
1702 {
1703 public:
1704- GBMDisplayConfigurationTest() :
1705- null_listener{std::make_shared<mg::NullDisplayReport>()}
1706+ GBMDisplayConfigurationTest()
1707 {
1708 using namespace testing;
1709
1710@@ -81,6 +82,13 @@
1711 setup_sample_modes();
1712 }
1713
1714+ std::shared_ptr<mgg::GBMPlatform> create_platform()
1715+ {
1716+ return std::make_shared<mgg::GBMPlatform>(
1717+ std::make_shared<mg::NullDisplayReport>(),
1718+ std::make_shared<mtd::NullVirtualTerminal>());
1719+ }
1720+
1721 void setup_sample_modes()
1722 {
1723 /* Add DRM modes */
1724@@ -98,7 +106,6 @@
1725 ::testing::NiceMock<mir::GLMock> mock_gl;
1726 ::testing::NiceMock<mgg::MockDRM> mock_drm;
1727 ::testing::NiceMock<mgg::MockGBM> mock_gbm;
1728- std::shared_ptr<mg::DisplayReport> const null_listener;
1729
1730 std::vector<drmModeModeInfo> modes0;
1731 std::vector<mg::DisplayConfigurationMode> conf_modes0;
1732@@ -176,7 +183,7 @@
1733 };
1734
1735 /* Test body */
1736- auto platform = std::make_shared<mgg::GBMPlatform>(null_listener);
1737+ auto platform = create_platform();
1738 auto display = platform->create_display();
1739
1740 auto conf = display->configuration();
1741@@ -214,7 +221,7 @@
1742 resources.prepare();
1743
1744 /* Test body */
1745- auto platform = std::make_shared<mgg::GBMPlatform>(null_listener);
1746+ auto platform = create_platform();
1747 auto display = platform->create_display();
1748
1749 auto conf = display->configuration();
1750@@ -253,7 +260,7 @@
1751 resources.prepare();
1752
1753 /* Test body */
1754- auto platform = std::make_shared<mgg::GBMPlatform>(null_listener);
1755+ auto platform = create_platform();
1756 auto display = platform->create_display();
1757
1758 auto conf = display->configuration();
1759
1760=== modified file 'tests/unit-tests/graphics/gbm/test_gbm_display_multi_monitor.cpp'
1761--- tests/unit-tests/graphics/gbm/test_gbm_display_multi_monitor.cpp 2013-03-13 08:09:52 +0000
1762+++ tests/unit-tests/graphics/gbm/test_gbm_display_multi_monitor.cpp 2013-04-10 12:56:24 +0000
1763@@ -23,6 +23,7 @@
1764 #include "mir_test/egl_mock.h"
1765 #include "mir_test/gl_mock.h"
1766 #include "mir/graphics/null_display_report.h"
1767+#include "mir_test_doubles/null_virtual_terminal.h"
1768
1769 #include "mock_drm.h"
1770 #include "mock_gbm.h"
1771@@ -33,6 +34,7 @@
1772 namespace mg = mir::graphics;
1773 namespace mgg = mir::graphics::gbm;
1774 namespace geom = mir::geometry;
1775+namespace mtd = mir::test::doubles;
1776
1777 namespace
1778 {
1779@@ -41,7 +43,6 @@
1780 {
1781 public:
1782 GBMDisplayMultiMonitorTest()
1783- : null_listener{std::make_shared<mg::NullDisplayReport>()}
1784 {
1785 using namespace testing;
1786
1787@@ -69,6 +70,13 @@
1788 .Times(AtLeast(0));
1789 }
1790
1791+ std::shared_ptr<mgg::GBMPlatform> create_platform()
1792+ {
1793+ return std::make_shared<mgg::GBMPlatform>(
1794+ std::make_shared<mg::NullDisplayReport>(),
1795+ std::make_shared<mtd::NullVirtualTerminal>());
1796+ }
1797+
1798 void setup_outputs(int n)
1799 {
1800 mgg::FakeDRMResources& resources(mock_drm.fake_drm);
1801@@ -117,7 +125,6 @@
1802 testing::NiceMock<mir::GLMock> mock_gl;
1803 testing::NiceMock<mgg::MockDRM> mock_drm;
1804 testing::NiceMock<mgg::MockGBM> mock_gbm;
1805- std::shared_ptr<mg::DisplayReport> const null_listener;
1806
1807 std::vector<drmModeModeInfo> modes0;
1808 std::vector<drmModeModeInfo> modes_empty;
1809@@ -168,7 +175,7 @@
1810 .After(crtc_setups);
1811 }
1812
1813- auto platform = std::make_shared<mgg::GBMPlatform>(null_listener);
1814+ auto platform = create_platform();
1815 auto display = platform->create_display();
1816 }
1817
1818@@ -201,7 +208,7 @@
1819 .Times(1);
1820 }
1821
1822- auto platform = std::make_shared<mgg::GBMPlatform>(null_listener);
1823+ auto platform = create_platform();
1824 auto display = platform->create_display();
1825 }
1826
1827@@ -254,7 +261,7 @@
1828 .WillOnce(DoAll(InvokePageFlipHandler(&user_data[1]), Return(0)))
1829 .WillOnce(DoAll(InvokePageFlipHandler(&user_data[2]), Return(0)));
1830
1831- auto platform = std::make_shared<mgg::GBMPlatform>(null_listener);
1832+ auto platform = create_platform();
1833 auto display = platform->create_display();
1834
1835 display->for_each_display_buffer([](mg::DisplayBuffer& buffer)
1836
1837=== modified file 'tests/unit-tests/graphics/gbm/test_gbm_platform.cpp'
1838--- tests/unit-tests/graphics/gbm/test_gbm_platform.cpp 2013-03-13 04:54:15 +0000
1839+++ tests/unit-tests/graphics/gbm/test_gbm_platform.cpp 2013-04-10 12:56:24 +0000
1840@@ -16,9 +16,11 @@
1841 * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
1842 */
1843
1844-#include "mir/graphics/platform.h"
1845 #include "mir/graphics/platform_ipc_package.h"
1846 #include "mir/graphics/drm_authenticator.h"
1847+#include "src/server/graphics/gbm/gbm_platform.h"
1848+#include "mir_test_doubles/null_virtual_terminal.h"
1849+#include "mir/main_loop.h"
1850
1851 #include "mir/graphics/null_display_report.h"
1852
1853@@ -28,13 +30,30 @@
1854 #include "mock_gbm.h"
1855
1856 #include <gtest/gtest.h>
1857+#include <gmock/gmock.h>
1858
1859 #include <stdexcept>
1860
1861 namespace mg = mir::graphics;
1862+namespace mgg = mir::graphics::gbm;
1863+namespace mtd = mir::test::doubles;
1864
1865 namespace
1866 {
1867+
1868+class MockVirtualTerminal : public mgg::VirtualTerminal
1869+{
1870+public:
1871+ ~MockVirtualTerminal() noexcept(true) {}
1872+
1873+ MOCK_METHOD0(set_graphics_mode, void());
1874+ MOCK_METHOD3(register_switch_handlers,
1875+ void(mir::MainLoop&,
1876+ std::function<void()> const&,
1877+ std::function<void()> const&));
1878+};
1879+
1880+
1881 class GBMGraphicsPlatform : public ::testing::Test
1882 {
1883 public:
1884@@ -43,6 +62,14 @@
1885 ::testing::Mock::VerifyAndClearExpectations(&mock_drm);
1886 ::testing::Mock::VerifyAndClearExpectations(&mock_gbm);
1887 }
1888+
1889+ std::shared_ptr<mg::Platform> create_platform()
1890+ {
1891+ return std::make_shared<mgg::GBMPlatform>(
1892+ std::make_shared<mg::NullDisplayReport>(),
1893+ std::make_shared<mtd::NullVirtualTerminal>());
1894+ }
1895+
1896 ::testing::NiceMock<mg::gbm::MockDRM> mock_drm;
1897 ::testing::NiceMock<mg::gbm::MockGBM> mock_gbm;
1898 };
1899@@ -69,7 +96,7 @@
1900 EXPECT_CALL(mock_drm, drmClose(auth_fd));
1901
1902 EXPECT_NO_THROW (
1903- auto platform = mg::create_platform(std::make_shared<mg::NullDisplayReport>());
1904+ auto platform = create_platform();
1905 auto pkg = platform->get_ipc_package();
1906
1907 ASSERT_TRUE(pkg.get());
1908@@ -87,7 +114,7 @@
1909
1910 try
1911 {
1912- auto platform = mg::create_platform(std::make_shared<mg::NullDisplayReport>());
1913+ auto platform = create_platform();
1914 } catch(...)
1915 {
1916 return;
1917@@ -105,7 +132,7 @@
1918 EXPECT_CALL(mock_drm, drmAuthMagic(mock_drm.fake_drm.fd(),magic))
1919 .WillOnce(Return(0));
1920
1921- auto platform = mg::create_platform(std::make_shared<mg::NullDisplayReport>());
1922+ auto platform = create_platform();
1923 auto authenticator = std::dynamic_pointer_cast<mg::DRMAuthenticator>(platform);
1924 authenticator->drm_auth_magic(magic);
1925 }
1926@@ -119,10 +146,68 @@
1927 EXPECT_CALL(mock_drm, drmAuthMagic(mock_drm.fake_drm.fd(),magic))
1928 .WillOnce(Return(-1));
1929
1930- auto platform = mg::create_platform(std::make_shared<mg::NullDisplayReport>());
1931+ auto platform = create_platform();
1932 auto authenticator = std::dynamic_pointer_cast<mg::DRMAuthenticator>(platform);
1933
1934 EXPECT_THROW({
1935 authenticator->drm_auth_magic(magic);
1936 }, std::runtime_error);
1937 }
1938+
1939+TEST_F(GBMGraphicsPlatform, sets_vt_graphics_mode)
1940+{
1941+ using namespace testing;
1942+
1943+ auto mock_vt = std::make_shared<MockVirtualTerminal>();
1944+
1945+ EXPECT_CALL(*mock_vt, set_graphics_mode())
1946+ .Times(1);
1947+
1948+ mgg::GBMPlatform platform{std::make_shared<mg::NullDisplayReport>(),
1949+ mock_vt};
1950+}
1951+
1952+TEST_F(GBMGraphicsPlatform, pause_drops_drm_master)
1953+{
1954+ using namespace testing;
1955+
1956+ EXPECT_CALL(mock_drm, drmDropMaster(mock_drm.fake_drm.fd()))
1957+ .Times(1);
1958+
1959+ auto platform = create_platform();
1960+ platform->pause();
1961+}
1962+
1963+TEST_F(GBMGraphicsPlatform, resume_sets_drm_master)
1964+{
1965+ using namespace testing;
1966+
1967+ InSequence s;
1968+
1969+ EXPECT_CALL(mock_drm, drmSetMaster(mock_drm.fake_drm.fd()))
1970+ .Times(1);
1971+
1972+ auto platform = create_platform();
1973+ platform->resume();
1974+}
1975+
1976+TEST_F(GBMGraphicsPlatform, set_or_drop_drm_master_failure_throws)
1977+{
1978+ using namespace testing;
1979+
1980+ EXPECT_CALL(mock_drm, drmDropMaster(_))
1981+ .WillOnce(Return(-1));
1982+
1983+ EXPECT_CALL(mock_drm, drmSetMaster(_))
1984+ .WillOnce(Return(-1));
1985+
1986+ auto platform = create_platform();
1987+
1988+ EXPECT_THROW({
1989+ platform->pause();
1990+ }, std::runtime_error);
1991+
1992+ EXPECT_THROW({
1993+ platform->resume();
1994+ }, std::runtime_error);
1995+}
1996
1997=== modified file 'tests/unit-tests/graphics/test_graphics_platform.cpp'
1998--- tests/unit-tests/graphics/test_graphics_platform.cpp 2013-03-22 17:08:01 +0000
1999+++ tests/unit-tests/graphics/test_graphics_platform.cpp 2013-04-10 12:56:24 +0000
2000@@ -25,6 +25,8 @@
2001 #ifndef ANDROID
2002 #include "gbm/mock_drm.h"
2003 #include "gbm/mock_gbm.h"
2004+#include "mir_test_doubles/null_virtual_terminal.h"
2005+#include "src/server/graphics/gbm/gbm_platform.h"
2006 #else
2007 #include "mir_test/hw_mock.h"
2008 #endif
2009@@ -69,6 +71,17 @@
2010 #endif
2011 }
2012
2013+ std::shared_ptr<mg::Platform> create_platform()
2014+ {
2015+#ifdef ANDROID
2016+ return mg::create_platform(std::make_shared<mg::NullDisplayReport>());
2017+#else
2018+ return std::make_shared<mg::gbm::GBMPlatform>(
2019+ std::make_shared<mg::NullDisplayReport>(),
2020+ std::make_shared<mir::test::doubles::NullVirtualTerminal>());
2021+#endif
2022+ }
2023+
2024 std::shared_ptr<ml::Logger> logger;
2025 std::shared_ptr<mg::BufferInitializer> buffer_initializer;
2026
2027@@ -87,7 +100,7 @@
2028 using namespace testing;
2029
2030 EXPECT_NO_THROW (
2031- auto platform = mg::create_platform(std::make_shared<mg::NullDisplayReport>());
2032+ auto platform = create_platform();
2033 auto allocator = platform->create_buffer_allocator(buffer_initializer);
2034
2035 EXPECT_TRUE(allocator.get());
2036@@ -97,7 +110,7 @@
2037
2038 TEST_F(GraphicsPlatform, buffer_creation)
2039 {
2040- auto platform = mg::create_platform(std::make_shared<mg::NullDisplayReport>());
2041+ auto platform = create_platform();
2042 auto allocator = platform->create_buffer_allocator(buffer_initializer);
2043 auto supported_pixel_formats = allocator->supported_pixel_formats();
2044
2045@@ -119,7 +132,7 @@
2046
2047 TEST_F(GraphicsPlatform, get_ipc_package)
2048 {
2049- auto platform = mg::create_platform(std::make_shared<mg::NullDisplayReport>());
2050+ auto platform = create_platform();
2051 auto pkg = platform->get_ipc_package();
2052
2053 ASSERT_TRUE(pkg.get() != NULL);

Subscribers

People subscribed via source and target branches