blob: 0fa993649c9a5f1cd4ce6c3397f46518b7a35eee [file] [log] [blame]
David Sodmanbbcb0522014-09-19 10:34:07 -07001/*
2 * Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
David Sodman8ef20062015-01-06 09:23:40 -08007#include <fcntl.h>
David Sodmanbbcb0522014-09-19 10:34:07 -07008#include <stdbool.h>
9#include <stddef.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <sys/mman.h>
14#include <unistd.h>
David Sodmanbbcb0522014-09-19 10:34:07 -070015
David Sodmanbbcb0522014-09-19 10:34:07 -070016#include "dbus_interface.h"
David Sodman8ef20062015-01-06 09:23:40 -080017#include "image.h"
David Sodmanf0a925a2015-05-04 11:19:19 -070018#include "input.h"
David Sodman8ef20062015-01-06 09:23:40 -080019#include "splash.h"
David Sodmanf0a925a2015-05-04 11:19:19 -070020#include "term.h"
David Sodman8ef20062015-01-06 09:23:40 -080021#include "util.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070022
23#define MAX_SPLASH_IMAGES (30)
David Sodmandd5b23e2015-02-18 21:36:38 -080024#define MAX_SPLASH_WAITTIME (8)
David Sodman8ef20062015-01-06 09:23:40 -080025#define DBUS_WAIT_DELAY (50000)
David Sodmanbbcb0522014-09-19 10:34:07 -070026
27typedef struct {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080028 image_t* image;
29 uint32_t duration;
David Sodman8ef20062015-01-06 09:23:40 -080030} splash_frame_t;
David Sodmanbbcb0522014-09-19 10:34:07 -070031
32struct _splash_t {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080033 video_t* video;
34 terminal_t* terminal;
35 int num_images;
36 uint32_t clear;
37 splash_frame_t image_frames[MAX_SPLASH_IMAGES];
38 bool terminated;
39 bool devmode;
40 dbus_t* dbus;
41 int32_t loop_start;
42 uint32_t loop_duration;
43 uint32_t default_duration;
44 int32_t offset_x;
45 int32_t offset_y;
46 int32_t loop_offset_x;
47 int32_t loop_offset_y;
David Sodmanbbcb0522014-09-19 10:34:07 -070048};
49
David Sodmanbf3f2842014-11-12 08:26:58 -080050
51splash_t* splash_init()
David Sodmanbbcb0522014-09-19 10:34:07 -070052{
53 splash_t* splash;
54
55 splash = (splash_t*)calloc(1, sizeof(splash_t));
56 if (splash == NULL)
57 return NULL;
58
David Sodmanbf3f2842014-11-12 08:26:58 -080059 splash->video = video_init();
Yuly Novikov945871e2015-05-23 00:00:41 -040060 if (!splash->video) {
61 free(splash);
62 return NULL;
63 }
64
David Sodmanf0a925a2015-05-04 11:19:19 -070065 splash->terminal = input_create_splash_term(splash->video);
David Sodman8ef20062015-01-06 09:23:40 -080066 splash->loop_start = -1;
67 splash->default_duration = 25;
68 splash->loop_duration = 25;
David Sodmanbbcb0522014-09-19 10:34:07 -070069
David Sodmanf0a925a2015-05-04 11:19:19 -070070 // Hide the cursor on the splash screen
71 term_hide_cursor(splash->terminal);
72
David Sodmanbbcb0522014-09-19 10:34:07 -070073 return splash;
74}
75
76int splash_destroy(splash_t* splash)
77{
David Sodmanf0a925a2015-05-04 11:19:19 -070078 if (splash->terminal) {
79 term_close(splash->terminal);
80 splash->terminal = NULL;
David Sodman8ef20062015-01-06 09:23:40 -080081 }
82 free(splash);
David Sodmanf0a925a2015-05-04 11:19:19 -070083 input_destroy_splash_term();
David Sodmanbbcb0522014-09-19 10:34:07 -070084 return 0;
85}
86
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080087int splash_set_clear(splash_t* splash, uint32_t clear_color)
David Sodmanbbcb0522014-09-19 10:34:07 -070088{
89 splash->clear = clear_color;
90 return 0;
91}
92
David Sodman8ef20062015-01-06 09:23:40 -080093int splash_add_image(splash_t* splash, char* filespec)
David Sodmanbbcb0522014-09-19 10:34:07 -070094{
David Sodman8ef20062015-01-06 09:23:40 -080095 image_t* image;
96 int32_t offset_x, offset_y;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080097 char* filename;
David Sodman8ef20062015-01-06 09:23:40 -080098 uint32_t duration;
David Sodmanbbcb0522014-09-19 10:34:07 -070099 if (splash->num_images >= MAX_SPLASH_IMAGES)
100 return 1;
101
David Sodman8ef20062015-01-06 09:23:40 -0800102 filename = (char*)malloc(strlen(filespec) + 1);
103 parse_filespec(filespec,
104 filename,
105 &offset_x, &offset_y, &duration,
106 splash->default_duration,
107 splash->offset_x,
108 splash->offset_y);
109
110 image = image_create();
111 image_set_filename(image, filename);
112 image_set_offset(image, offset_x, offset_y);
113 splash->image_frames[splash->num_images].image = image;
114 splash->image_frames[splash->num_images].duration = duration;
David Sodmanbbcb0522014-09-19 10:34:07 -0700115 splash->num_images++;
David Sodman8ef20062015-01-06 09:23:40 -0800116
117 free(filename);
David Sodmanbbcb0522014-09-19 10:34:07 -0700118 return 0;
119}
120
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800121static void splash_clear_screen(splash_t* splash)
David Sodmanbbcb0522014-09-19 10:34:07 -0700122{
David Sodmanf0a925a2015-05-04 11:19:19 -0700123 term_set_background(splash->terminal, splash->clear);
David Sodmanbbcb0522014-09-19 10:34:07 -0700124}
125
126int splash_run(splash_t* splash, dbus_t** dbus)
127{
128 int i;
David Sodmanbbcb0522014-09-19 10:34:07 -0700129 int status;
David Sodmanbbcb0522014-09-19 10:34:07 -0700130 int64_t last_show_ms;
131 int64_t now_ms;
132 int64_t sleep_ms;
133 struct timespec sleep_spec;
134 int fd;
135 int num_written;
David Sodman8ef20062015-01-06 09:23:40 -0800136 image_t* image;
137 uint32_t duration;
David Sodmanbbcb0522014-09-19 10:34:07 -0700138
David Sodmanbbcb0522014-09-19 10:34:07 -0700139 /*
140 * First draw the actual splash screen
141 */
David Sodmanf0a925a2015-05-04 11:19:19 -0700142 splash_clear_screen(splash);
143 term_activate(splash->terminal);
144 last_show_ms = -1;
145 for (i = 0; i < splash->num_images; i++) {
146 image = splash->image_frames[i].image;
147 status = image_load_image_from_file(image);
148 if (status != 0) {
149 LOG(WARNING, "image_load_image_from_file failed: %d", status);
150 break;
David Sodman8ef20062015-01-06 09:23:40 -0800151 }
152
David Sodmanf0a925a2015-05-04 11:19:19 -0700153 now_ms = get_monotonic_time_ms();
154 if (last_show_ms > 0) {
155 if (splash->loop_start >= 0 && i >= splash->loop_start)
156 duration = splash->loop_duration;
157 else
158 duration = splash->image_frames[i].duration;
159 sleep_ms = duration - (now_ms - last_show_ms);
160 if (sleep_ms > 0) {
161 sleep_spec.tv_sec = sleep_ms / MS_PER_SEC;
162 sleep_spec.tv_nsec = (sleep_ms % MS_PER_SEC) * NS_PER_MS;
163 nanosleep(&sleep_spec, NULL);
164 }
165 }
166
167 now_ms = get_monotonic_time_ms();
168
169 if (i >= splash->loop_start) {
170 image_set_offset(image,
171 splash->loop_offset_x,
172 splash->loop_offset_y);
173 }
174
175 status = term_show_image(splash->terminal, image);
176 if (status != 0) {
177 LOG(WARNING, "term_show_image failed: %d", status);
178 break;
179 }
180 status = input_process(splash->terminal, 1);
181 if (status != 0) {
182 LOG(WARNING, "input_process failed: %d", status);
183 break;
184 }
185 last_show_ms = now_ms;
186
187 if ((splash->loop_start >= 0) &&
188 (splash->loop_start < splash->num_images)) {
189 if (i == splash->num_images - 1)
190 i = splash->loop_start - 1;
191 }
192
193 image_release(image);
194 }
195
196 for (i = 0; i < splash->num_images; i++) {
197 image_destroy(splash->image_frames[i].image);
198 }
199
200 input_set_current(NULL);
201
202 /*
203 * Now Chrome can take over
204 */
205 video_release(splash->video);
206 video_unlock(splash->video);
207
208 if (dbus != NULL) {
209 do {
210 *dbus = dbus_init();
211 usleep(DBUS_WAIT_DELAY);
212 } while (*dbus == NULL);
213 splash_set_dbus(splash, *dbus);
214 }
215
216 if (splash->devmode) {
David Sodman5c9afa72015-02-14 09:32:53 -0800217 /*
David Sodmanf0a925a2015-05-04 11:19:19 -0700218 * Now set drm_master_relax so that we can transfer drm_master between
219 * chrome and frecon
David Sodman5c9afa72015-02-14 09:32:53 -0800220 */
David Sodmanf0a925a2015-05-04 11:19:19 -0700221 fd = open("/sys/kernel/debug/dri/drm_master_relax", O_WRONLY);
222 if (fd != -1) {
223 num_written = write(fd, "Y", 1);
224 close(fd);
David Sodmanbbcb0522014-09-19 10:34:07 -0700225
David Sodmanbbcb0522014-09-19 10:34:07 -0700226 /*
David Sodmanf0a925a2015-05-04 11:19:19 -0700227 * If we can't set drm_master relax, then transitions between chrome
228 * and frecon won't work. No point in having frecon hold any resources
David Sodmanbbcb0522014-09-19 10:34:07 -0700229 */
David Sodmanf0a925a2015-05-04 11:19:19 -0700230 if (num_written != 1) {
231 LOG(ERROR, "Unable to set drm_master_relax");
232 splash->devmode = false;
David Sodmanbbcb0522014-09-19 10:34:07 -0700233 }
David Sodmandd5b23e2015-02-18 21:36:38 -0800234 } else {
David Sodmanf0a925a2015-05-04 11:19:19 -0700235 LOG(ERROR, "unable to open drm_master_relax");
David Sodmanbbcb0522014-09-19 10:34:07 -0700236 }
David Sodmanf0a925a2015-05-04 11:19:19 -0700237 } else {
238 /*
239 * Below, we will wait for Chrome to appear above the splash
240 * image. If we are not in dev mode, wait and then exit
241 */
242 sleep(MAX_SPLASH_WAITTIME);
243 exit(EXIT_SUCCESS);
David Sodmanbbcb0522014-09-19 10:34:07 -0700244 }
David Sodman003faed2014-11-03 09:02:10 -0800245
David Sodman8ef20062015-01-06 09:23:40 -0800246 if (splash->dbus) {
247 (void)dbus_method_call0(splash->dbus,
248 kLibCrosServiceName,
249 kLibCrosServicePath,
250 kLibCrosServiceInterface,
251 kTakeDisplayOwnership);
252 }
David Sodmanf348b0d2015-02-10 08:34:57 -0800253
254 /*
255 * Finally, wait until chrome has drawn on top of the splash. In dev mode,
256 * wait a few seconds for chrome to show up.
257 */
258 sleep(MAX_SPLASH_WAITTIME);
David Sodmanbbcb0522014-09-19 10:34:07 -0700259 return status;
260}
261
David Sodman8ef20062015-01-06 09:23:40 -0800262void splash_set_offset(splash_t* splash, int32_t x, int32_t y)
263{
264 if (splash) {
265 splash->offset_x = x;
266 splash->offset_y = y;
267 }
268}
269
David Sodmanbbcb0522014-09-19 10:34:07 -0700270void splash_set_dbus(splash_t* splash, dbus_t* dbus)
271{
David Sodman8ef20062015-01-06 09:23:40 -0800272 if (splash)
273 splash->dbus = dbus;
David Sodmanbbcb0522014-09-19 10:34:07 -0700274}
275
276void splash_set_devmode(splash_t* splash)
277{
David Sodman8ef20062015-01-06 09:23:40 -0800278 if (splash)
279 splash->devmode = true;
280}
281
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800282int splash_num_images(splash_t* splash)
David Sodman8ef20062015-01-06 09:23:40 -0800283{
284 if (splash)
285 return splash->num_images;
286
287 return 0;
288}
289
290void splash_set_default_duration(splash_t* splash, uint32_t duration)
291{
292 if (splash)
293 splash->default_duration = duration;
294}
295
296void splash_set_loop_start(splash_t* splash, int32_t loop_start)
297{
298 if (splash)
299 splash->loop_start = loop_start;
300}
301
302void splash_set_loop_duration(splash_t* splash, uint32_t duration)
303{
304 if (splash)
305 splash->loop_duration = duration;
306}
307
308void splash_set_loop_offset(splash_t* splash, int32_t x, int32_t y)
309{
310 if (splash) {
311 splash->loop_offset_x = x;
312 splash->loop_offset_y = y;
313 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700314}
David Sodmanf0a925a2015-05-04 11:19:19 -0700315
316void splash_present_term_file(splash_t* splash)
317{
318 fprintf(stdout, "%s\n", term_get_ptsname(splash->terminal));
319}
Dominik Behr32a7c892015-10-09 15:47:53 -0700320
321int splash_is_hires(splash_t* splash)
322{
323 if (splash && splash->video)
324 return video_getwidth(splash->video) > 1920;
325 return 0;
326}