blob: e78d428be9027b6edb269dc0d0ab5e56ff6acc95 [file] [log] [blame]
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -07001/*
David Sodman8ef20062015-01-06 09:23:40 -08002 * Copyright 2014 The Chromium OS Authors. All rights reserved.
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -07003 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
Dominik Behr580462b2014-11-20 13:50:05 -08007#include <getopt.h>
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -07008#include <libtsm.h>
Dominik Behr580462b2014-11-20 13:50:05 -08009#include <memory.h>
10#include <stdbool.h>
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070011#include <stdio.h>
12#include <stdlib.h>
13#include <unistd.h>
14
Dominik Behr580462b2014-11-20 13:50:05 -080015#include "dbus.h"
Dominik Behr44e07e62016-01-13 19:43:57 -080016#include "dbus_interface.h"
Dominik Behr5239cca2016-01-21 18:22:04 -080017#include "dev.h"
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070018#include "input.h"
Dominik Behr44e07e62016-01-13 19:43:57 -080019#include "main.h"
Dominik Behr580462b2014-11-20 13:50:05 -080020#include "splash.h"
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070021#include "term.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070022#include "util.h"
Stéphane Marchesin62561a12015-12-11 17:32:37 -080023#include "video.h"
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070024
David Sodmanbbcb0522014-09-19 10:34:07 -070025#define FLAG_CLEAR 'c'
26#define FLAG_DAEMON 'd'
27#define FLAG_DEV_MODE 'e'
28#define FLAG_FRAME_INTERVAL 'f'
29#define FLAG_GAMMA 'g'
Dominik Behr32a7c892015-10-09 15:47:53 -070030#define FLAG_IMAGE 'i'
31#define FLAG_IMAGE_HIRES 'I'
David Sodman8ef20062015-01-06 09:23:40 -080032#define FLAG_LOOP_START 'l'
33#define FLAG_LOOP_INTERVAL 'L'
34#define FLAG_LOOP_OFFSET 'o'
35#define FLAG_OFFSET 'O'
David Sodmanbbcb0522014-09-19 10:34:07 -070036#define FLAG_PRINT_RESOLUTION 'p'
37
38static struct option command_options[] = {
39 { "clear", required_argument, NULL, FLAG_CLEAR },
40 { "daemon", no_argument, NULL, FLAG_DAEMON },
41 { "dev-mode", no_argument, NULL, FLAG_DEV_MODE },
42 { "frame-interval", required_argument, NULL, FLAG_FRAME_INTERVAL },
43 { "gamma", required_argument, NULL, FLAG_GAMMA },
Dominik Behr32a7c892015-10-09 15:47:53 -070044 { "image", required_argument, NULL, FLAG_IMAGE },
45 { "image-hires", required_argument, NULL, FLAG_IMAGE_HIRES },
David Sodman8ef20062015-01-06 09:23:40 -080046 { "loop-start", required_argument, NULL, FLAG_LOOP_START },
47 { "loop-interval", required_argument, NULL, FLAG_LOOP_INTERVAL },
48 { "loop-offset", required_argument, NULL, FLAG_LOOP_OFFSET },
49 { "offset", required_argument, NULL, FLAG_OFFSET },
David Sodmanbbcb0522014-09-19 10:34:07 -070050 { "print-resolution", no_argument, NULL, FLAG_PRINT_RESOLUTION },
51 { NULL, 0, NULL, 0 }
52};
53
David Sodman8ef20062015-01-06 09:23:40 -080054typedef struct {
David Sodman8ef20062015-01-06 09:23:40 -080055 bool standalone;
David Sodman8ef20062015-01-06 09:23:40 -080056} commandflags_t;
Dominik Behr580462b2014-11-20 13:50:05 -080057
Stéphane Marchesin8fc13522015-12-14 17:02:28 -080058static void parse_offset(char* param, int32_t* x, int32_t* y)
David Sodman8ef20062015-01-06 09:23:40 -080059{
60 char* token;
61 char* saveptr;
62
63 token = strtok_r(param, ",", &saveptr);
64 if (token)
65 *x = strtol(token, NULL, 0);
66
67 token = strtok_r(NULL, ",", &saveptr);
68 if (token)
69 *y = strtol(token, NULL, 0);
70}
David Sodmanbbcb0522014-09-19 10:34:07 -070071
Dominik Behr44e07e62016-01-13 19:43:57 -080072int main_process_events(uint32_t usec)
73{
74 terminal_t* terminal;
75 terminal_t* new_terminal;
76 fd_set read_set, exception_set;
Dominik Behrd7112672016-01-20 16:59:34 -080077 int maxfd = -1;
Dominik Behr44e07e62016-01-13 19:43:57 -080078 int sstat;
79 struct timeval tm;
80 struct timeval* ptm;
81
82 terminal = term_get_current_terminal();
83
84 FD_ZERO(&read_set);
85 FD_ZERO(&exception_set);
86
Dominik Behrd7112672016-01-20 16:59:34 -080087 dbus_add_fds(&read_set, &exception_set, &maxfd);
Dominik Behrd7112672016-01-20 16:59:34 -080088 input_add_fds(&read_set, &exception_set, &maxfd);
Dominik Behr5239cca2016-01-21 18:22:04 -080089 dev_add_fds(&read_set, &exception_set, &maxfd);
Dominik Behr44e07e62016-01-13 19:43:57 -080090
91 for (int i = 0; i < MAX_TERMINALS; i++) {
92 if (term_is_valid(term_get_terminal(i))) {
93 terminal_t* current_term = term_get_terminal(i);
Dominik Behrd7112672016-01-20 16:59:34 -080094 term_add_fds(current_term, &read_set, &exception_set, &maxfd);
Dominik Behr44e07e62016-01-13 19:43:57 -080095 }
96 }
97
98 if (usec) {
99 ptm = &tm;
100 tm.tv_sec = 0;
101 tm.tv_usec = usec;
102 } else
103 ptm = NULL;
104
Dominik Behrd7112672016-01-20 16:59:34 -0800105 sstat = select(maxfd + 1, &read_set, NULL, &exception_set, ptm);
Dominik Behr44e07e62016-01-13 19:43:57 -0800106 if (sstat == 0)
107 return 0;
108
109 dbus_dispatch_io();
110
111 if (term_exception(terminal, &exception_set))
112 return -1;
113
Dominik Behr5239cca2016-01-21 18:22:04 -0800114 dev_dispatch_io(&read_set, &exception_set);
Dominik Behr44e07e62016-01-13 19:43:57 -0800115 input_dispatch_io(&read_set, &exception_set);
116
117 for (int i = 0; i < MAX_TERMINALS; i++) {
118 if (term_is_valid(term_get_terminal(i))) {
119 terminal_t* current_term = term_get_terminal(i);
120 term_dispatch_io(current_term, &read_set);
121 }
122 }
123
124 if (term_is_valid(terminal)) {
125 if (term_is_child_done(terminal)) {
126 if (terminal == term_get_terminal(SPLASH_TERMINAL)) {
127 /*
128 * Note: reference is not lost because it is still referenced
129 * by the splash_t structure which will ultimately destroy
130 * it, once it's safe to do so
131 */
132 term_set_terminal(SPLASH_TERMINAL, NULL);
133 return -1;
134 }
135 term_set_current_terminal(term_init(true, term_getvideo(terminal)));
136 new_terminal = term_get_current_terminal();
137 if (!term_is_valid(new_terminal)) {
138 return -1;
139 }
140 term_activate(new_terminal);
141 term_close(terminal);
142 }
143 }
144
145 return 0;
146}
147
148int main_loop(bool standalone)
149{
150 terminal_t* terminal;
151 int status;
152
153 if (standalone) {
154 dbus_take_display_ownership();
155 term_set_current_terminal(term_init(true, NULL));
156 terminal = term_get_current_terminal();
157 term_activate(terminal);
158 }
159
160 while (1) {
161 status = main_process_events(0);
162 if (status != 0) {
163 LOG(ERROR, "input process returned %d", status);
164 break;
165 }
166 }
167
168 return 0;
169}
170
171
David Sodmanbbcb0522014-09-19 10:34:07 -0700172int main(int argc, char* argv[])
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700173{
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700174 int ret;
David Sodmanbbcb0522014-09-19 10:34:07 -0700175 int c;
David Sodman8ef20062015-01-06 09:23:40 -0800176 int32_t x, y;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800177 splash_t* splash;
David Sodman8ef20062015-01-06 09:23:40 -0800178 commandflags_t command_flags;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700179
Douglas Anderson4da95cd2015-10-05 15:04:30 -0700180 /* Handle resolution special before splash init */
181 for (;;) {
182 c = getopt_long(argc, argv, "", command_options, NULL);
183 if (c == -1) {
184 break;
185 } else if (c == FLAG_PRINT_RESOLUTION) {
186 video_t *video = video_init();
187 if (!video)
188 return EXIT_FAILURE;
189
190 printf("%d %d", video_getwidth(video),
191 video_getheight(video));
192 video_close(video);
193 return EXIT_SUCCESS;
194 }
195 }
196
197 /* Reset option parsing */
198 optind = 1;
199
Dominik Behr580462b2014-11-20 13:50:05 -0800200 memset(&command_flags, 0, sizeof(command_flags));
201 command_flags.standalone = true;
David Sodmanbbcb0522014-09-19 10:34:07 -0700202
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700203 ret = input_init();
204 if (ret) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700205 LOG(ERROR, "Input init failed");
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700206 return EXIT_FAILURE;
207 }
208
Dominik Behr5239cca2016-01-21 18:22:04 -0800209 ret = dev_init();
210 if (ret) {
211 LOG(ERROR, "Device management init failed");
212 return EXIT_FAILURE;
213 }
214
David Sodmanbf3f2842014-11-12 08:26:58 -0800215 splash = splash_init();
David Sodmanbbcb0522014-09-19 10:34:07 -0700216 if (splash == NULL) {
217 LOG(ERROR, "splash init failed");
218 return EXIT_FAILURE;
219 }
220
221 for (;;) {
222 c = getopt_long(argc, argv, "", command_options, NULL);
223
224 if (c == -1)
225 break;
226
227 switch (c) {
228 case FLAG_CLEAR:
229 splash_set_clear(splash, strtoul(optarg, NULL, 0));
230 break;
231
232 case FLAG_DAEMON:
Dominik Behr580462b2014-11-20 13:50:05 -0800233 command_flags.standalone = false;
David Sodmanbbcb0522014-09-19 10:34:07 -0700234 break;
235
David Sodman8ef20062015-01-06 09:23:40 -0800236 case FLAG_FRAME_INTERVAL:
237 splash_set_default_duration(splash, strtoul(optarg, NULL, 0));
238 break;
239
David Sodmanbbcb0522014-09-19 10:34:07 -0700240 case FLAG_DEV_MODE:
241 splash_set_devmode(splash);
242 break;
243
Dominik Behr32a7c892015-10-09 15:47:53 -0700244 case FLAG_IMAGE:
245 if (!splash_is_hires(splash))
246 splash_add_image(splash, optarg);
247 break;
248
249 case FLAG_IMAGE_HIRES:
250 if (splash_is_hires(splash))
251 splash_add_image(splash, optarg);
252 break;
253
David Sodman8ef20062015-01-06 09:23:40 -0800254 case FLAG_LOOP_START:
255 splash_set_loop_start(splash, strtoul(optarg, NULL, 0));
256 break;
257
258 case FLAG_LOOP_INTERVAL:
259 splash_set_loop_duration(splash, strtoul(optarg, NULL, 0));
260 break;
261
262 case FLAG_LOOP_OFFSET:
263 parse_offset(optarg, &x, &y);
264 splash_set_loop_offset(splash, x, y);
265 break;
266
267 case FLAG_OFFSET:
268 parse_offset(optarg, &x, &y);
269 splash_set_offset(splash, x, y);
270 break;
David Sodmanbbcb0522014-09-19 10:34:07 -0700271 }
272 }
273
Stéphane Marchesinac14d292015-12-14 15:27:18 -0800274 for (int i = optind; i < argc; i++)
David Sodman8ef20062015-01-06 09:23:40 -0800275 splash_add_image(splash, argv[i]);
276
David Sodmanbbcb0522014-09-19 10:34:07 -0700277 /*
278 * The DBUS service launches later than the boot-splash service, and
279 * as a result, when splash_run starts dbus is not yet up, but, by
280 * the time splash_run completes, it is running. At the same time,
281 * splash_run needs dbus to determine when chrome is visible. So,
282 * it creates the dbus object and then passes it back to the caller
283 * who can then pass it to the other objects that need it
284 */
Douglas Anderson4da95cd2015-10-05 15:04:30 -0700285 if (command_flags.standalone == false) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700286 splash_present_term_file(splash);
287 daemonize();
288 }
289 if (splash_num_images(splash) > 0) {
Dominik Behr797a3832016-01-11 15:53:11 -0800290 ret = splash_run(splash);
David Sodmanbbcb0522014-09-19 10:34:07 -0700291 if (ret) {
Yuly Novikov945871e2015-05-23 00:00:41 -0400292 LOG(ERROR, "splash_run failed: %d", ret);
293 return EXIT_FAILURE;
David Sodmanbbcb0522014-09-19 10:34:07 -0700294 }
295 }
David Sodmanf0a925a2015-05-04 11:19:19 -0700296 splash_destroy(splash);
David Sodmanbbcb0522014-09-19 10:34:07 -0700297
298 /*
299 * If splash_run didn't create the dbus object (for example, if
David Sodman8ef20062015-01-06 09:23:40 -0800300 * there are no splash screen images), then go ahead and create
301 * it now
David Sodmanbbcb0522014-09-19 10:34:07 -0700302 */
Dominik Behr797a3832016-01-11 15:53:11 -0800303 if (!dbus_is_initialized()) {
304 dbus_init();
David Sodmanbbcb0522014-09-19 10:34:07 -0700305 }
David Sodman8ef20062015-01-06 09:23:40 -0800306
Dominik Behr44e07e62016-01-13 19:43:57 -0800307 ret = main_loop(command_flags.standalone);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700308
309 input_close();
Dominik Behr5239cca2016-01-21 18:22:04 -0800310 dev_close();
Dominik Behr44e07e62016-01-13 19:43:57 -0800311 dbus_destroy();
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700312
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700313 return ret;
314}