Mir

Merge lp:mir/0.17 into lp:mir/ubuntu

Proposed by Alberto Aguirre on 2015-11-04
Status: Merged
Approved by: Alberto Aguirre on 2015-11-06
Approved revision: 3022
Merged at revision: 1249
Proposed branch: lp:mir/0.17
Merge into: lp:mir/ubuntu
Diff against target: 865 lines (+427/-65)
23 files modified
CMakeLists.txt (+1/-1)
debian/changelog (+20/-0)
debian/control (+1/-0)
debian/mir-client-platform-mesa-dev.install (+1/-0)
include/platform/mir/graphics/display_configuration.h (+3/-0)
src/platform/graphics/display_configuration.cpp (+23/-0)
src/platforms/android/client/android_client_platform.cpp (+3/-14)
src/platforms/common/client/mir/CMakeLists.txt (+1/-0)
src/platforms/common/client/mir/weak_egl.cpp (+65/-0)
src/platforms/common/client/mir/weak_egl.h (+47/-0)
src/platforms/mesa/CMakeLists.txt (+10/-1)
src/platforms/mesa/client/client_platform.cpp (+6/-17)
src/platforms/mesa/mir-client-platform-mesa-dev.pc.in (+1/-1)
src/platforms/mesa/mir-client-platform-mesa.pc.in (+7/-0)
src/server/graphics/nested/display.cpp (+39/-6)
src/server/graphics/nested/display.h (+6/-0)
src/server/input/display_input_region.cpp (+4/-1)
src/server/scene/rendering_tracker.cpp (+12/-0)
src/server/scene/rendering_tracker.h (+2/-1)
src/server/scene/surface_stack.cpp (+11/-8)
tests/acceptance-tests/test_nested_mir.cpp (+109/-15)
tests/unit-tests/input/test_display_input_region.cpp (+11/-0)
tests/unit-tests/scene/test_surface_stack.cpp (+44/-0)
To merge this branch: bzr merge lp:mir/0.17
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing on 2015-11-05
Mir development team 2015-11-04 Pending
Review via email: mp+276704@code.launchpad.net

Commit message

Mir 0.17.1 release

Description of the change

Mir 0.17.1 release

To post a comment you must log in.
lp:mir/0.17 updated on 2015-11-04
3017. By Alberto Aguirre on 2015-11-04

Avoid __attribute__((weak)) as that will fail to resolve symbols from
lazily loaded libraries (like Qt platform plugins apparently).

Cherry picked from lp:mir r3060

3018. By Alberto Aguirre on 2015-11-04

Update changelog

3019. By Brandon Schaefer on 2015-11-04

Add missing shlibs:Depends entry to libmircookie1 package dependency list

3020. By Alberto Aguirre on 2015-11-04

Update changelog, new bugfix entry

lp:mir/0.17 updated on 2015-11-05
3021. By Alexandros Frantzis on 2015-11-05

input: Return an empty input region bounding rectangle when there are no outputs.

Cherry picked from lp:mir r3085

3022. By Alberto Aguirre on 2015-11-05

Update changelog

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2015-10-08 09:48:35 +0000
3+++ CMakeLists.txt 2015-11-05 16:01:02 +0000
4@@ -28,7 +28,7 @@
5
6 set(MIR_VERSION_MAJOR 0)
7 set(MIR_VERSION_MINOR 17)
8-set(MIR_VERSION_PATCH 0)
9+set(MIR_VERSION_PATCH 1)
10
11 add_definitions(-DMIR_VERSION_MAJOR=${MIR_VERSION_MAJOR})
12 add_definitions(-DMIR_VERSION_MINOR=${MIR_VERSION_MINOR})
13
14=== modified file 'debian/changelog'
15--- debian/changelog 2015-10-08 16:12:19 +0000
16+++ debian/changelog 2015-11-05 16:01:02 +0000
17@@ -1,3 +1,23 @@
18+mir (0.17.1) UNRELEASED; urgency=medium
19+
20+ * New upstream release 0.17.1 (https://launchpad.net/mir/+milestone/0.17.1)
21+ - No ABI changes. Bug fix release only.
22+ - Bugs fixed:
23+ . compositing never stops when external monitor is connected
24+ (LP: #1499039)
25+ . half screen on external monitor (LP: #1511538)
26+ . Nested servers don't apply their display configuration at startup
27+ (LP: #1492269)
28+ . libmircookie1 package does not list libnettle as dependency
29+ (LP: #1513225)
30+ . unity-system-compositor crash, no interaction on windowed mode
31+ (LP: #1511095)
32+ . mir_connection_get_egl_pixel_format() crashes (LP: #1510218)
33+ . [regression] mir-client-platform-mesa-dev pkg-config file dropped
34+ (LP: #1509005)
35+
36+ -- Alberto Aguirre <alberto.aguirre@canonical.com> Wed, 04 Nov 2015 15:08:54 -0600
37+
38 mir (0.17.0+15.10.20151008.2-0ubuntu1) wily; urgency=medium
39
40 [ Alexandros Frantzis ]
41
42=== modified file 'debian/control'
43--- debian/control 2015-10-05 02:18:18 +0000
44+++ debian/control 2015-11-05 16:01:02 +0000
45@@ -424,6 +424,7 @@
46 Multi-Arch: same
47 Pre-Depends: ${misc:Pre-Depends}
48 Depends: ${misc:Depends},
49+ ${shlibs:Depends}
50 Description: Produce and verify spoof-resistant timestamps - runtime library
51 libmircookie provides a simple mechanism for a group of cooperating processes
52 to hand out and verify difficult-to-forge timestamps to untrusted 3rd parties.
53
54=== modified file 'debian/mir-client-platform-mesa-dev.install'
55--- debian/mir-client-platform-mesa-dev.install 2015-09-24 22:30:09 +0000
56+++ debian/mir-client-platform-mesa-dev.install 2015-11-05 16:01:02 +0000
57@@ -1,2 +1,3 @@
58 usr/include/mirplatform/mir_toolkit/mesa
59+usr/lib/*/pkgconfig/mir-client-platform-mesa-dev.pc
60 usr/lib/*/pkgconfig/mir-client-platform-mesa.pc
61
62=== modified file 'include/platform/mir/graphics/display_configuration.h'
63--- include/platform/mir/graphics/display_configuration.h 2015-10-05 05:22:49 +0000
64+++ include/platform/mir/graphics/display_configuration.h 2015-11-05 16:01:02 +0000
65@@ -181,6 +181,9 @@
66 DisplayConfiguration& operator=(DisplayConfiguration const& c) = delete;
67 };
68
69+bool operator==(DisplayConfiguration const& lhs, DisplayConfiguration const& rhs);
70+bool operator!=(DisplayConfiguration const& lhs, DisplayConfiguration const& rhs);
71+
72 std::ostream& operator<<(std::ostream& out, DisplayConfiguration const& val);
73
74 }
75
76=== modified file 'src/platform/graphics/display_configuration.cpp'
77--- src/platform/graphics/display_configuration.cpp 2015-10-02 05:14:37 +0000
78+++ src/platform/graphics/display_configuration.cpp 2015-11-05 16:01:02 +0000
79@@ -145,6 +145,7 @@
80
81 out << "\tscale: " << val.scale << std::endl;
82 out << "\tform factor: " << as_string(val.form_factor) << std::endl;
83+ out << "\torientation: " << val.orientation << '\n';
84 out << "}" << std::endl;
85
86 return out;
87@@ -219,6 +220,28 @@
88 return !(val1 == val2);
89 }
90
91+bool mg::operator==(DisplayConfiguration const& lhs, DisplayConfiguration const& rhs)
92+{
93+ std::vector<DisplayConfigurationCard> lhs_cards;
94+ std::vector<DisplayConfigurationOutput> lhs_outputs;
95+
96+ lhs.for_each_card([&lhs_cards](DisplayConfigurationCard const& card) { lhs_cards.emplace_back(card); });
97+ lhs.for_each_output([&lhs_outputs](DisplayConfigurationOutput const& output) { lhs_outputs.emplace_back(output); });
98+
99+ std::vector<DisplayConfigurationCard> rhs_cards;
100+ std::vector<DisplayConfigurationOutput> rhs_outputs;
101+
102+ rhs.for_each_card([&rhs_cards](DisplayConfigurationCard const& card) { rhs_cards.emplace_back(card); });
103+ rhs.for_each_output([&rhs_outputs](DisplayConfigurationOutput const& output) { rhs_outputs.emplace_back(output); });
104+
105+ return lhs_cards == rhs_cards && lhs_outputs == rhs_outputs;
106+}
107+
108+bool mg::operator!=(DisplayConfiguration const& lhs, DisplayConfiguration const& rhs)
109+{
110+ return !(lhs == rhs);
111+}
112+
113 namespace
114 {
115 mir::geometry::Rectangle extents_of(
116
117=== modified file 'src/platforms/android/client/android_client_platform.cpp'
118--- src/platforms/android/client/android_client_platform.cpp 2015-07-21 04:30:03 +0000
119+++ src/platforms/android/client/android_client_platform.cpp 2015-11-05 16:01:02 +0000
120@@ -24,6 +24,7 @@
121 #include "android_client_buffer_factory.h"
122 #include "egl_native_surface_interpreter.h"
123
124+#include "mir/weak_egl.h"
125 #include <EGL/egl.h>
126
127 #include <boost/throw_exception.hpp>
128@@ -124,19 +125,6 @@
129 return buf->anwb();
130 }
131
132-/*
133- * Driver modules get dlopened with RTLD_NOW, meaning that if the below egl
134- * functions aren't found in memory the driver fails to load. This would
135- * normally prevent software clients (those not linked to libEGL) from
136- * successfully loading our client module, but if we mark the undefined
137- * egl function symbols as "weak" then their absence is no longer an error,
138- * even with RTLD_NOW.
139- */
140-extern "C" EGLAPI EGLBoolean EGLAPIENTRY
141- eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
142- EGLint attribute, EGLint *value)
143- __attribute__((weak));
144-
145 MirPixelFormat mcla::AndroidClientPlatform::get_egl_pixel_format(
146 EGLDisplay disp, EGLConfig conf) const
147 {
148@@ -144,7 +132,8 @@
149
150 // EGL_KHR_platform_android says this will always work...
151 EGLint vis = 0;
152- if (eglGetConfigAttrib(disp, conf, EGL_NATIVE_VISUAL_ID, &vis))
153+ mcl::WeakEGL weak;
154+ if (weak.eglGetConfigAttrib(disp, conf, EGL_NATIVE_VISUAL_ID, &vis))
155 mir_format = mir::graphics::android::to_mir_format(vis);
156
157 return mir_format;
158
159=== modified file 'src/platforms/common/client/mir/CMakeLists.txt'
160--- src/platforms/common/client/mir/CMakeLists.txt 2015-01-19 14:16:46 +0000
161+++ src/platforms/common/client/mir/CMakeLists.txt 2015-11-05 16:01:02 +0000
162@@ -2,4 +2,5 @@
163
164 add_library(client_platform_common OBJECT
165 aging_buffer.cpp
166+ weak_egl.cpp
167 )
168
169=== added file 'src/platforms/common/client/mir/weak_egl.cpp'
170--- src/platforms/common/client/mir/weak_egl.cpp 1970-01-01 00:00:00 +0000
171+++ src/platforms/common/client/mir/weak_egl.cpp 2015-11-05 16:01:02 +0000
172@@ -0,0 +1,65 @@
173+/*
174+ * EGL without any linkage requirements!
175+ * ~~~
176+ * Copyright © 2015 Canonical Ltd.
177+ *
178+ * This program is free software: you can redistribute it and/or modify it
179+ * under the terms of the GNU Lesser General Public License version 3,
180+ * as published by the Free Software Foundation.
181+ *
182+ * This program is distributed in the hope that it will be useful,
183+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
184+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
185+ * GNU Lesser General Public License for more details.
186+ *
187+ * You should have received a copy of the GNU Lesser General Public License
188+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
189+ *
190+ * Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com>
191+ */
192+
193+#include "weak_egl.h"
194+#include <dlfcn.h>
195+
196+namespace mir { namespace client {
197+
198+WeakEGL::WeakEGL()
199+ : egl1(nullptr)
200+ , pGetConfigAttrib(nullptr)
201+{
202+}
203+
204+WeakEGL::~WeakEGL()
205+{
206+ if (egl1)
207+ dlclose(egl1);
208+}
209+
210+EGLBoolean WeakEGL::eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
211+ EGLint attribute, EGLint* value)
212+{
213+ if (find("eglGetConfigAttrib", (void**)&pGetConfigAttrib))
214+ return pGetConfigAttrib(dpy, config, attribute, value);
215+ else
216+ return EGL_FALSE;
217+}
218+
219+bool WeakEGL::find(char const* name, void** func)
220+{
221+ if (!*func)
222+ {
223+ // RTLD_DEFAULT is first choice to support wrappers like MockEGL
224+ if (!(*func = dlsym(RTLD_DEFAULT, name)))
225+ {
226+ // This will work more in real-world situations if the library
227+ // is hidden behind an RTLD_LOCAL (e.g. a Qt plugin)
228+ if (!egl1)
229+ egl1 = dlopen("libEGL.so.1", RTLD_NOLOAD|RTLD_LAZY);
230+ if (egl1)
231+ *func = dlsym(egl1, name);
232+ }
233+ }
234+ return *func != nullptr;
235+}
236+
237+}} // namespace mir::client
238
239=== added file 'src/platforms/common/client/mir/weak_egl.h'
240--- src/platforms/common/client/mir/weak_egl.h 1970-01-01 00:00:00 +0000
241+++ src/platforms/common/client/mir/weak_egl.h 2015-11-05 16:01:02 +0000
242@@ -0,0 +1,47 @@
243+/*
244+ * EGL without any linkage requirements!
245+ * ~~~
246+ * Copyright © 2015 Canonical Ltd.
247+ *
248+ * This program is free software: you can redistribute it and/or modify it
249+ * under the terms of the GNU Lesser General Public License version 3,
250+ * as published by the Free Software Foundation.
251+ *
252+ * This program is distributed in the hope that it will be useful,
253+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
254+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
255+ * GNU Lesser General Public License for more details.
256+ *
257+ * You should have received a copy of the GNU Lesser General Public License
258+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
259+ *
260+ * Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com>
261+ */
262+
263+#ifndef MIR_CLIENT_WEAK_EGL_H_
264+#define MIR_CLIENT_WEAK_EGL_H_
265+
266+#include <EGL/egl.h>
267+#include <dlfcn.h>
268+
269+namespace mir { namespace client {
270+
271+class WeakEGL
272+{
273+public:
274+ WeakEGL();
275+ ~WeakEGL();
276+ EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
277+ EGLint attribute, EGLint* value);
278+
279+private:
280+ bool find(char const* name, void** func);
281+
282+ void* egl1;
283+ EGLBoolean (*pGetConfigAttrib)(EGLDisplay dpy, EGLConfig config,
284+ EGLint attribute, EGLint* value);
285+};
286+
287+}} // namespace mir::client
288+
289+#endif // MIR_CLIENT_WEAK_EGL_H_
290
291=== modified file 'src/platforms/mesa/CMakeLists.txt'
292--- src/platforms/mesa/CMakeLists.txt 2015-09-24 22:30:09 +0000
293+++ src/platforms/mesa/CMakeLists.txt 2015-11-05 16:01:02 +0000
294@@ -1,6 +1,12 @@
295 set(INCLUDEDIR "${CMAKE_INSTALL_PREFIX}/include")
296
297 configure_file(
298+ ${CMAKE_CURRENT_SOURCE_DIR}/mir-client-platform-mesa-dev.pc.in
299+ ${CMAKE_CURRENT_BINARY_DIR}/mir-client-platform-mesa-dev.pc
300+ @ONLY
301+)
302+
303+configure_file(
304 ${CMAKE_CURRENT_SOURCE_DIR}/mir-client-platform-mesa.pc.in
305 ${CMAKE_CURRENT_BINARY_DIR}/mir-client-platform-mesa.pc
306 @ONLY
307@@ -20,6 +26,9 @@
308 )
309
310 install(
311- FILES ${CMAKE_CURRENT_BINARY_DIR}/mir-client-platform-mesa.pc
312+ FILES
313+ ${CMAKE_CURRENT_BINARY_DIR}/mir-client-platform-mesa-dev.pc
314+ ${CMAKE_CURRENT_BINARY_DIR}/mir-client-platform-mesa.pc
315+
316 DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
317 )
318
319=== modified file 'src/platforms/mesa/client/client_platform.cpp'
320--- src/platforms/mesa/client/client_platform.cpp 2015-07-17 08:08:44 +0000
321+++ src/platforms/mesa/client/client_platform.cpp 2015-11-05 16:01:02 +0000
322@@ -23,6 +23,7 @@
323 #include "native_surface.h"
324 #include "mir/client_buffer_factory.h"
325 #include "mir/client_context.h"
326+#include "mir/weak_egl.h"
327 #include "mir_toolkit/mesa/platform_operation.h"
328
329 #include <cstring>
330@@ -179,19 +180,6 @@
331 }
332
333
334-/*
335- * Driver modules get dlopened with RTLD_NOW, meaning that if the below egl
336- * functions aren't found in memory the driver fails to load. This would
337- * normally prevent software clients (those not linked to libEGL) from
338- * successfully loading our client module, but if we mark the undefined
339- * egl function symbols as "weak" then their absence is no longer an error,
340- * even with RTLD_NOW.
341- */
342-extern "C" EGLAPI EGLBoolean EGLAPIENTRY
343- eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
344- EGLint attribute, EGLint *value)
345- __attribute__((weak));
346-
347 MirPixelFormat mclm::ClientPlatform::get_egl_pixel_format(
348 EGLDisplay disp, EGLConfig conf) const
349 {
350@@ -208,10 +196,11 @@
351 * EGL_NATIVE_VISUAL_ID, so ignore that for now.
352 */
353 EGLint r = 0, g = 0, b = 0, a = 0;
354- eglGetConfigAttrib(disp, conf, EGL_RED_SIZE, &r);
355- eglGetConfigAttrib(disp, conf, EGL_GREEN_SIZE, &g);
356- eglGetConfigAttrib(disp, conf, EGL_BLUE_SIZE, &b);
357- eglGetConfigAttrib(disp, conf, EGL_ALPHA_SIZE, &a);
358+ mcl::WeakEGL weak;
359+ weak.eglGetConfigAttrib(disp, conf, EGL_RED_SIZE, &r);
360+ weak.eglGetConfigAttrib(disp, conf, EGL_GREEN_SIZE, &g);
361+ weak.eglGetConfigAttrib(disp, conf, EGL_BLUE_SIZE, &b);
362+ weak.eglGetConfigAttrib(disp, conf, EGL_ALPHA_SIZE, &a);
363
364 if (r == 8 && g == 8 && b == 8)
365 {
366
367=== renamed file 'src/platforms/mesa/mir-client-platform-mesa.pc.in' => 'src/platforms/mesa/mir-client-platform-mesa-dev.pc.in'
368--- src/platforms/mesa/mir-client-platform-mesa.pc.in 2015-10-07 12:53:33 +0000
369+++ src/platforms/mesa/mir-client-platform-mesa-dev.pc.in 2015-11-05 16:01:02 +0000
370@@ -1,6 +1,6 @@
371 includedir=@INCLUDEDIR@/mirplatform
372
373-Name: mir-client-platform-mesa
374+Name: mir-client-platform-mesa-dev
375 Description: Mir Mesa client platform development files
376 Version: @MIR_VERSION@
377 Requires.private: mirclient
378
379=== added file 'src/platforms/mesa/mir-client-platform-mesa.pc.in'
380--- src/platforms/mesa/mir-client-platform-mesa.pc.in 1970-01-01 00:00:00 +0000
381+++ src/platforms/mesa/mir-client-platform-mesa.pc.in 2015-11-05 16:01:02 +0000
382@@ -0,0 +1,7 @@
383+includedir=@INCLUDEDIR@/mirplatform
384+
385+Name: mir-client-platform-mesa
386+Description: Mir Mesa client platform development files
387+Version: @MIR_VERSION@
388+Requires.private: mirclient
389+Cflags: -I${includedir}
390
391=== modified file 'src/server/graphics/nested/display.cpp'
392--- src/server/graphics/nested/display.cpp 2015-10-06 09:28:48 +0000
393+++ src/server/graphics/nested/display.cpp 2015-11-05 16:01:02 +0000
394@@ -29,6 +29,9 @@
395 #include "mir/graphics/overlapping_output_grouping.h"
396 #include "mir/graphics/gl_config.h"
397 #include "mir/graphics/egl_error.h"
398+#include "mir_toolkit/mir_blob.h"
399+#include "mir_toolkit/mir_connection.h"
400+#include "mir/raii.h"
401
402 #include <boost/throw_exception.hpp>
403 #include <stdexcept>
404@@ -145,6 +148,20 @@
405 return std::chrono::milliseconds::zero();
406 }
407
408+namespace
409+{
410+auto copy_config(MirDisplayConfiguration* conf) -> std::shared_ptr<MirDisplayConfiguration>
411+{
412+ auto const blob = mir::raii::deleter_for(
413+ mir_blob_from_display_configuration(conf),
414+ [] (MirBlob* b) { mir_blob_release(b); });
415+
416+ return std::shared_ptr<MirDisplayConfiguration>{
417+ mir_blob_to_display_configuration(blob.get()),
418+ [] (MirDisplayConfiguration* c) { if (c) mir_display_config_destroy(c); }};
419+}
420+}
421+
422 mgn::Display::Display(
423 std::shared_ptr<mg::Platform> const& platform,
424 std::shared_ptr<HostConnection> const& connection,
425@@ -159,10 +176,15 @@
426 display_report{display_report},
427 egl_display{connection->egl_native_display(), gl_config},
428 cursor_listener{cursor_listener},
429- outputs{}
430+ outputs{},
431+ current_configuration(std::make_unique<NestedDisplayConfiguration>(connection->create_display_config()))
432 {
433 std::shared_ptr<DisplayConfiguration> conf(configuration());
434 initial_conf_policy->apply_to(*conf);
435+
436+ if (*current_configuration != *conf)
437+ apply_to_connection(*conf);
438+
439 create_surfaces(*conf);
440 }
441
442@@ -181,8 +203,8 @@
443
444 std::unique_ptr<mg::DisplayConfiguration> mgn::Display::configuration() const
445 {
446- return std::make_unique<NestedDisplayConfiguration>(
447- connection->create_display_config());
448+ std::lock_guard<std::mutex> lock(configuration_mutex);
449+ return std::make_unique<NestedDisplayConfiguration>(copy_config(*current_configuration));
450 }
451
452 void mgn::Display::complete_display_initialization(MirPixelFormat format)
453@@ -195,8 +217,12 @@
454
455 void mgn::Display::configure(mg::DisplayConfiguration const& configuration)
456 {
457- create_surfaces(configuration);
458- apply_to_connection(configuration);
459+ std::lock_guard<std::mutex> lock(configuration_mutex);
460+ if (*current_configuration != configuration)
461+ {
462+ apply_to_connection(configuration);
463+ create_surfaces(configuration);
464+ }
465 }
466
467 void mgn::Display::create_surfaces(mg::DisplayConfiguration const& configuration)
468@@ -254,13 +280,20 @@
469 auto const& conf = dynamic_cast<NestedDisplayConfiguration const&>(configuration);
470
471 connection->apply_display_config(*conf);
472+
473+ current_configuration = std::make_unique<NestedDisplayConfiguration>(copy_config(conf));
474 }
475
476 void mgn::Display::register_configuration_change_handler(
477 EventHandlerRegister& /*handlers*/,
478 DisplayConfigurationChangeHandler const& conf_change_handler)
479 {
480- connection->set_display_config_change_callback(conf_change_handler);
481+ auto const handler = [this, conf_change_handler] {
482+ current_configuration = std::make_unique<NestedDisplayConfiguration>(connection->create_display_config());
483+ conf_change_handler();
484+ };
485+
486+ connection->set_display_config_change_callback(handler);
487 }
488
489 void mgn::Display::register_pause_resume_handlers(
490
491=== modified file 'src/server/graphics/nested/display.h'
492--- src/server/graphics/nested/display.h 2015-08-20 02:44:54 +0000
493+++ src/server/graphics/nested/display.h 2015-11-05 16:01:02 +0000
494@@ -52,6 +52,8 @@
495
496 namespace nested
497 {
498+class NestedDisplayConfiguration;
499+
500 namespace detail
501 {
502
503@@ -151,6 +153,10 @@
504
505 std::mutex outputs_mutex;
506 std::unordered_map<DisplayConfigurationOutputId, std::shared_ptr<detail::DisplaySyncGroup>> outputs;
507+
508+ std::mutex mutable configuration_mutex;
509+ std::unique_ptr<NestedDisplayConfiguration> current_configuration;
510+
511 void create_surfaces(mir::graphics::DisplayConfiguration const& configuration);
512 void apply_to_connection(mir::graphics::DisplayConfiguration const& configuration);
513 void complete_display_initialization(MirPixelFormat format);
514
515=== modified file 'src/server/input/display_input_region.cpp'
516--- src/server/input/display_input_region.cpp 2015-09-24 02:16:12 +0000
517+++ src/server/input/display_input_region.cpp 2015-11-05 16:01:02 +0000
518@@ -51,7 +51,10 @@
519 // to group a touchscreen with a display. So for now, just return the view area
520 // of the first display, as that matches the most common systems (laptops with touchscreens,
521 // phone/tablets with touchscreens).
522- return *rectangles.begin();
523+ if (rectangles.size() != 0)
524+ return *rectangles.begin();
525+ else
526+ return geom::Rectangle{};
527 }
528
529 void mi::DisplayInputRegion::confine(geom::Point& point)
530
531=== modified file 'src/server/scene/rendering_tracker.cpp'
532--- src/server/scene/rendering_tracker.cpp 2015-02-22 07:46:25 +0000
533+++ src/server/scene/rendering_tracker.cpp 2015-11-05 16:01:02 +0000
534@@ -68,6 +68,18 @@
535 configure_visibility(mir_surface_visibility_occluded);
536 }
537
538+bool ms::RenderingTracker::is_exposed_in(mc::CompositorID cid) const
539+{
540+ std::lock_guard<std::mutex> lock{guard};
541+
542+ ensure_is_active_compositor(cid);
543+
544+ if (occlusions.size() == 0)
545+ return true;
546+
547+ return occlusions.find(cid) == occlusions.end();
548+}
549+
550 bool ms::RenderingTracker::occluded_in_all_active_compositors()
551 {
552 return occlusions == active_compositors_;
553
554=== modified file 'src/server/scene/rendering_tracker.h'
555--- src/server/scene/rendering_tracker.h 2015-02-22 07:46:25 +0000
556+++ src/server/scene/rendering_tracker.h 2015-11-05 16:01:02 +0000
557@@ -42,6 +42,7 @@
558 void rendered_in(compositor::CompositorID cid);
559 void occluded_in(compositor::CompositorID cid);
560 void active_compositors(std::set<compositor::CompositorID> const& cids);
561+ bool is_exposed_in(compositor::CompositorID cid) const;
562
563 private:
564 bool occluded_in_all_active_compositors();
565@@ -52,7 +53,7 @@
566 std::weak_ptr<Surface> const weak_surface;
567 std::set<compositor::CompositorID> occlusions;
568 std::set<compositor::CompositorID> active_compositors_;
569- std::mutex guard;
570+ std::mutex mutable guard;
571 };
572
573 }
574
575=== modified file 'src/server/scene/surface_stack.cpp'
576--- src/server/scene/surface_stack.cpp 2015-06-18 02:46:16 +0000
577+++ src/server/scene/surface_stack.cpp 2015-11-05 16:01:02 +0000
578@@ -168,15 +168,18 @@
579 // TODO: Rename mir_surface_attrib_visibility as it's obviously
580 // confusing with visible()
581 if (surface->visible() &&
582- surface->query(mir_surface_attrib_visibility) ==
583- mir_surface_visibility_exposed)
584+ surface->query(mir_surface_attrib_visibility) == mir_surface_visibility_exposed)
585 {
586- // Note that we ask the surface and not a Renderable.
587- // This is because we don't want to waste time and resources
588- // on a snapshot till we're sure we need it...
589- int ready = surface->buffers_ready_for_compositor(id);
590- if (ready > result)
591- result = ready;
592+ auto const tracker = rendering_trackers.find(surface.get());
593+ if (tracker != rendering_trackers.end() && tracker->second->is_exposed_in(id))
594+ {
595+ // Note that we ask the surface and not a Renderable.
596+ // This is because we don't want to waste time and resources
597+ // on a snapshot till we're sure we need it...
598+ int ready = surface->buffers_ready_for_compositor(id);
599+ if (ready > result)
600+ result = ready;
601+ }
602 }
603 }
604 }
605
606=== modified file 'tests/acceptance-tests/test_nested_mir.cpp'
607--- tests/acceptance-tests/test_nested_mir.cpp 2015-10-07 17:08:36 +0000
608+++ tests/acceptance-tests/test_nested_mir.cpp 2015-11-05 16:01:02 +0000
609@@ -22,12 +22,14 @@
610 #include "mir/input/cursor_images.h"
611 #include "mir/graphics/display.h"
612 #include "mir/graphics/display_configuration.h"
613+#include "mir/graphics/display_configuration_policy.h"
614 #include "mir/graphics/display_configuration_report.h"
615 #include "mir/input/cursor_listener.h"
616 #include "mir/cached_ptr.h"
617 #include "mir/main_loop.h"
618 #include "mir/scene/session_coordinator.h"
619 #include "mir/scene/session.h"
620+#include "mir/shell/display_configuration_controller.h"
621 #include "mir/shell/host_lifecycle_event_listener.h"
622
623 #include "mir_test_framework/headless_in_process_server.h"
624@@ -183,10 +185,41 @@
625 bool hidden{false};
626 };
627
628+struct MockDisplayConfigurationPolicy : mg::DisplayConfigurationPolicy
629+{
630+ MOCK_METHOD1(apply_to, void (mg::DisplayConfiguration&));
631+};
632+
633 class NestedMirRunner : public mtf::HeadlessNestedServerRunner
634 {
635 public:
636 NestedMirRunner(std::string const& connection_string)
637+ : NestedMirRunner(connection_string, true)
638+ {
639+ start_server();
640+ }
641+
642+ virtual ~NestedMirRunner()
643+ {
644+ stop_server();
645+ }
646+
647+ std::shared_ptr<MockHostLifecycleEventListener> the_mock_host_lifecycle_event_listener()
648+ {
649+ return mock_host_lifecycle_event_listener([]
650+ { return std::make_shared<NiceMock<MockHostLifecycleEventListener>>(); });
651+ }
652+
653+ std::shared_ptr<CursorWrapper> cursor_wrapper;
654+
655+ virtual std::shared_ptr<MockDisplayConfigurationPolicy> mock_display_configuration_policy()
656+ {
657+ return mock_display_configuration_policy_([this]
658+ { return std::make_shared<NiceMock<MockDisplayConfigurationPolicy>>(); });
659+ }
660+
661+protected:
662+ NestedMirRunner(std::string const& connection_string, bool)
663 : mtf::HeadlessNestedServerRunner(connection_string)
664 {
665 server.override_the_host_lifecycle_event_listener([this]
666@@ -197,24 +230,15 @@
667
668 server.override_the_cursor_images([] { return std::make_shared<CursorImages>(); });
669
670- start_server();
671- }
672-
673- ~NestedMirRunner()
674- {
675- stop_server();
676- }
677-
678- std::shared_ptr<MockHostLifecycleEventListener> the_mock_host_lifecycle_event_listener()
679- {
680- return mock_host_lifecycle_event_listener([]
681- { return std::make_shared<NiceMock<MockHostLifecycleEventListener>>(); });
682- }
683-
684- std::shared_ptr<CursorWrapper> cursor_wrapper;
685+ server.wrap_display_configuration_policy([this]
686+ (std::shared_ptr<mg::DisplayConfigurationPolicy> const&)
687+ { return mock_display_configuration_policy(); });
688+ }
689
690 private:
691 mir::CachedPtr<MockHostLifecycleEventListener> mock_host_lifecycle_event_listener;
692+
693+ mir::CachedPtr<MockDisplayConfigurationPolicy> mock_display_configuration_policy_;
694 };
695
696 struct NestedServer : mtf::HeadlessInProcessServer
697@@ -376,6 +400,7 @@
698 // No post on surface creation
699 EXPECT_CALL(*mock_session_mediator_report, session_submit_buffer_called(_)).Times(0);
700 NestedMirRunner nested_mir{new_connection()};
701+
702 auto const connection = mir_connect_sync(nested_mir.new_connection().c_str(), __PRETTY_FUNCTION__);
703 auto const surface = mtf::make_any_surface(connection);
704
705@@ -692,3 +717,72 @@
706 // surface as the host cursor then reverts to default.
707 Mock::VerifyAndClearExpectations(mock_cursor.get());
708 }
709+
710+TEST_F(NestedServer, applies_display_config_on_startup)
711+{
712+ mt::WaitCondition condition;
713+
714+ auto const expected_config = server.the_display()->configuration();
715+ expected_config->for_each_output([](mg::UserDisplayConfigurationOutput& output)
716+ { output.orientation = mir_orientation_inverted;});
717+
718+ EXPECT_CALL(*the_mock_display_configuration_report(), new_configuration(mt::DisplayConfigMatches(std::ref(*expected_config))))
719+ .WillRepeatedly(InvokeWithoutArgs([&] { condition.wake_up_everyone(); }));
720+
721+ struct MyNestedMirRunner : NestedMirRunner
722+ {
723+ MyNestedMirRunner(std::string const& connection_string) :
724+ NestedMirRunner(connection_string, true)
725+ {
726+ start_server();
727+ }
728+
729+ std::shared_ptr<MockDisplayConfigurationPolicy> mock_display_configuration_policy() override
730+ {
731+ auto result = std::make_unique<MockDisplayConfigurationPolicy>();
732+ EXPECT_CALL(*result, apply_to(_)).Times(AnyNumber())
733+ .WillOnce(Invoke([](mg::DisplayConfiguration& config)
734+ {
735+ config.for_each_output([](mg::UserDisplayConfigurationOutput& output)
736+ { output.orientation = mir_orientation_inverted; });
737+ }));
738+
739+ return std::shared_ptr<MockDisplayConfigurationPolicy>(std::move(result));
740+ }
741+ } nested_mir{new_connection()};
742+
743+ auto const connection = mir_connect_sync(nested_mir.new_connection().c_str(), __PRETTY_FUNCTION__);
744+ auto const surface = make_and_paint_surface(connection);
745+
746+ condition.wait_for_at_most_seconds(1);
747+ Mock::VerifyAndClearExpectations(the_mock_display_configuration_report().get());
748+
749+ EXPECT_TRUE(condition.woken());
750+
751+ mir_surface_release_sync(surface);
752+ mir_connection_release(connection);
753+}
754+
755+TEST_F(NestedServer, base_configuration_change_in_host_is_seen_in_nested)
756+{
757+ NestedMirRunner nested_mir{new_connection()};
758+ auto const connection = mir_connect_sync(nested_mir.new_connection().c_str(), __PRETTY_FUNCTION__);
759+ auto const surface = make_and_paint_surface(connection);
760+ auto const config_policy = nested_mir.mock_display_configuration_policy();
761+ std::shared_ptr<mg::DisplayConfiguration> const new_config{server.the_display()->configuration()};
762+ new_config->for_each_output([](mg::UserDisplayConfigurationOutput& output)
763+ { output.orientation = mir_orientation_inverted;});
764+
765+ mt::WaitCondition condition;
766+ EXPECT_CALL(*config_policy, apply_to(mt::DisplayConfigMatches(std::ref(*new_config))))
767+ .WillOnce(InvokeWithoutArgs([&] { condition.wake_up_everyone(); }));
768+
769+ server.the_display_configuration_controller()->set_default_display_configuration(new_config);
770+
771+ condition.wait_for_at_most_seconds(1);
772+ Mock::VerifyAndClearExpectations(config_policy.get());
773+ EXPECT_TRUE(condition.woken());
774+
775+ mir_surface_release_sync(surface);
776+ mir_connection_release(connection);
777+}
778
779=== modified file 'tests/unit-tests/input/test_display_input_region.cpp'
780--- tests/unit-tests/input/test_display_input_region.cpp 2015-09-24 02:16:12 +0000
781+++ tests/unit-tests/input/test_display_input_region.cpp 2015-11-05 16:01:02 +0000
782@@ -80,3 +80,14 @@
783 }
784
785 }
786+
787+TEST(DisplayInputRegionTest, returns_empty_bounding_rectangle_when_there_are_no_outputs)
788+{
789+ geom::Rectangle const empty_rect{};
790+ auto const stub_display = std::make_shared<mtd::StubDisplay>(0);
791+
792+ mi::DisplayInputRegion input_region{stub_display};
793+
794+ auto const bounding_rect = input_region.bounding_rectangle();
795+ EXPECT_EQ(empty_rect, bounding_rect);
796+}
797
798=== modified file 'tests/unit-tests/scene/test_surface_stack.cpp'
799--- tests/unit-tests/scene/test_surface_stack.cpp 2015-06-26 08:00:59 +0000
800+++ tests/unit-tests/scene/test_surface_stack.cpp 2015-11-05 16:01:02 +0000
801@@ -339,6 +339,7 @@
802 {
803 using namespace testing;
804 ms::SurfaceStack stack{report};
805+ stack.register_compositor(this);
806 mtd::StubBuffer stub_buffer;
807 int ready = 0;
808 auto mock_queue = std::make_shared<testing::NiceMock<mtd::MockBufferBundle>>();
809@@ -384,6 +385,7 @@
810 using namespace testing;
811
812 ms::SurfaceStack stack{report};
813+ stack.register_compositor(this);
814 auto surface = std::make_shared<ms::BasicSurface>(
815 std::string("stub"),
816 geom::Rectangle{{},{}},
817@@ -405,6 +407,48 @@
818 EXPECT_EQ(0, stack.frames_pending(this));
819 }
820
821+TEST_F(SurfaceStack, scene_doesnt_count_pending_frames_from_partially_exposed_surfaces)
822+{ // Regression test for LP: #1499039
823+ using namespace testing;
824+
825+ // Partially exposed means occluded in one compositor but not another
826+ ms::SurfaceStack stack{report};
827+ auto const comp1 = reinterpret_cast<mc::CompositorID>(0);
828+ auto const comp2 = reinterpret_cast<mc::CompositorID>(1);
829+
830+ stack.register_compositor(comp1);
831+ stack.register_compositor(comp2);
832+ auto surface = std::make_shared<ms::BasicSurface>(
833+ std::string("stub"),
834+ geom::Rectangle{{},{}},
835+ false,
836+ std::make_shared<mtd::StubBufferStream>(),
837+ std::shared_ptr<mir::input::InputChannel>(),
838+ std::shared_ptr<mir::input::InputSender>(),
839+ std::shared_ptr<mg::CursorImage>(),
840+ report);
841+
842+ stack.add_surface(surface, default_params.depth, default_params.input_mode);
843+ post_a_frame(*surface);
844+ post_a_frame(*surface);
845+ post_a_frame(*surface);
846+
847+ EXPECT_EQ(3, stack.frames_pending(comp2));
848+ auto elements = stack.scene_elements_for(comp1);
849+ for (auto const& elem : elements)
850+ {
851+ elem->rendered();
852+ }
853+
854+ elements = stack.scene_elements_for(comp2);
855+ for (auto const& elem : elements)
856+ {
857+ elem->occluded();
858+ }
859+
860+ EXPECT_EQ(0, stack.frames_pending(comp2));
861+}
862+
863 TEST_F(SurfaceStack, surfaces_are_emitted_by_layer)
864 {
865 using namespace testing;

Subscribers

People subscribed via source and target branches

to all changes: