cage/cage.c

269 lines
6.9 KiB
C
Raw Normal View History

2018-11-22 19:59:06 +01:00
/*
* Cage: A Wayland kiosk.
*
2019-01-02 20:58:39 +01:00
* Copyright (C) 2018-2019 Jente Hidskes
2018-11-22 19:59:06 +01:00
*
* See the LICENSE file accompanying this file.
*/
#define _POSIX_C_SOURCE 200112L
#include "config.h"
2018-11-22 19:59:06 +01:00
#include <signal.h>
#include <stdio.h>
2018-11-22 19:59:06 +01:00
#include <stdlib.h>
2018-12-16 21:51:48 +01:00
#include <sys/wait.h>
2018-11-22 19:59:06 +01:00
#include <unistd.h>
#include <wayland-server.h>
#include <wlr/backend.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_compositor.h>
2019-01-04 20:23:50 +01:00
#include <wlr/types/wlr_data_device.h>
#include <wlr/types/wlr_idle.h>
#include <wlr/types/wlr_idle_inhibit_v1.h>
2019-01-04 20:23:50 +01:00
#include <wlr/types/wlr_output_layout.h>
#if CAGE_HAS_XWAYLAND
#include <wlr/types/wlr_xcursor_manager.h>
#endif
2018-11-22 19:59:06 +01:00
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/log.h>
#if CAGE_HAS_XWAYLAND
#include <wlr/xwayland.h>
#endif
2018-11-22 19:59:06 +01:00
#include "idle_inhibit_v1.h"
#include "output.h"
#include "seat.h"
#include "server.h"
#include "xdg_shell.h"
#if CAGE_HAS_XWAYLAND
#include "xwayland.h"
#endif
2018-11-22 19:59:06 +01:00
2018-12-16 21:51:48 +01:00
static bool
spawn_primary_client(char *argv[], pid_t *pid_out)
{
pid_t pid = fork();
if (pid == 0) {
execvp(argv[0], argv);
_exit(1);
} else if (pid == -1) {
wlr_log_errno(WLR_ERROR, "Unable to fork");
return false;
}
*pid_out = pid;
wlr_log(WLR_DEBUG, "Child process created with pid %d", pid);
return true;
}
static int
handle_signal(int signal, void *data)
2018-11-22 19:59:06 +01:00
{
struct wl_display *display = data;
switch (signal) {
case SIGINT:
/* Fallthrough */
case SIGTERM:
wl_display_terminate(display);
return 0;
default:
return 1;
}
2018-11-22 19:59:06 +01:00
}
int
main(int argc, char *argv[])
{
struct cg_server server = {0};
struct wl_event_loop *event_loop = NULL;
struct wlr_renderer *renderer = NULL;
struct wlr_compositor *compositor = NULL;
struct wlr_data_device_manager *data_device_mgr = NULL;
struct wlr_xdg_shell *xdg_shell = NULL;
#if CAGE_HAS_XWAYLAND
struct wlr_xwayland *xwayland = NULL;
struct wlr_xcursor_manager *xcursor_manager = NULL;
#endif
2018-12-14 17:06:36 +01:00
int ret = 0;
if (argc < 2) {
2018-11-22 19:59:06 +01:00
printf("Usage: %s APPLICATION\n", argv[0]);
return 1;
}
#ifdef DEBUG
wlr_log_init(WLR_DEBUG, NULL);
#else
wlr_log_init(WLR_ERROR, NULL);
#endif
server.wl_display = wl_display_create();
2018-12-14 17:06:36 +01:00
if (!server.wl_display) {
wlr_log(WLR_ERROR, "Cannot allocate a Wayland display");
2018-12-14 17:06:36 +01:00
return 1;
}
event_loop = wl_display_get_event_loop(server.wl_display);
wl_event_loop_add_signal(event_loop, SIGINT, handle_signal, &server.wl_display);
wl_event_loop_add_signal(event_loop, SIGTERM, handle_signal, &server.wl_display);
2018-11-22 19:59:06 +01:00
server.backend = wlr_backend_autocreate(server.wl_display, NULL);
2018-12-14 17:06:36 +01:00
if (!server.backend) {
wlr_log(WLR_ERROR, "Unable to create the wlroots backend");
ret = 1;
goto end;
}
renderer = wlr_backend_get_renderer(server.backend);
wlr_renderer_init_wl_display(renderer, server.wl_display);
2018-12-14 17:06:36 +01:00
2018-11-22 19:59:06 +01:00
server.output_layout = wlr_output_layout_create();
2018-12-14 17:06:36 +01:00
if (!server.output_layout) {
wlr_log(WLR_ERROR, "Unable to create output layout");
ret = 1;
goto end;
}
2018-11-22 19:59:06 +01:00
compositor = wlr_compositor_create(server.wl_display, renderer);
2018-12-14 17:06:36 +01:00
if (!compositor) {
wlr_log(WLR_ERROR, "Unable to create the wlroots compositor");
ret = 1;
goto end;
}
data_device_mgr = wlr_data_device_manager_create(server.wl_display);
2018-12-14 17:06:36 +01:00
if (!data_device_mgr) {
wlr_log(WLR_ERROR, "Unable to create the data device manager");
ret = 1;
goto end;
}
2018-11-22 19:59:06 +01:00
/* Configure a listener to be notified when new outputs are
* available on the backend. We use this only to detect the
* first output and ignore subsequent outputs. */
server.new_output.notify = handle_new_output;
2018-11-22 19:59:06 +01:00
wl_signal_add(&server.backend->events.new_output, &server.new_output);
server.seat = cg_seat_create(&server);
if (!server.seat) {
wlr_log(WLR_ERROR, "Unable to create the seat");
2018-12-14 17:06:36 +01:00
ret = 1;
goto end;
}
2018-11-22 19:59:06 +01:00
server.idle = wlr_idle_create(server.wl_display);
if (!server.idle) {
wlr_log(WLR_ERROR, "Unable to create the idle tracker");
ret = 1;
goto end;
}
server.idle_inhibit_v1 = wlr_idle_inhibit_v1_create(server.wl_display);
if (!server.idle_inhibit_v1) {
wlr_log(WLR_ERROR, "Cannot create the idle inhibitor");
ret = 1;
goto end;
}
server.new_idle_inhibitor_v1.notify = handle_idle_inhibitor_v1_new;
wl_signal_add(&server.idle_inhibit_v1->events.new_inhibitor, &server.new_idle_inhibitor_v1);
wl_list_init(&server.inhibitors);
xdg_shell = wlr_xdg_shell_create(server.wl_display);
if (!xdg_shell) {
wlr_log(WLR_ERROR, "Unable to create the XDG shell interface");
2018-12-14 17:06:36 +01:00
ret = 1;
goto end;
}
wl_list_init(&server.views);
server.new_xdg_shell_surface.notify = handle_xdg_shell_surface_new;
wl_signal_add(&xdg_shell->events.new_surface, &server.new_xdg_shell_surface);
2018-11-22 19:59:06 +01:00
#if CAGE_HAS_XWAYLAND
xwayland = wlr_xwayland_create(server.wl_display, compositor, true);
2019-01-17 22:25:20 +01:00
if (!xwayland) {
wlr_log(WLR_ERROR, "Cannot create XWayland server");
ret = 1;
goto end;
}
server.new_xwayland_surface.notify = handle_xwayland_surface_new;
wl_signal_add(&xwayland->events.new_surface, &server.new_xwayland_surface);
xcursor_manager = wlr_xcursor_manager_create(DEFAULT_XCURSOR, XCURSOR_SIZE);
if (!xcursor_manager) {
wlr_log(WLR_ERROR, "Cannot create XWayland XCursor manager");
ret = 1;
goto end;
}
if (wlr_xcursor_manager_load(xcursor_manager, 1)) {
wlr_log(WLR_ERROR, "Cannot load XWayland XCursor theme");
}
struct wlr_xcursor *xcursor =
wlr_xcursor_manager_get_xcursor(xcursor_manager, DEFAULT_XCURSOR, 1);
if (xcursor) {
struct wlr_xcursor_image *image = xcursor->images[0];
wlr_xwayland_set_cursor(xwayland, image->buffer,
image->width * 4, image->width, image->height,
image->hotspot_x, image->hotspot_y);
}
#endif
2018-11-22 19:59:06 +01:00
const char *socket = wl_display_add_socket_auto(server.wl_display);
if (!socket) {
wlr_log_errno(WLR_ERROR, "Unable to open Wayland socket");
2018-12-14 17:06:36 +01:00
ret = 1;
goto end;
2018-11-22 19:59:06 +01:00
}
if (!wlr_backend_start(server.backend)) {
wlr_log(WLR_ERROR, "Unable to start the wlroots backend");
2018-12-14 17:06:36 +01:00
ret = 1;
goto end;
2018-11-22 19:59:06 +01:00
}
2018-12-14 17:06:36 +01:00
int rc = setenv("WAYLAND_DISPLAY", socket, true);
if (rc < 0) {
wlr_log_errno(WLR_ERROR, "Unable to set WAYLAND_DISPLAY.",
"Clients may not be able to connect");
} else {
wlr_log(WLR_DEBUG, "Cage is running on Wayland display %s", socket);
2018-12-14 17:06:36 +01:00
}
2018-11-22 19:59:06 +01:00
#if CAGE_HAS_XWAYLAND
2019-01-17 22:25:20 +01:00
wlr_xwayland_set_seat(xwayland, server.seat->seat);
#endif
2018-12-16 21:51:48 +01:00
pid_t pid;
if (!spawn_primary_client(argv + 1, &pid)) {
ret = 1;
goto end;
2018-11-22 19:59:06 +01:00
}
wl_display_run(server.wl_display);
wl_display_destroy_clients(server.wl_display);
2018-12-14 17:06:36 +01:00
2018-12-16 21:51:48 +01:00
waitpid(pid, NULL, 0);
2018-12-14 17:06:36 +01:00
end:
cg_seat_destroy(server.seat);
#if CAGE_HAS_XWAYLAND
wlr_xwayland_destroy(xwayland);
wlr_xcursor_manager_destroy(xcursor_manager);
#endif
2018-12-14 17:06:36 +01:00
wlr_xdg_shell_destroy(xdg_shell);
wlr_idle_inhibit_v1_destroy(server.idle_inhibit_v1);
if (server.idle) {
wlr_idle_destroy(server.idle);
}
2018-12-14 17:06:36 +01:00
wlr_data_device_manager_destroy(data_device_mgr);
wlr_compositor_destroy(compositor);
wlr_output_layout_destroy(server.output_layout);
2018-11-22 19:59:06 +01:00
wlr_backend_destroy(server.backend);
2018-12-14 17:06:36 +01:00
/* This function is not null-safe, but we only ever get here
with a proper wl_display. */
2018-11-22 19:59:06 +01:00
wl_display_destroy(server.wl_display);
2018-12-14 17:06:36 +01:00
return ret;
2018-11-22 19:59:06 +01:00
}