blob: 4e78e917e4719d30945c6f464dd348f00b05f122 [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
Giulio Camuffod52f3b72016-06-02 21:48:11 +0300334WL_EXPORT struct weston_config *
335wet_get_config(struct weston_compositor *compositor)
336{
337 return weston_compositor_get_user_data(compositor);
338}
339
Giulio Camuffobab996e2014-10-12 00:24:25 +0300340static const char xdg_error_message[] =
341 "fatal: environment variable XDG_RUNTIME_DIR is not set.\n";
342
343static const char xdg_wrong_message[] =
344 "fatal: environment variable XDG_RUNTIME_DIR\n"
345 "is set to \"%s\", which is not a directory.\n";
346
347static const char xdg_wrong_mode_message[] =
348 "warning: XDG_RUNTIME_DIR \"%s\" is not configured\n"
349 "correctly. Unix access mode must be 0700 (current mode is %o),\n"
350 "and must be owned by the user (current owner is UID %d).\n";
351
352static const char xdg_detail_message[] =
353 "Refer to your distribution on how to get it, or\n"
354 "http://www.freedesktop.org/wiki/Specifications/basedir-spec\n"
355 "on how to implement it.\n";
356
357static void
358verify_xdg_runtime_dir(void)
359{
360 char *dir = getenv("XDG_RUNTIME_DIR");
361 struct stat s;
362
363 if (!dir) {
364 weston_log(xdg_error_message);
365 weston_log_continue(xdg_detail_message);
366 exit(EXIT_FAILURE);
367 }
368
369 if (stat(dir, &s) || !S_ISDIR(s.st_mode)) {
370 weston_log(xdg_wrong_message, dir);
371 weston_log_continue(xdg_detail_message);
372 exit(EXIT_FAILURE);
373 }
374
375 if ((s.st_mode & 0777) != 0700 || s.st_uid != getuid()) {
376 weston_log(xdg_wrong_mode_message,
377 dir, s.st_mode & 0777, s.st_uid);
378 weston_log_continue(xdg_detail_message);
379 }
380}
381
382static int
383usage(int error_code)
384{
385 fprintf(stderr,
386 "Usage: weston [OPTIONS]\n\n"
387 "This is weston version " VERSION ", the Wayland reference compositor.\n"
388 "Weston supports multiple backends, and depending on which backend is in use\n"
389 "different options will be accepted.\n\n"
390
391
392 "Core options:\n\n"
393 " --version\t\tPrint weston version\n"
394 " -B, --backend=MODULE\tBackend module, one of\n"
395#if defined(BUILD_DRM_COMPOSITOR)
396 "\t\t\t\tdrm-backend.so\n"
397#endif
398#if defined(BUILD_FBDEV_COMPOSITOR)
399 "\t\t\t\tfbdev-backend.so\n"
400#endif
Dawid Gajownik71f57042015-07-31 17:39:00 -0300401#if defined(BUILD_HEADLESS_COMPOSITOR)
402 "\t\t\t\theadless-backend.so\n"
Giulio Camuffobab996e2014-10-12 00:24:25 +0300403#endif
404#if defined(BUILD_RDP_COMPOSITOR)
405 "\t\t\t\trdp-backend.so\n"
406#endif
Dawid Gajownik71f57042015-07-31 17:39:00 -0300407#if defined(BUILD_WAYLAND_COMPOSITOR)
408 "\t\t\t\twayland-backend.so\n"
409#endif
410#if defined(BUILD_X11_COMPOSITOR)
411 "\t\t\t\tx11-backend.so\n"
412#endif
Giulio Camuffobab996e2014-10-12 00:24:25 +0300413 " --shell=MODULE\tShell module, defaults to desktop-shell.so\n"
414 " -S, --socket=NAME\tName of socket to listen on\n"
415 " -i, --idle-time=SECS\tIdle time in seconds\n"
416 " --modules\t\tLoad the comma-separated list of modules\n"
417 " --log=FILE\t\tLog to the given file\n"
418 " -c, --config=FILE\tConfig file to load, defaults to weston.ini\n"
419 " --no-config\t\tDo not read weston.ini\n"
420 " -h, --help\t\tThis help message\n\n");
421
422#if defined(BUILD_DRM_COMPOSITOR)
423 fprintf(stderr,
424 "Options for drm-backend.so:\n\n"
425 " --connector=ID\tBring up only this connector\n"
426 " --seat=SEAT\t\tThe seat that weston should run on\n"
427 " --tty=TTY\t\tThe tty to use\n"
428 " --use-pixman\t\tUse the pixman (CPU) renderer\n"
429 " --current-mode\tPrefer current KMS mode over EDID preferred mode\n\n");
430#endif
431
432#if defined(BUILD_FBDEV_COMPOSITOR)
433 fprintf(stderr,
434 "Options for fbdev-backend.so:\n\n"
435 " --tty=TTY\t\tThe tty to use\n"
436 " --device=DEVICE\tThe framebuffer device to use\n"
437 " --use-gl\t\tUse the GL renderer\n\n");
438#endif
439
Dawid Gajownik71f57042015-07-31 17:39:00 -0300440#if defined(BUILD_HEADLESS_COMPOSITOR)
Giulio Camuffobab996e2014-10-12 00:24:25 +0300441 fprintf(stderr,
Dawid Gajownik71f57042015-07-31 17:39:00 -0300442 "Options for headless-backend.so:\n\n"
443 " --width=WIDTH\t\tWidth of memory surface\n"
444 " --height=HEIGHT\tHeight of memory surface\n"
Giulio Camuffobab996e2014-10-12 00:24:25 +0300445 " --transform=TR\tThe output transformation, TR is one of:\n"
446 "\tnormal 90 180 270 flipped flipped-90 flipped-180 flipped-270\n"
Dawid Gajownik71f57042015-07-31 17:39:00 -0300447 " --use-pixman\t\tUse the pixman (CPU) renderer (default: no rendering)\n\n");
Giulio Camuffobab996e2014-10-12 00:24:25 +0300448#endif
449
450#if defined(BUILD_RDP_COMPOSITOR)
451 fprintf(stderr,
452 "Options for rdp-backend.so:\n\n"
453 " --width=WIDTH\t\tWidth of desktop\n"
454 " --height=HEIGHT\tHeight of desktop\n"
Dawid Gajownikd99a0502015-07-31 14:49:57 -0300455 " --env-socket\t\tUse socket defined in RDP_FD env variable as peer connection\n"
Giulio Camuffobab996e2014-10-12 00:24:25 +0300456 " --address=ADDR\tThe address to bind\n"
457 " --port=PORT\t\tThe port to listen on\n"
458 " --no-clients-resize\tThe RDP peers will be forced to the size of the desktop\n"
459 " --rdp4-key=FILE\tThe file containing the key for RDP4 encryption\n"
460 " --rdp-tls-cert=FILE\tThe file containing the certificate for TLS encryption\n"
461 " --rdp-tls-key=FILE\tThe file containing the private key for TLS encryption\n"
462 "\n");
463#endif
464
Dawid Gajownik71f57042015-07-31 17:39:00 -0300465#if defined(BUILD_WAYLAND_COMPOSITOR)
466 fprintf(stderr,
467 "Options for wayland-backend.so:\n\n"
468 " --width=WIDTH\t\tWidth of Wayland surface\n"
469 " --height=HEIGHT\tHeight of Wayland surface\n"
470 " --scale=SCALE\t\tScale factor of output\n"
471 " --fullscreen\t\tRun in fullscreen mode\n"
472 " --use-pixman\t\tUse the pixman (CPU) renderer\n"
473 " --output-count=COUNT\tCreate multiple outputs\n"
474 " --sprawl\t\tCreate one fullscreen output for every parent output\n"
475 " --display=DISPLAY\tWayland display to connect to\n\n");
476#endif
477
478#if defined(BUILD_X11_COMPOSITOR)
479 fprintf(stderr,
480 "Options for x11-backend.so:\n\n"
481 " --width=WIDTH\t\tWidth of X window\n"
482 " --height=HEIGHT\tHeight of X window\n"
483 " --scale=SCALE\t\tScale factor of output\n"
484 " --fullscreen\t\tRun in fullscreen mode\n"
485 " --use-pixman\t\tUse the pixman (CPU) renderer\n"
486 " --output-count=COUNT\tCreate multiple outputs\n"
487 " --no-input\t\tDont create input devices\n\n");
Giulio Camuffobab996e2014-10-12 00:24:25 +0300488#endif
489
490 exit(error_code);
491}
492
493static int on_term_signal(int signal_number, void *data)
494{
495 struct wl_display *display = data;
496
497 weston_log("caught signal %d\n", signal_number);
498 wl_display_terminate(display);
499
500 return 1;
501}
502
503static void
504on_caught_signal(int s, siginfo_t *siginfo, void *context)
505{
506 /* This signal handler will do a best-effort backtrace, and
507 * then call the backend restore function, which will switch
508 * back to the vt we launched from or ungrab X etc and then
509 * raise SIGTRAP. If we run weston under gdb from X or a
510 * different vt, and tell gdb "handle *s* nostop", this
511 * will allow weston to switch back to gdb on crash and then
512 * gdb will catch the crash with SIGTRAP.*/
513
514 weston_log("caught signal: %d\n", s);
515
516 print_backtrace();
517
518 segv_compositor->backend->restore(segv_compositor);
519
520 raise(SIGTRAP);
521}
522
523static void
524catch_signals(void)
525{
526 struct sigaction action;
527
528 action.sa_flags = SA_SIGINFO | SA_RESETHAND;
529 action.sa_sigaction = on_caught_signal;
530 sigemptyset(&action.sa_mask);
531 sigaction(SIGSEGV, &action, NULL);
532 sigaction(SIGABRT, &action, NULL);
533}
534
535static const char *
536clock_name(clockid_t clk_id)
537{
538 static const char *names[] = {
539 [CLOCK_REALTIME] = "CLOCK_REALTIME",
540 [CLOCK_MONOTONIC] = "CLOCK_MONOTONIC",
541 [CLOCK_MONOTONIC_RAW] = "CLOCK_MONOTONIC_RAW",
542 [CLOCK_REALTIME_COARSE] = "CLOCK_REALTIME_COARSE",
543 [CLOCK_MONOTONIC_COARSE] = "CLOCK_MONOTONIC_COARSE",
Derek Foreman32838c92015-06-29 13:20:34 -0500544#ifdef CLOCK_BOOTTIME
Giulio Camuffobab996e2014-10-12 00:24:25 +0300545 [CLOCK_BOOTTIME] = "CLOCK_BOOTTIME",
Derek Foreman32838c92015-06-29 13:20:34 -0500546#endif
Giulio Camuffobab996e2014-10-12 00:24:25 +0300547 };
548
549 if (clk_id < 0 || (unsigned)clk_id >= ARRAY_LENGTH(names))
550 return "unknown";
551
552 return names[clk_id];
553}
554
555static const struct {
556 uint32_t bit; /* enum weston_capability */
557 const char *desc;
558} capability_strings[] = {
559 { WESTON_CAP_ROTATION_ANY, "arbitrary surface rotation:" },
560 { WESTON_CAP_CAPTURE_YFLIP, "screen capture uses y-flip:" },
561};
562
563static void
564weston_compositor_log_capabilities(struct weston_compositor *compositor)
565{
566 unsigned i;
567 int yes;
568
569 weston_log("Compositor capabilities:\n");
570 for (i = 0; i < ARRAY_LENGTH(capability_strings); i++) {
571 yes = compositor->capabilities & capability_strings[i].bit;
572 weston_log_continue(STAMP_SPACE "%s %s\n",
573 capability_strings[i].desc,
574 yes ? "yes" : "no");
575 }
576
577 weston_log_continue(STAMP_SPACE "presentation clock: %s, id %d\n",
578 clock_name(compositor->presentation_clock),
579 compositor->presentation_clock);
580}
581
582static void
583handle_primary_client_destroyed(struct wl_listener *listener, void *data)
584{
585 struct wl_client *client = data;
586
587 weston_log("Primary client died. Closing...\n");
588
589 wl_display_terminate(wl_client_get_display(client));
590}
591
592static int
593weston_create_listening_socket(struct wl_display *display, const char *socket_name)
594{
595 if (socket_name) {
596 if (wl_display_add_socket(display, socket_name)) {
597 weston_log("fatal: failed to add socket: %m\n");
598 return -1;
599 }
600 } else {
601 socket_name = wl_display_add_socket_auto(display);
602 if (!socket_name) {
603 weston_log("fatal: failed to add socket: %m\n");
604 return -1;
605 }
606 }
607
608 setenv("WAYLAND_DISPLAY", socket_name, 1);
609
610 return 0;
611}
612
613static int
614load_modules(struct weston_compositor *ec, const char *modules,
615 int *argc, char *argv[])
616{
617 const char *p, *end;
618 char buffer[256];
619 int (*module_init)(struct weston_compositor *ec,
620 int *argc, char *argv[]);
621
622 if (modules == NULL)
623 return 0;
624
625 p = modules;
626 while (*p) {
627 end = strchrnul(p, ',');
628 snprintf(buffer, sizeof buffer, "%.*s", (int) (end - p), p);
629 module_init = weston_load_module(buffer, "module_init");
630 if (!module_init)
631 return -1;
632 if (module_init(ec, argc, argv) < 0)
633 return -1;
634 p = end;
635 while (*p == ',')
636 p++;
637
638 }
639
640 return 0;
641}
642
643static int
644weston_compositor_init_config(struct weston_compositor *ec,
645 struct weston_config *config)
646{
647 struct xkb_rule_names xkb_names;
648 struct weston_config_section *s;
649 int repaint_msec;
Bob Ham91880f12016-01-12 10:21:47 +0000650 int vt_switching;
Giulio Camuffobab996e2014-10-12 00:24:25 +0300651
652 s = weston_config_get_section(config, "keyboard", NULL, NULL);
653 weston_config_section_get_string(s, "keymap_rules",
654 (char **) &xkb_names.rules, NULL);
655 weston_config_section_get_string(s, "keymap_model",
656 (char **) &xkb_names.model, NULL);
657 weston_config_section_get_string(s, "keymap_layout",
658 (char **) &xkb_names.layout, NULL);
659 weston_config_section_get_string(s, "keymap_variant",
660 (char **) &xkb_names.variant, NULL);
661 weston_config_section_get_string(s, "keymap_options",
662 (char **) &xkb_names.options, NULL);
663
Giulio Camuffo0358af42016-06-02 21:48:08 +0300664 if (weston_compositor_set_xkb_rule_names(ec, &xkb_names) < 0)
Giulio Camuffobab996e2014-10-12 00:24:25 +0300665 return -1;
666
667 weston_config_section_get_int(s, "repeat-rate",
668 &ec->kb_repeat_rate, 40);
669 weston_config_section_get_int(s, "repeat-delay",
670 &ec->kb_repeat_delay, 400);
671
Bob Ham91880f12016-01-12 10:21:47 +0000672 weston_config_section_get_bool(s, "vt-switching",
673 &vt_switching, true);
674 ec->vt_switching = vt_switching;
675
Giulio Camuffobab996e2014-10-12 00:24:25 +0300676 s = weston_config_get_section(config, "core", NULL, NULL);
677 weston_config_section_get_int(s, "repaint-window", &repaint_msec,
678 ec->repaint_msec);
679 if (repaint_msec < -10 || repaint_msec > 1000) {
680 weston_log("Invalid repaint_window value in config: %d\n",
681 repaint_msec);
682 } else {
683 ec->repaint_msec = repaint_msec;
684 }
685 weston_log("Output repaint window is %d ms maximum.\n",
686 ec->repaint_msec);
687
688 return 0;
689}
690
691static char *
692weston_choose_default_backend(void)
693{
694 char *backend = NULL;
695
696 if (getenv("WAYLAND_DISPLAY") || getenv("WAYLAND_SOCKET"))
697 backend = strdup("wayland-backend.so");
698 else if (getenv("DISPLAY"))
699 backend = strdup("x11-backend.so");
700 else
701 backend = strdup(WESTON_NATIVE_BACKEND);
702
703 return backend;
704}
705
706static const struct { const char *name; uint32_t token; } transforms[] = {
707 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
708 { "90", WL_OUTPUT_TRANSFORM_90 },
709 { "180", WL_OUTPUT_TRANSFORM_180 },
710 { "270", WL_OUTPUT_TRANSFORM_270 },
711 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
712 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
713 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
714 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
715};
716
717WL_EXPORT int
718weston_parse_transform(const char *transform, uint32_t *out)
719{
720 unsigned int i;
721
722 for (i = 0; i < ARRAY_LENGTH(transforms); i++)
723 if (strcmp(transforms[i].name, transform) == 0) {
724 *out = transforms[i].token;
725 return 0;
726 }
727
728 *out = WL_OUTPUT_TRANSFORM_NORMAL;
729 return -1;
730}
731
732WL_EXPORT const char *
733weston_transform_to_string(uint32_t output_transform)
734{
735 unsigned int i;
736
737 for (i = 0; i < ARRAY_LENGTH(transforms); i++)
738 if (transforms[i].token == output_transform)
739 return transforms[i].name;
740
741 return "<illegal value>";
742}
743
744static int
745load_configuration(struct weston_config **config, int32_t noconfig,
746 const char *config_file)
747{
748 const char *file = "weston.ini";
749 const char *full_path;
750
751 *config = NULL;
752
753 if (config_file)
754 file = config_file;
755
756 if (noconfig == 0)
757 *config = weston_config_parse(file);
758
759 if (*config) {
760 full_path = weston_config_get_full_path(*config);
761
762 weston_log("Using config file '%s'\n", full_path);
763 setenv(WESTON_CONFIG_FILE_ENV_VAR, full_path, 1);
764
765 return 0;
766 }
767
768 if (config_file && noconfig == 0) {
769 weston_log("fatal: error opening or reading config file"
770 " '%s'.\n", config_file);
771
772 return -1;
773 }
774
775 weston_log("Starting with no config file.\n");
776 setenv(WESTON_CONFIG_FILE_ENV_VAR, "", 1);
777
778 return 0;
779}
780
781static void
782handle_exit(struct weston_compositor *c)
783{
784 wl_display_terminate(c->wl_display);
785}
786
Giulio Camuffo43008c72015-10-17 19:24:15 +0300787/* Temporary function to be removed when all backends are converted. */
788static int
789load_backend_old(struct weston_compositor *compositor, const char *backend,
790 int *argc, char **argv, struct weston_config *wc)
791{
792 int (*backend_init)(struct weston_compositor *c,
793 int *argc, char *argv[],
794 struct weston_config *config,
795 struct weston_backend_config *config_base);
796
797 backend_init = weston_load_module(backend, "backend_init");
798 if (!backend_init)
799 return -1;
800
801 return backend_init(compositor, argc, argv, wc, NULL);
802}
803
Bryce Harrington98ab08b2016-04-15 20:28:36 -0700804/** Main module call-point for backends.
805 *
806 * All backends should use this routine to access their init routine.
807 * Backends may subclass weston_backend_config to add their own
808 * configuration data, setting the major/minor version in config_base
809 * accordingly.
810 *
811 * The config_base object should be treated as temporary, and any data
812 * copied out of it by backend_init before returning. The load_backend_new
813 * callers may then free the config_base object.
814 *
815 * NOTE: This is a temporary function intended to eventually be replaced
816 * by weston_compositor_load_backend().
817 */
Bryce Harrington6ca25b32016-04-15 20:28:27 -0700818static int
819load_backend_new(struct weston_compositor *compositor, const char *backend,
820 struct weston_backend_config *config_base)
821{
822 int (*backend_init)(struct weston_compositor *c,
823 int *argc, char *argv[],
824 struct weston_config *config,
825 struct weston_backend_config *config_base);
826
827 backend_init = weston_load_module(backend, "backend_init");
828 if (!backend_init)
829 return -1;
830
831 return backend_init(compositor, NULL, NULL, NULL, config_base);
832}
833
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -0700834static enum weston_drm_backend_output_mode
835drm_configure_output(struct weston_compositor *c,
836 bool use_current_mode,
837 const char *name,
838 struct weston_drm_backend_output_config *config)
839{
Giulio Camuffod52f3b72016-06-02 21:48:11 +0300840 struct weston_config *wc = wet_get_config(c);
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -0700841 struct weston_config_section *section;
842 char *s;
843 int scale;
844 enum weston_drm_backend_output_mode mode =
845 WESTON_DRM_BACKEND_OUTPUT_PREFERRED;
846
847 section = weston_config_get_section(wc, "output", "name", name);
848 weston_config_section_get_string(section, "mode", &s, "preferred");
849 if (strcmp(s, "off") == 0) {
850 free(s);
851 return WESTON_DRM_BACKEND_OUTPUT_OFF;
852 }
853
854 if (use_current_mode || strcmp(s, "current") == 0) {
855 mode = WESTON_DRM_BACKEND_OUTPUT_CURRENT;
856 } else if (strcmp(s, "preferred") != 0) {
857 config->modeline = s;
858 s = NULL;
859 }
860 free(s);
861
862 weston_config_section_get_int(section, "scale", &scale, 1);
863 config->base.scale = scale >= 1 ? scale : 1;
864 weston_config_section_get_string(section, "transform", &s, "normal");
865 if (weston_parse_transform(s, &config->base.transform) < 0)
866 weston_log("Invalid transform \"%s\" for output %s\n",
867 s, name);
868 free(s);
869
870 weston_config_section_get_string(section,
871 "gbm-format", &config->gbm_format, NULL);
872 weston_config_section_get_string(section, "seat", &config->seat, "");
873 return mode;
874}
875
876static int
877load_drm_backend(struct weston_compositor *c, const char *backend,
878 int *argc, char **argv, struct weston_config *wc)
879{
880 struct weston_drm_backend_config config = {{ 0, }};
881 struct weston_config_section *section;
882 int ret = 0;
883
884 const struct weston_option options[] = {
885 { WESTON_OPTION_INTEGER, "connector", 0, &config.connector },
886 { WESTON_OPTION_STRING, "seat", 0, &config.seat_id },
887 { WESTON_OPTION_INTEGER, "tty", 0, &config.tty },
888 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &config.use_current_mode },
889 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &config.use_pixman },
890 };
891
892 parse_options(options, ARRAY_LENGTH(options), argc, argv);
893
894 section = weston_config_get_section(wc, "core", NULL, NULL);
895 weston_config_section_get_string(section,
896 "gbm-format", &config.gbm_format,
897 NULL);
898
899 config.base.struct_version = WESTON_DRM_BACKEND_CONFIG_VERSION;
900 config.base.struct_size = sizeof(struct weston_drm_backend_config);
901 config.configure_output = drm_configure_output;
902
903 ret = load_backend_new(c, backend, &config.base);
904
905 free(config.gbm_format);
906 free(config.seat_id);
907
908 return ret;
909}
910
Giulio Camuffo43008c72015-10-17 19:24:15 +0300911static int
Benoit Gschwind3c530942016-04-15 20:28:32 -0700912load_headless_backend(struct weston_compositor *c, char const * backend,
913 int *argc, char **argv, struct weston_config *wc)
914{
915 struct weston_headless_backend_config config = {{ 0, }};
916 int ret = 0;
Benoit Gschwind2da6d0c2016-04-29 15:21:54 +0200917 char *transform = NULL;
Benoit Gschwind3c530942016-04-15 20:28:32 -0700918
919 config.width = 1024;
920 config.height = 640;
921
922 const struct weston_option options[] = {
923 { WESTON_OPTION_INTEGER, "width", 0, &config.width },
924 { WESTON_OPTION_INTEGER, "height", 0, &config.height },
925 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &config.use_pixman },
926 { WESTON_OPTION_STRING, "transform", 0, &transform },
927 };
928
929 parse_options(options, ARRAY_LENGTH(options), argc, argv);
930
Benoit Gschwind2da6d0c2016-04-29 15:21:54 +0200931 config.transform = WL_OUTPUT_TRANSFORM_NORMAL;
932 if (transform) {
933 if (weston_parse_transform(transform, &config.transform) < 0)
934 weston_log("Invalid transform \"%s\"\n", transform);
935 free(transform);
936 }
Benoit Gschwind3c530942016-04-15 20:28:32 -0700937
938 config.base.struct_version = WESTON_HEADLESS_BACKEND_CONFIG_VERSION;
939 config.base.struct_size = sizeof(struct weston_headless_backend_config);
940
941 /* load the actual wayland backend and configure it */
942 ret = load_backend_new(c, backend, &config.base);
943
944 return ret;
945}
946
Benoit Gschwindbd573102016-04-22 17:05:26 +0200947static void
948weston_rdp_backend_config_init(struct weston_rdp_backend_config *config)
949{
950 config->base.struct_version = WESTON_RDP_BACKEND_CONFIG_VERSION;
951 config->base.struct_size = sizeof(struct weston_rdp_backend_config);
952
953 config->width = 640;
954 config->height = 480;
955 config->bind_address = NULL;
956 config->port = 3389;
957 config->rdp_key = NULL;
958 config->server_cert = NULL;
959 config->server_key = NULL;
960 config->env_socket = 0;
961 config->no_clients_resize = 0;
962}
963
964static int
965load_rdp_backend(struct weston_compositor *c, char const * backend,
966 int *argc, char *argv[], struct weston_config *wc)
967{
968 struct weston_rdp_backend_config config = {{ 0, }};
969 int ret = 0;
970
971 weston_rdp_backend_config_init(&config);
972
973 const struct weston_option rdp_options[] = {
974 { WESTON_OPTION_BOOLEAN, "env-socket", 0, &config.env_socket },
975 { WESTON_OPTION_INTEGER, "width", 0, &config.width },
976 { WESTON_OPTION_INTEGER, "height", 0, &config.height },
977 { WESTON_OPTION_STRING, "address", 0, &config.bind_address },
978 { WESTON_OPTION_INTEGER, "port", 0, &config.port },
979 { WESTON_OPTION_BOOLEAN, "no-clients-resize", 0, &config.no_clients_resize },
980 { WESTON_OPTION_STRING, "rdp4-key", 0, &config.rdp_key },
981 { WESTON_OPTION_STRING, "rdp-tls-cert", 0, &config.server_cert },
982 { WESTON_OPTION_STRING, "rdp-tls-key", 0, &config.server_key }
983 };
984
985 parse_options(rdp_options, ARRAY_LENGTH(rdp_options), argc, argv);
986
987 ret = load_backend_new(c, backend, &config.base);
988
989 free(config.bind_address);
990 free(config.rdp_key);
991 free(config.server_cert);
992 free(config.server_key);
993 return ret;
994}
995
Benoit Gschwind3c530942016-04-15 20:28:32 -0700996static int
Benoit Gschwind934e89a2016-04-27 23:56:42 +0200997load_fbdev_backend(struct weston_compositor *c, char const * backend,
998 int *argc, char **argv, struct weston_config *wc)
999{
1000 struct weston_fbdev_backend_config config = {{ 0, }};
1001 struct weston_config_section *section;
1002 char *s = NULL;
1003 int ret = 0;
1004
1005 const struct weston_option fbdev_options[] = {
1006 { WESTON_OPTION_INTEGER, "tty", 0, &config.tty },
1007 { WESTON_OPTION_STRING, "device", 0, &config.device },
1008 { WESTON_OPTION_BOOLEAN, "use-gl", 0, &config.use_gl },
1009 };
1010
1011 parse_options(fbdev_options, ARRAY_LENGTH(fbdev_options), argc, argv);
1012
1013 if (!config.device)
1014 config.device = strdup("/dev/fb0");
1015
1016 section = weston_config_get_section(wc, "output", "name", "fbdev");
1017 weston_config_section_get_string(section, "transform", &s, "normal");
1018 if (weston_parse_transform(s, &config.output_transform) < 0)
1019 weston_log("Invalid transform \"%s\" for output fbdev\n", s);
1020 free(s);
1021
1022 config.base.struct_version = WESTON_FBDEV_BACKEND_CONFIG_VERSION;
1023 config.base.struct_size = sizeof(struct weston_fbdev_backend_config);
1024
1025 /* load the actual wayland backend and configure it */
1026 ret = load_backend_new(c, backend, &config.base);
1027
1028 free(config.device);
Benoit Gschwinde16acab2016-04-15 20:28:31 -07001029
1030 return ret;
1031}
1032
1033static int
1034weston_x11_backend_config_append_output_config(struct weston_x11_backend_config *config,
1035 struct weston_x11_backend_output_config *output_config) {
1036 struct weston_x11_backend_output_config *new_outputs;
1037
1038 new_outputs = realloc(config->outputs, (config->num_outputs+1) *
1039 sizeof(struct weston_x11_backend_output_config));
1040 if (new_outputs == NULL)
1041 return -1;
1042
1043 config->outputs = new_outputs;
1044 config->outputs[config->num_outputs].width = output_config->width;
1045 config->outputs[config->num_outputs].height = output_config->height;
1046 config->outputs[config->num_outputs].transform = output_config->transform;
1047 config->outputs[config->num_outputs].scale = output_config->scale;
1048 config->outputs[config->num_outputs].name = strdup(output_config->name);
1049 config->num_outputs++;
1050
1051 return 0;
1052}
1053
1054static int
1055load_x11_backend(struct weston_compositor *c, char const * backend,
1056 int *argc, char **argv, struct weston_config *wc)
1057{
1058 struct weston_x11_backend_output_config default_output;
1059 struct weston_x11_backend_config config = {{ 0, }};
1060 struct weston_config_section *section;
1061 int ret = 0;
1062 int option_width = 0;
1063 int option_height = 0;
1064 int option_scale = 0;
1065 int option_count = 1;
1066 int output_count = 0;
1067 char const *section_name;
1068 int i;
1069 uint32_t j;
1070
1071 const struct weston_option options[] = {
1072 { WESTON_OPTION_INTEGER, "width", 0, &option_width },
1073 { WESTON_OPTION_INTEGER, "height", 0, &option_height },
1074 { WESTON_OPTION_INTEGER, "scale", 0, &option_scale },
1075 { WESTON_OPTION_BOOLEAN, "fullscreen", 'f', &config.fullscreen },
1076 { WESTON_OPTION_INTEGER, "output-count", 0, &option_count },
1077 { WESTON_OPTION_BOOLEAN, "no-input", 0, &config.no_input },
1078 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &config.use_pixman },
1079 };
1080
1081 parse_options(options, ARRAY_LENGTH(options), argc, argv);
1082
1083 section = NULL;
1084 while (weston_config_next_section(wc, &section, &section_name)) {
1085 struct weston_x11_backend_output_config current_output = { 0, };
1086 char *t;
1087 char *mode;
1088
1089 if (strcmp(section_name, "output") != 0) {
1090 continue;
1091 }
1092
1093 weston_config_section_get_string(section, "name", &current_output.name, NULL);
1094 if (current_output.name == NULL || current_output.name[0] != 'X') {
1095 free(current_output.name);
1096 continue;
1097 }
1098
1099 weston_config_section_get_string(section, "mode", &mode, "1024x600");
1100 if (sscanf(mode, "%dx%d", &current_output.width,
1101 &current_output.height) != 2) {
1102 weston_log("Invalid mode \"%s\" for output %s\n",
1103 mode, current_output.name);
1104 current_output.width = 1024;
1105 current_output.height = 600;
1106 }
1107 free(mode);
1108 if (current_output.width < 1)
1109 current_output.width = 1024;
1110 if (current_output.height < 1)
1111 current_output.height = 600;
1112 if (option_width)
1113 current_output.width = option_width;
1114 if (option_height)
1115 current_output.height = option_height;
1116
1117 weston_config_section_get_int(section, "scale", &current_output.scale, 1);
1118 if (option_scale)
1119 current_output.scale = option_scale;
1120
1121 weston_config_section_get_string(section,
1122 "transform", &t, "normal");
1123 if (weston_parse_transform(t, &current_output.transform) < 0)
1124 weston_log("Invalid transform \"%s\" for output %s\n",
1125 t, current_output.name);
1126 free(t);
1127
1128 if (weston_x11_backend_config_append_output_config(&config, &current_output) < 0) {
1129 ret = -1;
1130 goto out;
1131 }
1132
1133 output_count++;
Bryce Harringtonaa258982016-05-03 01:34:23 -07001134 if (output_count >= option_count)
Benoit Gschwinde16acab2016-04-15 20:28:31 -07001135 break;
1136 }
1137
1138 default_output.name = NULL;
1139 default_output.width = option_width ? option_width : 1024;
1140 default_output.height = option_height ? option_height : 600;
1141 default_output.scale = option_scale ? option_scale : 1;
1142 default_output.transform = WL_OUTPUT_TRANSFORM_NORMAL;
1143
1144 for (i = output_count; i < option_count; i++) {
1145 if (asprintf(&default_output.name, "screen%d", i) < 0) {
1146 ret = -1;
1147 goto out;
1148 }
1149
1150 if (weston_x11_backend_config_append_output_config(&config, &default_output) < 0) {
1151 ret = -1;
1152 free(default_output.name);
1153 goto out;
1154 }
1155 free(default_output.name);
1156 }
1157
1158 config.base.struct_version = WESTON_X11_BACKEND_CONFIG_VERSION;
1159 config.base.struct_size = sizeof(struct weston_x11_backend_config);
1160
1161 /* load the actual backend and configure it */
1162 ret = load_backend_new(c, backend, &config.base);
1163
1164out:
1165 for (j = 0; j < config.num_outputs; ++j)
1166 free(config.outputs[j].name);
1167 free(config.outputs);
1168
Benoit Gschwind934e89a2016-04-27 23:56:42 +02001169 return ret;
1170}
1171
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001172static void
1173weston_wayland_output_config_init(struct weston_wayland_backend_output_config *output_config,
1174 struct weston_config_section *config_section,
1175 int option_width, int option_height,
1176 int option_scale)
1177{
1178 char *mode, *t, *str;
1179 unsigned int slen;
1180
1181 weston_config_section_get_string(config_section, "name", &output_config->name,
1182 NULL);
1183 if (output_config->name) {
1184 slen = strlen(output_config->name);
1185 slen += strlen(WINDOW_TITLE " - ");
1186 str = malloc(slen + 1);
1187 if (str)
1188 snprintf(str, slen + 1, WINDOW_TITLE " - %s",
1189 output_config->name);
1190 free(output_config->name);
1191 output_config->name = str;
1192 }
1193 if (!output_config->name)
1194 output_config->name = strdup(WINDOW_TITLE);
1195
1196 weston_config_section_get_string(config_section,
1197 "mode", &mode, "1024x600");
1198 if (sscanf(mode, "%dx%d", &output_config->width, &output_config->height) != 2) {
1199 weston_log("Invalid mode \"%s\" for output %s\n",
1200 mode, output_config->name);
1201 output_config->width = 1024;
1202 output_config->height = 640;
1203 }
1204 free(mode);
1205
1206 if (option_width)
1207 output_config->width = option_width;
1208 if (option_height)
1209 output_config->height = option_height;
1210
1211 weston_config_section_get_int(config_section, "scale", &output_config->scale, 1);
1212
1213 if (option_scale)
1214 output_config->scale = option_scale;
1215
1216 weston_config_section_get_string(config_section,
1217 "transform", &t, "normal");
1218 if (weston_parse_transform(t, &output_config->transform) < 0)
1219 weston_log("Invalid transform \"%s\" for output %s\n",
1220 t, output_config->name);
1221 free(t);
1222
1223}
1224
1225static void
Benoit Gschwinde48ab5f2016-05-10 22:47:55 +02001226weston_wayland_backend_config_release(struct weston_wayland_backend_config *config)
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001227{
1228 int i;
1229
Benoit Gschwinde48ab5f2016-05-10 22:47:55 +02001230 for (i = 0; i < config->num_outputs; ++i) {
1231 free(config->outputs[i].name);
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001232 }
Benoit Gschwinde48ab5f2016-05-10 22:47:55 +02001233 free(config->cursor_theme);
1234 free(config->display_name);
1235 free(config->outputs);
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001236}
1237
1238/*
1239 * Append a new output struct at the end of new_config.outputs and return a
1240 * pointer to the newly allocated structure or NULL if fail. The allocated
1241 * structure is NOT cleared nor set to default values.
1242 */
1243static struct weston_wayland_backend_output_config *
Benoit Gschwind44e302b2016-05-10 22:47:56 +02001244weston_wayland_backend_config_add_new_output(struct weston_wayland_backend_config *config)
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001245{
1246 struct weston_wayland_backend_output_config *outputs;
1247 const size_t element_size = sizeof(struct weston_wayland_backend_output_config);
1248
Benoit Gschwind44e302b2016-05-10 22:47:56 +02001249 outputs = realloc(config->outputs,
1250 (config->num_outputs + 1) * element_size);
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001251 if (!outputs)
1252 return NULL;
Benoit Gschwind44e302b2016-05-10 22:47:56 +02001253 config->num_outputs += 1;
1254 config->outputs = outputs;
1255 return &(config->outputs[config->num_outputs - 1]);
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001256}
1257
1258static int
1259load_wayland_backend_config(struct weston_compositor *compositor, int *argc,
Benoit Gschwind6c1cd2f2016-05-10 22:47:50 +02001260 char *argv[], struct weston_config *wc,
Benoit Gschwind55a22882016-05-10 22:47:51 +02001261 struct weston_wayland_backend_config *config)
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001262{
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001263 struct weston_config_section *section;
1264 struct weston_wayland_backend_output_config *oc;
1265 int count, width, height, scale;
1266 const char *section_name;
1267 char *name;
1268
1269 const struct weston_option wayland_options[] = {
1270 { WESTON_OPTION_INTEGER, "width", 0, &width },
1271 { WESTON_OPTION_INTEGER, "height", 0, &height },
1272 { WESTON_OPTION_INTEGER, "scale", 0, &scale },
Benoit Gschwind55a22882016-05-10 22:47:51 +02001273 { WESTON_OPTION_STRING, "display", 0, &config->display_name },
1274 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &config->use_pixman },
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001275 { WESTON_OPTION_INTEGER, "output-count", 0, &count },
Benoit Gschwind55a22882016-05-10 22:47:51 +02001276 { WESTON_OPTION_BOOLEAN, "fullscreen", 0, &config->fullscreen },
1277 { WESTON_OPTION_BOOLEAN, "sprawl", 0, &config->sprawl },
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001278 };
1279
1280 width = 0;
1281 height = 0;
1282 scale = 0;
Benoit Gschwind55a22882016-05-10 22:47:51 +02001283 config->display_name = NULL;
1284 config->use_pixman = 0;
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001285 count = 1;
Benoit Gschwind55a22882016-05-10 22:47:51 +02001286 config->fullscreen = 0;
1287 config->sprawl = 0;
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001288 parse_options(wayland_options,
1289 ARRAY_LENGTH(wayland_options), argc, argv);
1290
Benoit Gschwind55a22882016-05-10 22:47:51 +02001291 config->cursor_size = 32;
1292 config->cursor_theme = NULL;
1293 config->base.struct_size = sizeof(struct weston_wayland_backend_config);
1294 config->base.struct_version = WESTON_WAYLAND_BACKEND_CONFIG_VERSION;
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001295
Benoit Gschwind6c1cd2f2016-05-10 22:47:50 +02001296 section = weston_config_get_section(wc, "shell", NULL, NULL);
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001297 weston_config_section_get_string(section, "cursor-theme",
Benoit Gschwind55a22882016-05-10 22:47:51 +02001298 &config->cursor_theme, NULL);
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001299 weston_config_section_get_int(section, "cursor-size",
Benoit Gschwind55a22882016-05-10 22:47:51 +02001300 &config->cursor_size, 32);
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001301
Benoit Gschwind55a22882016-05-10 22:47:51 +02001302 if (config->sprawl) {
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001303 /* do nothing, everything is already set */
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001304 return 0;
1305 }
1306
Benoit Gschwind55a22882016-05-10 22:47:51 +02001307 if (config->fullscreen) {
Benoit Gschwind390af6d2016-05-10 22:47:52 +02001308 oc = weston_wayland_backend_config_add_new_output(config);
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001309 if (!oc)
Benoit Gschwind53753842016-05-10 22:47:57 +02001310 return -1;
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001311
1312 oc->width = width;
1313 oc->height = height;
1314 oc->name = NULL;
1315 oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
1316 oc->scale = 1;
1317
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001318 return 0;
1319 }
1320
1321 section = NULL;
Benoit Gschwind6c1cd2f2016-05-10 22:47:50 +02001322 while (weston_config_next_section(wc, &section, &section_name)) {
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001323 if (!section_name || strcmp(section_name, "output") != 0)
1324 continue;
1325 weston_config_section_get_string(section, "name", &name, NULL);
1326 if (name == NULL)
1327 continue;
1328
1329 if (name[0] != 'W' || name[1] != 'L') {
1330 free(name);
1331 continue;
1332 }
1333 free(name);
1334
Benoit Gschwind390af6d2016-05-10 22:47:52 +02001335 oc = weston_wayland_backend_config_add_new_output(config);
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001336 if (!oc)
Benoit Gschwind53753842016-05-10 22:47:57 +02001337 return -1;
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001338
1339 weston_wayland_output_config_init(oc, section, width,
1340 height, scale);
1341 --count;
1342 }
1343
1344 if (!width)
1345 width = 1024;
1346 if (!height)
1347 height = 640;
1348 if (!scale)
1349 scale = 1;
Benoit Gschwind55a22882016-05-10 22:47:51 +02001350
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001351 while (count > 0) {
Benoit Gschwind390af6d2016-05-10 22:47:52 +02001352 oc = weston_wayland_backend_config_add_new_output(config);
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001353 if (!oc)
Benoit Gschwind53753842016-05-10 22:47:57 +02001354 return -1;
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001355
1356 oc->width = width;
1357 oc->height = height;
1358 oc->name = NULL;
1359 oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
1360 oc->scale = scale;
1361
1362 --count;
1363 }
1364
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001365 return 0;
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001366}
1367
1368static int
1369load_wayland_backend(struct weston_compositor *c, char const * backend,
1370 int *argc, char **argv, struct weston_config *wc)
1371{
1372 struct weston_wayland_backend_config config = {{ 0, }};
1373 int ret = 0;
1374
1375 ret = load_wayland_backend_config(c, argc, argv, wc, &config);
1376 if(ret < 0) {
Benoit Gschwind53753842016-05-10 22:47:57 +02001377 weston_wayland_backend_config_release(&config);
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001378 return ret;
1379 }
1380
1381 /* load the actual wayland backend and configure it */
1382 ret = load_backend_new(c, backend, &config.base);
Benoit Gschwind68d6a6c2016-05-10 22:47:53 +02001383 weston_wayland_backend_config_release(&config);
Benoit Gschwind3ff10da2016-05-10 22:47:49 +02001384 return ret;
1385}
1386
1387
Benoit Gschwind934e89a2016-04-27 23:56:42 +02001388static int
Giulio Camuffo43008c72015-10-17 19:24:15 +03001389load_backend(struct weston_compositor *compositor, const char *backend,
1390 int *argc, char **argv, struct weston_config *config)
1391{
Benoit Gschwind3c530942016-04-15 20:28:32 -07001392 if (strstr(backend, "headless-backend.so"))
1393 return load_headless_backend(compositor, backend, argc, argv, config);
Benoit Gschwindbd573102016-04-22 17:05:26 +02001394 else if (strstr(backend, "rdp-backend.so"))
1395 return load_rdp_backend(compositor, backend, argc, argv, config);
Benoit Gschwind934e89a2016-04-27 23:56:42 +02001396 else if (strstr(backend, "fbdev-backend.so"))
1397 return load_fbdev_backend(compositor, backend, argc, argv, config);
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07001398 else if (strstr(backend, "drm-backend.so"))
1399 return load_drm_backend(compositor, backend, argc, argv, config);
Benoit Gschwinde16acab2016-04-15 20:28:31 -07001400 else if (strstr(backend, "x11-backend.so"))
1401 return load_x11_backend(compositor, backend, argc, argv, config);
Giulio Camuffo43008c72015-10-17 19:24:15 +03001402 else if (strstr(backend, "wayland-backend.so"))
1403 return load_wayland_backend(compositor, backend, argc, argv, config);
Giulio Camuffo43008c72015-10-17 19:24:15 +03001404
1405 return load_backend_old(compositor, backend, argc, argv, config);
1406}
1407
Giulio Camuffobab996e2014-10-12 00:24:25 +03001408int main(int argc, char *argv[])
1409{
1410 int ret = EXIT_FAILURE;
1411 struct wl_display *display;
1412 struct weston_compositor *ec;
1413 struct wl_event_source *signals[4];
1414 struct wl_event_loop *loop;
Giulio Camuffobab996e2014-10-12 00:24:25 +03001415 int i, fd;
1416 char *backend = NULL;
1417 char *shell = NULL;
1418 char *modules = NULL;
1419 char *option_modules = NULL;
1420 char *log = NULL;
1421 char *server_socket = NULL, *end;
1422 int32_t idle_time = -1;
1423 int32_t help = 0;
1424 char *socket_name = NULL;
1425 int32_t version = 0;
1426 int32_t noconfig = 0;
1427 int32_t numlock_on;
1428 char *config_file = NULL;
1429 struct weston_config *config = NULL;
1430 struct weston_config_section *section;
1431 struct wl_client *primary_client;
1432 struct wl_listener primary_client_destroyed;
1433 struct weston_seat *seat;
1434
1435 const struct weston_option core_options[] = {
1436 { WESTON_OPTION_STRING, "backend", 'B', &backend },
1437 { WESTON_OPTION_STRING, "shell", 0, &shell },
1438 { WESTON_OPTION_STRING, "socket", 'S', &socket_name },
1439 { WESTON_OPTION_INTEGER, "idle-time", 'i', &idle_time },
1440 { WESTON_OPTION_STRING, "modules", 0, &option_modules },
1441 { WESTON_OPTION_STRING, "log", 0, &log },
1442 { WESTON_OPTION_BOOLEAN, "help", 'h', &help },
1443 { WESTON_OPTION_BOOLEAN, "version", 0, &version },
1444 { WESTON_OPTION_BOOLEAN, "no-config", 0, &noconfig },
1445 { WESTON_OPTION_STRING, "config", 'c', &config_file },
1446 };
1447
1448 parse_options(core_options, ARRAY_LENGTH(core_options), &argc, argv);
1449
1450 if (help)
1451 usage(EXIT_SUCCESS);
1452
1453 if (version) {
1454 printf(PACKAGE_STRING "\n");
1455 return EXIT_SUCCESS;
1456 }
1457
1458 weston_log_file_open(log);
1459
1460 weston_log("%s\n"
1461 STAMP_SPACE "%s\n"
1462 STAMP_SPACE "Bug reports to: %s\n"
1463 STAMP_SPACE "Build: %s\n",
1464 PACKAGE_STRING, PACKAGE_URL, PACKAGE_BUGREPORT,
1465 BUILD_ID);
1466 log_uname();
1467
1468 verify_xdg_runtime_dir();
1469
1470 display = wl_display_create();
1471
1472 loop = wl_display_get_event_loop(display);
1473 signals[0] = wl_event_loop_add_signal(loop, SIGTERM, on_term_signal,
1474 display);
1475 signals[1] = wl_event_loop_add_signal(loop, SIGINT, on_term_signal,
1476 display);
1477 signals[2] = wl_event_loop_add_signal(loop, SIGQUIT, on_term_signal,
1478 display);
1479
1480 wl_list_init(&child_process_list);
1481 signals[3] = wl_event_loop_add_signal(loop, SIGCHLD, sigchld_handler,
1482 NULL);
1483
1484 if (!signals[0] || !signals[1] || !signals[2] || !signals[3])
1485 goto out_signals;
1486
1487 if (load_configuration(&config, noconfig, config_file) < 0)
1488 goto out_signals;
1489
1490 section = weston_config_get_section(config, "core", NULL, NULL);
1491
1492 if (!backend) {
1493 weston_config_section_get_string(section, "backend", &backend,
1494 NULL);
1495 if (!backend)
1496 backend = weston_choose_default_backend();
1497 }
1498
Giulio Camuffo1c0e40d2016-04-29 15:40:34 -07001499 ec = weston_compositor_create(display, config);
Giulio Camuffobab996e2014-10-12 00:24:25 +03001500 if (ec == NULL) {
1501 weston_log("fatal: failed to create compositor\n");
Giulio Camuffo3c241b12015-10-03 16:25:16 +03001502 goto out;
Giulio Camuffobab996e2014-10-12 00:24:25 +03001503 }
1504
Giulio Camuffobab996e2014-10-12 00:24:25 +03001505 if (weston_compositor_init_config(ec, config) < 0)
Giulio Camuffo3c241b12015-10-03 16:25:16 +03001506 goto out;
Giulio Camuffobab996e2014-10-12 00:24:25 +03001507
Giulio Camuffo43008c72015-10-17 19:24:15 +03001508 if (load_backend(ec, backend, &argc, argv, config) < 0) {
Giulio Camuffobab996e2014-10-12 00:24:25 +03001509 weston_log("fatal: failed to create compositor backend\n");
Giulio Camuffo3c241b12015-10-03 16:25:16 +03001510 goto out;
Giulio Camuffobab996e2014-10-12 00:24:25 +03001511 }
1512
1513 catch_signals();
1514 segv_compositor = ec;
1515
1516 if (idle_time < 0)
1517 weston_config_section_get_int(section, "idle-time", &idle_time, -1);
1518 if (idle_time < 0)
1519 idle_time = 300; /* default idle timeout, in seconds */
1520
1521 ec->idle_time = idle_time;
1522 ec->default_pointer_grab = NULL;
1523 ec->exit = handle_exit;
1524
1525 weston_compositor_log_capabilities(ec);
1526
1527 server_socket = getenv("WAYLAND_SERVER_SOCKET");
1528 if (server_socket) {
1529 weston_log("Running with single client\n");
1530 fd = strtol(server_socket, &end, 0);
1531 if (*end != '\0')
1532 fd = -1;
1533 } else {
1534 fd = -1;
1535 }
1536
1537 if (fd != -1) {
1538 primary_client = wl_client_create(display, fd);
1539 if (!primary_client) {
1540 weston_log("fatal: failed to add client: %m\n");
1541 goto out;
1542 }
1543 primary_client_destroyed.notify =
1544 handle_primary_client_destroyed;
1545 wl_client_add_destroy_listener(primary_client,
1546 &primary_client_destroyed);
1547 } else if (weston_create_listening_socket(display, socket_name)) {
1548 goto out;
1549 }
1550
1551 if (!shell)
1552 weston_config_section_get_string(section, "shell", &shell,
1553 "desktop-shell.so");
1554
1555 if (load_modules(ec, shell, &argc, argv) < 0)
1556 goto out;
1557
1558 weston_config_section_get_string(section, "modules", &modules, "");
1559 if (load_modules(ec, modules, &argc, argv) < 0)
1560 goto out;
1561
1562 if (load_modules(ec, option_modules, &argc, argv) < 0)
1563 goto out;
1564
1565 section = weston_config_get_section(config, "keyboard", NULL, NULL);
1566 weston_config_section_get_bool(section, "numlock-on", &numlock_on, 0);
1567 if (numlock_on) {
1568 wl_list_for_each(seat, &ec->seat_list, link) {
Derek Foreman1281a362015-07-31 16:55:32 -05001569 struct weston_keyboard *keyboard =
1570 weston_seat_get_keyboard(seat);
1571
1572 if (keyboard)
1573 weston_keyboard_set_locks(keyboard,
Giulio Camuffobab996e2014-10-12 00:24:25 +03001574 WESTON_NUM_LOCK,
1575 WESTON_NUM_LOCK);
1576 }
1577 }
1578
1579 for (i = 1; i < argc; i++)
1580 weston_log("fatal: unhandled option: %s\n", argv[i]);
1581 if (argc > 1)
1582 goto out;
1583
1584 weston_compositor_wake(ec);
1585
1586 wl_display_run(display);
1587
1588 /* Allow for setting return exit code after
1589 * wl_display_run returns normally. This is
1590 * useful for devs/testers and automated tests
1591 * that want to indicate failure status to
1592 * testing infrastructure above
1593 */
1594 ret = ec->exit_code;
1595
1596out:
1597 weston_compositor_destroy(ec);
1598
1599out_signals:
1600 for (i = ARRAY_LENGTH(signals) - 1; i >= 0; i--)
1601 if (signals[i])
1602 wl_event_source_remove(signals[i]);
1603
1604 wl_display_destroy(display);
1605
1606 weston_log_file_close();
1607
1608 if (config)
1609 weston_config_destroy(config);
1610 free(config_file);
1611 free(backend);
1612 free(shell);
1613 free(socket_name);
1614 free(option_modules);
1615 free(log);
1616 free(modules);
1617
1618 return ret;
1619}