Merge lp:~unity-team/unity-system-compositor/new-gl-screen into lp:unity-system-compositor
- new-gl-screen
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Michael Terry |
Approved revision: | 150 |
Merged at revision: | 134 |
Proposed branch: | lp:~unity-team/unity-system-compositor/new-gl-screen |
Merge into: | lp:unity-system-compositor |
Diff against target: |
1235 lines (+991/-30) 10 files modified
CMakeLists.txt (+10/-12) debian/control (+5/-1) debian/unity-system-compositor.install (+2/-0) spinner/CMakeLists.txt (+48/-0) spinner/eglapp.c (+372/-0) spinner/eglapp.h (+44/-0) spinner/eglspinner.c (+415/-0) src/CMakeLists.txt (+7/-0) src/system_compositor.cpp (+84/-17) src/system_compositor.h (+4/-0) |
To merge this branch: | bzr merge lp:~unity-team/unity-system-compositor/new-gl-screen |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michał Sawicz | Abstain | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Oliver Grawert (community) | Approve | ||
Review via email:
|
Commit message
This branch adds a new option "--spinner=/path" which allows for an interstitial 'busy wait' program to be specified during boot and between greeter and user sessions.
Description of the change
This branch adds a new option "--spinner=/path" which allows for an interstitial 'busy wait' program to be specified during boot and between greeter and user sessions.
- I've added a default spinner (not used yet, it's still be workshopped with Design, but is functional in current form) in the spinner/ subdirectory
- This meant adding gettext support and a po/ subdirectory (with sample fr.po translation)
- I cleaned up CMake rules a bit to better handle building two different executables.
- And finally added logic to the main USC executable to support the option, launch the spinner, and use it appropriately when a requested session is not available.
Once this lands, in future, we can fix up the spinner to be what design wants. And then add a --spinner option to ubuntu-
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Oliver Grawert (ogra) wrote : | # |
Is the design work coordinated with the spinner we have in the recovery img now (which is shown during upgrades) ?
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Oliver Grawert (ogra) wrote : | # |
hmm, seems the --spinner option is non-functional ... booting while connected via USB and excusting the following on a PC gets me a spinner though ...
adb wait-for-device && adb shell unity-system-
so it seems there is something missing in usc to actually execute the spinner when the option is set
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Michael Terry (mterry) wrote : | # |
I talked with Oliver on IRC about this. He was passing --spinner instead of --spinner=/path. Once fixed, the branch worked for him. I corrected the description to make that explicit.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Michael Terry (mterry) wrote : | # |
And as far as design goes, no. It's not coordinated with the recovery img animation yet. Design is getting back to me on what this loading screen should look like.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Oliver Grawert (ogra) wrote : | # |
Ok with the proper option it works on all devices for me (tested on flo, mako and manta)
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Michael Terry (mterry) wrote : | # |
Heads up that I changed this branch slightly in response to some design feedback:
- Black background instead of aubergine
- No "Loading..." text
This simplifies the merge a bunch (no gettext support needed now). I figured it was OK to glom this onto an Accepted branch since it doesn't touch the interesting parts of this merge, just the visual design.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Michał Sawicz (saviq) wrote : | # |
Hey folks.
Looks like we need to make the libandroid-
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:149
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Michał Sawicz (saviq) wrote : | # |
Confirmed with rsalveti, this (optional dependency on hybris) is the only way forward for now.
- 150. By Michael Terry
-
Make libandroid-
properties optional and only build-dep on it on supported architectures
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Michael Terry (mterry) wrote : | # |
Saviq, I've updated this branch to not require libandroid-
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:150
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Michał Sawicz (saviq) : | # |
Preview Diff
1 | === modified file 'CMakeLists.txt' | |||
2 | --- CMakeLists.txt 2013-11-20 10:46:10 +0000 | |||
3 | +++ CMakeLists.txt 2014-05-06 20:06:39 +0000 | |||
4 | @@ -14,7 +14,8 @@ | |||
5 | 14 | # | 14 | # |
6 | 15 | # Authored by: Robert Ancell <robert.ancell@canonical.com> | 15 | # Authored by: Robert Ancell <robert.ancell@canonical.com> |
7 | 16 | 16 | ||
9 | 17 | project(UnitySystemCompisitor) | 17 | project(UnitySystemCompositor) |
10 | 18 | set(PACKAGE "unity-system-compositor") | ||
11 | 18 | set(USC_VERSION_MAJOR 0) | 19 | set(USC_VERSION_MAJOR 0) |
12 | 19 | set(USC_VERSION_MINOR 0) | 20 | set(USC_VERSION_MINOR 0) |
13 | 20 | set(USC_VERSION_PATCH 2) | 21 | set(USC_VERSION_PATCH 2) |
14 | @@ -34,23 +35,20 @@ | |||
15 | 34 | set(CMAKE_AUTOMOC ON) | 35 | set(CMAKE_AUTOMOC ON) |
16 | 35 | 36 | ||
17 | 36 | # Use C++11 and warnings | 37 | # Use C++11 and warnings |
18 | 38 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -Wall") | ||
19 | 37 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall") | 39 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall") |
20 | 38 | 40 | ||
21 | 39 | # Check for Mir server library | ||
22 | 40 | find_package(PkgConfig) | 41 | find_package(PkgConfig) |
23 | 42 | pkg_check_modules(ANDROIDPROPS libandroid-properties) | ||
24 | 43 | pkg_check_modules(CAIRO REQUIRED cairo) | ||
25 | 44 | pkg_check_modules(GLIB REQUIRED glib-2.0) | ||
26 | 45 | pkg_check_modules(MIRCLIENT REQUIRED mirclient) | ||
27 | 41 | pkg_check_modules(MIRSERVER REQUIRED mirserver) | 46 | pkg_check_modules(MIRSERVER REQUIRED mirserver) |
28 | 42 | include_directories(${MIRSERVER_INCLUDE_DIRS}) | ||
29 | 43 | link_directories(${MIRSERVER_LIBRARY_DIRS}) | ||
30 | 44 | 47 | ||
31 | 48 | find_package(Boost 1.48.0 COMPONENTS chrono date_time filesystem system thread program_options regex REQUIRED) | ||
32 | 49 | find_package(GLESv2 REQUIRED) | ||
33 | 45 | find_package(Qt5Core) | 50 | find_package(Qt5Core) |
34 | 46 | find_package(Qt5DBus) | 51 | find_package(Qt5DBus) |
35 | 47 | 52 | ||
44 | 48 | # Check for boost | 53 | add_subdirectory(spinner/) |
37 | 49 | find_package(Boost 1.48.0 COMPONENTS chrono date_time filesystem system thread program_options regex REQUIRED) | ||
38 | 50 | include_directories(${Boost_INCLUDE_DIRS}) | ||
39 | 51 | |||
40 | 52 | # Check for GL | ||
41 | 53 | find_package(GLESv2 REQUIRED) | ||
42 | 54 | include_directories (${GLESv2_INCLUDE_DIRS}) | ||
43 | 55 | |||
45 | 56 | add_subdirectory(src/) | 54 | add_subdirectory(src/) |
46 | 57 | 55 | ||
47 | === modified file 'debian/control' | |||
48 | --- debian/control 2014-04-15 20:47:54 +0000 | |||
49 | +++ debian/control 2014-05-06 20:06:39 +0000 | |||
50 | @@ -5,6 +5,7 @@ | |||
51 | 5 | Build-Depends: cmake, | 5 | Build-Depends: cmake, |
52 | 6 | cmake-data, | 6 | cmake-data, |
53 | 7 | debhelper (>= 9), | 7 | debhelper (>= 9), |
54 | 8 | libandroid-properties-dev [i386 amd64 armhf], | ||
55 | 8 | libboost-chrono-dev, | 9 | libboost-chrono-dev, |
56 | 9 | libboost-date-time-dev, | 10 | libboost-date-time-dev, |
57 | 10 | libboost-filesystem-dev, | 11 | libboost-filesystem-dev, |
58 | @@ -12,11 +13,14 @@ | |||
59 | 12 | libboost-regex-dev, | 13 | libboost-regex-dev, |
60 | 13 | libboost-system-dev, | 14 | libboost-system-dev, |
61 | 14 | libboost-thread-dev, | 15 | libboost-thread-dev, |
62 | 16 | libcairo2-dev, | ||
63 | 17 | libglib2.0-dev, | ||
64 | 15 | libgles2-mesa-dev, | 18 | libgles2-mesa-dev, |
65 | 19 | libmirclient-dev (>= 0.1.9), | ||
66 | 16 | libmirserver-dev (>= 0.1.9), | 20 | libmirserver-dev (>= 0.1.9), |
67 | 17 | libprotobuf-dev, | 21 | libprotobuf-dev, |
68 | 18 | pkg-config, | 22 | pkg-config, |
70 | 19 | python (>= 2.7), | 23 | python:any (>= 2.7), |
71 | 20 | python-setuptools, | 24 | python-setuptools, |
72 | 21 | qt5-default, | 25 | qt5-default, |
73 | 22 | qtbase5-dev, | 26 | qtbase5-dev, |
74 | 23 | 27 | ||
75 | === modified file 'debian/unity-system-compositor.install' | |||
76 | --- debian/unity-system-compositor.install 2013-11-19 21:57:55 +0000 | |||
77 | +++ debian/unity-system-compositor.install 2014-05-06 20:06:39 +0000 | |||
78 | @@ -1,5 +1,7 @@ | |||
79 | 1 | debian/source_unity-system-compositor.py usr/share/apport/package-hooks | 1 | debian/source_unity-system-compositor.py usr/share/apport/package-hooks |
80 | 2 | debian/unity-system-compositor.sleep usr/sbin/ | 2 | debian/unity-system-compositor.sleep usr/sbin/ |
81 | 3 | etc/dbus-1/system.d/com.canonical.Unity.Screen.conf | 3 | etc/dbus-1/system.d/com.canonical.Unity.Screen.conf |
82 | 4 | usr/bin/unity-system-compositor-spinner | ||
83 | 4 | usr/sbin/unity-system-compositor | 5 | usr/sbin/unity-system-compositor |
84 | 5 | usr/share/dbus-1/interfaces/com.canonical.Unity.Screen.xml | 6 | usr/share/dbus-1/interfaces/com.canonical.Unity.Screen.xml |
85 | 7 | usr/share/unity-system-compositor | ||
86 | 6 | 8 | ||
87 | === added directory 'spinner' | |||
88 | === added file 'spinner/CMakeLists.txt' | |||
89 | --- spinner/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
90 | +++ spinner/CMakeLists.txt 2014-05-06 20:06:39 +0000 | |||
91 | @@ -0,0 +1,48 @@ | |||
92 | 1 | # -*- Mode: CMake; indent-tabs-mode: nil; tab-width: 2 -*- | ||
93 | 2 | # | ||
94 | 3 | # Copyright © 2014 Canonical Ltd. | ||
95 | 4 | # | ||
96 | 5 | # This program is free software: you can redistribute it and/or modify | ||
97 | 6 | # it under the terms of the GNU General Public License version 3 as | ||
98 | 7 | # published by the Free Software Foundation. | ||
99 | 8 | # | ||
100 | 9 | # This program is distributed in the hope that it will be useful, | ||
101 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
102 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
103 | 12 | # GNU General Public License for more details. | ||
104 | 13 | # | ||
105 | 14 | # You should have received a copy of the GNU General Public License | ||
106 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
107 | 16 | |||
108 | 17 | include_directories( | ||
109 | 18 | ${CAIRO_INCLUDE_DIRS} | ||
110 | 19 | ${GLIB_INCLUDE_DIRS} | ||
111 | 20 | ${ANDROIDPROPS_INCLUDE_DIRS} | ||
112 | 21 | ${GLESv2_INCLUDE_DIRS} | ||
113 | 22 | ${MIRCLIENT_INCLUDE_DIRS} | ||
114 | 23 | ) | ||
115 | 24 | add_definitions( | ||
116 | 25 | -DPACKAGE="${PACKAGE}" | ||
117 | 26 | -DLOCALEDIR="${CMAKE_INSTALL_FULL_LOCALEDIR}" | ||
118 | 27 | -DPKGDATADIR="${CMAKE_INSTALL_FULL_DATAROOTDIR}/${PACKAGE}" | ||
119 | 28 | ) | ||
120 | 29 | |||
121 | 30 | if(ANDROIDPROPS_FOUND) | ||
122 | 31 | add_definitions(-DHAVE_PROPS) | ||
123 | 32 | endif() | ||
124 | 33 | |||
125 | 34 | link_directories(${MIRCLIENT_LIBRARY_DIRS}) | ||
126 | 35 | |||
127 | 36 | add_executable(unity-system-compositor-spinner eglapp.c eglapp.h eglspinner.c) | ||
128 | 37 | target_link_libraries(unity-system-compositor-spinner | ||
129 | 38 | EGL | ||
130 | 39 | ${CAIRO_LDFLAGS} | ||
131 | 40 | ${GLIB_LDFLAGS} | ||
132 | 41 | ${ANDROIDPROPS_LDFLAGS} | ||
133 | 42 | ${GLESv2_LIBRARIES} | ||
134 | 43 | ${MIRCLIENT_LDFLAGS} | ||
135 | 44 | ) | ||
136 | 45 | install(TARGETS unity-system-compositor-spinner RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) | ||
137 | 46 | |||
138 | 47 | install(FILES spinner-logo.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PACKAGE}) | ||
139 | 48 | install(FILES spinner-glow.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PACKAGE}) | ||
140 | 0 | 49 | ||
141 | === added file 'spinner/eglapp.c' | |||
142 | --- spinner/eglapp.c 1970-01-01 00:00:00 +0000 | |||
143 | +++ spinner/eglapp.c 2014-05-06 20:06:39 +0000 | |||
144 | @@ -0,0 +1,372 @@ | |||
145 | 1 | /* | ||
146 | 2 | * Copyright © 2013 Canonical Ltd. | ||
147 | 3 | * | ||
148 | 4 | * This program is free software: you can redistribute it and/or modify | ||
149 | 5 | * it under the terms of the GNU General Public License version 3 as | ||
150 | 6 | * published by the Free Software Foundation. | ||
151 | 7 | * | ||
152 | 8 | * This program is distributed in the hope that it will be useful, | ||
153 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
154 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
155 | 11 | * GNU General Public License for more details. | ||
156 | 12 | * | ||
157 | 13 | * You should have received a copy of the GNU General Public License | ||
158 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
159 | 15 | * | ||
160 | 16 | * Author: Daniel van Vugt <daniel.van.vugt@canonical.com> | ||
161 | 17 | */ | ||
162 | 18 | |||
163 | 19 | #include "eglapp.h" | ||
164 | 20 | #include "mir_toolkit/mir_client_library.h" | ||
165 | 21 | #include <stdio.h> | ||
166 | 22 | #include <stdlib.h> | ||
167 | 23 | #include <signal.h> | ||
168 | 24 | #include <time.h> | ||
169 | 25 | #include <EGL/egl.h> | ||
170 | 26 | #include <GLES2/gl2.h> | ||
171 | 27 | |||
172 | 28 | float mir_eglapp_background_opacity = 1.0f; | ||
173 | 29 | |||
174 | 30 | static const char appname[] = "eglspinner"; | ||
175 | 31 | |||
176 | 32 | static MirConnection *connection; | ||
177 | 33 | static MirSurface *surface; | ||
178 | 34 | static EGLDisplay egldisplay; | ||
179 | 35 | static EGLSurface eglsurface; | ||
180 | 36 | static volatile sig_atomic_t running = 0; | ||
181 | 37 | |||
182 | 38 | #define CHECK(_cond, _err) \ | ||
183 | 39 | if (!(_cond)) \ | ||
184 | 40 | { \ | ||
185 | 41 | printf("%s\n", (_err)); \ | ||
186 | 42 | return 0; \ | ||
187 | 43 | } | ||
188 | 44 | |||
189 | 45 | void mir_eglapp_shutdown(void) | ||
190 | 46 | { | ||
191 | 47 | eglMakeCurrent(egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); | ||
192 | 48 | eglTerminate(egldisplay); | ||
193 | 49 | mir_surface_release_sync(surface); | ||
194 | 50 | surface = NULL; | ||
195 | 51 | mir_connection_release(connection); | ||
196 | 52 | connection = NULL; | ||
197 | 53 | } | ||
198 | 54 | |||
199 | 55 | static void shutdown(int signum) | ||
200 | 56 | { | ||
201 | 57 | if (running) | ||
202 | 58 | { | ||
203 | 59 | running = 0; | ||
204 | 60 | printf("Signal %d received. Good night.\n", signum); | ||
205 | 61 | } | ||
206 | 62 | } | ||
207 | 63 | |||
208 | 64 | mir_eglapp_bool mir_eglapp_running(void) | ||
209 | 65 | { | ||
210 | 66 | return running; | ||
211 | 67 | } | ||
212 | 68 | |||
213 | 69 | void mir_eglapp_swap_buffers(void) | ||
214 | 70 | { | ||
215 | 71 | EGLint width, height; | ||
216 | 72 | |||
217 | 73 | if (!running) | ||
218 | 74 | return; | ||
219 | 75 | |||
220 | 76 | eglSwapBuffers(egldisplay, eglsurface); | ||
221 | 77 | |||
222 | 78 | /* | ||
223 | 79 | * Querying the surface (actually the current buffer) dimensions here is | ||
224 | 80 | * the only truly safe way to be sure that the dimensions we think we | ||
225 | 81 | * have are those of the buffer being rendered to. But this should be | ||
226 | 82 | * improved in future; https://bugs.launchpad.net/mir/+bug/1194384 | ||
227 | 83 | */ | ||
228 | 84 | if (eglQuerySurface(egldisplay, eglsurface, EGL_WIDTH, &width) && | ||
229 | 85 | eglQuerySurface(egldisplay, eglsurface, EGL_HEIGHT, &height)) | ||
230 | 86 | { | ||
231 | 87 | glViewport(0, 0, width, height); | ||
232 | 88 | } | ||
233 | 89 | } | ||
234 | 90 | |||
235 | 91 | static void mir_eglapp_handle_event(MirSurface* surface, MirEvent const* ev, void* context) | ||
236 | 92 | { | ||
237 | 93 | (void) surface; | ||
238 | 94 | (void) context; | ||
239 | 95 | if (ev->type == mir_event_type_resize) | ||
240 | 96 | { | ||
241 | 97 | /* | ||
242 | 98 | * FIXME: https://bugs.launchpad.net/mir/+bug/1194384 | ||
243 | 99 | * It is unsafe to set the width and height here because we're in a | ||
244 | 100 | * different thread to that doing the rendering. So we either need | ||
245 | 101 | * support for event queuing (directing them to another thread) or | ||
246 | 102 | * full single-threaded callbacks. (LP: #1194384). | ||
247 | 103 | */ | ||
248 | 104 | printf("Resized to %dx%d\n", ev->resize.width, ev->resize.height); | ||
249 | 105 | } | ||
250 | 106 | } | ||
251 | 107 | |||
252 | 108 | static const MirDisplayOutput *find_active_output( | ||
253 | 109 | const MirDisplayConfiguration *conf) | ||
254 | 110 | { | ||
255 | 111 | const MirDisplayOutput *output = NULL; | ||
256 | 112 | int d; | ||
257 | 113 | |||
258 | 114 | for (d = 0; d < (int)conf->num_outputs; d++) | ||
259 | 115 | { | ||
260 | 116 | const MirDisplayOutput *out = conf->outputs + d; | ||
261 | 117 | |||
262 | 118 | if (out->used && | ||
263 | 119 | out->connected && | ||
264 | 120 | out->num_modes && | ||
265 | 121 | out->current_mode < out->num_modes) | ||
266 | 122 | { | ||
267 | 123 | output = out; | ||
268 | 124 | break; | ||
269 | 125 | } | ||
270 | 126 | } | ||
271 | 127 | |||
272 | 128 | return output; | ||
273 | 129 | } | ||
274 | 130 | |||
275 | 131 | mir_eglapp_bool mir_eglapp_init(int argc, char *argv[], | ||
276 | 132 | unsigned int *width, unsigned int *height) | ||
277 | 133 | { | ||
278 | 134 | EGLint ctxattribs[] = | ||
279 | 135 | { | ||
280 | 136 | EGL_CONTEXT_CLIENT_VERSION, 2, | ||
281 | 137 | EGL_NONE | ||
282 | 138 | }; | ||
283 | 139 | MirSurfaceParameters surfaceparm = | ||
284 | 140 | { | ||
285 | 141 | "eglappsurface", | ||
286 | 142 | 256, 256, | ||
287 | 143 | mir_pixel_format_xbgr_8888, | ||
288 | 144 | mir_buffer_usage_hardware, | ||
289 | 145 | mir_display_output_id_invalid | ||
290 | 146 | }; | ||
291 | 147 | MirEventDelegate delegate = | ||
292 | 148 | { | ||
293 | 149 | mir_eglapp_handle_event, | ||
294 | 150 | NULL | ||
295 | 151 | }; | ||
296 | 152 | EGLConfig eglconfig; | ||
297 | 153 | EGLint neglconfigs; | ||
298 | 154 | EGLContext eglctx; | ||
299 | 155 | EGLBoolean ok; | ||
300 | 156 | EGLint swapinterval = 1; | ||
301 | 157 | char *mir_socket = NULL; | ||
302 | 158 | |||
303 | 159 | if (argc > 1) | ||
304 | 160 | { | ||
305 | 161 | int i; | ||
306 | 162 | for (i = 1; i < argc; i++) | ||
307 | 163 | { | ||
308 | 164 | mir_eglapp_bool help = 0; | ||
309 | 165 | const char *arg = argv[i]; | ||
310 | 166 | |||
311 | 167 | if (arg[0] == '-') | ||
312 | 168 | { | ||
313 | 169 | switch (arg[1]) | ||
314 | 170 | { | ||
315 | 171 | case 'b': | ||
316 | 172 | { | ||
317 | 173 | float alpha = 1.0f; | ||
318 | 174 | arg += 2; | ||
319 | 175 | if (!arg[0] && i < argc-1) | ||
320 | 176 | { | ||
321 | 177 | i++; | ||
322 | 178 | arg = argv[i]; | ||
323 | 179 | } | ||
324 | 180 | if (sscanf(arg, "%f", &alpha) == 1) | ||
325 | 181 | { | ||
326 | 182 | mir_eglapp_background_opacity = alpha; | ||
327 | 183 | } | ||
328 | 184 | else | ||
329 | 185 | { | ||
330 | 186 | printf("Invalid opacity value: %s\n", arg); | ||
331 | 187 | help = 1; | ||
332 | 188 | } | ||
333 | 189 | } | ||
334 | 190 | break; | ||
335 | 191 | case 'n': | ||
336 | 192 | swapinterval = 0; | ||
337 | 193 | break; | ||
338 | 194 | case 'o': | ||
339 | 195 | { | ||
340 | 196 | unsigned int output_id = 0; | ||
341 | 197 | arg += 2; | ||
342 | 198 | if (!arg[0] && i < argc-1) | ||
343 | 199 | { | ||
344 | 200 | i++; | ||
345 | 201 | arg = argv[i]; | ||
346 | 202 | } | ||
347 | 203 | if (sscanf(arg, "%u", &output_id) == 1) | ||
348 | 204 | { | ||
349 | 205 | surfaceparm.output_id = output_id; | ||
350 | 206 | } | ||
351 | 207 | else | ||
352 | 208 | { | ||
353 | 209 | printf("Invalid output ID: %s\n", arg); | ||
354 | 210 | help = 1; | ||
355 | 211 | } | ||
356 | 212 | } | ||
357 | 213 | break; | ||
358 | 214 | case 'f': | ||
359 | 215 | *width = 0; | ||
360 | 216 | *height = 0; | ||
361 | 217 | break; | ||
362 | 218 | case 's': | ||
363 | 219 | { | ||
364 | 220 | unsigned int w, h; | ||
365 | 221 | arg += 2; | ||
366 | 222 | if (!arg[0] && i < argc-1) | ||
367 | 223 | { | ||
368 | 224 | i++; | ||
369 | 225 | arg = argv[i]; | ||
370 | 226 | } | ||
371 | 227 | if (sscanf(arg, "%ux%u", &w, &h) == 2) | ||
372 | 228 | { | ||
373 | 229 | *width = w; | ||
374 | 230 | *height = h; | ||
375 | 231 | } | ||
376 | 232 | else | ||
377 | 233 | { | ||
378 | 234 | printf("Invalid size: %s\n", arg); | ||
379 | 235 | help = 1; | ||
380 | 236 | } | ||
381 | 237 | } | ||
382 | 238 | break; | ||
383 | 239 | case 'm': | ||
384 | 240 | mir_socket = argv[++i]; | ||
385 | 241 | break; | ||
386 | 242 | case 'q': | ||
387 | 243 | { | ||
388 | 244 | FILE *unused = freopen("/dev/null", "a", stdout); | ||
389 | 245 | (void)unused; | ||
390 | 246 | break; | ||
391 | 247 | } | ||
392 | 248 | case 'h': | ||
393 | 249 | default: | ||
394 | 250 | help = 1; | ||
395 | 251 | break; | ||
396 | 252 | } | ||
397 | 253 | } | ||
398 | 254 | else | ||
399 | 255 | { | ||
400 | 256 | help = 1; | ||
401 | 257 | } | ||
402 | 258 | |||
403 | 259 | if (help) | ||
404 | 260 | { | ||
405 | 261 | printf("Usage: %s [<options>]\n" | ||
406 | 262 | " -b Background opacity (0.0 - 1.0)\n" | ||
407 | 263 | " -h Show this help text\n" | ||
408 | 264 | " -f Force full screen\n" | ||
409 | 265 | " -o ID Force placement on output monitor ID\n" | ||
410 | 266 | " -n Don't sync to vblank\n" | ||
411 | 267 | " -m socket Mir server socket\n" | ||
412 | 268 | " -s WIDTHxHEIGHT Force surface size\n" | ||
413 | 269 | " -q Quiet mode (no messages output)\n" | ||
414 | 270 | , argv[0]); | ||
415 | 271 | return 0; | ||
416 | 272 | } | ||
417 | 273 | } | ||
418 | 274 | } | ||
419 | 275 | |||
420 | 276 | connection = mir_connect_sync(mir_socket, appname); | ||
421 | 277 | CHECK(mir_connection_is_valid(connection), "Can't get connection"); | ||
422 | 278 | |||
423 | 279 | /* eglapps are interested in the screen size, so | ||
424 | 280 | use mir_connection_create_display_config */ | ||
425 | 281 | MirDisplayConfiguration* display_config = | ||
426 | 282 | mir_connection_create_display_config(connection); | ||
427 | 283 | |||
428 | 284 | const MirDisplayOutput *output = find_active_output(display_config); | ||
429 | 285 | |||
430 | 286 | if (output == NULL) | ||
431 | 287 | { | ||
432 | 288 | printf("No active outputs found.\n"); | ||
433 | 289 | return 0; | ||
434 | 290 | } | ||
435 | 291 | |||
436 | 292 | const MirDisplayMode *mode = &output->modes[output->current_mode]; | ||
437 | 293 | |||
438 | 294 | unsigned int format[mir_pixel_formats]; | ||
439 | 295 | unsigned int nformats; | ||
440 | 296 | |||
441 | 297 | mir_connection_get_available_surface_formats(connection, | ||
442 | 298 | (MirPixelFormat*) format, mir_pixel_formats, &nformats); | ||
443 | 299 | |||
444 | 300 | surfaceparm.pixel_format = (MirPixelFormat) format[0]; | ||
445 | 301 | |||
446 | 302 | printf("Current active output is %dx%d %+d%+d\n", | ||
447 | 303 | mode->horizontal_resolution, mode->vertical_resolution, | ||
448 | 304 | output->position_x, output->position_y); | ||
449 | 305 | |||
450 | 306 | surfaceparm.width = *width > 0 ? *width : mode->horizontal_resolution; | ||
451 | 307 | surfaceparm.height = *height > 0 ? *height : mode->vertical_resolution; | ||
452 | 308 | |||
453 | 309 | mir_display_config_destroy(display_config); | ||
454 | 310 | |||
455 | 311 | printf("Server supports %d of %d surface pixel formats. Using format: %d\n", | ||
456 | 312 | nformats, mir_pixel_formats, surfaceparm.pixel_format); | ||
457 | 313 | unsigned int bpp = 8 * MIR_BYTES_PER_PIXEL(surfaceparm.pixel_format); | ||
458 | 314 | EGLint attribs[] = | ||
459 | 315 | { | ||
460 | 316 | EGL_SURFACE_TYPE, EGL_WINDOW_BIT, | ||
461 | 317 | EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, | ||
462 | 318 | EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER, | ||
463 | 319 | EGL_BUFFER_SIZE, (EGLint) bpp, | ||
464 | 320 | EGL_NONE | ||
465 | 321 | }; | ||
466 | 322 | |||
467 | 323 | surface = mir_connection_create_surface_sync(connection, &surfaceparm); | ||
468 | 324 | CHECK(mir_surface_is_valid(surface), "Can't create a surface"); | ||
469 | 325 | |||
470 | 326 | mir_surface_set_event_handler(surface, &delegate); | ||
471 | 327 | |||
472 | 328 | egldisplay = eglGetDisplay( | ||
473 | 329 | (EGLNativeDisplayType) mir_connection_get_egl_native_display(connection)); | ||
474 | 330 | CHECK(egldisplay != EGL_NO_DISPLAY, "Can't eglGetDisplay"); | ||
475 | 331 | |||
476 | 332 | ok = eglInitialize(egldisplay, NULL, NULL); | ||
477 | 333 | CHECK(ok, "Can't eglInitialize"); | ||
478 | 334 | |||
479 | 335 | ok = eglChooseConfig(egldisplay, attribs, &eglconfig, 1, &neglconfigs); | ||
480 | 336 | CHECK(ok, "Could not eglChooseConfig"); | ||
481 | 337 | CHECK(neglconfigs > 0, "No EGL config available"); | ||
482 | 338 | |||
483 | 339 | eglsurface = eglCreateWindowSurface(egldisplay, eglconfig, | ||
484 | 340 | (EGLNativeWindowType)mir_surface_get_egl_native_window(surface), | ||
485 | 341 | NULL); | ||
486 | 342 | CHECK(eglsurface != EGL_NO_SURFACE, "eglCreateWindowSurface failed"); | ||
487 | 343 | |||
488 | 344 | eglctx = eglCreateContext(egldisplay, eglconfig, EGL_NO_CONTEXT, | ||
489 | 345 | ctxattribs); | ||
490 | 346 | CHECK(eglctx != EGL_NO_CONTEXT, "eglCreateContext failed"); | ||
491 | 347 | |||
492 | 348 | ok = eglMakeCurrent(egldisplay, eglsurface, eglsurface, eglctx); | ||
493 | 349 | CHECK(ok, "Can't eglMakeCurrent"); | ||
494 | 350 | |||
495 | 351 | signal(SIGINT, shutdown); | ||
496 | 352 | signal(SIGTERM, shutdown); | ||
497 | 353 | |||
498 | 354 | *width = surfaceparm.width; | ||
499 | 355 | *height = surfaceparm.height; | ||
500 | 356 | |||
501 | 357 | eglSwapInterval(egldisplay, swapinterval); | ||
502 | 358 | |||
503 | 359 | running = 1; | ||
504 | 360 | |||
505 | 361 | return 1; | ||
506 | 362 | } | ||
507 | 363 | |||
508 | 364 | struct MirConnection* mir_eglapp_native_connection() | ||
509 | 365 | { | ||
510 | 366 | return connection; | ||
511 | 367 | } | ||
512 | 368 | |||
513 | 369 | struct MirSurface* mir_eglapp_native_surface() | ||
514 | 370 | { | ||
515 | 371 | return surface; | ||
516 | 372 | } | ||
517 | 0 | 373 | ||
518 | === added file 'spinner/eglapp.h' | |||
519 | --- spinner/eglapp.h 1970-01-01 00:00:00 +0000 | |||
520 | +++ spinner/eglapp.h 2014-05-06 20:06:39 +0000 | |||
521 | @@ -0,0 +1,44 @@ | |||
522 | 1 | /* | ||
523 | 2 | * Copyright © 2013 Canonical Ltd. | ||
524 | 3 | * | ||
525 | 4 | * This program is free software: you can redistribute it and/or modify | ||
526 | 5 | * it under the terms of the GNU General Public License version 3 as | ||
527 | 6 | * published by the Free Software Foundation. | ||
528 | 7 | * | ||
529 | 8 | * This program is distributed in the hope that it will be useful, | ||
530 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
531 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
532 | 11 | * GNU General Public License for more details. | ||
533 | 12 | * | ||
534 | 13 | * You should have received a copy of the GNU General Public License | ||
535 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
536 | 15 | * | ||
537 | 16 | * Author: Daniel van Vugt <daniel.van.vugt@canonical.com> | ||
538 | 17 | */ | ||
539 | 18 | |||
540 | 19 | #ifndef __EGLAPP_H__ | ||
541 | 20 | #define __EGLAPP_H__ | ||
542 | 21 | |||
543 | 22 | #ifdef __cplusplus | ||
544 | 23 | extern "C" { | ||
545 | 24 | #endif | ||
546 | 25 | |||
547 | 26 | typedef int mir_eglapp_bool; | ||
548 | 27 | struct MirConnection; | ||
549 | 28 | struct MirSurface; | ||
550 | 29 | |||
551 | 30 | extern float mir_eglapp_background_opacity; | ||
552 | 31 | |||
553 | 32 | mir_eglapp_bool mir_eglapp_init(int argc, char *argv[], | ||
554 | 33 | unsigned int *width, unsigned int *height); | ||
555 | 34 | void mir_eglapp_swap_buffers(void); | ||
556 | 35 | mir_eglapp_bool mir_eglapp_running(void); | ||
557 | 36 | void mir_eglapp_shutdown(void); | ||
558 | 37 | |||
559 | 38 | struct MirConnection* mir_eglapp_native_connection(); | ||
560 | 39 | struct MirSurface* mir_eglapp_native_surface(); | ||
561 | 40 | #ifdef __cplusplus | ||
562 | 41 | } | ||
563 | 42 | #endif | ||
564 | 43 | |||
565 | 44 | #endif | ||
566 | 0 | 45 | ||
567 | === added file 'spinner/eglspinner.c' | |||
568 | --- spinner/eglspinner.c 1970-01-01 00:00:00 +0000 | |||
569 | +++ spinner/eglspinner.c 2014-05-06 20:06:39 +0000 | |||
570 | @@ -0,0 +1,415 @@ | |||
571 | 1 | /* | ||
572 | 2 | * Copyright © 2013 Canonical Ltd. | ||
573 | 3 | * | ||
574 | 4 | * This program is free software: you can redistribute it and/or modify | ||
575 | 5 | * it under the terms of the GNU General Public License version 3 as | ||
576 | 6 | * published by the Free Software Foundation. | ||
577 | 7 | * | ||
578 | 8 | * This program is distributed in the hope that it will be useful, | ||
579 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
580 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
581 | 11 | * GNU General Public License for more details. | ||
582 | 12 | * | ||
583 | 13 | * You should have received a copy of the GNU General Public License | ||
584 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
585 | 15 | * | ||
586 | 16 | * Authors: Daniel van Vugt <daniel.van.vugt@canonical.com> | ||
587 | 17 | * Mirco Müller <mirco.mueller@canonical.com> | ||
588 | 18 | */ | ||
589 | 19 | |||
590 | 20 | #include "eglapp.h" | ||
591 | 21 | #include <assert.h> | ||
592 | 22 | #include <cairo.h> | ||
593 | 23 | #include <glib.h> | ||
594 | 24 | #include <stdio.h> | ||
595 | 25 | #include <string.h> | ||
596 | 26 | #include <strings.h> | ||
597 | 27 | #include <stdlib.h> | ||
598 | 28 | #include <GLES2/gl2.h> | ||
599 | 29 | #include <math.h> | ||
600 | 30 | #if HAVE_PROPS | ||
601 | 31 | #include <hybris/properties/properties.h> | ||
602 | 32 | #endif | ||
603 | 33 | |||
604 | 34 | // this is needed for get_gu() to obtain the grid-unit value | ||
605 | 35 | #define MAX_LENGTH 256 | ||
606 | 36 | #define VALUE_KEY "GRID_UNIT_PX" | ||
607 | 37 | #define VALUE_KEY_LENGTH 12 | ||
608 | 38 | #define PROP_KEY "ro.product.device" | ||
609 | 39 | #define FILE_BASE "/etc/ubuntu-touch-session.d/" | ||
610 | 40 | #define FILE_EXTENSION ".conf" | ||
611 | 41 | |||
612 | 42 | int get_gu () | ||
613 | 43 | { | ||
614 | 44 | int gu = 10; // use 10 as a default value | ||
615 | 45 | FILE* handle = NULL; | ||
616 | 46 | int i = 0; | ||
617 | 47 | int j = 0; | ||
618 | 48 | int len = 0; | ||
619 | 49 | char line[MAX_LENGTH]; | ||
620 | 50 | char filename[MAX_LENGTH]; | ||
621 | 51 | |||
622 | 52 | // get name of file to read from | ||
623 | 53 | bzero ((void*) filename, MAX_LENGTH); | ||
624 | 54 | strcpy (filename, FILE_BASE); | ||
625 | 55 | #ifdef HAVE_PROPS | ||
626 | 56 | char* defaultValue = ""; | ||
627 | 57 | char value[PROP_VALUE_MAX]; | ||
628 | 58 | property_get (PROP_KEY, value, defaultValue); | ||
629 | 59 | strcat (filename, value); | ||
630 | 60 | #endif | ||
631 | 61 | strcat (filename, FILE_EXTENSION); | ||
632 | 62 | |||
633 | 63 | // try to open it | ||
634 | 64 | handle = fopen ((const char*) filename, "r"); | ||
635 | 65 | if (!handle) | ||
636 | 66 | return gu; | ||
637 | 67 | |||
638 | 68 | // read one line at a time | ||
639 | 69 | while (fgets (line, MAX_LENGTH, handle)) | ||
640 | 70 | { | ||
641 | 71 | // strip line of whitespaces | ||
642 | 72 | i = 0; | ||
643 | 73 | j = 0; | ||
644 | 74 | len = (int) strlen (line); | ||
645 | 75 | while (i != len) | ||
646 | 76 | { | ||
647 | 77 | if (line[i] != ' ' && line[i] != '\t') | ||
648 | 78 | line[j++] = line[i]; | ||
649 | 79 | i++; | ||
650 | 80 | } | ||
651 | 81 | line[j] = 0; | ||
652 | 82 | |||
653 | 83 | // parse the line for GU-value | ||
654 | 84 | if (!strncmp (line, VALUE_KEY, VALUE_KEY_LENGTH)) | ||
655 | 85 | sscanf (line, VALUE_KEY"=%d", &gu); | ||
656 | 86 | } | ||
657 | 87 | |||
658 | 88 | // clean up | ||
659 | 89 | fclose (handle); | ||
660 | 90 | |||
661 | 91 | return gu; | ||
662 | 92 | } | ||
663 | 93 | |||
664 | 94 | static GLuint load_shader(const char *src, GLenum type) | ||
665 | 95 | { | ||
666 | 96 | GLuint shader = glCreateShader(type); | ||
667 | 97 | if (shader) | ||
668 | 98 | { | ||
669 | 99 | GLint compiled; | ||
670 | 100 | glShaderSource(shader, 1, &src, NULL); | ||
671 | 101 | glCompileShader(shader); | ||
672 | 102 | glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); | ||
673 | 103 | if (!compiled) | ||
674 | 104 | { | ||
675 | 105 | GLchar log[1024]; | ||
676 | 106 | glGetShaderInfoLog(shader, sizeof log - 1, NULL, log); | ||
677 | 107 | log[sizeof log - 1] = '\0'; | ||
678 | 108 | printf("load_shader compile failed: %s\n", log); | ||
679 | 109 | glDeleteShader(shader); | ||
680 | 110 | shader = 0; | ||
681 | 111 | } | ||
682 | 112 | } | ||
683 | 113 | return shader; | ||
684 | 114 | } | ||
685 | 115 | |||
686 | 116 | // Colours from http://design.ubuntu.com/brand/colour-palette | ||
687 | 117 | #define MID_AUBERGINE 0.368627451f, 0.152941176f, 0.31372549f | ||
688 | 118 | #define ORANGE 0.866666667f, 0.282352941f, 0.141414141f | ||
689 | 119 | #define WARM_GREY 0.682352941f, 0.654901961f, 0.623529412f | ||
690 | 120 | #define COOL_GREY 0.2f, 0.2f, 0.2f | ||
691 | 121 | #define LIGHT_AUBERGINE 0.466666667f, 0.297297297f, 0.435294118f | ||
692 | 122 | #define DARK_AUBERGINE 0.17254902f, 0.0f, 0.117647059f | ||
693 | 123 | #define BLACK 0.0f, 0.0f, 0.0f | ||
694 | 124 | #define WHITE 1.0f, 1.0f, 1.0f | ||
695 | 125 | |||
696 | 126 | cairo_surface_t* pngToSurface (const char* filename) | ||
697 | 127 | { | ||
698 | 128 | // sanity check | ||
699 | 129 | if (!filename) | ||
700 | 130 | return NULL; | ||
701 | 131 | |||
702 | 132 | // create surface from PNG | ||
703 | 133 | cairo_surface_t* surface = NULL; | ||
704 | 134 | surface = cairo_image_surface_create_from_png (filename); | ||
705 | 135 | if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) | ||
706 | 136 | return NULL; | ||
707 | 137 | |||
708 | 138 | return surface; | ||
709 | 139 | } | ||
710 | 140 | |||
711 | 141 | void uploadTexture (GLuint id, const char* filename) | ||
712 | 142 | { | ||
713 | 143 | if (!id || !filename) | ||
714 | 144 | return; | ||
715 | 145 | |||
716 | 146 | cairo_surface_t* surface = pngToSurface (filename); | ||
717 | 147 | |||
718 | 148 | glBindTexture(GL_TEXTURE_2D, id); | ||
719 | 149 | |||
720 | 150 | if (cairo_surface_status (surface) == CAIRO_STATUS_SUCCESS) | ||
721 | 151 | { | ||
722 | 152 | glTexImage2D(GL_TEXTURE_2D, | ||
723 | 153 | 0, | ||
724 | 154 | cairo_image_surface_get_format (surface) == CAIRO_FORMAT_ARGB32 ? GL_RGBA : GL_RGB, | ||
725 | 155 | cairo_image_surface_get_width (surface), | ||
726 | 156 | cairo_image_surface_get_height (surface), | ||
727 | 157 | 0, | ||
728 | 158 | cairo_image_surface_get_format (surface) == CAIRO_FORMAT_ARGB32 ? GL_RGBA : GL_RGB, | ||
729 | 159 | GL_UNSIGNED_BYTE, | ||
730 | 160 | cairo_image_surface_get_data (surface)); | ||
731 | 161 | cairo_surface_destroy (surface); | ||
732 | 162 | } | ||
733 | 163 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | ||
734 | 164 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||
735 | 165 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||
736 | 166 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||
737 | 167 | glBindTexture(GL_TEXTURE_2D, 0); | ||
738 | 168 | } | ||
739 | 169 | |||
740 | 170 | GLuint createShaderProgram(const char* vertexShaderSrc, const char* fragmentShaderSrc) | ||
741 | 171 | { | ||
742 | 172 | if (!vertexShaderSrc || !fragmentShaderSrc) | ||
743 | 173 | return 0; | ||
744 | 174 | |||
745 | 175 | GLuint vShaderId = 0; | ||
746 | 176 | vShaderId = load_shader(vertexShaderSrc, GL_VERTEX_SHADER); | ||
747 | 177 | assert(vShaderId); | ||
748 | 178 | |||
749 | 179 | GLuint fShaderId = 0; | ||
750 | 180 | fShaderId = load_shader(fragmentShaderSrc, GL_FRAGMENT_SHADER); | ||
751 | 181 | assert(fShaderId); | ||
752 | 182 | |||
753 | 183 | GLuint progId = 0; | ||
754 | 184 | progId = glCreateProgram(); | ||
755 | 185 | assert(progId); | ||
756 | 186 | glAttachShader(progId, vShaderId); | ||
757 | 187 | glAttachShader(progId, fShaderId); | ||
758 | 188 | glLinkProgram(progId); | ||
759 | 189 | |||
760 | 190 | GLint linked = 0; | ||
761 | 191 | glGetProgramiv(progId, GL_LINK_STATUS, &linked); | ||
762 | 192 | if (!linked) | ||
763 | 193 | { | ||
764 | 194 | GLchar log[1024]; | ||
765 | 195 | glGetProgramInfoLog(progId, sizeof log - 1, NULL, log); | ||
766 | 196 | log[sizeof log - 1] = '\0'; | ||
767 | 197 | printf("Link failed: %s\n", log); | ||
768 | 198 | return 0; | ||
769 | 199 | } | ||
770 | 200 | |||
771 | 201 | return progId; | ||
772 | 202 | } | ||
773 | 203 | |||
774 | 204 | typedef struct _AnimationValues | ||
775 | 205 | { | ||
776 | 206 | double lastTimeStamp; | ||
777 | 207 | double angle; | ||
778 | 208 | double fadeBackground; | ||
779 | 209 | double fadeLogo; | ||
780 | 210 | double fadeGlow; | ||
781 | 211 | } AnimationValues; | ||
782 | 212 | |||
783 | 213 | void | ||
784 | 214 | updateAnimation (GTimer* timer, AnimationValues* anim) | ||
785 | 215 | { | ||
786 | 216 | if (!timer || !anim) | ||
787 | 217 | return; | ||
788 | 218 | |||
789 | 219 | //1.) 0.0 - 0.6: logo fades in fully | ||
790 | 220 | //2.) 0.0 - 6.0: logo does one full spin 360° | ||
791 | 221 | //3.) 6.0 - 6.833: glow fades in fully, black-background fades out to 50% | ||
792 | 222 | //4.) 6.833 - 7.666: glow fades out fully, black-background fades out to 0% | ||
793 | 223 | //5.) 7.666 - 8.266: logo fades out fully | ||
794 | 224 | //8.266..: now spinner can be closed as all its elements are faded out | ||
795 | 225 | |||
796 | 226 | double elapsed = g_timer_elapsed (timer, NULL); | ||
797 | 227 | double dt = elapsed - anim->lastTimeStamp; | ||
798 | 228 | anim->lastTimeStamp = elapsed; | ||
799 | 229 | |||
800 | 230 | // step 1.) | ||
801 | 231 | if (elapsed < 0.6f) | ||
802 | 232 | anim->fadeLogo += 1.6f * dt; | ||
803 | 233 | |||
804 | 234 | // step 2.) | ||
805 | 235 | anim->angle -= (0.017453292519943f * 360.0f / 6.0f) * dt; | ||
806 | 236 | |||
807 | 237 | // step 3.) glow | ||
808 | 238 | if (elapsed > 6.0f && elapsed < 6.833f) | ||
809 | 239 | anim->fadeGlow += 1.2f * dt; | ||
810 | 240 | |||
811 | 241 | // Ignore the following three until we can synchronize with greeter | ||
812 | 242 | |||
813 | 243 | // step 3.) background | ||
814 | 244 | //if (elapsed > 6.0f && elapsed < 6.833f) | ||
815 | 245 | // anim->fadeBackground -= 0.6f * dt; | ||
816 | 246 | |||
817 | 247 | // step 4.) background | ||
818 | 248 | //if (elapsed > 7.0f) | ||
819 | 249 | // anim->fadeBackground -= 0.6f * dt; | ||
820 | 250 | |||
821 | 251 | // step 5.) | ||
822 | 252 | //if (elapsed > 6.833f) | ||
823 | 253 | // anim->fadeLogo -= 1.6f * dt; | ||
824 | 254 | } | ||
825 | 255 | |||
826 | 256 | int main(int argc, char *argv[]) | ||
827 | 257 | { | ||
828 | 258 | const char vShaderSrcSpinner[] = | ||
829 | 259 | "attribute vec4 vPosition; \n" | ||
830 | 260 | "attribute vec2 aTexCoords; \n" | ||
831 | 261 | "uniform float theta; \n" | ||
832 | 262 | "varying vec2 vTexCoords; \n" | ||
833 | 263 | "void main() \n" | ||
834 | 264 | "{ \n" | ||
835 | 265 | " float c = cos(theta); \n" | ||
836 | 266 | " float s = sin(theta); \n" | ||
837 | 267 | " mat2 m; \n" | ||
838 | 268 | " m[0] = vec2(c, s); \n" | ||
839 | 269 | " m[1] = vec2(-s, c); \n" | ||
840 | 270 | " vTexCoords = m * aTexCoords + vec2 (0.5, 0.5); \n" | ||
841 | 271 | " gl_Position = vec4(vPosition.xy, -1.0, 1.0); \n" | ||
842 | 272 | "} \n"; | ||
843 | 273 | |||
844 | 274 | const char fShaderSrcGlow[] = | ||
845 | 275 | "precision mediump float; \n" | ||
846 | 276 | "varying vec2 vTexCoords; \n" | ||
847 | 277 | "uniform sampler2D uSampler; \n" | ||
848 | 278 | "uniform float uFadeGlow; \n" | ||
849 | 279 | "void main() \n" | ||
850 | 280 | "{ \n" | ||
851 | 281 | " // swizzle because texture was created with cairo\n" | ||
852 | 282 | " vec4 col = texture2D(uSampler, vTexCoords).bgra; \n" | ||
853 | 283 | " float r = col.r * uFadeGlow; \n" | ||
854 | 284 | " float g = col.g * uFadeGlow; \n" | ||
855 | 285 | " float b = col.b * uFadeGlow; \n" | ||
856 | 286 | " float a = col.a * uFadeGlow; \n" | ||
857 | 287 | " gl_FragColor = vec4(r, g, b, a); \n" | ||
858 | 288 | "} \n"; | ||
859 | 289 | |||
860 | 290 | const char fShaderSrcLogo[] = | ||
861 | 291 | "precision mediump float; \n" | ||
862 | 292 | "varying vec2 vTexCoords; \n" | ||
863 | 293 | "uniform sampler2D uSampler; \n" | ||
864 | 294 | "uniform float uFadeLogo; \n" | ||
865 | 295 | "void main() \n" | ||
866 | 296 | "{ \n" | ||
867 | 297 | " // swizzle because texture was created with cairo\n" | ||
868 | 298 | " vec4 col = texture2D(uSampler, vTexCoords).bgra; \n" | ||
869 | 299 | " float r = col.r * uFadeLogo; \n" | ||
870 | 300 | " float g = col.g * uFadeLogo; \n" | ||
871 | 301 | " float b = col.b * uFadeLogo; \n" | ||
872 | 302 | " float a = col.a * uFadeLogo; \n" | ||
873 | 303 | " gl_FragColor = vec4(r, g, b, a); \n" | ||
874 | 304 | "} \n"; | ||
875 | 305 | |||
876 | 306 | GLuint prog[2]; | ||
877 | 307 | GLuint texture[2]; | ||
878 | 308 | GLint vpos[2]; | ||
879 | 309 | GLint theta; | ||
880 | 310 | GLint fadeGlow; | ||
881 | 311 | GLint fadeLogo; | ||
882 | 312 | GLint aTexCoords[2]; | ||
883 | 313 | GLint sampler[2]; | ||
884 | 314 | unsigned int width = 0; | ||
885 | 315 | unsigned int height = 0; | ||
886 | 316 | |||
887 | 317 | if (!mir_eglapp_init(argc, argv, &width, &height)) | ||
888 | 318 | return 1; | ||
889 | 319 | |||
890 | 320 | double pixelSize = (double) get_gu () * 11.18; | ||
891 | 321 | double halfRealWidth = ((2.0 / (double) width) * pixelSize) / 2.0; | ||
892 | 322 | double halfRealHeight = ((2.0 / (double) height) * pixelSize) / 2.0; | ||
893 | 323 | |||
894 | 324 | const GLfloat vertices[] = | ||
895 | 325 | { | ||
896 | 326 | halfRealWidth, halfRealHeight, | ||
897 | 327 | halfRealWidth, -halfRealHeight, | ||
898 | 328 | -halfRealWidth, halfRealHeight, | ||
899 | 329 | -halfRealWidth, -halfRealHeight, | ||
900 | 330 | }; | ||
901 | 331 | |||
902 | 332 | const GLfloat texCoordsSpinner[] = | ||
903 | 333 | { | ||
904 | 334 | -0.5f, 0.5f, | ||
905 | 335 | -0.5f, -0.5f, | ||
906 | 336 | 0.5f, 0.5f, | ||
907 | 337 | 0.5f, -0.5f, | ||
908 | 338 | }; | ||
909 | 339 | |||
910 | 340 | prog[0] = createShaderProgram (vShaderSrcSpinner, fShaderSrcGlow); | ||
911 | 341 | prog[1] = createShaderProgram (vShaderSrcSpinner, fShaderSrcLogo); | ||
912 | 342 | |||
913 | 343 | // setup viewport and projection | ||
914 | 344 | glClearColor(BLACK, mir_eglapp_background_opacity); | ||
915 | 345 | glViewport(0, 0, width, height); | ||
916 | 346 | |||
917 | 347 | // setup proper GL-blending | ||
918 | 348 | glEnable(GL_BLEND); | ||
919 | 349 | glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); | ||
920 | 350 | glBlendEquation(GL_FUNC_ADD); | ||
921 | 351 | |||
922 | 352 | // get locations of shader-attributes/uniforms | ||
923 | 353 | vpos[0] = glGetAttribLocation(prog[0], "vPosition"); | ||
924 | 354 | aTexCoords[0] = glGetAttribLocation(prog[0], "aTexCoords"); | ||
925 | 355 | theta = glGetUniformLocation(prog[0], "theta"); | ||
926 | 356 | sampler[0] = glGetUniformLocation(prog[0], "uSampler"); | ||
927 | 357 | fadeGlow = glGetUniformLocation(prog[0], "uFadeGlow"); | ||
928 | 358 | vpos[1] = glGetAttribLocation(prog[1], "vPosition"); | ||
929 | 359 | aTexCoords[1] = glGetAttribLocation(prog[1], "aTexCoords"); | ||
930 | 360 | sampler[1] = glGetUniformLocation(prog[1], "uSampler"); | ||
931 | 361 | fadeLogo = glGetUniformLocation(prog[1], "uFadeLogo"); | ||
932 | 362 | |||
933 | 363 | // create and upload spinner-artwork | ||
934 | 364 | glGenTextures(2, texture); | ||
935 | 365 | uploadTexture(texture[0], PKGDATADIR "/spinner-glow.png"); | ||
936 | 366 | uploadTexture(texture[1], PKGDATADIR "/spinner-logo.png"); | ||
937 | 367 | |||
938 | 368 | // bunch of shader-attributes to enable | ||
939 | 369 | glVertexAttribPointer(vpos[0], 2, GL_FLOAT, GL_FALSE, 0, vertices); | ||
940 | 370 | glVertexAttribPointer(vpos[1], 2, GL_FLOAT, GL_FALSE, 0, vertices); | ||
941 | 371 | glVertexAttribPointer(aTexCoords[0], 2, GL_FLOAT, GL_FALSE, 0, texCoordsSpinner); | ||
942 | 372 | glVertexAttribPointer(aTexCoords[1], 2, GL_FLOAT, GL_FALSE, 0, texCoordsSpinner); | ||
943 | 373 | glEnableVertexAttribArray(vpos[0]); | ||
944 | 374 | glEnableVertexAttribArray(vpos[1]); | ||
945 | 375 | glEnableVertexAttribArray(aTexCoords[0]); | ||
946 | 376 | glEnableVertexAttribArray(aTexCoords[1]); | ||
947 | 377 | glActiveTexture(GL_TEXTURE0); | ||
948 | 378 | |||
949 | 379 | AnimationValues anim = {0.0, 0.0, 1.0, 0.0, 0.0}; | ||
950 | 380 | GTimer* timer = g_timer_new (); | ||
951 | 381 | |||
952 | 382 | while (mir_eglapp_running()) | ||
953 | 383 | { | ||
954 | 384 | glClearColor(BLACK, anim.fadeBackground); | ||
955 | 385 | glClear(GL_COLOR_BUFFER_BIT); | ||
956 | 386 | |||
957 | 387 | // draw glow | ||
958 | 388 | glUseProgram(prog[0]); | ||
959 | 389 | glBindTexture(GL_TEXTURE_2D, texture[0]); | ||
960 | 390 | glUniform1i(sampler[0], 0); | ||
961 | 391 | glUniform1f(theta, anim.angle); | ||
962 | 392 | glUniform1f(fadeGlow, anim.fadeGlow); | ||
963 | 393 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | ||
964 | 394 | |||
965 | 395 | // draw logo | ||
966 | 396 | glUseProgram(prog[1]); | ||
967 | 397 | glBindTexture(GL_TEXTURE_2D, texture[1]); | ||
968 | 398 | glUniform1i(sampler[1], 0); | ||
969 | 399 | glUniform1f(theta, anim.angle); | ||
970 | 400 | glUniform1f(fadeLogo, anim.fadeLogo); | ||
971 | 401 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | ||
972 | 402 | |||
973 | 403 | // update animation variable | ||
974 | 404 | updateAnimation (timer, &anim); | ||
975 | 405 | |||
976 | 406 | mir_eglapp_swap_buffers(); | ||
977 | 407 | } | ||
978 | 408 | |||
979 | 409 | mir_eglapp_shutdown(); | ||
980 | 410 | |||
981 | 411 | glDeleteTextures(2, texture); | ||
982 | 412 | g_timer_destroy (timer); | ||
983 | 413 | |||
984 | 414 | return 0; | ||
985 | 415 | } | ||
986 | 0 | 416 | ||
987 | === added file 'spinner/spinner-glow.png' | |||
988 | 1 | Binary files spinner/spinner-glow.png 1970-01-01 00:00:00 +0000 and spinner/spinner-glow.png 2014-05-06 20:06:39 +0000 differ | 417 | Binary files spinner/spinner-glow.png 1970-01-01 00:00:00 +0000 and spinner/spinner-glow.png 2014-05-06 20:06:39 +0000 differ |
989 | === added file 'spinner/spinner-logo.png' | |||
990 | 2 | Binary files spinner/spinner-logo.png 1970-01-01 00:00:00 +0000 and spinner/spinner-logo.png 2014-05-06 20:06:39 +0000 differ | 418 | Binary files spinner/spinner-logo.png 1970-01-01 00:00:00 +0000 and spinner/spinner-logo.png 2014-05-06 20:06:39 +0000 differ |
991 | === modified file 'src/CMakeLists.txt' | |||
992 | --- src/CMakeLists.txt 2013-10-31 19:16:23 +0000 | |||
993 | +++ src/CMakeLists.txt 2014-05-06 20:06:39 +0000 | |||
994 | @@ -39,9 +39,16 @@ | |||
995 | 39 | include_directories( | 39 | include_directories( |
996 | 40 | ${CMAKE_CURRENT_SOURCE_DIR} | 40 | ${CMAKE_CURRENT_SOURCE_DIR} |
997 | 41 | ${CMAKE_CURRENT_BINARY_DIR} | 41 | ${CMAKE_CURRENT_BINARY_DIR} |
998 | 42 | ${Boost_INCLUDE_DIRS} | ||
999 | 43 | ${GLESv2_INCLUDE_DIRS} | ||
1000 | 44 | ${MIRSERVER_INCLUDE_DIRS} | ||
1001 | 45 | ) | ||
1002 | 46 | add_definitions( | ||
1003 | 47 | -DDEFAULT_SPINNER="${CMAKE_INSTALL_FULL_BINDIR}/unity-system-compositor-spinner" | ||
1004 | 42 | ) | 48 | ) |
1005 | 43 | 49 | ||
1006 | 44 | # Link against libmirserver | 50 | # Link against libmirserver |
1007 | 51 | link_directories(${MIRSERVER_LIBRARY_DIRS}) | ||
1008 | 45 | target_link_libraries(unity-system-compositor | 52 | target_link_libraries(unity-system-compositor |
1009 | 46 | mirserver | 53 | mirserver |
1010 | 47 | pthread | 54 | pthread |
1011 | 48 | 55 | ||
1012 | === modified file 'src/system_compositor.cpp' | |||
1013 | --- src/system_compositor.cpp 2014-04-15 20:47:54 +0000 | |||
1014 | +++ src/system_compositor.cpp 2014-05-06 20:06:39 +0000 | |||
1015 | @@ -48,9 +48,10 @@ | |||
1016 | 48 | class SystemCompositorShell : public mf::Shell | 48 | class SystemCompositorShell : public mf::Shell |
1017 | 49 | { | 49 | { |
1018 | 50 | public: | 50 | public: |
1020 | 51 | SystemCompositorShell(std::shared_ptr<mf::Shell> const& self, | 51 | SystemCompositorShell(SystemCompositor *compositor, |
1021 | 52 | std::shared_ptr<mf::Shell> const& self, | ||
1022 | 52 | std::shared_ptr<msh::FocusController> const& focus_controller) | 53 | std::shared_ptr<msh::FocusController> const& focus_controller) |
1024 | 53 | : self(self), focus_controller{focus_controller} {} | 54 | : compositor{compositor}, self(self), focus_controller{focus_controller} {} |
1025 | 54 | 55 | ||
1026 | 55 | std::shared_ptr<mf::Session> session_named(std::string const& name) | 56 | std::shared_ptr<mf::Session> session_named(std::string const& name) |
1027 | 56 | { | 57 | { |
1028 | @@ -60,42 +61,72 @@ | |||
1029 | 60 | void set_active_session(std::string const& name) | 61 | void set_active_session(std::string const& name) |
1030 | 61 | { | 62 | { |
1031 | 62 | active_session = name; | 63 | active_session = name; |
1037 | 63 | 64 | update_session_focus(); | |
1033 | 64 | if (auto session = std::static_pointer_cast<msc::Session>(session_named(name))) | ||
1034 | 65 | focus_controller->set_focus_to(session); | ||
1035 | 66 | else | ||
1036 | 67 | std::cerr << "Unable to set active session, unknown client name " << name << std::endl; | ||
1038 | 68 | } | 65 | } |
1039 | 69 | 66 | ||
1040 | 70 | void set_next_session(std::string const& name) | 67 | void set_next_session(std::string const& name) |
1041 | 71 | { | 68 | { |
1049 | 72 | if (auto const session = std::static_pointer_cast<msc::Session>(session_named(name))) | 69 | next_session = name; |
1050 | 73 | { | 70 | update_session_focus(); |
1044 | 74 | focus_controller->set_focus_to(session); // raise session inside its depth id set | ||
1045 | 75 | set_active_session(active_session); // to restore input focus to where it should be | ||
1046 | 76 | } | ||
1047 | 77 | else | ||
1048 | 78 | std::cerr << "Unable to set next session, unknown client name " << name << std::endl; | ||
1051 | 79 | } | 71 | } |
1052 | 80 | 72 | ||
1053 | 81 | private: | 73 | private: |
1054 | 74 | void update_session_focus() | ||
1055 | 75 | { | ||
1056 | 76 | auto spinner = std::static_pointer_cast<msc::Session>(session_named(spinner_session)); | ||
1057 | 77 | auto next = std::static_pointer_cast<msc::Session>(session_named(next_session)); | ||
1058 | 78 | auto active = std::static_pointer_cast<msc::Session>(session_named(active_session)); | ||
1059 | 79 | |||
1060 | 80 | if (spinner) | ||
1061 | 81 | spinner->hide(); | ||
1062 | 82 | |||
1063 | 83 | if (next) | ||
1064 | 84 | { | ||
1065 | 85 | std::cerr << "Setting next focus to session " << next_session; | ||
1066 | 86 | focus_controller->set_focus_to(next); | ||
1067 | 87 | } | ||
1068 | 88 | else if (spinner) | ||
1069 | 89 | { | ||
1070 | 90 | std::cerr << "Setting next focus to spinner"; | ||
1071 | 91 | spinner->show(); | ||
1072 | 92 | focus_controller->set_focus_to(spinner); | ||
1073 | 93 | } | ||
1074 | 94 | |||
1075 | 95 | if (active) | ||
1076 | 96 | { | ||
1077 | 97 | std::cerr << "; active focus to session " << active_session << std::endl; | ||
1078 | 98 | focus_controller->set_focus_to(active); | ||
1079 | 99 | } | ||
1080 | 100 | else if (spinner) | ||
1081 | 101 | { | ||
1082 | 102 | std::cerr << "; active focus to spinner" << std::endl; | ||
1083 | 103 | spinner->show(); | ||
1084 | 104 | focus_controller->set_focus_to(spinner); | ||
1085 | 105 | } | ||
1086 | 106 | } | ||
1087 | 107 | |||
1088 | 82 | std::shared_ptr<mf::Session> open_session( | 108 | std::shared_ptr<mf::Session> open_session( |
1089 | 83 | pid_t client_pid, | 109 | pid_t client_pid, |
1090 | 84 | std::string const& name, | 110 | std::string const& name, |
1091 | 85 | std::shared_ptr<mf::EventSink> const& sink) | 111 | std::shared_ptr<mf::EventSink> const& sink) |
1092 | 86 | { | 112 | { |
1093 | 113 | std::cerr << "Opening session " << name << std::endl; | ||
1094 | 87 | auto result = self->open_session(client_pid, name, sink); | 114 | auto result = self->open_session(client_pid, name, sink); |
1095 | 88 | sessions[name] = result; | 115 | sessions[name] = result; |
1096 | 89 | 116 | ||
1100 | 90 | // Opening a new session will steal focus from our active session, so | 117 | if (client_pid == compositor->get_spinner_pid()) |
1101 | 91 | // restore the focus if needed. | 118 | spinner_session = name; |
1099 | 92 | set_active_session(active_session); | ||
1102 | 93 | 119 | ||
1103 | 94 | return result; | 120 | return result; |
1104 | 95 | } | 121 | } |
1105 | 96 | 122 | ||
1106 | 97 | void close_session(std::shared_ptr<mf::Session> const& session) | 123 | void close_session(std::shared_ptr<mf::Session> const& session) |
1107 | 98 | { | 124 | { |
1108 | 125 | std::cerr << "Closing session " << session->name() << std::endl; | ||
1109 | 126 | |||
1110 | 127 | if (session->name() == spinner_session) | ||
1111 | 128 | spinner_session = ""; | ||
1112 | 129 | |||
1113 | 99 | sessions.erase(session->name()); | 130 | sessions.erase(session->name()); |
1114 | 100 | self->close_session(session); | 131 | self->close_session(session); |
1115 | 101 | } | 132 | } |
1116 | @@ -110,12 +141,19 @@ | |||
1117 | 110 | void handle_surface_created(std::shared_ptr<mf::Session> const& session) | 141 | void handle_surface_created(std::shared_ptr<mf::Session> const& session) |
1118 | 111 | { | 142 | { |
1119 | 112 | self->handle_surface_created(session); | 143 | self->handle_surface_created(session); |
1120 | 144 | |||
1121 | 145 | // Opening a new surface will steal focus from our active surface, so | ||
1122 | 146 | // restore the focus if needed. | ||
1123 | 147 | update_session_focus(); | ||
1124 | 113 | } | 148 | } |
1125 | 114 | 149 | ||
1126 | 150 | SystemCompositor *compositor; | ||
1127 | 115 | std::shared_ptr<mf::Shell> const self; | 151 | std::shared_ptr<mf::Shell> const self; |
1128 | 116 | std::shared_ptr<msh::FocusController> const focus_controller; | 152 | std::shared_ptr<msh::FocusController> const focus_controller; |
1129 | 117 | std::map<std::string, std::shared_ptr<mf::Session>> sessions; | 153 | std::map<std::string, std::shared_ptr<mf::Session>> sessions; |
1130 | 118 | std::string active_session; | 154 | std::string active_session; |
1131 | 155 | std::string next_session; | ||
1132 | 156 | std::string spinner_session; | ||
1133 | 119 | }; | 157 | }; |
1134 | 120 | 158 | ||
1135 | 121 | class SystemCompositorServerConfiguration : public mir::DefaultServerConfiguration | 159 | class SystemCompositorServerConfiguration : public mir::DefaultServerConfiguration |
1136 | @@ -158,6 +196,15 @@ | |||
1137 | 158 | return x; | 196 | return x; |
1138 | 159 | } | 197 | } |
1139 | 160 | 198 | ||
1140 | 199 | std::string spinner() | ||
1141 | 200 | { | ||
1142 | 201 | // TODO: once our default spinner is ready for use everywhere, replace | ||
1143 | 202 | // default value with DEFAULT_SPINNER instead of the empty string. | ||
1144 | 203 | auto x = the_options()->get("spinner", ""); | ||
1145 | 204 | boost::trim(x); | ||
1146 | 205 | return x; | ||
1147 | 206 | } | ||
1148 | 207 | |||
1149 | 161 | bool public_socket() | 208 | bool public_socket() |
1150 | 162 | { | 209 | { |
1151 | 163 | return !the_options()->is_set("no-file") && the_options()->get("public-socket", true); | 210 | return !the_options()->is_set("no-file") && the_options()->get("public-socket", true); |
1152 | @@ -217,6 +264,7 @@ | |||
1153 | 217 | return sc_shell([this] | 264 | return sc_shell([this] |
1154 | 218 | { | 265 | { |
1155 | 219 | return std::make_shared<SystemCompositorShell>( | 266 | return std::make_shared<SystemCompositorShell>( |
1156 | 267 | compositor, | ||
1157 | 220 | mir::DefaultServerConfiguration::the_frontend_shell(), | 268 | mir::DefaultServerConfiguration::the_frontend_shell(), |
1158 | 221 | the_focus_controller()); | 269 | the_focus_controller()); |
1159 | 222 | }); | 270 | }); |
1160 | @@ -244,6 +292,7 @@ | |||
1161 | 244 | ("to-dm-fd", po::value<int>(), "File descriptor of write end of pipe to display manager [int]") | 292 | ("to-dm-fd", po::value<int>(), "File descriptor of write end of pipe to display manager [int]") |
1162 | 245 | ("blacklist", po::value<std::string>(), "Video blacklist regex to use") | 293 | ("blacklist", po::value<std::string>(), "Video blacklist regex to use") |
1163 | 246 | ("version", "Show version of Unity System Compositor") | 294 | ("version", "Show version of Unity System Compositor") |
1164 | 295 | ("spinner", po::value<std::string>(), "Path to spinner executable") | ||
1165 | 247 | ("public-socket", po::value<bool>(), "Make the socket file publicly writable") | 296 | ("public-socket", po::value<bool>(), "Make the socket file publicly writable") |
1166 | 248 | ("power-off-delay", po::value<int>(), "Delay in milliseconds before powering off screen [int]") | 297 | ("power-off-delay", po::value<int>(), "Delay in milliseconds before powering off screen [int]") |
1167 | 249 | ("enable-hardware-cursor", po::value<bool>(), "Enable the hardware cursor (disabled by default)"); | 298 | ("enable-hardware-cursor", po::value<bool>(), "Enable the hardware cursor (disabled by default)"); |
1168 | @@ -354,6 +403,11 @@ | |||
1169 | 354 | active_session->set_lifecycle_state(mir_lifecycle_state_resumed); | 403 | active_session->set_lifecycle_state(mir_lifecycle_state_resumed); |
1170 | 355 | } | 404 | } |
1171 | 356 | 405 | ||
1172 | 406 | pid_t SystemCompositor::get_spinner_pid() const | ||
1173 | 407 | { | ||
1174 | 408 | return spinner_process.pid(); | ||
1175 | 409 | } | ||
1176 | 410 | |||
1177 | 357 | void SystemCompositor::set_active_session(std::string client_name) | 411 | void SystemCompositor::set_active_session(std::string client_name) |
1178 | 358 | { | 412 | { |
1179 | 359 | std::cerr << "set_active_session" << std::endl; | 413 | std::cerr << "set_active_session" << std::endl; |
1180 | @@ -381,9 +435,22 @@ | |||
1181 | 381 | io_service.run(); | 435 | io_service.run(); |
1182 | 382 | } | 436 | } |
1183 | 383 | 437 | ||
1184 | 438 | void SystemCompositor::launch_spinner() | ||
1185 | 439 | { | ||
1186 | 440 | if (config->spinner().empty()) | ||
1187 | 441 | return; | ||
1188 | 442 | |||
1189 | 443 | // Launch spinner process to provide default background when a session isn't ready | ||
1190 | 444 | QStringList env = QProcess::systemEnvironment(); | ||
1191 | 445 | env << "MIR_SOCKET=" + QString(config->get_socket_file().c_str()); | ||
1192 | 446 | spinner_process.setEnvironment(env); | ||
1193 | 447 | spinner_process.start(config->spinner().c_str()); | ||
1194 | 448 | } | ||
1195 | 449 | |||
1196 | 384 | void SystemCompositor::qt_main(int argc, char **argv) | 450 | void SystemCompositor::qt_main(int argc, char **argv) |
1197 | 385 | { | 451 | { |
1198 | 386 | QCoreApplication app(argc, argv); | 452 | QCoreApplication app(argc, argv); |
1199 | 387 | DBusScreen dbus_screen(config, config->power_off_delay()); | 453 | DBusScreen dbus_screen(config, config->power_off_delay()); |
1200 | 454 | launch_spinner(); | ||
1201 | 388 | app.exec(); | 455 | app.exec(); |
1202 | 389 | } | 456 | } |
1203 | 390 | 457 | ||
1204 | === modified file 'src/system_compositor.h' | |||
1205 | --- src/system_compositor.h 2014-04-15 20:47:54 +0000 | |||
1206 | +++ src/system_compositor.h 2014-05-06 20:06:39 +0000 | |||
1207 | @@ -20,6 +20,7 @@ | |||
1208 | 20 | #define SYSTEM_COMPOSITOR_H_ | 20 | #define SYSTEM_COMPOSITOR_H_ |
1209 | 21 | 21 | ||
1210 | 22 | #include "dm_connection.h" | 22 | #include "dm_connection.h" |
1211 | 23 | #include <QProcess> | ||
1212 | 23 | 24 | ||
1213 | 24 | namespace mir { namespace scene { class Session; } } | 25 | namespace mir { namespace scene { class Session; } } |
1214 | 25 | 26 | ||
1215 | @@ -32,17 +33,20 @@ | |||
1216 | 32 | void run(int argc, char **argv); | 33 | void run(int argc, char **argv); |
1217 | 33 | void pause(); | 34 | void pause(); |
1218 | 34 | void resume(); | 35 | void resume(); |
1219 | 36 | pid_t get_spinner_pid() const; | ||
1220 | 35 | 37 | ||
1221 | 36 | private: | 38 | private: |
1222 | 37 | std::shared_ptr<SystemCompositorServerConfiguration> config; | 39 | std::shared_ptr<SystemCompositorServerConfiguration> config; |
1223 | 38 | std::shared_ptr<SystemCompositorShell> shell; | 40 | std::shared_ptr<SystemCompositorShell> shell; |
1224 | 39 | boost::asio::io_service io_service; | 41 | boost::asio::io_service io_service; |
1225 | 40 | std::shared_ptr<DMConnection> dm_connection; | 42 | std::shared_ptr<DMConnection> dm_connection; |
1226 | 43 | QProcess spinner_process; | ||
1227 | 41 | 44 | ||
1228 | 42 | void set_active_session(std::string client_name); | 45 | void set_active_session(std::string client_name); |
1229 | 43 | void set_next_session(std::string client_name); | 46 | void set_next_session(std::string client_name); |
1230 | 44 | void main(); | 47 | void main(); |
1231 | 45 | void qt_main(int argc, char **argv); | 48 | void qt_main(int argc, char **argv); |
1232 | 49 | void launch_spinner(); | ||
1233 | 46 | }; | 50 | }; |
1234 | 47 | 51 | ||
1235 | 48 | #endif /* SYSTEM_COMPOSITOR_H_ */ | 52 | #endif /* SYSTEM_COMPOSITOR_H_ */ |
PASSED: Continuous integration, rev:131 jenkins. qa.ubuntu. com/job/ unity-system- compositor- ci/90/ jenkins. qa.ubuntu. com/job/ unity-system- compositor- trusty- amd64-ci/ 42 jenkins. qa.ubuntu. com/job/ unity-system- compositor- trusty- armhf-ci/ 42
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/unity- system- compositor- ci/90/rebuild
http://