Merge lp:~unity-team/unity-system-compositor/new-gl-screen into lp:unity-system-compositor

Proposed by Michael Terry
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
Reviewer Review Type Date Requested Status
Michał Sawicz Abstain
PS Jenkins bot (community) continuous-integration Approve
Oliver Grawert (community) Approve
Review via email: mp+210466@code.launchpad.net

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-touch-session to point to the default one. (And eventually, when we want to use the spinner on the desktop too, we can just have USC use the default spinner as a fallback when --spinner isn't specified.)

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Oliver Grawert (ogra) wrote :

Is the design work coordinated with the spinner we have in the recovery img now (which is shown during upgrades) ?

Revision history for this message
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-compositor-spinner

so it seems there is something missing in usc to actually execute the spinner when the option is set

Revision history for this message
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.

Revision history for this message
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.

Revision history for this message
Oliver Grawert (ogra) wrote :

Ok with the proper option it works on all devices for me (tested on flo, mako and manta)

review: Approve
Revision history for this message
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.

Revision history for this message
Michał Sawicz (saviq) wrote :

Hey folks.

Looks like we need to make the libandroid-properties-dev dependency arch-specific (only for i386, amd64, armhf) and fall back to the default when it's unavailable. Otherwise we're limited to those three arches while currently u-s-c builds on arm64 as well.

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
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

Revision history for this message
Michael Terry (mterry) wrote :

Saviq, I've updated this branch to not require libandroid-properties (but to make use of it on the supported architectures).

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michał Sawicz (saviq) :
review: Abstain

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2013-11-20 10:46:10 +0000
+++ CMakeLists.txt 2014-05-06 20:06:39 +0000
@@ -14,7 +14,8 @@
14#14#
15# Authored by: Robert Ancell <robert.ancell@canonical.com>15# Authored by: Robert Ancell <robert.ancell@canonical.com>
1616
17project(UnitySystemCompisitor)17project(UnitySystemCompositor)
18set(PACKAGE "unity-system-compositor")
18set(USC_VERSION_MAJOR 0)19set(USC_VERSION_MAJOR 0)
19set(USC_VERSION_MINOR 0)20set(USC_VERSION_MINOR 0)
20set(USC_VERSION_PATCH 2)21set(USC_VERSION_PATCH 2)
@@ -34,23 +35,20 @@
34set(CMAKE_AUTOMOC ON)35set(CMAKE_AUTOMOC ON)
3536
36# Use C++11 and warnings37# Use C++11 and warnings
38set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -Wall")
37set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall")39set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall")
3840
39# Check for Mir server library
40find_package(PkgConfig)41find_package(PkgConfig)
42pkg_check_modules(ANDROIDPROPS libandroid-properties)
43pkg_check_modules(CAIRO REQUIRED cairo)
44pkg_check_modules(GLIB REQUIRED glib-2.0)
45pkg_check_modules(MIRCLIENT REQUIRED mirclient)
41pkg_check_modules(MIRSERVER REQUIRED mirserver)46pkg_check_modules(MIRSERVER REQUIRED mirserver)
42include_directories(${MIRSERVER_INCLUDE_DIRS})
43link_directories(${MIRSERVER_LIBRARY_DIRS})
4447
48find_package(Boost 1.48.0 COMPONENTS chrono date_time filesystem system thread program_options regex REQUIRED)
49find_package(GLESv2 REQUIRED)
45find_package(Qt5Core)50find_package(Qt5Core)
46find_package(Qt5DBus)51find_package(Qt5DBus)
4752
48# Check for boost53add_subdirectory(spinner/)
49find_package(Boost 1.48.0 COMPONENTS chrono date_time filesystem system thread program_options regex REQUIRED)
50include_directories(${Boost_INCLUDE_DIRS})
51
52# Check for GL
53find_package(GLESv2 REQUIRED)
54include_directories (${GLESv2_INCLUDE_DIRS})
55
56add_subdirectory(src/)54add_subdirectory(src/)
5755
=== modified file 'debian/control'
--- debian/control 2014-04-15 20:47:54 +0000
+++ debian/control 2014-05-06 20:06:39 +0000
@@ -5,6 +5,7 @@
5Build-Depends: cmake,5Build-Depends: cmake,
6 cmake-data,6 cmake-data,
7 debhelper (>= 9),7 debhelper (>= 9),
8 libandroid-properties-dev [i386 amd64 armhf],
8 libboost-chrono-dev,9 libboost-chrono-dev,
9 libboost-date-time-dev,10 libboost-date-time-dev,
10 libboost-filesystem-dev,11 libboost-filesystem-dev,
@@ -12,11 +13,14 @@
12 libboost-regex-dev,13 libboost-regex-dev,
13 libboost-system-dev,14 libboost-system-dev,
14 libboost-thread-dev,15 libboost-thread-dev,
16 libcairo2-dev,
17 libglib2.0-dev,
15 libgles2-mesa-dev,18 libgles2-mesa-dev,
19 libmirclient-dev (>= 0.1.9),
16 libmirserver-dev (>= 0.1.9),20 libmirserver-dev (>= 0.1.9),
17 libprotobuf-dev,21 libprotobuf-dev,
18 pkg-config,22 pkg-config,
19 python (>= 2.7),23 python:any (>= 2.7),
20 python-setuptools,24 python-setuptools,
21 qt5-default,25 qt5-default,
22 qtbase5-dev,26 qtbase5-dev,
2327
=== modified file 'debian/unity-system-compositor.install'
--- debian/unity-system-compositor.install 2013-11-19 21:57:55 +0000
+++ debian/unity-system-compositor.install 2014-05-06 20:06:39 +0000
@@ -1,5 +1,7 @@
1debian/source_unity-system-compositor.py usr/share/apport/package-hooks1debian/source_unity-system-compositor.py usr/share/apport/package-hooks
2debian/unity-system-compositor.sleep usr/sbin/2debian/unity-system-compositor.sleep usr/sbin/
3etc/dbus-1/system.d/com.canonical.Unity.Screen.conf3etc/dbus-1/system.d/com.canonical.Unity.Screen.conf
4usr/bin/unity-system-compositor-spinner
4usr/sbin/unity-system-compositor5usr/sbin/unity-system-compositor
5usr/share/dbus-1/interfaces/com.canonical.Unity.Screen.xml6usr/share/dbus-1/interfaces/com.canonical.Unity.Screen.xml
7usr/share/unity-system-compositor
68
=== added directory 'spinner'
=== added file 'spinner/CMakeLists.txt'
--- spinner/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ spinner/CMakeLists.txt 2014-05-06 20:06:39 +0000
@@ -0,0 +1,48 @@
1# -*- Mode: CMake; indent-tabs-mode: nil; tab-width: 2 -*-
2#
3# Copyright © 2014 Canonical Ltd.
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License version 3 as
7# published by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17include_directories(
18 ${CAIRO_INCLUDE_DIRS}
19 ${GLIB_INCLUDE_DIRS}
20 ${ANDROIDPROPS_INCLUDE_DIRS}
21 ${GLESv2_INCLUDE_DIRS}
22 ${MIRCLIENT_INCLUDE_DIRS}
23)
24add_definitions(
25 -DPACKAGE="${PACKAGE}"
26 -DLOCALEDIR="${CMAKE_INSTALL_FULL_LOCALEDIR}"
27 -DPKGDATADIR="${CMAKE_INSTALL_FULL_DATAROOTDIR}/${PACKAGE}"
28)
29
30if(ANDROIDPROPS_FOUND)
31add_definitions(-DHAVE_PROPS)
32endif()
33
34link_directories(${MIRCLIENT_LIBRARY_DIRS})
35
36add_executable(unity-system-compositor-spinner eglapp.c eglapp.h eglspinner.c)
37target_link_libraries(unity-system-compositor-spinner
38 EGL
39 ${CAIRO_LDFLAGS}
40 ${GLIB_LDFLAGS}
41 ${ANDROIDPROPS_LDFLAGS}
42 ${GLESv2_LIBRARIES}
43 ${MIRCLIENT_LDFLAGS}
44)
45install(TARGETS unity-system-compositor-spinner RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
46
47install(FILES spinner-logo.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PACKAGE})
48install(FILES spinner-glow.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PACKAGE})
049
=== added file 'spinner/eglapp.c'
--- spinner/eglapp.c 1970-01-01 00:00:00 +0000
+++ spinner/eglapp.c 2014-05-06 20:06:39 +0000
@@ -0,0 +1,372 @@
1/*
2 * Copyright © 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Daniel van Vugt <daniel.van.vugt@canonical.com>
17 */
18
19#include "eglapp.h"
20#include "mir_toolkit/mir_client_library.h"
21#include <stdio.h>
22#include <stdlib.h>
23#include <signal.h>
24#include <time.h>
25#include <EGL/egl.h>
26#include <GLES2/gl2.h>
27
28float mir_eglapp_background_opacity = 1.0f;
29
30static const char appname[] = "eglspinner";
31
32static MirConnection *connection;
33static MirSurface *surface;
34static EGLDisplay egldisplay;
35static EGLSurface eglsurface;
36static volatile sig_atomic_t running = 0;
37
38#define CHECK(_cond, _err) \
39 if (!(_cond)) \
40 { \
41 printf("%s\n", (_err)); \
42 return 0; \
43 }
44
45void mir_eglapp_shutdown(void)
46{
47 eglMakeCurrent(egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
48 eglTerminate(egldisplay);
49 mir_surface_release_sync(surface);
50 surface = NULL;
51 mir_connection_release(connection);
52 connection = NULL;
53}
54
55static void shutdown(int signum)
56{
57 if (running)
58 {
59 running = 0;
60 printf("Signal %d received. Good night.\n", signum);
61 }
62}
63
64mir_eglapp_bool mir_eglapp_running(void)
65{
66 return running;
67}
68
69void mir_eglapp_swap_buffers(void)
70{
71 EGLint width, height;
72
73 if (!running)
74 return;
75
76 eglSwapBuffers(egldisplay, eglsurface);
77
78 /*
79 * Querying the surface (actually the current buffer) dimensions here is
80 * the only truly safe way to be sure that the dimensions we think we
81 * have are those of the buffer being rendered to. But this should be
82 * improved in future; https://bugs.launchpad.net/mir/+bug/1194384
83 */
84 if (eglQuerySurface(egldisplay, eglsurface, EGL_WIDTH, &width) &&
85 eglQuerySurface(egldisplay, eglsurface, EGL_HEIGHT, &height))
86 {
87 glViewport(0, 0, width, height);
88 }
89}
90
91static void mir_eglapp_handle_event(MirSurface* surface, MirEvent const* ev, void* context)
92{
93 (void) surface;
94 (void) context;
95 if (ev->type == mir_event_type_resize)
96 {
97 /*
98 * FIXME: https://bugs.launchpad.net/mir/+bug/1194384
99 * It is unsafe to set the width and height here because we're in a
100 * different thread to that doing the rendering. So we either need
101 * support for event queuing (directing them to another thread) or
102 * full single-threaded callbacks. (LP: #1194384).
103 */
104 printf("Resized to %dx%d\n", ev->resize.width, ev->resize.height);
105 }
106}
107
108static const MirDisplayOutput *find_active_output(
109 const MirDisplayConfiguration *conf)
110{
111 const MirDisplayOutput *output = NULL;
112 int d;
113
114 for (d = 0; d < (int)conf->num_outputs; d++)
115 {
116 const MirDisplayOutput *out = conf->outputs + d;
117
118 if (out->used &&
119 out->connected &&
120 out->num_modes &&
121 out->current_mode < out->num_modes)
122 {
123 output = out;
124 break;
125 }
126 }
127
128 return output;
129}
130
131mir_eglapp_bool mir_eglapp_init(int argc, char *argv[],
132 unsigned int *width, unsigned int *height)
133{
134 EGLint ctxattribs[] =
135 {
136 EGL_CONTEXT_CLIENT_VERSION, 2,
137 EGL_NONE
138 };
139 MirSurfaceParameters surfaceparm =
140 {
141 "eglappsurface",
142 256, 256,
143 mir_pixel_format_xbgr_8888,
144 mir_buffer_usage_hardware,
145 mir_display_output_id_invalid
146 };
147 MirEventDelegate delegate =
148 {
149 mir_eglapp_handle_event,
150 NULL
151 };
152 EGLConfig eglconfig;
153 EGLint neglconfigs;
154 EGLContext eglctx;
155 EGLBoolean ok;
156 EGLint swapinterval = 1;
157 char *mir_socket = NULL;
158
159 if (argc > 1)
160 {
161 int i;
162 for (i = 1; i < argc; i++)
163 {
164 mir_eglapp_bool help = 0;
165 const char *arg = argv[i];
166
167 if (arg[0] == '-')
168 {
169 switch (arg[1])
170 {
171 case 'b':
172 {
173 float alpha = 1.0f;
174 arg += 2;
175 if (!arg[0] && i < argc-1)
176 {
177 i++;
178 arg = argv[i];
179 }
180 if (sscanf(arg, "%f", &alpha) == 1)
181 {
182 mir_eglapp_background_opacity = alpha;
183 }
184 else
185 {
186 printf("Invalid opacity value: %s\n", arg);
187 help = 1;
188 }
189 }
190 break;
191 case 'n':
192 swapinterval = 0;
193 break;
194 case 'o':
195 {
196 unsigned int output_id = 0;
197 arg += 2;
198 if (!arg[0] && i < argc-1)
199 {
200 i++;
201 arg = argv[i];
202 }
203 if (sscanf(arg, "%u", &output_id) == 1)
204 {
205 surfaceparm.output_id = output_id;
206 }
207 else
208 {
209 printf("Invalid output ID: %s\n", arg);
210 help = 1;
211 }
212 }
213 break;
214 case 'f':
215 *width = 0;
216 *height = 0;
217 break;
218 case 's':
219 {
220 unsigned int w, h;
221 arg += 2;
222 if (!arg[0] && i < argc-1)
223 {
224 i++;
225 arg = argv[i];
226 }
227 if (sscanf(arg, "%ux%u", &w, &h) == 2)
228 {
229 *width = w;
230 *height = h;
231 }
232 else
233 {
234 printf("Invalid size: %s\n", arg);
235 help = 1;
236 }
237 }
238 break;
239 case 'm':
240 mir_socket = argv[++i];
241 break;
242 case 'q':
243 {
244 FILE *unused = freopen("/dev/null", "a", stdout);
245 (void)unused;
246 break;
247 }
248 case 'h':
249 default:
250 help = 1;
251 break;
252 }
253 }
254 else
255 {
256 help = 1;
257 }
258
259 if (help)
260 {
261 printf("Usage: %s [<options>]\n"
262 " -b Background opacity (0.0 - 1.0)\n"
263 " -h Show this help text\n"
264 " -f Force full screen\n"
265 " -o ID Force placement on output monitor ID\n"
266 " -n Don't sync to vblank\n"
267 " -m socket Mir server socket\n"
268 " -s WIDTHxHEIGHT Force surface size\n"
269 " -q Quiet mode (no messages output)\n"
270 , argv[0]);
271 return 0;
272 }
273 }
274 }
275
276 connection = mir_connect_sync(mir_socket, appname);
277 CHECK(mir_connection_is_valid(connection), "Can't get connection");
278
279 /* eglapps are interested in the screen size, so
280 use mir_connection_create_display_config */
281 MirDisplayConfiguration* display_config =
282 mir_connection_create_display_config(connection);
283
284 const MirDisplayOutput *output = find_active_output(display_config);
285
286 if (output == NULL)
287 {
288 printf("No active outputs found.\n");
289 return 0;
290 }
291
292 const MirDisplayMode *mode = &output->modes[output->current_mode];
293
294 unsigned int format[mir_pixel_formats];
295 unsigned int nformats;
296
297 mir_connection_get_available_surface_formats(connection,
298 (MirPixelFormat*) format, mir_pixel_formats, &nformats);
299
300 surfaceparm.pixel_format = (MirPixelFormat) format[0];
301
302 printf("Current active output is %dx%d %+d%+d\n",
303 mode->horizontal_resolution, mode->vertical_resolution,
304 output->position_x, output->position_y);
305
306 surfaceparm.width = *width > 0 ? *width : mode->horizontal_resolution;
307 surfaceparm.height = *height > 0 ? *height : mode->vertical_resolution;
308
309 mir_display_config_destroy(display_config);
310
311 printf("Server supports %d of %d surface pixel formats. Using format: %d\n",
312 nformats, mir_pixel_formats, surfaceparm.pixel_format);
313 unsigned int bpp = 8 * MIR_BYTES_PER_PIXEL(surfaceparm.pixel_format);
314 EGLint attribs[] =
315 {
316 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
317 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
318 EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,
319 EGL_BUFFER_SIZE, (EGLint) bpp,
320 EGL_NONE
321 };
322
323 surface = mir_connection_create_surface_sync(connection, &surfaceparm);
324 CHECK(mir_surface_is_valid(surface), "Can't create a surface");
325
326 mir_surface_set_event_handler(surface, &delegate);
327
328 egldisplay = eglGetDisplay(
329 (EGLNativeDisplayType) mir_connection_get_egl_native_display(connection));
330 CHECK(egldisplay != EGL_NO_DISPLAY, "Can't eglGetDisplay");
331
332 ok = eglInitialize(egldisplay, NULL, NULL);
333 CHECK(ok, "Can't eglInitialize");
334
335 ok = eglChooseConfig(egldisplay, attribs, &eglconfig, 1, &neglconfigs);
336 CHECK(ok, "Could not eglChooseConfig");
337 CHECK(neglconfigs > 0, "No EGL config available");
338
339 eglsurface = eglCreateWindowSurface(egldisplay, eglconfig,
340 (EGLNativeWindowType)mir_surface_get_egl_native_window(surface),
341 NULL);
342 CHECK(eglsurface != EGL_NO_SURFACE, "eglCreateWindowSurface failed");
343
344 eglctx = eglCreateContext(egldisplay, eglconfig, EGL_NO_CONTEXT,
345 ctxattribs);
346 CHECK(eglctx != EGL_NO_CONTEXT, "eglCreateContext failed");
347
348 ok = eglMakeCurrent(egldisplay, eglsurface, eglsurface, eglctx);
349 CHECK(ok, "Can't eglMakeCurrent");
350
351 signal(SIGINT, shutdown);
352 signal(SIGTERM, shutdown);
353
354 *width = surfaceparm.width;
355 *height = surfaceparm.height;
356
357 eglSwapInterval(egldisplay, swapinterval);
358
359 running = 1;
360
361 return 1;
362}
363
364struct MirConnection* mir_eglapp_native_connection()
365{
366 return connection;
367}
368
369struct MirSurface* mir_eglapp_native_surface()
370{
371 return surface;
372}
0373
=== added file 'spinner/eglapp.h'
--- spinner/eglapp.h 1970-01-01 00:00:00 +0000
+++ spinner/eglapp.h 2014-05-06 20:06:39 +0000
@@ -0,0 +1,44 @@
1/*
2 * Copyright © 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Daniel van Vugt <daniel.van.vugt@canonical.com>
17 */
18
19#ifndef __EGLAPP_H__
20#define __EGLAPP_H__
21
22#ifdef __cplusplus
23extern "C" {
24#endif
25
26typedef int mir_eglapp_bool;
27struct MirConnection;
28struct MirSurface;
29
30extern float mir_eglapp_background_opacity;
31
32mir_eglapp_bool mir_eglapp_init(int argc, char *argv[],
33 unsigned int *width, unsigned int *height);
34void mir_eglapp_swap_buffers(void);
35mir_eglapp_bool mir_eglapp_running(void);
36void mir_eglapp_shutdown(void);
37
38struct MirConnection* mir_eglapp_native_connection();
39struct MirSurface* mir_eglapp_native_surface();
40#ifdef __cplusplus
41}
42#endif
43
44#endif
045
=== added file 'spinner/eglspinner.c'
--- spinner/eglspinner.c 1970-01-01 00:00:00 +0000
+++ spinner/eglspinner.c 2014-05-06 20:06:39 +0000
@@ -0,0 +1,415 @@
1/*
2 * Copyright © 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors: Daniel van Vugt <daniel.van.vugt@canonical.com>
17 * Mirco Müller <mirco.mueller@canonical.com>
18 */
19
20#include "eglapp.h"
21#include <assert.h>
22#include <cairo.h>
23#include <glib.h>
24#include <stdio.h>
25#include <string.h>
26#include <strings.h>
27#include <stdlib.h>
28#include <GLES2/gl2.h>
29#include <math.h>
30#if HAVE_PROPS
31#include <hybris/properties/properties.h>
32#endif
33
34// this is needed for get_gu() to obtain the grid-unit value
35#define MAX_LENGTH 256
36#define VALUE_KEY "GRID_UNIT_PX"
37#define VALUE_KEY_LENGTH 12
38#define PROP_KEY "ro.product.device"
39#define FILE_BASE "/etc/ubuntu-touch-session.d/"
40#define FILE_EXTENSION ".conf"
41
42int get_gu ()
43{
44 int gu = 10; // use 10 as a default value
45 FILE* handle = NULL;
46 int i = 0;
47 int j = 0;
48 int len = 0;
49 char line[MAX_LENGTH];
50 char filename[MAX_LENGTH];
51
52 // get name of file to read from
53 bzero ((void*) filename, MAX_LENGTH);
54 strcpy (filename, FILE_BASE);
55#ifdef HAVE_PROPS
56 char* defaultValue = "";
57 char value[PROP_VALUE_MAX];
58 property_get (PROP_KEY, value, defaultValue);
59 strcat (filename, value);
60#endif
61 strcat (filename, FILE_EXTENSION);
62
63 // try to open it
64 handle = fopen ((const char*) filename, "r");
65 if (!handle)
66 return gu;
67
68 // read one line at a time
69 while (fgets (line, MAX_LENGTH, handle))
70 {
71 // strip line of whitespaces
72 i = 0;
73 j = 0;
74 len = (int) strlen (line);
75 while (i != len)
76 {
77 if (line[i] != ' ' && line[i] != '\t')
78 line[j++] = line[i];
79 i++;
80 }
81 line[j] = 0;
82
83 // parse the line for GU-value
84 if (!strncmp (line, VALUE_KEY, VALUE_KEY_LENGTH))
85 sscanf (line, VALUE_KEY"=%d", &gu);
86 }
87
88 // clean up
89 fclose (handle);
90
91 return gu;
92}
93
94static GLuint load_shader(const char *src, GLenum type)
95{
96 GLuint shader = glCreateShader(type);
97 if (shader)
98 {
99 GLint compiled;
100 glShaderSource(shader, 1, &src, NULL);
101 glCompileShader(shader);
102 glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
103 if (!compiled)
104 {
105 GLchar log[1024];
106 glGetShaderInfoLog(shader, sizeof log - 1, NULL, log);
107 log[sizeof log - 1] = '\0';
108 printf("load_shader compile failed: %s\n", log);
109 glDeleteShader(shader);
110 shader = 0;
111 }
112 }
113 return shader;
114}
115
116// Colours from http://design.ubuntu.com/brand/colour-palette
117#define MID_AUBERGINE 0.368627451f, 0.152941176f, 0.31372549f
118#define ORANGE 0.866666667f, 0.282352941f, 0.141414141f
119#define WARM_GREY 0.682352941f, 0.654901961f, 0.623529412f
120#define COOL_GREY 0.2f, 0.2f, 0.2f
121#define LIGHT_AUBERGINE 0.466666667f, 0.297297297f, 0.435294118f
122#define DARK_AUBERGINE 0.17254902f, 0.0f, 0.117647059f
123#define BLACK 0.0f, 0.0f, 0.0f
124#define WHITE 1.0f, 1.0f, 1.0f
125
126cairo_surface_t* pngToSurface (const char* filename)
127{
128 // sanity check
129 if (!filename)
130 return NULL;
131
132 // create surface from PNG
133 cairo_surface_t* surface = NULL;
134 surface = cairo_image_surface_create_from_png (filename);
135 if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
136 return NULL;
137
138 return surface;
139}
140
141void uploadTexture (GLuint id, const char* filename)
142{
143 if (!id || !filename)
144 return;
145
146 cairo_surface_t* surface = pngToSurface (filename);
147
148 glBindTexture(GL_TEXTURE_2D, id);
149
150 if (cairo_surface_status (surface) == CAIRO_STATUS_SUCCESS)
151 {
152 glTexImage2D(GL_TEXTURE_2D,
153 0,
154 cairo_image_surface_get_format (surface) == CAIRO_FORMAT_ARGB32 ? GL_RGBA : GL_RGB,
155 cairo_image_surface_get_width (surface),
156 cairo_image_surface_get_height (surface),
157 0,
158 cairo_image_surface_get_format (surface) == CAIRO_FORMAT_ARGB32 ? GL_RGBA : GL_RGB,
159 GL_UNSIGNED_BYTE,
160 cairo_image_surface_get_data (surface));
161 cairo_surface_destroy (surface);
162 }
163 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
164 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
165 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
166 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
167 glBindTexture(GL_TEXTURE_2D, 0);
168}
169
170GLuint createShaderProgram(const char* vertexShaderSrc, const char* fragmentShaderSrc)
171{
172 if (!vertexShaderSrc || !fragmentShaderSrc)
173 return 0;
174
175 GLuint vShaderId = 0;
176 vShaderId = load_shader(vertexShaderSrc, GL_VERTEX_SHADER);
177 assert(vShaderId);
178
179 GLuint fShaderId = 0;
180 fShaderId = load_shader(fragmentShaderSrc, GL_FRAGMENT_SHADER);
181 assert(fShaderId);
182
183 GLuint progId = 0;
184 progId = glCreateProgram();
185 assert(progId);
186 glAttachShader(progId, vShaderId);
187 glAttachShader(progId, fShaderId);
188 glLinkProgram(progId);
189
190 GLint linked = 0;
191 glGetProgramiv(progId, GL_LINK_STATUS, &linked);
192 if (!linked)
193 {
194 GLchar log[1024];
195 glGetProgramInfoLog(progId, sizeof log - 1, NULL, log);
196 log[sizeof log - 1] = '\0';
197 printf("Link failed: %s\n", log);
198 return 0;
199 }
200
201 return progId;
202}
203
204typedef struct _AnimationValues
205{
206 double lastTimeStamp;
207 double angle;
208 double fadeBackground;
209 double fadeLogo;
210 double fadeGlow;
211} AnimationValues;
212
213void
214updateAnimation (GTimer* timer, AnimationValues* anim)
215{
216 if (!timer || !anim)
217 return;
218
219 //1.) 0.0 - 0.6: logo fades in fully
220 //2.) 0.0 - 6.0: logo does one full spin 360°
221 //3.) 6.0 - 6.833: glow fades in fully, black-background fades out to 50%
222 //4.) 6.833 - 7.666: glow fades out fully, black-background fades out to 0%
223 //5.) 7.666 - 8.266: logo fades out fully
224 //8.266..: now spinner can be closed as all its elements are faded out
225
226 double elapsed = g_timer_elapsed (timer, NULL);
227 double dt = elapsed - anim->lastTimeStamp;
228 anim->lastTimeStamp = elapsed;
229
230 // step 1.)
231 if (elapsed < 0.6f)
232 anim->fadeLogo += 1.6f * dt;
233
234 // step 2.)
235 anim->angle -= (0.017453292519943f * 360.0f / 6.0f) * dt;
236
237 // step 3.) glow
238 if (elapsed > 6.0f && elapsed < 6.833f)
239 anim->fadeGlow += 1.2f * dt;
240
241 // Ignore the following three until we can synchronize with greeter
242
243 // step 3.) background
244 //if (elapsed > 6.0f && elapsed < 6.833f)
245 // anim->fadeBackground -= 0.6f * dt;
246
247 // step 4.) background
248 //if (elapsed > 7.0f)
249 // anim->fadeBackground -= 0.6f * dt;
250
251 // step 5.)
252 //if (elapsed > 6.833f)
253 // anim->fadeLogo -= 1.6f * dt;
254}
255
256int main(int argc, char *argv[])
257{
258 const char vShaderSrcSpinner[] =
259 "attribute vec4 vPosition; \n"
260 "attribute vec2 aTexCoords; \n"
261 "uniform float theta; \n"
262 "varying vec2 vTexCoords; \n"
263 "void main() \n"
264 "{ \n"
265 " float c = cos(theta); \n"
266 " float s = sin(theta); \n"
267 " mat2 m; \n"
268 " m[0] = vec2(c, s); \n"
269 " m[1] = vec2(-s, c); \n"
270 " vTexCoords = m * aTexCoords + vec2 (0.5, 0.5); \n"
271 " gl_Position = vec4(vPosition.xy, -1.0, 1.0); \n"
272 "} \n";
273
274 const char fShaderSrcGlow[] =
275 "precision mediump float; \n"
276 "varying vec2 vTexCoords; \n"
277 "uniform sampler2D uSampler; \n"
278 "uniform float uFadeGlow; \n"
279 "void main() \n"
280 "{ \n"
281 " // swizzle because texture was created with cairo\n"
282 " vec4 col = texture2D(uSampler, vTexCoords).bgra; \n"
283 " float r = col.r * uFadeGlow; \n"
284 " float g = col.g * uFadeGlow; \n"
285 " float b = col.b * uFadeGlow; \n"
286 " float a = col.a * uFadeGlow; \n"
287 " gl_FragColor = vec4(r, g, b, a); \n"
288 "} \n";
289
290 const char fShaderSrcLogo[] =
291 "precision mediump float; \n"
292 "varying vec2 vTexCoords; \n"
293 "uniform sampler2D uSampler; \n"
294 "uniform float uFadeLogo; \n"
295 "void main() \n"
296 "{ \n"
297 " // swizzle because texture was created with cairo\n"
298 " vec4 col = texture2D(uSampler, vTexCoords).bgra; \n"
299 " float r = col.r * uFadeLogo; \n"
300 " float g = col.g * uFadeLogo; \n"
301 " float b = col.b * uFadeLogo; \n"
302 " float a = col.a * uFadeLogo; \n"
303 " gl_FragColor = vec4(r, g, b, a); \n"
304 "} \n";
305
306 GLuint prog[2];
307 GLuint texture[2];
308 GLint vpos[2];
309 GLint theta;
310 GLint fadeGlow;
311 GLint fadeLogo;
312 GLint aTexCoords[2];
313 GLint sampler[2];
314 unsigned int width = 0;
315 unsigned int height = 0;
316
317 if (!mir_eglapp_init(argc, argv, &width, &height))
318 return 1;
319
320 double pixelSize = (double) get_gu () * 11.18;
321 double halfRealWidth = ((2.0 / (double) width) * pixelSize) / 2.0;
322 double halfRealHeight = ((2.0 / (double) height) * pixelSize) / 2.0;
323
324 const GLfloat vertices[] =
325 {
326 halfRealWidth, halfRealHeight,
327 halfRealWidth, -halfRealHeight,
328 -halfRealWidth, halfRealHeight,
329 -halfRealWidth, -halfRealHeight,
330 };
331
332 const GLfloat texCoordsSpinner[] =
333 {
334 -0.5f, 0.5f,
335 -0.5f, -0.5f,
336 0.5f, 0.5f,
337 0.5f, -0.5f,
338 };
339
340 prog[0] = createShaderProgram (vShaderSrcSpinner, fShaderSrcGlow);
341 prog[1] = createShaderProgram (vShaderSrcSpinner, fShaderSrcLogo);
342
343 // setup viewport and projection
344 glClearColor(BLACK, mir_eglapp_background_opacity);
345 glViewport(0, 0, width, height);
346
347 // setup proper GL-blending
348 glEnable(GL_BLEND);
349 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
350 glBlendEquation(GL_FUNC_ADD);
351
352 // get locations of shader-attributes/uniforms
353 vpos[0] = glGetAttribLocation(prog[0], "vPosition");
354 aTexCoords[0] = glGetAttribLocation(prog[0], "aTexCoords");
355 theta = glGetUniformLocation(prog[0], "theta");
356 sampler[0] = glGetUniformLocation(prog[0], "uSampler");
357 fadeGlow = glGetUniformLocation(prog[0], "uFadeGlow");
358 vpos[1] = glGetAttribLocation(prog[1], "vPosition");
359 aTexCoords[1] = glGetAttribLocation(prog[1], "aTexCoords");
360 sampler[1] = glGetUniformLocation(prog[1], "uSampler");
361 fadeLogo = glGetUniformLocation(prog[1], "uFadeLogo");
362
363 // create and upload spinner-artwork
364 glGenTextures(2, texture);
365 uploadTexture(texture[0], PKGDATADIR "/spinner-glow.png");
366 uploadTexture(texture[1], PKGDATADIR "/spinner-logo.png");
367
368 // bunch of shader-attributes to enable
369 glVertexAttribPointer(vpos[0], 2, GL_FLOAT, GL_FALSE, 0, vertices);
370 glVertexAttribPointer(vpos[1], 2, GL_FLOAT, GL_FALSE, 0, vertices);
371 glVertexAttribPointer(aTexCoords[0], 2, GL_FLOAT, GL_FALSE, 0, texCoordsSpinner);
372 glVertexAttribPointer(aTexCoords[1], 2, GL_FLOAT, GL_FALSE, 0, texCoordsSpinner);
373 glEnableVertexAttribArray(vpos[0]);
374 glEnableVertexAttribArray(vpos[1]);
375 glEnableVertexAttribArray(aTexCoords[0]);
376 glEnableVertexAttribArray(aTexCoords[1]);
377 glActiveTexture(GL_TEXTURE0);
378
379 AnimationValues anim = {0.0, 0.0, 1.0, 0.0, 0.0};
380 GTimer* timer = g_timer_new ();
381
382 while (mir_eglapp_running())
383 {
384 glClearColor(BLACK, anim.fadeBackground);
385 glClear(GL_COLOR_BUFFER_BIT);
386
387 // draw glow
388 glUseProgram(prog[0]);
389 glBindTexture(GL_TEXTURE_2D, texture[0]);
390 glUniform1i(sampler[0], 0);
391 glUniform1f(theta, anim.angle);
392 glUniform1f(fadeGlow, anim.fadeGlow);
393 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
394
395 // draw logo
396 glUseProgram(prog[1]);
397 glBindTexture(GL_TEXTURE_2D, texture[1]);
398 glUniform1i(sampler[1], 0);
399 glUniform1f(theta, anim.angle);
400 glUniform1f(fadeLogo, anim.fadeLogo);
401 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
402
403 // update animation variable
404 updateAnimation (timer, &anim);
405
406 mir_eglapp_swap_buffers();
407 }
408
409 mir_eglapp_shutdown();
410
411 glDeleteTextures(2, texture);
412 g_timer_destroy (timer);
413
414 return 0;
415}
0416
=== added file 'spinner/spinner-glow.png'
1Binary files spinner/spinner-glow.png 1970-01-01 00:00:00 +0000 and spinner/spinner-glow.png 2014-05-06 20:06:39 +0000 differ417Binary 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
=== added file 'spinner/spinner-logo.png'
2Binary files spinner/spinner-logo.png 1970-01-01 00:00:00 +0000 and spinner/spinner-logo.png 2014-05-06 20:06:39 +0000 differ418Binary 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
=== modified file 'src/CMakeLists.txt'
--- src/CMakeLists.txt 2013-10-31 19:16:23 +0000
+++ src/CMakeLists.txt 2014-05-06 20:06:39 +0000
@@ -39,9 +39,16 @@
39include_directories(39include_directories(
40 ${CMAKE_CURRENT_SOURCE_DIR}40 ${CMAKE_CURRENT_SOURCE_DIR}
41 ${CMAKE_CURRENT_BINARY_DIR}41 ${CMAKE_CURRENT_BINARY_DIR}
42 ${Boost_INCLUDE_DIRS}
43 ${GLESv2_INCLUDE_DIRS}
44 ${MIRSERVER_INCLUDE_DIRS}
45)
46add_definitions(
47 -DDEFAULT_SPINNER="${CMAKE_INSTALL_FULL_BINDIR}/unity-system-compositor-spinner"
42)48)
4349
44# Link against libmirserver50# Link against libmirserver
51link_directories(${MIRSERVER_LIBRARY_DIRS})
45target_link_libraries(unity-system-compositor52target_link_libraries(unity-system-compositor
46 mirserver53 mirserver
47 pthread54 pthread
4855
=== modified file 'src/system_compositor.cpp'
--- src/system_compositor.cpp 2014-04-15 20:47:54 +0000
+++ src/system_compositor.cpp 2014-05-06 20:06:39 +0000
@@ -48,9 +48,10 @@
48class SystemCompositorShell : public mf::Shell48class SystemCompositorShell : public mf::Shell
49{49{
50public:50public:
51 SystemCompositorShell(std::shared_ptr<mf::Shell> const& self,51 SystemCompositorShell(SystemCompositor *compositor,
52 std::shared_ptr<mf::Shell> const& self,
52 std::shared_ptr<msh::FocusController> const& focus_controller)53 std::shared_ptr<msh::FocusController> const& focus_controller)
53 : self(self), focus_controller{focus_controller} {}54 : compositor{compositor}, self(self), focus_controller{focus_controller} {}
5455
55 std::shared_ptr<mf::Session> session_named(std::string const& name)56 std::shared_ptr<mf::Session> session_named(std::string const& name)
56 {57 {
@@ -60,42 +61,72 @@
60 void set_active_session(std::string const& name)61 void set_active_session(std::string const& name)
61 {62 {
62 active_session = name;63 active_session = name;
6364 update_session_focus();
64 if (auto session = std::static_pointer_cast<msc::Session>(session_named(name)))
65 focus_controller->set_focus_to(session);
66 else
67 std::cerr << "Unable to set active session, unknown client name " << name << std::endl;
68 }65 }
6966
70 void set_next_session(std::string const& name)67 void set_next_session(std::string const& name)
71 {68 {
72 if (auto const session = std::static_pointer_cast<msc::Session>(session_named(name)))69 next_session = name;
73 {70 update_session_focus();
74 focus_controller->set_focus_to(session); // raise session inside its depth id set
75 set_active_session(active_session); // to restore input focus to where it should be
76 }
77 else
78 std::cerr << "Unable to set next session, unknown client name " << name << std::endl;
79 }71 }
8072
81private:73private:
74 void update_session_focus()
75 {
76 auto spinner = std::static_pointer_cast<msc::Session>(session_named(spinner_session));
77 auto next = std::static_pointer_cast<msc::Session>(session_named(next_session));
78 auto active = std::static_pointer_cast<msc::Session>(session_named(active_session));
79
80 if (spinner)
81 spinner->hide();
82
83 if (next)
84 {
85 std::cerr << "Setting next focus to session " << next_session;
86 focus_controller->set_focus_to(next);
87 }
88 else if (spinner)
89 {
90 std::cerr << "Setting next focus to spinner";
91 spinner->show();
92 focus_controller->set_focus_to(spinner);
93 }
94
95 if (active)
96 {
97 std::cerr << "; active focus to session " << active_session << std::endl;
98 focus_controller->set_focus_to(active);
99 }
100 else if (spinner)
101 {
102 std::cerr << "; active focus to spinner" << std::endl;
103 spinner->show();
104 focus_controller->set_focus_to(spinner);
105 }
106 }
107
82 std::shared_ptr<mf::Session> open_session(108 std::shared_ptr<mf::Session> open_session(
83 pid_t client_pid,109 pid_t client_pid,
84 std::string const& name,110 std::string const& name,
85 std::shared_ptr<mf::EventSink> const& sink)111 std::shared_ptr<mf::EventSink> const& sink)
86 {112 {
113 std::cerr << "Opening session " << name << std::endl;
87 auto result = self->open_session(client_pid, name, sink);114 auto result = self->open_session(client_pid, name, sink);
88 sessions[name] = result;115 sessions[name] = result;
89116
90 // Opening a new session will steal focus from our active session, so117 if (client_pid == compositor->get_spinner_pid())
91 // restore the focus if needed.118 spinner_session = name;
92 set_active_session(active_session);
93119
94 return result;120 return result;
95 }121 }
96122
97 void close_session(std::shared_ptr<mf::Session> const& session)123 void close_session(std::shared_ptr<mf::Session> const& session)
98 {124 {
125 std::cerr << "Closing session " << session->name() << std::endl;
126
127 if (session->name() == spinner_session)
128 spinner_session = "";
129
99 sessions.erase(session->name());130 sessions.erase(session->name());
100 self->close_session(session);131 self->close_session(session);
101 }132 }
@@ -110,12 +141,19 @@
110 void handle_surface_created(std::shared_ptr<mf::Session> const& session)141 void handle_surface_created(std::shared_ptr<mf::Session> const& session)
111 {142 {
112 self->handle_surface_created(session);143 self->handle_surface_created(session);
144
145 // Opening a new surface will steal focus from our active surface, so
146 // restore the focus if needed.
147 update_session_focus();
113 }148 }
114149
150 SystemCompositor *compositor;
115 std::shared_ptr<mf::Shell> const self;151 std::shared_ptr<mf::Shell> const self;
116 std::shared_ptr<msh::FocusController> const focus_controller;152 std::shared_ptr<msh::FocusController> const focus_controller;
117 std::map<std::string, std::shared_ptr<mf::Session>> sessions;153 std::map<std::string, std::shared_ptr<mf::Session>> sessions;
118 std::string active_session;154 std::string active_session;
155 std::string next_session;
156 std::string spinner_session;
119};157};
120158
121class SystemCompositorServerConfiguration : public mir::DefaultServerConfiguration159class SystemCompositorServerConfiguration : public mir::DefaultServerConfiguration
@@ -158,6 +196,15 @@
158 return x;196 return x;
159 }197 }
160198
199 std::string spinner()
200 {
201 // TODO: once our default spinner is ready for use everywhere, replace
202 // default value with DEFAULT_SPINNER instead of the empty string.
203 auto x = the_options()->get("spinner", "");
204 boost::trim(x);
205 return x;
206 }
207
161 bool public_socket()208 bool public_socket()
162 {209 {
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);
@@ -217,6 +264,7 @@
217 return sc_shell([this]264 return sc_shell([this]
218 {265 {
219 return std::make_shared<SystemCompositorShell>(266 return std::make_shared<SystemCompositorShell>(
267 compositor,
220 mir::DefaultServerConfiguration::the_frontend_shell(),268 mir::DefaultServerConfiguration::the_frontend_shell(),
221 the_focus_controller());269 the_focus_controller());
222 });270 });
@@ -244,6 +292,7 @@
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]")
245 ("blacklist", po::value<std::string>(), "Video blacklist regex to use")293 ("blacklist", po::value<std::string>(), "Video blacklist regex to use")
246 ("version", "Show version of Unity System Compositor")294 ("version", "Show version of Unity System Compositor")
295 ("spinner", po::value<std::string>(), "Path to spinner executable")
247 ("public-socket", po::value<bool>(), "Make the socket file publicly writable")296 ("public-socket", po::value<bool>(), "Make the socket file publicly writable")
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]")
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)");
@@ -354,6 +403,11 @@
354 active_session->set_lifecycle_state(mir_lifecycle_state_resumed);403 active_session->set_lifecycle_state(mir_lifecycle_state_resumed);
355}404}
356405
406pid_t SystemCompositor::get_spinner_pid() const
407{
408 return spinner_process.pid();
409}
410
357void SystemCompositor::set_active_session(std::string client_name)411void SystemCompositor::set_active_session(std::string client_name)
358{412{
359 std::cerr << "set_active_session" << std::endl;413 std::cerr << "set_active_session" << std::endl;
@@ -381,9 +435,22 @@
381 io_service.run();435 io_service.run();
382}436}
383437
438void SystemCompositor::launch_spinner()
439{
440 if (config->spinner().empty())
441 return;
442
443 // Launch spinner process to provide default background when a session isn't ready
444 QStringList env = QProcess::systemEnvironment();
445 env << "MIR_SOCKET=" + QString(config->get_socket_file().c_str());
446 spinner_process.setEnvironment(env);
447 spinner_process.start(config->spinner().c_str());
448}
449
384void SystemCompositor::qt_main(int argc, char **argv)450void SystemCompositor::qt_main(int argc, char **argv)
385{451{
386 QCoreApplication app(argc, argv);452 QCoreApplication app(argc, argv);
387 DBusScreen dbus_screen(config, config->power_off_delay());453 DBusScreen dbus_screen(config, config->power_off_delay());
454 launch_spinner();
388 app.exec();455 app.exec();
389}456}
390457
=== modified file 'src/system_compositor.h'
--- src/system_compositor.h 2014-04-15 20:47:54 +0000
+++ src/system_compositor.h 2014-05-06 20:06:39 +0000
@@ -20,6 +20,7 @@
20#define SYSTEM_COMPOSITOR_H_20#define SYSTEM_COMPOSITOR_H_
2121
22#include "dm_connection.h"22#include "dm_connection.h"
23#include <QProcess>
2324
24namespace mir { namespace scene { class Session; } }25namespace mir { namespace scene { class Session; } }
2526
@@ -32,17 +33,20 @@
32 void run(int argc, char **argv);33 void run(int argc, char **argv);
33 void pause();34 void pause();
34 void resume();35 void resume();
36 pid_t get_spinner_pid() const;
3537
36private:38private:
37 std::shared_ptr<SystemCompositorServerConfiguration> config;39 std::shared_ptr<SystemCompositorServerConfiguration> config;
38 std::shared_ptr<SystemCompositorShell> shell;40 std::shared_ptr<SystemCompositorShell> shell;
39 boost::asio::io_service io_service;41 boost::asio::io_service io_service;
40 std::shared_ptr<DMConnection> dm_connection;42 std::shared_ptr<DMConnection> dm_connection;
43 QProcess spinner_process;
4144
42 void set_active_session(std::string client_name);45 void set_active_session(std::string client_name);
43 void set_next_session(std::string client_name);46 void set_next_session(std::string client_name);
44 void main();47 void main();
45 void qt_main(int argc, char **argv);48 void qt_main(int argc, char **argv);
49 void launch_spinner();
46};50};
4751
48#endif /* SYSTEM_COMPOSITOR_H_ */52#endif /* SYSTEM_COMPOSITOR_H_ */

Subscribers

People subscribed via source and target branches