blob: 217bd5aa61b48364917180b7e538e03421ba01d2 [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"
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070017#include "input.h"
Dominik Behr44e07e62016-01-13 19:43:57 -080018#include "main.h"
Dominik Behr580462b2014-11-20 13:50:05 -080019#include "splash.h"
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070020#include "term.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070021#include "util.h"
Stéphane Marchesin62561a12015-12-11 17:32:37 -080022#include "video.h"
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070023
David Sodmanbbcb0522014-09-19 10:34:07 -070024#define FLAG_CLEAR 'c'
25#define FLAG_DAEMON 'd'
26#define FLAG_DEV_MODE 'e'
27#define FLAG_FRAME_INTERVAL 'f'
28#define FLAG_GAMMA 'g'
Dominik Behr32a7c892015-10-09 15:47:53 -070029#define FLAG_IMAGE 'i'
30#define FLAG_IMAGE_HIRES 'I'
David Sodman8ef20062015-01-06 09:23:40 -080031#define FLAG_LOOP_START 'l'
32#define FLAG_LOOP_INTERVAL 'L'
33#define FLAG_LOOP_OFFSET 'o'
34#define FLAG_OFFSET 'O'
David Sodmanbbcb0522014-09-19 10:34:07 -070035#define FLAG_PRINT_RESOLUTION 'p'
36
37static struct option command_options[] = {
38 { "clear", required_argument, NULL, FLAG_CLEAR },
39 { "daemon", no_argument, NULL, FLAG_DAEMON },
40 { "dev-mode", no_argument, NULL, FLAG_DEV_MODE },
41 { "frame-interval", required_argument, NULL, FLAG_FRAME_INTERVAL },
42 { "gamma", required_argument, NULL, FLAG_GAMMA },
Dominik Behr32a7c892015-10-09 15:47:53 -070043 { "image", required_argument, NULL, FLAG_IMAGE },
44 { "image-hires", required_argument, NULL, FLAG_IMAGE_HIRES },
David Sodman8ef20062015-01-06 09:23:40 -080045 { "loop-start", required_argument, NULL, FLAG_LOOP_START },
46 { "loop-interval", required_argument, NULL, FLAG_LOOP_INTERVAL },
47 { "loop-offset", required_argument, NULL, FLAG_LOOP_OFFSET },
48 { "offset", required_argument, NULL, FLAG_OFFSET },
David Sodmanbbcb0522014-09-19 10:34:07 -070049 { "print-resolution", no_argument, NULL, FLAG_PRINT_RESOLUTION },
50 { NULL, 0, NULL, 0 }
51};
52
David Sodman8ef20062015-01-06 09:23:40 -080053typedef struct {
David Sodman8ef20062015-01-06 09:23:40 -080054 bool standalone;
David Sodman8ef20062015-01-06 09:23:40 -080055} commandflags_t;
Dominik Behr580462b2014-11-20 13:50:05 -080056
Stéphane Marchesin8fc13522015-12-14 17:02:28 -080057static void parse_offset(char* param, int32_t* x, int32_t* y)
David Sodman8ef20062015-01-06 09:23:40 -080058{
59 char* token;
60 char* saveptr;
61
62 token = strtok_r(param, ",", &saveptr);
63 if (token)
64 *x = strtol(token, NULL, 0);
65
66 token = strtok_r(NULL, ",", &saveptr);
67 if (token)
68 *y = strtol(token, NULL, 0);
69}
David Sodmanbbcb0522014-09-19 10:34:07 -070070
Dominik Behr44e07e62016-01-13 19:43:57 -080071int main_process_events(uint32_t usec)
72{
73 terminal_t* terminal;
74 terminal_t* new_terminal;
75 fd_set read_set, exception_set;
76 int maxfd;
77 int sstat;
78 struct timeval tm;
79 struct timeval* ptm;
80
81 terminal = term_get_current_terminal();
82
83 FD_ZERO(&read_set);
84 FD_ZERO(&exception_set);
85
86 maxfd = dbus_add_fds(&read_set, &exception_set) + 1;
87
88 maxfd = MAX(maxfd, input_add_fds(&read_set, &exception_set)) + 1;
89
90 for (int i = 0; i < MAX_TERMINALS; i++) {
91 if (term_is_valid(term_get_terminal(i))) {
92 terminal_t* current_term = term_get_terminal(i);
93 maxfd = MAX(maxfd, term_add_fds(current_term, &read_set, &exception_set)) + 1;
94 }
95 }
96
97 if (usec) {
98 ptm = &tm;
99 tm.tv_sec = 0;
100 tm.tv_usec = usec;
101 } else
102 ptm = NULL;
103
104 sstat = select(maxfd, &read_set, NULL, &exception_set, ptm);
105 if (sstat == 0)
106 return 0;
107
108 dbus_dispatch_io();
109
110 if (term_exception(terminal, &exception_set))
111 return -1;
112
113 input_dispatch_io(&read_set, &exception_set);
114
115 for (int i = 0; i < MAX_TERMINALS; i++) {
116 if (term_is_valid(term_get_terminal(i))) {
117 terminal_t* current_term = term_get_terminal(i);
118 term_dispatch_io(current_term, &read_set);
119 }
120 }
121
122 if (term_is_valid(terminal)) {
123 if (term_is_child_done(terminal)) {
124 if (terminal == term_get_terminal(SPLASH_TERMINAL)) {
125 /*
126 * Note: reference is not lost because it is still referenced
127 * by the splash_t structure which will ultimately destroy
128 * it, once it's safe to do so
129 */
130 term_set_terminal(SPLASH_TERMINAL, NULL);
131 return -1;
132 }
133 term_set_current_terminal(term_init(true, term_getvideo(terminal)));
134 new_terminal = term_get_current_terminal();
135 if (!term_is_valid(new_terminal)) {
136 return -1;
137 }
138 term_activate(new_terminal);
139 term_close(terminal);
140 }
141 }
142
143 return 0;
144}
145
146int main_loop(bool standalone)
147{
148 terminal_t* terminal;
149 int status;
150
151 if (standalone) {
152 dbus_take_display_ownership();
153 term_set_current_terminal(term_init(true, NULL));
154 terminal = term_get_current_terminal();
155 term_activate(terminal);
156 }
157
158 while (1) {
159 status = main_process_events(0);
160 if (status != 0) {
161 LOG(ERROR, "input process returned %d", status);
162 break;
163 }
164 }
165
166 return 0;
167}
168
169
David Sodmanbbcb0522014-09-19 10:34:07 -0700170int main(int argc, char* argv[])
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700171{
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700172 int ret;
David Sodmanbbcb0522014-09-19 10:34:07 -0700173 int c;
David Sodman8ef20062015-01-06 09:23:40 -0800174 int32_t x, y;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800175 splash_t* splash;
David Sodman8ef20062015-01-06 09:23:40 -0800176 commandflags_t command_flags;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700177
Douglas Anderson4da95cd2015-10-05 15:04:30 -0700178 /* Handle resolution special before splash init */
179 for (;;) {
180 c = getopt_long(argc, argv, "", command_options, NULL);
181 if (c == -1) {
182 break;
183 } else if (c == FLAG_PRINT_RESOLUTION) {
184 video_t *video = video_init();
185 if (!video)
186 return EXIT_FAILURE;
187
188 printf("%d %d", video_getwidth(video),
189 video_getheight(video));
190 video_close(video);
191 return EXIT_SUCCESS;
192 }
193 }
194
195 /* Reset option parsing */
196 optind = 1;
197
Dominik Behr580462b2014-11-20 13:50:05 -0800198 memset(&command_flags, 0, sizeof(command_flags));
199 command_flags.standalone = true;
David Sodmanbbcb0522014-09-19 10:34:07 -0700200
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700201 ret = input_init();
202 if (ret) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700203 LOG(ERROR, "Input init failed");
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700204 return EXIT_FAILURE;
205 }
206
David Sodmanbf3f2842014-11-12 08:26:58 -0800207 splash = splash_init();
David Sodmanbbcb0522014-09-19 10:34:07 -0700208 if (splash == NULL) {
209 LOG(ERROR, "splash init failed");
210 return EXIT_FAILURE;
211 }
212
213 for (;;) {
214 c = getopt_long(argc, argv, "", command_options, NULL);
215
216 if (c == -1)
217 break;
218
219 switch (c) {
220 case FLAG_CLEAR:
221 splash_set_clear(splash, strtoul(optarg, NULL, 0));
222 break;
223
224 case FLAG_DAEMON:
Dominik Behr580462b2014-11-20 13:50:05 -0800225 command_flags.standalone = false;
David Sodmanbbcb0522014-09-19 10:34:07 -0700226 break;
227
David Sodman8ef20062015-01-06 09:23:40 -0800228 case FLAG_FRAME_INTERVAL:
229 splash_set_default_duration(splash, strtoul(optarg, NULL, 0));
230 break;
231
David Sodmanbbcb0522014-09-19 10:34:07 -0700232 case FLAG_DEV_MODE:
233 splash_set_devmode(splash);
234 break;
235
Dominik Behr32a7c892015-10-09 15:47:53 -0700236 case FLAG_IMAGE:
237 if (!splash_is_hires(splash))
238 splash_add_image(splash, optarg);
239 break;
240
241 case FLAG_IMAGE_HIRES:
242 if (splash_is_hires(splash))
243 splash_add_image(splash, optarg);
244 break;
245
David Sodman8ef20062015-01-06 09:23:40 -0800246 case FLAG_LOOP_START:
247 splash_set_loop_start(splash, strtoul(optarg, NULL, 0));
248 break;
249
250 case FLAG_LOOP_INTERVAL:
251 splash_set_loop_duration(splash, strtoul(optarg, NULL, 0));
252 break;
253
254 case FLAG_LOOP_OFFSET:
255 parse_offset(optarg, &x, &y);
256 splash_set_loop_offset(splash, x, y);
257 break;
258
259 case FLAG_OFFSET:
260 parse_offset(optarg, &x, &y);
261 splash_set_offset(splash, x, y);
262 break;
David Sodmanbbcb0522014-09-19 10:34:07 -0700263 }
264 }
265
Stéphane Marchesinac14d292015-12-14 15:27:18 -0800266 for (int i = optind; i < argc; i++)
David Sodman8ef20062015-01-06 09:23:40 -0800267 splash_add_image(splash, argv[i]);
268
David Sodmanbbcb0522014-09-19 10:34:07 -0700269 /*
270 * The DBUS service launches later than the boot-splash service, and
271 * as a result, when splash_run starts dbus is not yet up, but, by
272 * the time splash_run completes, it is running. At the same time,
273 * splash_run needs dbus to determine when chrome is visible. So,
274 * it creates the dbus object and then passes it back to the caller
275 * who can then pass it to the other objects that need it
276 */
Douglas Anderson4da95cd2015-10-05 15:04:30 -0700277 if (command_flags.standalone == false) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700278 splash_present_term_file(splash);
279 daemonize();
280 }
281 if (splash_num_images(splash) > 0) {
Dominik Behr797a3832016-01-11 15:53:11 -0800282 ret = splash_run(splash);
David Sodmanbbcb0522014-09-19 10:34:07 -0700283 if (ret) {
Yuly Novikov945871e2015-05-23 00:00:41 -0400284 LOG(ERROR, "splash_run failed: %d", ret);
285 return EXIT_FAILURE;
David Sodmanbbcb0522014-09-19 10:34:07 -0700286 }
287 }
David Sodmanf0a925a2015-05-04 11:19:19 -0700288 splash_destroy(splash);
David Sodmanbbcb0522014-09-19 10:34:07 -0700289
290 /*
291 * If splash_run didn't create the dbus object (for example, if
David Sodman8ef20062015-01-06 09:23:40 -0800292 * there are no splash screen images), then go ahead and create
293 * it now
David Sodmanbbcb0522014-09-19 10:34:07 -0700294 */
Dominik Behr797a3832016-01-11 15:53:11 -0800295 if (!dbus_is_initialized()) {
296 dbus_init();
David Sodmanbbcb0522014-09-19 10:34:07 -0700297 }
David Sodman8ef20062015-01-06 09:23:40 -0800298
Dominik Behr44e07e62016-01-13 19:43:57 -0800299 ret = main_loop(command_flags.standalone);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700300
301 input_close();
Dominik Behr44e07e62016-01-13 19:43:57 -0800302 dbus_destroy();
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700303
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700304 return ret;
305}