Merge lp:unity-system-compositor into lp:unity-system-compositor/ubuntu
- trunk
- Merge into ubuntu
Status: | Merged |
---|---|
Approved by: | Andreas Pokorny |
Approved revision: | 226 |
Merged at revision: | 207 |
Proposed branch: | lp:unity-system-compositor |
Merge into: | lp:unity-system-compositor/ubuntu |
Diff against target: |
2561 lines (+1216/-599) 31 files modified
CMakeLists.txt (+1/-2) cmake/FindPIL.cmake (+8/-0) debian/changelog (+6/-0) debian/control (+1/-2) debian/unity-system-compositor.install (+0/-1) spinner/CMakeLists.txt (+45/-11) spinner/eglapp.cpp (+117/-231) spinner/eglapp.h (+4/-17) spinner/eglspinner.cpp (+278/-220) spinner/miregl.cpp (+247/-0) spinner/miregl.h (+67/-0) src/external_spinner.cpp (+17/-0) src/mir_screen.cpp (+2/-5) src/mir_screen.h (+1/-1) src/screen.h (+1/-1) src/screen_event_handler.cpp (+22/-1) src/screen_event_handler.h (+1/-0) src/server.cpp (+50/-7) src/session_monitor.h (+63/-0) src/session_switcher.h (+6/-23) src/window_manager.cpp (+13/-43) src/window_manager.h (+4/-3) tests/integration-tests/CMakeLists.txt (+1/-0) tests/integration-tests/spin_wait.cpp (+39/-0) tests/integration-tests/spin_wait.h (+39/-0) tests/integration-tests/test_dbus_event_loop.cpp (+2/-1) tests/integration-tests/test_external_spinner.cpp (+44/-11) tests/integration-tests/test_unity_screen_service.cpp (+1/-1) tests/unit-tests/test_mir_screen.cpp (+8/-5) tests/unit-tests/test_screen_event_handler.cpp (+42/-13) tools/png2header.py (+86/-0) |
To merge this branch: | bzr merge lp:unity-system-compositor |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Needs Fixing | |
Unity System Compositor Development Team | Pending | ||
Review via email: mp+262866@code.launchpad.net |
Commit message
Release in step with Mir 0.14.0
Description of the change
Release in step with Mir 0.14.0
PS Jenkins bot (ps-jenkins) wrote : | # |
- 221. By CI Train Bot Account
-
merge lp:unity-system-compositor/ubuntu.
Approved by Andreas Pokorny, PS Jenkins bot.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:221
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 222. By Andreas Pokorny
-
add wily changelog entry from last release.
Approved by PS Jenkins bot.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:222
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 223. By Mirco Müller
-
Updated visuals of spinner boot-anim to latest spec from Design.
Approved by PS Jenkins bot, Alexandros Frantzis.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:223
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 224. By Alexandros Frantzis
-
Don't restart the inactivity timers when receiving invalid dbus calls or uninteresting dbus events
Previously, invalid dbus calls (e.g., trying to remove a non-existent keepDisplayOn request), or uninteresting dbus events (e.g., being informed about disconnections of dbus clients that hadn't issued any keepDisplayOn requests), would restart the inactivity timers, effectively increasing the delay until display dimming and poweroff. Fixes: https:/
/bugs.launchpad .net/bugs/ 1461476. Approved by Andreas Pokorny, Alberto Aguirre, PS Jenkins bot.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:224
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 225. By Alexandros Frantzis
-
Ensure inactivity timers are enabled when turning the screen on using the power button. Fixes: https:/
/bugs.launchpad .net/bugs/ 1473979. Approved by Alberto Aguirre, PS Jenkins bot.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:225
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 226. By Andreas Pokorny
-
update changelog
- 227. By kevin gunn
-
update changelog to something proper
- 228. By kevin gunn
-
removed bad paste from changelog
- 229. By kevin gunn
-
one more changelog update to trick it
- 230. By kevin gunn
-
changelog update to trick it
- 231. By kevin gunn
-
changelog update to trick it2
- 232. By kevin gunn
-
clean up change log mess, this should work
- 233. By Alexandros Frantzis
-
Wait a bit for spinner process to appear in AnExternalSpinner tests. Fixes: https:/
/bugs.launchpad .net/bugs/ 1473418. Approved by Kevin DuBois, PS Jenkins bot.
- 234. By Alexandros Frantzis
-
Don't leave zombie spinner processes. Fixes: https:/
/bugs.launchpad .net/bugs/ 1473061. Approved by PS Jenkins bot, Kevin DuBois.
- 235. By Daniel van Vugt
-
Drop build dep on g++-4.9 (LP: #1452347). Fixes: https:/
/bugs.launchpad .net/bugs/ 1452347. Approved by Alexandros Frantzis, Kevin DuBois, PS Jenkins bot.
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2015-04-07 13:36:48 +0000 |
3 | +++ CMakeLists.txt 2015-07-20 10:34:37 +0000 |
4 | @@ -15,7 +15,6 @@ |
5 | # Authored by: Robert Ancell <robert.ancell@canonical.com> |
6 | |
7 | project(UnitySystemCompositor) |
8 | -set(PACKAGE "unity-system-compositor") |
9 | set(USC_VERSION_MAJOR 0) |
10 | set(USC_VERSION_MINOR 0) |
11 | set(USC_VERSION_PATCH 4) |
12 | @@ -40,7 +39,6 @@ |
13 | |
14 | find_package(PkgConfig) |
15 | pkg_check_modules(ANDROIDPROPS libandroid-properties) |
16 | -pkg_check_modules(CAIRO REQUIRED cairo) |
17 | pkg_check_modules(GLIB REQUIRED glib-2.0) |
18 | pkg_check_modules(MIRCLIENT REQUIRED mirclient) |
19 | pkg_check_modules(MIRSERVER REQUIRED mirserver) |
20 | @@ -48,6 +46,7 @@ |
21 | |
22 | find_package(Boost 1.48.0 COMPONENTS system REQUIRED) |
23 | find_package(GLESv2 REQUIRED) |
24 | +find_package(PIL REQUIRED) |
25 | |
26 | add_subdirectory(spinner/) |
27 | add_subdirectory(src/) |
28 | |
29 | === added file 'cmake/FindPIL.cmake' |
30 | --- cmake/FindPIL.cmake 1970-01-01 00:00:00 +0000 |
31 | +++ cmake/FindPIL.cmake 2015-07-20 10:34:37 +0000 |
32 | @@ -0,0 +1,8 @@ |
33 | +execute_process( |
34 | + COMMAND python -c "from PIL import Image" |
35 | + RESULT_VARIABLE HAVE_PIL |
36 | +) |
37 | + |
38 | +if (NOT ${HAVE_PIL} EQUAL 0) |
39 | + message(FATAL_ERROR "Python Imaging Library (PIL) not found") |
40 | +endif() |
41 | |
42 | === modified file 'debian/changelog' |
43 | --- debian/changelog 2015-07-13 14:17:04 +0000 |
44 | +++ debian/changelog 2015-07-20 10:34:37 +0000 |
45 | @@ -1,3 +1,9 @@ |
46 | +unity-system-compositor (0.0.5+15.10.20150506.2-0ubuntu1) UNRELEASED; urgency=medium |
47 | + |
48 | + * Release in step with Mir 0.14 |
49 | + |
50 | + -- Kevin Gunn <kevin.gunn@canonical.com> Thu, 16 Jul 2015 15:14:22 -0500 |
51 | + |
52 | unity-system-compositor (0.0.5+15.04.20150713-0ubuntu1) vivid; urgency=medium |
53 | |
54 | [ Alexandros Frantzis ] |
55 | |
56 | === modified file 'debian/control' |
57 | --- debian/control 2015-05-06 16:09:19 +0000 |
58 | +++ debian/control 2015-07-20 10:34:37 +0000 |
59 | @@ -6,12 +6,10 @@ |
60 | cmake-data, |
61 | dbus, |
62 | debhelper (>= 9), |
63 | - g++-4.9, |
64 | google-mock, |
65 | libandroid-properties-dev [i386 amd64 armhf], |
66 | libboost-dev, |
67 | libboost-system-dev, |
68 | - libcairo2-dev, |
69 | libdbus-1-dev, |
70 | libglib2.0-dev, |
71 | libgles2-mesa-dev, |
72 | @@ -21,6 +19,7 @@ |
73 | pkg-config, |
74 | python:any (>= 2.7), |
75 | python-setuptools, |
76 | + python-pil, |
77 | Standards-Version: 3.9.4 |
78 | Homepage: https://launchpad.net/unity-system-compositor |
79 | # if you don't have have commit access to this branch but would like to upload |
80 | |
81 | === modified file 'debian/unity-system-compositor.install' |
82 | --- debian/unity-system-compositor.install 2014-06-16 16:53:55 +0000 |
83 | +++ debian/unity-system-compositor.install 2015-07-20 10:34:37 +0000 |
84 | @@ -4,4 +4,3 @@ |
85 | usr/bin/unity-system-compositor-spinner |
86 | usr/sbin/unity-system-compositor |
87 | usr/share/dbus-1/interfaces/com.canonical.Unity.Screen.xml |
88 | -usr/share/unity-system-compositor |
89 | |
90 | === modified file 'spinner/CMakeLists.txt' |
91 | --- spinner/CMakeLists.txt 2014-05-06 20:06:27 +0000 |
92 | +++ spinner/CMakeLists.txt 2015-07-20 10:34:37 +0000 |
93 | @@ -14,17 +14,44 @@ |
94 | # You should have received a copy of the GNU General Public License |
95 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
96 | |
97 | +function(png2header png header varname) |
98 | + add_custom_command( |
99 | + OUTPUT ${header} |
100 | + COMMAND python ${CMAKE_SOURCE_DIR}/tools/png2header.py ${png} ${varname} > ${header} |
101 | + DEPENDS ${png} ${CMAKE_SOURCE_DIR}/tools/png2header.py |
102 | + ) |
103 | +endfunction() |
104 | + |
105 | +png2header( |
106 | + ${CMAKE_CURRENT_SOURCE_DIR}/wallpaper.png |
107 | + ${CMAKE_CURRENT_BINARY_DIR}/wallpaper.h |
108 | + wallpaper |
109 | +) |
110 | + |
111 | +png2header( |
112 | + ${CMAKE_CURRENT_SOURCE_DIR}/logo.png |
113 | + ${CMAKE_CURRENT_BINARY_DIR}/logo.h |
114 | + logo |
115 | +) |
116 | + |
117 | +png2header( |
118 | + ${CMAKE_CURRENT_SOURCE_DIR}/white-dot.png |
119 | + ${CMAKE_CURRENT_BINARY_DIR}/white_dot.h |
120 | + white_dot |
121 | +) |
122 | + |
123 | +png2header( |
124 | + ${CMAKE_CURRENT_SOURCE_DIR}/orange-dot.png |
125 | + ${CMAKE_CURRENT_BINARY_DIR}/orange_dot.h |
126 | + orange_dot |
127 | +) |
128 | + |
129 | include_directories( |
130 | - ${CAIRO_INCLUDE_DIRS} |
131 | ${GLIB_INCLUDE_DIRS} |
132 | ${ANDROIDPROPS_INCLUDE_DIRS} |
133 | ${GLESv2_INCLUDE_DIRS} |
134 | ${MIRCLIENT_INCLUDE_DIRS} |
135 | -) |
136 | -add_definitions( |
137 | - -DPACKAGE="${PACKAGE}" |
138 | - -DLOCALEDIR="${CMAKE_INSTALL_FULL_LOCALEDIR}" |
139 | - -DPKGDATADIR="${CMAKE_INSTALL_FULL_DATAROOTDIR}/${PACKAGE}" |
140 | + ${CMAKE_CURRENT_BINARY_DIR} |
141 | ) |
142 | |
143 | if(ANDROIDPROPS_FOUND) |
144 | @@ -33,16 +60,23 @@ |
145 | |
146 | link_directories(${MIRCLIENT_LIBRARY_DIRS}) |
147 | |
148 | -add_executable(unity-system-compositor-spinner eglapp.c eglapp.h eglspinner.c) |
149 | +add_executable(unity-system-compositor-spinner |
150 | + eglapp.cpp |
151 | + eglapp.h |
152 | + eglspinner.cpp |
153 | + miregl.h |
154 | + miregl.cpp |
155 | + ${CMAKE_CURRENT_BINARY_DIR}/wallpaper.h |
156 | + ${CMAKE_CURRENT_BINARY_DIR}/logo.h |
157 | + ${CMAKE_CURRENT_BINARY_DIR}/white_dot.h |
158 | + ${CMAKE_CURRENT_BINARY_DIR}/orange_dot.h |
159 | +) |
160 | + |
161 | target_link_libraries(unity-system-compositor-spinner |
162 | EGL |
163 | - ${CAIRO_LDFLAGS} |
164 | ${GLIB_LDFLAGS} |
165 | ${ANDROIDPROPS_LDFLAGS} |
166 | ${GLESv2_LIBRARIES} |
167 | ${MIRCLIENT_LDFLAGS} |
168 | ) |
169 | install(TARGETS unity-system-compositor-spinner RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) |
170 | - |
171 | -install(FILES spinner-logo.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PACKAGE}) |
172 | -install(FILES spinner-glow.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PACKAGE}) |
173 | |
174 | === renamed file 'spinner/eglapp.c' => 'spinner/eglapp.cpp' |
175 | --- spinner/eglapp.c 2015-04-24 12:48:10 +0000 |
176 | +++ spinner/eglapp.cpp 2015-07-20 10:34:37 +0000 |
177 | @@ -1,5 +1,5 @@ |
178 | /* |
179 | - * Copyright © 2013 Canonical Ltd. |
180 | + * Copyright © 2013, 2015 Canonical Ltd. |
181 | * |
182 | * This program is free software: you can redistribute it and/or modify |
183 | * it under the terms of the GNU General Public License version 3 as |
184 | @@ -12,145 +12,77 @@ |
185 | * |
186 | * You should have received a copy of the GNU General Public License |
187 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
188 | - * |
189 | - * Author: Daniel van Vugt <daniel.van.vugt@canonical.com> |
190 | */ |
191 | |
192 | #include "eglapp.h" |
193 | -#include "mir_toolkit/mir_client_library.h" |
194 | -#include <stdio.h> |
195 | -#include <stdlib.h> |
196 | -#include <signal.h> |
197 | -#include <time.h> |
198 | -#include <EGL/egl.h> |
199 | -#include <GLES2/gl2.h> |
200 | + |
201 | +#include "miregl.h" |
202 | + |
203 | + |
204 | |
205 | float mir_eglapp_background_opacity = 1.0f; |
206 | |
207 | static const char appname[] = "eglspinner"; |
208 | |
209 | -static MirConnection *connection; |
210 | -static MirSurface *surface; |
211 | -static EGLDisplay egldisplay; |
212 | -static EGLSurface eglsurface; |
213 | -static volatile sig_atomic_t running = 0; |
214 | - |
215 | -#define CHECK(_cond, _err) \ |
216 | - if (!(_cond)) \ |
217 | - { \ |
218 | - printf("%s\n", (_err)); \ |
219 | - return 0; \ |
220 | - } |
221 | - |
222 | -void mir_eglapp_shutdown(void) |
223 | -{ |
224 | - eglMakeCurrent(egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); |
225 | - eglTerminate(egldisplay); |
226 | - mir_surface_release_sync(surface); |
227 | - surface = NULL; |
228 | - mir_connection_release(connection); |
229 | - connection = NULL; |
230 | -} |
231 | - |
232 | -static void shutdown(int signum) |
233 | -{ |
234 | - if (running) |
235 | - { |
236 | - running = 0; |
237 | - printf("Signal %d received. Good night.\n", signum); |
238 | - } |
239 | -} |
240 | - |
241 | -mir_eglapp_bool mir_eglapp_running(void) |
242 | -{ |
243 | - return running; |
244 | -} |
245 | - |
246 | -void mir_eglapp_swap_buffers(void) |
247 | -{ |
248 | - EGLint width, height; |
249 | - |
250 | - if (!running) |
251 | - return; |
252 | - |
253 | - eglSwapBuffers(egldisplay, eglsurface); |
254 | - |
255 | - /* |
256 | - * Querying the surface (actually the current buffer) dimensions here is |
257 | - * the only truly safe way to be sure that the dimensions we think we |
258 | - * have are those of the buffer being rendered to. But this should be |
259 | - * improved in future; https://bugs.launchpad.net/mir/+bug/1194384 |
260 | - */ |
261 | - if (eglQuerySurface(egldisplay, eglsurface, EGL_WIDTH, &width) && |
262 | - eglQuerySurface(egldisplay, eglsurface, EGL_HEIGHT, &height)) |
263 | - { |
264 | - glViewport(0, 0, width, height); |
265 | - } |
266 | -} |
267 | - |
268 | -static void mir_eglapp_handle_event(MirSurface* surface, MirEvent const* ev, void* context) |
269 | -{ |
270 | - (void) surface; |
271 | - (void) context; |
272 | - if (mir_event_get_type(ev) == mir_event_type_resize) |
273 | - { |
274 | - MirResizeEvent const* resize = mir_event_get_resize_event(ev); |
275 | - /* |
276 | - * FIXME: https://bugs.launchpad.net/mir/+bug/1194384 |
277 | - * It is unsafe to set the width and height here because we're in a |
278 | - * different thread to that doing the rendering. So we either need |
279 | - * support for event queuing (directing them to another thread) or |
280 | - * full single-threaded callbacks. (LP: #1194384). |
281 | - */ |
282 | - printf("Resized to %dx%d\n", |
283 | - mir_resize_event_get_width(resize), |
284 | - mir_resize_event_get_height(resize)); |
285 | - } |
286 | -} |
287 | - |
288 | -static const MirDisplayOutput *find_active_output( |
289 | - const MirDisplayConfiguration *conf) |
290 | -{ |
291 | - const MirDisplayOutput *output = NULL; |
292 | - int d; |
293 | - |
294 | - for (d = 0; d < (int)conf->num_outputs; d++) |
295 | - { |
296 | - const MirDisplayOutput *out = conf->outputs + d; |
297 | - |
298 | - if (out->used && |
299 | - out->connected && |
300 | - out->num_modes && |
301 | - out->current_mode < out->num_modes) |
302 | + |
303 | +namespace |
304 | +{ |
305 | +template<typename ActiveOutputHandler> |
306 | +void for_each_active_output( |
307 | + MirConnection* const connection, ActiveOutputHandler const& handler) |
308 | +{ |
309 | + /* eglapps are interested in the screen size, so |
310 | + use mir_connection_create_display_config */ |
311 | + MirDisplayConfiguration* display_config = |
312 | + mir_connection_create_display_config(connection); |
313 | + |
314 | + for (MirDisplayOutput* output = display_config->outputs; |
315 | + output != display_config->outputs + display_config->num_outputs; |
316 | + ++output) |
317 | + { |
318 | + if (output->used && |
319 | + output->connected && |
320 | + output->num_modes && |
321 | + output->current_mode < output->num_modes) |
322 | { |
323 | - output = out; |
324 | - break; |
325 | + handler(output); |
326 | } |
327 | } |
328 | |
329 | - return output; |
330 | -} |
331 | - |
332 | -mir_eglapp_bool mir_eglapp_init(int argc, char *argv[], |
333 | - unsigned int *width, unsigned int *height) |
334 | -{ |
335 | - EGLint ctxattribs[] = |
336 | - { |
337 | - EGL_CONTEXT_CLIENT_VERSION, 2, |
338 | - EGL_NONE |
339 | - }; |
340 | + mir_display_config_destroy(display_config); |
341 | +} |
342 | + |
343 | +MirPixelFormat select_pixel_format(MirConnection* connection) |
344 | +{ |
345 | + unsigned int format[mir_pixel_formats]; |
346 | + unsigned int nformats; |
347 | + |
348 | + mir_connection_get_available_surface_formats( |
349 | + connection, |
350 | + (MirPixelFormat*) format, |
351 | + mir_pixel_formats, |
352 | + &nformats); |
353 | + |
354 | + auto const pixel_format = (MirPixelFormat) format[0]; |
355 | + |
356 | + printf("Server supports %d of %d surface pixel formats. Using format: %d\n", |
357 | + nformats, mir_pixel_formats, pixel_format); |
358 | + |
359 | + return pixel_format; |
360 | +} |
361 | +} |
362 | + |
363 | +std::vector<std::shared_ptr<MirEglSurface>> mir_eglapp_init(int argc, char *argv[]) |
364 | +{ |
365 | MirSurfaceParameters surfaceparm = |
366 | - { |
367 | - "eglappsurface", |
368 | - 256, 256, |
369 | - mir_pixel_format_xbgr_8888, |
370 | - mir_buffer_usage_hardware, |
371 | - mir_display_output_id_invalid |
372 | - }; |
373 | - EGLConfig eglconfig; |
374 | - EGLint neglconfigs; |
375 | - EGLContext eglctx; |
376 | - EGLBoolean ok; |
377 | + { |
378 | + "eglappsurface", |
379 | + 0, 0, |
380 | + mir_pixel_format_xbgr_8888, |
381 | + mir_buffer_usage_hardware, |
382 | + mir_display_output_id_invalid |
383 | + }; |
384 | + |
385 | EGLint swapinterval = 1; |
386 | char *mir_socket = NULL; |
387 | |
388 | @@ -159,7 +91,7 @@ |
389 | int i; |
390 | for (i = 1; i < argc; i++) |
391 | { |
392 | - mir_eglapp_bool help = 0; |
393 | + bool help = 0; |
394 | const char *arg = argv[i]; |
395 | |
396 | if (arg[0] == '-') |
397 | @@ -209,10 +141,6 @@ |
398 | } |
399 | } |
400 | break; |
401 | - case 'f': |
402 | - *width = 0; |
403 | - *height = 0; |
404 | - break; |
405 | case 's': |
406 | { |
407 | unsigned int w, h; |
408 | @@ -224,8 +152,8 @@ |
409 | } |
410 | if (sscanf(arg, "%ux%u", &w, &h) == 2) |
411 | { |
412 | - *width = w; |
413 | - *height = h; |
414 | + surfaceparm.width = w; |
415 | + surfaceparm.height = h; |
416 | } |
417 | else |
418 | { |
419 | @@ -259,111 +187,69 @@ |
420 | printf("Usage: %s [<options>]\n" |
421 | " -b Background opacity (0.0 - 1.0)\n" |
422 | " -h Show this help text\n" |
423 | - " -f Force full screen\n" |
424 | " -o ID Force placement on output monitor ID\n" |
425 | " -n Don't sync to vblank\n" |
426 | " -m socket Mir server socket\n" |
427 | " -s WIDTHxHEIGHT Force surface size\n" |
428 | " -q Quiet mode (no messages output)\n" |
429 | , argv[0]); |
430 | - return 0; |
431 | + return {}; |
432 | } |
433 | } |
434 | } |
435 | |
436 | - connection = mir_connect_sync(mir_socket, appname); |
437 | - CHECK(mir_connection_is_valid(connection), "Can't get connection"); |
438 | - |
439 | - /* eglapps are interested in the screen size, so |
440 | - use mir_connection_create_display_config */ |
441 | - MirDisplayConfiguration* display_config = |
442 | - mir_connection_create_display_config(connection); |
443 | - |
444 | - const MirDisplayOutput *output = find_active_output(display_config); |
445 | - |
446 | - if (output == NULL) |
447 | - { |
448 | - printf("No active outputs found.\n"); |
449 | - return 0; |
450 | - } |
451 | - |
452 | - const MirDisplayMode *mode = &output->modes[output->current_mode]; |
453 | - |
454 | - unsigned int format[mir_pixel_formats]; |
455 | - unsigned int nformats; |
456 | - |
457 | - mir_connection_get_available_surface_formats(connection, |
458 | - (MirPixelFormat*) format, mir_pixel_formats, &nformats); |
459 | - |
460 | - surfaceparm.pixel_format = (MirPixelFormat) format[0]; |
461 | - |
462 | - printf("Current active output is %dx%d %+d%+d\n", |
463 | - mode->horizontal_resolution, mode->vertical_resolution, |
464 | - output->position_x, output->position_y); |
465 | - |
466 | - surfaceparm.width = *width > 0 ? *width : mode->horizontal_resolution; |
467 | - surfaceparm.height = *height > 0 ? *height : mode->vertical_resolution; |
468 | - |
469 | - mir_display_config_destroy(display_config); |
470 | - |
471 | - printf("Server supports %d of %d surface pixel formats. Using format: %d\n", |
472 | - nformats, mir_pixel_formats, surfaceparm.pixel_format); |
473 | - unsigned int bpp = 8 * MIR_BYTES_PER_PIXEL(surfaceparm.pixel_format); |
474 | - EGLint attribs[] = |
475 | - { |
476 | - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, |
477 | - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, |
478 | - EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER, |
479 | - EGL_BUFFER_SIZE, (EGLint) bpp, |
480 | - EGL_NONE |
481 | - }; |
482 | - |
483 | - surface = mir_connection_create_surface_sync(connection, &surfaceparm); |
484 | - CHECK(mir_surface_is_valid(surface), "Can't create a surface"); |
485 | - |
486 | - mir_surface_set_event_handler(surface, mir_eglapp_handle_event, NULL); |
487 | - |
488 | - egldisplay = eglGetDisplay( |
489 | - (EGLNativeDisplayType) mir_connection_get_egl_native_display(connection)); |
490 | - CHECK(egldisplay != EGL_NO_DISPLAY, "Can't eglGetDisplay"); |
491 | - |
492 | - ok = eglInitialize(egldisplay, NULL, NULL); |
493 | - CHECK(ok, "Can't eglInitialize"); |
494 | - |
495 | - ok = eglChooseConfig(egldisplay, attribs, &eglconfig, 1, &neglconfigs); |
496 | - CHECK(ok, "Could not eglChooseConfig"); |
497 | - CHECK(neglconfigs > 0, "No EGL config available"); |
498 | - |
499 | - eglsurface = eglCreateWindowSurface(egldisplay, eglconfig, |
500 | - (EGLNativeWindowType)mir_buffer_stream_get_egl_native_window(mir_surface_get_buffer_stream(surface)), NULL); |
501 | - CHECK(eglsurface != EGL_NO_SURFACE, "eglCreateWindowSurface failed"); |
502 | - |
503 | - eglctx = eglCreateContext(egldisplay, eglconfig, EGL_NO_CONTEXT, |
504 | - ctxattribs); |
505 | - CHECK(eglctx != EGL_NO_CONTEXT, "eglCreateContext failed"); |
506 | - |
507 | - ok = eglMakeCurrent(egldisplay, eglsurface, eglsurface, eglctx); |
508 | - CHECK(ok, "Can't eglMakeCurrent"); |
509 | - |
510 | - signal(SIGINT, shutdown); |
511 | - signal(SIGTERM, shutdown); |
512 | - |
513 | - *width = surfaceparm.width; |
514 | - *height = surfaceparm.height; |
515 | - |
516 | - eglSwapInterval(egldisplay, swapinterval); |
517 | - |
518 | - running = 1; |
519 | - |
520 | - return 1; |
521 | -} |
522 | - |
523 | -struct MirConnection* mir_eglapp_native_connection() |
524 | -{ |
525 | - return connection; |
526 | -} |
527 | - |
528 | -struct MirSurface* mir_eglapp_native_surface() |
529 | -{ |
530 | - return surface; |
531 | + MirConnection* const connection{mir_connect_sync(mir_socket, appname)}; |
532 | + if (!mir_connection_is_valid(connection)) |
533 | + throw std::runtime_error("Can't get connection"); |
534 | + |
535 | + auto const pixel_format = select_pixel_format(connection); |
536 | + surfaceparm.pixel_format = pixel_format; |
537 | + |
538 | + auto const mir_egl_app = make_mir_eglapp(connection, pixel_format); |
539 | + |
540 | + std::vector<std::shared_ptr<MirEglSurface>> result; |
541 | + |
542 | + // If a size has been specified just do that |
543 | + if (surfaceparm.width && surfaceparm.height) |
544 | + { |
545 | + result.push_back(std::make_shared<MirEglSurface>(mir_egl_app, surfaceparm, swapinterval)); |
546 | + return result; |
547 | + } |
548 | + |
549 | + // If an output has been specified just do that |
550 | + if (surfaceparm.output_id != mir_display_output_id_invalid) |
551 | + { |
552 | + for_each_active_output(connection, [&](MirDisplayOutput const* output) |
553 | + { |
554 | + if (output->output_id == surfaceparm.output_id) |
555 | + { |
556 | + auto const& mode = output->modes[output->current_mode]; |
557 | + surfaceparm.width = mode.horizontal_resolution; |
558 | + surfaceparm.height = mode.vertical_resolution; |
559 | + } |
560 | + }); |
561 | + result.push_back(std::make_shared<MirEglSurface>(mir_egl_app, surfaceparm, swapinterval)); |
562 | + return result; |
563 | + } |
564 | + |
565 | + // but normally, we're fullscreen on every active output |
566 | + for_each_active_output(connection, [&](MirDisplayOutput const* output) |
567 | + { |
568 | + auto const& mode = output->modes[output->current_mode]; |
569 | + |
570 | + printf("Active output [%u] at (%d, %d) is %dx%d\n", |
571 | + output->output_id, |
572 | + output->position_x, output->position_y, |
573 | + mode.horizontal_resolution, mode.vertical_resolution); |
574 | + |
575 | + surfaceparm.width = mode.horizontal_resolution; |
576 | + surfaceparm.height = mode.vertical_resolution; |
577 | + surfaceparm.output_id = output->output_id; |
578 | + result.push_back(std::make_shared<MirEglSurface>(mir_egl_app, surfaceparm, swapinterval)); |
579 | + }); |
580 | + |
581 | + if (result.empty()) |
582 | + throw std::runtime_error("No active outputs found."); |
583 | + |
584 | + return result; |
585 | } |
586 | |
587 | === modified file 'spinner/eglapp.h' |
588 | --- spinner/eglapp.h 2014-03-08 22:01:45 +0000 |
589 | +++ spinner/eglapp.h 2015-07-20 10:34:37 +0000 |
590 | @@ -19,26 +19,13 @@ |
591 | #ifndef __EGLAPP_H__ |
592 | #define __EGLAPP_H__ |
593 | |
594 | -#ifdef __cplusplus |
595 | -extern "C" { |
596 | -#endif |
597 | +#include <memory> |
598 | +#include <vector> |
599 | |
600 | -typedef int mir_eglapp_bool; |
601 | -struct MirConnection; |
602 | -struct MirSurface; |
603 | +class MirEglSurface; |
604 | |
605 | extern float mir_eglapp_background_opacity; |
606 | |
607 | -mir_eglapp_bool mir_eglapp_init(int argc, char *argv[], |
608 | - unsigned int *width, unsigned int *height); |
609 | -void mir_eglapp_swap_buffers(void); |
610 | -mir_eglapp_bool mir_eglapp_running(void); |
611 | -void mir_eglapp_shutdown(void); |
612 | - |
613 | -struct MirConnection* mir_eglapp_native_connection(); |
614 | -struct MirSurface* mir_eglapp_native_surface(); |
615 | -#ifdef __cplusplus |
616 | -} |
617 | -#endif |
618 | +std::vector<std::shared_ptr<MirEglSurface>> mir_eglapp_init(int argc, char *argv[]); |
619 | |
620 | #endif |
621 | |
622 | === renamed file 'spinner/eglspinner.c' => 'spinner/eglspinner.cpp' |
623 | --- spinner/eglspinner.c 2015-05-01 14:16:27 +0000 |
624 | +++ spinner/eglspinner.cpp 2015-07-20 10:34:37 +0000 |
625 | @@ -1,5 +1,5 @@ |
626 | /* |
627 | - * Copyright © 2013 Canonical Ltd. |
628 | + * Copyright © 2013-2015 Canonical Ltd. |
629 | * |
630 | * This program is free software: you can redistribute it and/or modify |
631 | * it under the terms of the GNU General Public License version 3 as |
632 | @@ -15,22 +15,26 @@ |
633 | * |
634 | * Authors: Daniel van Vugt <daniel.van.vugt@canonical.com> |
635 | * Mirco Müller <mirco.mueller@canonical.com> |
636 | + * Alan Griffiths <alan@octopull.co.uk> |
637 | + * Kevin DuBois <kevin.dubois@canonical.com> |
638 | */ |
639 | |
640 | #include "eglapp.h" |
641 | +#include "miregl.h" |
642 | #include <assert.h> |
643 | -#include <cairo.h> |
644 | #include <glib.h> |
645 | -#include <stdio.h> |
646 | #include <string.h> |
647 | -#include <strings.h> |
648 | -#include <stdlib.h> |
649 | #include <GLES2/gl2.h> |
650 | -#include <math.h> |
651 | #include <sys/stat.h> |
652 | #if HAVE_PROPS |
653 | #include <hybris/properties/properties.h> |
654 | #endif |
655 | +#include <signal.h> |
656 | + |
657 | +#include "wallpaper.h" |
658 | +#include "logo.h" |
659 | +#include "white_dot.h" |
660 | +#include "orange_dot.h" |
661 | |
662 | // this is needed for get_gu() to obtain the grid-unit value |
663 | #define MAX_LENGTH 256 |
664 | @@ -41,9 +45,17 @@ |
665 | #define FILE_BASE "/etc/ubuntu-touch-session.d/" |
666 | #define FILE_EXTENSION ".conf" |
667 | |
668 | +enum TextureIds { |
669 | + WALLPAPER = 0, |
670 | + LOGO, |
671 | + WHITE_DOT, |
672 | + ORANGE_DOT, |
673 | + MAX_TEXTURES |
674 | +}; |
675 | + |
676 | int get_gu () |
677 | { |
678 | - int gu = 10; // use 10 as a default value |
679 | + int gu = 13; // use 13 as a default value |
680 | FILE* handle = NULL; |
681 | int i = 0; |
682 | int j = 0; |
683 | @@ -63,7 +75,7 @@ |
684 | else |
685 | { |
686 | #ifdef HAVE_PROPS |
687 | - char* defaultValue = ""; |
688 | + char const* defaultValue = ""; |
689 | char value[PROP_VALUE_MAX]; |
690 | property_get (PROP_KEY, value, defaultValue); |
691 | strcat (filename, value); |
692 | @@ -125,56 +137,34 @@ |
693 | } |
694 | |
695 | // Colours from http://design.ubuntu.com/brand/colour-palette |
696 | -#define MID_AUBERGINE 0.368627451f, 0.152941176f, 0.31372549f |
697 | -#define ORANGE 0.866666667f, 0.282352941f, 0.141414141f |
698 | -#define WARM_GREY 0.682352941f, 0.654901961f, 0.623529412f |
699 | -#define COOL_GREY 0.2f, 0.2f, 0.2f |
700 | -#define LIGHT_AUBERGINE 0.466666667f, 0.297297297f, 0.435294118f |
701 | -#define DARK_AUBERGINE 0.17254902f, 0.0f, 0.117647059f |
702 | +//#define MID_AUBERGINE 0.368627451f, 0.152941176f, 0.31372549f |
703 | +//#define ORANGE 0.866666667f, 0.282352941f, 0.141414141f |
704 | +//#define WARM_GREY 0.682352941f, 0.654901961f, 0.623529412f |
705 | +//#define COOL_GREY 0.2f, 0.2f, 0.2f |
706 | +//#define LIGHT_AUBERGINE 0.466666667f, 0.297297297f, 0.435294118f |
707 | +//#define DARK_AUBERGINE 0.17254902f, 0.0f, 0.117647059f |
708 | #define BLACK 0.0f, 0.0f, 0.0f |
709 | -#define WHITE 1.0f, 1.0f, 1.0f |
710 | - |
711 | -cairo_surface_t* pngToSurface (const char* filename) |
712 | -{ |
713 | - // sanity check |
714 | - if (!filename) |
715 | - return NULL; |
716 | - |
717 | - // create surface from PNG |
718 | - cairo_surface_t* surface = NULL; |
719 | - surface = cairo_image_surface_create_from_png (filename); |
720 | - if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) |
721 | - return NULL; |
722 | - |
723 | - return surface; |
724 | -} |
725 | - |
726 | -void uploadTexture (GLuint id, const char* filename) |
727 | -{ |
728 | - if (!id || !filename) |
729 | - return; |
730 | - |
731 | - cairo_surface_t* surface = pngToSurface (filename); |
732 | - |
733 | +//#define WHITE 1.0f, 1.0f, 1.0f |
734 | + |
735 | +template <typename Image> |
736 | +void uploadTexture (GLuint id, Image& image) |
737 | +{ |
738 | glBindTexture(GL_TEXTURE_2D, id); |
739 | |
740 | - if (cairo_surface_status (surface) == CAIRO_STATUS_SUCCESS) |
741 | - { |
742 | - glTexImage2D(GL_TEXTURE_2D, |
743 | - 0, |
744 | - cairo_image_surface_get_format (surface) == CAIRO_FORMAT_ARGB32 ? GL_RGBA : GL_RGB, |
745 | - cairo_image_surface_get_width (surface), |
746 | - cairo_image_surface_get_height (surface), |
747 | - 0, |
748 | - cairo_image_surface_get_format (surface) == CAIRO_FORMAT_ARGB32 ? GL_RGBA : GL_RGB, |
749 | - GL_UNSIGNED_BYTE, |
750 | - cairo_image_surface_get_data (surface)); |
751 | - cairo_surface_destroy (surface); |
752 | - } |
753 | + glTexImage2D(GL_TEXTURE_2D, |
754 | + 0, |
755 | + GL_RGBA, |
756 | + image.width, |
757 | + image.height, |
758 | + 0, |
759 | + GL_RGBA, |
760 | + GL_UNSIGNED_BYTE, |
761 | + image.pixel_data); |
762 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
763 | - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
764 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); |
765 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
766 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
767 | + glGenerateMipmap(GL_TEXTURE_2D); |
768 | glBindTexture(GL_TEXTURE_2D, 0); |
769 | } |
770 | |
771 | @@ -215,145 +205,150 @@ |
772 | typedef struct _AnimationValues |
773 | { |
774 | double lastTimeStamp; |
775 | - double angle; |
776 | - double fadeBackground; |
777 | - double fadeLogo; |
778 | - double fadeGlow; |
779 | + GLfloat fadeBackground; |
780 | + int dot_mask; |
781 | } AnimationValues; |
782 | |
783 | +void ortho(GLfloat* mat, |
784 | + GLfloat left, |
785 | + GLfloat right, |
786 | + GLfloat bottom, |
787 | + GLfloat top, |
788 | + GLfloat near, |
789 | + GLfloat far) |
790 | +{ |
791 | + if (right == left || |
792 | + top == bottom || |
793 | + far == near || |
794 | + mat == NULL) |
795 | + { |
796 | + return; |
797 | + } |
798 | + |
799 | + mat[0] = 2.0f / (right - left); |
800 | + mat[1] = 0.0f; |
801 | + mat[2] = 0.0f; |
802 | + mat[3] = 0.0f; |
803 | + |
804 | + mat[4] = 0.0f; |
805 | + mat[5] = 2.0f / (top - bottom); |
806 | + mat[6] = 0.0f; |
807 | + mat[7] = 0.0f; |
808 | + |
809 | + mat[8] = 0.0f; |
810 | + mat[9] = 0.0f; |
811 | + mat[10] = -2.0f / (far - near); |
812 | + mat[11] = 0.0f; |
813 | + |
814 | + mat[12] = -(right + left) / (right - left); |
815 | + mat[13] = -(top + bottom) / (top - bottom); |
816 | + mat[14] = -(far + near) / (far - near); |
817 | + mat[15] = 1.0f; |
818 | +} |
819 | + |
820 | +GLfloat gu2px(GLfloat gu) { |
821 | + static GLfloat pixelsPerGU = get_gu(); |
822 | + |
823 | + return gu * pixelsPerGU; |
824 | +} |
825 | + |
826 | void |
827 | updateAnimation (GTimer* timer, AnimationValues* anim) |
828 | { |
829 | if (!timer || !anim) |
830 | return; |
831 | |
832 | - //1.) 0.0 - 0.6: logo fades in fully |
833 | - //2.) 0.0 - 6.0: logo does one full spin 360° |
834 | - //3.) 6.0 - 6.833: glow fades in fully, black-background fades out to 50% |
835 | - //4.) 6.833 - 7.666: glow fades out fully, black-background fades out to 0% |
836 | - //5.) 7.666 - 8.266: logo fades out fully |
837 | - //8.266..: now spinner can be closed as all its elements are faded out |
838 | + static const int sequence[] = {0, 1, 3, 7, 15, 31}; |
839 | + static int counter = 0; |
840 | + static double second = 0.0f; |
841 | |
842 | double elapsed = g_timer_elapsed (timer, NULL); |
843 | - double dt = elapsed - anim->lastTimeStamp; |
844 | + |
845 | + if (second >= 1.0f) { |
846 | + second = 0.0f; |
847 | + counter++; |
848 | + } else { |
849 | + second += elapsed - anim->lastTimeStamp; |
850 | + } |
851 | + anim->dot_mask = sequence[counter%6]; |
852 | + |
853 | anim->lastTimeStamp = elapsed; |
854 | - |
855 | - // step 1.) |
856 | - if (elapsed < 0.6f) |
857 | - anim->fadeLogo += 1.6f * dt; |
858 | - |
859 | - // step 2.) |
860 | - anim->angle -= (0.017453292519943f * 360.0f / 6.0f) * dt; |
861 | - |
862 | - // step 3.) glow |
863 | - if (elapsed > 6.0f && elapsed < 6.833f) |
864 | - anim->fadeGlow += 1.2f * dt; |
865 | - |
866 | - // Ignore the following three until we can synchronize with greeter |
867 | - |
868 | - // step 3.) background |
869 | - //if (elapsed > 6.0f && elapsed < 6.833f) |
870 | - // anim->fadeBackground -= 0.6f * dt; |
871 | - |
872 | - // step 4.) background |
873 | - //if (elapsed > 7.0f) |
874 | - // anim->fadeBackground -= 0.6f * dt; |
875 | - |
876 | - // step 5.) |
877 | - //if (elapsed > 6.833f) |
878 | - // anim->fadeLogo -= 1.6f * dt; |
879 | +} |
880 | + |
881 | +namespace |
882 | +{ |
883 | +const char vShaderSrcPlain[] = |
884 | + "attribute vec4 aPosition; \n" |
885 | + "attribute vec2 aTexCoords; \n" |
886 | + "uniform vec2 uOffset; \n" |
887 | + "varying vec2 vTexCoords; \n" |
888 | + "uniform mat4 uProjMat; \n" |
889 | + "void main() \n" |
890 | + "{ \n" |
891 | + " vTexCoords = aTexCoords + vec2 (0.5, 0.5); \n" |
892 | + " gl_Position = uProjMat * vec4(aPosition.xy + uOffset.xy, 0.0, 1.0);\n" |
893 | + "} \n"; |
894 | + |
895 | +const char fShaderSrcPlain[] = |
896 | + "precision mediump float; \n" |
897 | + "varying vec2 vTexCoords; \n" |
898 | + "uniform sampler2D uSampler; \n" |
899 | + "void main() \n" |
900 | + "{ \n" |
901 | + " gl_FragColor = texture2D(uSampler, vTexCoords);\n" |
902 | + "} \n"; |
903 | + |
904 | +static volatile sig_atomic_t running = 0; |
905 | + |
906 | +static void shutdown(int signum) |
907 | +{ |
908 | + if (running) |
909 | + { |
910 | + running = 0; |
911 | + printf("Signal %d received. Good night.\n", signum); |
912 | + } |
913 | +} |
914 | + |
915 | +bool mir_eglapp_running() |
916 | +{ |
917 | + return running; |
918 | +} |
919 | } |
920 | |
921 | int main(int argc, char *argv[]) |
922 | +try |
923 | { |
924 | - const char vShaderSrcSpinner[] = |
925 | - "attribute vec4 vPosition; \n" |
926 | - "attribute vec2 aTexCoords; \n" |
927 | - "uniform float theta; \n" |
928 | - "varying vec2 vTexCoords; \n" |
929 | - "void main() \n" |
930 | - "{ \n" |
931 | - " float c = cos(theta); \n" |
932 | - " float s = sin(theta); \n" |
933 | - " mat2 m; \n" |
934 | - " m[0] = vec2(c, s); \n" |
935 | - " m[1] = vec2(-s, c); \n" |
936 | - " vTexCoords = m * aTexCoords + vec2 (0.5, 0.5); \n" |
937 | - " gl_Position = vec4(vPosition.xy, -1.0, 1.0); \n" |
938 | - "} \n"; |
939 | - |
940 | - const char fShaderSrcGlow[] = |
941 | - "precision mediump float; \n" |
942 | - "varying vec2 vTexCoords; \n" |
943 | - "uniform sampler2D uSampler; \n" |
944 | - "uniform float uFadeGlow; \n" |
945 | - "void main() \n" |
946 | - "{ \n" |
947 | - " // swizzle because texture was created with cairo\n" |
948 | - " vec4 col = texture2D(uSampler, vTexCoords).bgra; \n" |
949 | - " float r = col.r * uFadeGlow; \n" |
950 | - " float g = col.g * uFadeGlow; \n" |
951 | - " float b = col.b * uFadeGlow; \n" |
952 | - " float a = col.a * uFadeGlow; \n" |
953 | - " gl_FragColor = vec4(r, g, b, a); \n" |
954 | - "} \n"; |
955 | - |
956 | - const char fShaderSrcLogo[] = |
957 | - "precision mediump float; \n" |
958 | - "varying vec2 vTexCoords; \n" |
959 | - "uniform sampler2D uSampler; \n" |
960 | - "uniform float uFadeLogo; \n" |
961 | - "void main() \n" |
962 | - "{ \n" |
963 | - " // swizzle because texture was created with cairo\n" |
964 | - " vec4 col = texture2D(uSampler, vTexCoords).bgra; \n" |
965 | - " float r = col.r * uFadeLogo; \n" |
966 | - " float g = col.g * uFadeLogo; \n" |
967 | - " float b = col.b * uFadeLogo; \n" |
968 | - " float a = col.a * uFadeLogo; \n" |
969 | - " gl_FragColor = vec4(r, g, b, a); \n" |
970 | - "} \n"; |
971 | - |
972 | - GLuint prog[2]; |
973 | - GLuint texture[2]; |
974 | - GLint vpos[2]; |
975 | - GLint theta; |
976 | - GLint fadeGlow; |
977 | - GLint fadeLogo; |
978 | - GLint aTexCoords[2]; |
979 | - GLint sampler[2]; |
980 | - unsigned int width = 0; |
981 | - unsigned int height = 0; |
982 | - |
983 | - if (!mir_eglapp_init(argc, argv, &width, &height)) |
984 | - return 1; |
985 | - |
986 | - double pixelSize = (double) get_gu () * 11.18; |
987 | - double halfRealWidth = ((2.0 / (double) width) * pixelSize) / 2.0; |
988 | - double halfRealHeight = ((2.0 / (double) height) * pixelSize) / 2.0; |
989 | - |
990 | - const GLfloat vertices[] = |
991 | - { |
992 | - halfRealWidth, halfRealHeight, |
993 | - halfRealWidth, -halfRealHeight, |
994 | - -halfRealWidth, halfRealHeight, |
995 | - -halfRealWidth, -halfRealHeight, |
996 | - }; |
997 | - |
998 | - const GLfloat texCoordsSpinner[] = |
999 | - { |
1000 | - -0.5f, 0.5f, |
1001 | + GLuint prog[3]; |
1002 | + GLuint texture[MAX_TEXTURES]; |
1003 | + GLint vpos[MAX_TEXTURES]; |
1004 | + GLint aTexCoords[MAX_TEXTURES]; |
1005 | + GLint sampler[MAX_TEXTURES]; |
1006 | + GLint offset[MAX_TEXTURES]; |
1007 | + GLint projMat[MAX_TEXTURES]; |
1008 | + |
1009 | + auto const surfaces = mir_eglapp_init(argc, argv); |
1010 | + |
1011 | + if (!surfaces.size()) |
1012 | + { |
1013 | + printf("No surfaces created\n"); |
1014 | + return EXIT_SUCCESS; |
1015 | + } |
1016 | + |
1017 | + running = 1; |
1018 | + signal(SIGINT, shutdown); |
1019 | + signal(SIGTERM, shutdown); |
1020 | + |
1021 | + const GLfloat texCoords[] = |
1022 | + { |
1023 | + 0.5f, -0.5f, |
1024 | + 0.5f, 0.5f, |
1025 | -0.5f, -0.5f, |
1026 | - 0.5f, 0.5f, |
1027 | - 0.5f, -0.5f, |
1028 | + -0.5f, 0.5f, |
1029 | }; |
1030 | |
1031 | - prog[0] = createShaderProgram (vShaderSrcSpinner, fShaderSrcGlow); |
1032 | - prog[1] = createShaderProgram (vShaderSrcSpinner, fShaderSrcLogo); |
1033 | - |
1034 | - // setup viewport and projection |
1035 | - glClearColor(BLACK, mir_eglapp_background_opacity); |
1036 | - glViewport(0, 0, width, height); |
1037 | + prog[WALLPAPER] = createShaderProgram(vShaderSrcPlain, fShaderSrcPlain); |
1038 | + prog[LOGO] = createShaderProgram(vShaderSrcPlain, fShaderSrcPlain); |
1039 | + prog[WHITE_DOT] = createShaderProgram(vShaderSrcPlain, fShaderSrcPlain); |
1040 | |
1041 | // setup proper GL-blending |
1042 | glEnable(GL_BLEND); |
1043 | @@ -361,66 +356,129 @@ |
1044 | glBlendEquation(GL_FUNC_ADD); |
1045 | |
1046 | // get locations of shader-attributes/uniforms |
1047 | - vpos[0] = glGetAttribLocation(prog[0], "vPosition"); |
1048 | - aTexCoords[0] = glGetAttribLocation(prog[0], "aTexCoords"); |
1049 | - theta = glGetUniformLocation(prog[0], "theta"); |
1050 | - sampler[0] = glGetUniformLocation(prog[0], "uSampler"); |
1051 | - fadeGlow = glGetUniformLocation(prog[0], "uFadeGlow"); |
1052 | - vpos[1] = glGetAttribLocation(prog[1], "vPosition"); |
1053 | - aTexCoords[1] = glGetAttribLocation(prog[1], "aTexCoords"); |
1054 | - sampler[1] = glGetUniformLocation(prog[1], "uSampler"); |
1055 | - fadeLogo = glGetUniformLocation(prog[1], "uFadeLogo"); |
1056 | + vpos[WALLPAPER] = glGetAttribLocation(prog[WALLPAPER], "aPosition"); |
1057 | + aTexCoords[WALLPAPER] = glGetAttribLocation(prog[WALLPAPER], "aTexCoords"); |
1058 | + sampler[WALLPAPER] = glGetUniformLocation(prog[WALLPAPER], "uSampler"); |
1059 | + offset[WALLPAPER] = glGetUniformLocation(prog[WALLPAPER], "uOffset"); |
1060 | + projMat[WALLPAPER] = glGetUniformLocation(prog[WALLPAPER], "uProjMat"); |
1061 | + |
1062 | + vpos[LOGO] = glGetAttribLocation(prog[LOGO], "aPosition"); |
1063 | + aTexCoords[LOGO] = glGetAttribLocation(prog[LOGO], "aTexCoords"); |
1064 | + sampler[LOGO] = glGetUniformLocation(prog[LOGO], "uSampler"); |
1065 | + offset[LOGO] = glGetUniformLocation(prog[LOGO], "uOffset"); |
1066 | + projMat[LOGO] = glGetUniformLocation(prog[LOGO], "uProjMat"); |
1067 | + |
1068 | + vpos[WHITE_DOT] = glGetAttribLocation(prog[WHITE_DOT], "aPosition"); |
1069 | + aTexCoords[WHITE_DOT] = glGetAttribLocation(prog[WHITE_DOT], "aTexCoords"); |
1070 | + sampler[WHITE_DOT] = glGetUniformLocation(prog[WHITE_DOT], "uSampler"); |
1071 | + offset[WHITE_DOT] = glGetUniformLocation(prog[WHITE_DOT], "uOffset"); |
1072 | + projMat[WHITE_DOT] = glGetUniformLocation(prog[WHITE_DOT], "uProjMat"); |
1073 | |
1074 | // create and upload spinner-artwork |
1075 | - glGenTextures(2, texture); |
1076 | - uploadTexture(texture[0], PKGDATADIR "/spinner-glow.png"); |
1077 | - uploadTexture(texture[1], PKGDATADIR "/spinner-logo.png"); |
1078 | + // note that the embedded image data has pre-multiplied alpha |
1079 | + glGenTextures(MAX_TEXTURES, texture); |
1080 | + uploadTexture(texture[WALLPAPER], wallpaper); |
1081 | + uploadTexture(texture[LOGO], logo); |
1082 | + uploadTexture(texture[WHITE_DOT], white_dot); |
1083 | + uploadTexture(texture[ORANGE_DOT], orange_dot); |
1084 | |
1085 | // bunch of shader-attributes to enable |
1086 | - glVertexAttribPointer(vpos[0], 2, GL_FLOAT, GL_FALSE, 0, vertices); |
1087 | - glVertexAttribPointer(vpos[1], 2, GL_FLOAT, GL_FALSE, 0, vertices); |
1088 | - glVertexAttribPointer(aTexCoords[0], 2, GL_FLOAT, GL_FALSE, 0, texCoordsSpinner); |
1089 | - glVertexAttribPointer(aTexCoords[1], 2, GL_FLOAT, GL_FALSE, 0, texCoordsSpinner); |
1090 | - glEnableVertexAttribArray(vpos[0]); |
1091 | - glEnableVertexAttribArray(vpos[1]); |
1092 | - glEnableVertexAttribArray(aTexCoords[0]); |
1093 | - glEnableVertexAttribArray(aTexCoords[1]); |
1094 | + glVertexAttribPointer(aTexCoords[WALLPAPER], 2, GL_FLOAT, GL_FALSE, 0, texCoords); |
1095 | + glEnableVertexAttribArray(vpos[WALLPAPER]); |
1096 | + glEnableVertexAttribArray(aTexCoords[WALLPAPER]); |
1097 | + glVertexAttribPointer(aTexCoords[LOGO], 2, GL_FLOAT, GL_FALSE, 0, texCoords); |
1098 | + glEnableVertexAttribArray(vpos[LOGO]); |
1099 | + glEnableVertexAttribArray(aTexCoords[LOGO]); |
1100 | + glVertexAttribPointer(aTexCoords[WHITE_DOT], 2, GL_FLOAT, GL_FALSE, 0, texCoords); |
1101 | + glEnableVertexAttribArray(vpos[WHITE_DOT]); |
1102 | + glEnableVertexAttribArray(aTexCoords[WHITE_DOT]); |
1103 | glActiveTexture(GL_TEXTURE0); |
1104 | |
1105 | - AnimationValues anim = {0.0, 0.0, 1.0, 0.0, 0.0}; |
1106 | - GTimer* timer = g_timer_new (); |
1107 | + AnimationValues anim = {0.0, 0.0, 0}; |
1108 | + GTimer* timer = g_timer_new(); |
1109 | |
1110 | while (mir_eglapp_running()) |
1111 | { |
1112 | - glClearColor(BLACK, anim.fadeBackground); |
1113 | - glClear(GL_COLOR_BUFFER_BIT); |
1114 | - |
1115 | - // draw glow |
1116 | - glUseProgram(prog[0]); |
1117 | - glBindTexture(GL_TEXTURE_2D, texture[0]); |
1118 | - glUniform1i(sampler[0], 0); |
1119 | - glUniform1f(theta, anim.angle); |
1120 | - glUniform1f(fadeGlow, anim.fadeGlow); |
1121 | - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
1122 | - |
1123 | - // draw logo |
1124 | - glUseProgram(prog[1]); |
1125 | - glBindTexture(GL_TEXTURE_2D, texture[1]); |
1126 | - glUniform1i(sampler[1], 0); |
1127 | - glUniform1f(theta, anim.angle); |
1128 | - glUniform1f(fadeLogo, anim.fadeLogo); |
1129 | - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
1130 | + for (auto const& surface : surfaces) |
1131 | + surface->paint([&](unsigned int width, unsigned int height) |
1132 | + { |
1133 | + GLfloat logoWidth = gu2px (14.5f); |
1134 | + GLfloat logoHeight = gu2px (3.0f); |
1135 | + GLfloat logoXOffset = gu2px (1.0f); |
1136 | + GLfloat dotSize = gu2px (0.5f); |
1137 | + GLfloat dotXGap = gu2px (2.5f); |
1138 | + GLfloat dotYGap = gu2px (2.0f); |
1139 | + |
1140 | + const GLfloat fullscreen[] = { |
1141 | + (GLfloat) width, 0.0f, |
1142 | + (GLfloat) width, (GLfloat) height, |
1143 | + 0.0f, 0.0f, |
1144 | + 0.0f, (GLfloat) height |
1145 | + }; |
1146 | + |
1147 | + const GLfloat logo[] = { |
1148 | + logoWidth, 0.0f, |
1149 | + logoWidth, logoHeight, |
1150 | + 0.0f, 0.0f, |
1151 | + 0.0f, logoHeight |
1152 | + }; |
1153 | + |
1154 | + const GLfloat dot[] = { |
1155 | + dotSize, 0.0f, |
1156 | + dotSize, dotSize, |
1157 | + 0.0f, 0.0f, |
1158 | + 0.0f, dotSize |
1159 | + }; |
1160 | + |
1161 | + GLfloat projMatrix[16]; |
1162 | + ortho(&projMatrix[0], 0.0f, (GLfloat) width, (GLfloat) height, 0.0f, -1.0f, 1.0f); |
1163 | + |
1164 | + glViewport(0, 0, width, height); |
1165 | + |
1166 | + glClearColor(BLACK, anim.fadeBackground); |
1167 | + glClear(GL_COLOR_BUFFER_BIT); |
1168 | + |
1169 | + // draw wallpaper backdrop |
1170 | + glVertexAttribPointer(vpos[WALLPAPER], 2, GL_FLOAT, GL_FALSE, 0, fullscreen); |
1171 | + glUseProgram(prog[WALLPAPER]); |
1172 | + glBindTexture(GL_TEXTURE_2D, texture[WALLPAPER]); |
1173 | + glUniform1i(sampler[WALLPAPER], 0); |
1174 | + glUniform2f(offset[WALLPAPER], 0.0f, 0.0f); |
1175 | + glUniformMatrix4fv(projMat[WALLPAPER], 1, GL_FALSE, projMatrix); |
1176 | + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
1177 | + |
1178 | + // draw logo |
1179 | + glVertexAttribPointer(vpos[LOGO], 2, GL_FLOAT, GL_FALSE, 0, logo); |
1180 | + glUseProgram(prog[LOGO]); |
1181 | + glBindTexture(GL_TEXTURE_2D, texture[LOGO]); |
1182 | + glUniform1i(sampler[LOGO], 0); |
1183 | + glUniform2f(offset[LOGO], width/2.0f - logoWidth / 2.0f + logoXOffset, height / 2.0f - logoHeight * 0.75f); |
1184 | + glUniformMatrix4fv(projMat[LOGO], 1, GL_FALSE, projMatrix); |
1185 | + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
1186 | + |
1187 | + // draw white/orange dots |
1188 | + glVertexAttribPointer(vpos[WHITE_DOT], 2, GL_FLOAT, GL_FALSE, 0, dot); |
1189 | + glUseProgram(prog[WHITE_DOT]); |
1190 | + glUniform1i(sampler[WHITE_DOT], 0); |
1191 | + glUniformMatrix4fv(projMat[WHITE_DOT], 1, GL_FALSE, projMatrix); |
1192 | + for (int i = -2; i < 3; i++) { |
1193 | + glBindTexture(GL_TEXTURE_2D, texture[anim.dot_mask >> (i + 2) ? ORANGE_DOT : WHITE_DOT]); |
1194 | + glUniform2f(offset[WHITE_DOT], width/2.0f + i * dotXGap, height / 2.0f + logoHeight / 2.0f + dotYGap - logoHeight * 0.25f); |
1195 | + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
1196 | + } |
1197 | + }); |
1198 | |
1199 | // update animation variable |
1200 | - updateAnimation (timer, &anim); |
1201 | - |
1202 | - mir_eglapp_swap_buffers(); |
1203 | + updateAnimation(timer, &anim); |
1204 | } |
1205 | |
1206 | - mir_eglapp_shutdown(); |
1207 | - |
1208 | - glDeleteTextures(2, texture); |
1209 | + glDeleteTextures(MAX_TEXTURES, texture); |
1210 | g_timer_destroy (timer); |
1211 | |
1212 | - return 0; |
1213 | + return EXIT_SUCCESS; |
1214 | +} |
1215 | +catch (std::exception const& x) |
1216 | +{ |
1217 | + printf("%s\n", x.what()); |
1218 | + return EXIT_FAILURE; |
1219 | } |
1220 | |
1221 | === added file 'spinner/logo.png' |
1222 | Binary files spinner/logo.png 1970-01-01 00:00:00 +0000 and spinner/logo.png 2015-07-20 10:34:37 +0000 differ |
1223 | === added file 'spinner/miregl.cpp' |
1224 | --- spinner/miregl.cpp 1970-01-01 00:00:00 +0000 |
1225 | +++ spinner/miregl.cpp 2015-07-20 10:34:37 +0000 |
1226 | @@ -0,0 +1,247 @@ |
1227 | +/* |
1228 | + * Copyright © 2015 Canonical Ltd. |
1229 | + * |
1230 | + * This program is free software: you can redistribute it and/or modify |
1231 | + * it under the terms of the GNU General Public License version 3 as |
1232 | + * published by the Free Software Foundation. |
1233 | + * |
1234 | + * This program is distributed in the hope that it will be useful, |
1235 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1236 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1237 | + * GNU General Public License for more details. |
1238 | + * |
1239 | + * You should have received a copy of the GNU General Public License |
1240 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1241 | + */ |
1242 | + |
1243 | +#include "miregl.h" |
1244 | + |
1245 | +#include <cstring> |
1246 | + |
1247 | +#include <GLES2/gl2.h> |
1248 | + |
1249 | +class MirEglApp |
1250 | +{ |
1251 | +public: |
1252 | + MirEglApp(MirConnection* const connection, MirPixelFormat pixel_format); |
1253 | + |
1254 | + EGLSurface create_surface(MirSurface* surface); |
1255 | + |
1256 | + void release_current(); |
1257 | + |
1258 | + void make_current(EGLSurface eglsurface) const; |
1259 | + |
1260 | + void swap_buffers(EGLSurface eglsurface) const; |
1261 | + |
1262 | + void destroy_surface(EGLSurface eglsurface) const; |
1263 | + |
1264 | + void get_surface_size(EGLSurface eglsurface, int* width, int* height) const; |
1265 | + |
1266 | + void set_swap_interval(EGLSurface eglsurface, int interval) const; |
1267 | + |
1268 | + bool supports_surfaceless_context(); |
1269 | + |
1270 | + ~MirEglApp(); |
1271 | + |
1272 | + MirConnection* const connection; |
1273 | +private: |
1274 | + EGLDisplay egldisplay; |
1275 | + EGLContext eglctx; |
1276 | + EGLConfig eglconfig; |
1277 | + EGLint neglconfigs; |
1278 | + EGLSurface dummy_surface; |
1279 | +}; |
1280 | + |
1281 | +std::shared_ptr<MirEglApp> make_mir_eglapp( |
1282 | + MirConnection* const connection, MirPixelFormat const& pixel_format) |
1283 | +{ |
1284 | + return std::make_shared<MirEglApp>(connection, pixel_format); |
1285 | +} |
1286 | + |
1287 | +namespace |
1288 | +{ |
1289 | +MirSurface* create_surface(MirConnection* const connection, MirSurfaceParameters const& surfaceparm) |
1290 | +{ |
1291 | + auto const spec = mir_connection_create_spec_for_normal_surface( |
1292 | + connection, |
1293 | + surfaceparm.width, |
1294 | + surfaceparm.height, |
1295 | + surfaceparm.pixel_format); |
1296 | + |
1297 | + mir_surface_spec_set_name(spec, surfaceparm.name); |
1298 | + mir_surface_spec_set_buffer_usage(spec, surfaceparm.buffer_usage); |
1299 | + mir_surface_spec_set_fullscreen_on_output(spec, surfaceparm.output_id); |
1300 | + |
1301 | + auto const surface = mir_surface_create_sync(spec); |
1302 | + mir_surface_spec_release(spec); |
1303 | + |
1304 | + if (!mir_surface_is_valid(surface)) |
1305 | + throw std::runtime_error(std::string("Can't create a surface ") + mir_surface_get_error_message(surface)); |
1306 | + |
1307 | + if (surfaceparm.output_id != mir_display_output_id_invalid) |
1308 | + mir_surface_set_state(surface, mir_surface_state_fullscreen); |
1309 | + |
1310 | + return surface; |
1311 | +} |
1312 | +} |
1313 | + |
1314 | +MirEglSurface::MirEglSurface(std::shared_ptr<MirEglApp> const& mir_egl_app, MirSurfaceParameters const& surfaceparm, int swapinterval) : |
1315 | + mir_egl_app{mir_egl_app}, |
1316 | + surface{create_surface(mir_egl_app->connection, surfaceparm)}, |
1317 | + eglsurface{mir_egl_app->create_surface(surface)}, |
1318 | + width_{0}, |
1319 | + height_{0} |
1320 | +{ |
1321 | + mir_egl_app->set_swap_interval(eglsurface, swapinterval); |
1322 | +} |
1323 | + |
1324 | +MirEglSurface::~MirEglSurface() |
1325 | +{ |
1326 | + mir_egl_app->destroy_surface(eglsurface); |
1327 | + mir_surface_release_sync(surface); |
1328 | +} |
1329 | + |
1330 | +void MirEglSurface::egl_make_current() |
1331 | +{ |
1332 | + mir_egl_app->get_surface_size(eglsurface, &width_, &height_); |
1333 | + mir_egl_app->make_current(eglsurface); |
1334 | +} |
1335 | + |
1336 | +void MirEglSurface::swap_buffers() |
1337 | +{ |
1338 | + mir_egl_app->swap_buffers(eglsurface); |
1339 | +} |
1340 | + |
1341 | +unsigned int MirEglSurface::width() const |
1342 | +{ |
1343 | + return width_; |
1344 | +} |
1345 | + |
1346 | +unsigned int MirEglSurface::height() const |
1347 | +{ |
1348 | + return height_; |
1349 | +} |
1350 | + |
1351 | +MirEglApp::MirEglApp(MirConnection* const connection, MirPixelFormat pixel_format) : |
1352 | + connection{connection}, |
1353 | + dummy_surface{EGL_NO_SURFACE} |
1354 | +{ |
1355 | + unsigned int bpp = 8*MIR_BYTES_PER_PIXEL(pixel_format); |
1356 | + |
1357 | + EGLint attribs[] = |
1358 | + { |
1359 | + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, |
1360 | + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, |
1361 | + EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER, |
1362 | + EGL_BUFFER_SIZE, (EGLint) bpp, |
1363 | + EGL_NONE |
1364 | + }; |
1365 | + |
1366 | + egldisplay = eglGetDisplay((EGLNativeDisplayType) mir_connection_get_egl_native_display(connection)); |
1367 | + if (egldisplay == EGL_NO_DISPLAY) |
1368 | + throw std::runtime_error("Can't eglGetDisplay"); |
1369 | + |
1370 | + EGLint major; |
1371 | + EGLint minor; |
1372 | + if (!eglInitialize(egldisplay, &major, &minor)) |
1373 | + throw std::runtime_error("Can't eglInitialize"); |
1374 | + |
1375 | + if (major != 1 || minor != 4) |
1376 | + throw std::runtime_error("EGL version is not 1.4"); |
1377 | + |
1378 | + if (!eglChooseConfig(egldisplay, attribs, &eglconfig, 1, &neglconfigs)) |
1379 | + throw std::runtime_error("Could not eglChooseConfig"); |
1380 | + |
1381 | + if (neglconfigs == 0) |
1382 | + throw std::runtime_error("No EGL config available"); |
1383 | + |
1384 | + EGLint ctxattribs[] = |
1385 | + { |
1386 | + EGL_CONTEXT_CLIENT_VERSION, 2, |
1387 | + EGL_NONE |
1388 | + }; |
1389 | + |
1390 | + eglctx = eglCreateContext(egldisplay, eglconfig, EGL_NO_CONTEXT, ctxattribs); |
1391 | + if (eglctx == EGL_NO_CONTEXT) |
1392 | + throw std::runtime_error("eglCreateContext failed"); |
1393 | + |
1394 | + if (!supports_surfaceless_context()) |
1395 | + { |
1396 | + static EGLint const dummy_pbuffer_attribs[] = |
1397 | + { |
1398 | + EGL_WIDTH, 1, |
1399 | + EGL_HEIGHT, 1, |
1400 | + EGL_NONE |
1401 | + }; |
1402 | + |
1403 | + dummy_surface = eglCreatePbufferSurface(egldisplay, eglconfig, dummy_pbuffer_attribs); |
1404 | + if (dummy_surface == EGL_NO_SURFACE) |
1405 | + throw std::runtime_error("eglCreatePbufferSurface failed"); |
1406 | + } |
1407 | + |
1408 | + make_current(dummy_surface); |
1409 | +} |
1410 | + |
1411 | +EGLSurface MirEglApp::create_surface(MirSurface* surface) |
1412 | +{ |
1413 | + auto const eglsurface = eglCreateWindowSurface( |
1414 | + egldisplay, |
1415 | + eglconfig, |
1416 | + (EGLNativeWindowType) mir_buffer_stream_get_egl_native_window(mir_surface_get_buffer_stream(surface)), NULL); |
1417 | + |
1418 | + if (eglsurface == EGL_NO_SURFACE) |
1419 | + throw std::runtime_error("eglCreateWindowSurface failed"); |
1420 | + |
1421 | + return eglsurface; |
1422 | +} |
1423 | + |
1424 | +void MirEglApp::make_current(EGLSurface eglsurface) const |
1425 | +{ |
1426 | + if (!eglMakeCurrent(egldisplay, eglsurface, eglsurface, eglctx)) |
1427 | + throw std::runtime_error("Can't eglMakeCurrent"); |
1428 | +} |
1429 | + |
1430 | +void MirEglApp::swap_buffers(EGLSurface eglsurface) const |
1431 | +{ |
1432 | + eglSwapBuffers(egldisplay, eglsurface); |
1433 | +} |
1434 | + |
1435 | +void MirEglApp::destroy_surface(EGLSurface eglsurface) const |
1436 | +{ |
1437 | + eglDestroySurface(egldisplay, eglsurface); |
1438 | +} |
1439 | + |
1440 | +void MirEglApp::get_surface_size(EGLSurface eglsurface, int* width, int* height) const |
1441 | +{ |
1442 | + eglQuerySurface(egldisplay, eglsurface, EGL_WIDTH, width); |
1443 | + eglQuerySurface(egldisplay, eglsurface, EGL_HEIGHT, height); |
1444 | +} |
1445 | + |
1446 | +void MirEglApp::set_swap_interval(EGLSurface eglsurface, int interval) const |
1447 | +{ |
1448 | + auto const previous_surface = eglGetCurrentSurface(EGL_DRAW); |
1449 | + |
1450 | + make_current(eglsurface); |
1451 | + eglSwapInterval(egldisplay, interval); |
1452 | + |
1453 | + if (previous_surface != EGL_NO_SURFACE) |
1454 | + make_current(previous_surface); |
1455 | +} |
1456 | + |
1457 | +bool MirEglApp::supports_surfaceless_context() |
1458 | +{ |
1459 | + auto const extensions = eglQueryString(egldisplay, EGL_EXTENSIONS); |
1460 | + if (!extensions) |
1461 | + return false; |
1462 | + return std::strstr(extensions, "EGL_KHR_surfaceless_context") != nullptr; |
1463 | +} |
1464 | + |
1465 | +MirEglApp::~MirEglApp() |
1466 | +{ |
1467 | + eglMakeCurrent(egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); |
1468 | + if (dummy_surface != EGL_NO_SURFACE) |
1469 | + destroy_surface(dummy_surface); |
1470 | + eglDestroyContext(egldisplay, eglctx); |
1471 | + eglTerminate(egldisplay); |
1472 | + mir_connection_release(connection); |
1473 | +} |
1474 | |
1475 | === added file 'spinner/miregl.h' |
1476 | --- spinner/miregl.h 1970-01-01 00:00:00 +0000 |
1477 | +++ spinner/miregl.h 2015-07-20 10:34:37 +0000 |
1478 | @@ -0,0 +1,67 @@ |
1479 | +/* |
1480 | + * Copyright © 2015 Canonical Ltd. |
1481 | + * |
1482 | + * This program is free software: you can redistribute it and/or modify |
1483 | + * it under the terms of the GNU General Public License version 3 as |
1484 | + * published by the Free Software Foundation. |
1485 | + * |
1486 | + * This program is distributed in the hope that it will be useful, |
1487 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1488 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1489 | + * GNU General Public License for more details. |
1490 | + * |
1491 | + * You should have received a copy of the GNU General Public License |
1492 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1493 | + */ |
1494 | + |
1495 | +#ifndef UNITYSYSTEMCOMPOSITOR_MIREGL_H |
1496 | +#define UNITYSYSTEMCOMPOSITOR_MIREGL_H |
1497 | + |
1498 | +#include <mir_toolkit/common.h> |
1499 | +#include <mir_toolkit/client_types.h> |
1500 | +#include "mir_toolkit/mir_client_library.h" |
1501 | + |
1502 | +#include <EGL/egl.h> |
1503 | + |
1504 | +#include <memory> |
1505 | + |
1506 | +class MirEglApp; |
1507 | +class MirEglSurface; |
1508 | + |
1509 | +std::shared_ptr<MirEglApp> make_mir_eglapp( |
1510 | + MirConnection* const connection, |
1511 | + MirPixelFormat const& pixel_format); |
1512 | + |
1513 | +class MirEglSurface |
1514 | +{ |
1515 | +public: |
1516 | + MirEglSurface( |
1517 | + std::shared_ptr<MirEglApp> const& mir_egl_app, |
1518 | + MirSurfaceParameters const& surfaceparm, |
1519 | + int swapinterval); |
1520 | + |
1521 | + ~MirEglSurface(); |
1522 | + |
1523 | + template<typename Painter> |
1524 | + void paint(Painter const& functor) |
1525 | + { |
1526 | + egl_make_current(); |
1527 | + functor(width(), height()); |
1528 | + swap_buffers(); |
1529 | + } |
1530 | + |
1531 | +private: |
1532 | + void egl_make_current(); |
1533 | + |
1534 | + void swap_buffers(); |
1535 | + unsigned int width() const; |
1536 | + unsigned int height() const; |
1537 | + |
1538 | + std::shared_ptr<MirEglApp> const mir_egl_app; |
1539 | + MirSurface* const surface; |
1540 | + EGLSurface const eglsurface; |
1541 | + int width_; |
1542 | + int height_; |
1543 | +}; |
1544 | + |
1545 | +#endif //UNITYSYSTEMCOMPOSITOR_MIREGL_H |
1546 | |
1547 | === added file 'spinner/orange-dot.png' |
1548 | Binary files spinner/orange-dot.png 1970-01-01 00:00:00 +0000 and spinner/orange-dot.png 2015-07-20 10:34:37 +0000 differ |
1549 | === removed file 'spinner/spinner-glow.png' |
1550 | Binary files spinner/spinner-glow.png 2014-04-02 18:27:53 +0000 and spinner/spinner-glow.png 1970-01-01 00:00:00 +0000 differ |
1551 | === removed file 'spinner/spinner-logo.png' |
1552 | Binary files spinner/spinner-logo.png 2014-04-02 18:27:53 +0000 and spinner/spinner-logo.png 1970-01-01 00:00:00 +0000 differ |
1553 | === added file 'spinner/wallpaper.png' |
1554 | Binary files spinner/wallpaper.png 1970-01-01 00:00:00 +0000 and spinner/wallpaper.png 2015-07-20 10:34:37 +0000 differ |
1555 | === added file 'spinner/white-dot.png' |
1556 | Binary files spinner/white-dot.png 1970-01-01 00:00:00 +0000 and spinner/white-dot.png 2015-07-20 10:34:37 +0000 differ |
1557 | === modified file 'src/external_spinner.cpp' |
1558 | --- src/external_spinner.cpp 2015-04-01 17:06:16 +0000 |
1559 | +++ src/external_spinner.cpp 2015-07-20 10:34:37 +0000 |
1560 | @@ -20,6 +20,18 @@ |
1561 | |
1562 | #include <unistd.h> |
1563 | #include <signal.h> |
1564 | +#include <sys/wait.h> |
1565 | + |
1566 | +namespace |
1567 | +{ |
1568 | + |
1569 | +void wait_for_child(int) |
1570 | +{ |
1571 | + while (waitpid(-1, nullptr, WNOHANG) > 0) |
1572 | + continue; |
1573 | +} |
1574 | + |
1575 | +} |
1576 | |
1577 | usc::ExternalSpinner::ExternalSpinner( |
1578 | std::string const& executable, |
1579 | @@ -28,6 +40,11 @@ |
1580 | mir_socket{mir_socket}, |
1581 | spinner_pid{0} |
1582 | { |
1583 | + struct sigaction sa; |
1584 | + sigfillset(&sa.sa_mask); |
1585 | + sa.sa_handler = wait_for_child; |
1586 | + sa.sa_flags = 0; |
1587 | + sigaction(SIGCHLD, &sa, nullptr); |
1588 | } |
1589 | |
1590 | usc::ExternalSpinner::~ExternalSpinner() |
1591 | |
1592 | === modified file 'src/mir_screen.cpp' |
1593 | --- src/mir_screen.cpp 2015-03-16 10:24:45 +0000 |
1594 | +++ src/mir_screen.cpp 2015-07-20 10:34:37 +0000 |
1595 | @@ -79,13 +79,10 @@ |
1596 | enable_inactivity_timers_l(enable); |
1597 | } |
1598 | |
1599 | -void usc::MirScreen::toggle_screen_power_mode(PowerStateChangeReason reason) |
1600 | +MirPowerMode usc::MirScreen::get_screen_power_mode() |
1601 | { |
1602 | std::lock_guard<std::mutex> lock{guard}; |
1603 | - MirPowerMode new_mode = (current_power_mode == MirPowerMode::mir_power_mode_on) ? |
1604 | - MirPowerMode::mir_power_mode_off : MirPowerMode::mir_power_mode_on; |
1605 | - |
1606 | - set_screen_power_mode_l(new_mode, reason); |
1607 | + return current_power_mode; |
1608 | } |
1609 | |
1610 | void usc::MirScreen::set_screen_power_mode(MirPowerMode mode, PowerStateChangeReason reason) |
1611 | |
1612 | === modified file 'src/mir_screen.h' |
1613 | --- src/mir_screen.h 2015-03-16 10:24:45 +0000 |
1614 | +++ src/mir_screen.h 2015-07-20 10:34:37 +0000 |
1615 | @@ -51,9 +51,9 @@ |
1616 | ~MirScreen(); |
1617 | |
1618 | void enable_inactivity_timers(bool enable) override; |
1619 | - void toggle_screen_power_mode(PowerStateChangeReason reason) override; |
1620 | void keep_display_on_temporarily() override; |
1621 | |
1622 | + MirPowerMode get_screen_power_mode() override; |
1623 | void set_screen_power_mode(MirPowerMode mode, PowerStateChangeReason reason) override; |
1624 | void keep_display_on(bool on) override; |
1625 | void set_brightness(int brightness) override; |
1626 | |
1627 | === modified file 'src/screen.h' |
1628 | --- src/screen.h 2015-02-18 14:40:29 +0000 |
1629 | +++ src/screen.h 2015-07-20 10:34:37 +0000 |
1630 | @@ -33,9 +33,9 @@ |
1631 | virtual ~Screen() = default; |
1632 | |
1633 | virtual void enable_inactivity_timers(bool enable) = 0; |
1634 | - virtual void toggle_screen_power_mode(PowerStateChangeReason reason) = 0; |
1635 | virtual void keep_display_on_temporarily() = 0; |
1636 | |
1637 | + virtual MirPowerMode get_screen_power_mode() = 0; |
1638 | virtual void set_screen_power_mode(MirPowerMode mode, PowerStateChangeReason reason) = 0; |
1639 | virtual void keep_display_on(bool on) = 0; |
1640 | virtual void set_brightness(int brightness) = 0; |
1641 | |
1642 | === modified file 'src/screen_event_handler.cpp' |
1643 | --- src/screen_event_handler.cpp 2015-04-07 13:36:48 +0000 |
1644 | +++ src/screen_event_handler.cpp 2015-07-20 10:34:37 +0000 |
1645 | @@ -35,6 +35,7 @@ |
1646 | shutdown_timeout{shutdown_timeout}, |
1647 | shutdown{shutdown}, |
1648 | long_press_detected{false}, |
1649 | + mode_at_press_start{MirPowerMode::mir_power_mode_off}, |
1650 | shutdown_alarm{alarm_factory->create_alarm([this]{ shutdown_alarm_notification(); })}, |
1651 | long_press_alarm{alarm_factory->create_alarm([this]{ long_press_notification(); })} |
1652 | { |
1653 | @@ -77,6 +78,14 @@ |
1654 | void usc::ScreenEventHandler::power_key_down() |
1655 | { |
1656 | std::lock_guard<std::mutex> lock{guard}; |
1657 | + |
1658 | + mode_at_press_start = screen->get_screen_power_mode(); |
1659 | + if (mode_at_press_start != MirPowerMode::mir_power_mode_on) |
1660 | + { |
1661 | + screen->set_screen_power_mode( |
1662 | + MirPowerMode::mir_power_mode_on, PowerStateChangeReason::power_key); |
1663 | + } |
1664 | + |
1665 | screen->enable_inactivity_timers(false); |
1666 | long_press_detected = false; |
1667 | long_press_alarm->reschedule_in(power_key_ignore_timeout); |
1668 | @@ -88,9 +97,18 @@ |
1669 | std::lock_guard<std::mutex> lock{guard}; |
1670 | shutdown_alarm->cancel(); |
1671 | long_press_alarm->cancel(); |
1672 | + |
1673 | if (!long_press_detected) |
1674 | { |
1675 | - screen->toggle_screen_power_mode(PowerStateChangeReason::power_key); |
1676 | + if (mode_at_press_start == MirPowerMode::mir_power_mode_on) |
1677 | + { |
1678 | + screen->set_screen_power_mode( |
1679 | + MirPowerMode::mir_power_mode_off, PowerStateChangeReason::power_key); |
1680 | + } |
1681 | + else |
1682 | + { |
1683 | + screen->enable_inactivity_timers(true); |
1684 | + } |
1685 | } |
1686 | } |
1687 | |
1688 | @@ -103,6 +121,9 @@ |
1689 | |
1690 | void usc::ScreenEventHandler::long_press_notification() |
1691 | { |
1692 | + // We know the screen is already on after power_key_down(), but we turn the |
1693 | + // screen on here to ensure that it is also at full brightness for the |
1694 | + // presumed system power dialog that will appear. |
1695 | screen->set_screen_power_mode( |
1696 | MirPowerMode::mir_power_mode_on, PowerStateChangeReason::power_key); |
1697 | long_press_detected = true; |
1698 | |
1699 | === modified file 'src/screen_event_handler.h' |
1700 | --- src/screen_event_handler.h 2015-04-07 13:36:48 +0000 |
1701 | +++ src/screen_event_handler.h 2015-07-20 10:34:37 +0000 |
1702 | @@ -65,6 +65,7 @@ |
1703 | std::function<void()> const shutdown; |
1704 | |
1705 | std::atomic<bool> long_press_detected; |
1706 | + std::atomic<MirPowerMode> mode_at_press_start; |
1707 | std::unique_ptr<mir::time::Alarm> shutdown_alarm; |
1708 | std::unique_ptr<mir::time::Alarm> long_press_alarm; |
1709 | }; |
1710 | |
1711 | === modified file 'src/server.cpp' |
1712 | --- src/server.cpp 2015-04-07 13:36:48 +0000 |
1713 | +++ src/server.cpp 2015-07-20 10:34:37 +0000 |
1714 | @@ -30,6 +30,7 @@ |
1715 | #include <mir/server_status_listener.h> |
1716 | #include <mir/shell/focus_controller.h> |
1717 | #include <mir/scene/session.h> |
1718 | +#include <mir/abnormal_exit.h> |
1719 | #include <mir/main_loop.h> |
1720 | |
1721 | #include <iostream> |
1722 | @@ -92,12 +93,20 @@ |
1723 | |
1724 | std::shared_ptr<msh::FocusController> const focus_controller; |
1725 | }; |
1726 | +const char* const dm_from_fd = "from-dm-fd"; |
1727 | +const char* const dm_to_fd = "to-dm-fd"; |
1728 | +const char* const dm_stub = "debug-without-dm"; |
1729 | +const char* const dm_stub_active = "debug-active-session-name"; |
1730 | } |
1731 | |
1732 | usc::Server::Server(int argc, char** argv) |
1733 | { |
1734 | - add_configuration_option("from-dm-fd", "File descriptor of read end of pipe from display manager [int]", mir::OptionType::integer); |
1735 | - add_configuration_option("to-dm-fd", "File descriptor of write end of pipe to display manager [int]", mir::OptionType::integer); |
1736 | + add_configuration_option(dm_from_fd, "File descriptor of read end of pipe from display manager [int]", |
1737 | + mir::OptionType::integer); |
1738 | + add_configuration_option(dm_to_fd, "File descriptor of write end of pipe to display manager [int]", |
1739 | + mir::OptionType::integer); |
1740 | + add_configuration_option(dm_stub, "Run without a display manager (only useful when debugging)", mir::OptionType::null); |
1741 | + add_configuration_option(dm_stub_active, "Expected connection when run without a display manager (only useful when debugging)", "nested-mir@:/run/user/1000/mir_socket"); |
1742 | add_configuration_option("blacklist", "Video blacklist regex to use", mir::OptionType::string); |
1743 | add_configuration_option("version", "Show version of Unity System Compositor", mir::OptionType::null); |
1744 | add_configuration_option("spinner", "Path to spinner executable", mir::OptionType::string); |
1745 | @@ -171,15 +180,49 @@ |
1746 | return the_session_switcher(); |
1747 | } |
1748 | |
1749 | +namespace |
1750 | +{ |
1751 | +struct NullDMMessageHandler : usc::DMConnection |
1752 | +{ |
1753 | + explicit NullDMMessageHandler( |
1754 | + std::shared_ptr<usc::DMMessageHandler> const& dm_message_handler, |
1755 | + std::string const& client_name) : |
1756 | + dm_message_handler{dm_message_handler}, |
1757 | + client_name{client_name} |
1758 | + {} |
1759 | + |
1760 | + ~NullDMMessageHandler() = default; |
1761 | + |
1762 | + void start() override |
1763 | + { |
1764 | + dm_message_handler->set_active_session(client_name); |
1765 | + }; |
1766 | + |
1767 | + std::shared_ptr<usc::DMMessageHandler> const dm_message_handler; |
1768 | + std::string const client_name; |
1769 | +}; |
1770 | +} |
1771 | + |
1772 | std::shared_ptr<usc::DMConnection> usc::Server::the_dm_connection() |
1773 | { |
1774 | return dm_connection( |
1775 | - [this] |
1776 | + [this]() -> std::shared_ptr<usc::DMConnection> |
1777 | { |
1778 | - return std::make_shared<AsioDMConnection>( |
1779 | - the_options()->get("from-dm-fd", -1), |
1780 | - the_options()->get("to-dm-fd", -1), |
1781 | - the_dm_message_handler()); |
1782 | + if (the_options()->is_set(dm_from_fd) && the_options()->is_set(dm_to_fd)) |
1783 | + { |
1784 | + return std::make_shared<AsioDMConnection>( |
1785 | + the_options()->get(dm_from_fd, -1), |
1786 | + the_options()->get(dm_to_fd, -1), |
1787 | + the_dm_message_handler()); |
1788 | + } |
1789 | + else if (the_options()->is_set(dm_stub)) |
1790 | + { |
1791 | + return std::make_shared<NullDMMessageHandler>( |
1792 | + the_dm_message_handler(), |
1793 | + the_options()->get<std::string>(dm_stub_active)); |
1794 | + } |
1795 | + |
1796 | + BOOST_THROW_EXCEPTION(mir::AbnormalExit("to and from FDs are required for display manager")); |
1797 | }); |
1798 | } |
1799 | |
1800 | |
1801 | === added file 'src/session_monitor.h' |
1802 | --- src/session_monitor.h 1970-01-01 00:00:00 +0000 |
1803 | +++ src/session_monitor.h 2015-07-20 10:34:37 +0000 |
1804 | @@ -0,0 +1,63 @@ |
1805 | +/* |
1806 | + * Copyright © 2015 Canonical Ltd. |
1807 | + * |
1808 | + * This program is free software: you can redistribute it and/or modify |
1809 | + * it under the terms of the GNU General Public License version 3 as |
1810 | + * published by the Free Software Foundation. |
1811 | + * |
1812 | + * This program is distributed in the hope that it will be useful, |
1813 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1814 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1815 | + * GNU General Public License for more details. |
1816 | + * |
1817 | + * You should have received a copy of the GNU General Public License |
1818 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1819 | + * |
1820 | + * Authored by: Alan Griffiths <alan.griffiths@canonical.com> |
1821 | + */ |
1822 | + |
1823 | +#ifndef USC_SESSION_MONITOR_H |
1824 | +#define USC_SESSION_MONITOR_H |
1825 | + |
1826 | +#include <sys/types.h> |
1827 | + |
1828 | +#include <memory> |
1829 | +#include <string> |
1830 | + |
1831 | +namespace mir { namespace frontend { class Session; }}; |
1832 | + |
1833 | +namespace usc |
1834 | +{ |
1835 | +class Session |
1836 | +{ |
1837 | +public: |
1838 | + virtual ~Session() = default; |
1839 | + |
1840 | + virtual std::string name() = 0; |
1841 | + virtual void show() = 0; |
1842 | + virtual void hide() = 0; |
1843 | + virtual void raise_and_focus() = 0; |
1844 | + virtual bool corresponds_to(mir::frontend::Session const*) = 0; |
1845 | + |
1846 | +protected: |
1847 | + Session() = default; |
1848 | + Session(Session const&) = delete; |
1849 | + Session& operator=(Session const&) = delete; |
1850 | +}; |
1851 | + |
1852 | +class SessionMonitor |
1853 | +{ |
1854 | +public: |
1855 | + virtual void add(std::shared_ptr<Session> const& session, pid_t pid) = 0; |
1856 | + virtual void remove(std::shared_ptr<mir::frontend::Session> const& session) = 0; |
1857 | + virtual void mark_ready(mir::frontend::Session const* session) = 0; |
1858 | + |
1859 | +protected: |
1860 | + SessionMonitor() = default; |
1861 | + SessionMonitor(SessionMonitor const&) = delete; |
1862 | + SessionMonitor& operator=(SessionMonitor const&) = delete; |
1863 | + virtual ~SessionMonitor() = default; |
1864 | +}; |
1865 | +} |
1866 | + |
1867 | +#endif //USC_SESSION_MONITOR_H |
1868 | |
1869 | === modified file 'src/session_switcher.h' |
1870 | --- src/session_switcher.h 2014-10-22 19:31:57 +0000 |
1871 | +++ src/session_switcher.h 2015-07-20 10:34:37 +0000 |
1872 | @@ -20,41 +20,24 @@ |
1873 | #define USC_SESSION_SWITCHER_H_ |
1874 | |
1875 | #include "dm_connection.h" |
1876 | +#include "session_monitor.h" |
1877 | |
1878 | #include <map> |
1879 | -#include <memory> |
1880 | #include <mutex> |
1881 | |
1882 | -namespace mir { namespace frontend { class Session; }}; |
1883 | namespace usc |
1884 | { |
1885 | class Spinner; |
1886 | |
1887 | -class Session |
1888 | -{ |
1889 | -public: |
1890 | - virtual ~Session() = default; |
1891 | - |
1892 | - virtual std::string name() = 0; |
1893 | - virtual void show() = 0; |
1894 | - virtual void hide() = 0; |
1895 | - virtual void raise_and_focus() = 0; |
1896 | - virtual bool corresponds_to(mir::frontend::Session const*) = 0; |
1897 | - |
1898 | -protected: |
1899 | - Session() = default; |
1900 | - Session(Session const&) = delete; |
1901 | - Session& operator=(Session const&) = delete; |
1902 | -}; |
1903 | - |
1904 | -class SessionSwitcher : public DMMessageHandler |
1905 | +class SessionSwitcher : public DMMessageHandler, public SessionMonitor |
1906 | { |
1907 | public: |
1908 | explicit SessionSwitcher(std::shared_ptr<Spinner> const& spinner); |
1909 | |
1910 | - void add(std::shared_ptr<Session> const& session, pid_t pid); |
1911 | - void remove(std::shared_ptr<mir::frontend::Session> const& session); |
1912 | - void mark_ready(mir::frontend::Session const* session); |
1913 | + /* From SessionMonitor */ |
1914 | + void add(std::shared_ptr<Session> const& session, pid_t pid) override; |
1915 | + void remove(std::shared_ptr<mir::frontend::Session> const& session) override; |
1916 | + void mark_ready(mir::frontend::Session const* session) override; |
1917 | |
1918 | /* From DMMessageHandler */ |
1919 | void set_active_session(std::string const& name) override; |
1920 | |
1921 | === modified file 'src/window_manager.cpp' |
1922 | --- src/window_manager.cpp 2015-04-09 11:27:06 +0000 |
1923 | +++ src/window_manager.cpp 2015-07-20 10:34:37 +0000 |
1924 | @@ -18,10 +18,10 @@ |
1925 | |
1926 | #include "window_manager.h" |
1927 | |
1928 | -#include "session_switcher.h" |
1929 | +#include "session_monitor.h" |
1930 | |
1931 | #include "mir/geometry/rectangle.h" |
1932 | -#include "mir/scene/null_surface_observer.h" |
1933 | +#include "mir/shell/surface_ready_observer.h" |
1934 | #include "mir/scene/session.h" |
1935 | #include "mir/scene/session_coordinator.h" |
1936 | #include "mir/scene/surface.h" |
1937 | @@ -82,52 +82,17 @@ |
1938 | std::shared_ptr<ms::Session> const scene_session; |
1939 | msh::FocusController& focus_controller; |
1940 | }; |
1941 | - |
1942 | - |
1943 | -struct SessionReadyObserver : ms::NullSurfaceObserver, |
1944 | - std::enable_shared_from_this<SessionReadyObserver> |
1945 | -{ |
1946 | - SessionReadyObserver( |
1947 | - std::shared_ptr<usc::SessionSwitcher> const& switcher, |
1948 | - std::shared_ptr<ms::Surface> const& surface, |
1949 | - ms::Session const* session) |
1950 | - : switcher{switcher}, |
1951 | - surface{surface}, |
1952 | - session{session} |
1953 | - { |
1954 | - } |
1955 | - |
1956 | - void frame_posted(int) override |
1957 | - { |
1958 | - ++num_frames_posted; |
1959 | - if (num_frames_posted == num_frames_for_session_ready) |
1960 | - { |
1961 | - switcher->mark_ready(session); |
1962 | - surface->remove_observer(shared_from_this()); |
1963 | - } |
1964 | - } |
1965 | - |
1966 | - std::shared_ptr<usc::SessionSwitcher> const switcher; |
1967 | - std::shared_ptr<ms::Surface> const surface; |
1968 | - ms::Session const* const session; |
1969 | - // We need to wait for the second frame before marking the session |
1970 | - // as ready. The first frame posted from sessions is a blank frame. |
1971 | - // TODO: Solve this issue at its root and remove this workaround |
1972 | - int const num_frames_for_session_ready{2}; |
1973 | - int num_frames_posted{0}; |
1974 | -}; |
1975 | - |
1976 | } |
1977 | |
1978 | usc::WindowManager::WindowManager( |
1979 | mir::shell::FocusController* focus_controller, |
1980 | std::shared_ptr<mir::shell::DisplayLayout> const& display_layout, |
1981 | std::shared_ptr<ms::SessionCoordinator> const& session_coordinator, |
1982 | - std::shared_ptr<SessionSwitcher> const& session_switcher) : |
1983 | + std::shared_ptr<SessionMonitor> const& session_monitor) : |
1984 | focus_controller{focus_controller}, |
1985 | display_layout{display_layout}, |
1986 | session_coordinator{session_coordinator}, |
1987 | - session_switcher{session_switcher} |
1988 | + session_monitor{session_monitor} |
1989 | { |
1990 | } |
1991 | |
1992 | @@ -139,7 +104,7 @@ |
1993 | |
1994 | auto const usc_session = std::make_shared<UscSession>(session, *focus_controller); |
1995 | |
1996 | - session_switcher->add(usc_session, session->process_id()); |
1997 | + session_monitor->add(usc_session, session->process_id()); |
1998 | } |
1999 | |
2000 | void usc::WindowManager::remove_session(std::shared_ptr<ms::Session> const& session) |
2001 | @@ -152,7 +117,7 @@ |
2002 | else |
2003 | focus_controller->set_focus_to(next_session, {}); |
2004 | |
2005 | - session_switcher->remove(session); |
2006 | + session_monitor->remove(session); |
2007 | } |
2008 | |
2009 | auto usc::WindowManager::add_surface( |
2010 | @@ -178,8 +143,13 @@ |
2011 | auto const result = build(session, placed_parameters); |
2012 | auto const surface = session->surface(result); |
2013 | |
2014 | - auto const session_ready_observer = std::make_shared<SessionReadyObserver>( |
2015 | - session_switcher, surface, session.get()); |
2016 | + auto const session_ready_observer = std::make_shared<msh::SurfaceReadyObserver>( |
2017 | + [this](std::shared_ptr<ms::Session> const& session, std::shared_ptr<ms::Surface> const& surface) |
2018 | + { |
2019 | + session_monitor->mark_ready(session.get()); |
2020 | + }, |
2021 | + session, |
2022 | + surface); |
2023 | |
2024 | surface->add_observer(session_ready_observer); |
2025 | |
2026 | |
2027 | === modified file 'src/window_manager.h' |
2028 | --- src/window_manager.h 2015-04-09 11:27:06 +0000 |
2029 | +++ src/window_manager.h 2015-07-20 10:34:37 +0000 |
2030 | @@ -20,6 +20,7 @@ |
2031 | #define USC_WINDOW_MANAGER_H_ |
2032 | |
2033 | #include <mir/shell/window_manager.h> |
2034 | +#include "session_monitor.h" |
2035 | |
2036 | namespace mir |
2037 | { |
2038 | @@ -29,7 +30,7 @@ |
2039 | |
2040 | namespace usc |
2041 | { |
2042 | -class SessionSwitcher; |
2043 | +class SessionMonitor; |
2044 | |
2045 | class WindowManager : public mir::shell::WindowManager |
2046 | { |
2047 | @@ -38,7 +39,7 @@ |
2048 | mir::shell::FocusController* focus_controller, |
2049 | std::shared_ptr<mir::shell::DisplayLayout> const& display_layout, |
2050 | std::shared_ptr<mir::scene::SessionCoordinator> const& session_coordinator, |
2051 | - std::shared_ptr<SessionSwitcher> const& session_switcher); |
2052 | + std::shared_ptr<SessionMonitor> const& session_switcher); |
2053 | |
2054 | void add_session(std::shared_ptr<mir::scene::Session> const& session) override; |
2055 | |
2056 | @@ -78,7 +79,7 @@ |
2057 | mir::shell::FocusController* const focus_controller; |
2058 | std::shared_ptr<mir::shell::DisplayLayout> const display_layout; |
2059 | std::shared_ptr<mir::scene::SessionCoordinator> const session_coordinator; |
2060 | - std::shared_ptr<SessionSwitcher> const session_switcher; |
2061 | + std::shared_ptr<SessionMonitor> const session_monitor; |
2062 | }; |
2063 | } |
2064 | |
2065 | |
2066 | === modified file 'tests/integration-tests/CMakeLists.txt' |
2067 | --- tests/integration-tests/CMakeLists.txt 2015-04-07 13:36:48 +0000 |
2068 | +++ tests/integration-tests/CMakeLists.txt 2015-07-20 10:34:37 +0000 |
2069 | @@ -32,6 +32,7 @@ |
2070 | run_command.cpp |
2071 | dbus_bus.cpp |
2072 | dbus_client.cpp |
2073 | + spin_wait.cpp |
2074 | test_dbus_event_loop.cpp |
2075 | test_unity_screen_service.cpp |
2076 | test_external_spinner.cpp |
2077 | |
2078 | === added file 'tests/integration-tests/spin_wait.cpp' |
2079 | --- tests/integration-tests/spin_wait.cpp 1970-01-01 00:00:00 +0000 |
2080 | +++ tests/integration-tests/spin_wait.cpp 2015-07-20 10:34:37 +0000 |
2081 | @@ -0,0 +1,39 @@ |
2082 | +/* |
2083 | + * Copyright © 2015 Canonical Ltd. |
2084 | + * |
2085 | + * This program is free software: you can redistribute it and/or modify it |
2086 | + * under the terms of the GNU General Public License version 3, |
2087 | + * as published by the Free Software Foundation. |
2088 | + * |
2089 | + * This program is distributed in the hope that it will be useful, |
2090 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2091 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2092 | + * GNU General Public License for more details. |
2093 | + * |
2094 | + * You should have received a copy of the GNU General Public License |
2095 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2096 | + * |
2097 | + * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com> |
2098 | + */ |
2099 | + |
2100 | +#include "spin_wait.h" |
2101 | + |
2102 | +#include <thread> |
2103 | + |
2104 | +bool usc::test::spin_wait_for_condition_or_timeout( |
2105 | + std::function<bool()> const& condition, |
2106 | + std::chrono::milliseconds timeout, |
2107 | + std::chrono::milliseconds spin_period) |
2108 | +{ |
2109 | + auto const end = std::chrono::steady_clock::now() + timeout; |
2110 | + bool condition_fulfilled = false; |
2111 | + |
2112 | + while (std::chrono::steady_clock::now() < end && |
2113 | + !(condition_fulfilled = condition())) |
2114 | + { |
2115 | + std::this_thread::sleep_for(spin_period); |
2116 | + } |
2117 | + |
2118 | + return condition_fulfilled; |
2119 | +} |
2120 | + |
2121 | |
2122 | === added file 'tests/integration-tests/spin_wait.h' |
2123 | --- tests/integration-tests/spin_wait.h 1970-01-01 00:00:00 +0000 |
2124 | +++ tests/integration-tests/spin_wait.h 2015-07-20 10:34:37 +0000 |
2125 | @@ -0,0 +1,39 @@ |
2126 | +/* |
2127 | + * Copyright © 2015 Canonical Ltd. |
2128 | + * |
2129 | + * This program is free software: you can redistribute it and/or modify it |
2130 | + * under the terms of the GNU General Public License version 3, |
2131 | + * as published by the Free Software Foundation. |
2132 | + * |
2133 | + * This program is distributed in the hope that it will be useful, |
2134 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2135 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2136 | + * GNU General Public License for more details. |
2137 | + * |
2138 | + * You should have received a copy of the GNU General Public License |
2139 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2140 | + * |
2141 | + * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com> |
2142 | + */ |
2143 | + |
2144 | +#ifndef USC_SPIN_WAIT_H_ |
2145 | +#define USC_SPIN_WAIT_H_ |
2146 | + |
2147 | +#include <functional> |
2148 | +#include <chrono> |
2149 | + |
2150 | +namespace usc |
2151 | +{ |
2152 | +namespace test |
2153 | +{ |
2154 | + |
2155 | + |
2156 | +bool spin_wait_for_condition_or_timeout( |
2157 | + std::function<bool()> const& condition, |
2158 | + std::chrono::milliseconds timeout, |
2159 | + std::chrono::milliseconds spin_period = std::chrono::milliseconds{10}); |
2160 | + |
2161 | +} |
2162 | +} |
2163 | + |
2164 | +#endif |
2165 | |
2166 | === modified file 'tests/integration-tests/test_dbus_event_loop.cpp' |
2167 | --- tests/integration-tests/test_dbus_event_loop.cpp 2015-03-18 12:48:33 +0000 |
2168 | +++ tests/integration-tests/test_dbus_event_loop.cpp 2015-07-20 10:34:37 +0000 |
2169 | @@ -201,6 +201,8 @@ |
2170 | |
2171 | static int const timeout_ms = 100; |
2172 | |
2173 | + auto const start = std::chrono::steady_clock::now(); |
2174 | + |
2175 | dbus_event_loop.enqueue( |
2176 | [this,&pending_promise] |
2177 | { |
2178 | @@ -218,7 +220,6 @@ |
2179 | }); |
2180 | |
2181 | // No one is going to reply to the signal, so the notification should time out |
2182 | - auto const start = std::chrono::steady_clock::now(); |
2183 | auto pending = pending_future.get(); |
2184 | auto const end = std::chrono::steady_clock::now(); |
2185 | auto const delay = end - start; |
2186 | |
2187 | === modified file 'tests/integration-tests/test_external_spinner.cpp' |
2188 | --- tests/integration-tests/test_external_spinner.cpp 2015-04-01 17:11:57 +0000 |
2189 | +++ tests/integration-tests/test_external_spinner.cpp 2015-07-20 10:34:37 +0000 |
2190 | @@ -18,6 +18,7 @@ |
2191 | |
2192 | #include "src/external_spinner.h" |
2193 | #include "run_command.h" |
2194 | +#include "spin_wait.h" |
2195 | |
2196 | #include <fstream> |
2197 | #include <chrono> |
2198 | @@ -70,16 +71,35 @@ |
2199 | return pids; |
2200 | } |
2201 | |
2202 | +bool is_zombie(pid_t pid) |
2203 | +{ |
2204 | + std::ifstream stat("/proc/" + std::to_string(pid) + "/stat"); |
2205 | + |
2206 | + std::stringstream ss; |
2207 | + ss << stat.rdbuf(); |
2208 | + |
2209 | + return ss.str().find(" Z ") != std::string::npos; |
2210 | +} |
2211 | + |
2212 | struct AnExternalSpinner : testing::Test |
2213 | { |
2214 | std::vector<pid_t> spinner_pids() |
2215 | { |
2216 | - return pidof(spinner_cmd); |
2217 | + std::vector<pid_t> pids; |
2218 | + |
2219 | + usc::test::spin_wait_for_condition_or_timeout( |
2220 | + [&pids, this] { pids = pidof(spinner_cmd); return !pids.empty(); }, |
2221 | + timeout); |
2222 | + |
2223 | + if (pids.empty()) |
2224 | + BOOST_THROW_EXCEPTION(std::runtime_error("spinner_pids timed out")); |
2225 | + |
2226 | + return pids; |
2227 | } |
2228 | |
2229 | std::vector<std::string> environment_of_spinner() |
2230 | { |
2231 | - auto const pids = pidof(spinner_cmd); |
2232 | + auto const pids = spinner_pids(); |
2233 | if (pids.size() > 1) |
2234 | BOOST_THROW_EXCEPTION(std::runtime_error("Detected multiple spinner processes")); |
2235 | std::vector<std::string> env; |
2236 | @@ -96,19 +116,14 @@ |
2237 | |
2238 | void wait_for_spinner_to_terminate() |
2239 | { |
2240 | - auto const timeout = std::chrono::milliseconds{3000}; |
2241 | - auto const expire = std::chrono::steady_clock::now() + timeout; |
2242 | - |
2243 | - while (spinner_pids().size() > 0) |
2244 | - { |
2245 | - if (std::chrono::steady_clock::now() > expire) |
2246 | - BOOST_THROW_EXCEPTION(std::runtime_error("wait_for_no_spinner timed out")); |
2247 | - std::this_thread::sleep_for(std::chrono::milliseconds{10}); |
2248 | - } |
2249 | + usc::test::spin_wait_for_condition_or_timeout( |
2250 | + [this] { return pidof(spinner_cmd).empty(); }, |
2251 | + timeout); |
2252 | } |
2253 | |
2254 | std::string const spinner_cmd{executable_path() + "/usc_test_helper_wait_for_signal"}; |
2255 | std::string const mir_socket{"usc_mir_socket"}; |
2256 | + std::chrono::milliseconds const timeout{3000}; |
2257 | usc::ExternalSpinner spinner{spinner_cmd, mir_socket}; |
2258 | }; |
2259 | |
2260 | @@ -165,3 +180,21 @@ |
2261 | |
2262 | EXPECT_THAT(environment_of_spinner(), Contains("MIR_SOCKET=" + mir_socket)); |
2263 | } |
2264 | + |
2265 | +TEST_F(AnExternalSpinner, does_not_leave_zombie_process) |
2266 | +{ |
2267 | + using namespace testing; |
2268 | + |
2269 | + spinner.ensure_running(); |
2270 | + auto const spinner_pid = spinner_pids()[0]; |
2271 | + spinner.kill(); |
2272 | + |
2273 | + wait_for_spinner_to_terminate(); |
2274 | + |
2275 | + // Wait a bit for zombie to be reaped by parent |
2276 | + bool const spinner_is_not_zombie = usc::test::spin_wait_for_condition_or_timeout( |
2277 | + [spinner_pid] { return !is_zombie(spinner_pid); }, |
2278 | + timeout); |
2279 | + |
2280 | + EXPECT_TRUE(spinner_is_not_zombie); |
2281 | +} |
2282 | |
2283 | === modified file 'tests/integration-tests/test_unity_screen_service.cpp' |
2284 | --- tests/integration-tests/test_unity_screen_service.cpp 2015-07-08 11:38:59 +0000 |
2285 | +++ tests/integration-tests/test_unity_screen_service.cpp 2015-07-20 10:34:37 +0000 |
2286 | @@ -40,9 +40,9 @@ |
2287 | struct MockScreen : usc::Screen |
2288 | { |
2289 | MOCK_METHOD1(enable_inactivity_timers, void(bool enable)); |
2290 | - MOCK_METHOD1(toggle_screen_power_mode, void(PowerStateChangeReason reason)); |
2291 | MOCK_METHOD0(keep_display_on_temporarily, void()); |
2292 | |
2293 | + MOCK_METHOD0(get_screen_power_mode, MirPowerMode()); |
2294 | MOCK_METHOD2(set_screen_power_mode, void(MirPowerMode mode, PowerStateChangeReason reason)); |
2295 | MOCK_METHOD1(keep_display_on, void(bool on)); |
2296 | MOCK_METHOD1(set_brightness, void(int brightness)); |
2297 | |
2298 | === modified file 'tests/unit-tests/test_mir_screen.cpp' |
2299 | --- tests/unit-tests/test_mir_screen.cpp 2015-03-16 10:24:45 +0000 |
2300 | +++ tests/unit-tests/test_mir_screen.cpp 2015-07-20 10:34:37 +0000 |
2301 | @@ -298,18 +298,20 @@ |
2302 | timer->advance_by(power_off_timeout); |
2303 | } |
2304 | |
2305 | -TEST_F(AMirScreen, toggle_screen_power_mode_from_on_to_off) |
2306 | +TEST_F(AMirScreen, set_screen_power_mode_from_on_to_off) |
2307 | { |
2308 | expect_screen_is_turned_off(); |
2309 | - mir_screen.toggle_screen_power_mode(PowerStateChangeReason::power_key); |
2310 | + mir_screen.set_screen_power_mode(MirPowerMode::mir_power_mode_off, |
2311 | + PowerStateChangeReason::power_key); |
2312 | } |
2313 | |
2314 | -TEST_F(AMirScreen, toggle_screen_power_mode_from_off_to_on) |
2315 | +TEST_F(AMirScreen, set_screen_power_mode_from_off_to_on) |
2316 | { |
2317 | turn_screen_off(); |
2318 | |
2319 | expect_screen_is_turned_on(); |
2320 | - mir_screen.toggle_screen_power_mode(PowerStateChangeReason::power_key); |
2321 | + mir_screen.set_screen_power_mode(MirPowerMode::mir_power_mode_on, |
2322 | + PowerStateChangeReason::power_key); |
2323 | } |
2324 | |
2325 | TEST_F(AMirScreen, sets_hardware_brightness) |
2326 | @@ -359,7 +361,8 @@ |
2327 | mir_screen.register_power_state_change_handler(handler); |
2328 | |
2329 | auto const toggle_reason = PowerStateChangeReason::power_key; |
2330 | - mir_screen.toggle_screen_power_mode(PowerStateChangeReason::power_key); |
2331 | + mir_screen.set_screen_power_mode(MirPowerMode::mir_power_mode_off, |
2332 | + PowerStateChangeReason::power_key); |
2333 | |
2334 | EXPECT_THAT(handler_reason, Eq(toggle_reason)); |
2335 | EXPECT_THAT(handler_mode, Eq(MirPowerMode::mir_power_mode_off)); |
2336 | |
2337 | === modified file 'tests/unit-tests/test_screen_event_handler.cpp' |
2338 | --- tests/unit-tests/test_screen_event_handler.cpp 2015-04-07 13:36:48 +0000 |
2339 | +++ tests/unit-tests/test_screen_event_handler.cpp 2015-07-20 10:34:37 +0000 |
2340 | @@ -36,9 +36,9 @@ |
2341 | struct MockScreen : usc::Screen |
2342 | { |
2343 | MOCK_METHOD1(enable_inactivity_timers, void(bool enable)); |
2344 | - MOCK_METHOD1(toggle_screen_power_mode, void(PowerStateChangeReason reason)); |
2345 | MOCK_METHOD0(keep_display_on_temporarily, void()); |
2346 | |
2347 | + MirPowerMode get_screen_power_mode() override {return mock_mode;} |
2348 | MOCK_METHOD2(set_screen_power_mode, void(MirPowerMode mode, PowerStateChangeReason reason)); |
2349 | MOCK_METHOD1(keep_display_on, void(bool on)); |
2350 | MOCK_METHOD1(set_brightness, void(int brightness)); |
2351 | @@ -48,6 +48,8 @@ |
2352 | MOCK_METHOD1(set_touch_visualization_enabled, void(bool enabled)); |
2353 | MOCK_METHOD1(register_power_state_change_handler, void( |
2354 | usc::PowerStateChangeHandler const& handler)); |
2355 | + |
2356 | + MirPowerMode mock_mode = MirPowerMode::mir_power_mode_off; |
2357 | }; |
2358 | |
2359 | struct AScreenEventHandler : testing::Test |
2360 | @@ -74,21 +76,29 @@ |
2361 | |
2362 | static const int32_t POWER_KEY_CODE = 26; |
2363 | mir::EventUPtr power_key_down_event = mir::events::make_event( |
2364 | - MirInputDeviceId{1}, 0, mir_keyboard_action_down, |
2365 | + MirInputDeviceId{1}, std::chrono::nanoseconds(0), |
2366 | + mir_keyboard_action_down, |
2367 | POWER_KEY_CODE, 0, mir_input_event_modifier_none); |
2368 | + |
2369 | mir::EventUPtr power_key_up_event = mir::events::make_event( |
2370 | - MirInputDeviceId{1}, 0, mir_keyboard_action_up, |
2371 | + MirInputDeviceId{1}, std::chrono::nanoseconds(0), |
2372 | + mir_keyboard_action_up, |
2373 | POWER_KEY_CODE, 0, mir_input_event_modifier_none); |
2374 | + |
2375 | mir::EventUPtr touch_event = mir::events::make_event( |
2376 | - MirInputDeviceId{1}, 0, mir_input_event_modifier_none); |
2377 | + MirInputDeviceId{1}, std::chrono::nanoseconds(0), |
2378 | + mir_input_event_modifier_none); |
2379 | + |
2380 | mir::EventUPtr pointer_event = mir::events::make_event( |
2381 | - MirInputDeviceId{1}, 0, mir_input_event_modifier_none, |
2382 | + MirInputDeviceId{1}, std::chrono::nanoseconds(0), |
2383 | + mir_input_event_modifier_none, |
2384 | mir_pointer_action_motion, |
2385 | {}, 0.0f, 0.0f, 0.0f, 0.0f); |
2386 | |
2387 | AdvanceableTimer timer; |
2388 | std::chrono::milliseconds const power_key_ignore_timeout{5000}; |
2389 | std::chrono::milliseconds const shutdown_timeout{10000}; |
2390 | + std::chrono::milliseconds const normal_press_duration{100}; |
2391 | testing::NiceMock<MockScreen> mock_screen; |
2392 | std::atomic<bool> shutdown_called{false}; |
2393 | usc::ScreenEventHandler screen_event_handler{ |
2394 | @@ -101,7 +111,7 @@ |
2395 | |
2396 | } |
2397 | |
2398 | -TEST_F(AScreenEventHandler, turns_screen_on_on_long_press) |
2399 | +TEST_F(AScreenEventHandler, turns_screen_on_immediately_on_press) |
2400 | { |
2401 | auto const long_press_duration = power_key_ignore_timeout; |
2402 | |
2403 | @@ -110,7 +120,6 @@ |
2404 | PowerStateChangeReason::power_key)); |
2405 | |
2406 | press_power_key(); |
2407 | - timer.advance_by(long_press_duration); |
2408 | } |
2409 | |
2410 | TEST_F(AScreenEventHandler, shuts_down_system_when_power_key_pressed_for_long_enough) |
2411 | @@ -158,28 +167,32 @@ |
2412 | move_pointer(); |
2413 | } |
2414 | |
2415 | -TEST_F(AScreenEventHandler, toggles_screen_mode_on_normal_press_release) |
2416 | +TEST_F(AScreenEventHandler, sets_screen_mode_off_normal_press_release) |
2417 | { |
2418 | - std::chrono::milliseconds const normal_press_duration{100}; |
2419 | - |
2420 | EXPECT_CALL(mock_screen, |
2421 | - toggle_screen_power_mode(PowerStateChangeReason::power_key)); |
2422 | + set_screen_power_mode(MirPowerMode::mir_power_mode_off, |
2423 | + PowerStateChangeReason::power_key)); |
2424 | |
2425 | + mock_screen.mock_mode = MirPowerMode::mir_power_mode_on; |
2426 | press_power_key(); |
2427 | timer.advance_by(normal_press_duration); |
2428 | release_power_key(); |
2429 | } |
2430 | |
2431 | -TEST_F(AScreenEventHandler, does_not_toggle_screen_mode_on_long_press_release) |
2432 | +TEST_F(AScreenEventHandler, does_not_set_screen_mode_off_long_press_release) |
2433 | { |
2434 | using namespace testing; |
2435 | |
2436 | auto const long_press_duration = power_key_ignore_timeout; |
2437 | |
2438 | EXPECT_CALL(mock_screen, |
2439 | - toggle_screen_power_mode(_)) |
2440 | + set_screen_power_mode(MirPowerMode::mir_power_mode_on, |
2441 | + PowerStateChangeReason::power_key)); |
2442 | + EXPECT_CALL(mock_screen, |
2443 | + set_screen_power_mode(MirPowerMode::mir_power_mode_off, _)) |
2444 | .Times(0); |
2445 | |
2446 | + mock_screen.mock_mode = MirPowerMode::mir_power_mode_on; |
2447 | press_power_key(); |
2448 | timer.advance_by(long_press_duration); |
2449 | release_power_key(); |
2450 | @@ -194,3 +207,19 @@ |
2451 | EXPECT_FALSE(screen_event_handler.handle(*touch_event)); |
2452 | EXPECT_FALSE(screen_event_handler.handle(*pointer_event)); |
2453 | } |
2454 | + |
2455 | +TEST_F(AScreenEventHandler, disables_inactivity_timers_on_power_key_down) |
2456 | +{ |
2457 | + EXPECT_CALL(mock_screen, enable_inactivity_timers(false)); |
2458 | + |
2459 | + press_power_key(); |
2460 | +} |
2461 | + |
2462 | +TEST_F(AScreenEventHandler, enables_inactivity_timers_on_power_key_up_when_turning_screen_on) |
2463 | +{ |
2464 | + press_power_key(); |
2465 | + timer.advance_by(normal_press_duration); |
2466 | + |
2467 | + EXPECT_CALL(mock_screen, enable_inactivity_timers(true)); |
2468 | + release_power_key(); |
2469 | +} |
2470 | |
2471 | === added directory 'tools' |
2472 | === added file 'tools/png2header.py' |
2473 | --- tools/png2header.py 1970-01-01 00:00:00 +0000 |
2474 | +++ tools/png2header.py 2015-07-20 10:34:37 +0000 |
2475 | @@ -0,0 +1,86 @@ |
2476 | +#!/usr/bin/env python |
2477 | +# coding: utf-8 |
2478 | + |
2479 | +# Copyright © 2015 Canonical Ltd. |
2480 | +# |
2481 | +# This program is free software: you can redistribute it and/or modify |
2482 | +# it under the terms of the GNU General Public License version 3 as |
2483 | +# published by the Free Software Foundation. |
2484 | +# |
2485 | +# This program is distributed in the hope that it will be useful, |
2486 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2487 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2488 | +# GNU General Public License for more details. |
2489 | +# |
2490 | +# You should have received a copy of the GNU General Public License |
2491 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
2492 | +# |
2493 | +# Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com> |
2494 | + |
2495 | +import sys |
2496 | +from PIL import Image |
2497 | + |
2498 | +def premultiply(image): |
2499 | + pixels = image.load() |
2500 | + for i in range(image.size[0]): |
2501 | + for j in range(image.size[1]): |
2502 | + orig = pixels[i,j] |
2503 | + m = orig[3] / 255.0 |
2504 | + pixels[i,j] = (int(orig[0] * m) , int(orig[1] * m), int(orig[2] * m), orig[3]) |
2505 | + |
2506 | +def tocstring(data): |
2507 | + result = '' |
2508 | + line_chars = 0 |
2509 | + line_limit = 80 |
2510 | + |
2511 | + for c in data: |
2512 | + if line_chars == 0: |
2513 | + result += ' "' |
2514 | + |
2515 | + s = '\\%o' % ord(c) |
2516 | + result += s |
2517 | + line_chars += len(s) |
2518 | + |
2519 | + if line_chars >= line_limit: |
2520 | + result += '"\n' |
2521 | + line_chars = 0 |
2522 | + |
2523 | + if line_chars != 0: |
2524 | + result += '"' |
2525 | + |
2526 | + return result |
2527 | + |
2528 | +def bytes_per_pixel(image): |
2529 | + if image.mode == 'RGBA': |
2530 | + return 4 |
2531 | + elif image.mode == 'RGB': |
2532 | + return 3 |
2533 | + else: |
2534 | + raise "Unsupported image mode %s" % image.mode |
2535 | + |
2536 | +def export(image, variable_name): |
2537 | + image_info = (image.size[0], image.size[1], bytes_per_pixel(image)) |
2538 | + print "static const struct {" |
2539 | + print " unsigned int width;" |
2540 | + print " unsigned int height;" |
2541 | + print " unsigned int bytes_per_pixel; /* 3:RGB, 4:RGBA */" |
2542 | + print " unsigned char pixel_data[%d * %d * %d + 1];" % image_info |
2543 | + print "} %s = {" % variable_name |
2544 | + print " %d, %d, %d," % image_info |
2545 | + print tocstring(image.tostring()) |
2546 | + print "};" |
2547 | + |
2548 | +def show_usage(): |
2549 | + print >>sys.stderr, "Usage: ./png2header.py PNGFILE VARNAME > HEADER_FILE" |
2550 | + print >>sys.stderr, "Convert a PNG image to an embeddable C/C++ header file" |
2551 | + |
2552 | +if len(sys.argv) < 3: |
2553 | + show_usage() |
2554 | + sys.exit(1) |
2555 | + |
2556 | +image_filename = sys.argv[1] |
2557 | +variable_name = sys.argv[2] |
2558 | + |
2559 | +image = Image.open(image_filename) |
2560 | +premultiply(image) |
2561 | +export(image, variable_name) |
FAILED: Continuous integration, rev:220 jenkins. qa.ubuntu. com/job/ unity-system- compositor- ubuntu- ci/3/ jenkins. qa.ubuntu. com/job/ unity-system- compositor- ubuntu- wily-amd64- ci/1/console jenkins. qa.ubuntu. com/job/ unity-system- compositor- ubuntu- wily-armhf- ci/1/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/unity- system- compositor- ubuntu- ci/3/rebuild
http://