blob: 225110142b532988e23193bd065410e40703b822 [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.
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02005 * Copyright © 2010-2011 Benjamin Franzke
6 * Copyright © 2013 Jason Ekstrand
Giulio Camuffobab996e2014-10-12 00:24:25 +03007 *
8 * Permission is hereby granted, free of charge, to any person obtaining
9 * a copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sublicense, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial
18 * portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * SOFTWARE.
28 */
29
30#include "config.h"
31
32#include <unistd.h>
33#include <signal.h>
34#include <errno.h>
35#include <dlfcn.h>
36#include <string.h>
37#include <sys/utsname.h>
38#include <sys/stat.h>
39#include <sys/wait.h>
Giulio Camuffofba27fb2016-06-02 21:48:10 +030040#include <sys/socket.h>
Giulio Camuffobab996e2014-10-12 00:24:25 +030041
42#ifdef HAVE_LIBUNWIND
43#define UNW_LOCAL_ONLY
44#include <libunwind.h>
45#endif
46
47#include "compositor.h"
48#include "../shared/os-compatibility.h"
49#include "../shared/helpers.h"
50#include "git-version.h"
51#include "version.h"
Giulio Camuffofba27fb2016-06-02 21:48:10 +030052#include "weston.h"
Giulio Camuffobab996e2014-10-12 00:24:25 +030053
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -070054#include "compositor-drm.h"
Benoit Gschwind3c530942016-04-15 20:28:32 -070055#include "compositor-headless.h"
Benoit Gschwindbd573102016-04-22 17:05:26 +020056#include "compositor-rdp.h"
Benoit Gschwind934e89a2016-04-27 23:56:42 +020057#include "compositor-fbdev.h"
Benoit Gschwinde16acab2016-04-15 20:28:31 -070058#include "compositor-x11.h"
Benoit Gschwind3ff10da2016-05-10 22:47:49 +020059#include "compositor-wayland.h"
60
61#define WINDOW_TITLE "Weston Compositor"
Benoit Gschwind3c530942016-04-15 20:28:32 -070062
Giulio Camuffobab996e2014-10-12 00:24:25 +030063static struct wl_list child_process_list;
64static struct weston_compositor *segv_compositor;
65
66static int
67sigchld_handler(int signal_number, void *data)
68{
69 struct weston_process *p;
70 int status;
71 pid_t pid;
72
73 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
74 wl_list_for_each(p, &child_process_list, link) {
75 if (p->pid == pid)
76 break;
77 }
78
79 if (&p->link == &child_process_list) {
80 weston_log("unknown child process exited\n");
81 continue;
82 }
83
84 wl_list_remove(&p->link);
85 p->cleanup(p, status);
86 }
87
88 if (pid < 0 && errno != ECHILD)
89 weston_log("waitpid error %m\n");
90
91 return 1;
92}
93
94#ifdef HAVE_LIBUNWIND
95
96static void
97print_backtrace(void)
98{
99 unw_cursor_t cursor;
100 unw_context_t context;
101 unw_word_t off;
102 unw_proc_info_t pip;
103 int ret, i = 0;
104 char procname[256];
105 const char *filename;
106 Dl_info dlinfo;
107
108 pip.unwind_info = NULL;
109 ret = unw_getcontext(&context);
110 if (ret) {
111 weston_log("unw_getcontext: %d\n", ret);
112 return;
113 }
114
115 ret = unw_init_local(&cursor, &context);
116 if (ret) {
117 weston_log("unw_init_local: %d\n", ret);
118 return;
119 }
120
121 ret = unw_step(&cursor);
122 while (ret > 0) {
123 ret = unw_get_proc_info(&cursor, &pip);
124 if (ret) {
125 weston_log("unw_get_proc_info: %d\n", ret);
126 break;
127 }
128
129 ret = unw_get_proc_name(&cursor, procname, 256, &off);
130 if (ret && ret != -UNW_ENOMEM) {
131 if (ret != -UNW_EUNSPEC)
132 weston_log("unw_get_proc_name: %d\n", ret);
133 procname[0] = '?';
134 procname[1] = 0;
135 }
136
137 if (dladdr((void *)(pip.start_ip + off), &dlinfo) && dlinfo.dli_fname &&
138 *dlinfo.dli_fname)
139 filename = dlinfo.dli_fname;
140 else
141 filename = "?";
142
143 weston_log("%u: %s (%s%s+0x%x) [%p]\n", i++, filename, procname,
144 ret == -UNW_ENOMEM ? "..." : "", (int)off, (void *)(pip.start_ip + off));
145
146 ret = unw_step(&cursor);
147 if (ret < 0)
148 weston_log("unw_step: %d\n", ret);
149 }
150}
151
152#else
153
154static void
155print_backtrace(void)
156{
157 void *buffer[32];
158 int i, count;
159 Dl_info info;
160
161 count = backtrace(buffer, ARRAY_LENGTH(buffer));
162 for (i = 0; i < count; i++) {
163 dladdr(buffer[i], &info);
164 weston_log(" [%016lx] %s (%s)\n",
165 (long) buffer[i],
166 info.dli_sname ? info.dli_sname : "--",
167 info.dli_fname);
168 }
169}
170
171#endif
172
Giulio Camuffofba27fb2016-06-02 21:48:10 +0300173static void
174child_client_exec(int sockfd, const char *path)
175{
176 int clientfd;
177 char s[32];
178 sigset_t allsigs;
179
180 /* do not give our signal mask to the new process */
181 sigfillset(&allsigs);
182 sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
183
184 /* Launch clients as the user. Do not lauch clients with wrong euid.*/
185 if (seteuid(getuid()) == -1) {
186 weston_log("compositor: failed seteuid\n");
187 return;
188 }
189
190 /* SOCK_CLOEXEC closes both ends, so we dup the fd to get a
191 * non-CLOEXEC fd to pass through exec. */
192 clientfd = dup(sockfd);
193 if (clientfd == -1) {
194 weston_log("compositor: dup failed: %m\n");
195 return;
196 }
197
198 snprintf(s, sizeof s, "%d", clientfd);
199 setenv("WAYLAND_SOCKET", s, 1);
200
201 if (execl(path, path, NULL) < 0)
202 weston_log("compositor: executing '%s' failed: %m\n",
203 path);
204}
205
206WL_EXPORT struct wl_client *
207weston_client_launch(struct weston_compositor *compositor,
208 struct weston_process *proc,
209 const char *path,
210 weston_process_cleanup_func_t cleanup)
211{
212 int sv[2];
213 pid_t pid;
214 struct wl_client *client;
215
216 weston_log("launching '%s'\n", path);
217
218 if (os_socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, sv) < 0) {
219 weston_log("weston_client_launch: "
220 "socketpair failed while launching '%s': %m\n",
221 path);
222 return NULL;
223 }
224
225 pid = fork();
226 if (pid == -1) {
227 close(sv[0]);
228 close(sv[1]);
229 weston_log("weston_client_launch: "
230 "fork failed while launching '%s': %m\n", path);
231 return NULL;
232 }
233
234 if (pid == 0) {
235 child_client_exec(sv[1], path);
236 _exit(-1);
237 }
238
239 close(sv[1]);
240
241 client = wl_client_create(compositor->wl_display, sv[0]);
242 if (!client) {
243 close(sv[0]);
244 weston_log("weston_client_launch: "
245 "wl_client_create failed while launching '%s'.\n",
246 path);
247 return NULL;
248 }
249
250 proc->pid = pid;
251 proc->cleanup = cleanup;
252 weston_watch_process(proc);
253
254 return client;
255}
256
Giulio Camuffobab996e2014-10-12 00:24:25 +0300257WL_EXPORT void
258weston_watch_process(struct weston_process *process)
259{
260 wl_list_insert(&child_process_list, &process->link);
261}
262
Giulio Camuffofba27fb2016-06-02 21:48:10 +0300263struct process_info {
264 struct weston_process proc;
265 char *path;
266};
267
268static void
269process_handle_sigchld(struct weston_process *process, int status)
270{
271 struct process_info *pinfo =
272 container_of(process, struct process_info, proc);
273
274 /*
275 * There are no guarantees whether this runs before or after
276 * the wl_client destructor.
277 */
278
279 if (WIFEXITED(status)) {
280 weston_log("%s exited with status %d\n", pinfo->path,
281 WEXITSTATUS(status));
282 } else if (WIFSIGNALED(status)) {
283 weston_log("%s died on signal %d\n", pinfo->path,
284 WTERMSIG(status));
285 } else {
286 weston_log("%s disappeared\n", pinfo->path);
287 }
288
289 free(pinfo->path);
290 free(pinfo);
291}
292
293WL_EXPORT struct wl_client *
294weston_client_start(struct weston_compositor *compositor, const char *path)
295{
296 struct process_info *pinfo;
297 struct wl_client *client;
298
299 pinfo = zalloc(sizeof *pinfo);
300 if (!pinfo)
301 return NULL;
302
303 pinfo->path = strdup(path);
304 if (!pinfo->path)
305 goto out_free;
306
307 client = weston_client_launch(compositor, &pinfo->proc, path,
308 process_handle_sigchld);
309 if (!client)
310 goto out_str;
311
312 return client;
313
314out_str:
315 free(pinfo->path);
316
317out_free:
318 free(pinfo);
319
320 return NULL;
321}
322
Giulio Camuffobab996e2014-10-12 00:24:25 +0300323static void
324log_uname(void)
325{
326 struct utsname usys;
327
328 uname(&usys);
329
330 weston_log("OS: %s, %s, %s, %s\n", usys.sysname, usys.release,
331 usys.version, usys.machine);
332}
333
334static const char xdg_error_message[] =
335 "fatal: environment variable XDG_RUNTIME_DIR is not set.\n";
336
337static const char xdg_wrong_message[] =
338 "fatal: environment variable XDG_RUNTIME_DIR\n"
339 "is set to \"%s\", which is not a directory.\n";
340
341static const char xdg_wrong_mode_message[] =
342 "warning: XDG_RUNTIME_DIR \"%s\" is not configured\n"
343 "correctly. Unix access mode must be 0700 (current mode is %o),\n"
344 "and must be owned by the user (current owner is UID %d).\n";
345
346static const char xdg_detail_message[] =
347 "Refer to your distribution on how to get it, or\n"
348 "http://www.freedesktop.org/wiki/Specifications/basedir-spec\n"
349 "on how to implement it.\n";
350
351static void
352verify_xdg_runtime_dir(void)
353{
354 char *dir = getenv("XDG_RUNTIME_DIR");
355 struct stat s;
356
357 if (!dir) {
358 weston_log(xdg_error_message);
359 weston_log_continue(xdg_detail_message);
360 exit(EXIT_FAILURE);
361 }
362
363 if (stat(dir, &s) || !S_ISDIR(s.st_mode)) {
364 weston_log(xdg_wrong_message, dir);
365 weston_log_continue(xdg_detail_message);
366 exit(EXIT_FAILURE);
367 }
368
369 if ((s.st_mode & 0777) != 0700 || s.st_uid != getuid()) {
370 weston_log(xdg_wrong_mode_message,
371 dir, s.st_mode & 0777, s.st_uid);
372 weston_log_continue(xdg_detail_message);
373 }
374}
375
376static int
377usage(int error_code)
378{
379 fprintf(stderr,
380 "Usage: weston [OPTIONS]\n\n"
381 "This is weston version " VERSION ", the Wayland reference compositor.\n"
382 "Weston supports multiple backends, and depending on which backend is in use\n"
383 "different options will be accepted.\n\n"
384
385
386 "Core options:\n\n"
387 " --version\t\tPrint weston version\n"
388 " -B, --backend=MODULE\tBackend module, one of\n"
389#if defined(BUILD_DRM_COMPOSITOR)
390 "\t\t\t\tdrm-backend.so\n"
391#endif
392#if defined(BUILD_FBDEV_COMPOSITOR)
393 "\t\t\t\tfbdev-backend.so\n"
394#endif
Dawid Gajownik71f57042015-07-31 17:39:00 -0300395#if defined(BUILD_HEADLESS_COMPOSITOR)
396 "\t\t\t\theadless-backend.so\n"
Giulio Camuffobab996e2014-10-12 00:24:25 +0300397#endif
398#if defined(BUILD_RDP_COMPOSITOR)
399 "\t\t\t\trdp-backend.so\n"
400#endif
Dawid Gajownik71f57042015-07-31 17:39:00 -0300401#if defined(BUILD_WAYLAND_COMPOSITOR)
402 "\t\t\t\twayland-backend.so\n"
403#endif
404#if defined(BUILD_X11_COMPOSITOR)
405 "\t\t\t\tx11-backend.so\n"
406#endif
Giulio Camuffobab996e2014-10-12 00:24:25 +0300407 " --shell=MODULE\tShell module, defaults to desktop-shell.so\n"
408 " -S, --socket=NAME\tName of socket to listen on\n"
409 " -i, --idle-time=SECS\tIdle time in seconds\n"
410 " --modules\t\tLoad the comma-separated list of modules\n"
411 " --log=FILE\t\tLog to the given file\n"
412 " -c, --config=FILE\tConfig file to load, defaults to weston.ini\n"
413 " --no-config\t\tDo not read weston.ini\n"
414 " -h, --help\t\tThis help message\n\n");
415
416#if defined(BUILD_DRM_COMPOSITOR)
417 fprintf(stderr,
418 "Options for drm-backend.so:\n\n"
419 " --connector=ID\tBring up only this connector\n"
420 " --seat=SEAT\t\tThe seat that weston should run on\n"
421 " --tty=TTY\t\tThe tty to use\n"
422 " --use-pixman\t\tUse the pixman (CPU) renderer\n"
423 " --current-mode\tPrefer current KMS mode over EDID preferred mode\n\n");
424#endif
425
426#if defined(BUILD_FBDEV_COMPOSITOR)
427 fprintf(stderr,
428 "Options for fbdev-backend.so:\n\n"
429 " --tty=TTY\t\tThe tty to use\n"
430 " --device=DEVICE\tThe framebuffer device to use\n"
431 " --use-gl\t\tUse the GL renderer\n\n");
432#endif
433
Dawid Gajownik71f57042015-07-31 17:39:00 -0300434#if defined(BUILD_HEADLESS_COMPOSITOR)
Giulio Camuffobab996e2014-10-12 00:24:25 +0300435 fprintf(stderr,
Dawid Gajownik71f57042015-07-31 17:39:00 -0300436 "Options for headless-backend.so:\n\n"
437 " --width=WIDTH\t\tWidth of memory surface\n"
438 " --height=HEIGHT\tHeight of memory surface\n"
Giulio Camuffobab996e2014-10-12 00:24:25 +0300439 " --transform=TR\tThe output transformation, TR is one of:\n"
440 "\tnormal 90 180 270 flipped flipped-90 flipped-180 flipped-270\n"
Dawid Gajownik71f57042015-07-31 17:39:00 -0300441 " --use-pixman\t\tUse the pixman (CPU) renderer (default: no rendering)\n\n");
Giulio Camuffobab996e2014-10-12 00:24:25 +0300442#endif
443
444#if defined(BUILD_RDP_COMPOSITOR)
445 fprintf(stderr,
446 "Options for rdp-backend.so:\n\n"
447 " --width=WIDTH\t\tWidth of desktop\n"
448 " --height=HEIGHT\tHeight of desktop\n"
Dawid Gajownikd99a0502015-07-31 14:49:57 -0300449 " --env-socket\t\tUse socket defined in RDP_FD env variable as peer connection\n"
Giulio Camuffobab996e2014-10-12 00:24:25 +0300450 " --address=ADDR\tThe address to bind\n"
451 " --port=PORT\t\tThe port to listen on\n"
452 " --no-clients-resize\tThe RDP peers will be forced to the size of the desktop\n"
453 " --rdp4-key=FILE\tThe file containing the key for RDP4 encryption\n"
454 " --rdp-tls-cert=FILE\tThe file containing the certificate for TLS encryption\n"
455 " --rdp-tls-key=FILE\tThe file containing the private key for TLS encryption\n"
456 "\n");
457#endif
458
Dawid Gajownik71f57042015-07-31 17:39:00 -0300459#if defined(BUILD_WAYLAND_COMPOSITOR)
460 fprintf(stderr,
461 "Options for wayland-backend.so:\n\n"
462 " --width=WIDTH\t\tWidth of Wayland surface\n"
463 " --height=HEIGHT\tHeight of Wayland surface\n"
464 " --scale=SCALE\t\tScale factor of output\n"
465 " --fullscreen\t\tRun in fullscreen mode\n"
466 " --use-pixman\t\tUse the pixman (CPU) renderer\n"
467 " --output-count=COUNT\tCreate multiple outputs\n"
468 " --sprawl\t\tCreate one fullscreen output for every parent output\n"
469 " --display=DISPLAY\tWayland display to connect to\n\n");
470#endif
471
472#if defined(BUILD_X11_COMPOSITOR)
473 fprintf(stderr,
474 "Options for x11-backend.so:\n\n"
475 " --width=WIDTH\t\tWidth of X window\n"
476 " --height=HEIGHT\tHeight of X window\n"
477 " --scale=SCALE\t\tScale factor of output\n"
478 " --fullscreen\t\tRun in fullscreen mode\n"
479 " --use-pixman\t\tUse the pixman (CPU) renderer\n"
480 " --output-count=COUNT\tCreate multiple outputs\n"
481 " --no-input\t\tDont create input devices\n\n");
Giulio Camuffobab996e2014-10-12 00:24:25 +0300482#endif
483
484 exit(error_code);
485}
486
487static int on_term_signal(int signal_number, void *data)
488{
489 struct wl_display *display = data;
490
491 weston_log("caught signal %d\n", signal_number);
492 wl_display_terminate(display);
493
494 return 1;
495}
496
497static void
498on_caught_signal(int s, siginfo_t *siginfo, void *context)
499{
500 /* This signal handler will do a best-effort backtrace, and
501 * then call the backend restore function, which will switch
502 * back to the vt we launched from or ungrab X etc and then
503 * raise SIGTRAP. If we run weston under gdb from X or a
504 * different vt, and tell gdb "handle *s* nostop", this
505 * will allow weston to switch back to gdb on crash and then
506 * gdb will catch the crash with SIGTRAP.*/
507
508 weston_log("caught signal: %d\n", s);
509
510 print_backtrace();
511
512 segv_compositor->backend->restore(segv_compositor);
513
514 raise(SIGTRAP);
515}
516
517static void
518catch_signals(void)
519{
520 struct sigaction action;
521
522 action.sa_flags = SA_SIGINFO | SA_RESETHAND;
523 action.sa_sigaction = on_caught_signal;
524 sigemptyset(&action.sa_mask);
525 sigaction(SIGSEGV, &action, NULL);
526 sigaction(SIGABRT, &action, NULL);
527}
528
529static const char *
530clock_name(clockid_t clk_id)
531{
532 static const char *names[] = {
533 [CLOCK_REALTIME] = "CLOCK_REALTIME",
534 [CLOCK_MONOTONIC] = "CLOCK_MONOTONIC",
535 [CLOCK_MONOTONIC_RAW] = "CLOCK_MONOTONIC_RAW",
536 [CLOCK_REALTIME_COARSE] = "CLOCK_REALTIME_COARSE",
537 [CLOCK_MONOTONIC_COARSE] = "CLOCK_MONOTONIC_COARSE",
Derek Foreman32838c92015-06-29 13:20:34 -0500538#ifdef CLOCK_BOOTTIME
Giulio Camuffobab996e2014-10-12 00:24:25 +0300539 [CLOCK_BOOTTIME] = "CLOCK_BOOTTIME",
Derek Foreman32838c92015-06-29 13:20:34 -0500540#endif
Giulio Camuffobab996e2014-10-12 00:24:25 +0300541 };
542
543 if (clk_id < 0 || (unsigned)clk_id >= ARRAY_LENGTH(names))
544 return "unknown";
545
546 return names[clk_id];
547}
548
549static const struct {
550 uint32_t bit; /* enum weston_capability */
551 const char *desc;
552} capability_strings[] = {
553 { WESTON_CAP_ROTATION_ANY, "arbitrary surface rotation:" },
554 { WESTON_CAP_CAPTURE_YFLIP, "screen capture uses y-flip:" },
555};
556
557static void
558weston_compositor_log_capabilities(struct weston_compositor *compositor)
559{
560 unsigned i;
561 int yes;
562
563 weston_log("Compositor capabilities:\n");
564 for (i = 0; i < ARRAY_LENGTH(capability_strings); i++) {
565 yes = compositor->capabilities & capability_strings[i].bit;
566 weston_log_continue(STAMP_SPACE "%s %s\n",
567 capability_strings[i].desc,
568 yes ? "yes" : "no");
569 }
570
571 weston_log_continue(STAMP_SPACE "presentation clock: %s, id %d\n",
572 clock_name(compositor->presentation_clock),
573 compositor->presentation_clock);
574}
575
576static void
577handle_primary_client_destroyed(struct wl_listener *listener, void *data)
578{
579 struct wl_client *client = data;
580
581 weston_log("Primary client died. Closing...\n");
582
583 wl_display_terminate(wl_client_get_display(client));
584}
585
586static int
587weston_create_listening_socket(struct wl_display *display, const char *socket_name)
588{
589 if (socket_name) {
590 if (wl_display_add_socket(display, socket_name)) {
591 weston_log("fatal: failed to add socket: %m\n");
592 return -1;
593 }
594 } else {
595 socket_name = wl_display_add_socket_auto(display);
596 if (!socket_name) {
597 weston_log("fatal: failed to add socket: %m\n");
598 return -1;
599 }
600 }
601
602 setenv("WAYLAND_DISPLAY", socket_name, 1);
603
604 return 0;
605}
606
607static int
608load_modules(struct weston_compositor *ec, const char *modules,
609 int *argc, char *argv[])
610{
611 const char *p, *end;
612 char buffer[256];
613 int (*module_init)(struct weston_compositor *ec,
614 int *argc, char *argv[]);
615
616 if (modules == NULL)
617 return 0;
618
619 p = modules;
620 while (*p) {
621 end = strchrnul(p, ',');
622 snprintf(buffer, sizeof buffer, "%.*s", (int) (end - p), p);
623 module_init = weston_load_module(buffer, "module_init");
624 if (!module_init)
625 return -1;
626 if (module_init(ec, argc, argv) < 0)
627 return -1;
628 p = end;
629 while (*p == ',')
630 p++;
631
632 }
633
634 return 0;
635}
636
637static int
638weston_compositor_init_config(struct weston_compositor *ec,
639 struct weston_config *config)
640{
641 struct xkb_rule_names xkb_names;
642 struct weston_config_section *s;
643 int repaint_msec;
Bob Ham91880f12016-01-12 10:21:47 +0000644 int vt_switching;
Giulio Camuffobab996e2014-10-12 00:24:25 +0300645
646 s = weston_config_get_section(config, "keyboard", NULL, NULL);
647 weston_config_section_get_string(s, "keymap_rules",
648 (char **) &xkb_names.rules, NULL);
649 weston_config_section_get_string(s, "keymap_model",
650 (char **) &xkb_names.model, NULL);
651 weston_config_section_get_string(s, "keymap_layout",
652 (char **) &xkb_names.layout, NULL);
653 weston_config_section_get_string(s, "keymap_variant",
654 (char **) &xkb_names.variant, NULL);
655 weston_config_section_get_string(s, "keymap_options",
656 (char **) &xkb_names.options, NULL);
657
Giulio Camuffo0358af42016-06-02 21:48:08 +0300658 if (weston_compositor_set_xkb_rule_names(ec, &xkb_names) < 0)
Giulio Camuffobab996e2014-10-12 00:24:25 +0300659 return -1;
660
661 weston_config_section_get_int(s, "repeat-rate",
662 &ec->kb_repeat_rate, 40);
663 weston_config_section_get_int(s, "repeat-delay",
664 &ec->kb_repeat_delay, 400);
665
Bob Ham91880f12016-01-12 10:21:47 +0000666 weston_config_section_get_bool(s, "vt-switching",
667 &vt_switching, true);
668 ec->vt_switching = vt_switching;
669
Giulio Camuffobab996e2014-10-12 00:24:25 +0300670 s = weston_config_get_section(config, "core", NULL, NULL);
671 weston_config_section_get_int(s, "repaint-window", &repaint_msec,
672 ec->repaint_msec);
673 if (repaint_msec < -10 || repaint_msec > 1000) {
674 weston_log("Invalid repaint_window value in config: %d\n",
675 repaint_msec);
676 } else {
677 ec->repaint_msec = repaint_msec;
678 }
679 weston_log("Output repaint window is %d ms maximum.\n",
680 ec->repaint_msec);
681
682 return 0;
683}
684
685static char *
686weston_choose_default_backend(void)
687{
688 char *backend = NULL;
689
690 if (getenv("WAYLAND_DISPLAY") || getenv("WAYLAND_SOCKET"))
691 backend = strdup("wayland-backend.so");
692 else if (getenv("DISPLAY"))
693 backend = strdup("x11-backend.so");
694 else
695 backend = strdup(WESTON_NATIVE_BACKEND);
696
697 return backend;
698}
699
700static const struct { const char *name; uint32_t token; } transforms[] = {
701 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
702 { "90", WL_OUTPUT_TRANSFORM_90 },
703 { "180", WL_OUTPUT_TRANSFORM_180 },
704 { "270", WL_OUTPUT_TRANSFORM_270 },
705 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
706 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
707 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
708 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
709};
710
711WL_EXPORT int
712weston_parse_transform(const char *transform, uint32_t *out)
713{
714 unsigned int i;
715
716 for (i = 0; i < ARRAY_LENGTH(transforms); i++)
717 if (strcmp(transforms[i].name, transform) == 0) {
718 *out = transforms[i].token;
719 return 0;
720 }
721
722 *out = WL_OUTPUT_TRANSFORM_NORMAL;
723 return -1;
724}
725
726WL_EXPORT const char *
727weston_transform_to_string(uint32_t output_transform)
728{
729 unsigned int i;
730
731 for (i = 0; i < ARRAY_LENGTH(transforms); i++)
732 if (transforms[i].token == output_transform)
733 return transforms[i].name;
734
735 return "<illegal value>";
736}
737
738static int
739load_configuration(struct weston_config **config, int32_t noconfig,
740 const char *config_file)
741{
742 const char *file = "weston.ini";
743 const char *full_path;
744
745 *config = NULL;
746
747 if (config_file)
748 file = config_file;
749
750 if (noconfig == 0)
751 *config = weston_config_parse(file);
752
753 if (*config) {
754 full_path = weston_config_get_full_path(*config);
755
756 weston_log("Using config file '%s'\n", full_path);
757 setenv(WESTON_CONFIG_FILE_ENV_VAR, full_path, 1);
758
759 return 0;
760 }
761
762 if (config_file && noconfig == 0) {
763 weston_log("fatal: error opening or reading config file"
764 " '%s'.\n", config_file);
765
766 return -1;
767 }
768
769 weston_log("Starting with no config file.\n");
770 setenv(WESTON_CONFIG_FILE_ENV_VAR, "", 1);
771
772 return 0;
773}
774
775static void
776handle_exit(struct weston_compositor *c)
777{
778 wl_display_terminate(c->wl_display);
779}
780
Giulio Camuffo43008c72015-10-17 19:24:15 +0300781/* Temporary function to be removed when all backends are converted. */
782static int
783load_backend_old(struct weston_compositor *compositor, const char *backend,
784 int *argc, char **argv, struct weston_config *wc)
785{
786 int (*backend_init)(struct weston_compositor *c,
787 int *argc, char *argv[],
788 struct weston_config *config,
789 struct weston_backend_config *config_base);
790
791 backend_init = weston_load_module(backend, "backend_init");
792 if (!backend_init)
793 return -1;
794
795 return backend_init(compositor, argc, argv, wc, NULL);
796}
797
Bryce Harrington98ab08b2016-04-15 20:28:36 -0700798/** Main module call-point for backends.
799 *
800 * All backends should use this routine to access their init routine.
801 * Backends may subclass weston_backend_config to add their own
802 * configuration data, setting the major/minor version in config_base
803 * accordingly.
804 *
805 * The config_base object should be treated as temporary, and any data
806 * copied out of it by backend_init before returning. The load_backend_new
807 * callers may then free the config_base object.
808 *
809 * NOTE: This is a temporary function intended to eventually be replaced
810 * by weston_compositor_load_backend().
811 */
Bryce Harrington6ca25b32016-04-15 20:28:27 -0700812static int
813load_backend_new(struct weston_compositor *compositor, const char *backend,
814 struct weston_backend_config *config_base)
815{
816 int (*backend_init)(struct weston_compositor *c,
817 int *argc, char *argv[],
818 struct weston_config *config,
819 struct weston_backend_config *config_base);
820
821 backend_init = weston_load_module(backend, "backend_init");
822 if (!backend_init)
823 return -1;
824
825 return backend_init(compositor, NULL, NULL, NULL, config_base);
826}
827
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -0700828static enum weston_drm_backend_output_mode
829drm_configure_output(struct weston_compositor *c,
830 bool use_current_mode,
831 const char *name,
832 struct weston_drm_backend_output_config *config)
833{
834 struct weston_config *wc = weston_compositor_get_user_data(c);
835 struct weston_config_section *section;
836 char *s;
837 int scale;
838 enum weston_drm_backend_output_mode mode =
839 WESTON_DRM_BACKEND_OUTPUT_PREFERRED;
840
841 section = weston_config_get_section(wc, "output", "name", name);
842 weston_config_section_get_string(section, "mode", &s, "preferred");
843 if (strcmp(s, "off") == 0) {
844 free(s);
845 return WESTON_DRM_BACKEND_OUTPUT_OFF;
846 }
847
848 if (use_current_mode || strcmp(s, "current") == 0) {
849 mode = WESTON_DRM_BACKEND_OUTPUT_CURRENT;
850 } else if (strcmp(s, "preferred") != 0) {
851 config->modeline = s;
852 s = NULL;
853 }
854 free(s);
855
856 weston_config_section_get_int(section, "scale", &scale, 1);
857 config->base.scale = scale >= 1 ? scale : 1;
858 weston_config_section_get_string(section, "transform", &s, "normal");
859 if (weston_parse_transform(s, &config->base.transform) < 0)
860 weston_log("Invalid transform \"%s\" for output %s\n",
861 s, name);
862 free(s);
863
864 weston_config_section_get_string(section,
865 "gbm-format", &config->gbm_format, NULL);
866 weston_config_section_get_string(section, "seat", &config->seat, "");
867 return mode;
868}
869
870static int
871load_drm_backend(struct weston_compositor *c, const char *backend,
872 int *argc, char **argv, struct weston_config *wc)
873{
874 struct weston_drm_backend_config config = {{ 0, }};
875 struct weston_config_section *section;
876 int ret = 0;
877
878 const struct weston_option options[] = {
879 { WESTON_OPTION_INTEGER, "connector", 0, &config.connector },
880 { WESTON_OPTION_STRING, "seat", 0, &config.seat_id },
881 { WESTON_OPTION_INTEGER, "tty", 0, &config.tty },
882 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &config.use_current_mode },
883 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &config.use_pixman },
884 };
885
886 parse_options(options, ARRAY_LENGTH(options), argc, argv);
887
888 section = weston_config_get_section(wc, "core", NULL, NULL);
889 weston_config_section_get_string(section,
890 "gbm-format", &config.gbm_format,
891 NULL);
892
893 config.base.struct_version = WESTON_DRM_BACKEND_CONFIG_VERSION;
894 config.base.struct_size = sizeof(struct weston_drm_backend_config);
895 config.configure_output = drm_configure_output;
896
897 ret = load_backend_new(c, backend, &config.base);
898
899 free(config.gbm_format);
900 free(config.seat_id);
901
902 return ret;
903}
904
Giulio Camuffo43008c72015-10-17 19:24:15 +0300905static int
Benoit Gschwind3c530942016-04-15 20:28:32 -0700906load_headless_backend(struct weston_compositor *c, char const * backend,
907 int *argc, char **argv, struct weston_config *wc)
908{
909 struct weston_headless_backend_config config = {{ 0, }};
910 int ret = 0;
Benoit Gschwind2da6d0c2016-04-29 15:21:54 +0200911 char *transform = NULL;
Benoit Gschwind3c530942016-04-15 20:28:32 -0700912
913 config.width = 1024;
914 config.height = 640;
915
916 const struct weston_option options[] = {
917 { WESTON_OPTION_INTEGER, "width", 0, &config.width },
918 { WESTON_OPTION_INTEGER, "height", 0, &config.height },
919 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &config.use_pixman },
920 { WESTON_OPTION_STRING, "transform", 0, &transform },
921 };
922
923 parse_options(options, ARRAY_LENGTH(options), argc, argv);
924
Benoit Gschwind2da6d0c2016-04-29 15:21:54 +0200925 config.transform = WL_OUTPUT_TRANSFORM_NORMAL;
926 if (transform) {
927 if (weston_parse_transform(transform, &config.transform) < 0)
928 weston_log("Invalid transform \"%s\"\n", transform);
929 free(transform);
930 }
Benoit Gschwind3c530942016-04-15 20:28:32 -0700931
932 config.base.struct_version = WESTON_HEADLESS_BACKEND_CONFIG_VERSION;
933 config.base.struct_size = sizeof(struct weston_headless_backend_config);
934
935 /* load the actual wayland backend and configure it */
936 ret = load_backend_new(c, backend, &config.base);
937
938 return ret;
939}
940
Benoit Gschwindbd573102016-04-22 17:05:26 +0200941static void
942weston_rdp_backend_config_init(struct weston_rdp_backend_config *config)
943{
944 config->base.struct_version = WESTON_RDP_BACKEND_CONFIG_VERSION;
945 config->base.struct_size = sizeof(struct weston_rdp_backend_config);
946
947 config->width = 640;
948 config->height = 480;
949 config->bind_address = NULL;
950 config->port = 3389;
951 config->rdp_key = NULL;
952 config->server_cert = NULL;
953 config->server_key = NULL;
954 config->env_socket = 0;
955 config->no_clients_resize = 0;
956}
957
958static int
959load_rdp_backend(struct weston_compositor *c, char const * backend,
960 int *argc, char *argv[], struct weston_config *wc)
961{
962 struct weston_rdp_backend_config config = {{ 0, }};
963 int ret = 0;
964
965 weston_rdp_backend_config_init(&config);
966
967 const struct weston_option rdp_options[] = {
968 { WESTON_OPTION_BOOLEAN, "env-socket", 0, &config.env_socket },
969 { WESTON_OPTION_INTEGER, "width", 0, &config.width },
970 { WESTON_OPTION_INTEGER, "height", 0, &config.height },
971 { WESTON_OPTION_STRING, "address", 0, &config.bind_address },
972 { WESTON_OPTION_INTEGER, "port", 0, &config.port },
973 { WESTON_OPTION_BOOLEAN, "no-clients-resize", 0, &config.no_clients_resize },
974 { WESTON_OPTION_STRING, "rdp4-key", 0, &config.rdp_key },
975 { WESTON_OPTION_STRING, "rdp-tls-cert", 0, &config.server_cert },
976 { WESTON_OPTION_STRING, "rdp-tls-key", 0, &config.server_key }
977 };
978
979 parse_options(rdp_options, ARRAY_LENGTH(rdp_options), argc, argv);
980
981 ret = load_backend_new(c, backend, &config.base);
982
983 free(config.bind_address);
984 free(config.rdp_key);
985 free(config.server_cert);
986 free(config.server_key);
987 return ret;
988}
989
Benoit Gschwind3c530942016-04-15 20:28:32 -0700990static int
Benoit Gschwind934e89a2016-04-27 23:56:42 +0200991load_fbdev_backend(struct weston_compositor *c, char const * backend,
992 int *argc, char **argv, struct weston_config *wc)
993{
994 struct weston_fbdev_backend_config config = {{ 0, }};
995 struct weston_config_section *section;
996 char *s = NULL;
997 int ret = 0;
998
999 const struct weston_option fbdev_options[] = {
1000 { WESTON_OPTION_INTEGER, "tty", 0, &config.tty },
1001 { WESTON_OPTION_STRING, "device", 0, &config.device },
1002 { WESTON_OPTION_BOOLEAN, "use-gl", 0, &config.use_gl },
1003 };
1004
1005 parse_options(fbdev_options, ARRAY_LENGTH(fbdev_options), argc, argv);
1006
1007 if (!config.device)
1008 config.device = strdup("/dev/fb0");
1009
1010 section = weston_config_get_section(wc, "output", "name", "fbdev");
1011 weston_config_section_get_string(section, "transform", &s, "normal");
1012 if (weston_parse_transform(s, &config.output_transform) < 0)
1013 weston_log("Invalid transform \"%s\" for output fbdev\n", s);
1014 free(s);
1015
1016 config.base.struct_version = WESTON_FBDEV_BACKEND_CONFIG_VERSION;
1017 config.base.struct_size = sizeof(struct weston_fbdev_backend_config);
1018
1019 /* load the actual wayland backend and configure it */
1020 ret = load_backend_new(c, backend, &config.base);
1021
1022 free(config.device);
Benoit Gschwinde16acab2016-04-15 20:28:31 -07001023
1024 return ret;
1025}
1026
1027static int
1028weston_x11_backend_config_append_output_config(struct weston_x11_backend_config *config,
1029 struct weston_x11_backend_output_config *output_config) {
1030 struct weston_x11_backend_output_config *new_outputs;
1031
1032 new_outputs = realloc(config->outputs, (config->num_outputs+1) *
1033 sizeof(struct weston_x11_backend_output_config));
1034 if (new_outputs == NULL)
1035 return -1;
1036
1037 config->outputs = new_outputs;
1038 config->outputs[config->num_outputs].width = output_config->width;
1039 config->outputs[config->num_outputs].height = output_config->height;
1040 config->outputs[config->num_outputs].transform = output_config->transform;
1041 config->outputs[config->num_outputs].scale = output_config->scale;
1042 config->outputs[config->num_outputs].name = strdup(output_config->name);
1043 config->num_outputs++;
1044
1045 return 0;
1046}
1047
1048static int
1049load_x11_backend(struct weston_compositor *c, char const * backend,
1050 int *argc, char **argv, struct weston_config *wc)
1051{
1052 struct weston_x11_backend_output_config default_output;
1053 struct weston_x11_backend_config config = {{ 0, }};
1054 struct weston_config_section *section;
1055 int ret = 0;
1056 int option_width = 0;
1057 int option_height = 0;
1058 int option_scale = 0;
1059 int option_count = 1;
1060 int output_count = 0;
1061 char const *section_name;
1062 int i;
1063 uint32_t j;
1064
1065 const struct weston_option options[] = {
1066 { WESTON_OPTION_INTEGER, "width", 0, &option_width },
1067 { WESTON_OPTION_INTEGER, "height", 0, &option_height },
1068 { WESTON_OPTION_INTEGER, "scale", 0, &option_scale },
1069 { WESTON_OPTION_BOOLEAN, "fullscreen", 'f', &config.fullscreen },
1070 { WESTON_OPTION_INTEGER, "output-count", 0, &option_count },
1071 { WESTON_OPTION_BOOLEAN, "no-input", 0, &config.no_input },
1072 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &config.use_pixman },
1073 };
1074
1075 parse_options(options, ARRAY_LENGTH(options), argc, argv);
1076
1077 section = NULL;
1078 while (weston_config_next_section(wc, &section, &section_name)) {
1079 struct weston_x11_backend_output_config current_output = { 0, };
1080 char *t;
1081 char *mode;
1082
1083 if (strcmp(section_name, "output") != 0) {
1084 continue;
1085 }
1086
1087 weston_config_section_get_string(section, "name", &current_output.name, NULL);
1088 if (current_output.name == NULL || current_output.name[0] != 'X') {
1089 free(current_output.name);
1090 continue;
1091 }
1092
1093 weston_config_section_get_string(section, "mode", &mode, "1024x600");
1094 if (sscanf(mode, "%dx%d", &current_output.width,
1095 &current_output.height) != 2) {
1096 weston_log("Invalid mode \"%s\" for output %s\n",
1097 mode, current_output.name);
1098 current_output.width = 1024;
1099 current_output.height = 600;
1100 }
1101 free(mode);
1102 if (current_output.width < 1)
1103 current_output.width = 1024;
1104 if (current_output.height < 1)
1105 current_output.height = 600;
1106 if (option_width)
1107 current_output.width = option_width;
1108 if (option_height)
1109 current_output.height = option_height;
1110
1111 weston_config_section_get_int(section, "scale", &current_output.scale, 1);
1112 if (option_scale)
1113 current_output.scale = option_scale;
1114
1115 weston_config_section_get_string(section,
1116 "transform", &t, "normal");
1117 if (weston_parse_transform(t, &current_output.transform) < 0)
1118 weston_log("Invalid transform \"%s\" for output %s\n",
1119 t, current_output.name);
1120 free(t);
1121
1122 if (weston_x11_backend_config_append_output_config(&config, &current_output) < 0) {
1123 ret = -1;
1124 goto out;
1125 }
1126
1127 output_count++;
Bryce Harringtonaa258982016-05-03 01:34:23 -07001128 if (output_count >= option_count)
Benoit Gschwinde16acab2016-04-15 20:28:31 -07001129 break;
1130 }
1131
1132 default_output.name = NULL;
1133 default_output.width = option_width ? option_width : 1024;
1134 default_output.height = option_height ? option_height : 600;
1135 default_output.scale = option_scale ? option_scale : 1;
1136 default_output.transform = WL_OUTPUT_TRANSFORM_NORMAL;
1137
1138 for (i = output_count; i < option_count; i++) {
1139 if (asprintf(&default_output.name, "screen%d", i) < 0) {
1140 ret = -1;
1141 goto out;
1142 }
1143
1144 if (weston_x11_backend_config_append_output_config(&config, &default_output) < 0) {
1145 ret = -1;
1146 free(default_output.name);
1147 goto out;
1148 }
1149 free(default_output.name);
1150 }
1151
1152 config.base.struct_version = WESTON_X11_BACKEND_CONFIG_VERSION;
1153 config.base.struct_size = sizeof(struct weston_x11_backend_config);
1154
1155 /* load the actual backend and configure it */
1156 ret = load_backend_new(c, backend, &config.base);
1157
1158out:
1159 for (j = 0; j < config.num_outputs; ++j)
1160 free(config.outputs[j].name);
1161 free(config.outputs);
1162
Benoit Gschwind934e89a2016-04-27 23:56:42 +02001163 return ret;
1164}
1165
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001166static void
1167weston_wayland_output_config_init(struct weston_wayland_backend_output_config *output_config,
1168 struct weston_config_section *config_section,
1169 int option_width, int option_height,
1170 int option_scale)
1171{
1172 char *mode, *t, *str;
1173 unsigned int slen;
1174
1175 weston_config_section_get_string(config_section, "name", &output_config->name,
1176 NULL);
1177 if (output_config->name) {
1178 slen = strlen(output_config->name);
1179 slen += strlen(WINDOW_TITLE " - ");
1180 str = malloc(slen + 1);
1181 if (str)
1182 snprintf(str, slen + 1, WINDOW_TITLE " - %s",
1183 output_config->name);
1184 free(output_config->name);
1185 output_config->name = str;
1186 }
1187 if (!output_config->name)
1188 output_config->name = strdup(WINDOW_TITLE);
1189
1190 weston_config_section_get_string(config_section,
1191 "mode", &mode, "1024x600");
1192 if (sscanf(mode, "%dx%d", &output_config->width, &output_config->height) != 2) {
1193 weston_log("Invalid mode \"%s\" for output %s\n",
1194 mode, output_config->name);
1195 output_config->width = 1024;
1196 output_config->height = 640;
1197 }
1198 free(mode);
1199
1200 if (option_width)
1201 output_config->width = option_width;
1202 if (option_height)
1203 output_config->height = option_height;
1204
1205 weston_config_section_get_int(config_section, "scale", &output_config->scale, 1);
1206
1207 if (option_scale)
1208 output_config->scale = option_scale;
1209
1210 weston_config_section_get_string(config_section,
1211 "transform", &t, "normal");
1212 if (weston_parse_transform(t, &output_config->transform) < 0)
1213 weston_log("Invalid transform \"%s\" for output %s\n",
1214 t, output_config->name);
1215 free(t);
1216
1217}
1218
1219static void
Benoit Gschwinde48ab5f2016-05-10 22:47:55 +02001220weston_wayland_backend_config_release(struct weston_wayland_backend_config *config)
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001221{
1222 int i;
1223
Benoit Gschwinde48ab5f2016-05-10 22:47:55 +02001224 for (i = 0; i < config->num_outputs; ++i) {
1225 free(config->outputs[i].name);
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001226 }
Benoit Gschwinde48ab5f2016-05-10 22:47:55 +02001227 free(config->cursor_theme);
1228 free(config->display_name);
1229 free(config->outputs);
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001230}
1231
1232/*
1233 * Append a new output struct at the end of new_config.outputs and return a
1234 * pointer to the newly allocated structure or NULL if fail. The allocated
1235 * structure is NOT cleared nor set to default values.
1236 */
1237static struct weston_wayland_backend_output_config *
Benoit Gschwind44e302b2016-05-10 22:47:56 +02001238weston_wayland_backend_config_add_new_output(struct weston_wayland_backend_config *config)
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001239{
1240 struct weston_wayland_backend_output_config *outputs;
1241 const size_t element_size = sizeof(struct weston_wayland_backend_output_config);
1242
Benoit Gschwind44e302b2016-05-10 22:47:56 +02001243 outputs = realloc(config->outputs,
1244 (config->num_outputs + 1) * element_size);
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001245 if (!outputs)
1246 return NULL;
Benoit Gschwind44e302b2016-05-10 22:47:56 +02001247 config->num_outputs += 1;
1248 config->outputs = outputs;
1249 return &(config->outputs[config->num_outputs - 1]);
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001250}
1251
1252static int
1253load_wayland_backend_config(struct weston_compositor *compositor, int *argc,
Benoit Gschwind6c1cd2f2016-05-10 22:47:50 +02001254 char *argv[], struct weston_config *wc,
Benoit Gschwind55a22882016-05-10 22:47:51 +02001255 struct weston_wayland_backend_config *config)
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001256{
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001257 struct weston_config_section *section;
1258 struct weston_wayland_backend_output_config *oc;
1259 int count, width, height, scale;
1260 const char *section_name;
1261 char *name;
1262
1263 const struct weston_option wayland_options[] = {
1264 { WESTON_OPTION_INTEGER, "width", 0, &width },
1265 { WESTON_OPTION_INTEGER, "height", 0, &height },
1266 { WESTON_OPTION_INTEGER, "scale", 0, &scale },
Benoit Gschwind55a22882016-05-10 22:47:51 +02001267 { WESTON_OPTION_STRING, "display", 0, &config->display_name },
1268 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &config->use_pixman },
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001269 { WESTON_OPTION_INTEGER, "output-count", 0, &count },
Benoit Gschwind55a22882016-05-10 22:47:51 +02001270 { WESTON_OPTION_BOOLEAN, "fullscreen", 0, &config->fullscreen },
1271 { WESTON_OPTION_BOOLEAN, "sprawl", 0, &config->sprawl },
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001272 };
1273
1274 width = 0;
1275 height = 0;
1276 scale = 0;
Benoit Gschwind55a22882016-05-10 22:47:51 +02001277 config->display_name = NULL;
1278 config->use_pixman = 0;
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001279 count = 1;
Benoit Gschwind55a22882016-05-10 22:47:51 +02001280 config->fullscreen = 0;
1281 config->sprawl = 0;
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001282 parse_options(wayland_options,
1283 ARRAY_LENGTH(wayland_options), argc, argv);
1284
Benoit Gschwind55a22882016-05-10 22:47:51 +02001285 config->cursor_size = 32;
1286 config->cursor_theme = NULL;
1287 config->base.struct_size = sizeof(struct weston_wayland_backend_config);
1288 config->base.struct_version = WESTON_WAYLAND_BACKEND_CONFIG_VERSION;
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001289
Benoit Gschwind6c1cd2f2016-05-10 22:47:50 +02001290 section = weston_config_get_section(wc, "shell", NULL, NULL);
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001291 weston_config_section_get_string(section, "cursor-theme",
Benoit Gschwind55a22882016-05-10 22:47:51 +02001292 &config->cursor_theme, NULL);
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001293 weston_config_section_get_int(section, "cursor-size",
Benoit Gschwind55a22882016-05-10 22:47:51 +02001294 &config->cursor_size, 32);
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001295
Benoit Gschwind55a22882016-05-10 22:47:51 +02001296 if (config->sprawl) {
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001297 /* do nothing, everything is already set */
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001298 return 0;
1299 }
1300
Benoit Gschwind55a22882016-05-10 22:47:51 +02001301 if (config->fullscreen) {
Benoit Gschwind390af6d2016-05-10 22:47:52 +02001302 oc = weston_wayland_backend_config_add_new_output(config);
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001303 if (!oc)
Benoit Gschwind53753842016-05-10 22:47:57 +02001304 return -1;
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001305
1306 oc->width = width;
1307 oc->height = height;
1308 oc->name = NULL;
1309 oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
1310 oc->scale = 1;
1311
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001312 return 0;
1313 }
1314
1315 section = NULL;
Benoit Gschwind6c1cd2f2016-05-10 22:47:50 +02001316 while (weston_config_next_section(wc, &section, &section_name)) {
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001317 if (!section_name || strcmp(section_name, "output") != 0)
1318 continue;
1319 weston_config_section_get_string(section, "name", &name, NULL);
1320 if (name == NULL)
1321 continue;
1322
1323 if (name[0] != 'W' || name[1] != 'L') {
1324 free(name);
1325 continue;
1326 }
1327 free(name);
1328
Benoit Gschwind390af6d2016-05-10 22:47:52 +02001329 oc = weston_wayland_backend_config_add_new_output(config);
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001330 if (!oc)
Benoit Gschwind53753842016-05-10 22:47:57 +02001331 return -1;
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001332
1333 weston_wayland_output_config_init(oc, section, width,
1334 height, scale);
1335 --count;
1336 }
1337
1338 if (!width)
1339 width = 1024;
1340 if (!height)
1341 height = 640;
1342 if (!scale)
1343 scale = 1;
Benoit Gschwind55a22882016-05-10 22:47:51 +02001344
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001345 while (count > 0) {
Benoit Gschwind390af6d2016-05-10 22:47:52 +02001346 oc = weston_wayland_backend_config_add_new_output(config);
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001347 if (!oc)
Benoit Gschwind53753842016-05-10 22:47:57 +02001348 return -1;
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001349
1350 oc->width = width;
1351 oc->height = height;
1352 oc->name = NULL;
1353 oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
1354 oc->scale = scale;
1355
1356 --count;
1357 }
1358
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001359 return 0;
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001360}
1361
1362static int
1363load_wayland_backend(struct weston_compositor *c, char const * backend,
1364 int *argc, char **argv, struct weston_config *wc)
1365{
1366 struct weston_wayland_backend_config config = {{ 0, }};
1367 int ret = 0;
1368
1369 ret = load_wayland_backend_config(c, argc, argv, wc, &config);
1370 if(ret < 0) {
Benoit Gschwind53753842016-05-10 22:47:57 +02001371 weston_wayland_backend_config_release(&config);
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001372 return ret;
1373 }
1374
1375 /* load the actual wayland backend and configure it */
1376 ret = load_backend_new(c, backend, &config.base);
Benoit Gschwind68d6a6c2016-05-10 22:47:53 +02001377 weston_wayland_backend_config_release(&config);
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001378 return ret;
1379}
1380
1381
Benoit Gschwind934e89a2016-04-27 23:56:42 +02001382static int
Giulio Camuffo43008c72015-10-17 19:24:15 +03001383load_backend(struct weston_compositor *compositor, const char *backend,
1384 int *argc, char **argv, struct weston_config *config)
1385{
Benoit Gschwind3c530942016-04-15 20:28:32 -07001386 if (strstr(backend, "headless-backend.so"))
1387 return load_headless_backend(compositor, backend, argc, argv, config);
Benoit Gschwindbd573102016-04-22 17:05:26 +02001388 else if (strstr(backend, "rdp-backend.so"))
1389 return load_rdp_backend(compositor, backend, argc, argv, config);
Benoit Gschwind934e89a2016-04-27 23:56:42 +02001390 else if (strstr(backend, "fbdev-backend.so"))
1391 return load_fbdev_backend(compositor, backend, argc, argv, config);
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07001392 else if (strstr(backend, "drm-backend.so"))
1393 return load_drm_backend(compositor, backend, argc, argv, config);
Benoit Gschwinde16acab2016-04-15 20:28:31 -07001394 else if (strstr(backend, "x11-backend.so"))
1395 return load_x11_backend(compositor, backend, argc, argv, config);
Giulio Camuffo43008c72015-10-17 19:24:15 +03001396 else if (strstr(backend, "wayland-backend.so"))
1397 return load_wayland_backend(compositor, backend, argc, argv, config);
Giulio Camuffo43008c72015-10-17 19:24:15 +03001398
1399 return load_backend_old(compositor, backend, argc, argv, config);
1400}
1401
Giulio Camuffobab996e2014-10-12 00:24:25 +03001402int main(int argc, char *argv[])
1403{
1404 int ret = EXIT_FAILURE;
1405 struct wl_display *display;
1406 struct weston_compositor *ec;
1407 struct wl_event_source *signals[4];
1408 struct wl_event_loop *loop;
Giulio Camuffobab996e2014-10-12 00:24:25 +03001409 int i, fd;
1410 char *backend = NULL;
1411 char *shell = NULL;
1412 char *modules = NULL;
1413 char *option_modules = NULL;
1414 char *log = NULL;
1415 char *server_socket = NULL, *end;
1416 int32_t idle_time = -1;
1417 int32_t help = 0;
1418 char *socket_name = NULL;
1419 int32_t version = 0;
1420 int32_t noconfig = 0;
1421 int32_t numlock_on;
1422 char *config_file = NULL;
1423 struct weston_config *config = NULL;
1424 struct weston_config_section *section;
1425 struct wl_client *primary_client;
1426 struct wl_listener primary_client_destroyed;
1427 struct weston_seat *seat;
1428
1429 const struct weston_option core_options[] = {
1430 { WESTON_OPTION_STRING, "backend", 'B', &backend },
1431 { WESTON_OPTION_STRING, "shell", 0, &shell },
1432 { WESTON_OPTION_STRING, "socket", 'S', &socket_name },
1433 { WESTON_OPTION_INTEGER, "idle-time", 'i', &idle_time },
1434 { WESTON_OPTION_STRING, "modules", 0, &option_modules },
1435 { WESTON_OPTION_STRING, "log", 0, &log },
1436 { WESTON_OPTION_BOOLEAN, "help", 'h', &help },
1437 { WESTON_OPTION_BOOLEAN, "version", 0, &version },
1438 { WESTON_OPTION_BOOLEAN, "no-config", 0, &noconfig },
1439 { WESTON_OPTION_STRING, "config", 'c', &config_file },
1440 };
1441
1442 parse_options(core_options, ARRAY_LENGTH(core_options), &argc, argv);
1443
1444 if (help)
1445 usage(EXIT_SUCCESS);
1446
1447 if (version) {
1448 printf(PACKAGE_STRING "\n");
1449 return EXIT_SUCCESS;
1450 }
1451
1452 weston_log_file_open(log);
1453
1454 weston_log("%s\n"
1455 STAMP_SPACE "%s\n"
1456 STAMP_SPACE "Bug reports to: %s\n"
1457 STAMP_SPACE "Build: %s\n",
1458 PACKAGE_STRING, PACKAGE_URL, PACKAGE_BUGREPORT,
1459 BUILD_ID);
1460 log_uname();
1461
1462 verify_xdg_runtime_dir();
1463
1464 display = wl_display_create();
1465
1466 loop = wl_display_get_event_loop(display);
1467 signals[0] = wl_event_loop_add_signal(loop, SIGTERM, on_term_signal,
1468 display);
1469 signals[1] = wl_event_loop_add_signal(loop, SIGINT, on_term_signal,
1470 display);
1471 signals[2] = wl_event_loop_add_signal(loop, SIGQUIT, on_term_signal,
1472 display);
1473
1474 wl_list_init(&child_process_list);
1475 signals[3] = wl_event_loop_add_signal(loop, SIGCHLD, sigchld_handler,
1476 NULL);
1477
1478 if (!signals[0] || !signals[1] || !signals[2] || !signals[3])
1479 goto out_signals;
1480
1481 if (load_configuration(&config, noconfig, config_file) < 0)
1482 goto out_signals;
1483
1484 section = weston_config_get_section(config, "core", NULL, NULL);
1485
1486 if (!backend) {
1487 weston_config_section_get_string(section, "backend", &backend,
1488 NULL);
1489 if (!backend)
1490 backend = weston_choose_default_backend();
1491 }
1492
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07001493 ec = weston_compositor_create(display, config);
Giulio Camuffobab996e2014-10-12 00:24:25 +03001494 if (ec == NULL) {
1495 weston_log("fatal: failed to create compositor\n");
Giulio Camuffo3c241b12015-10-03 16:25:16 +03001496 goto out;
Giulio Camuffobab996e2014-10-12 00:24:25 +03001497 }
1498
1499 ec->config = config;
1500 if (weston_compositor_init_config(ec, config) < 0)
Giulio Camuffo3c241b12015-10-03 16:25:16 +03001501 goto out;
Giulio Camuffobab996e2014-10-12 00:24:25 +03001502
Giulio Camuffo43008c72015-10-17 19:24:15 +03001503 if (load_backend(ec, backend, &argc, argv, config) < 0) {
Giulio Camuffobab996e2014-10-12 00:24:25 +03001504 weston_log("fatal: failed to create compositor backend\n");
Giulio Camuffo3c241b12015-10-03 16:25:16 +03001505 goto out;
Giulio Camuffobab996e2014-10-12 00:24:25 +03001506 }
1507
1508 catch_signals();
1509 segv_compositor = ec;
1510
1511 if (idle_time < 0)
1512 weston_config_section_get_int(section, "idle-time", &idle_time, -1);
1513 if (idle_time < 0)
1514 idle_time = 300; /* default idle timeout, in seconds */
1515
1516 ec->idle_time = idle_time;
1517 ec->default_pointer_grab = NULL;
1518 ec->exit = handle_exit;
1519
1520 weston_compositor_log_capabilities(ec);
1521
1522 server_socket = getenv("WAYLAND_SERVER_SOCKET");
1523 if (server_socket) {
1524 weston_log("Running with single client\n");
1525 fd = strtol(server_socket, &end, 0);
1526 if (*end != '\0')
1527 fd = -1;
1528 } else {
1529 fd = -1;
1530 }
1531
1532 if (fd != -1) {
1533 primary_client = wl_client_create(display, fd);
1534 if (!primary_client) {
1535 weston_log("fatal: failed to add client: %m\n");
1536 goto out;
1537 }
1538 primary_client_destroyed.notify =
1539 handle_primary_client_destroyed;
1540 wl_client_add_destroy_listener(primary_client,
1541 &primary_client_destroyed);
1542 } else if (weston_create_listening_socket(display, socket_name)) {
1543 goto out;
1544 }
1545
1546 if (!shell)
1547 weston_config_section_get_string(section, "shell", &shell,
1548 "desktop-shell.so");
1549
1550 if (load_modules(ec, shell, &argc, argv) < 0)
1551 goto out;
1552
1553 weston_config_section_get_string(section, "modules", &modules, "");
1554 if (load_modules(ec, modules, &argc, argv) < 0)
1555 goto out;
1556
1557 if (load_modules(ec, option_modules, &argc, argv) < 0)
1558 goto out;
1559
1560 section = weston_config_get_section(config, "keyboard", NULL, NULL);
1561 weston_config_section_get_bool(section, "numlock-on", &numlock_on, 0);
1562 if (numlock_on) {
1563 wl_list_for_each(seat, &ec->seat_list, link) {
Derek Foreman1281a362015-07-31 16:55:32 -05001564 struct weston_keyboard *keyboard =
1565 weston_seat_get_keyboard(seat);
1566
1567 if (keyboard)
1568 weston_keyboard_set_locks(keyboard,
Giulio Camuffobab996e2014-10-12 00:24:25 +03001569 WESTON_NUM_LOCK,
1570 WESTON_NUM_LOCK);
1571 }
1572 }
1573
1574 for (i = 1; i < argc; i++)
1575 weston_log("fatal: unhandled option: %s\n", argv[i]);
1576 if (argc > 1)
1577 goto out;
1578
1579 weston_compositor_wake(ec);
1580
1581 wl_display_run(display);
1582
1583 /* Allow for setting return exit code after
1584 * wl_display_run returns normally. This is
1585 * useful for devs/testers and automated tests
1586 * that want to indicate failure status to
1587 * testing infrastructure above
1588 */
1589 ret = ec->exit_code;
1590
1591out:
1592 weston_compositor_destroy(ec);
1593
1594out_signals:
1595 for (i = ARRAY_LENGTH(signals) - 1; i >= 0; i--)
1596 if (signals[i])
1597 wl_event_source_remove(signals[i]);
1598
1599 wl_display_destroy(display);
1600
1601 weston_log_file_close();
1602
1603 if (config)
1604 weston_config_destroy(config);
1605 free(config_file);
1606 free(backend);
1607 free(shell);
1608 free(socket_name);
1609 free(option_modules);
1610 free(log);
1611 free(modules);
1612
1613 return ret;
1614}