e1ebab53090fef0483f3c105cfb10961a24e7d08
[src/agl-compositor.git] / src / main.c
1 /*
2  * Copyright © 2012-2019 Collabora, Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25
26 #include "ivi-compositor.h"
27
28 #include <assert.h>
29 #include <errno.h>
30 #include <signal.h>
31 #include <stdarg.h>
32 #include <stdbool.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <linux/input.h>
38
39 #include <libweston/backend-drm.h>
40 #include <libweston/backend-wayland.h>
41 #ifdef HAVE_BACKEND_X11
42 #include <libweston/backend-x11.h>
43 #endif
44 #include <libweston/libweston.h>
45 #include <libweston/windowed-output-api.h>
46 #include <libweston/config-parser.h>
47 #include <libweston/weston-log.h>
48
49 #include "shared/os-compatibility.h"
50
51 #include "agl-shell-server-protocol.h"
52
53 struct ivi_compositor *
54 to_ivi_compositor(struct weston_compositor *ec)
55 {
56         return weston_compositor_get_user_data(ec);
57 }
58
59 static void
60 handle_output_destroy(struct wl_listener *listener, void *data)
61 {
62         struct ivi_output *output;
63
64         output = wl_container_of(listener, output, output_destroy);
65         assert(output->output == data);
66
67         output->output = NULL;
68         wl_list_remove(&output->output_destroy.link);
69 }
70
71 struct ivi_output *
72 to_ivi_output(struct weston_output *o)
73 {
74         struct wl_listener *listener;
75         struct ivi_output *output;
76
77         listener = weston_output_get_destroy_listener(o, handle_output_destroy);
78         output = wl_container_of(listener, output, output_destroy);
79
80         return output;
81 }
82
83 static struct ivi_output *
84 ivi_ensure_output(struct ivi_compositor *ivi, char *name,
85                   struct weston_config_section *config)
86 {
87         struct ivi_output *output = NULL;
88         wl_list_for_each(output, &ivi->outputs, link) {
89                 if (strcmp(output->name, name) == 0) {
90                         free(name);
91                         return output;
92                 }
93         }
94
95         output = zalloc(sizeof *output);
96         if (!output) {
97                 free(name);
98                 return NULL;
99         }
100
101         output->ivi = ivi;
102         output->name = name;
103         output->config = config;
104
105         output->output = weston_compositor_create_output(ivi->compositor, name);
106         if (!output->output) {
107                 free(output->name);
108                 free(output);
109                 return NULL;
110         }
111
112         output->output_destroy.notify = handle_output_destroy;
113         weston_output_add_destroy_listener(output->output,
114                                            &output->output_destroy);
115
116         wl_list_insert(&ivi->outputs, &output->link);
117         return output;
118 }
119
120 static int
121 count_heads(struct weston_output *output)
122 {
123         struct weston_head *iter = NULL;
124         int n = 0;
125
126         while ((iter = weston_output_iterate_heads(output, iter)))
127                 ++n;
128
129         return n;
130 }
131
132 static void
133 handle_head_destroy(struct wl_listener *listener, void *data)
134 {
135         struct weston_head *head = data;
136         struct weston_output *output;
137
138         wl_list_remove(&listener->link);
139         free(listener);
140
141         output = weston_head_get_output(head);
142
143         /* On shutdown path, the output might be already gone. */
144         if (!output)
145                 return;
146
147         /* We're the last head */
148         if (count_heads(output) <= 1)
149                 weston_output_destroy(output);
150 }
151
152 static void
153 add_head_destroyed_listener(struct weston_head *head)
154 {
155         /* We already have a destroy listener */
156         if (weston_head_get_destroy_listener(head, handle_head_destroy))
157                 return;
158
159         struct wl_listener *listener = zalloc(sizeof *listener);
160         if (!listener)
161                 return;
162
163         listener->notify = handle_head_destroy;
164         weston_head_add_destroy_listener(head, listener);
165 }
166
167 static int
168 drm_configure_output(struct ivi_output *output)
169 {
170         struct ivi_compositor *ivi = output->ivi;
171         struct weston_config_section *section = output->config;
172         enum weston_drm_backend_output_mode mode =
173                 WESTON_DRM_BACKEND_OUTPUT_PREFERRED;
174         char *modeline = NULL;
175         char *gbm_format = NULL;
176         char *seat = NULL;
177
178         if (section) {
179                 char *m;
180                 weston_config_section_get_string(section, "mode", &m, "preferred");
181
182                 /* This should have been handled earlier */
183                 assert(strcmp(m, "off") != 0);
184
185                 if (ivi->cmdline.use_current_mode || strcmp(m, "current") == 0) {
186                         mode = WESTON_DRM_BACKEND_OUTPUT_CURRENT;
187                 } else if (strcmp(m, "preferred") != 0) {
188                         modeline = m;
189                         m = NULL;
190                 }
191                 free(m);
192
193                 weston_config_section_get_string(section, "gbm-format",
194                                                  &gbm_format, NULL);
195
196                 weston_config_section_get_string(section, "seat", &seat, "");
197         }
198
199         if (ivi->drm_api->set_mode(output->output, mode, modeline) < 0) {
200                 weston_log("Cannot configure output using weston_drm_output_api.\n");
201                 free(modeline);
202                 return -1;
203         }
204         free(modeline);
205
206         ivi->drm_api->set_gbm_format(output->output, gbm_format);
207         free(gbm_format);
208
209         ivi->drm_api->set_seat(output->output, seat);
210         free(seat);
211
212         return 0;
213 }
214
215 #define WINDOWED_DEFAULT_WIDTH 1024
216 #define WINDOWED_DEFAULT_HEIGHT 768
217
218 static int
219 windowed_configure_output(struct ivi_output *output)
220 {
221         struct ivi_compositor *ivi = output->ivi;
222         struct weston_config_section *section = output->config;
223         int width = WINDOWED_DEFAULT_WIDTH;
224         int height = WINDOWED_DEFAULT_HEIGHT;
225
226         if (section) {
227                 char *mode;
228
229                 weston_config_section_get_string(section, "mode", &mode, NULL);
230                 if (!mode || sscanf(mode, "%dx%d", &width, &height) != 2) {
231                         weston_log("Invalid mode for output %s. Using defaults.\n",
232                                    output->name);
233                         width = WINDOWED_DEFAULT_WIDTH;
234                         height = WINDOWED_DEFAULT_HEIGHT;
235                 }
236                 free(mode);
237         }
238
239         if (ivi->cmdline.width)
240                 width = ivi->cmdline.width;
241         if (ivi->cmdline.height)
242                 height = ivi->cmdline.height;
243         if (ivi->cmdline.scale)
244                 weston_output_set_scale(output->output, ivi->cmdline.scale);
245
246         if (ivi->window_api->output_set_size(output->output, width, height) < 0) {
247                 weston_log("Cannot configure output '%s' using weston_windowed_output_api.\n",
248                            output->name);
249                 return -1;
250         }
251
252         return 0;
253 }
254
255 static int
256 parse_transform(const char *transform, uint32_t *out)
257 {
258         static const struct { const char *name; uint32_t token; } transforms[] = {
259                 { "normal",     WL_OUTPUT_TRANSFORM_NORMAL },
260                 { "90",         WL_OUTPUT_TRANSFORM_90 },
261                 { "180",        WL_OUTPUT_TRANSFORM_180 },
262                 { "270",        WL_OUTPUT_TRANSFORM_270 },
263                 { "flipped",    WL_OUTPUT_TRANSFORM_FLIPPED },
264                 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
265                 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
266                 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
267         };
268
269         for (size_t i = 0; i < ARRAY_LENGTH(transforms); i++)
270                 if (strcmp(transforms[i].name, transform) == 0) {
271                         *out = transforms[i].token;
272                         return 0;
273                 }
274
275         *out = WL_OUTPUT_TRANSFORM_NORMAL;
276         return -1;
277 }
278
279 static int
280 configure_output(struct ivi_output *output)
281 {
282         struct ivi_compositor *ivi = output->ivi;
283         struct weston_config_section *section = output->config;
284         int32_t scale = 1;
285         uint32_t transform = WL_OUTPUT_TRANSFORM_NORMAL;
286
287         /*
288          * This can happen with the wayland backend with 'sprawl'. The config
289          * is hard-coded, so we don't need to do anything.
290          */
291         if (!ivi->drm_api && !ivi->window_api)
292                 return 0;
293
294         if (section) {
295                 char *t;
296
297                 weston_config_section_get_int(section, "scale", &scale, 1);
298                 weston_config_section_get_string(section, "transform", &t, "normal");
299                 if (parse_transform(t, &transform) < 0)
300                         weston_log("Invalid transform \"%s\" for output %s\n",
301                                    t, output->name);
302                 free(t);
303         }
304
305         weston_output_set_scale(output->output, scale);
306         weston_output_set_transform(output->output, transform);
307
308         if (ivi->drm_api)
309                 return drm_configure_output(output);
310         else
311                 return windowed_configure_output(output);
312 }
313
314 /*
315  * Reorgainizes the output's add array into two sections.
316  * add[0..ret-1] are the heads that failed to get attached.
317  * add[ret..add_len] are the heads that were successfully attached.
318  *
319  * The order between elements in each section is stable.
320  */
321 static size_t
322 try_attach_heads(struct ivi_output *output)
323 {
324         size_t fail_len = 0;
325
326         for (size_t i = 0; i < output->add_len; ++i) {
327                 if (weston_output_attach_head(output->output, output->add[i]) < 0) {
328                         struct weston_head *tmp = output->add[i];
329                         memmove(&output->add[fail_len + 1], output->add[fail_len],
330                                 sizeof output->add[0] * (i - fail_len));
331                         output->add[fail_len++] = tmp;
332                 }
333         }
334
335         return fail_len;
336 }
337
338 /*
339  * Like try_attach_heads, this reorganizes the output's add array into a failed
340  * and successful section.
341  * i is the number of heads that already failed the previous step.
342  */
343 static size_t
344 try_enable_output(struct ivi_output *output, size_t i)
345 {
346         for (; i < output->add_len; ++i) {
347                 struct weston_head *head;
348
349                 if (weston_output_enable(output->output) == 0)
350                         break;
351
352                 head = output->add[output->add_len - 1];
353                 memmove(&output->add[i + 1], &output->add[i],
354                         sizeof output->add[0] * (output->add_len - i));
355                 output->add[i] = head;
356
357                 weston_head_detach(head);
358         }
359
360         return i;
361 }
362
363 static int
364 try_attach_enable_heads(struct ivi_output *output)
365 {
366         size_t fail_len;
367         assert(!output->output->enabled);
368
369         fail_len = try_attach_heads(output);
370
371         if (configure_output(output) < 0)
372                 return -1;
373
374         fail_len = try_enable_output(output, fail_len);
375
376         /* All heads failed to be attached */
377         if (fail_len == output->add_len)
378                 return -1;
379
380         /* For each successful head attached */
381         for (size_t i = fail_len; i < output->add_len; ++i)
382                 add_head_destroyed_listener(output->add[i]);
383
384         output->add_len = fail_len;
385         return 0;
386 }
387
388 static int
389 process_output(struct ivi_output *output)
390 {
391         if (output->output->enabled) {
392                 output->add_len = try_attach_heads(output);
393                 return output->add_len == 0 ? 0 : -1;
394         }
395
396         return try_attach_enable_heads(output);
397 }
398
399 static void
400 head_disable(struct ivi_compositor *ivi, struct weston_head *head)
401 {
402         struct weston_output *output;
403         struct ivi_output *ivi_output;
404         struct wl_listener *listener;
405
406         output = weston_head_get_output(head);
407         assert(output);
408
409         listener = weston_output_get_destroy_listener(output,
410                                                       handle_output_destroy);
411         assert(listener);
412
413         ivi_output = wl_container_of(listener, ivi_output, output_destroy);
414         assert(ivi_output->output == output);
415
416         weston_head_detach(head);
417         if (count_heads(ivi_output->output) == 0) {
418                 weston_output_disable(ivi_output->output);
419         }
420 }
421
422 static struct weston_config_section *
423 find_controlling_output_config(struct weston_config *config,
424                                const char *name)
425 {
426         struct weston_config_section *section;
427         char *same_as;
428         int depth = 0;
429
430         same_as = strdup(name);
431         do {
432                 section = weston_config_get_section(config, "output",
433                                                     "name", same_as);
434                 if (!section && depth > 0)
435                         weston_log("Configuration error: output section reffered"
436                                    "to by same-as=%s not found.\n", same_as);
437                 free(same_as);
438
439                 if (!section)
440                         return NULL;
441
442                 if (depth++ > 8) {
443                         weston_log("Configuration error: same-as nested too "
444                                    "deep for output '%s'.\n", name);
445                         return NULL;
446                 }
447
448                 weston_config_section_get_string(section, "same-as",
449                                                  &same_as, NULL);
450         } while (same_as);
451
452         return section;
453 }
454
455 static void
456 head_prepare_enable(struct ivi_compositor *ivi, struct weston_head *head)
457 {
458         const char *name = weston_head_get_name(head);
459         struct weston_config_section *section;
460         struct ivi_output *output;
461         char *output_name = NULL;
462
463         section = find_controlling_output_config(ivi->config, name);
464         if (section) {
465                 char *mode;
466
467                 weston_config_section_get_string(section, "mode", &mode, NULL);
468                 if (mode && strcmp(mode, "off") == 0) {
469                         free(mode);
470                         return;
471                 }
472                 free(mode);
473
474                 weston_config_section_get_string(section, "name",
475                                                  &output_name, NULL);
476         } else {
477                 output_name = strdup(name);
478         }
479
480         if (!output_name)
481                 return;
482
483         output = ivi_ensure_output(ivi, output_name, section);
484         if (!output)
485                 return;
486
487         if (output->add_len >= ARRAY_LENGTH(output->add))
488                 return;
489
490         output->add[output->add_len++] = head;
491 }
492
493 static void
494 heads_changed(struct wl_listener *listener, void *arg)
495 {
496         struct weston_compositor *compositor = arg;
497         struct weston_head *head = NULL;
498         struct ivi_compositor *ivi = to_ivi_compositor(compositor);
499         struct ivi_output *output;
500
501         while ((head = weston_compositor_iterate_heads(ivi->compositor, head))) {
502                 bool connected = weston_head_is_connected(head);
503                 bool enabled = weston_head_is_enabled(head);
504                 bool changed = weston_head_is_device_changed(head);
505                 bool non_desktop = weston_head_is_non_desktop(head);
506
507                 if (connected && !enabled && !non_desktop)
508                         head_prepare_enable(ivi, head);
509                 else if (!connected && enabled)
510                         head_disable(ivi, head);
511                 else if (enabled && changed)
512                         weston_log("Detected a monitor change on head '%s', "
513                                    "not bothering to do anything about it.\n",
514                                    weston_head_get_name(head));
515
516                 weston_head_reset_device_changed(head);
517         }
518
519         wl_list_for_each(output, &ivi->outputs, link) {
520                 if (output->add_len == 0)
521                         continue;
522
523                 if (process_output(output) < 0) {
524                         output->add_len = 0;
525                         ivi->init_failed = true;
526                 }
527         }
528 }
529
530 static int
531 load_drm_backend(struct ivi_compositor *ivi, int *argc, char *argv[])
532 {
533         struct weston_drm_backend_config config = {
534                 .base = {
535                         .struct_version = WESTON_DRM_BACKEND_CONFIG_VERSION,
536                         .struct_size = sizeof config,
537                 },
538         };
539         struct weston_config_section *section;
540         int use_current_mode = 0;
541         int use_pixman = 0;
542         int use_shadow;
543         int ret;
544
545         const struct weston_option options[] = {
546                 { WESTON_OPTION_STRING, "seat", 0, &config.seat_id },
547                 { WESTON_OPTION_INTEGER, "tty", 0, &config.tty },
548                 { WESTON_OPTION_STRING, "drm-device", 0, &config.specific_device },
549                 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &use_current_mode },
550                 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
551         };
552
553         parse_options(options, ARRAY_LENGTH(options), argc, argv);
554         config.use_pixman = use_pixman;
555         ivi->cmdline.use_current_mode = use_current_mode;
556
557         section = weston_config_get_section(ivi->config, "core", NULL, NULL);
558         weston_config_section_get_string(section, "gbm-format",
559                                          &config.gbm_format, NULL);
560         weston_config_section_get_uint(section, "pageflip-timeout",
561                                        &config.pageflip_timeout, 0);
562         weston_config_section_get_bool(section, "pixman-shadow", &use_shadow, 1);
563         config.use_pixman_shadow = use_shadow;
564
565         ret = weston_compositor_load_backend(ivi->compositor, WESTON_BACKEND_DRM,
566                                              &config.base);
567         if (ret < 0)
568                 return ret;
569
570         ivi->drm_api = weston_drm_output_get_api(ivi->compositor);
571         if (!ivi->drm_api) {
572                 weston_log("Cannot use drm output api.\n");
573                 ret = -1;
574                 goto error;
575         }
576
577 error:
578         free(config.gbm_format);
579         free(config.seat_id);
580         return ret;
581 }
582
583 static void
584 windowed_parse_common_options(struct ivi_compositor *ivi, int *argc, char *argv[],
585                               bool *use_pixman, bool *fullscreen, int *output_count)
586 {
587         struct weston_config_section *section;
588         int pixman;
589         int fs = 0;
590
591         const struct weston_option options[] = {
592                 { WESTON_OPTION_INTEGER, "width", 0, &ivi->cmdline.width },
593                 { WESTON_OPTION_INTEGER, "height", 0, &ivi->cmdline.height },
594                 { WESTON_OPTION_INTEGER, "scale", 0, &ivi->cmdline.scale },
595                 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &pixman },
596                 { WESTON_OPTION_BOOLEAN, "fullscreen", 0, &fs },
597                 { WESTON_OPTION_INTEGER, "output-count", 0, output_count },
598         };
599
600         section = weston_config_get_section(ivi->config, "core", NULL, NULL);
601         weston_config_section_get_bool(section, "use-pixman", &pixman, 0);
602
603         *output_count = 1;
604         parse_options(options, ARRAY_LENGTH(options), argc, argv);
605         *use_pixman = pixman;
606         *fullscreen = fs;
607 }
608
609 static int
610 windowed_create_outputs(struct ivi_compositor *ivi, int output_count,
611                         const char *match_prefix, const char *name_prefix)
612 {
613         struct weston_config_section *section = NULL;
614         const char *section_name;
615         char *default_output = NULL;
616         int i = 0;
617         size_t match_len = strlen(match_prefix);
618
619         while (weston_config_next_section(ivi->config, &section, &section_name)) {
620                 char *output_name;
621
622                 if (i >= output_count)
623                         break;
624
625                 if (strcmp(section_name, "output") != 0)
626                         continue;
627
628                 weston_config_section_get_string(section, "name", &output_name, NULL);
629                 if (output_name == NULL)
630                         continue;
631                 if (strncmp(output_name, match_prefix, match_len) != 0) {
632                         free(output_name);
633                         continue;
634                 }
635
636                 if (ivi->window_api->create_head(ivi->compositor, output_name) < 0) {
637                         free(output_name);
638                         return -1;
639                 }
640
641                 free(output_name);
642                 ++i;
643         }
644
645         for (; i < output_count; ++i) {
646                 if (asprintf(&default_output, "%s%d", name_prefix, i) < 0)
647                         return -1;
648
649                 if (ivi->window_api->create_head(ivi->compositor, default_output) < 0) {
650                         free(default_output);
651                         return -1;
652                 }
653
654                 free(default_output);
655         }
656
657         return 0;
658 }
659
660 static int
661 load_wayland_backend(struct ivi_compositor *ivi, int *argc, char *argv[])
662 {
663         struct weston_wayland_backend_config config = {
664                 .base = {
665                         .struct_version = WESTON_WAYLAND_BACKEND_CONFIG_VERSION,
666                         .struct_size = sizeof config,
667                 },
668         };
669         struct weston_config_section *section;
670         int sprawl = 0;
671         int output_count;
672         int ret;
673
674         const struct weston_option options[] = {
675                 { WESTON_OPTION_STRING, "display", 0, &config.display_name },
676                 { WESTON_OPTION_STRING, "sprawl", 0, &sprawl },
677         };
678
679         windowed_parse_common_options(ivi, argc, argv, &config.use_pixman,
680                                       &config.fullscreen, &output_count);
681
682         parse_options(options, ARRAY_LENGTH(options), argc, argv);
683         config.sprawl = sprawl;
684
685         section = weston_config_get_section(ivi->config, "shell", NULL, NULL);
686         weston_config_section_get_string(section, "cursor-theme",
687                                          &config.cursor_theme, NULL);
688         weston_config_section_get_int(section, "cursor-size",
689                                       &config.cursor_size, 32);
690
691         ret = weston_compositor_load_backend(ivi->compositor, WESTON_BACKEND_WAYLAND,
692                                              &config.base);
693
694         free(config.cursor_theme);
695         free(config.display_name);
696
697         if (ret < 0)
698                 return ret;
699
700         ivi->window_api = weston_windowed_output_get_api(ivi->compositor);
701
702         /*
703          * We will just assume if load_backend() finished cleanly and
704          * windowed_output_api is not present that wayland backend is started
705          * with --sprawl or runs on fullscreen-shell. In this case, all values
706          * are hardcoded, so nothing can be configured; simply create and
707          * enable an output.
708          */
709         if (ivi->window_api == NULL)
710                 return 0;
711
712         return windowed_create_outputs(ivi, output_count, "WL", "wayland");
713 }
714
715 #ifdef HAVE_BACKEND_X11
716 static int
717 load_x11_backend(struct ivi_compositor *ivi, int *argc, char *argv[])
718 {
719         struct weston_x11_backend_config config = {
720                 .base = {
721                         .struct_version = WESTON_X11_BACKEND_CONFIG_VERSION,
722                         .struct_size = sizeof config,
723                 },
724         };
725         int no_input = 0;
726         int output_count;
727         int ret;
728
729         const struct weston_option options[] = {
730                { WESTON_OPTION_BOOLEAN, "no-input", 0, &no_input },
731         };
732
733         windowed_parse_common_options(ivi, argc, argv, &config.use_pixman,
734                                       &config.fullscreen, &output_count);
735
736         parse_options(options, ARRAY_LENGTH(options), argc, argv);
737         config.no_input = no_input;
738
739         ret = weston_compositor_load_backend(ivi->compositor, WESTON_BACKEND_X11,
740                                              &config.base);
741
742         if (ret < 0)
743                 return ret;
744
745         ivi->window_api = weston_windowed_output_get_api(ivi->compositor);
746         if (!ivi->window_api) {
747                 weston_log("Cannot use weston_windowed_output_api.\n");
748                 return -1;
749         }
750
751         return windowed_create_outputs(ivi, output_count, "X", "screen");
752 }
753 #else
754 static int
755 load_x11_backend(struct ivi_compositor *ivi, int *argc, char *argv[])
756 {
757         return -1;
758 }
759 #endif
760
761 static int
762 load_backend(struct ivi_compositor *ivi, const char *backend,
763              int *argc, char *argv[])
764 {
765         if (strcmp(backend, "drm-backend.so") == 0) {
766                 return load_drm_backend(ivi, argc, argv);
767         } else if (strcmp(backend, "wayland-backend.so") == 0) {
768                 return load_wayland_backend(ivi, argc, argv);
769         } else if (strcmp(backend, "x11-backend.so") == 0) {
770                 return load_x11_backend(ivi, argc, argv);
771         }
772
773         weston_log("fatal: unknown backend '%s'.\n", backend);
774         return -1;
775 }
776
777 static char *
778 choose_default_backend(void)
779 {
780         char *backend = NULL;
781
782         if (getenv("WAYLAND_DISPLAY") || getenv("WAYLAND_SOCKET"))
783                 backend = strdup("wayland-backend.so");
784         else if (getenv("DISPLAY"))
785                 backend = strdup("x11-backend.so");
786         else
787                 backend = strdup("drm-backend.so");
788
789         return backend;
790 }
791
792 static int
793 compositor_init_config(struct weston_compositor *compositor,
794                        struct weston_config *config)
795 {
796         struct xkb_rule_names xkb_names;
797         struct weston_config_section *section;
798         int repaint_msec;
799         int vt_switching;
800         int require_input;
801
802         /* agl-compositor.ini [keyboard] */
803         section = weston_config_get_section(config, "keyboard", NULL, NULL);
804         weston_config_section_get_string(section, "keymap_rules",
805                                          (char **) &xkb_names.rules, NULL);
806         weston_config_section_get_string(section, "keymap_model",
807                                          (char **) &xkb_names.model, NULL);
808         weston_config_section_get_string(section, "keymap_layout",
809                                          (char **) &xkb_names.layout, NULL);
810         weston_config_section_get_string(section, "keymap_variant",
811                                          (char **) &xkb_names.variant, NULL);
812         weston_config_section_get_string(section, "keymap_options",
813                                          (char **) &xkb_names.options, NULL);
814
815         if (weston_compositor_set_xkb_rule_names(compositor, &xkb_names) < 0)
816                 return -1;
817
818         weston_config_section_get_int(section, "repeat-rate",
819                                       &compositor->kb_repeat_rate, 40);
820         weston_config_section_get_int(section, "repeat-delay",
821                                       &compositor->kb_repeat_delay, 400);
822
823         weston_config_section_get_bool(section, "vt-switching",
824                                        &vt_switching, true);
825         compositor->vt_switching = vt_switching;
826
827         /* agl-compositor.ini [core] */
828         section = weston_config_get_section(config, "core", NULL, NULL);
829
830         weston_config_section_get_bool(section, "require-input", &require_input, true);
831         compositor->require_input = require_input;
832
833         weston_config_section_get_int(section, "repaint-window", &repaint_msec,
834                                       compositor->repaint_msec);
835         if (repaint_msec < -10 || repaint_msec > 1000) {
836                 weston_log("Invalid repaint_window value in config: %d\n",
837                            repaint_msec);
838         } else {
839                 compositor->repaint_msec = repaint_msec;
840         }
841         weston_log("Output repaint window is %d ms maximum.\n",
842                    compositor->repaint_msec);
843
844         return 0;
845 }
846
847 struct ivi_surface *
848 to_ivi_surface(struct weston_surface *surface)
849 {
850         struct weston_desktop_surface *dsurface;
851
852         dsurface = weston_surface_get_desktop_surface(surface);
853         if (!dsurface)
854                 return NULL;
855
856         return weston_desktop_surface_get_user_data(dsurface);
857 }
858
859 static void
860 activate_binding(struct weston_seat *seat,
861                  struct weston_view *focus_view)
862 {
863         struct weston_surface *focus = focus_view->surface;
864         struct weston_surface *main_surface =
865                 weston_surface_get_main_surface(focus);
866         struct ivi_surface *surface;
867
868         surface = to_ivi_surface(main_surface);
869         if (!surface)
870                 return;
871
872         weston_seat_set_keyboard_focus(seat, focus);
873 }
874
875 static void
876 click_to_activate_binding(struct weston_pointer *pointer,
877                           const struct timespec *time,
878                           uint32_t button, void *data)
879 {
880         if (pointer->grab != &pointer->default_grab)
881                 return;
882         if (pointer->focus == NULL)
883                 return;
884
885         activate_binding(pointer->seat, pointer->focus);
886 }
887
888 static void
889 touch_to_activate_binding(struct weston_touch *touch,
890                           const struct timespec *time,
891                           void *data)
892 {
893         if (touch->grab != &touch->default_grab)
894                 return;
895         if (touch->focus == NULL)
896                 return;
897
898         activate_binding(touch->seat, touch->focus);
899 }
900
901 static void
902 add_bindings(struct weston_compositor *compositor)
903 {
904         weston_compositor_add_button_binding(compositor, BTN_LEFT, 0,
905                                              click_to_activate_binding,
906                                              NULL);
907         weston_compositor_add_button_binding(compositor, BTN_RIGHT, 0,
908                                              click_to_activate_binding,
909                                              NULL);
910         weston_compositor_add_touch_binding(compositor, 0,
911                                             touch_to_activate_binding,
912                                             NULL);
913 }
914
915 static int
916 create_listening_socket(struct wl_display *display, const char *socket_name)
917 {
918         if (socket_name) {
919                 if (wl_display_add_socket(display, socket_name)) {
920                         weston_log("fatal: failed to add socket: %s\n",
921                                    strerror(errno));
922                         return -1;
923                 }
924         } else {
925                 socket_name = wl_display_add_socket_auto(display);
926                 if (!socket_name) {
927                         weston_log("fatal: failed to add socket: %s\n",
928                                    strerror(errno));
929                         return -1;
930                 }
931         }
932
933         setenv("WAYLAND_DISPLAY", socket_name, 1);
934
935         return 0;
936 }
937
938 static bool
939 global_filter(const struct wl_client *client, const struct wl_global *global,
940               void *data)
941 {
942         return true;
943 }
944
945 static int
946 load_config(struct weston_config **config, bool no_config,
947             const char *config_file)
948 {
949         const char *file = "agl-compositor.ini";
950         const char *full_path;
951
952         if (config_file)
953                 file = config_file;
954
955         if (!no_config)
956                 *config = weston_config_parse(file);
957
958         if (*config) {
959                 full_path = weston_config_get_full_path(*config);
960
961                 weston_log("Using config file '%s'.\n", full_path);
962                 setenv(WESTON_CONFIG_FILE_ENV_VAR, full_path, 1);
963
964                 return 0;
965         }
966
967         if (config_file && !no_config) {
968                 weston_log("fatal: error opening or reading config file '%s'.\n",
969                         config_file);
970
971                 return -1;
972         }
973
974         weston_log("Starting with no config file.\n");
975         setenv(WESTON_CONFIG_FILE_ENV_VAR, "", 1);
976
977         return 0;
978 }
979
980 static FILE *logfile;
981
982 static int
983 log_timestamp(void)
984 {
985         static int cached_tm_mday = -1;
986         struct timespec ts;
987         struct tm brokendown_time;
988         char buf[128];
989
990         clock_gettime(CLOCK_REALTIME, &ts);
991         if (!localtime_r(&ts.tv_sec, &brokendown_time))
992                 return fprintf(logfile, "[(NULL)localtime] ");
993
994         if (brokendown_time.tm_mday != cached_tm_mday) {
995                 strftime(buf, sizeof buf, "%Y-%m-%d %Z", &brokendown_time);
996                 fprintf(logfile, "Date: %s\n", buf);
997
998                 cached_tm_mday = brokendown_time.tm_mday;
999         }
1000
1001         strftime(buf, sizeof buf, "%H:%M:%S", &brokendown_time);
1002
1003         return fprintf(logfile, "[%s.%03ld] ", buf, ts.tv_nsec / 1000000);
1004 }
1005
1006 static void
1007 custom_handler(const char *fmt, va_list arg)
1008 {
1009         log_timestamp();
1010         fprintf(logfile, "libwayland: ");
1011         vfprintf(logfile, fmt, arg);
1012 }
1013
1014 static void
1015 log_file_open(const char *filename)
1016 {
1017         wl_log_set_handler_server(custom_handler);
1018
1019         if (filename)
1020                 logfile = fopen(filename, "a");
1021
1022         if (!logfile) {
1023                 logfile = stderr;
1024         } else {
1025                 os_fd_set_cloexec(fileno(logfile));
1026                 setvbuf(logfile, NULL, _IOLBF, 256);
1027         }
1028 }
1029
1030 static void
1031 log_file_close(void)
1032 {
1033         if (logfile && logfile != stderr)
1034                 fclose(logfile);
1035         logfile = stderr;
1036 }
1037
1038 static int
1039 vlog(const char *fmt, va_list ap)
1040 {
1041         int l;
1042
1043         l = log_timestamp();
1044         l += vfprintf(logfile, fmt, ap);
1045
1046         return l;
1047 }
1048
1049 static int
1050 vlog_continue(const char *fmt, va_list ap)
1051 {
1052         return vfprintf(logfile, fmt, ap);
1053 }
1054
1055 static int
1056 on_term_signal(int signo, void *data)
1057 {
1058         struct wl_display *display = data;
1059
1060         weston_log("caught signal %d\n", signo);
1061         wl_display_terminate(display);
1062
1063         return 1;
1064 }
1065
1066 static void
1067 handle_exit(struct weston_compositor *compositor)
1068 {
1069         wl_display_terminate(compositor->wl_display);
1070 }
1071
1072 static void
1073 usage(int error_code)
1074 {
1075         FILE *out = error_code == EXIT_SUCCESS ? stdout : stderr;
1076         fprintf(out,
1077                 "Usage: agl-compositor [OPTIONS]\n"
1078                 "\n"
1079                 "This is " PACKAGE_STRING ", the reference compositor for\n"
1080                 "Automotive Grade Linux. Weston-ivi supports multiple backends, and depending\n"
1081                 "on which backend is in use different options will be accepted.\n"
1082                 "\n"
1083                 "Core options:\n"
1084                 "\n"
1085                 "  --version\t\tPrint agl-compositor version\n"
1086                 "  -B, --backend=MODULE\tBackend module, one of\n"
1087                         "\t\t\t\tdrm-backend.so\n"
1088                         "\t\t\t\twayland-backend.so\n"
1089                         "\t\t\t\tx11-backend.so\n"
1090                 "  -S, --socket=NAME\tName of socket to listen on\n"
1091                 "  --log=FILE\t\tLog to the given file\n"
1092                 "  -c, --config=FILE\tConfig file to load, defaults to agl-compositor.ini\n"
1093                 "  --no-config\t\tDo not read agl-compositor.ini\n"
1094                 "  --debug\t\tEnable debug extension\n"
1095                 "  -h, --help\t\tThis help message\n"
1096                 "\n");
1097         exit(error_code);
1098 }
1099
1100 static void
1101 ivi_compositor_get_quirks(struct ivi_compositor *ivi)
1102 {
1103         struct weston_config_section *section;
1104
1105         if (!ivi->config)
1106                 return;
1107
1108         section = weston_config_get_section(ivi->config, "shell", NULL, NULL);
1109         weston_config_section_get_bool(section, "activate-by-default",
1110                         &ivi->quirks.activate_apps_by_default, 0);
1111
1112 }
1113
1114 int main(int argc, char *argv[])
1115 {
1116         struct ivi_compositor ivi = { 0 };
1117         struct wl_display *display = NULL;
1118         struct wl_event_loop *loop;
1119         struct wl_event_source *signals[3] = { 0 };
1120         struct weston_config_section *section;
1121         /* Command line options */
1122         char *backend = NULL;
1123         char *socket_name = NULL;
1124         char *log = NULL;
1125         int help = 0;
1126         int version = 0;
1127         int no_config = 0;
1128         char *config_file = NULL;
1129         int debug_protocol = 0;
1130         struct weston_log_context *log_ctx = NULL;
1131         struct weston_log_scope *log_scope;
1132         struct weston_log_subscriber *logger;
1133
1134         const struct weston_option core_options[] = {
1135                 { WESTON_OPTION_STRING, "backend", 'B', &backend },
1136                 { WESTON_OPTION_STRING, "socket", 'S', &socket_name },
1137                 { WESTON_OPTION_STRING, "log", 0, &log },
1138                 { WESTON_OPTION_BOOLEAN, "help", 'h', &help },
1139                 { WESTON_OPTION_BOOLEAN, "version", 0, &version },
1140                 { WESTON_OPTION_BOOLEAN, "no-config", 0, &no_config },
1141                 { WESTON_OPTION_STRING, "config", 'c', &config_file },
1142                 { WESTON_OPTION_BOOLEAN, "debug", 0, &debug_protocol },
1143         };
1144
1145         wl_list_init(&ivi.outputs);
1146         wl_list_init(&ivi.surfaces);
1147         wl_list_init(&ivi.pending_surfaces);
1148
1149         /* Prevent any clients we spawn getting our stdin */
1150         os_fd_set_cloexec(STDIN_FILENO);
1151
1152         parse_options(core_options, ARRAY_LENGTH(core_options), &argc, argv);
1153
1154         if (help)
1155                 usage(EXIT_SUCCESS);
1156
1157         if (version) {
1158                 printf(PACKAGE_STRING "\n");
1159                 return EXIT_SUCCESS;
1160         }
1161
1162         log_ctx = weston_log_ctx_compositor_create();
1163         if (!log_ctx) {
1164                 fprintf(stderr, "Failed to initialize weston debug framework.\n");
1165                 return EXIT_FAILURE;
1166         }
1167
1168         log_scope = weston_compositor_add_log_scope(log_ctx, "log",
1169                                                     "agl-compositor log\n",
1170                                                     NULL, NULL);
1171
1172         log_file_open(log);
1173         weston_log_set_handler(vlog, vlog_continue);
1174
1175         logger = weston_log_subscriber_create_log(logfile);
1176
1177         if (load_config(&ivi.config, no_config, config_file) < 0)
1178                 goto error_signals;
1179         section = weston_config_get_section(ivi.config, "core", NULL, NULL);
1180         if (!backend) {
1181                 weston_config_section_get_string(section, "backend", &backend,
1182                                                  NULL);
1183                 if (!backend)
1184                         backend = choose_default_backend();
1185         }
1186
1187         ivi_compositor_get_quirks(&ivi);
1188
1189         display = wl_display_create();
1190         loop = wl_display_get_event_loop(display);
1191
1192         wl_display_set_global_filter(display,
1193                                      global_filter, &ivi);
1194
1195         /* Register signal handlers so we shut down cleanly */
1196
1197         signals[0] = wl_event_loop_add_signal(loop, SIGTERM, on_term_signal,
1198                                               display);
1199         signals[1] = wl_event_loop_add_signal(loop, SIGINT, on_term_signal,
1200                                               display);
1201         signals[2] = wl_event_loop_add_signal(loop, SIGQUIT, on_term_signal,
1202                                               display);
1203
1204         for (size_t i = 0; i < ARRAY_LENGTH(signals); ++i)
1205                 if (!signals[i])
1206                         goto error_signals;
1207
1208         ivi.compositor = weston_compositor_create(display, log_ctx, &ivi);
1209         if (!ivi.compositor) {
1210                 weston_log("fatal: failed to create compositor.\n");
1211                 goto error_signals;
1212         }
1213
1214         if (compositor_init_config(ivi.compositor, ivi.config) < 0)
1215                 goto error_compositor;
1216
1217         if (load_backend(&ivi, backend, &argc, argv) < 0) {
1218                 weston_log("fatal: failed to create compositor backend.\n");
1219                 goto error_compositor;
1220         }
1221
1222         ivi.heads_changed.notify = heads_changed;
1223         weston_compositor_add_heads_changed_listener(ivi.compositor,
1224                                                      &ivi.heads_changed);
1225
1226         if (ivi_desktop_init(&ivi) < 0)
1227                 goto error_compositor;
1228
1229         if (ivi_shell_init(&ivi) < 0)
1230                 goto error_compositor;
1231
1232         add_bindings(ivi.compositor);
1233
1234         weston_compositor_flush_heads_changed(ivi.compositor);
1235
1236         ivi_shell_init_black_fs(&ivi);
1237
1238         if (create_listening_socket(display, socket_name) < 0)
1239                 goto error_compositor;
1240
1241         ivi.compositor->exit = handle_exit;
1242
1243         weston_compositor_wake(ivi.compositor);
1244
1245         ivi_shell_create_global(&ivi);
1246         ivi_launch_shell_client(&ivi);
1247         ivi_agl_systemd_notify(&ivi);
1248
1249         wl_display_run(display);
1250
1251         wl_display_destroy_clients(display);
1252
1253 error_compositor:
1254         weston_compositor_tear_down(ivi.compositor);
1255
1256         weston_compositor_log_scope_destroy(log_scope);
1257         log_scope = NULL;
1258
1259         weston_log_ctx_compositor_destroy(ivi.compositor);
1260         weston_compositor_destroy(ivi.compositor);
1261
1262         weston_log_subscriber_destroy_log(logger);
1263
1264 error_signals:
1265         for (size_t i = 0; i < ARRAY_LENGTH(signals); ++i)
1266                 if (signals[i])
1267                         wl_event_source_remove(signals[i]);
1268
1269         wl_display_destroy(display);
1270
1271         log_file_close();
1272         if (ivi.config)
1273                 weston_config_destroy(ivi.config);
1274 }