blob: fc97dd8022f365d0607b4f1a63ceeb5ea4f37f57 [file] [log] [blame]
Giulio Camuffobab996e2014-10-12 00:24:25 +03001/*
2 * Copyright © 2010-2011 Intel Corporation
3 * Copyright © 2008-2011 Kristian Høgsberg
4 * Copyright © 2012-2015 Collabora, Ltd.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 */
27
28#include "config.h"
29
30#include <unistd.h>
31#include <signal.h>
32#include <errno.h>
33#include <dlfcn.h>
34#include <string.h>
35#include <sys/utsname.h>
36#include <sys/stat.h>
37#include <sys/wait.h>
38
39#ifdef HAVE_LIBUNWIND
40#define UNW_LOCAL_ONLY
41#include <libunwind.h>
42#endif
43
44#include "compositor.h"
45#include "../shared/os-compatibility.h"
46#include "../shared/helpers.h"
47#include "git-version.h"
48#include "version.h"
49
Benoit Gschwind3c530942016-04-15 20:28:32 -070050#include "compositor-headless.h"
51
Giulio Camuffobab996e2014-10-12 00:24:25 +030052static struct wl_list child_process_list;
53static struct weston_compositor *segv_compositor;
54
55static int
56sigchld_handler(int signal_number, void *data)
57{
58 struct weston_process *p;
59 int status;
60 pid_t pid;
61
62 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
63 wl_list_for_each(p, &child_process_list, link) {
64 if (p->pid == pid)
65 break;
66 }
67
68 if (&p->link == &child_process_list) {
69 weston_log("unknown child process exited\n");
70 continue;
71 }
72
73 wl_list_remove(&p->link);
74 p->cleanup(p, status);
75 }
76
77 if (pid < 0 && errno != ECHILD)
78 weston_log("waitpid error %m\n");
79
80 return 1;
81}
82
83#ifdef HAVE_LIBUNWIND
84
85static void
86print_backtrace(void)
87{
88 unw_cursor_t cursor;
89 unw_context_t context;
90 unw_word_t off;
91 unw_proc_info_t pip;
92 int ret, i = 0;
93 char procname[256];
94 const char *filename;
95 Dl_info dlinfo;
96
97 pip.unwind_info = NULL;
98 ret = unw_getcontext(&context);
99 if (ret) {
100 weston_log("unw_getcontext: %d\n", ret);
101 return;
102 }
103
104 ret = unw_init_local(&cursor, &context);
105 if (ret) {
106 weston_log("unw_init_local: %d\n", ret);
107 return;
108 }
109
110 ret = unw_step(&cursor);
111 while (ret > 0) {
112 ret = unw_get_proc_info(&cursor, &pip);
113 if (ret) {
114 weston_log("unw_get_proc_info: %d\n", ret);
115 break;
116 }
117
118 ret = unw_get_proc_name(&cursor, procname, 256, &off);
119 if (ret && ret != -UNW_ENOMEM) {
120 if (ret != -UNW_EUNSPEC)
121 weston_log("unw_get_proc_name: %d\n", ret);
122 procname[0] = '?';
123 procname[1] = 0;
124 }
125
126 if (dladdr((void *)(pip.start_ip + off), &dlinfo) && dlinfo.dli_fname &&
127 *dlinfo.dli_fname)
128 filename = dlinfo.dli_fname;
129 else
130 filename = "?";
131
132 weston_log("%u: %s (%s%s+0x%x) [%p]\n", i++, filename, procname,
133 ret == -UNW_ENOMEM ? "..." : "", (int)off, (void *)(pip.start_ip + off));
134
135 ret = unw_step(&cursor);
136 if (ret < 0)
137 weston_log("unw_step: %d\n", ret);
138 }
139}
140
141#else
142
143static void
144print_backtrace(void)
145{
146 void *buffer[32];
147 int i, count;
148 Dl_info info;
149
150 count = backtrace(buffer, ARRAY_LENGTH(buffer));
151 for (i = 0; i < count; i++) {
152 dladdr(buffer[i], &info);
153 weston_log(" [%016lx] %s (%s)\n",
154 (long) buffer[i],
155 info.dli_sname ? info.dli_sname : "--",
156 info.dli_fname);
157 }
158}
159
160#endif
161
162WL_EXPORT void
163weston_watch_process(struct weston_process *process)
164{
165 wl_list_insert(&child_process_list, &process->link);
166}
167
168static void
169log_uname(void)
170{
171 struct utsname usys;
172
173 uname(&usys);
174
175 weston_log("OS: %s, %s, %s, %s\n", usys.sysname, usys.release,
176 usys.version, usys.machine);
177}
178
179static const char xdg_error_message[] =
180 "fatal: environment variable XDG_RUNTIME_DIR is not set.\n";
181
182static const char xdg_wrong_message[] =
183 "fatal: environment variable XDG_RUNTIME_DIR\n"
184 "is set to \"%s\", which is not a directory.\n";
185
186static const char xdg_wrong_mode_message[] =
187 "warning: XDG_RUNTIME_DIR \"%s\" is not configured\n"
188 "correctly. Unix access mode must be 0700 (current mode is %o),\n"
189 "and must be owned by the user (current owner is UID %d).\n";
190
191static const char xdg_detail_message[] =
192 "Refer to your distribution on how to get it, or\n"
193 "http://www.freedesktop.org/wiki/Specifications/basedir-spec\n"
194 "on how to implement it.\n";
195
196static void
197verify_xdg_runtime_dir(void)
198{
199 char *dir = getenv("XDG_RUNTIME_DIR");
200 struct stat s;
201
202 if (!dir) {
203 weston_log(xdg_error_message);
204 weston_log_continue(xdg_detail_message);
205 exit(EXIT_FAILURE);
206 }
207
208 if (stat(dir, &s) || !S_ISDIR(s.st_mode)) {
209 weston_log(xdg_wrong_message, dir);
210 weston_log_continue(xdg_detail_message);
211 exit(EXIT_FAILURE);
212 }
213
214 if ((s.st_mode & 0777) != 0700 || s.st_uid != getuid()) {
215 weston_log(xdg_wrong_mode_message,
216 dir, s.st_mode & 0777, s.st_uid);
217 weston_log_continue(xdg_detail_message);
218 }
219}
220
221static int
222usage(int error_code)
223{
224 fprintf(stderr,
225 "Usage: weston [OPTIONS]\n\n"
226 "This is weston version " VERSION ", the Wayland reference compositor.\n"
227 "Weston supports multiple backends, and depending on which backend is in use\n"
228 "different options will be accepted.\n\n"
229
230
231 "Core options:\n\n"
232 " --version\t\tPrint weston version\n"
233 " -B, --backend=MODULE\tBackend module, one of\n"
234#if defined(BUILD_DRM_COMPOSITOR)
235 "\t\t\t\tdrm-backend.so\n"
236#endif
237#if defined(BUILD_FBDEV_COMPOSITOR)
238 "\t\t\t\tfbdev-backend.so\n"
239#endif
Dawid Gajownik71f57042015-07-31 17:39:00 -0300240#if defined(BUILD_HEADLESS_COMPOSITOR)
241 "\t\t\t\theadless-backend.so\n"
Giulio Camuffobab996e2014-10-12 00:24:25 +0300242#endif
243#if defined(BUILD_RDP_COMPOSITOR)
244 "\t\t\t\trdp-backend.so\n"
245#endif
Giulio Camuffobab996e2014-10-12 00:24:25 +0300246#if defined(BUILD_RPI_COMPOSITOR) && defined(HAVE_BCM_HOST)
247 "\t\t\t\trpi-backend.so\n"
248#endif
Dawid Gajownik71f57042015-07-31 17:39:00 -0300249#if defined(BUILD_WAYLAND_COMPOSITOR)
250 "\t\t\t\twayland-backend.so\n"
251#endif
252#if defined(BUILD_X11_COMPOSITOR)
253 "\t\t\t\tx11-backend.so\n"
254#endif
Giulio Camuffobab996e2014-10-12 00:24:25 +0300255 " --shell=MODULE\tShell module, defaults to desktop-shell.so\n"
256 " -S, --socket=NAME\tName of socket to listen on\n"
257 " -i, --idle-time=SECS\tIdle time in seconds\n"
258 " --modules\t\tLoad the comma-separated list of modules\n"
259 " --log=FILE\t\tLog to the given file\n"
260 " -c, --config=FILE\tConfig file to load, defaults to weston.ini\n"
261 " --no-config\t\tDo not read weston.ini\n"
262 " -h, --help\t\tThis help message\n\n");
263
264#if defined(BUILD_DRM_COMPOSITOR)
265 fprintf(stderr,
266 "Options for drm-backend.so:\n\n"
267 " --connector=ID\tBring up only this connector\n"
268 " --seat=SEAT\t\tThe seat that weston should run on\n"
269 " --tty=TTY\t\tThe tty to use\n"
270 " --use-pixman\t\tUse the pixman (CPU) renderer\n"
271 " --current-mode\tPrefer current KMS mode over EDID preferred mode\n\n");
272#endif
273
274#if defined(BUILD_FBDEV_COMPOSITOR)
275 fprintf(stderr,
276 "Options for fbdev-backend.so:\n\n"
277 " --tty=TTY\t\tThe tty to use\n"
278 " --device=DEVICE\tThe framebuffer device to use\n"
279 " --use-gl\t\tUse the GL renderer\n\n");
280#endif
281
Dawid Gajownik71f57042015-07-31 17:39:00 -0300282#if defined(BUILD_HEADLESS_COMPOSITOR)
Giulio Camuffobab996e2014-10-12 00:24:25 +0300283 fprintf(stderr,
Dawid Gajownik71f57042015-07-31 17:39:00 -0300284 "Options for headless-backend.so:\n\n"
285 " --width=WIDTH\t\tWidth of memory surface\n"
286 " --height=HEIGHT\tHeight of memory surface\n"
Giulio Camuffobab996e2014-10-12 00:24:25 +0300287 " --transform=TR\tThe output transformation, TR is one of:\n"
288 "\tnormal 90 180 270 flipped flipped-90 flipped-180 flipped-270\n"
Dawid Gajownik71f57042015-07-31 17:39:00 -0300289 " --use-pixman\t\tUse the pixman (CPU) renderer (default: no rendering)\n\n");
Giulio Camuffobab996e2014-10-12 00:24:25 +0300290#endif
291
292#if defined(BUILD_RDP_COMPOSITOR)
293 fprintf(stderr,
294 "Options for rdp-backend.so:\n\n"
295 " --width=WIDTH\t\tWidth of desktop\n"
296 " --height=HEIGHT\tHeight of desktop\n"
Dawid Gajownikd99a0502015-07-31 14:49:57 -0300297 " --env-socket\t\tUse socket defined in RDP_FD env variable as peer connection\n"
Giulio Camuffobab996e2014-10-12 00:24:25 +0300298 " --address=ADDR\tThe address to bind\n"
299 " --port=PORT\t\tThe port to listen on\n"
300 " --no-clients-resize\tThe RDP peers will be forced to the size of the desktop\n"
301 " --rdp4-key=FILE\tThe file containing the key for RDP4 encryption\n"
302 " --rdp-tls-cert=FILE\tThe file containing the certificate for TLS encryption\n"
303 " --rdp-tls-key=FILE\tThe file containing the private key for TLS encryption\n"
304 "\n");
305#endif
306
Dawid Gajownik71f57042015-07-31 17:39:00 -0300307#if defined(BUILD_RPI_COMPOSITOR) && defined(HAVE_BCM_HOST)
Giulio Camuffobab996e2014-10-12 00:24:25 +0300308 fprintf(stderr,
Dawid Gajownik71f57042015-07-31 17:39:00 -0300309 "Options for rpi-backend.so:\n\n"
310 " --tty=TTY\t\tThe tty to use\n"
311 " --single-buffer\tUse single-buffered Dispmanx elements.\n"
Giulio Camuffobab996e2014-10-12 00:24:25 +0300312 " --transform=TR\tThe output transformation, TR is one of:\n"
313 "\tnormal 90 180 270 flipped flipped-90 flipped-180 flipped-270\n"
Dawid Gajownik71f57042015-07-31 17:39:00 -0300314 " --opaque-regions\tEnable support for opaque regions, can be "
315 "very slow without support in the GPU firmware.\n"
316 "\n");
317#endif
318
319#if defined(BUILD_WAYLAND_COMPOSITOR)
320 fprintf(stderr,
321 "Options for wayland-backend.so:\n\n"
322 " --width=WIDTH\t\tWidth of Wayland surface\n"
323 " --height=HEIGHT\tHeight of Wayland surface\n"
324 " --scale=SCALE\t\tScale factor of output\n"
325 " --fullscreen\t\tRun in fullscreen mode\n"
326 " --use-pixman\t\tUse the pixman (CPU) renderer\n"
327 " --output-count=COUNT\tCreate multiple outputs\n"
328 " --sprawl\t\tCreate one fullscreen output for every parent output\n"
329 " --display=DISPLAY\tWayland display to connect to\n\n");
330#endif
331
332#if defined(BUILD_X11_COMPOSITOR)
333 fprintf(stderr,
334 "Options for x11-backend.so:\n\n"
335 " --width=WIDTH\t\tWidth of X window\n"
336 " --height=HEIGHT\tHeight of X window\n"
337 " --scale=SCALE\t\tScale factor of output\n"
338 " --fullscreen\t\tRun in fullscreen mode\n"
339 " --use-pixman\t\tUse the pixman (CPU) renderer\n"
340 " --output-count=COUNT\tCreate multiple outputs\n"
341 " --no-input\t\tDont create input devices\n\n");
Giulio Camuffobab996e2014-10-12 00:24:25 +0300342#endif
343
344 exit(error_code);
345}
346
347static int on_term_signal(int signal_number, void *data)
348{
349 struct wl_display *display = data;
350
351 weston_log("caught signal %d\n", signal_number);
352 wl_display_terminate(display);
353
354 return 1;
355}
356
357static void
358on_caught_signal(int s, siginfo_t *siginfo, void *context)
359{
360 /* This signal handler will do a best-effort backtrace, and
361 * then call the backend restore function, which will switch
362 * back to the vt we launched from or ungrab X etc and then
363 * raise SIGTRAP. If we run weston under gdb from X or a
364 * different vt, and tell gdb "handle *s* nostop", this
365 * will allow weston to switch back to gdb on crash and then
366 * gdb will catch the crash with SIGTRAP.*/
367
368 weston_log("caught signal: %d\n", s);
369
370 print_backtrace();
371
372 segv_compositor->backend->restore(segv_compositor);
373
374 raise(SIGTRAP);
375}
376
377static void
378catch_signals(void)
379{
380 struct sigaction action;
381
382 action.sa_flags = SA_SIGINFO | SA_RESETHAND;
383 action.sa_sigaction = on_caught_signal;
384 sigemptyset(&action.sa_mask);
385 sigaction(SIGSEGV, &action, NULL);
386 sigaction(SIGABRT, &action, NULL);
387}
388
389static const char *
390clock_name(clockid_t clk_id)
391{
392 static const char *names[] = {
393 [CLOCK_REALTIME] = "CLOCK_REALTIME",
394 [CLOCK_MONOTONIC] = "CLOCK_MONOTONIC",
395 [CLOCK_MONOTONIC_RAW] = "CLOCK_MONOTONIC_RAW",
396 [CLOCK_REALTIME_COARSE] = "CLOCK_REALTIME_COARSE",
397 [CLOCK_MONOTONIC_COARSE] = "CLOCK_MONOTONIC_COARSE",
Derek Foreman32838c92015-06-29 13:20:34 -0500398#ifdef CLOCK_BOOTTIME
Giulio Camuffobab996e2014-10-12 00:24:25 +0300399 [CLOCK_BOOTTIME] = "CLOCK_BOOTTIME",
Derek Foreman32838c92015-06-29 13:20:34 -0500400#endif
Giulio Camuffobab996e2014-10-12 00:24:25 +0300401 };
402
403 if (clk_id < 0 || (unsigned)clk_id >= ARRAY_LENGTH(names))
404 return "unknown";
405
406 return names[clk_id];
407}
408
409static const struct {
410 uint32_t bit; /* enum weston_capability */
411 const char *desc;
412} capability_strings[] = {
413 { WESTON_CAP_ROTATION_ANY, "arbitrary surface rotation:" },
414 { WESTON_CAP_CAPTURE_YFLIP, "screen capture uses y-flip:" },
415};
416
417static void
418weston_compositor_log_capabilities(struct weston_compositor *compositor)
419{
420 unsigned i;
421 int yes;
422
423 weston_log("Compositor capabilities:\n");
424 for (i = 0; i < ARRAY_LENGTH(capability_strings); i++) {
425 yes = compositor->capabilities & capability_strings[i].bit;
426 weston_log_continue(STAMP_SPACE "%s %s\n",
427 capability_strings[i].desc,
428 yes ? "yes" : "no");
429 }
430
431 weston_log_continue(STAMP_SPACE "presentation clock: %s, id %d\n",
432 clock_name(compositor->presentation_clock),
433 compositor->presentation_clock);
434}
435
436static void
437handle_primary_client_destroyed(struct wl_listener *listener, void *data)
438{
439 struct wl_client *client = data;
440
441 weston_log("Primary client died. Closing...\n");
442
443 wl_display_terminate(wl_client_get_display(client));
444}
445
446static int
447weston_create_listening_socket(struct wl_display *display, const char *socket_name)
448{
449 if (socket_name) {
450 if (wl_display_add_socket(display, socket_name)) {
451 weston_log("fatal: failed to add socket: %m\n");
452 return -1;
453 }
454 } else {
455 socket_name = wl_display_add_socket_auto(display);
456 if (!socket_name) {
457 weston_log("fatal: failed to add socket: %m\n");
458 return -1;
459 }
460 }
461
462 setenv("WAYLAND_DISPLAY", socket_name, 1);
463
464 return 0;
465}
466
467static int
468load_modules(struct weston_compositor *ec, const char *modules,
469 int *argc, char *argv[])
470{
471 const char *p, *end;
472 char buffer[256];
473 int (*module_init)(struct weston_compositor *ec,
474 int *argc, char *argv[]);
475
476 if (modules == NULL)
477 return 0;
478
479 p = modules;
480 while (*p) {
481 end = strchrnul(p, ',');
482 snprintf(buffer, sizeof buffer, "%.*s", (int) (end - p), p);
483 module_init = weston_load_module(buffer, "module_init");
484 if (!module_init)
485 return -1;
486 if (module_init(ec, argc, argv) < 0)
487 return -1;
488 p = end;
489 while (*p == ',')
490 p++;
491
492 }
493
494 return 0;
495}
496
497static int
498weston_compositor_init_config(struct weston_compositor *ec,
499 struct weston_config *config)
500{
501 struct xkb_rule_names xkb_names;
502 struct weston_config_section *s;
503 int repaint_msec;
Bob Ham91880f12016-01-12 10:21:47 +0000504 int vt_switching;
Giulio Camuffobab996e2014-10-12 00:24:25 +0300505
506 s = weston_config_get_section(config, "keyboard", NULL, NULL);
507 weston_config_section_get_string(s, "keymap_rules",
508 (char **) &xkb_names.rules, NULL);
509 weston_config_section_get_string(s, "keymap_model",
510 (char **) &xkb_names.model, NULL);
511 weston_config_section_get_string(s, "keymap_layout",
512 (char **) &xkb_names.layout, NULL);
513 weston_config_section_get_string(s, "keymap_variant",
514 (char **) &xkb_names.variant, NULL);
515 weston_config_section_get_string(s, "keymap_options",
516 (char **) &xkb_names.options, NULL);
517
518 if (weston_compositor_xkb_init(ec, &xkb_names) < 0)
519 return -1;
520
521 weston_config_section_get_int(s, "repeat-rate",
522 &ec->kb_repeat_rate, 40);
523 weston_config_section_get_int(s, "repeat-delay",
524 &ec->kb_repeat_delay, 400);
525
Bob Ham91880f12016-01-12 10:21:47 +0000526 weston_config_section_get_bool(s, "vt-switching",
527 &vt_switching, true);
528 ec->vt_switching = vt_switching;
529
Giulio Camuffobab996e2014-10-12 00:24:25 +0300530 s = weston_config_get_section(config, "core", NULL, NULL);
531 weston_config_section_get_int(s, "repaint-window", &repaint_msec,
532 ec->repaint_msec);
533 if (repaint_msec < -10 || repaint_msec > 1000) {
534 weston_log("Invalid repaint_window value in config: %d\n",
535 repaint_msec);
536 } else {
537 ec->repaint_msec = repaint_msec;
538 }
539 weston_log("Output repaint window is %d ms maximum.\n",
540 ec->repaint_msec);
541
542 return 0;
543}
544
545static char *
546weston_choose_default_backend(void)
547{
548 char *backend = NULL;
549
550 if (getenv("WAYLAND_DISPLAY") || getenv("WAYLAND_SOCKET"))
551 backend = strdup("wayland-backend.so");
552 else if (getenv("DISPLAY"))
553 backend = strdup("x11-backend.so");
554 else
555 backend = strdup(WESTON_NATIVE_BACKEND);
556
557 return backend;
558}
559
560static const struct { const char *name; uint32_t token; } transforms[] = {
561 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
562 { "90", WL_OUTPUT_TRANSFORM_90 },
563 { "180", WL_OUTPUT_TRANSFORM_180 },
564 { "270", WL_OUTPUT_TRANSFORM_270 },
565 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
566 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
567 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
568 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
569};
570
571WL_EXPORT int
572weston_parse_transform(const char *transform, uint32_t *out)
573{
574 unsigned int i;
575
576 for (i = 0; i < ARRAY_LENGTH(transforms); i++)
577 if (strcmp(transforms[i].name, transform) == 0) {
578 *out = transforms[i].token;
579 return 0;
580 }
581
582 *out = WL_OUTPUT_TRANSFORM_NORMAL;
583 return -1;
584}
585
586WL_EXPORT const char *
587weston_transform_to_string(uint32_t output_transform)
588{
589 unsigned int i;
590
591 for (i = 0; i < ARRAY_LENGTH(transforms); i++)
592 if (transforms[i].token == output_transform)
593 return transforms[i].name;
594
595 return "<illegal value>";
596}
597
598static int
599load_configuration(struct weston_config **config, int32_t noconfig,
600 const char *config_file)
601{
602 const char *file = "weston.ini";
603 const char *full_path;
604
605 *config = NULL;
606
607 if (config_file)
608 file = config_file;
609
610 if (noconfig == 0)
611 *config = weston_config_parse(file);
612
613 if (*config) {
614 full_path = weston_config_get_full_path(*config);
615
616 weston_log("Using config file '%s'\n", full_path);
617 setenv(WESTON_CONFIG_FILE_ENV_VAR, full_path, 1);
618
619 return 0;
620 }
621
622 if (config_file && noconfig == 0) {
623 weston_log("fatal: error opening or reading config file"
624 " '%s'.\n", config_file);
625
626 return -1;
627 }
628
629 weston_log("Starting with no config file.\n");
630 setenv(WESTON_CONFIG_FILE_ENV_VAR, "", 1);
631
632 return 0;
633}
634
635static void
636handle_exit(struct weston_compositor *c)
637{
638 wl_display_terminate(c->wl_display);
639}
640
Giulio Camuffo43008c72015-10-17 19:24:15 +0300641/* Temporary function to be removed when all backends are converted. */
642static int
643load_backend_old(struct weston_compositor *compositor, const char *backend,
644 int *argc, char **argv, struct weston_config *wc)
645{
646 int (*backend_init)(struct weston_compositor *c,
647 int *argc, char *argv[],
648 struct weston_config *config,
649 struct weston_backend_config *config_base);
650
651 backend_init = weston_load_module(backend, "backend_init");
652 if (!backend_init)
653 return -1;
654
655 return backend_init(compositor, argc, argv, wc, NULL);
656}
657
Bryce Harrington98ab08b2016-04-15 20:28:36 -0700658/** Main module call-point for backends.
659 *
660 * All backends should use this routine to access their init routine.
661 * Backends may subclass weston_backend_config to add their own
662 * configuration data, setting the major/minor version in config_base
663 * accordingly.
664 *
665 * The config_base object should be treated as temporary, and any data
666 * copied out of it by backend_init before returning. The load_backend_new
667 * callers may then free the config_base object.
668 *
669 * NOTE: This is a temporary function intended to eventually be replaced
670 * by weston_compositor_load_backend().
671 */
Bryce Harrington6ca25b32016-04-15 20:28:27 -0700672static int
673load_backend_new(struct weston_compositor *compositor, const char *backend,
674 struct weston_backend_config *config_base)
675{
676 int (*backend_init)(struct weston_compositor *c,
677 int *argc, char *argv[],
678 struct weston_config *config,
679 struct weston_backend_config *config_base);
680
681 backend_init = weston_load_module(backend, "backend_init");
682 if (!backend_init)
683 return -1;
684
685 return backend_init(compositor, NULL, NULL, NULL, config_base);
686}
687
Giulio Camuffo43008c72015-10-17 19:24:15 +0300688static int
Benoit Gschwind3c530942016-04-15 20:28:32 -0700689load_headless_backend(struct weston_compositor *c, char const * backend,
690 int *argc, char **argv, struct weston_config *wc)
691{
692 struct weston_headless_backend_config config = {{ 0, }};
693 int ret = 0;
694 const char *transform = "normal";
695
696 config.width = 1024;
697 config.height = 640;
698
699 const struct weston_option options[] = {
700 { WESTON_OPTION_INTEGER, "width", 0, &config.width },
701 { WESTON_OPTION_INTEGER, "height", 0, &config.height },
702 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &config.use_pixman },
703 { WESTON_OPTION_STRING, "transform", 0, &transform },
704 };
705
706 parse_options(options, ARRAY_LENGTH(options), argc, argv);
707
708 if (weston_parse_transform(transform, &config.transform) < 0)
709 weston_log("Invalid transform \"%s\"\n", transform);
710
711 config.base.struct_version = WESTON_HEADLESS_BACKEND_CONFIG_VERSION;
712 config.base.struct_size = sizeof(struct weston_headless_backend_config);
713
714 /* load the actual wayland backend and configure it */
715 ret = load_backend_new(c, backend, &config.base);
716
717 return ret;
718}
719
720static int
Giulio Camuffo43008c72015-10-17 19:24:15 +0300721load_backend(struct weston_compositor *compositor, const char *backend,
722 int *argc, char **argv, struct weston_config *config)
723{
Benoit Gschwind3c530942016-04-15 20:28:32 -0700724 if (strstr(backend, "headless-backend.so"))
725 return load_headless_backend(compositor, backend, argc, argv, config);
Giulio Camuffo43008c72015-10-17 19:24:15 +0300726#if 0
Benoit Gschwind3c530942016-04-15 20:28:32 -0700727 else if (strstr(backend, "drm-backend.so"))
Giulio Camuffo43008c72015-10-17 19:24:15 +0300728 return load_drm_backend(compositor, backend, argc, argv, config);
729 else if (strstr(backend, "wayland-backend.so"))
730 return load_wayland_backend(compositor, backend, argc, argv, config);
731 else if (strstr(backend, "x11-backend.so"))
732 return load_x11_backend(compositor, backend, argc, argv, config);
733 else if (strstr(backend, "fbdev-backend.so"))
734 return load_fbdev_backend(compositor, backend, argc, argv, config);
Giulio Camuffo43008c72015-10-17 19:24:15 +0300735 else if (strstr(backend, "rpi-backend.so"))
736 return load_rpi_backend(compositor, backend, argc, argv, config);
737 else if (strstr(backend, "rdp-backend.so"))
738 return load_rdp_backend(compositor, backend, argc, argv, config);
739#endif
740
741 return load_backend_old(compositor, backend, argc, argv, config);
742}
743
Giulio Camuffobab996e2014-10-12 00:24:25 +0300744int main(int argc, char *argv[])
745{
746 int ret = EXIT_FAILURE;
747 struct wl_display *display;
748 struct weston_compositor *ec;
749 struct wl_event_source *signals[4];
750 struct wl_event_loop *loop;
Giulio Camuffobab996e2014-10-12 00:24:25 +0300751 int i, fd;
752 char *backend = NULL;
753 char *shell = NULL;
754 char *modules = NULL;
755 char *option_modules = NULL;
756 char *log = NULL;
757 char *server_socket = NULL, *end;
758 int32_t idle_time = -1;
759 int32_t help = 0;
760 char *socket_name = NULL;
761 int32_t version = 0;
762 int32_t noconfig = 0;
763 int32_t numlock_on;
764 char *config_file = NULL;
765 struct weston_config *config = NULL;
766 struct weston_config_section *section;
767 struct wl_client *primary_client;
768 struct wl_listener primary_client_destroyed;
769 struct weston_seat *seat;
770
771 const struct weston_option core_options[] = {
772 { WESTON_OPTION_STRING, "backend", 'B', &backend },
773 { WESTON_OPTION_STRING, "shell", 0, &shell },
774 { WESTON_OPTION_STRING, "socket", 'S', &socket_name },
775 { WESTON_OPTION_INTEGER, "idle-time", 'i', &idle_time },
776 { WESTON_OPTION_STRING, "modules", 0, &option_modules },
777 { WESTON_OPTION_STRING, "log", 0, &log },
778 { WESTON_OPTION_BOOLEAN, "help", 'h', &help },
779 { WESTON_OPTION_BOOLEAN, "version", 0, &version },
780 { WESTON_OPTION_BOOLEAN, "no-config", 0, &noconfig },
781 { WESTON_OPTION_STRING, "config", 'c', &config_file },
782 };
783
784 parse_options(core_options, ARRAY_LENGTH(core_options), &argc, argv);
785
786 if (help)
787 usage(EXIT_SUCCESS);
788
789 if (version) {
790 printf(PACKAGE_STRING "\n");
791 return EXIT_SUCCESS;
792 }
793
794 weston_log_file_open(log);
795
796 weston_log("%s\n"
797 STAMP_SPACE "%s\n"
798 STAMP_SPACE "Bug reports to: %s\n"
799 STAMP_SPACE "Build: %s\n",
800 PACKAGE_STRING, PACKAGE_URL, PACKAGE_BUGREPORT,
801 BUILD_ID);
802 log_uname();
803
804 verify_xdg_runtime_dir();
805
806 display = wl_display_create();
807
808 loop = wl_display_get_event_loop(display);
809 signals[0] = wl_event_loop_add_signal(loop, SIGTERM, on_term_signal,
810 display);
811 signals[1] = wl_event_loop_add_signal(loop, SIGINT, on_term_signal,
812 display);
813 signals[2] = wl_event_loop_add_signal(loop, SIGQUIT, on_term_signal,
814 display);
815
816 wl_list_init(&child_process_list);
817 signals[3] = wl_event_loop_add_signal(loop, SIGCHLD, sigchld_handler,
818 NULL);
819
820 if (!signals[0] || !signals[1] || !signals[2] || !signals[3])
821 goto out_signals;
822
823 if (load_configuration(&config, noconfig, config_file) < 0)
824 goto out_signals;
825
826 section = weston_config_get_section(config, "core", NULL, NULL);
827
828 if (!backend) {
829 weston_config_section_get_string(section, "backend", &backend,
830 NULL);
831 if (!backend)
832 backend = weston_choose_default_backend();
833 }
834
Giulio Camuffobab996e2014-10-12 00:24:25 +0300835 ec = weston_compositor_create(display, NULL);
836 if (ec == NULL) {
837 weston_log("fatal: failed to create compositor\n");
Giulio Camuffo3c241b12015-10-03 16:25:16 +0300838 goto out;
Giulio Camuffobab996e2014-10-12 00:24:25 +0300839 }
840
841 ec->config = config;
842 if (weston_compositor_init_config(ec, config) < 0)
Giulio Camuffo3c241b12015-10-03 16:25:16 +0300843 goto out;
Giulio Camuffobab996e2014-10-12 00:24:25 +0300844
Giulio Camuffo43008c72015-10-17 19:24:15 +0300845 if (load_backend(ec, backend, &argc, argv, config) < 0) {
Giulio Camuffobab996e2014-10-12 00:24:25 +0300846 weston_log("fatal: failed to create compositor backend\n");
Giulio Camuffo3c241b12015-10-03 16:25:16 +0300847 goto out;
Giulio Camuffobab996e2014-10-12 00:24:25 +0300848 }
849
850 catch_signals();
851 segv_compositor = ec;
852
853 if (idle_time < 0)
854 weston_config_section_get_int(section, "idle-time", &idle_time, -1);
855 if (idle_time < 0)
856 idle_time = 300; /* default idle timeout, in seconds */
857
858 ec->idle_time = idle_time;
859 ec->default_pointer_grab = NULL;
860 ec->exit = handle_exit;
861
862 weston_compositor_log_capabilities(ec);
863
864 server_socket = getenv("WAYLAND_SERVER_SOCKET");
865 if (server_socket) {
866 weston_log("Running with single client\n");
867 fd = strtol(server_socket, &end, 0);
868 if (*end != '\0')
869 fd = -1;
870 } else {
871 fd = -1;
872 }
873
874 if (fd != -1) {
875 primary_client = wl_client_create(display, fd);
876 if (!primary_client) {
877 weston_log("fatal: failed to add client: %m\n");
878 goto out;
879 }
880 primary_client_destroyed.notify =
881 handle_primary_client_destroyed;
882 wl_client_add_destroy_listener(primary_client,
883 &primary_client_destroyed);
884 } else if (weston_create_listening_socket(display, socket_name)) {
885 goto out;
886 }
887
888 if (!shell)
889 weston_config_section_get_string(section, "shell", &shell,
890 "desktop-shell.so");
891
892 if (load_modules(ec, shell, &argc, argv) < 0)
893 goto out;
894
895 weston_config_section_get_string(section, "modules", &modules, "");
896 if (load_modules(ec, modules, &argc, argv) < 0)
897 goto out;
898
899 if (load_modules(ec, option_modules, &argc, argv) < 0)
900 goto out;
901
902 section = weston_config_get_section(config, "keyboard", NULL, NULL);
903 weston_config_section_get_bool(section, "numlock-on", &numlock_on, 0);
904 if (numlock_on) {
905 wl_list_for_each(seat, &ec->seat_list, link) {
Derek Foreman1281a362015-07-31 16:55:32 -0500906 struct weston_keyboard *keyboard =
907 weston_seat_get_keyboard(seat);
908
909 if (keyboard)
910 weston_keyboard_set_locks(keyboard,
Giulio Camuffobab996e2014-10-12 00:24:25 +0300911 WESTON_NUM_LOCK,
912 WESTON_NUM_LOCK);
913 }
914 }
915
916 for (i = 1; i < argc; i++)
917 weston_log("fatal: unhandled option: %s\n", argv[i]);
918 if (argc > 1)
919 goto out;
920
921 weston_compositor_wake(ec);
922
923 wl_display_run(display);
924
925 /* Allow for setting return exit code after
926 * wl_display_run returns normally. This is
927 * useful for devs/testers and automated tests
928 * that want to indicate failure status to
929 * testing infrastructure above
930 */
931 ret = ec->exit_code;
932
933out:
934 weston_compositor_destroy(ec);
935
936out_signals:
937 for (i = ARRAY_LENGTH(signals) - 1; i >= 0; i--)
938 if (signals[i])
939 wl_event_source_remove(signals[i]);
940
941 wl_display_destroy(display);
942
943 weston_log_file_close();
944
945 if (config)
946 weston_config_destroy(config);
947 free(config_file);
948 free(backend);
949 free(shell);
950 free(socket_name);
951 free(option_modules);
952 free(log);
953 free(modules);
954
955 return ret;
956}