chiark / gitweb /
Remove src/libsystemd-terminal
authorAndy Wingo <wingo@pobox.com>
Sun, 19 Apr 2015 11:28:46 +0000 (13:28 +0200)
committerAndy Wingo <wingo@pobox.com>
Sun, 19 Apr 2015 11:32:24 +0000 (13:32 +0200)
30 files changed:
src/libsystemd-terminal/.gitignore [deleted file]
src/libsystemd-terminal/evcat.c [deleted file]
src/libsystemd-terminal/grdev-drm.c [deleted file]
src/libsystemd-terminal/grdev-internal.h [deleted file]
src/libsystemd-terminal/grdev.c [deleted file]
src/libsystemd-terminal/grdev.h [deleted file]
src/libsystemd-terminal/idev-evdev.c [deleted file]
src/libsystemd-terminal/idev-internal.h [deleted file]
src/libsystemd-terminal/idev-keyboard.c [deleted file]
src/libsystemd-terminal/idev.c [deleted file]
src/libsystemd-terminal/idev.h [deleted file]
src/libsystemd-terminal/modeset.c [deleted file]
src/libsystemd-terminal/subterm.c [deleted file]
src/libsystemd-terminal/sysview-internal.h [deleted file]
src/libsystemd-terminal/sysview.c [deleted file]
src/libsystemd-terminal/sysview.h [deleted file]
src/libsystemd-terminal/term-charset.c [deleted file]
src/libsystemd-terminal/term-internal.h [deleted file]
src/libsystemd-terminal/term-page.c [deleted file]
src/libsystemd-terminal/term-parser.c [deleted file]
src/libsystemd-terminal/term-screen.c [deleted file]
src/libsystemd-terminal/term-wcwidth.c [deleted file]
src/libsystemd-terminal/term.h [deleted file]
src/libsystemd-terminal/test-term-page.c [deleted file]
src/libsystemd-terminal/test-term-parser.c [deleted file]
src/libsystemd-terminal/test-unifont.c [deleted file]
src/libsystemd-terminal/unifont-def.h [deleted file]
src/libsystemd-terminal/unifont.c [deleted file]
src/libsystemd-terminal/unifont.h [deleted file]
src/libsystemd-terminal/unifont.hex [deleted file]

diff --git a/src/libsystemd-terminal/.gitignore b/src/libsystemd-terminal/.gitignore
deleted file mode 100644 (file)
index 7de83bd..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/unifont-glyph-array.bin
diff --git a/src/libsystemd-terminal/evcat.c b/src/libsystemd-terminal/evcat.c
deleted file mode 100644 (file)
index d274225..0000000
+++ /dev/null
@@ -1,487 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-/*
- * Event Catenation
- * The evcat tool catenates input events of all requested devices and prints
- * them to standard-output. It's only meant for debugging of input-related
- * problems.
- */
-
-#include <errno.h>
-#include <getopt.h>
-#include <libevdev/libevdev.h>
-#include <linux/kd.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <systemd/sd-bus.h>
-#include <systemd/sd-event.h>
-#include <systemd/sd-login.h>
-#include <termios.h>
-#include <unistd.h>
-#include <xkbcommon/xkbcommon.h>
-#include "build.h"
-#include "event-util.h"
-#include "idev.h"
-#include "macro.h"
-#include "sysview.h"
-#include "term-internal.h"
-#include "util.h"
-
-typedef struct Evcat Evcat;
-
-struct Evcat {
-        char *session;
-        char *seat;
-        sd_event *event;
-        sd_bus *bus;
-        sysview_context *sysview;
-        idev_context *idev;
-        idev_session *idev_session;
-
-        bool managed : 1;
-};
-
-static Evcat *evcat_free(Evcat *e) {
-        if (!e)
-                return NULL;
-
-        e->idev_session = idev_session_free(e->idev_session);
-        e->idev = idev_context_unref(e->idev);
-        e->sysview = sysview_context_free(e->sysview);
-        e->bus = sd_bus_unref(e->bus);
-        e->event = sd_event_unref(e->event);
-        free(e->seat);
-        free(e->session);
-        free(e);
-
-        tcflush(0, TCIOFLUSH);
-
-        return NULL;
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(Evcat*, evcat_free);
-
-static bool is_managed(const char *session) {
-        unsigned int vtnr;
-        struct stat st;
-        long mode;
-        int r;
-
-        /* Using logind's Controller API is highly fragile if there is already
-         * a session controller running. If it is registered as controller
-         * itself, TakeControl will simply fail. But if its a legacy controller
-         * that does not use logind's controller API, we must never register
-         * our own controller. Otherwise, we really mess up the VT. Therefore,
-         * only run in managed mode if there's no-one else. */
-
-        if (geteuid() == 0)
-                return false;
-
-        if (!isatty(1))
-                return false;
-
-        if (!session)
-                return false;
-
-        r = sd_session_get_vt(session, &vtnr);
-        if (r < 0 || vtnr < 1 || vtnr > 63)
-                return false;
-
-        mode = 0;
-        r = ioctl(1, KDGETMODE, &mode);
-        if (r < 0 || mode != KD_TEXT)
-                return false;
-
-        r = fstat(1, &st);
-        if (r < 0 || minor(st.st_rdev) != vtnr)
-                return false;
-
-        return true;
-}
-
-static int evcat_new(Evcat **out) {
-        _cleanup_(evcat_freep) Evcat *e = NULL;
-        int r;
-
-        assert(out);
-
-        e = new0(Evcat, 1);
-        if (!e)
-                return log_oom();
-
-        r = sd_pid_get_session(getpid(), &e->session);
-        if (r < 0)
-                return log_error_errno(r, "Cannot retrieve logind session: %m");
-
-        r = sd_session_get_seat(e->session, &e->seat);
-        if (r < 0)
-                return log_error_errno(r, "Cannot retrieve seat of logind session: %m");
-
-        e->managed = is_managed(e->session);
-
-        r = sd_event_default(&e->event);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_open_system(&e->bus);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_attach_event(e->bus, e->event, SD_EVENT_PRIORITY_NORMAL);
-        if (r < 0)
-                return r;
-
-        r = sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1);
-        if (r < 0)
-                return r;
-
-        r = sd_event_add_signal(e->event, NULL, SIGTERM, NULL, NULL);
-        if (r < 0)
-                return r;
-
-        r = sd_event_add_signal(e->event, NULL, SIGINT, NULL, NULL);
-        if (r < 0)
-                return r;
-
-        r = sysview_context_new(&e->sysview,
-                                SYSVIEW_CONTEXT_SCAN_LOGIND |
-                                SYSVIEW_CONTEXT_SCAN_EVDEV,
-                                e->event,
-                                e->bus,
-                                NULL);
-        if (r < 0)
-                return r;
-
-        r = idev_context_new(&e->idev, e->event, e->bus);
-        if (r < 0)
-                return r;
-
-        *out = e;
-        e = NULL;
-        return 0;
-}
-
-static void kdata_print(idev_data *data) {
-        idev_data_keyboard *k = &data->keyboard;
-        char buf[128];
-        uint32_t i, c;
-        int cwidth;
-
-        /* Key-press state: UP/DOWN/REPEAT */
-        printf(" %-6s", k->value == 0 ? "UP" :
-                        k->value == 1 ? "DOWN" :
-                        "REPEAT");
-
-        /* Resync state */
-        printf(" | %-6s", data->resync ? "RESYNC" : "");
-
-        /* Keycode that triggered the event */
-        printf(" | %5u", (unsigned)k->keycode);
-
-        /* Well-known name of the keycode */
-        printf(" | %-20s", libevdev_event_code_get_name(EV_KEY, k->keycode) ? : "<unknown>");
-
-        /* Well-known modifiers */
-        printf(" | %-5s", (k->mods & IDEV_KBDMOD_SHIFT) ? "SHIFT" : "");
-        printf(" %-4s", (k->mods & IDEV_KBDMOD_CTRL) ? "CTRL" : "");
-        printf(" %-3s", (k->mods & IDEV_KBDMOD_ALT) ? "ALT" : "");
-        printf(" %-5s", (k->mods & IDEV_KBDMOD_LINUX) ? "LINUX" : "");
-        printf(" %-4s", (k->mods & IDEV_KBDMOD_CAPS) ? "CAPS" : "");
-
-        /* Consumed modifiers */
-        printf(" | %-5s", (k->consumed_mods & IDEV_KBDMOD_SHIFT) ? "SHIFT" : "");
-        printf(" %-4s", (k->consumed_mods & IDEV_KBDMOD_CTRL) ? "CTRL" : "");
-        printf(" %-3s", (k->consumed_mods & IDEV_KBDMOD_ALT) ? "ALT" : "");
-        printf(" %-5s", (k->consumed_mods & IDEV_KBDMOD_LINUX) ? "LINUX" : "");
-        printf(" %-4s", (k->consumed_mods & IDEV_KBDMOD_CAPS) ? "CAPS" : "");
-
-        /* Resolved symbols */
-        printf(" |");
-        for (i = 0; i < k->n_syms; ++i) {
-                buf[0] = 0;
-                xkb_keysym_get_name(k->keysyms[i], buf, sizeof(buf));
-
-                if (is_locale_utf8()) {
-                        c = k->codepoints[i];
-                        if (c < 0x110000 && c > 0x20 && (c < 0x7f || c > 0x9f)) {
-                                /* "%4lc" doesn't work well, so hard-code it */
-                                cwidth = mk_wcwidth(c);
-                                while (cwidth++ < 2)
-                                        printf(" ");
-
-                                printf(" '%lc':", (wchar_t)c);
-                        } else {
-                                printf("      ");
-                        }
-                }
-
-                printf(" XKB_KEY_%-30s", buf);
-        }
-
-        printf("\n");
-}
-
-static bool kdata_is_exit(idev_data *data) {
-        idev_data_keyboard *k = &data->keyboard;
-
-        if (k->value != 1)
-                return false;
-        if (k->n_syms != 1)
-                return false;
-
-        return k->codepoints[0] == 'q';
-}
-
-static int evcat_idev_fn(idev_session *session, void *userdata, idev_event *ev) {
-        Evcat *e = userdata;
-
-        switch (ev->type) {
-        case IDEV_EVENT_DEVICE_ADD:
-                idev_device_enable(ev->device_add.device);
-                break;
-        case IDEV_EVENT_DEVICE_REMOVE:
-                idev_device_disable(ev->device_remove.device);
-                break;
-        case IDEV_EVENT_DEVICE_DATA:
-                switch (ev->device_data.data.type) {
-                case IDEV_DATA_KEYBOARD:
-                        if (kdata_is_exit(&ev->device_data.data))
-                                sd_event_exit(e->event, 0);
-                        else
-                                kdata_print(&ev->device_data.data);
-
-                        break;
-                }
-
-                break;
-        }
-
-        return 0;
-}
-
-static int evcat_sysview_fn(sysview_context *c, void *userdata, sysview_event *ev) {
-        unsigned int flags, type;
-        Evcat *e = userdata;
-        sysview_device *d;
-        const char *name;
-        int r;
-
-        switch (ev->type) {
-        case SYSVIEW_EVENT_SESSION_FILTER:
-                if (streq_ptr(e->session, ev->session_filter.id))
-                        return 1;
-
-                break;
-        case SYSVIEW_EVENT_SESSION_ADD:
-                assert(!e->idev_session);
-
-                name = sysview_session_get_name(ev->session_add.session);
-                flags = 0;
-
-                if (e->managed)
-                        flags |= IDEV_SESSION_MANAGED;
-
-                r = idev_session_new(&e->idev_session,
-                                     e->idev,
-                                     flags,
-                                     name,
-                                     evcat_idev_fn,
-                                     e);
-                if (r < 0)
-                        return log_error_errno(r, "Cannot create idev session: %m");
-
-                if (e->managed) {
-                        r = sysview_session_take_control(ev->session_add.session);
-                        if (r < 0)
-                                return log_error_errno(r, "Cannot request session control: %m");
-                }
-
-                idev_session_enable(e->idev_session);
-
-                break;
-        case SYSVIEW_EVENT_SESSION_REMOVE:
-                idev_session_disable(e->idev_session);
-                e->idev_session = idev_session_free(e->idev_session);
-                if (sd_event_get_exit_code(e->event, &r) == -ENODATA)
-                        sd_event_exit(e->event, 0);
-                break;
-        case SYSVIEW_EVENT_SESSION_ATTACH:
-                d = ev->session_attach.device;
-                type = sysview_device_get_type(d);
-                if (type == SYSVIEW_DEVICE_EVDEV) {
-                        r = idev_session_add_evdev(e->idev_session, sysview_device_get_ud(d));
-                        if (r < 0)
-                                return log_error_errno(r, "Cannot add evdev device to idev: %m");
-                }
-
-                break;
-        case SYSVIEW_EVENT_SESSION_DETACH:
-                d = ev->session_detach.device;
-                type = sysview_device_get_type(d);
-                if (type == SYSVIEW_DEVICE_EVDEV) {
-                        r = idev_session_remove_evdev(e->idev_session, sysview_device_get_ud(d));
-                        if (r < 0)
-                                return log_error_errno(r, "Cannot remove evdev device from idev: %m");
-                }
-
-                break;
-        case SYSVIEW_EVENT_SESSION_CONTROL:
-                r = ev->session_control.error;
-                if (r < 0)
-                        return log_error_errno(r, "Cannot acquire session control: %m");
-
-                r = ioctl(1, KDSKBMODE, K_UNICODE);
-                if (r < 0)
-                        return log_error_errno(errno, "Cannot set K_UNICODE on stdout: %m");
-
-                r = ioctl(1, KDSETMODE, KD_TEXT);
-                if (r < 0)
-                        return log_error_errno(errno, "Cannot set KD_TEXT on stdout: %m");
-
-                printf("\n");
-
-                break;
-        }
-
-        return 0;
-}
-
-static int evcat_run(Evcat *e) {
-        struct termios in_attr, saved_attr;
-        int r;
-
-        assert(e);
-
-        if (!e->managed && geteuid() > 0)
-                log_warning("You run in unmanaged mode without being root. This is likely to produce no output..");
-
-        printf("evcat - Read and catenate events from selected input devices\n"
-               "        Running on seat '%s' in user-session '%s'\n"
-               "        Exit by pressing ^C or 'q'\n\n",
-               e->seat ? : "seat0", e->session ? : "<none>");
-
-        r = sysview_context_start(e->sysview, evcat_sysview_fn, e);
-        if (r < 0)
-                goto out;
-
-        r = tcgetattr(0, &in_attr);
-        if (r < 0) {
-                r = -errno;
-                goto out;
-        }
-
-        saved_attr = in_attr;
-        in_attr.c_lflag &= ~ECHO;
-
-        r = tcsetattr(0, TCSANOW, &in_attr);
-        if (r < 0) {
-                r = -errno;
-                goto out;
-        }
-
-        r = sd_event_loop(e->event);
-        tcsetattr(0, TCSANOW, &saved_attr);
-        printf("exiting..\n");
-
-out:
-        sysview_context_stop(e->sysview);
-        return r;
-}
-
-static int help(void) {
-        printf("%s [OPTIONS...]\n\n"
-               "Read and catenate events from selected input devices.\n\n"
-               "  -h --help               Show this help\n"
-               "     --version            Show package version\n"
-               , program_invocation_short_name);
-
-        return 0;
-}
-
-static int parse_argv(int argc, char *argv[]) {
-        enum {
-                ARG_VERSION = 0x100,
-        };
-        static const struct option options[] = {
-                { "help",       no_argument,    NULL, 'h'               },
-                { "version",    no_argument,    NULL, ARG_VERSION       },
-                {},
-        };
-        int c;
-
-        assert(argc >= 0);
-        assert(argv);
-
-        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
-                switch (c) {
-                case 'h':
-                        help();
-                        return 0;
-
-                case ARG_VERSION:
-                        puts(PACKAGE_STRING);
-                        puts(SYSTEMD_FEATURES);
-                        return 0;
-
-                case '?':
-                        return -EINVAL;
-
-                default:
-                        assert_not_reached("Unhandled option");
-                }
-
-        if (argc > optind) {
-                log_error("Too many arguments");
-                return -EINVAL;
-        }
-
-        return 1;
-}
-
-int main(int argc, char *argv[]) {
-        _cleanup_(evcat_freep) Evcat *e = NULL;
-        int r;
-
-        log_set_target(LOG_TARGET_AUTO);
-        log_parse_environment();
-        log_open();
-
-        setlocale(LC_ALL, "");
-        if (!is_locale_utf8())
-                log_warning("Locale is not set to UTF-8. Codepoints will not be printed!");
-
-        r = parse_argv(argc, argv);
-        if (r <= 0)
-                goto finish;
-
-        r = evcat_new(&e);
-        if (r < 0)
-                goto finish;
-
-        r = evcat_run(e);
-
-finish:
-        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
-}
diff --git a/src/libsystemd-terminal/grdev-drm.c b/src/libsystemd-terminal/grdev-drm.c
deleted file mode 100644 (file)
index 066a4d8..0000000
+++ /dev/null
@@ -1,3095 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <fcntl.h>
-#include <inttypes.h>
-#include <libudev.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <systemd/sd-bus.h>
-#include <systemd/sd-event.h>
-#include <unistd.h>
-
-/* Yuck! DRM headers need system headers included first.. but we have to
- * include it before shared/missing.h to avoid redefining ioctl bits */
-#include <drm.h>
-#include <drm_fourcc.h>
-#include <drm_mode.h>
-
-#include "bus-util.h"
-#include "hashmap.h"
-#include "grdev.h"
-#include "grdev-internal.h"
-#include "macro.h"
-#include "util.h"
-
-#define GRDRM_MAX_TRIES (16)
-
-typedef struct grdrm_object grdrm_object;
-typedef struct grdrm_plane grdrm_plane;
-typedef struct grdrm_connector grdrm_connector;
-typedef struct grdrm_encoder grdrm_encoder;
-typedef struct grdrm_crtc grdrm_crtc;
-
-typedef struct grdrm_fb grdrm_fb;
-typedef struct grdrm_pipe grdrm_pipe;
-typedef struct grdrm_card grdrm_card;
-typedef struct unmanaged_card unmanaged_card;
-typedef struct managed_card managed_card;
-
-/*
- * Objects
- */
-
-enum {
-        GRDRM_TYPE_CRTC,
-        GRDRM_TYPE_ENCODER,
-        GRDRM_TYPE_CONNECTOR,
-        GRDRM_TYPE_PLANE,
-        GRDRM_TYPE_CNT
-};
-
-struct grdrm_object {
-        grdrm_card *card;
-        uint32_t id;
-        uint32_t index;
-        unsigned int type;
-        void (*free_fn) (grdrm_object *object);
-
-        bool present : 1;
-        bool assigned : 1;
-};
-
-struct grdrm_plane {
-        grdrm_object object;
-
-        struct {
-                uint32_t used_crtc;
-                uint32_t used_fb;
-                uint32_t gamma_size;
-
-                uint32_t n_crtcs;
-                uint32_t max_crtcs;
-                uint32_t *crtcs;
-                uint32_t n_formats;
-                uint32_t max_formats;
-                uint32_t *formats;
-        } kern;
-};
-
-struct grdrm_connector {
-        grdrm_object object;
-
-        struct {
-                uint32_t type;
-                uint32_t type_id;
-                uint32_t used_encoder;
-                uint32_t connection;
-                uint32_t mm_width;
-                uint32_t mm_height;
-                uint32_t subpixel;
-
-                uint32_t n_encoders;
-                uint32_t max_encoders;
-                uint32_t *encoders;
-                uint32_t n_modes;
-                uint32_t max_modes;
-                struct drm_mode_modeinfo *modes;
-                uint32_t n_props;
-                uint32_t max_props;
-                uint32_t *prop_ids;
-                uint64_t *prop_values;
-        } kern;
-};
-
-struct grdrm_encoder {
-        grdrm_object object;
-
-        struct {
-                uint32_t type;
-                uint32_t used_crtc;
-
-                uint32_t n_crtcs;
-                uint32_t max_crtcs;
-                uint32_t *crtcs;
-                uint32_t n_clones;
-                uint32_t max_clones;
-                uint32_t *clones;
-        } kern;
-};
-
-struct grdrm_crtc {
-        grdrm_object object;
-
-        struct {
-                uint32_t used_fb;
-                uint32_t fb_offset_x;
-                uint32_t fb_offset_y;
-                uint32_t gamma_size;
-
-                uint32_t n_used_connectors;
-                uint32_t max_used_connectors;
-                uint32_t *used_connectors;
-
-                bool mode_set;
-                struct drm_mode_modeinfo mode;
-        } kern;
-
-        struct {
-                bool set;
-                uint32_t fb;
-                uint32_t fb_x;
-                uint32_t fb_y;
-                uint32_t gamma;
-
-                uint32_t n_connectors;
-                uint32_t *connectors;
-
-                bool mode_set;
-                struct drm_mode_modeinfo mode;
-        } old;
-
-        struct {
-                struct drm_mode_modeinfo mode;
-                uint32_t n_connectors;
-                uint32_t max_connectors;
-                uint32_t *connectors;
-        } set;
-
-        grdrm_pipe *pipe;
-
-        bool applied : 1;
-};
-
-#define GRDRM_OBJECT_INIT(_card, _id, _index, _type, _free_fn) ((grdrm_object){ \
-                .card = (_card), \
-                .id = (_id), \
-                .index = (_index), \
-                .type = (_type), \
-                .free_fn = (_free_fn), \
-        })
-
-grdrm_object *grdrm_find_object(grdrm_card *card, uint32_t id);
-int grdrm_object_add(grdrm_object *object);
-grdrm_object *grdrm_object_free(grdrm_object *object);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(grdrm_object*, grdrm_object_free);
-
-int grdrm_plane_new(grdrm_plane **out, grdrm_card *card, uint32_t id, uint32_t index);
-int grdrm_connector_new(grdrm_connector **out, grdrm_card *card, uint32_t id, uint32_t index);
-int grdrm_encoder_new(grdrm_encoder **out, grdrm_card *card, uint32_t id, uint32_t index);
-int grdrm_crtc_new(grdrm_crtc **out, grdrm_card *card, uint32_t id, uint32_t index);
-
-#define plane_from_object(_obj) container_of((_obj), grdrm_plane, object)
-#define connector_from_object(_obj) container_of((_obj), grdrm_connector, object)
-#define encoder_from_object(_obj) container_of((_obj), grdrm_encoder, object)
-#define crtc_from_object(_obj) container_of((_obj), grdrm_crtc, object)
-
-/*
- * Framebuffers
- */
-
-struct grdrm_fb {
-        grdev_fb base;
-        grdrm_card *card;
-        uint32_t id;
-        uint32_t handles[4];
-        uint32_t offsets[4];
-        uint32_t sizes[4];
-        uint32_t flipid;
-};
-
-static int grdrm_fb_new(grdrm_fb **out, grdrm_card *card, const struct drm_mode_modeinfo *mode);
-grdrm_fb *grdrm_fb_free(grdrm_fb *fb);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(grdrm_fb*, grdrm_fb_free);
-
-#define fb_from_base(_fb) container_of((_fb), grdrm_fb, base)
-
-/*
- * Pipes
- */
-
-struct grdrm_pipe {
-        grdev_pipe base;
-        grdrm_crtc *crtc;
-        uint32_t counter;
-};
-
-#define grdrm_pipe_from_base(_e) container_of((_e), grdrm_pipe, base)
-
-#define GRDRM_PIPE_NAME_MAX (GRDRM_CARD_NAME_MAX + 1 + DECIMAL_STR_MAX(uint32_t))
-
-static const grdev_pipe_vtable grdrm_pipe_vtable;
-
-static int grdrm_pipe_new(grdrm_pipe **out, grdrm_crtc *crtc, struct drm_mode_modeinfo *mode, size_t n_fbs);
-
-/*
- * Cards
- */
-
-struct grdrm_card {
-        grdev_card base;
-
-        int fd;
-        sd_event_source *fd_src;
-
-        uint32_t n_crtcs;
-        uint32_t n_encoders;
-        uint32_t n_connectors;
-        uint32_t n_planes;
-        uint32_t max_ids;
-        Hashmap *object_map;
-
-        bool async_hotplug : 1;
-        bool hotplug : 1;
-        bool running : 1;
-        bool ready : 1;
-        bool cap_dumb : 1;
-        bool cap_monotonic : 1;
-};
-
-struct unmanaged_card {
-        grdrm_card card;
-        char *devnode;
-};
-
-struct managed_card {
-        grdrm_card card;
-        dev_t devnum;
-
-        sd_bus_slot *slot_pause_device;
-        sd_bus_slot *slot_resume_device;
-        sd_bus_slot *slot_take_device;
-
-        bool requested : 1;             /* TakeDevice() was sent */
-        bool acquired : 1;              /* TakeDevice() was successful */
-        bool master : 1;                /* we are DRM-Master */
-};
-
-#define grdrm_card_from_base(_e) container_of((_e), grdrm_card, base)
-#define unmanaged_card_from_base(_e) \
-        container_of(grdrm_card_from_base(_e), unmanaged_card, card)
-#define managed_card_from_base(_e) \
-        container_of(grdrm_card_from_base(_e), managed_card, card)
-
-#define GRDRM_CARD_INIT(_vtable, _session) ((grdrm_card){ \
-                .base = GRDEV_CARD_INIT((_vtable), (_session)), \
-                .fd = -1, \
-                .max_ids = 32, \
-        })
-
-#define GRDRM_CARD_NAME_MAX (6 + DECIMAL_STR_MAX(unsigned) * 2)
-
-static const grdev_card_vtable unmanaged_card_vtable;
-static const grdev_card_vtable managed_card_vtable;
-
-static int grdrm_card_open(grdrm_card *card, int dev_fd);
-static void grdrm_card_close(grdrm_card *card);
-static bool grdrm_card_async(grdrm_card *card, int r);
-
-/*
- * The page-flip event of the kernel provides 64bit of arbitrary user-data. As
- * drivers tend to drop events on intermediate deep mode-sets or because we
- * might receive events during session activation, we try to avoid allocaing
- * dynamic data on those events. Instead, we safe the CRTC id plus a 32bit
- * counter in there. This way, we only get 32bit counters, not 64bit, but that
- * should be more than enough. On the bright side, we no longer care whether we
- * lose events. No memory leaks will occur.
- * Modern DRM drivers might be fixed to no longer leak events, but we want to
- * be safe. And associating dynamically allocated data with those events is
- * kinda ugly, anyway.
- */
-
-static uint64_t grdrm_encode_vblank_data(uint32_t id, uint32_t counter) {
-        return id | ((uint64_t)counter << 32);
-}
-
-static void grdrm_decode_vblank_data(uint64_t data, uint32_t *out_id, uint32_t *out_counter) {
-        if (out_id)
-                *out_id = data & 0xffffffffU;
-        if (out_counter)
-                *out_counter = (data >> 32) & 0xffffffffU;
-}
-
-static bool grdrm_modes_compatible(const struct drm_mode_modeinfo *a, const struct drm_mode_modeinfo *b) {
-        assert(a);
-        assert(b);
-
-        /* Test whether both modes are compatible according to our internal
-         * assumptions on modes. This comparison is highly dependent on how
-         * we treat modes in grdrm. If we export mode details, we need to
-         * make this comparison much stricter. */
-
-        if (a->hdisplay != b->hdisplay)
-                return false;
-        if (a->vdisplay != b->vdisplay)
-                return false;
-        if (a->vrefresh != b->vrefresh)
-                return false;
-
-        return true;
-}
-
-/*
- * Objects
- */
-
-grdrm_object *grdrm_find_object(grdrm_card *card, uint32_t id) {
-        assert_return(card, NULL);
-
-        return id > 0 ? hashmap_get(card->object_map, UINT32_TO_PTR(id)) : NULL;
-}
-
-int grdrm_object_add(grdrm_object *object) {
-        int r;
-
-        assert(object);
-        assert(object->card);
-        assert(object->id > 0);
-        assert(IN_SET(object->type, GRDRM_TYPE_CRTC, GRDRM_TYPE_ENCODER, GRDRM_TYPE_CONNECTOR, GRDRM_TYPE_PLANE));
-        assert(object->free_fn);
-
-        if (object->index >= 32)
-                log_debug("grdrm: %s: object index exceeds 32bit masks: type=%u, index=%" PRIu32,
-                          object->card->base.name, object->type, object->index);
-
-        r = hashmap_put(object->card->object_map, UINT32_TO_PTR(object->id), object);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-grdrm_object *grdrm_object_free(grdrm_object *object) {
-        if (!object)
-                return NULL;
-
-        assert(object->card);
-        assert(object->id > 0);
-        assert(IN_SET(object->type, GRDRM_TYPE_CRTC, GRDRM_TYPE_ENCODER, GRDRM_TYPE_CONNECTOR, GRDRM_TYPE_PLANE));
-        assert(object->free_fn);
-
-        hashmap_remove_value(object->card->object_map, UINT32_TO_PTR(object->id), object);
-
-        object->free_fn(object);
-        return NULL;
-}
-
-/*
- * Planes
- */
-
-static void plane_free(grdrm_object *object) {
-        grdrm_plane *plane = plane_from_object(object);
-
-        free(plane->kern.formats);
-        free(plane->kern.crtcs);
-        free(plane);
-}
-
-int grdrm_plane_new(grdrm_plane **out, grdrm_card *card, uint32_t id, uint32_t index) {
-        _cleanup_(grdrm_object_freep) grdrm_object *object = NULL;
-        grdrm_plane *plane;
-        int r;
-
-        assert(card);
-
-        plane = new0(grdrm_plane, 1);
-        if (!plane)
-                return -ENOMEM;
-
-        object = &plane->object;
-        *object = GRDRM_OBJECT_INIT(card, id, index, GRDRM_TYPE_PLANE, plane_free);
-
-        plane->kern.max_crtcs = 32;
-        plane->kern.crtcs = new0(uint32_t, plane->kern.max_crtcs);
-        if (!plane->kern.crtcs)
-                return -ENOMEM;
-
-        plane->kern.max_formats = 32;
-        plane->kern.formats = new0(uint32_t, plane->kern.max_formats);
-        if (!plane->kern.formats)
-                return -ENOMEM;
-
-        r = grdrm_object_add(object);
-        if (r < 0)
-                return r;
-
-        if (out)
-                *out = plane;
-        object = NULL;
-        return 0;
-}
-
-static int grdrm_plane_resync(grdrm_plane *plane) {
-        grdrm_card *card = plane->object.card;
-        size_t tries;
-        int r;
-
-        assert(plane);
-
-        for (tries = 0; tries < GRDRM_MAX_TRIES; ++tries) {
-                struct drm_mode_get_plane res;
-                grdrm_object *object;
-                bool resized = false;
-                Iterator iter;
-
-                zero(res);
-                res.plane_id = plane->object.id;
-                res.format_type_ptr = PTR_TO_UINT64(plane->kern.formats);
-                res.count_format_types = plane->kern.max_formats;
-
-                r = ioctl(card->fd, DRM_IOCTL_MODE_GETPLANE, &res);
-                if (r < 0) {
-                        r = -errno;
-                        if (r == -ENOENT) {
-                                card->async_hotplug = true;
-                                r = 0;
-                                log_debug("grdrm: %s: plane %u removed during resync",
-                                          card->base.name, plane->object.id);
-                        } else {
-                                log_debug_errno(errno, "grdrm: %s: cannot retrieve plane %u: %m",
-                                                card->base.name, plane->object.id);
-                        }
-
-                        return r;
-                }
-
-                plane->kern.n_crtcs = 0;
-                memzero(plane->kern.crtcs, sizeof(uint32_t) * plane->kern.max_crtcs);
-
-                HASHMAP_FOREACH(object, card->object_map, iter) {
-                        if (object->type != GRDRM_TYPE_CRTC || object->index >= 32)
-                                continue;
-                        if (!(res.possible_crtcs & (1 << object->index)))
-                                continue;
-                        if (plane->kern.n_crtcs >= 32) {
-                                log_debug("grdrm: %s: possible_crtcs of plane %" PRIu32 " exceeds 32bit mask",
-                                          card->base.name, plane->object.id);
-                                continue;
-                        }
-
-                        plane->kern.crtcs[plane->kern.n_crtcs++] = object->id;
-                }
-
-                if (res.count_format_types > plane->kern.max_formats) {
-                        uint32_t max, *t;
-
-                        max = ALIGN_POWER2(res.count_format_types);
-                        if (!max || max > UINT16_MAX) {
-                                log_debug("grdrm: %s: excessive plane resource limit: %" PRIu32, card->base.name, max);
-                                return -ERANGE;
-                        }
-
-                        t = realloc(plane->kern.formats, sizeof(*t) * max);
-                        if (!t)
-                                return -ENOMEM;
-
-                        plane->kern.formats = t;
-                        plane->kern.max_formats = max;
-                        resized = true;
-                }
-
-                if (resized)
-                        continue;
-
-                plane->kern.n_formats = res.count_format_types;
-                plane->kern.used_crtc = res.crtc_id;
-                plane->kern.used_fb = res.fb_id;
-                plane->kern.gamma_size = res.gamma_size;
-
-                break;
-        }
-
-        if (tries >= GRDRM_MAX_TRIES) {
-                log_debug("grdrm: %s: plane %u not settled for retrieval", card->base.name, plane->object.id);
-                return -EFAULT;
-        }
-
-        return 0;
-}
-
-/*
- * Connectors
- */
-
-static void connector_free(grdrm_object *object) {
-        grdrm_connector *connector = connector_from_object(object);
-
-        free(connector->kern.prop_values);
-        free(connector->kern.prop_ids);
-        free(connector->kern.modes);
-        free(connector->kern.encoders);
-        free(connector);
-}
-
-int grdrm_connector_new(grdrm_connector **out, grdrm_card *card, uint32_t id, uint32_t index) {
-        _cleanup_(grdrm_object_freep) grdrm_object *object = NULL;
-        grdrm_connector *connector;
-        int r;
-
-        assert(card);
-
-        connector = new0(grdrm_connector, 1);
-        if (!connector)
-                return -ENOMEM;
-
-        object = &connector->object;
-        *object = GRDRM_OBJECT_INIT(card, id, index, GRDRM_TYPE_CONNECTOR, connector_free);
-
-        connector->kern.max_encoders = 32;
-        connector->kern.encoders = new0(uint32_t, connector->kern.max_encoders);
-        if (!connector->kern.encoders)
-                return -ENOMEM;
-
-        connector->kern.max_modes = 32;
-        connector->kern.modes = new0(struct drm_mode_modeinfo, connector->kern.max_modes);
-        if (!connector->kern.modes)
-                return -ENOMEM;
-
-        connector->kern.max_props = 32;
-        connector->kern.prop_ids = new0(uint32_t, connector->kern.max_props);
-        connector->kern.prop_values = new0(uint64_t, connector->kern.max_props);
-        if (!connector->kern.prop_ids || !connector->kern.prop_values)
-                return -ENOMEM;
-
-        r = grdrm_object_add(object);
-        if (r < 0)
-                return r;
-
-        if (out)
-                *out = connector;
-        object = NULL;
-        return 0;
-}
-
-static int grdrm_connector_resync(grdrm_connector *connector) {
-        grdrm_card *card = connector->object.card;
-        size_t tries;
-        int r;
-
-        assert(connector);
-
-        for (tries = 0; tries < GRDRM_MAX_TRIES; ++tries) {
-                struct drm_mode_get_connector res;
-                bool resized = false;
-                uint32_t max;
-
-                zero(res);
-                res.connector_id = connector->object.id;
-                res.encoders_ptr = PTR_TO_UINT64(connector->kern.encoders);
-                res.props_ptr = PTR_TO_UINT64(connector->kern.prop_ids);
-                res.prop_values_ptr = PTR_TO_UINT64(connector->kern.prop_values);
-                res.count_encoders = connector->kern.max_encoders;
-                res.count_props = connector->kern.max_props;
-
-                /* The kernel reads modes from the EDID information only if we
-                 * pass count_modes==0. This is a legacy hack for libdrm (which
-                 * called every ioctl twice). Now we have to adopt.. *sigh*.
-                 * If we never received an hotplug event, there's no reason to
-                 * sync modes. EDID reads are heavy, so skip that if not
-                 * required. */
-                if (card->hotplug) {
-                        if (tries > 0) {
-                                res.modes_ptr = PTR_TO_UINT64(connector->kern.modes);
-                                res.count_modes = connector->kern.max_modes;
-                        } else {
-                                resized = true;
-                        }
-                }
-
-                r = ioctl(card->fd, DRM_IOCTL_MODE_GETCONNECTOR, &res);
-                if (r < 0) {
-                        r = -errno;
-                        if (r == -ENOENT) {
-                                card->async_hotplug = true;
-                                r = 0;
-                                log_debug("grdrm: %s: connector %u removed during resync",
-                                          card->base.name, connector->object.id);
-                        } else {
-                                log_debug_errno(errno, "grdrm: %s: cannot retrieve connector %u: %m",
-                                                card->base.name, connector->object.id);
-                        }
-
-                        return r;
-                }
-
-                if (res.count_encoders > connector->kern.max_encoders) {
-                        uint32_t *t;
-
-                        max = ALIGN_POWER2(res.count_encoders);
-                        if (!max || max > UINT16_MAX) {
-                                log_debug("grdrm: %s: excessive connector resource limit: %" PRIu32, card->base.name, max);
-                                return -ERANGE;
-                        }
-
-                        t = realloc(connector->kern.encoders, sizeof(*t) * max);
-                        if (!t)
-                                return -ENOMEM;
-
-                        connector->kern.encoders = t;
-                        connector->kern.max_encoders = max;
-                        resized = true;
-                }
-
-                if (res.count_modes > connector->kern.max_modes) {
-                        struct drm_mode_modeinfo *t;
-
-                        max = ALIGN_POWER2(res.count_modes);
-                        if (!max || max > UINT16_MAX) {
-                                log_debug("grdrm: %s: excessive connector resource limit: %" PRIu32, card->base.name, max);
-                                return -ERANGE;
-                        }
-
-                        t = realloc(connector->kern.modes, sizeof(*t) * max);
-                        if (!t)
-                                return -ENOMEM;
-
-                        connector->kern.modes = t;
-                        connector->kern.max_modes = max;
-                        resized = true;
-                }
-
-                if (res.count_props > connector->kern.max_props) {
-                        uint32_t *tids;
-                        uint64_t *tvals;
-
-                        max = ALIGN_POWER2(res.count_props);
-                        if (!max || max > UINT16_MAX) {
-                                log_debug("grdrm: %s: excessive connector resource limit: %" PRIu32, card->base.name, max);
-                                return -ERANGE;
-                        }
-
-                        tids = realloc(connector->kern.prop_ids, sizeof(*tids) * max);
-                        if (!tids)
-                                return -ENOMEM;
-                        connector->kern.prop_ids = tids;
-
-                        tvals = realloc(connector->kern.prop_values, sizeof(*tvals) * max);
-                        if (!tvals)
-                                return -ENOMEM;
-                        connector->kern.prop_values = tvals;
-
-                        connector->kern.max_props = max;
-                        resized = true;
-                }
-
-                if (resized)
-                        continue;
-
-                connector->kern.n_encoders = res.count_encoders;
-                connector->kern.n_props = res.count_props;
-                connector->kern.type = res.connector_type;
-                connector->kern.type_id = res.connector_type_id;
-                connector->kern.used_encoder = res.encoder_id;
-                connector->kern.connection = res.connection;
-                connector->kern.mm_width = res.mm_width;
-                connector->kern.mm_height = res.mm_height;
-                connector->kern.subpixel = res.subpixel;
-                if (res.modes_ptr == PTR_TO_UINT64(connector->kern.modes))
-                        connector->kern.n_modes = res.count_modes;
-
-                break;
-        }
-
-        if (tries >= GRDRM_MAX_TRIES) {
-                log_debug("grdrm: %s: connector %u not settled for retrieval", card->base.name, connector->object.id);
-                return -EFAULT;
-        }
-
-        return 0;
-}
-
-/*
- * Encoders
- */
-
-static void encoder_free(grdrm_object *object) {
-        grdrm_encoder *encoder = encoder_from_object(object);
-
-        free(encoder->kern.clones);
-        free(encoder->kern.crtcs);
-        free(encoder);
-}
-
-int grdrm_encoder_new(grdrm_encoder **out, grdrm_card *card, uint32_t id, uint32_t index) {
-        _cleanup_(grdrm_object_freep) grdrm_object *object = NULL;
-        grdrm_encoder *encoder;
-        int r;
-
-        assert(card);
-
-        encoder = new0(grdrm_encoder, 1);
-        if (!encoder)
-                return -ENOMEM;
-
-        object = &encoder->object;
-        *object = GRDRM_OBJECT_INIT(card, id, index, GRDRM_TYPE_ENCODER, encoder_free);
-
-        encoder->kern.max_crtcs = 32;
-        encoder->kern.crtcs = new0(uint32_t, encoder->kern.max_crtcs);
-        if (!encoder->kern.crtcs)
-                return -ENOMEM;
-
-        encoder->kern.max_clones = 32;
-        encoder->kern.clones = new0(uint32_t, encoder->kern.max_clones);
-        if (!encoder->kern.clones)
-                return -ENOMEM;
-
-        r = grdrm_object_add(object);
-        if (r < 0)
-                return r;
-
-        if (out)
-                *out = encoder;
-        object = NULL;
-        return 0;
-}
-
-static int grdrm_encoder_resync(grdrm_encoder *encoder) {
-        grdrm_card *card = encoder->object.card;
-        struct drm_mode_get_encoder res;
-        grdrm_object *object;
-        Iterator iter;
-        int r;
-
-        assert(encoder);
-
-        zero(res);
-        res.encoder_id = encoder->object.id;
-
-        r = ioctl(card->fd, DRM_IOCTL_MODE_GETENCODER, &res);
-        if (r < 0) {
-                r = -errno;
-                if (r == -ENOENT) {
-                        card->async_hotplug = true;
-                        r = 0;
-                        log_debug("grdrm: %s: encoder %u removed during resync",
-                                  card->base.name, encoder->object.id);
-                } else {
-                        log_debug_errno(errno, "grdrm: %s: cannot retrieve encoder %u: %m",
-                                        card->base.name, encoder->object.id);
-                }
-
-                return r;
-        }
-
-        encoder->kern.type = res.encoder_type;
-        encoder->kern.used_crtc = res.crtc_id;
-
-        encoder->kern.n_crtcs = 0;
-        memzero(encoder->kern.crtcs, sizeof(uint32_t) * encoder->kern.max_crtcs);
-
-        HASHMAP_FOREACH(object, card->object_map, iter) {
-                if (object->type != GRDRM_TYPE_CRTC || object->index >= 32)
-                        continue;
-                if (!(res.possible_crtcs & (1 << object->index)))
-                        continue;
-                if (encoder->kern.n_crtcs >= 32) {
-                        log_debug("grdrm: %s: possible_crtcs exceeds 32bit mask", card->base.name);
-                        continue;
-                }
-
-                encoder->kern.crtcs[encoder->kern.n_crtcs++] = object->id;
-        }
-
-        encoder->kern.n_clones = 0;
-        memzero(encoder->kern.clones, sizeof(uint32_t) * encoder->kern.max_clones);
-
-        HASHMAP_FOREACH(object, card->object_map, iter) {
-                if (object->type != GRDRM_TYPE_ENCODER || object->index >= 32)
-                        continue;
-                if (!(res.possible_clones & (1 << object->index)))
-                        continue;
-                if (encoder->kern.n_clones >= 32) {
-                        log_debug("grdrm: %s: possible_encoders exceeds 32bit mask", card->base.name);
-                        continue;
-                }
-
-                encoder->kern.clones[encoder->kern.n_clones++] = object->id;
-        }
-
-        return 0;
-}
-
-/*
- * Crtcs
- */
-
-static void crtc_free(grdrm_object *object) {
-        grdrm_crtc *crtc = crtc_from_object(object);
-
-        if (crtc->pipe)
-                grdev_pipe_free(&crtc->pipe->base);
-        free(crtc->set.connectors);
-        free(crtc->old.connectors);
-        free(crtc->kern.used_connectors);
-        free(crtc);
-}
-
-int grdrm_crtc_new(grdrm_crtc **out, grdrm_card *card, uint32_t id, uint32_t index) {
-        _cleanup_(grdrm_object_freep) grdrm_object *object = NULL;
-        grdrm_crtc *crtc;
-        int r;
-
-        assert(card);
-
-        crtc = new0(grdrm_crtc, 1);
-        if (!crtc)
-                return -ENOMEM;
-
-        object = &crtc->object;
-        *object = GRDRM_OBJECT_INIT(card, id, index, GRDRM_TYPE_CRTC, crtc_free);
-
-        crtc->kern.max_used_connectors = 32;
-        crtc->kern.used_connectors = new0(uint32_t, crtc->kern.max_used_connectors);
-        if (!crtc->kern.used_connectors)
-                return -ENOMEM;
-
-        crtc->old.connectors = new0(uint32_t, crtc->kern.max_used_connectors);
-        if (!crtc->old.connectors)
-                return -ENOMEM;
-
-        r = grdrm_object_add(object);
-        if (r < 0)
-                return r;
-
-        if (out)
-                *out = crtc;
-        object = NULL;
-        return 0;
-}
-
-static int grdrm_crtc_resync(grdrm_crtc *crtc) {
-        grdrm_card *card = crtc->object.card;
-        struct drm_mode_crtc res = { .crtc_id = crtc->object.id };
-        int r;
-
-        assert(crtc);
-
-        /* make sure we can cache any combination later */
-        if (card->n_connectors > crtc->kern.max_used_connectors) {
-                uint32_t max, *t;
-
-                max = ALIGN_POWER2(card->n_connectors);
-                if (!max)
-                        return -ENOMEM;
-
-                t = realloc_multiply(crtc->kern.used_connectors, sizeof(*t), max);
-                if (!t)
-                        return -ENOMEM;
-
-                crtc->kern.used_connectors = t;
-                crtc->kern.max_used_connectors = max;
-
-                if (!crtc->old.set) {
-                        crtc->old.connectors = calloc(sizeof(*t), max);
-                        if (!crtc->old.connectors)
-                                return -ENOMEM;
-                }
-        }
-
-        /* GETCRTC doesn't return connectors. We have to read all
-         * encoder-state and deduce the setup ourselves.. */
-        crtc->kern.n_used_connectors = 0;
-
-        r = ioctl(card->fd, DRM_IOCTL_MODE_GETCRTC, &res);
-        if (r < 0) {
-                r = -errno;
-                if (r == -ENOENT) {
-                        card->async_hotplug = true;
-                        r = 0;
-                        log_debug("grdrm: %s: crtc %u removed during resync",
-                                  card->base.name, crtc->object.id);
-                } else {
-                        log_debug_errno(errno, "grdrm: %s: cannot retrieve crtc %u: %m",
-                                        card->base.name, crtc->object.id);
-                }
-
-                return r;
-        }
-
-        crtc->kern.used_fb = res.fb_id;
-        crtc->kern.fb_offset_x = res.x;
-        crtc->kern.fb_offset_y = res.y;
-        crtc->kern.gamma_size = res.gamma_size;
-        crtc->kern.mode_set = res.mode_valid;
-        crtc->kern.mode = res.mode;
-
-        return 0;
-}
-
-static void grdrm_crtc_assign(grdrm_crtc *crtc, grdrm_connector *connector) {
-        uint32_t n_connectors;
-        int r;
-
-        assert(crtc);
-        assert(!crtc->object.assigned);
-        assert(!connector || !connector->object.assigned);
-
-        /* always mark both as assigned; even if assignments cannot be set */
-        crtc->object.assigned = true;
-        if (connector)
-                connector->object.assigned = true;
-
-        /* we will support hw clone mode in the future */
-        n_connectors = connector ? 1 : 0;
-
-        /* bail out if configuration is preserved */
-        if (crtc->set.n_connectors == n_connectors &&
-            (n_connectors == 0 || crtc->set.connectors[0] == connector->object.id))
-                return;
-
-        crtc->applied = false;
-        crtc->set.n_connectors = 0;
-
-        if (n_connectors > crtc->set.max_connectors) {
-                uint32_t max, *t;
-
-                max = ALIGN_POWER2(n_connectors);
-                if (!max) {
-                        r = -ENOMEM;
-                        goto error;
-                }
-
-                t = realloc(crtc->set.connectors, sizeof(*t) * max);
-                if (!t) {
-                        r = -ENOMEM;
-                        goto error;
-                }
-
-                crtc->set.connectors = t;
-                crtc->set.max_connectors = max;
-        }
-
-        if (connector) {
-                struct drm_mode_modeinfo *m, *pref = NULL;
-                uint32_t i;
-
-                for (i = 0; i < connector->kern.n_modes; ++i) {
-                        m = &connector->kern.modes[i];
-
-                        /* ignore 3D modes by default */
-                        if (m->flags & DRM_MODE_FLAG_3D_MASK)
-                                continue;
-
-                        if (!pref) {
-                                pref = m;
-                                continue;
-                        }
-
-                        /* use PREFERRED over non-PREFERRED */
-                        if ((pref->type & DRM_MODE_TYPE_PREFERRED) &&
-                            !(m->type & DRM_MODE_TYPE_PREFERRED))
-                                continue;
-
-                        /* use DRIVER over non-PREFERRED|DRIVER */
-                        if ((pref->type & DRM_MODE_TYPE_DRIVER) &&
-                            !(m->type & (DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED)))
-                                continue;
-
-                        /* always prefer higher resolution */
-                        if (pref->hdisplay > m->hdisplay ||
-                            (pref->hdisplay == m->hdisplay && pref->vdisplay > m->vdisplay))
-                                continue;
-
-                        pref = m;
-                }
-
-                if (pref) {
-                        crtc->set.mode = *pref;
-                        crtc->set.n_connectors = 1;
-                        crtc->set.connectors[0] = connector->object.id;
-                        log_debug("grdrm: %s: assigned connector %" PRIu32 " to crtc %" PRIu32 " with mode %s",
-                                  crtc->object.card->base.name, connector->object.id, crtc->object.id, pref->name);
-                } else {
-                        log_debug("grdrm: %s: connector %" PRIu32 " to be assigned but has no valid mode",
-                                  crtc->object.card->base.name, connector->object.id);
-                }
-        }
-
-        return;
-
-error:
-        log_debug("grdrm: %s: cannot assign crtc %" PRIu32 ": %s",
-                  crtc->object.card->base.name, crtc->object.id, strerror(-r));
-}
-
-static void grdrm_crtc_expose(grdrm_crtc *crtc) {
-        grdrm_pipe *pipe;
-        grdrm_fb *fb;
-        size_t i;
-        int r;
-
-        assert(crtc);
-        assert(crtc->object.assigned);
-
-        if (crtc->set.n_connectors < 1) {
-                if (crtc->pipe)
-                        grdev_pipe_free(&crtc->pipe->base);
-                crtc->pipe = NULL;
-                return;
-        }
-
-        pipe = crtc->pipe;
-        if (pipe) {
-                if (pipe->base.width != crtc->set.mode.hdisplay ||
-                    pipe->base.height != crtc->set.mode.vdisplay ||
-                    pipe->base.vrefresh != crtc->set.mode.vrefresh) {
-                        grdev_pipe_free(&pipe->base);
-                        crtc->pipe = NULL;
-                        pipe = NULL;
-                }
-        }
-
-        if (crtc->pipe) {
-                pipe->base.front = NULL;
-                pipe->base.back = NULL;
-                for (i = 0; i < pipe->base.max_fbs; ++i) {
-                        fb = fb_from_base(pipe->base.fbs[i]);
-                        if (fb->id == crtc->kern.used_fb)
-                                pipe->base.front = &fb->base;
-                        else if (!fb->flipid)
-                                pipe->base.back = &fb->base;
-                }
-        } else {
-                r = grdrm_pipe_new(&pipe, crtc, &crtc->set.mode, 2);
-                if (r < 0) {
-                        log_debug("grdrm: %s: cannot create pipe for crtc %" PRIu32 ": %s",
-                                  crtc->object.card->base.name, crtc->object.id, strerror(-r));
-                        return;
-                }
-
-                for (i = 0; i < pipe->base.max_fbs; ++i) {
-                        r = grdrm_fb_new(&fb, crtc->object.card, &crtc->set.mode);
-                        if (r < 0) {
-                                log_debug("grdrm: %s: cannot allocate framebuffer for crtc %" PRIu32 ": %s",
-                                          crtc->object.card->base.name, crtc->object.id, strerror(-r));
-                                grdev_pipe_free(&pipe->base);
-                                return;
-                        }
-
-                        pipe->base.fbs[i] = &fb->base;
-                }
-
-                pipe->base.front = NULL;
-                pipe->base.back = pipe->base.fbs[0];
-                crtc->pipe = pipe;
-        }
-
-        grdev_pipe_ready(&crtc->pipe->base, true);
-}
-
-static void grdrm_crtc_commit_deep(grdrm_crtc *crtc, grdev_fb *basefb) {
-        struct drm_mode_crtc set_crtc = { .crtc_id = crtc->object.id };
-        grdrm_card *card = crtc->object.card;
-        grdrm_pipe *pipe = crtc->pipe;
-        grdrm_fb *fb;
-        int r;
-
-        assert(crtc);
-        assert(basefb);
-        assert(pipe);
-
-        fb = fb_from_base(basefb);
-
-        set_crtc.set_connectors_ptr = PTR_TO_UINT64(crtc->set.connectors);
-        set_crtc.count_connectors = crtc->set.n_connectors;
-        set_crtc.fb_id = fb->id;
-        set_crtc.x = 0;
-        set_crtc.y = 0;
-        set_crtc.mode_valid = 1;
-        set_crtc.mode = crtc->set.mode;
-
-        r = ioctl(card->fd, DRM_IOCTL_MODE_SETCRTC, &set_crtc);
-        if (r < 0) {
-                r = -errno;
-                log_debug_errno(errno, "grdrm: %s: cannot set crtc %" PRIu32 ": %m",
-                                card->base.name, crtc->object.id);
-
-                grdrm_card_async(card, r);
-                return;
-        }
-
-        if (!crtc->applied) {
-                log_debug("grdrm: %s: crtc %" PRIu32 " applied via deep modeset",
-                          card->base.name, crtc->object.id);
-                crtc->applied = true;
-        }
-
-        pipe->base.back = NULL;
-        pipe->base.front = &fb->base;
-        fb->flipid = 0;
-        ++pipe->counter;
-        pipe->base.flipping = false;
-        pipe->base.flip = false;
-
-        /* We cannot schedule dummy page-flips on pipes, hence, the
-         * application would have to schedule their own frame-timers.
-         * To avoid duplicating that everywhere, we schedule our own
-         * timer and raise a fake FRAME event when it fires. */
-        grdev_pipe_schedule(&pipe->base, 1);
-}
-
-static int grdrm_crtc_commit_flip(grdrm_crtc *crtc, grdev_fb *basefb) {
-        struct drm_mode_crtc_page_flip page_flip = { .crtc_id = crtc->object.id };
-        grdrm_card *card = crtc->object.card;
-        grdrm_pipe *pipe = crtc->pipe;
-        grdrm_fb *fb;
-        uint32_t cnt;
-        int r;
-
-        assert(crtc);
-        assert(basefb);
-        assert(pipe);
-
-        if (!crtc->applied) {
-                if (!grdrm_modes_compatible(&crtc->kern.mode, &crtc->set.mode))
-                        return 0;
-
-                /* TODO: Theoretically, we should be able to page-flip to our
-                 * framebuffer here. We didn't perform any deep modeset, but the
-                 * DRM driver is really supposed to reject our page-flip in case
-                 * the FB is not compatible. We then properly fall back to a
-                 * deep modeset.
-                 * As it turns out, drivers don't to this. Therefore, we need to
-                 * perform a full modeset on enter now. We might avoid this in
-                 * the future with fixed drivers.. */
-
-                return 0;
-        }
-
-        fb = fb_from_base(basefb);
-
-        cnt = ++pipe->counter ? : ++pipe->counter;
-        page_flip.fb_id = fb->id;
-        page_flip.flags = DRM_MODE_PAGE_FLIP_EVENT;
-        page_flip.user_data = grdrm_encode_vblank_data(crtc->object.id, cnt);
-
-        r = ioctl(card->fd, DRM_IOCTL_MODE_PAGE_FLIP, &page_flip);
-        if (r < 0) {
-                r = -errno;
-                /* Avoid excessive logging on EINVAL; it is currently not
-                 * possible to see whether cards support page-flipping, so
-                 * avoid logging on each frame. */
-                if (r != -EINVAL)
-                        log_debug_errno(errno, "grdrm: %s: cannot schedule page-flip on crtc %" PRIu32 ": %m",
-                                        card->base.name, crtc->object.id);
-
-                if (grdrm_card_async(card, r))
-                        return r;
-
-                return 0;
-        }
-
-        if (!crtc->applied) {
-                log_debug("grdrm: %s: crtc %" PRIu32 " applied via page flip",
-                          card->base.name, crtc->object.id);
-                crtc->applied = true;
-        }
-
-        pipe->base.flipping = true;
-        pipe->base.flip = false;
-        pipe->counter = cnt;
-        fb->flipid = cnt;
-        pipe->base.back = NULL;
-
-        /* Raise fake FRAME event if it takes longer than 2
-         * frames to receive the pageflip event. We assume the
-         * queue ran over or some other error happened. */
-        grdev_pipe_schedule(&pipe->base, 2);
-
-        return 1;
-}
-
-static void grdrm_crtc_commit(grdrm_crtc *crtc) {
-        struct drm_mode_crtc set_crtc = { .crtc_id = crtc->object.id };
-        grdrm_card *card = crtc->object.card;
-        grdrm_pipe *pipe;
-        grdev_fb *fb;
-        int r;
-
-        assert(crtc);
-        assert(crtc->object.assigned);
-
-        pipe = crtc->pipe;
-        if (!pipe) {
-                /* If a crtc is not assigned any connector, we want any
-                 * previous setup to be cleared, so make sure the CRTC is
-                 * disabled. Otherwise, there might be content on the CRTC
-                 * while we run, which is not what we want.
-                 * If you want to avoid modesets on specific CRTCs, you should
-                 * still keep their assignment, but never enable the resulting
-                 * pipe. This way, we wouldn't touch it at all. */
-                if (!crtc->applied) {
-                        crtc->applied = true;
-                        r = ioctl(card->fd, DRM_IOCTL_MODE_SETCRTC, &set_crtc);
-                        if (r < 0) {
-                                r = -errno;
-                                log_debug_errno(errno, "grdrm: %s: cannot shutdown crtc %" PRIu32 ": %m",
-                                                card->base.name, crtc->object.id);
-
-                                grdrm_card_async(card, r);
-                                return;
-                        }
-
-                        log_debug("grdrm: %s: crtc %" PRIu32 " applied via shutdown",
-                                  card->base.name, crtc->object.id);
-                }
-
-                return;
-        }
-
-        /* we always fully ignore disabled pipes */
-        if (!pipe->base.enabled)
-                return;
-
-        assert(crtc->set.n_connectors > 0);
-
-        if (pipe->base.flip)
-                fb = pipe->base.back;
-        else if (!crtc->applied)
-                fb = pipe->base.front;
-        else
-                return;
-
-        if (!fb)
-                return;
-
-        r = grdrm_crtc_commit_flip(crtc, fb);
-        if (r == 0) {
-                /* in case we couldn't page-flip, perform deep modeset */
-                grdrm_crtc_commit_deep(crtc, fb);
-        }
-}
-
-static void grdrm_crtc_restore(grdrm_crtc *crtc) {
-        struct drm_mode_crtc set_crtc = { .crtc_id = crtc->object.id };
-        grdrm_card *card = crtc->object.card;
-        int r;
-
-        if (!crtc->old.set)
-                return;
-
-        set_crtc.set_connectors_ptr = PTR_TO_UINT64(crtc->old.connectors);
-        set_crtc.count_connectors = crtc->old.n_connectors;
-        set_crtc.fb_id = crtc->old.fb;
-        set_crtc.x = crtc->old.fb_x;
-        set_crtc.y = crtc->old.fb_y;
-        set_crtc.gamma_size = crtc->old.gamma;
-        set_crtc.mode_valid = crtc->old.mode_set;
-        set_crtc.mode = crtc->old.mode;
-
-        r = ioctl(card->fd, DRM_IOCTL_MODE_SETCRTC, &set_crtc);
-        if (r < 0) {
-                r = -errno;
-                log_debug_errno(errno, "grdrm: %s: cannot restore crtc %" PRIu32 ": %m",
-                                card->base.name, crtc->object.id);
-
-                grdrm_card_async(card, r);
-                return;
-        }
-
-        if (crtc->pipe) {
-                ++crtc->pipe->counter;
-                crtc->pipe->base.front = NULL;
-                crtc->pipe->base.flipping = false;
-        }
-
-        log_debug("grdrm: %s: crtc %" PRIu32 " restored", card->base.name, crtc->object.id);
-}
-
-static void grdrm_crtc_flip_complete(grdrm_crtc *crtc, uint32_t counter, struct drm_event_vblank *event) {
-        bool flipped = false;
-        grdrm_pipe *pipe;
-        size_t i;
-
-        assert(crtc);
-        assert(event);
-
-        pipe = crtc->pipe;
-        if (!pipe)
-                return;
-
-        /* We got a page-flip event. To be safe, we reset all FBs on the same
-         * pipe that have smaller flipids than the flip we got as we know they
-         * are executed in order. We need to do this to guarantee
-         * queue-overflows or other missed events don't cause starvation.
-         * Furthermore, if we find the exact FB this event is for, *and* this
-         * is the most recent event, we mark it as front FB and raise a
-         * frame event. */
-
-        for (i = 0; i < pipe->base.max_fbs; ++i) {
-                grdrm_fb *fb;
-
-                if (!pipe->base.fbs[i])
-                        continue;
-
-                fb = fb_from_base(pipe->base.fbs[i]);
-                if (counter != 0 && counter == pipe->counter && fb->flipid == counter) {
-                        pipe->base.front = &fb->base;
-                        fb->flipid = 0;
-                        flipped = true;
-                } else if (counter - fb->flipid < UINT16_MAX) {
-                        fb->flipid = 0;
-                }
-        }
-
-        if (flipped) {
-                crtc->pipe->base.flipping = false;
-                grdev_pipe_frame(&pipe->base);
-        }
-}
-
-/*
- * Framebuffers
- */
-
-static int grdrm_fb_new(grdrm_fb **out, grdrm_card *card, const struct drm_mode_modeinfo *mode) {
-        _cleanup_(grdrm_fb_freep) grdrm_fb *fb = NULL;
-        struct drm_mode_create_dumb create_dumb = { };
-        struct drm_mode_map_dumb map_dumb = { };
-        struct drm_mode_fb_cmd2 add_fb = { };
-        unsigned int i;
-        int r;
-
-        assert_return(out, -EINVAL);
-        assert_return(card, -EINVAL);
-
-        fb = new0(grdrm_fb, 1);
-        if (!fb)
-                return -ENOMEM;
-
-        /* TODO: we should choose a compatible format of the previous CRTC
-         * setting to allow page-flip to it. Only choose fallback if the
-         * previous setting was crap (non xrgb32'ish). */
-
-        fb->card = card;
-        fb->base.format = DRM_FORMAT_XRGB8888;
-        fb->base.width = mode->hdisplay;
-        fb->base.height = mode->vdisplay;
-
-        for (i = 0; i < ELEMENTSOF(fb->base.maps); ++i)
-                fb->base.maps[i] = MAP_FAILED;
-
-        create_dumb.width = fb->base.width;
-        create_dumb.height = fb->base.height;
-        create_dumb.bpp = 32;
-
-        r = ioctl(card->fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb);
-        if (r < 0) {
-                r = negative_errno();
-                log_debug_errno(errno, "grdrm: %s: cannot create dumb buffer %" PRIu32 "x%" PRIu32": %m",
-                                card->base.name, fb->base.width, fb->base.height);
-                return r;
-        }
-
-        fb->handles[0] = create_dumb.handle;
-        fb->base.strides[0] = create_dumb.pitch;
-        fb->sizes[0] = create_dumb.size;
-
-        map_dumb.handle = fb->handles[0];
-
-        r = ioctl(card->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb);
-        if (r < 0) {
-                r = negative_errno();
-                log_debug_errno(errno, "grdrm: %s: cannot map dumb buffer %" PRIu32 "x%" PRIu32": %m",
-                                card->base.name, fb->base.width, fb->base.height);
-                return r;
-        }
-
-        fb->base.maps[0] = mmap(0, fb->sizes[0], PROT_WRITE, MAP_SHARED, card->fd, map_dumb.offset);
-        if (fb->base.maps[0] == MAP_FAILED) {
-                r = negative_errno();
-                log_debug_errno(errno, "grdrm: %s: cannot memory-map dumb buffer %" PRIu32 "x%" PRIu32": %m",
-                                card->base.name, fb->base.width, fb->base.height);
-                return r;
-        }
-
-        memzero(fb->base.maps[0], fb->sizes[0]);
-
-        add_fb.width = fb->base.width;
-        add_fb.height = fb->base.height;
-        add_fb.pixel_format = fb->base.format;
-        add_fb.flags = 0;
-        memcpy(add_fb.handles, fb->handles, sizeof(fb->handles));
-        memcpy(add_fb.pitches, fb->base.strides, sizeof(fb->base.strides));
-        memcpy(add_fb.offsets, fb->offsets, sizeof(fb->offsets));
-
-        r = ioctl(card->fd, DRM_IOCTL_MODE_ADDFB2, &add_fb);
-        if (r < 0) {
-                r = negative_errno();
-                log_debug_errno(errno, "grdrm: %s: cannot add framebuffer %" PRIu32 "x%" PRIu32": %m",
-                                card->base.name, fb->base.width, fb->base.height);
-                return r;
-        }
-
-        fb->id = add_fb.fb_id;
-
-        *out = fb;
-        fb = NULL;
-        return 0;
-}
-
-grdrm_fb *grdrm_fb_free(grdrm_fb *fb) {
-        unsigned int i;
-        int r;
-
-        if (!fb)
-                return NULL;
-
-        assert(fb->card);
-
-        if (fb->base.free_fn)
-                fb->base.free_fn(fb->base.data.ptr);
-
-        if (fb->id > 0 && fb->card->fd >= 0) {
-                r = ioctl(fb->card->fd, DRM_IOCTL_MODE_RMFB, fb->id);
-                if (r < 0)
-                        log_debug_errno(errno, "grdrm: %s: cannot delete framebuffer %" PRIu32 ": %m",
-                                        fb->card->base.name, fb->id);
-        }
-
-        for (i = 0; i < ELEMENTSOF(fb->handles); ++i) {
-                struct drm_mode_destroy_dumb destroy_dumb = { };
-
-                if (fb->base.maps[i] != MAP_FAILED)
-                        munmap(fb->base.maps[i], fb->sizes[i]);
-
-                if (fb->handles[i] > 0 && fb->card->fd >= 0) {
-                        destroy_dumb.handle = fb->handles[i];
-                        r = ioctl(fb->card->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb);
-                        if (r < 0)
-                                log_debug_errno(errno, "grdrm: %s: cannot destroy dumb-buffer %" PRIu32 ": %m",
-                                                fb->card->base.name, fb->handles[i]);
-                }
-        }
-
-        free(fb);
-
-        return NULL;
-}
-
-/*
- * Pipes
- */
-
-static void grdrm_pipe_name(char *out, grdrm_crtc *crtc) {
-        /* @out must be at least of size GRDRM_PIPE_NAME_MAX */
-        sprintf(out, "%s/%" PRIu32, crtc->object.card->base.name, crtc->object.id);
-}
-
-static int grdrm_pipe_new(grdrm_pipe **out, grdrm_crtc *crtc, struct drm_mode_modeinfo *mode, size_t n_fbs) {
-        _cleanup_(grdev_pipe_freep) grdev_pipe *basepipe = NULL;
-        grdrm_card *card = crtc->object.card;
-        char name[GRDRM_PIPE_NAME_MAX];
-        grdrm_pipe *pipe;
-        int r;
-
-        assert_return(crtc, -EINVAL);
-        assert_return(grdev_is_drm_card(&card->base), -EINVAL);
-
-        pipe = new0(grdrm_pipe, 1);
-        if (!pipe)
-                return -ENOMEM;
-
-        basepipe = &pipe->base;
-        pipe->base = GRDEV_PIPE_INIT(&grdrm_pipe_vtable, &card->base);
-        pipe->crtc = crtc;
-        pipe->base.width = mode->hdisplay;
-        pipe->base.height = mode->vdisplay;
-        pipe->base.vrefresh = mode->vrefresh ? : 25;
-
-        grdrm_pipe_name(name, crtc);
-        r = grdev_pipe_add(&pipe->base, name, n_fbs);
-        if (r < 0)
-                return r;
-
-        if (out)
-                *out = pipe;
-        basepipe = NULL;
-        return 0;
-}
-
-static void grdrm_pipe_free(grdev_pipe *basepipe) {
-        grdrm_pipe *pipe = grdrm_pipe_from_base(basepipe);
-        size_t i;
-
-        assert(pipe->crtc);
-
-        for (i = 0; i < pipe->base.max_fbs; ++i)
-                if (pipe->base.fbs[i])
-                        grdrm_fb_free(fb_from_base(pipe->base.fbs[i]));
-
-        free(pipe);
-}
-
-static grdev_fb *grdrm_pipe_target(grdev_pipe *basepipe) {
-        grdrm_fb *fb;
-        size_t i;
-
-        if (!basepipe->back) {
-                for (i = 0; i < basepipe->max_fbs; ++i) {
-                        if (!basepipe->fbs[i])
-                                continue;
-
-                        fb = fb_from_base(basepipe->fbs[i]);
-                        if (&fb->base == basepipe->front)
-                                continue;
-                        if (basepipe->flipping && fb->flipid)
-                                continue;
-
-                        basepipe->back = &fb->base;
-                        break;
-                }
-        }
-
-        return basepipe->back;
-}
-
-static void grdrm_pipe_enable(grdev_pipe *basepipe) {
-        grdrm_pipe *pipe = grdrm_pipe_from_base(basepipe);
-
-        pipe->crtc->applied = false;
-}
-
-static void grdrm_pipe_disable(grdev_pipe *basepipe) {
-        grdrm_pipe *pipe = grdrm_pipe_from_base(basepipe);
-
-        pipe->crtc->applied = false;
-}
-
-static const grdev_pipe_vtable grdrm_pipe_vtable = {
-        .free                   = grdrm_pipe_free,
-        .target                 = grdrm_pipe_target,
-        .enable                 = grdrm_pipe_enable,
-        .disable                = grdrm_pipe_disable,
-};
-
-/*
- * Cards
- */
-
-static void grdrm_name(char *out, dev_t devnum) {
-        /* @out must be at least of size GRDRM_CARD_NAME_MAX */
-        sprintf(out, "drm/%u:%u", major(devnum), minor(devnum));
-}
-
-static void grdrm_card_print(grdrm_card *card) {
-        grdrm_object *object;
-        grdrm_crtc *crtc;
-        grdrm_encoder *encoder;
-        grdrm_connector *connector;
-        grdrm_plane *plane;
-        Iterator iter;
-        uint32_t i;
-        char *p, *buf;
-
-        log_debug("grdrm: %s: state dump", card->base.name);
-
-        log_debug("  crtcs:");
-        HASHMAP_FOREACH(object, card->object_map, iter) {
-                if (object->type != GRDRM_TYPE_CRTC)
-                        continue;
-
-                crtc = crtc_from_object(object);
-                log_debug("    (id: %u index: %d)", object->id, object->index);
-
-                if (crtc->kern.mode_set)
-                        log_debug("      mode: %dx%d", crtc->kern.mode.hdisplay, crtc->kern.mode.vdisplay);
-                else
-                        log_debug("      mode: <none>");
-        }
-
-        log_debug("  encoders:");
-        HASHMAP_FOREACH(object, card->object_map, iter) {
-                if (object->type != GRDRM_TYPE_ENCODER)
-                        continue;
-
-                encoder = encoder_from_object(object);
-                log_debug("    (id: %u index: %d)", object->id, object->index);
-
-                if (encoder->kern.used_crtc)
-                        log_debug("      crtc: %u", encoder->kern.used_crtc);
-                else
-                        log_debug("      crtc: <none>");
-
-                buf = malloc((DECIMAL_STR_MAX(uint32_t) + 1) * encoder->kern.n_crtcs + 1);
-                if (buf) {
-                        buf[0] = 0;
-                        p = buf;
-
-                        for (i = 0; i < encoder->kern.n_crtcs; ++i)
-                                p += sprintf(p, " %" PRIu32, encoder->kern.crtcs[i]);
-
-                        log_debug("      possible crtcs:%s", buf);
-                        free(buf);
-                }
-
-                buf = malloc((DECIMAL_STR_MAX(uint32_t) + 1) * encoder->kern.n_clones + 1);
-                if (buf) {
-                        buf[0] = 0;
-                        p = buf;
-
-                        for (i = 0; i < encoder->kern.n_clones; ++i)
-                                p += sprintf(p, " %" PRIu32, encoder->kern.clones[i]);
-
-                        log_debug("      possible clones:%s", buf);
-                        free(buf);
-                }
-        }
-
-        log_debug("  connectors:");
-        HASHMAP_FOREACH(object, card->object_map, iter) {
-                if (object->type != GRDRM_TYPE_CONNECTOR)
-                        continue;
-
-                connector = connector_from_object(object);
-                log_debug("    (id: %u index: %d)", object->id, object->index);
-                log_debug("      type: %" PRIu32 "-%" PRIu32 " connection: %" PRIu32 " subpixel: %" PRIu32 " extents: %" PRIu32 "x%" PRIu32,
-                          connector->kern.type, connector->kern.type_id, connector->kern.connection, connector->kern.subpixel,
-                          connector->kern.mm_width, connector->kern.mm_height);
-
-                if (connector->kern.used_encoder)
-                        log_debug("      encoder: %" PRIu32, connector->kern.used_encoder);
-                else
-                        log_debug("      encoder: <none>");
-
-                buf = malloc((DECIMAL_STR_MAX(uint32_t) + 1) * connector->kern.n_encoders + 1);
-                if (buf) {
-                        buf[0] = 0;
-                        p = buf;
-
-                        for (i = 0; i < connector->kern.n_encoders; ++i)
-                                p += sprintf(p, " %" PRIu32, connector->kern.encoders[i]);
-
-                        log_debug("      possible encoders:%s", buf);
-                        free(buf);
-                }
-
-                for (i = 0; i < connector->kern.n_modes; ++i) {
-                        struct drm_mode_modeinfo *mode = &connector->kern.modes[i];
-                        log_debug("      mode: %" PRIu32 "x%" PRIu32, mode->hdisplay, mode->vdisplay);
-                }
-        }
-
-        log_debug("  planes:");
-        HASHMAP_FOREACH(object, card->object_map, iter) {
-                if (object->type != GRDRM_TYPE_PLANE)
-                        continue;
-
-                plane = plane_from_object(object);
-                log_debug("    (id: %u index: %d)", object->id, object->index);
-                log_debug("      gamma-size: %" PRIu32, plane->kern.gamma_size);
-
-                if (plane->kern.used_crtc)
-                        log_debug("      crtc: %" PRIu32, plane->kern.used_crtc);
-                else
-                        log_debug("      crtc: <none>");
-
-                buf = malloc((DECIMAL_STR_MAX(uint32_t) + 1) * plane->kern.n_crtcs + 1);
-                if (buf) {
-                        buf[0] = 0;
-                        p = buf;
-
-                        for (i = 0; i < plane->kern.n_crtcs; ++i)
-                                p += sprintf(p, " %" PRIu32, plane->kern.crtcs[i]);
-
-                        log_debug("      possible crtcs:%s", buf);
-                        free(buf);
-                }
-
-                buf = malloc((DECIMAL_STR_MAX(unsigned int) + 3) * plane->kern.n_formats + 1);
-                if (buf) {
-                        buf[0] = 0;
-                        p = buf;
-
-                        for (i = 0; i < plane->kern.n_formats; ++i)
-                                p += sprintf(p, " 0x%x", (unsigned int)plane->kern.formats[i]);
-
-                        log_debug("      possible formats:%s", buf);
-                        free(buf);
-                }
-        }
-}
-
-static int grdrm_card_resync(grdrm_card *card) {
-        _cleanup_free_ uint32_t *crtc_ids = NULL, *encoder_ids = NULL, *connector_ids = NULL, *plane_ids = NULL;
-        uint32_t allocated = 0;
-        grdrm_object *object;
-        Iterator iter;
-        size_t tries;
-        int r;
-
-        assert(card);
-
-        card->async_hotplug = false;
-        allocated = 0;
-
-        /* mark existing objects for possible removal */
-        HASHMAP_FOREACH(object, card->object_map, iter)
-                object->present = false;
-
-        for (tries = 0; tries < GRDRM_MAX_TRIES; ++tries) {
-                struct drm_mode_get_plane_res pres;
-                struct drm_mode_card_res res;
-                uint32_t i, max;
-
-                if (allocated < card->max_ids) {
-                        free(crtc_ids);
-                        free(encoder_ids);
-                        free(connector_ids);
-                        free(plane_ids);
-                        crtc_ids = new0(uint32_t, card->max_ids);
-                        encoder_ids = new0(uint32_t, card->max_ids);
-                        connector_ids = new0(uint32_t, card->max_ids);
-                        plane_ids = new0(uint32_t, card->max_ids);
-
-                        if (!crtc_ids || !encoder_ids || !connector_ids || !plane_ids)
-                                return -ENOMEM;
-
-                        allocated = card->max_ids;
-                }
-
-                zero(res);
-                res.crtc_id_ptr = PTR_TO_UINT64(crtc_ids);
-                res.connector_id_ptr = PTR_TO_UINT64(connector_ids);
-                res.encoder_id_ptr = PTR_TO_UINT64(encoder_ids);
-                res.count_crtcs = allocated;
-                res.count_encoders = allocated;
-                res.count_connectors = allocated;
-
-                r = ioctl(card->fd, DRM_IOCTL_MODE_GETRESOURCES, &res);
-                if (r < 0) {
-                        r = -errno;
-                        log_debug_errno(errno, "grdrm: %s: cannot retrieve drm resources: %m",
-                                        card->base.name);
-                        return r;
-                }
-
-                zero(pres);
-                pres.plane_id_ptr = PTR_TO_UINT64(plane_ids);
-                pres.count_planes = allocated;
-
-                r = ioctl(card->fd, DRM_IOCTL_MODE_GETPLANERESOURCES, &pres);
-                if (r < 0) {
-                        r = -errno;
-                        log_debug_errno(errno, "grdrm: %s: cannot retrieve drm plane-resources: %m",
-                                        card->base.name);
-                        return r;
-                }
-
-                max = MAX(MAX(res.count_crtcs, res.count_encoders),
-                          MAX(res.count_connectors, pres.count_planes));
-                if (max > allocated) {
-                        uint32_t n;
-
-                        n = ALIGN_POWER2(max);
-                        if (!n || n > UINT16_MAX) {
-                                log_debug("grdrm: %s: excessive DRM resource limit: %" PRIu32,
-                                          card->base.name, max);
-                                return -ERANGE;
-                        }
-
-                        /* retry with resized buffers */
-                        card->max_ids = n;
-                        continue;
-                }
-
-                /* mark available objects as present */
-
-                for (i = 0; i < res.count_crtcs; ++i) {
-                        object = grdrm_find_object(card, crtc_ids[i]);
-                        if (object && object->type == GRDRM_TYPE_CRTC) {
-                                object->present = true;
-                                object->index = i;
-                                crtc_ids[i] = 0;
-                        }
-                }
-
-                for (i = 0; i < res.count_encoders; ++i) {
-                        object = grdrm_find_object(card, encoder_ids[i]);
-                        if (object && object->type == GRDRM_TYPE_ENCODER) {
-                                object->present = true;
-                                object->index = i;
-                                encoder_ids[i] = 0;
-                        }
-                }
-
-                for (i = 0; i < res.count_connectors; ++i) {
-                        object = grdrm_find_object(card, connector_ids[i]);
-                        if (object && object->type == GRDRM_TYPE_CONNECTOR) {
-                                object->present = true;
-                                object->index = i;
-                                connector_ids[i] = 0;
-                        }
-                }
-
-                for (i = 0; i < pres.count_planes; ++i) {
-                        object = grdrm_find_object(card, plane_ids[i]);
-                        if (object && object->type == GRDRM_TYPE_PLANE) {
-                                object->present = true;
-                                object->index = i;
-                                plane_ids[i] = 0;
-                        }
-                }
-
-                /* drop removed objects */
-
-                HASHMAP_FOREACH(object, card->object_map, iter)
-                        if (!object->present)
-                                grdrm_object_free(object);
-
-                /* add new objects */
-
-                card->n_crtcs = res.count_crtcs;
-                for (i = 0; i < res.count_crtcs; ++i) {
-                        if (crtc_ids[i] < 1)
-                                continue;
-
-                        r = grdrm_crtc_new(NULL, card, crtc_ids[i], i);
-                        if (r < 0)
-                                return r;
-                }
-
-                card->n_encoders = res.count_encoders;
-                for (i = 0; i < res.count_encoders; ++i) {
-                        if (encoder_ids[i] < 1)
-                                continue;
-
-                        r = grdrm_encoder_new(NULL, card, encoder_ids[i], i);
-                        if (r < 0)
-                                return r;
-                }
-
-                card->n_connectors = res.count_connectors;
-                for (i = 0; i < res.count_connectors; ++i) {
-                        if (connector_ids[i] < 1)
-                                continue;
-
-                        r = grdrm_connector_new(NULL, card, connector_ids[i], i);
-                        if (r < 0)
-                                return r;
-                }
-
-                card->n_planes = pres.count_planes;
-                for (i = 0; i < pres.count_planes; ++i) {
-                        if (plane_ids[i] < 1)
-                                continue;
-
-                        r = grdrm_plane_new(NULL, card, plane_ids[i], i);
-                        if (r < 0)
-                                return r;
-                }
-
-                /* re-sync objects after object_map is synced */
-
-                HASHMAP_FOREACH(object, card->object_map, iter) {
-                        switch (object->type) {
-                        case GRDRM_TYPE_CRTC:
-                                r = grdrm_crtc_resync(crtc_from_object(object));
-                                break;
-                        case GRDRM_TYPE_ENCODER:
-                                r = grdrm_encoder_resync(encoder_from_object(object));
-                                break;
-                        case GRDRM_TYPE_CONNECTOR:
-                                r = grdrm_connector_resync(connector_from_object(object));
-                                break;
-                        case GRDRM_TYPE_PLANE:
-                                r = grdrm_plane_resync(plane_from_object(object));
-                                break;
-                        default:
-                                assert_not_reached("grdrm: invalid object type");
-                                r = 0;
-                        }
-
-                        if (r < 0)
-                                return r;
-
-                        if (card->async_hotplug)
-                                break;
-                }
-
-                /* if modeset objects change during sync, start over */
-                if (card->async_hotplug) {
-                        card->async_hotplug = false;
-                        continue;
-                }
-
-                /* cache crtc/connector relationship */
-                HASHMAP_FOREACH(object, card->object_map, iter) {
-                        grdrm_connector *connector;
-                        grdrm_encoder *encoder;
-                        grdrm_crtc *crtc;
-
-                        if (object->type != GRDRM_TYPE_CONNECTOR)
-                                continue;
-
-                        connector = connector_from_object(object);
-                        if (connector->kern.connection != 1 || connector->kern.used_encoder < 1)
-                                continue;
-
-                        object = grdrm_find_object(card, connector->kern.used_encoder);
-                        if (!object || object->type != GRDRM_TYPE_ENCODER)
-                                continue;
-
-                        encoder = encoder_from_object(object);
-                        if (encoder->kern.used_crtc < 1)
-                                continue;
-
-                        object = grdrm_find_object(card, encoder->kern.used_crtc);
-                        if (!object || object->type != GRDRM_TYPE_CRTC)
-                                continue;
-
-                        crtc = crtc_from_object(object);
-                        assert(crtc->kern.n_used_connectors < crtc->kern.max_used_connectors);
-                        crtc->kern.used_connectors[crtc->kern.n_used_connectors++] = connector->object.id;
-                }
-
-                /* cache old crtc settings for later restore */
-                HASHMAP_FOREACH(object, card->object_map, iter) {
-                        grdrm_crtc *crtc;
-
-                        if (object->type != GRDRM_TYPE_CRTC)
-                                continue;
-
-                        crtc = crtc_from_object(object);
-
-                        /* Save data if it is the first time we refresh the CRTC. This data can
-                         * be used optionally to restore any previous configuration. For
-                         * instance, it allows us to restore VT configurations after we close
-                         * our session again. */
-                        if (!crtc->old.set) {
-                                crtc->old.fb = crtc->kern.used_fb;
-                                crtc->old.fb_x = crtc->kern.fb_offset_x;
-                                crtc->old.fb_y = crtc->kern.fb_offset_y;
-                                crtc->old.gamma = crtc->kern.gamma_size;
-                                crtc->old.n_connectors = crtc->kern.n_used_connectors;
-                                if (crtc->old.n_connectors)
-                                        memcpy(crtc->old.connectors, crtc->kern.used_connectors, sizeof(uint32_t) * crtc->old.n_connectors);
-                                crtc->old.mode_set = crtc->kern.mode_set;
-                                crtc->old.mode = crtc->kern.mode;
-                                crtc->old.set = true;
-                        }
-                }
-
-                /* everything synced */
-                break;
-        }
-
-        if (tries >= GRDRM_MAX_TRIES) {
-                /*
-                 * Ugh! We were unable to sync the DRM card state due to heavy
-                 * hotplugging. This should never happen, so print a debug
-                 * message and bail out. The next uevent will trigger
-                 * this again.
-                 */
-
-                log_debug("grdrm: %s: hotplug-storm when syncing card", card->base.name);
-                return -EFAULT;
-        }
-
-        return 0;
-}
-
-static bool card_configure_crtc(grdrm_crtc *crtc, grdrm_connector *connector) {
-        grdrm_card *card = crtc->object.card;
-        grdrm_encoder *encoder;
-        grdrm_object *object;
-        uint32_t i, j;
-
-        if (crtc->object.assigned || connector->object.assigned)
-                return false;
-        if (connector->kern.connection != 1)
-                return false;
-
-        for (i = 0; i < connector->kern.n_encoders; ++i) {
-                object = grdrm_find_object(card, connector->kern.encoders[i]);
-                if (!object || object->type != GRDRM_TYPE_ENCODER)
-                        continue;
-
-                encoder = encoder_from_object(object);
-                for (j = 0; j < encoder->kern.n_crtcs; ++j) {
-                        if (encoder->kern.crtcs[j] == crtc->object.id) {
-                                grdrm_crtc_assign(crtc, connector);
-                                return true;
-                        }
-                }
-        }
-
-        return false;
-}
-
-static void grdrm_card_configure(grdrm_card *card) {
-        /*
-         * Modeset Configuration
-         * This is where we update our modeset configuration and assign
-         * connectors to CRTCs. This means, each connector that we want to
-         * enable needs a CRTC, disabled (or unavailable) connectors are left
-         * alone in the dark. Once all CRTCs are assigned, the remaining CRTCs
-         * are disabled.
-         * Sounds trivial, but there're several caveats:
-         *
-         *   * Multiple connectors can be driven by the same CRTC. This is
-         *     known as 'hardware clone mode'. Advantage over software clone
-         *     mode is that only a single CRTC is needed to drive multiple
-         *     displays. However, few hardware supports this and it's a huge
-         *     headache to configure on dynamic demands. Therefore, we only
-         *     support it if configured statically beforehand.
-         *
-         *   * CRTCs are not created equal. Some might be much more powerful
-         *     than others, including more advanced plane support. So far, our
-         *     CRTC selection is random. You need to supply static
-         *     configuration if you want special setups. So far, there is no
-         *     proper way to do advanced CRTC selection on dynamic demands. It
-         *     is not really clear which demands require what CRTC, so, like
-         *     everyone else, we do random CRTC selection unless explicitly
-         *     states otherwise.
-         *
-         *   * Each Connector has a list of possible encoders that can drive
-         *     it, and each encoder has a list of possible CRTCs. If this graph
-         *     is a tree, assignment is trivial. However, if not, we cannot
-         *     reliably decide on configurations beforehand. The encoder is
-         *     always selected by the kernel, so we have to actually set a mode
-         *     to know which encoder is used. There is no way to ask the kernel
-         *     whether a given configuration is possible. This will change with
-         *     atomic-modesetting, but until then, we keep our configurations
-         *     simple and assume they work all just fine. If one fails
-         *     unexpectedly, we print a warning and disable it.
-         *
-         * Configuring a card consists of several steps:
-         *
-         *  1) First of all, we apply any user-configuration. If a user wants
-         *     a fixed configuration, we apply it and preserve it.
-         *     So far, we don't support user configuration files, so this step
-         *     is skipped.
-         *
-         *  2) Secondly, we need to apply any quirks from hwdb. Some hardware
-         *     might only support limited configurations or require special
-         *     CRTC/Connector mappings. We read this from hwdb and apply it, if
-         *     present.
-         *     So far, we don't support this as there is no known quirk, so
-         *     this step is skipped.
-         *
-         *  3) As deep modesets are expensive, we try to avoid them if
-         *     possible. Therefore, we read the current configuration from the
-         *     kernel and try to preserve it, if compatible with our demands.
-         *     If not, we break it and reassign it in a following step.
-         *
-         *  4) The main step involves configuring all remaining objects. By
-         *     default, all available connectors are enabled, except for those
-         *     disabled by user-configuration. We lookup a suitable CRTC for
-         *     each connector and assign them. As there might be more
-         *     connectors than CRTCs, we apply some ordering so users can
-         *     select which connectors are more important right now.
-         *     So far, we only apply the default ordering, more might be added
-         *     in the future.
-         */
-
-        grdrm_object *object;
-        grdrm_crtc *crtc;
-        Iterator i, j;
-
-        /* clear assignments */
-        HASHMAP_FOREACH(object, card->object_map, i)
-                object->assigned = false;
-
-        /* preserve existing configurations */
-        HASHMAP_FOREACH(object, card->object_map, i) {
-                if (object->type != GRDRM_TYPE_CRTC || object->assigned)
-                        continue;
-
-                crtc = crtc_from_object(object);
-
-                if (crtc->applied) {
-                        /* If our mode is set, preserve it. If no connector is
-                         * set, modeset either failed or the pipe is unused. In
-                         * both cases, leave it alone. It might be tried again
-                         * below in case there're remaining connectors.
-                         * Otherwise, try restoring the assignments. If they
-                         * are no longer valid, leave the pipe untouched. */
-
-                        if (crtc->set.n_connectors < 1)
-                                continue;
-
-                        assert(crtc->set.n_connectors == 1);
-
-                        object = grdrm_find_object(card, crtc->set.connectors[0]);
-                        if (!object || object->type != GRDRM_TYPE_CONNECTOR)
-                                continue;
-
-                        card_configure_crtc(crtc, connector_from_object(object));
-                } else if (crtc->kern.mode_set && crtc->kern.n_used_connectors != 1) {
-                        /* If our mode is not set on the pipe, we know the kern
-                         * information is valid. Try keeping it. If it's not
-                         * possible, leave the pipe untouched for later
-                         * assignements. */
-
-                        object = grdrm_find_object(card, crtc->kern.used_connectors[0]);
-                        if (!object || object->type != GRDRM_TYPE_CONNECTOR)
-                                continue;
-
-                        card_configure_crtc(crtc, connector_from_object(object));
-                }
-        }
-
-        /* assign remaining objects */
-        HASHMAP_FOREACH(object, card->object_map, i) {
-                if (object->type != GRDRM_TYPE_CRTC || object->assigned)
-                        continue;
-
-                crtc = crtc_from_object(object);
-
-                HASHMAP_FOREACH(object, card->object_map, j) {
-                        if (object->type != GRDRM_TYPE_CONNECTOR)
-                                continue;
-
-                        if (card_configure_crtc(crtc, connector_from_object(object)))
-                                break;
-                }
-
-                if (!crtc->object.assigned)
-                        grdrm_crtc_assign(crtc, NULL);
-        }
-
-        /* expose configuration */
-        HASHMAP_FOREACH(object, card->object_map, i) {
-                if (object->type != GRDRM_TYPE_CRTC)
-                        continue;
-
-                grdrm_crtc_expose(crtc_from_object(object));
-        }
-}
-
-static void grdrm_card_hotplug(grdrm_card *card) {
-        int r;
-
-        assert(card);
-
-        if (!card->running)
-                return;
-
-        log_debug("grdrm: %s/%s: reconfigure card", card->base.session->name, card->base.name);
-
-        card->ready = false;
-        r = grdrm_card_resync(card);
-        if (r < 0) {
-                log_debug_errno(r, "grdrm: %s/%s: cannot re-sync card: %m",
-                                card->base.session->name, card->base.name);
-                return;
-        }
-
-        grdev_session_pin(card->base.session);
-
-        /* debug statement to print card information */
-        if (0)
-                grdrm_card_print(card);
-
-        grdrm_card_configure(card);
-        card->ready = true;
-        card->hotplug = false;
-
-        grdev_session_unpin(card->base.session);
-}
-
-static int grdrm_card_io_fn(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-        grdrm_card *card = userdata;
-        struct drm_event_vblank *vblank;
-        struct drm_event *event;
-        uint32_t id, counter;
-        grdrm_object *object;
-        char buf[4096];
-        size_t len;
-        ssize_t l;
-
-        if (revents & (EPOLLHUP | EPOLLERR)) {
-                /* Immediately close device on HUP; no need to flush pending
-                 * data.. there're no events we care about here. */
-                log_debug("grdrm: %s/%s: HUP", card->base.session->name, card->base.name);
-                grdrm_card_close(card);
-                return 0;
-        }
-
-        if (revents & (EPOLLIN)) {
-                l = read(card->fd, buf, sizeof(buf));
-                if (l < 0) {
-                        if (errno == EAGAIN || errno == EINTR)
-                                return 0;
-
-                        log_debug_errno(errno, "grdrm: %s/%s: read error: %m",
-                                        card->base.session->name, card->base.name);
-                        grdrm_card_close(card);
-                        return 0;
-                }
-
-                for (len = l; len > 0; len -= event->length) {
-                        event = (void*)buf;
-
-                        if (len < sizeof(*event) || len < event->length) {
-                                log_debug("grdrm: %s/%s: truncated event",
-                                          card->base.session->name, card->base.name);
-                                break;
-                        }
-
-                        switch (event->type) {
-                        case DRM_EVENT_FLIP_COMPLETE:
-                                vblank = (void*)event;
-                                if (event->length < sizeof(*vblank)) {
-                                        log_debug("grdrm: %s/%s: truncated vblank event",
-                                                  card->base.session->name, card->base.name);
-                                        break;
-                                }
-
-                                grdrm_decode_vblank_data(vblank->user_data, &id, &counter);
-                                object = grdrm_find_object(card, id);
-                                if (!object || object->type != GRDRM_TYPE_CRTC)
-                                        break;
-
-                                grdrm_crtc_flip_complete(crtc_from_object(object), counter, vblank);
-                                break;
-                        }
-                }
-        }
-
-        return 0;
-}
-
-static int grdrm_card_add(grdrm_card *card, const char *name) {
-        assert(card);
-        assert(card->fd < 0);
-
-        card->object_map = hashmap_new(&trivial_hash_ops);
-        if (!card->object_map)
-                return -ENOMEM;
-
-        return grdev_card_add(&card->base, name);
-}
-
-static void grdrm_card_destroy(grdrm_card *card) {
-        assert(card);
-        assert(!card->running);
-        assert(card->fd < 0);
-        assert(hashmap_size(card->object_map) == 0);
-
-        hashmap_free(card->object_map);
-}
-
-static void grdrm_card_commit(grdev_card *basecard) {
-        grdrm_card *card = grdrm_card_from_base(basecard);
-        grdrm_object *object;
-        Iterator iter;
-
-        HASHMAP_FOREACH(object, card->object_map, iter) {
-                if (!card->ready)
-                        break;
-
-                if (object->type != GRDRM_TYPE_CRTC)
-                        continue;
-
-                grdrm_crtc_commit(crtc_from_object(object));
-        }
-}
-
-static void grdrm_card_restore(grdev_card *basecard) {
-        grdrm_card *card = grdrm_card_from_base(basecard);
-        grdrm_object *object;
-        Iterator iter;
-
-        HASHMAP_FOREACH(object, card->object_map, iter) {
-                if (!card->ready)
-                        break;
-
-                if (object->type != GRDRM_TYPE_CRTC)
-                        continue;
-
-                grdrm_crtc_restore(crtc_from_object(object));
-        }
-}
-
-static void grdrm_card_enable(grdrm_card *card) {
-        assert(card);
-
-        if (card->fd < 0 || card->running)
-                return;
-
-        /* ignore cards without DUMB_BUFFER capability */
-        if (!card->cap_dumb)
-                return;
-
-        assert(card->fd_src);
-
-        log_debug("grdrm: %s/%s: enable", card->base.session->name, card->base.name);
-
-        card->running = true;
-        sd_event_source_set_enabled(card->fd_src, SD_EVENT_ON);
-        grdrm_card_hotplug(card);
-}
-
-static void grdrm_card_disable(grdrm_card *card) {
-        grdrm_object *object;
-        Iterator iter;
-
-        assert(card);
-
-        if (card->fd < 0 || !card->running)
-                return;
-
-        assert(card->fd_src);
-
-        log_debug("grdrm: %s/%s: disable", card->base.session->name, card->base.name);
-
-        card->running = false;
-        card->ready = false;
-        sd_event_source_set_enabled(card->fd_src, SD_EVENT_OFF);
-
-        /* stop all pipes */
-        HASHMAP_FOREACH(object, card->object_map, iter) {
-                grdrm_crtc *crtc;
-
-                if (object->type != GRDRM_TYPE_CRTC)
-                        continue;
-
-                crtc = crtc_from_object(object);
-                crtc->applied = false;
-                if (crtc->pipe)
-                        grdev_pipe_ready(&crtc->pipe->base, false);
-        }
-}
-
-static int grdrm_card_open(grdrm_card *card, int dev_fd) {
-        _cleanup_(grdev_session_unpinp) grdev_session *pin = NULL;
-        _cleanup_close_ int fd = dev_fd;
-        struct drm_get_cap cap;
-        int r, flags;
-
-        assert(card);
-        assert(dev_fd >= 0);
-        assert(card->fd != dev_fd);
-
-        pin = grdev_session_pin(card->base.session);
-        grdrm_card_close(card);
-
-        log_debug("grdrm: %s/%s: open", card->base.session->name, card->base.name);
-
-        r = fd_nonblock(fd, true);
-        if (r < 0)
-                return r;
-
-        r = fd_cloexec(fd, true);
-        if (r < 0)
-                return r;
-
-        flags = fcntl(fd, F_GETFL, 0);
-        if (flags < 0)
-                return -errno;
-        if ((flags & O_ACCMODE) != O_RDWR)
-                return -EACCES;
-
-        r = sd_event_add_io(card->base.session->context->event,
-                            &card->fd_src,
-                            fd,
-                            EPOLLHUP | EPOLLERR | EPOLLIN,
-                            grdrm_card_io_fn,
-                            card);
-        if (r < 0)
-                return r;
-
-        sd_event_source_set_enabled(card->fd_src, SD_EVENT_OFF);
-
-        card->hotplug = true;
-        card->fd = fd;
-        fd = -1;
-
-        /* cache DUMB_BUFFER capability */
-        cap.capability = DRM_CAP_DUMB_BUFFER;
-        cap.value = 0;
-        r = ioctl(card->fd, DRM_IOCTL_GET_CAP, &cap);
-        card->cap_dumb = r >= 0 && cap.value;
-        if (r < 0)
-                log_debug_errno(r, "grdrm: %s/%s: cannot retrieve DUMB_BUFFER capability: %m",
-                                card->base.session->name, card->base.name);
-        else if (!card->cap_dumb)
-                log_debug("grdrm: %s/%s: DUMB_BUFFER capability not supported",
-                          card->base.session->name, card->base.name);
-
-        /* cache TIMESTAMP_MONOTONIC capability */
-        cap.capability = DRM_CAP_TIMESTAMP_MONOTONIC;
-        cap.value = 0;
-        r = ioctl(card->fd, DRM_IOCTL_GET_CAP, &cap);
-        card->cap_monotonic = r >= 0 && cap.value;
-        if (r < 0)
-                log_debug_errno(r, "grdrm: %s/%s: cannot retrieve TIMESTAMP_MONOTONIC capability: %m",
-                                card->base.session->name, card->base.name);
-        else if (!card->cap_monotonic)
-                log_debug("grdrm: %s/%s: TIMESTAMP_MONOTONIC is disabled globally, fix this NOW!",
-                          card->base.session->name, card->base.name);
-
-        return 0;
-}
-
-static void grdrm_card_close(grdrm_card *card) {
-        grdrm_object *object;
-
-        if (card->fd < 0)
-                return;
-
-        log_debug("grdrm: %s/%s: close", card->base.session->name, card->base.name);
-
-        grdrm_card_disable(card);
-
-        card->fd_src = sd_event_source_unref(card->fd_src);
-        card->fd = safe_close(card->fd);
-
-        grdev_session_pin(card->base.session);
-        while ((object = hashmap_first(card->object_map)))
-                grdrm_object_free(object);
-        grdev_session_unpin(card->base.session);
-}
-
-static bool grdrm_card_async(grdrm_card *card, int r) {
-        switch (r) {
-        case -EACCES:
-                /* If we get EACCES on runtime DRM calls, we lost DRM-Master
-                 * (or we did something terribly wrong). Immediately disable
-                 * the card, so we stop all pipes and wait to be activated
-                 * again. */
-                grdrm_card_disable(card);
-                break;
-        case -ENOENT:
-                /* DRM objects can be hotplugged at any time. If an object is
-                 * removed that we use, we remember that state so a following
-                 * call can test for this.
-                 * Note that we also get a uevent as followup, this will resync
-                 * the whole device. */
-                card->async_hotplug = true;
-                break;
-        }
-
-        return !card->ready;
-}
-
-/*
- * Unmanaged Cards
- * The unmanaged DRM card opens the device node for a given DRM device
- * directly (/dev/dri/cardX) and thus needs sufficient privileges. It opens
- * the device only if we really require it and releases it as soon as we're
- * disabled or closed.
- * The unmanaged element can be used in all situations where you have direct
- * access to DRM device nodes. Unlike managed DRM elements, it can be used
- * outside of user sessions and in emergency situations where logind is not
- * available.
- */
-
-static void unmanaged_card_enable(grdev_card *basecard) {
-        unmanaged_card *cu = unmanaged_card_from_base(basecard);
-        int r, fd;
-
-        if (cu->card.fd < 0) {
-                /* try open on activation if it failed during allocation */
-                fd = open(cu->devnode, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK);
-                if (fd < 0) {
-                        /* not fatal; simply ignore the device */
-                        log_debug_errno(errno, "grdrm: %s/%s: cannot open node %s: %m",
-                                        basecard->session->name, basecard->name, cu->devnode);
-                        return;
-                }
-
-                /* we might already be DRM-Master by open(); that's fine */
-
-                r = grdrm_card_open(&cu->card, fd);
-                if (r < 0) {
-                        log_debug_errno(r, "grdrm: %s/%s: cannot open: %m",
-                                        basecard->session->name, basecard->name);
-                        return;
-                }
-        }
-
-        r = ioctl(cu->card.fd, DRM_IOCTL_SET_MASTER, 0);
-        if (r < 0) {
-                log_debug_errno(errno, "grdrm: %s/%s: cannot acquire DRM-Master: %m",
-                                basecard->session->name, basecard->name);
-                return;
-        }
-
-        grdrm_card_enable(&cu->card);
-}
-
-static void unmanaged_card_disable(grdev_card *basecard) {
-        unmanaged_card *cu = unmanaged_card_from_base(basecard);
-
-        grdrm_card_disable(&cu->card);
-}
-
-static int unmanaged_card_new(grdev_card **out, grdev_session *session, struct udev_device *ud) {
-        _cleanup_(grdev_card_freep) grdev_card *basecard = NULL;
-        char name[GRDRM_CARD_NAME_MAX];
-        unmanaged_card *cu;
-        const char *devnode;
-        dev_t devnum;
-        int r, fd;
-
-        assert_return(session, -EINVAL);
-        assert_return(ud, -EINVAL);
-
-        devnode = udev_device_get_devnode(ud);
-        devnum = udev_device_get_devnum(ud);
-        if (!devnode || devnum == 0)
-                return -ENODEV;
-
-        grdrm_name(name, devnum);
-
-        cu = new0(unmanaged_card, 1);
-        if (!cu)
-                return -ENOMEM;
-
-        basecard = &cu->card.base;
-        cu->card = GRDRM_CARD_INIT(&unmanaged_card_vtable, session);
-
-        cu->devnode = strdup(devnode);
-        if (!cu->devnode)
-                return -ENOMEM;
-
-        r = grdrm_card_add(&cu->card, name);
-        if (r < 0)
-                return r;
-
-        /* try to open but ignore errors */
-        fd = open(cu->devnode, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK);
-        if (fd < 0) {
-                /* not fatal; allow uaccess based control on activation */
-                log_debug_errno(errno, "grdrm: %s/%s: cannot open node %s: %m",
-                                basecard->session->name, basecard->name, cu->devnode);
-        } else {
-                /* We might get DRM-Master implicitly on open(); drop it immediately
-                 * so we acquire it only once we're actually enabled. We don't
-                 * really care whether this call fails or not, but lets log any
-                 * weird errors, anyway. */
-                r = ioctl(fd, DRM_IOCTL_DROP_MASTER, 0);
-                if (r < 0 && errno != EACCES && errno != EINVAL)
-                        log_debug_errno(errno, "grdrm: %s/%s: cannot drop DRM-Master: %m",
-                                        basecard->session->name, basecard->name);
-
-                r = grdrm_card_open(&cu->card, fd);
-                if (r < 0)
-                        log_debug_errno(r, "grdrm: %s/%s: cannot open: %m",
-                                        basecard->session->name, basecard->name);
-        }
-
-        if (out)
-                *out = basecard;
-        basecard = NULL;
-        return 0;
-}
-
-static void unmanaged_card_free(grdev_card *basecard) {
-        unmanaged_card *cu = unmanaged_card_from_base(basecard);
-
-        assert(!basecard->enabled);
-
-        grdrm_card_close(&cu->card);
-        grdrm_card_destroy(&cu->card);
-        free(cu->devnode);
-        free(cu);
-}
-
-static const grdev_card_vtable unmanaged_card_vtable = {
-        .free                   = unmanaged_card_free,
-        .enable                 = unmanaged_card_enable,
-        .disable                = unmanaged_card_disable,
-        .commit                 = grdrm_card_commit,
-        .restore                = grdrm_card_restore,
-};
-
-/*
- * Managed Cards
- * The managed DRM card uses systemd-logind to acquire DRM devices. This
- * means, we do not open the device node /dev/dri/cardX directly. Instead,
- * logind passes us a file-descriptor whenever our session is activated. Thus,
- * we don't need access to the device node directly.
- * Furthermore, whenever the session is put asleep, logind revokes the
- * file-descriptor so we loose access to the device.
- * Managed DRM cards should be preferred over unmanaged DRM cards whenever
- * you run inside a user session with exclusive device access.
- */
-
-static void managed_card_enable(grdev_card *card) {
-        managed_card *cm = managed_card_from_base(card);
-
-        /* If the device is manually re-enabled, we try to resume our card
-         * management. Note that we have no control over DRM-Master and the fd,
-         * so we have to take over the state from the last logind event. */
-
-        if (cm->master)
-                grdrm_card_enable(&cm->card);
-}
-
-static void managed_card_disable(grdev_card *card) {
-        managed_card *cm = managed_card_from_base(card);
-
-        /* If the device is manually disabled, we keep the FD but put our card
-         * management asleep. This way, we can wake up at any time, but don't
-         * touch the device while asleep. */
-
-        grdrm_card_disable(&cm->card);
-}
-
-static int managed_card_pause_device_fn(sd_bus *bus,
-                                        sd_bus_message *signal,
-                                        void *userdata,
-                                        sd_bus_error *ret_error) {
-        managed_card *cm = userdata;
-        grdev_session *session = cm->card.base.session;
-        uint32_t major, minor;
-        const char *mode;
-        int r;
-
-        /*
-         * We get PauseDevice() signals from logind whenever a device we
-         * requested was, or is about to be, paused. Arguments are major/minor
-         * number of the device and the mode of the operation.
-         * In case the event is not about our device, we ignore it. Otherwise,
-         * we treat it as asynchronous DRM-DROP-MASTER. Note that we might have
-         * already handled an EACCES error from a modeset ioctl, in which case
-         * we already disabled the device.
-         *
-         * @mode can be one of the following:
-         *   "pause": The device is about to be paused. We must react
-         *            immediately and respond with PauseDeviceComplete(). Once
-         *            we replied, logind will pause the device. Note that
-         *            logind might apply any kind of timeout and force pause
-         *            the device if we don't respond in a timely manner. In
-         *            this case, we will receive a second PauseDevice event
-         *            with @mode set to "force" (or similar).
-         *   "force": The device was disabled forecfully by logind. DRM-Master
-         *            was already dropped. This is just an asynchronous
-         *            notification so we can put the device asleep (in case
-         *            we didn't already notice the dropped DRM-Master).
-         *    "gone": This is like "force" but is sent if the device was
-         *            paused due to a device-removal event.
-         *
-         * We always handle PauseDevice signals as "force" as we properly
-         * support asynchronously dropping DRM-Master, anyway. But in case
-         * logind sent mode "pause", we also call PauseDeviceComplete() to
-         * immediately acknowledge the request.
-         */
-
-        r = sd_bus_message_read(signal, "uus", &major, &minor, &mode);
-        if (r < 0) {
-                log_debug("grdrm: %s/%s: erroneous PauseDevice signal",
-                          session->name, cm->card.base.name);
-                return 0;
-        }
-
-        /* not our device? */
-        if (makedev(major, minor) != cm->devnum)
-                return 0;
-
-        cm->master = false;
-        grdrm_card_disable(&cm->card);
-
-        if (streq(mode, "pause")) {
-                _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-
-                /*
-                 * Sending PauseDeviceComplete() is racy if logind triggers the
-                 * timeout. That is, if we take too long and logind pauses the
-                 * device by sending a forced PauseDevice, our
-                 * PauseDeviceComplete call will be stray. That's fine, though.
-                 * logind ignores such stray calls. Only if logind also sent a
-                 * further PauseDevice() signal, it might match our call
-                 * incorrectly to the newer PauseDevice(). That's fine, too, as
-                 * we handle that event asynchronously, anyway. Therefore,
-                 * whatever happens, we're fine. Yay!
-                 */
-
-                r = sd_bus_message_new_method_call(session->context->sysbus,
-                                                   &m,
-                                                   "org.freedesktop.login1",
-                                                   session->path,
-                                                   "org.freedesktop.login1.Session",
-                                                   "PauseDeviceComplete");
-                if (r >= 0) {
-                        r = sd_bus_message_append(m, "uu", major, minor);
-                        if (r >= 0)
-                                r = sd_bus_send(session->context->sysbus, m, NULL);
-                }
-
-                if (r < 0)
-                        log_debug_errno(r, "grdrm: %s/%s: cannot send PauseDeviceComplete: %m",
-                                        session->name, cm->card.base.name);
-        }
-
-        return 0;
-}
-
-static int managed_card_resume_device_fn(sd_bus *bus,
-                                         sd_bus_message *signal,
-                                         void *userdata,
-                                         sd_bus_error *ret_error) {
-        managed_card *cm = userdata;
-        grdev_session *session = cm->card.base.session;
-        uint32_t major, minor;
-        int r, fd;
-
-        /*
-         * We get ResumeDevice signals whenever logind resumed a previously
-         * paused device. The arguments contain the major/minor number of the
-         * related device and a new file-descriptor for the freshly opened
-         * device-node.
-         * If the signal is not about our device, we simply ignore it.
-         * Otherwise, we immediately resume the device. Note that we drop the
-         * new file-descriptor as we already have one from TakeDevice(). logind
-         * preserves the file-context across pause/resume for DRM but only
-         * drops/acquires DRM-Master accordingly. This way, our context (like
-         * DRM-FBs and BOs) is preserved.
-         */
-
-        r = sd_bus_message_read(signal, "uuh", &major, &minor, &fd);
-        if (r < 0) {
-                log_debug("grdrm: %s/%s: erroneous ResumeDevice signal",
-                          session->name, cm->card.base.name);
-                return 0;
-        }
-
-        /* not our device? */
-        if (makedev(major, minor) != cm->devnum)
-                return 0;
-
-        if (cm->card.fd < 0) {
-                /* This shouldn't happen. We should already own an FD from
-                 * TakeDevice(). However, lets be safe and use this FD in case
-                 * we really don't have one. There is no harm in doing this
-                 * and our code works fine this way. */
-                fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
-                if (fd < 0) {
-                        log_debug_errno(errno, "grdrm: %s/%s: cannot duplicate fd: %m",
-                                        session->name, cm->card.base.name);
-                        return 0;
-                }
-
-                r = grdrm_card_open(&cm->card, fd);
-                if (r < 0) {
-                        log_debug_errno(r, "grdrm: %s/%s: cannot open: %m",
-                                        session->name, cm->card.base.name);
-                        return 0;
-                }
-        }
-
-        cm->master = true;
-        if (cm->card.base.enabled)
-                grdrm_card_enable(&cm->card);
-
-        return 0;
-}
-
-static int managed_card_setup_bus(managed_card *cm) {
-        grdev_session *session = cm->card.base.session;
-        _cleanup_free_ char *match = NULL;
-        int r;
-
-        match = strjoin("type='signal',"
-                        "sender='org.freedesktop.login1',"
-                        "interface='org.freedesktop.login1.Session',"
-                        "member='PauseDevice',"
-                        "path='", session->path, "'",
-                        NULL);
-        if (!match)
-                return -ENOMEM;
-
-        r = sd_bus_add_match(session->context->sysbus,
-                             &cm->slot_pause_device,
-                             match,
-                             managed_card_pause_device_fn,
-                             cm);
-        if (r < 0)
-                return r;
-
-        free(match);
-        match = strjoin("type='signal',"
-                        "sender='org.freedesktop.login1',"
-                        "interface='org.freedesktop.login1.Session',"
-                        "member='ResumeDevice',"
-                        "path='", session->path, "'",
-                        NULL);
-        if (!match)
-                return -ENOMEM;
-
-        r = sd_bus_add_match(session->context->sysbus,
-                             &cm->slot_resume_device,
-                             match,
-                             managed_card_resume_device_fn,
-                             cm);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-static int managed_card_take_device_fn(sd_bus *bus,
-                                       sd_bus_message *reply,
-                                       void *userdata,
-                                       sd_bus_error *ret_error) {
-        managed_card *cm = userdata;
-        grdev_session *session = cm->card.base.session;
-        int r, paused, fd;
-
-        cm->slot_take_device = sd_bus_slot_unref(cm->slot_take_device);
-
-        if (sd_bus_message_is_method_error(reply, NULL)) {
-                const sd_bus_error *error = sd_bus_message_get_error(reply);
-
-                log_debug("grdrm: %s/%s: TakeDevice failed: %s: %s",
-                          session->name, cm->card.base.name, error->name, error->message);
-                return 0;
-        }
-
-        cm->acquired = true;
-
-        r = sd_bus_message_read(reply, "hb", &fd, &paused);
-        if (r < 0) {
-                log_debug("grdrm: %s/%s: erroneous TakeDevice reply",
-                          session->name, cm->card.base.name);
-                return 0;
-        }
-
-        fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
-        if (fd < 0) {
-                log_debug_errno(errno, "grdrm: %s/%s: cannot duplicate fd: %m",
-                                session->name, cm->card.base.name);
-                return 0;
-        }
-
-        r = grdrm_card_open(&cm->card, fd);
-        if (r < 0) {
-                log_debug_errno(r, "grdrm: %s/%s: cannot open: %m",
-                                session->name, cm->card.base.name);
-                return 0;
-        }
-
-        if (!paused && cm->card.base.enabled)
-                grdrm_card_enable(&cm->card);
-
-        return 0;
-}
-
-static void managed_card_take_device(managed_card *cm) {
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        grdev_session *session = cm->card.base.session;
-        int r;
-
-        r = sd_bus_message_new_method_call(session->context->sysbus,
-                                           &m,
-                                           "org.freedesktop.login1",
-                                           session->path,
-                                           "org.freedesktop.login1.Session",
-                                           "TakeDevice");
-        if (r < 0)
-                goto error;
-
-        r = sd_bus_message_append(m, "uu", major(cm->devnum), minor(cm->devnum));
-        if (r < 0)
-                goto error;
-
-        r = sd_bus_call_async(session->context->sysbus,
-                              &cm->slot_take_device,
-                              m,
-                              managed_card_take_device_fn,
-                              cm,
-                              0);
-        if (r < 0)
-                goto error;
-
-        cm->requested = true;
-        return;
-
-error:
-        log_debug_errno(r, "grdrm: %s/%s: cannot send TakeDevice request: %m",
-                        session->name, cm->card.base.name);
-}
-
-static void managed_card_release_device(managed_card *cm) {
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        grdev_session *session = cm->card.base.session;
-        int r;
-
-        /*
-         * If TakeDevice() is pending or was successful, make sure to
-         * release the device again. We don't care for return-values,
-         * so send it without waiting or callbacks.
-         * If a failed TakeDevice() is pending, but someone else took
-         * the device on the same bus-connection, we might incorrectly
-         * release their device. This is an unlikely race, though.
-         * Furthermore, you really shouldn't have two users of the
-         * controller-API on the same session, on the same devices, *AND* on
-         * the same bus-connection. So we don't care for that race..
-         */
-
-        grdrm_card_close(&cm->card);
-        cm->requested = false;
-
-        if (!cm->acquired && !cm->slot_take_device)
-                return;
-
-        cm->slot_take_device = sd_bus_slot_unref(cm->slot_take_device);
-        cm->acquired = false;
-
-        r = sd_bus_message_new_method_call(session->context->sysbus,
-                                           &m,
-                                           "org.freedesktop.login1",
-                                           session->path,
-                                           "org.freedesktop.login1.Session",
-                                           "ReleaseDevice");
-        if (r >= 0) {
-                r = sd_bus_message_append(m, "uu", major(cm->devnum), minor(cm->devnum));
-                if (r >= 0)
-                        r = sd_bus_send(session->context->sysbus, m, NULL);
-        }
-
-        if (r < 0 && r != -ENOTCONN)
-                log_debug_errno(r, "grdrm: %s/%s: cannot send ReleaseDevice: %m",
-                                session->name, cm->card.base.name);
-}
-
-static int managed_card_new(grdev_card **out, grdev_session *session, struct udev_device *ud) {
-        _cleanup_(grdev_card_freep) grdev_card *basecard = NULL;
-        char name[GRDRM_CARD_NAME_MAX];
-        managed_card *cm;
-        dev_t devnum;
-        int r;
-
-        assert_return(session, -EINVAL);
-        assert_return(session->managed, -EINVAL);
-        assert_return(session->context->sysbus, -EINVAL);
-        assert_return(ud, -EINVAL);
-
-        devnum = udev_device_get_devnum(ud);
-        if (devnum == 0)
-                return -ENODEV;
-
-        grdrm_name(name, devnum);
-
-        cm = new0(managed_card, 1);
-        if (!cm)
-                return -ENOMEM;
-
-        basecard = &cm->card.base;
-        cm->card = GRDRM_CARD_INIT(&managed_card_vtable, session);
-        cm->devnum = devnum;
-
-        r = managed_card_setup_bus(cm);
-        if (r < 0)
-                return r;
-
-        r = grdrm_card_add(&cm->card, name);
-        if (r < 0)
-                return r;
-
-        managed_card_take_device(cm);
-
-        if (out)
-                *out = basecard;
-        basecard = NULL;
-        return 0;
-}
-
-static void managed_card_free(grdev_card *basecard) {
-        managed_card *cm = managed_card_from_base(basecard);
-
-        assert(!basecard->enabled);
-
-        managed_card_release_device(cm);
-        cm->slot_resume_device = sd_bus_slot_unref(cm->slot_resume_device);
-        cm->slot_pause_device = sd_bus_slot_unref(cm->slot_pause_device);
-        grdrm_card_destroy(&cm->card);
-        free(cm);
-}
-
-static const grdev_card_vtable managed_card_vtable = {
-        .free                   = managed_card_free,
-        .enable                 = managed_card_enable,
-        .disable                = managed_card_disable,
-        .commit                 = grdrm_card_commit,
-        .restore                = grdrm_card_restore,
-};
-
-/*
- * Generic Constructor
- * Instead of relying on the caller to choose between managed and unmanaged
- * DRM devices, the grdev_drm_new() constructor does that for you (by
- * looking at session->managed).
- */
-
-bool grdev_is_drm_card(grdev_card *basecard) {
-        return basecard && (basecard->vtable == &unmanaged_card_vtable ||
-                            basecard->vtable == &managed_card_vtable);
-}
-
-grdev_card *grdev_find_drm_card(grdev_session *session, dev_t devnum) {
-        char name[GRDRM_CARD_NAME_MAX];
-
-        assert_return(session, NULL);
-        assert_return(devnum != 0, NULL);
-
-        grdrm_name(name, devnum);
-        return grdev_find_card(session, name);
-}
-
-int grdev_drm_card_new(grdev_card **out, grdev_session *session, struct udev_device *ud) {
-        assert_return(session, -EINVAL);
-        assert_return(ud, -EINVAL);
-
-        return session->managed ? managed_card_new(out, session, ud) : unmanaged_card_new(out, session, ud);
-}
-
-void grdev_drm_card_hotplug(grdev_card *basecard, struct udev_device *ud) {
-        const char *p, *action;
-        grdrm_card *card;
-        dev_t devnum;
-
-        assert(basecard);
-        assert(grdev_is_drm_card(basecard));
-        assert(ud);
-
-        card = grdrm_card_from_base(basecard);
-
-        action = udev_device_get_action(ud);
-        if (!action || streq(action, "add") || streq(action, "remove")) {
-                /* If we get add/remove events on DRM nodes without devnum, we
-                 * got hotplugged DRM objects so refresh the device. */
-                devnum = udev_device_get_devnum(ud);
-                if (devnum == 0) {
-                        card->hotplug = true;
-                        grdrm_card_hotplug(card);
-                }
-        } else if (streq_ptr(action, "change")) {
-                /* A change event with HOTPLUG=1 is sent whenever a connector
-                 * changed state. Refresh the device to update our state. */
-                p = udev_device_get_property_value(ud, "HOTPLUG");
-                if (streq_ptr(p, "1")) {
-                        card->hotplug = true;
-                        grdrm_card_hotplug(card);
-                }
-        }
-}
diff --git a/src/libsystemd-terminal/grdev-internal.h b/src/libsystemd-terminal/grdev-internal.h
deleted file mode 100644 (file)
index f455dd4..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#pragma once
-
-#include <inttypes.h>
-#include <libudev.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <systemd/sd-bus.h>
-#include <systemd/sd-event.h>
-#include "grdev.h"
-#include "hashmap.h"
-#include "list.h"
-#include "util.h"
-
-typedef struct grdev_tile               grdev_tile;
-typedef struct grdev_display_cache      grdev_display_cache;
-
-typedef struct grdev_pipe_vtable        grdev_pipe_vtable;
-typedef struct grdev_pipe               grdev_pipe;
-typedef struct grdev_card_vtable        grdev_card_vtable;
-typedef struct grdev_card               grdev_card;
-
-/*
- * DRM cards
- */
-
-bool grdev_is_drm_card(grdev_card *card);
-grdev_card *grdev_find_drm_card(grdev_session *session, dev_t devnum);
-int grdev_drm_card_new(grdev_card **out, grdev_session *session, struct udev_device *ud);
-void grdev_drm_card_hotplug(grdev_card *card, struct udev_device *ud);
-
-/*
- * Displays
- */
-
-enum {
-        GRDEV_TILE_LEAF,
-        GRDEV_TILE_NODE,
-        GRDEV_TILE_CNT
-};
-
-struct grdev_tile {
-        LIST_FIELDS(grdev_tile, children_by_node);
-        grdev_tile *parent;
-        grdev_display *display;
-
-        uint32_t x;
-        uint32_t y;
-        unsigned int rotate;
-        unsigned int flip;
-        uint32_t cache_w;
-        uint32_t cache_h;
-
-        unsigned int type;
-
-        union {
-                struct {
-                        grdev_pipe *pipe;
-                } leaf;
-
-                struct {
-                        size_t n_children;
-                        LIST_HEAD(grdev_tile, child_list);
-                } node;
-        };
-};
-
-int grdev_tile_new_leaf(grdev_tile **out, grdev_pipe *pipe);
-int grdev_tile_new_node(grdev_tile **out);
-grdev_tile *grdev_tile_free(grdev_tile *tile);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(grdev_tile*, grdev_tile_free);
-
-struct grdev_display {
-        grdev_session *session;
-        char *name;
-        void *userdata;
-
-        size_t n_leafs;
-        grdev_tile *tile;
-
-        size_t n_pipes;
-        size_t max_pipes;
-
-        uint32_t width;
-        uint32_t height;
-
-        struct grdev_display_cache {
-                grdev_pipe *pipe;
-                grdev_display_target target;
-
-                bool incomplete : 1;
-        } *pipes;
-
-        bool enabled : 1;
-        bool public : 1;
-        bool modified : 1;
-        bool framed : 1;
-};
-
-grdev_display *grdev_find_display(grdev_session *session, const char *name);
-
-int grdev_display_new(grdev_display **out, grdev_session *session, const char *name);
-grdev_display *grdev_display_free(grdev_display *display);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(grdev_display*, grdev_display_free);
-
-/*
- * Pipes
- */
-
-struct grdev_pipe_vtable {
-        void (*free) (grdev_pipe *pipe);
-        void (*enable) (grdev_pipe *pipe);
-        void (*disable) (grdev_pipe *pipe);
-        grdev_fb *(*target) (grdev_pipe *pipe);
-};
-
-struct grdev_pipe {
-        const grdev_pipe_vtable *vtable;
-        grdev_card *card;
-        char *name;
-
-        grdev_tile *tile;
-        grdev_display_cache *cache;
-        sd_event_source *vsync_src;
-
-        uint32_t width;
-        uint32_t height;
-        uint32_t vrefresh;
-
-        size_t max_fbs;
-        grdev_fb *front;
-        grdev_fb *back;
-        grdev_fb **fbs;
-
-        bool enabled : 1;
-        bool running : 1;
-        bool flip : 1;
-        bool flipping : 1;
-};
-
-#define GRDEV_PIPE_INIT(_vtable, _card) ((grdev_pipe){ \
-                .vtable = (_vtable), \
-                .card = (_card), \
-        })
-
-grdev_pipe *grdev_find_pipe(grdev_card *card, const char *name);
-
-int grdev_pipe_add(grdev_pipe *pipe, const char *name, size_t n_fbs);
-grdev_pipe *grdev_pipe_free(grdev_pipe *pipe);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(grdev_pipe*, grdev_pipe_free);
-
-void grdev_pipe_ready(grdev_pipe *pipe, bool running);
-void grdev_pipe_frame(grdev_pipe *pipe);
-void grdev_pipe_schedule(grdev_pipe *pipe, uint64_t frames);
-
-/*
- * Cards
- */
-
-struct grdev_card_vtable {
-        void (*free) (grdev_card *card);
-        void (*enable) (grdev_card *card);
-        void (*disable) (grdev_card *card);
-        void (*commit) (grdev_card *card);
-        void (*restore) (grdev_card *card);
-};
-
-struct grdev_card {
-        const grdev_card_vtable *vtable;
-        grdev_session *session;
-        char *name;
-
-        Hashmap *pipe_map;
-
-        bool enabled : 1;
-        bool modified : 1;
-};
-
-#define GRDEV_CARD_INIT(_vtable, _session) ((grdev_card){ \
-                .vtable = (_vtable), \
-                .session = (_session), \
-        })
-
-grdev_card *grdev_find_card(grdev_session *session, const char *name);
-
-int grdev_card_add(grdev_card *card, const char *name);
-grdev_card *grdev_card_free(grdev_card *card);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(grdev_card*, grdev_card_free);
-
-/*
- * Sessions
- */
-
-struct grdev_session {
-        grdev_context *context;
-        char *name;
-        char *path;
-        grdev_event_fn event_fn;
-        void *userdata;
-
-        unsigned long n_pins;
-
-        Hashmap *card_map;
-        Hashmap *display_map;
-
-        bool custom : 1;
-        bool managed : 1;
-        bool enabled : 1;
-        bool modified : 1;
-};
-
-grdev_session *grdev_session_pin(grdev_session *session);
-grdev_session *grdev_session_unpin(grdev_session *session);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(grdev_session*, grdev_session_unpin);
-
-/*
- * Contexts
- */
-
-struct grdev_context {
-        unsigned long ref;
-        sd_event *event;
-        sd_bus *sysbus;
-
-        Hashmap *session_map;
-};
diff --git a/src/libsystemd-terminal/grdev.c b/src/libsystemd-terminal/grdev.c
deleted file mode 100644 (file)
index feed579..0000000
+++ /dev/null
@@ -1,1359 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <libudev.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <systemd/sd-bus.h>
-#include <systemd/sd-event.h>
-#include "grdev.h"
-#include "grdev-internal.h"
-#include "hashmap.h"
-#include "login-shared.h"
-#include "macro.h"
-#include "util.h"
-
-static void pipe_enable(grdev_pipe *pipe);
-static void pipe_disable(grdev_pipe *pipe);
-static void card_modified(grdev_card *card);
-static void session_frame(grdev_session *session, grdev_display *display);
-
-/*
- * Displays
- */
-
-static inline grdev_tile *tile_leftmost(grdev_tile *tile) {
-        if (!tile)
-                return NULL;
-
-        while (tile->type == GRDEV_TILE_NODE && tile->node.child_list)
-                tile = tile->node.child_list;
-
-        return tile;
-}
-
-#define TILE_FOREACH(_root, _i) \
-        for (_i = tile_leftmost(_root); _i; _i = tile_leftmost(_i->children_by_node_next) ? : _i->parent)
-
-#define TILE_FOREACH_SAFE(_root, _i, _next) \
-        for (_i = tile_leftmost(_root); _i && ((_next = tile_leftmost(_i->children_by_node_next) ? : _i->parent), true); _i = _next)
-
-static void tile_link(grdev_tile *tile, grdev_tile *parent) {
-        grdev_display *display;
-        grdev_tile *t;
-
-        assert(tile);
-        assert(!tile->parent);
-        assert(!tile->display);
-        assert(parent);
-        assert(parent->type == GRDEV_TILE_NODE);
-
-        display = parent->display;
-
-        assert(!display || !display->enabled);
-
-        ++parent->node.n_children;
-        LIST_PREPEND(children_by_node, parent->node.child_list, tile);
-        tile->parent = parent;
-
-        if (display) {
-                display->modified = true;
-                TILE_FOREACH(tile, t) {
-                        t->display = display;
-                        if (t->type == GRDEV_TILE_LEAF) {
-                                ++display->n_leafs;
-                                if (display->enabled)
-                                        pipe_enable(t->leaf.pipe);
-                        }
-                }
-        }
-}
-
-static void tile_unlink(grdev_tile *tile) {
-        grdev_tile *parent, *t;
-        grdev_display *display;
-
-        assert(tile);
-
-        display = tile->display;
-        parent = tile->parent;
-        if (!parent) {
-                assert(!display);
-                return;
-        }
-
-        assert(parent->type == GRDEV_TILE_NODE);
-        assert(parent->display == display);
-        assert(parent->node.n_children > 0);
-
-        --parent->node.n_children;
-        LIST_REMOVE(children_by_node, parent->node.child_list, tile);
-        tile->parent = NULL;
-
-        if (display) {
-                display->modified = true;
-                TILE_FOREACH(tile, t) {
-                        t->display = NULL;
-                        if (t->type == GRDEV_TILE_LEAF) {
-                                --display->n_leafs;
-                                t->leaf.pipe->cache = NULL;
-                                pipe_disable(t->leaf.pipe);
-                        }
-                }
-        }
-
-        /* Tile trees are driven by leafs. Internal nodes have no owner, thus,
-         * we must take care to not leave them around. Therefore, whenever we
-         * unlink any part of a tree, we also destroy the parent, in case it's
-         * now stale.
-         * Parents are stale if they have no children and either have no display
-         * or if they are intermediate nodes (i.e, they have a parent).
-         * This means, you can easily create trees, but you can never partially
-         * move or destruct them so far. They're always reduced to minimal form
-         * if you cut them. This might change later, but so far we didn't need
-         * partial destruction or the ability to move whole trees. */
-
-        if (parent->node.n_children < 1 && (parent->parent || !parent->display))
-                grdev_tile_free(parent);
-}
-
-static int tile_new(grdev_tile **out) {
-        _cleanup_(grdev_tile_freep) grdev_tile *tile = NULL;
-
-        assert(out);
-
-        tile = new0(grdev_tile, 1);
-        if (!tile)
-                return -ENOMEM;
-
-        tile->type = (unsigned)-1;
-
-        *out = tile;
-        tile = NULL;
-        return 0;
-}
-
-int grdev_tile_new_leaf(grdev_tile **out, grdev_pipe *pipe) {
-        _cleanup_(grdev_tile_freep) grdev_tile *tile = NULL;
-        int r;
-
-        assert_return(out, -EINVAL);
-        assert_return(pipe, -EINVAL);
-        assert_return(!pipe->tile, -EINVAL);
-
-        r = tile_new(&tile);
-        if (r < 0)
-                return r;
-
-        tile->type = GRDEV_TILE_LEAF;
-        tile->leaf.pipe = pipe;
-
-        if (out)
-                *out = tile;
-        tile = NULL;
-        return 0;
-}
-
-int grdev_tile_new_node(grdev_tile **out) {
-        _cleanup_(grdev_tile_freep) grdev_tile *tile = NULL;
-        int r;
-
-        assert_return(out, -EINVAL);
-
-        r = tile_new(&tile);
-        if (r < 0)
-                return r;
-
-        tile->type = GRDEV_TILE_NODE;
-
-        *out = tile;
-        tile = NULL;
-        return 0;
-}
-
-grdev_tile *grdev_tile_free(grdev_tile *tile) {
-        if (!tile)
-                return NULL;
-
-        tile_unlink(tile);
-
-        switch (tile->type) {
-        case GRDEV_TILE_LEAF:
-                assert(!tile->parent);
-                assert(!tile->display);
-                assert(tile->leaf.pipe);
-
-                break;
-        case GRDEV_TILE_NODE:
-                assert(!tile->parent);
-                assert(!tile->display);
-                assert(tile->node.n_children == 0);
-
-                break;
-        }
-
-        free(tile);
-
-        return NULL;
-}
-
-grdev_display *grdev_find_display(grdev_session *session, const char *name) {
-        assert_return(session, NULL);
-        assert_return(name, NULL);
-
-        return hashmap_get(session->display_map, name);
-}
-
-int grdev_display_new(grdev_display **out, grdev_session *session, const char *name) {
-        _cleanup_(grdev_display_freep) grdev_display *display = NULL;
-        int r;
-
-        assert(session);
-        assert(name);
-
-        display = new0(grdev_display, 1);
-        if (!display)
-                return -ENOMEM;
-
-        display->session = session;
-
-        display->name = strdup(name);
-        if (!display->name)
-                return -ENOMEM;
-
-        r = grdev_tile_new_node(&display->tile);
-        if (r < 0)
-                return r;
-
-        display->tile->display = display;
-
-        r = hashmap_put(session->display_map, display->name, display);
-        if (r < 0)
-                return r;
-
-        if (out)
-                *out = display;
-        display = NULL;
-        return 0;
-}
-
-grdev_display *grdev_display_free(grdev_display *display) {
-        if (!display)
-                return NULL;
-
-        assert(!display->public);
-        assert(!display->enabled);
-        assert(!display->modified);
-        assert(display->n_leafs == 0);
-        assert(display->n_pipes == 0);
-
-        if (display->name)
-                hashmap_remove_value(display->session->display_map, display->name, display);
-
-        if (display->tile) {
-                display->tile->display = NULL;
-                grdev_tile_free(display->tile);
-        }
-
-        free(display->pipes);
-        free(display->name);
-        free(display);
-
-        return NULL;
-}
-
-void grdev_display_set_userdata(grdev_display *display, void *userdata) {
-        assert(display);
-
-        display->userdata = userdata;
-}
-
-void *grdev_display_get_userdata(grdev_display *display) {
-        assert_return(display, NULL);
-
-        return display->userdata;
-}
-
-const char *grdev_display_get_name(grdev_display *display) {
-        assert_return(display, NULL);
-
-        return display->name;
-}
-
-uint32_t grdev_display_get_width(grdev_display *display) {
-        assert_return(display, 0);
-
-        return display->width;
-}
-
-uint32_t grdev_display_get_height(grdev_display *display) {
-        assert_return(display, 0);
-
-        return display->height;
-}
-
-bool grdev_display_is_enabled(grdev_display *display) {
-        return display && display->enabled;
-}
-
-void grdev_display_enable(grdev_display *display) {
-        grdev_tile *t;
-
-        assert(display);
-
-        if (!display->enabled) {
-                display->enabled = true;
-                TILE_FOREACH(display->tile, t)
-                        if (t->type == GRDEV_TILE_LEAF)
-                                pipe_enable(t->leaf.pipe);
-        }
-}
-
-void grdev_display_disable(grdev_display *display) {
-        grdev_tile *t;
-
-        assert(display);
-
-        if (display->enabled) {
-                display->enabled = false;
-                TILE_FOREACH(display->tile, t)
-                        if (t->type == GRDEV_TILE_LEAF)
-                                pipe_disable(t->leaf.pipe);
-        }
-}
-
-const grdev_display_target *grdev_display_next_target(grdev_display *display, const grdev_display_target *prev) {
-        grdev_display_cache *cache;
-        size_t idx;
-
-        assert_return(display, NULL);
-        assert_return(!display->modified, NULL);
-        assert_return(display->enabled, NULL);
-
-        if (prev) {
-                cache = container_of(prev, grdev_display_cache, target);
-
-                assert(cache->pipe);
-                assert(cache->pipe->tile->display == display);
-                assert(display->pipes >= cache);
-
-                idx = cache - display->pipes + 1;
-        } else {
-                idx = 0;
-        }
-
-        for (cache = display->pipes + idx; idx < display->n_pipes; ++idx, ++cache) {
-                grdev_display_target *target;
-                grdev_pipe *pipe;
-                grdev_fb *fb;
-
-                pipe = cache->pipe;
-                target = &cache->target;
-
-                if (!pipe->running || !pipe->enabled)
-                        continue;
-
-                /* find suitable back-buffer */
-                if (!pipe->back) {
-                        if (!pipe->vtable->target)
-                                continue;
-                        if (!(fb = pipe->vtable->target(pipe)))
-                                continue;
-
-                        assert(fb == pipe->back);
-                }
-
-                target->front = pipe->front;
-                target->back = pipe->back;
-
-                return target;
-        }
-
-        return NULL;
-}
-
-void grdev_display_flip_target(grdev_display *display, const grdev_display_target *target) {
-        grdev_display_cache *cache;
-
-        assert(display);
-        assert(!display->modified);
-        assert(display->enabled);
-        assert(target);
-
-        cache = container_of(target, grdev_display_cache, target);
-
-        assert(cache->pipe);
-        assert(cache->pipe->tile->display == display);
-
-        cache->pipe->flip = true;
-}
-
-static void display_cache_apply(grdev_display_cache *c, grdev_tile *l) {
-        uint32_t x, y, width, height;
-        grdev_display_target *t;
-
-        assert(c);
-        assert(l);
-        assert(l->cache_w >= c->target.width + c->target.x);
-        assert(l->cache_h >= c->target.height + c->target.y);
-
-        t = &c->target;
-
-        /* rotate child */
-
-        t->rotate = (t->rotate + l->rotate) & 0x3;
-
-        x = t->x;
-        y = t->y;
-        width = t->width;
-        height = t->height;
-
-        switch (l->rotate) {
-        case GRDEV_ROTATE_0:
-                break;
-        case GRDEV_ROTATE_90:
-                t->x = l->cache_h - (height + y);
-                t->y = x;
-                t->width = height;
-                t->height = width;
-                break;
-        case GRDEV_ROTATE_180:
-                t->x = l->cache_w - (width + x);
-                t->y = l->cache_h - (height + y);
-                break;
-        case GRDEV_ROTATE_270:
-                t->x = y;
-                t->y = l->cache_w - (width + x);
-                t->width = height;
-                t->height = width;
-                break;
-        }
-
-        /* flip child */
-
-        t->flip ^= l->flip;
-
-        if (l->flip & GRDEV_FLIP_HORIZONTAL)
-                t->x = l->cache_w - (t->width + t->x);
-        if (l->flip & GRDEV_FLIP_VERTICAL)
-                t->y = l->cache_h - (t->height + t->y);
-
-        /* move child */
-
-        t->x += l->x;
-        t->y += l->y;
-}
-
-static void display_cache_targets(grdev_display *display) {
-        grdev_display_cache *c;
-        grdev_tile *tile;
-
-        assert(display);
-
-        /* depth-first with children before parent */
-        for (tile = tile_leftmost(display->tile);
-             tile;
-             tile = tile_leftmost(tile->children_by_node_next) ? : tile->parent) {
-                if (tile->type == GRDEV_TILE_LEAF) {
-                        grdev_pipe *p;
-
-                        /* We're at a leaf and no parent has been cached, yet.
-                         * Copy the pipe information into the target cache and
-                         * update our global pipe-caches if required. */
-
-                        assert(tile->leaf.pipe);
-                        assert(display->n_pipes + 1 <= display->max_pipes);
-
-                        p = tile->leaf.pipe;
-                        c = &display->pipes[display->n_pipes++];
-
-                        zero(*c);
-                        c->pipe = p;
-                        c->pipe->cache = c;
-                        c->target.width = p->width;
-                        c->target.height = p->height;
-                        tile->cache_w = p->width;
-                        tile->cache_h = p->height;
-
-                        /* all new tiles are incomplete due to geometry changes */
-                        c->incomplete = true;
-
-                        display_cache_apply(c, tile);
-                } else {
-                        grdev_tile *child, *l;
-
-                        /* We're now at a node with all its children already
-                         * computed (depth-first, child before parent). We
-                         * first need to know the size of our tile, then we
-                         * recurse into all leafs and update their cache. */
-
-                        tile->cache_w = 0;
-                        tile->cache_h = 0;
-
-                        LIST_FOREACH(children_by_node, child, tile->node.child_list) {
-                                if (child->x + child->cache_w > tile->cache_w)
-                                        tile->cache_w = child->x + child->cache_w;
-                                if (child->y + child->cache_h > tile->cache_h)
-                                        tile->cache_h = child->y + child->cache_h;
-                        }
-
-                        assert(tile->cache_w > 0);
-                        assert(tile->cache_h > 0);
-
-                        TILE_FOREACH(tile, l)
-                                if (l->type == GRDEV_TILE_LEAF)
-                                        display_cache_apply(l->leaf.pipe->cache, tile);
-                }
-        }
-}
-
-static bool display_cache(grdev_display *display) {
-        grdev_tile *tile;
-        size_t n;
-        void *t;
-        int r;
-
-        assert(display);
-
-        if (!display->modified)
-                return false;
-
-        display->modified = false;
-        display->framed = false;
-        display->n_pipes = 0;
-        display->width = 0;
-        display->height = 0;
-
-        if (display->n_leafs < 1)
-                return false;
-
-        TILE_FOREACH(display->tile, tile)
-                if (tile->type == GRDEV_TILE_LEAF)
-                        tile->leaf.pipe->cache = NULL;
-
-        if (display->n_leafs > display->max_pipes) {
-                n = ALIGN_POWER2(display->n_leafs);
-                if (!n) {
-                        r = -ENOMEM;
-                        goto out;
-                }
-
-                t = realloc_multiply(display->pipes, sizeof(*display->pipes), n);
-                if (!t) {
-                        r = -ENOMEM;
-                        goto out;
-                }
-
-                display->pipes = t;
-                display->max_pipes = n;
-        }
-
-        display_cache_targets(display);
-        display->width = display->tile->cache_w;
-        display->height = display->tile->cache_h;
-
-        r = 0;
-
-out:
-        if (r < 0)
-                log_debug_errno(r, "grdev: %s/%s: cannot cache pipes: %m",
-                                display->session->name, display->name);
-        return true;
-}
-
-/*
- * Pipes
- */
-
-grdev_pipe *grdev_find_pipe(grdev_card *card, const char *name) {
-        assert_return(card, NULL);
-        assert_return(name, NULL);
-
-        return hashmap_get(card->pipe_map, name);
-}
-
-static int pipe_vsync_fn(sd_event_source *src, uint64_t usec, void *userdata) {
-        grdev_pipe *pipe = userdata;
-
-        grdev_pipe_frame(pipe);
-        return 0;
-}
-
-int grdev_pipe_add(grdev_pipe *pipe, const char *name, size_t n_fbs) {
-        int r;
-
-        assert_return(pipe, -EINVAL);
-        assert_return(pipe->vtable, -EINVAL);
-        assert_return(pipe->vtable->free, -EINVAL);
-        assert_return(pipe->card, -EINVAL);
-        assert_return(pipe->card->session, -EINVAL);
-        assert_return(!pipe->cache, -EINVAL);
-        assert_return(pipe->width > 0, -EINVAL);
-        assert_return(pipe->height > 0, -EINVAL);
-        assert_return(pipe->vrefresh > 0, -EINVAL);
-        assert_return(!pipe->enabled, -EINVAL);
-        assert_return(!pipe->running, -EINVAL);
-        assert_return(name, -EINVAL);
-
-        pipe->name = strdup(name);
-        if (!pipe->name)
-                return -ENOMEM;
-
-        if (n_fbs > 0) {
-                pipe->fbs = new0(grdev_fb*, n_fbs);
-                if (!pipe->fbs)
-                        return -ENOMEM;
-
-                pipe->max_fbs = n_fbs;
-        }
-
-        r = grdev_tile_new_leaf(&pipe->tile, pipe);
-        if (r < 0)
-                return r;
-
-        r = sd_event_add_time(pipe->card->session->context->event,
-                              &pipe->vsync_src,
-                              CLOCK_MONOTONIC,
-                              0,
-                              10 * USEC_PER_MSEC,
-                              pipe_vsync_fn,
-                              pipe);
-        if (r < 0)
-                return r;
-
-        r = sd_event_source_set_enabled(pipe->vsync_src, SD_EVENT_OFF);
-        if (r < 0)
-                return r;
-
-        r = hashmap_put(pipe->card->pipe_map, pipe->name, pipe);
-        if (r < 0)
-                return r;
-
-        card_modified(pipe->card);
-        return 0;
-}
-
-grdev_pipe *grdev_pipe_free(grdev_pipe *pipe) {
-        grdev_pipe tmp;
-
-        if (!pipe)
-                return NULL;
-
-        assert(pipe->card);
-        assert(pipe->vtable);
-        assert(pipe->vtable->free);
-
-        if (pipe->name)
-                hashmap_remove_value(pipe->card->pipe_map, pipe->name, pipe);
-        if (pipe->tile)
-                tile_unlink(pipe->tile);
-
-        assert(!pipe->cache);
-
-        tmp = *pipe;
-        pipe->vtable->free(pipe);
-
-        sd_event_source_unref(tmp.vsync_src);
-        grdev_tile_free(tmp.tile);
-        card_modified(tmp.card);
-        free(tmp.fbs);
-        free(tmp.name);
-
-        return NULL;
-}
-
-static void pipe_enable(grdev_pipe *pipe) {
-        assert(pipe);
-
-        if (!pipe->enabled) {
-                pipe->enabled = true;
-                if (pipe->vtable->enable)
-                        pipe->vtable->enable(pipe);
-        }
-}
-
-static void pipe_disable(grdev_pipe *pipe) {
-        assert(pipe);
-
-        if (pipe->enabled) {
-                pipe->enabled = false;
-                if (pipe->vtable->disable)
-                        pipe->vtable->disable(pipe);
-        }
-}
-
-void grdev_pipe_ready(grdev_pipe *pipe, bool running) {
-        assert(pipe);
-
-        /* grdev_pipe_ready() is used by backends to notify about pipe state
-         * changed. If a pipe is ready, it can be fully used by us (available,
-         * enabled and accessible). Backends can disable pipes at any time
-         * (like for async revocation), but can only enable them from parent
-         * context. Otherwise, we might call user-callbacks recursively. */
-
-        if (pipe->running == running)
-                return;
-
-        pipe->running = running;
-
-        /* runtime events for unused pipes are not interesting */
-        if (pipe->cache && pipe->enabled) {
-                grdev_display *display = pipe->tile->display;
-
-                assert(display);
-
-                if (running)
-                        session_frame(display->session, display);
-                else
-                        pipe->cache->incomplete = true;
-        }
-}
-
-void grdev_pipe_frame(grdev_pipe *pipe) {
-        grdev_display *display;
-
-        assert(pipe);
-
-        /* if pipe is unused, ignore any frame events */
-        if (!pipe->cache || !pipe->enabled)
-                return;
-
-        display = pipe->tile->display;
-        assert(display);
-
-        grdev_pipe_schedule(pipe, 0);
-        session_frame(display->session, display);
-}
-
-void grdev_pipe_schedule(grdev_pipe *pipe, uint64_t frames) {
-        int r;
-        uint64_t ts;
-
-        if (!frames) {
-                sd_event_source_set_enabled(pipe->vsync_src, SD_EVENT_OFF);
-                return;
-        }
-
-        r = sd_event_now(pipe->card->session->context->event, CLOCK_MONOTONIC, &ts);
-        if (r < 0)
-                goto error;
-
-        ts += frames * USEC_PER_MSEC * 1000ULL / pipe->vrefresh;
-
-        r = sd_event_source_set_time(pipe->vsync_src, ts);
-        if (r < 0)
-                goto error;
-
-        r = sd_event_source_set_enabled(pipe->vsync_src, SD_EVENT_ONESHOT);
-        if (r < 0)
-                goto error;
-
-        return;
-
-error:
-        log_debug_errno(r, "grdev: %s/%s/%s: cannot schedule vsync timer: %m",
-                        pipe->card->session->name, pipe->card->name, pipe->name);
-}
-
-/*
- * Cards
- */
-
-grdev_card *grdev_find_card(grdev_session *session, const char *name) {
-        assert_return(session, NULL);
-        assert_return(name, NULL);
-
-        return hashmap_get(session->card_map, name);
-}
-
-int grdev_card_add(grdev_card *card, const char *name) {
-        int r;
-
-        assert_return(card, -EINVAL);
-        assert_return(card->vtable, -EINVAL);
-        assert_return(card->vtable->free, -EINVAL);
-        assert_return(card->session, -EINVAL);
-        assert_return(name, -EINVAL);
-
-        card->name = strdup(name);
-        if (!card->name)
-                return -ENOMEM;
-
-        card->pipe_map = hashmap_new(&string_hash_ops);
-        if (!card->pipe_map)
-                return -ENOMEM;
-
-        r = hashmap_put(card->session->card_map, card->name, card);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-grdev_card *grdev_card_free(grdev_card *card) {
-        grdev_card tmp;
-
-        if (!card)
-                return NULL;
-
-        assert(!card->enabled);
-        assert(card->vtable);
-        assert(card->vtable->free);
-
-        if (card->name)
-                hashmap_remove_value(card->session->card_map, card->name, card);
-
-        tmp = *card;
-        card->vtable->free(card);
-
-        assert(hashmap_size(tmp.pipe_map) == 0);
-
-        hashmap_free(tmp.pipe_map);
-        free(tmp.name);
-
-        return NULL;
-}
-
-static void card_modified(grdev_card *card) {
-        assert(card);
-        assert(card->session->n_pins > 0);
-
-        card->modified = true;
-}
-
-static void grdev_card_enable(grdev_card *card) {
-        assert(card);
-
-        if (!card->enabled) {
-                card->enabled = true;
-                if (card->vtable->enable)
-                        card->vtable->enable(card);
-        }
-}
-
-static void grdev_card_disable(grdev_card *card) {
-        assert(card);
-
-        if (card->enabled) {
-                card->enabled = false;
-                if (card->vtable->disable)
-                        card->vtable->disable(card);
-        }
-}
-
-/*
- * Sessions
- */
-
-static void session_raise(grdev_session *session, grdev_event *event) {
-        session->event_fn(session, session->userdata, event);
-}
-
-static void session_raise_display_add(grdev_session *session, grdev_display *display) {
-        grdev_event event = {
-                .type = GRDEV_EVENT_DISPLAY_ADD,
-                .display_add = {
-                        .display = display,
-                },
-        };
-
-        session_raise(session, &event);
-}
-
-static void session_raise_display_remove(grdev_session *session, grdev_display *display) {
-        grdev_event event = {
-                .type = GRDEV_EVENT_DISPLAY_REMOVE,
-                .display_remove = {
-                        .display = display,
-                },
-        };
-
-        session_raise(session, &event);
-}
-
-static void session_raise_display_change(grdev_session *session, grdev_display *display) {
-        grdev_event event = {
-                .type = GRDEV_EVENT_DISPLAY_CHANGE,
-                .display_change = {
-                        .display = display,
-                },
-        };
-
-        session_raise(session, &event);
-}
-
-static void session_raise_display_frame(grdev_session *session, grdev_display *display) {
-        grdev_event event = {
-                .type = GRDEV_EVENT_DISPLAY_FRAME,
-                .display_frame = {
-                        .display = display,
-                },
-        };
-
-        session_raise(session, &event);
-}
-
-static void session_add_card(grdev_session *session, grdev_card *card) {
-        assert(session);
-        assert(card);
-
-        log_debug("grdev: %s: add card '%s'", session->name, card->name);
-
-        /* Cards are not exposed to users, but managed internally. Cards are
-         * enabled if the session is enabled, and will track that state. The
-         * backend can probe the card at any time, but only if enabled. It
-         * will then add pipes according to hardware state.
-         * That is, the card may create pipes as soon as we enable it here. */
-
-        if (session->enabled)
-                grdev_card_enable(card);
-}
-
-static void session_remove_card(grdev_session *session, grdev_card *card) {
-        assert(session);
-        assert(card);
-
-        log_debug("grdev: %s: remove card '%s'", session->name, card->name);
-
-        /* As cards are not exposed, it can never be accessed by outside
-         * users and we can simply remove it. Disabling the card does not
-         * necessarily drop all pipes of the card. This is usually deferred
-         * to card destruction (as pipes are cached as long as FDs remain
-         * open). Therefore, the card destruction might cause pipes, and thus
-         * visible displays, to be removed. */
-
-        grdev_card_disable(card);
-        grdev_card_free(card);
-}
-
-static void session_add_display(grdev_session *session, grdev_display *display) {
-        assert(session);
-        assert(display);
-        assert(!display->enabled);
-
-        log_debug("grdev: %s: add display '%s'", session->name, display->name);
-
-        /* Displays are the main entity for public API users. We create them
-         * independent of card backends and they wrap any underlying display
-         * architecture. Displays are public at all times, thus, may be entered
-         * by outside users at any time. */
-
-        display->public = true;
-        session_raise_display_add(session, display);
-}
-
-static void session_remove_display(grdev_session *session, grdev_display *display) {
-        assert(session);
-        assert(display);
-
-        log_debug("grdev: %s: remove display '%s'", session->name, display->name);
-
-        /* Displays are public, so we have to be careful when removing them.
-         * We first tell users about their removal, disable them and then drop
-         * them. We now, after the notification, no external access will
-         * happen. Therefore, we can release the tiles afterwards safely. */
-
-        if (display->public) {
-                display->public = false;
-                session_raise_display_remove(session, display);
-        }
-
-        grdev_display_disable(display);
-        grdev_display_free(display);
-}
-
-static void session_change_display(grdev_session *session, grdev_display *display) {
-        bool changed;
-
-        assert(session);
-        assert(display);
-
-        changed = display_cache(display);
-
-        if (display->n_leafs == 0) {
-                session_remove_display(session, display);
-        } else if (!display->public) {
-                session_add_display(session, display);
-                session_frame(session, display);
-        } else if (changed) {
-                session_raise_display_change(session, display);
-                session_frame(session, display);
-        } else if (display->framed) {
-                session_frame(session, display);
-        }
-}
-
-static void session_frame(grdev_session *session, grdev_display *display) {
-        assert(session);
-        assert(display);
-
-        display->framed = false;
-
-        if (!display->enabled || !session->enabled)
-                return;
-
-        if (session->n_pins > 0)
-                display->framed = true;
-        else
-                session_raise_display_frame(session, display);
-}
-
-int grdev_session_new(grdev_session **out,
-                      grdev_context *context,
-                      unsigned int flags,
-                      const char *name,
-                      grdev_event_fn event_fn,
-                      void *userdata) {
-        _cleanup_(grdev_session_freep) grdev_session *session = NULL;
-        int r;
-
-        assert(out);
-        assert(context);
-        assert(name);
-        assert(event_fn);
-        assert_return(session_id_valid(name) == !(flags & GRDEV_SESSION_CUSTOM), -EINVAL);
-        assert_return(!(flags & GRDEV_SESSION_CUSTOM) || !(flags & GRDEV_SESSION_MANAGED), -EINVAL);
-        assert_return(!(flags & GRDEV_SESSION_MANAGED) || context->sysbus, -EINVAL);
-
-        session = new0(grdev_session, 1);
-        if (!session)
-                return -ENOMEM;
-
-        session->context = grdev_context_ref(context);
-        session->custom = flags & GRDEV_SESSION_CUSTOM;
-        session->managed = flags & GRDEV_SESSION_MANAGED;
-        session->event_fn = event_fn;
-        session->userdata = userdata;
-
-        session->name = strdup(name);
-        if (!session->name)
-                return -ENOMEM;
-
-        if (session->managed) {
-                r = sd_bus_path_encode("/org/freedesktop/login1/session",
-                                       session->name, &session->path);
-                if (r < 0)
-                        return r;
-        }
-
-        session->card_map = hashmap_new(&string_hash_ops);
-        if (!session->card_map)
-                return -ENOMEM;
-
-        session->display_map = hashmap_new(&string_hash_ops);
-        if (!session->display_map)
-                return -ENOMEM;
-
-        r = hashmap_put(context->session_map, session->name, session);
-        if (r < 0)
-                return r;
-
-        *out = session;
-        session = NULL;
-        return 0;
-}
-
-grdev_session *grdev_session_free(grdev_session *session) {
-        grdev_card *card;
-
-        if (!session)
-                return NULL;
-
-        grdev_session_disable(session);
-
-        while ((card = hashmap_first(session->card_map)))
-                session_remove_card(session, card);
-
-        assert(hashmap_size(session->display_map) == 0);
-
-        if (session->name)
-                hashmap_remove_value(session->context->session_map, session->name, session);
-
-        hashmap_free(session->display_map);
-        hashmap_free(session->card_map);
-        session->context = grdev_context_unref(session->context);
-        free(session->path);
-        free(session->name);
-        free(session);
-
-        return NULL;
-}
-
-bool grdev_session_is_enabled(grdev_session *session) {
-        return session && session->enabled;
-}
-
-void grdev_session_enable(grdev_session *session) {
-        grdev_card *card;
-        Iterator iter;
-
-        assert(session);
-
-        if (!session->enabled) {
-                session->enabled = true;
-                HASHMAP_FOREACH(card, session->card_map, iter)
-                        grdev_card_enable(card);
-        }
-}
-
-void grdev_session_disable(grdev_session *session) {
-        grdev_card *card;
-        Iterator iter;
-
-        assert(session);
-
-        if (session->enabled) {
-                session->enabled = false;
-                HASHMAP_FOREACH(card, session->card_map, iter)
-                        grdev_card_disable(card);
-        }
-}
-
-void grdev_session_commit(grdev_session *session) {
-        grdev_card *card;
-        Iterator iter;
-
-        assert(session);
-
-        if (!session->enabled)
-                return;
-
-        HASHMAP_FOREACH(card, session->card_map, iter)
-                if (card->vtable->commit)
-                        card->vtable->commit(card);
-}
-
-void grdev_session_restore(grdev_session *session) {
-        grdev_card *card;
-        Iterator iter;
-
-        assert(session);
-
-        if (!session->enabled)
-                return;
-
-        HASHMAP_FOREACH(card, session->card_map, iter)
-                if (card->vtable->restore)
-                        card->vtable->restore(card);
-}
-
-void grdev_session_add_drm(grdev_session *session, struct udev_device *ud) {
-        grdev_card *card;
-        dev_t devnum;
-        int r;
-
-        assert(session);
-        assert(ud);
-
-        devnum = udev_device_get_devnum(ud);
-        if (devnum == 0)
-                return grdev_session_hotplug_drm(session, ud);
-
-        card = grdev_find_drm_card(session, devnum);
-        if (card)
-                return;
-
-        r = grdev_drm_card_new(&card, session, ud);
-        if (r < 0) {
-                log_debug_errno(r, "grdev: %s: cannot add DRM device for %s: %m",
-                                session->name, udev_device_get_syspath(ud));
-                return;
-        }
-
-        session_add_card(session, card);
-}
-
-void grdev_session_remove_drm(grdev_session *session, struct udev_device *ud) {
-        grdev_card *card;
-        dev_t devnum;
-
-        assert(session);
-        assert(ud);
-
-        devnum = udev_device_get_devnum(ud);
-        if (devnum == 0)
-                return grdev_session_hotplug_drm(session, ud);
-
-        card = grdev_find_drm_card(session, devnum);
-        if (!card)
-                return;
-
-        session_remove_card(session, card);
-}
-
-void grdev_session_hotplug_drm(grdev_session *session, struct udev_device *ud) {
-        grdev_card *card = NULL;
-        struct udev_device *p;
-        dev_t devnum;
-
-        assert(session);
-        assert(ud);
-
-        for (p = ud; p; p = udev_device_get_parent_with_subsystem_devtype(p, "drm", NULL)) {
-                devnum = udev_device_get_devnum(ud);
-                if (devnum == 0)
-                        continue;
-
-                card = grdev_find_drm_card(session, devnum);
-                if (card)
-                        break;
-        }
-
-        if (!card)
-                return;
-
-        grdev_drm_card_hotplug(card, ud);
-}
-
-static void session_configure(grdev_session *session) {
-        grdev_display *display;
-        grdev_tile *tile;
-        grdev_card *card;
-        grdev_pipe *pipe;
-        Iterator i, j;
-        int r;
-
-        assert(session);
-
-        /*
-         * Whenever backends add or remove pipes, we set session->modified and
-         * require them to pin the session while modifying it. On release, we
-         * reconfigure the device and re-assign displays to all modified pipes.
-         *
-         * So far, we configure each pipe as a separate display. We do not
-         * support user-configuration, nor have we gotten any reports from
-         * users with multi-pipe monitors (4k on DP-1.2 MST and so on). Until
-         * we get reports, we keep the logic to a minimum.
-         */
-
-        /* create new displays for all unconfigured pipes */
-        HASHMAP_FOREACH(card, session->card_map, i) {
-                if (!card->modified)
-                        continue;
-
-                card->modified = false;
-
-                HASHMAP_FOREACH(pipe, card->pipe_map, j) {
-                        tile = pipe->tile;
-                        if (tile->display)
-                                continue;
-
-                        assert(!tile->parent);
-
-                        display = grdev_find_display(session, pipe->name);
-                        if (display && display->tile) {
-                                log_debug("grdev: %s/%s: occupied display for pipe %s",
-                                          session->name, card->name, pipe->name);
-                                continue;
-                        } else if (!display) {
-                                r = grdev_display_new(&display, session, pipe->name);
-                                if (r < 0) {
-                                        log_debug_errno(r, "grdev: %s/%s: cannot create display for pipe %s: %m",
-                                                        session->name, card->name, pipe->name);
-                                        continue;
-                                }
-                        }
-
-                        tile_link(pipe->tile, display->tile);
-                }
-        }
-
-        /* update displays */
-        HASHMAP_FOREACH(display, session->display_map, i)
-                session_change_display(session, display);
-}
-
-grdev_session *grdev_session_pin(grdev_session *session) {
-        assert(session);
-
-        ++session->n_pins;
-        return session;
-}
-
-grdev_session *grdev_session_unpin(grdev_session *session) {
-        if (!session)
-                return NULL;
-
-        assert(session->n_pins > 0);
-
-        if (--session->n_pins == 0)
-                session_configure(session);
-
-        return NULL;
-}
-
-/*
- * Contexts
- */
-
-int grdev_context_new(grdev_context **out, sd_event *event, sd_bus *sysbus) {
-        _cleanup_(grdev_context_unrefp) grdev_context *context = NULL;
-
-        assert_return(out, -EINVAL);
-        assert_return(event, -EINVAL);
-
-        context = new0(grdev_context, 1);
-        if (!context)
-                return -ENOMEM;
-
-        context->ref = 1;
-        context->event = sd_event_ref(event);
-
-        if (sysbus)
-                context->sysbus = sd_bus_ref(sysbus);
-
-        context->session_map = hashmap_new(&string_hash_ops);
-        if (!context->session_map)
-                return -ENOMEM;
-
-        *out = context;
-        context = NULL;
-        return 0;
-}
-
-static void context_cleanup(grdev_context *context) {
-        assert(hashmap_size(context->session_map) == 0);
-
-        hashmap_free(context->session_map);
-        context->sysbus = sd_bus_unref(context->sysbus);
-        context->event = sd_event_unref(context->event);
-        free(context);
-}
-
-grdev_context *grdev_context_ref(grdev_context *context) {
-        assert_return(context, NULL);
-        assert_return(context->ref > 0, NULL);
-
-        ++context->ref;
-        return context;
-}
-
-grdev_context *grdev_context_unref(grdev_context *context) {
-        if (!context)
-                return NULL;
-
-        assert_return(context->ref > 0, NULL);
-
-        if (--context->ref == 0)
-                context_cleanup(context);
-
-        return NULL;
-}
diff --git a/src/libsystemd-terminal/grdev.h b/src/libsystemd-terminal/grdev.h
deleted file mode 100644 (file)
index db2a508..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-/*
- * Graphics Devices
- * The grdev layer provides generic access to graphics devices. The device
- * types are hidden in the implementation and exported in a generic way. The
- * grdev_session object forms the base layer. It loads, configures and prepares
- * any graphics devices associated with that session. Each session is totally
- * independent of other sessions and can be controlled separately.
- * The target devices on a session are called display. A display always
- * corresponds to a real display regardless how many pipes are needed to drive
- * that display. That is, an exported display might internally be created out
- * of arbitrary combinations of target pipes. However, this is meant as
- * implementation detail and API users must never assume details below the
- * display-level. That is, a display is the most low-level object exported.
- * Therefore, pipe-configuration and any low-level modesetting is hidden from
- * the public API. It is provided by the implementation, and it is the
- * implementation that decides how pipes are driven.
- *
- * The API users are free to ignore specific displays or combine them to create
- * larger screens. This often requires user-configuration so is dictated by
- * policy. The underlying pipe-configuration might be affected by these
- * high-level policies, but is never directly controlled by those. That means,
- * depending on the displays you use, it might affect how underlying resources
- * are assigned. However, users can never directly apply policies to the pipes,
- * but only to displays. In case specific hardware needs quirks on the pipe
- * level, we support that via hwdb, not via public user configuration.
- *
- * Right now, displays are limited to rgb32 memory-mapped framebuffers on the
- * primary plane. However, the grdev implementation can be easily extended to
- * allow more powerful access (including hardware-acceleration for 2D and 3D
- * compositing). So far, this wasn't needed so it is not exposed.
- */
-
-#pragma once
-
-#include <libudev.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <systemd/sd-bus.h>
-#include <systemd/sd-event.h>
-#include "util.h"
-
-typedef struct grdev_fb                 grdev_fb;
-typedef struct grdev_display_target     grdev_display_target;
-typedef struct grdev_display            grdev_display;
-
-typedef struct grdev_event              grdev_event;
-typedef struct grdev_session            grdev_session;
-typedef struct grdev_context            grdev_context;
-
-enum {
-        /* clockwise rotation; we treat this is abelian group Z4 with ADD */
-        GRDEV_ROTATE_0                  = 0,
-        GRDEV_ROTATE_90                 = 1,
-        GRDEV_ROTATE_180                = 2,
-        GRDEV_ROTATE_270                = 3,
-};
-
-enum {
-        /* flip states; we treat this as abelian group V4 with XOR */
-        GRDEV_FLIP_NONE                 = 0x0,
-        GRDEV_FLIP_HORIZONTAL           = 0x1,
-        GRDEV_FLIP_VERTICAL             = 0x2,
-};
-
-/*
- * Displays
- */
-
-struct grdev_fb {
-        uint32_t width;
-        uint32_t height;
-        uint32_t format;
-        int32_t strides[4];
-        void *maps[4];
-
-        union {
-                void *ptr;
-                uint64_t u64;
-        } data;
-
-        void (*free_fn) (void *ptr);
-};
-
-struct grdev_display_target {
-        uint32_t x;
-        uint32_t y;
-        uint32_t width;
-        uint32_t height;
-        unsigned int rotate;
-        unsigned int flip;
-        grdev_fb *front;
-        grdev_fb *back;
-};
-
-void grdev_display_set_userdata(grdev_display *display, void *userdata);
-void *grdev_display_get_userdata(grdev_display *display);
-
-const char *grdev_display_get_name(grdev_display *display);
-uint32_t grdev_display_get_width(grdev_display *display);
-uint32_t grdev_display_get_height(grdev_display *display);
-
-bool grdev_display_is_enabled(grdev_display *display);
-void grdev_display_enable(grdev_display *display);
-void grdev_display_disable(grdev_display *display);
-
-const grdev_display_target *grdev_display_next_target(grdev_display *display, const grdev_display_target *prev);
-void grdev_display_flip_target(grdev_display *display, const grdev_display_target *target);
-
-#define GRDEV_DISPLAY_FOREACH_TARGET(_display, _t)                      \
-        for ((_t) = grdev_display_next_target((_display), NULL);        \
-             (_t);                                                      \
-             (_t) = grdev_display_next_target((_display), (_t)))
-
-/*
- * Events
- */
-
-enum {
-        GRDEV_EVENT_DISPLAY_ADD,
-        GRDEV_EVENT_DISPLAY_REMOVE,
-        GRDEV_EVENT_DISPLAY_CHANGE,
-        GRDEV_EVENT_DISPLAY_FRAME,
-};
-
-typedef void (*grdev_event_fn) (grdev_session *session, void *userdata, grdev_event *ev);
-
-struct grdev_event {
-        unsigned int type;
-        union {
-                struct {
-                        grdev_display *display;
-                } display_add, display_remove, display_change;
-
-                struct {
-                        grdev_display *display;
-                } display_frame;
-        };
-};
-
-/*
- * Sessions
- */
-
-enum {
-        GRDEV_SESSION_CUSTOM                    = (1 << 0),
-        GRDEV_SESSION_MANAGED                   = (1 << 1),
-};
-
-int grdev_session_new(grdev_session **out,
-                      grdev_context *context,
-                      unsigned int flags,
-                      const char *name,
-                      grdev_event_fn event_fn,
-                      void *userdata);
-grdev_session *grdev_session_free(grdev_session *session);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(grdev_session*, grdev_session_free);
-
-bool grdev_session_is_enabled(grdev_session *session);
-void grdev_session_enable(grdev_session *session);
-void grdev_session_disable(grdev_session *session);
-
-void grdev_session_commit(grdev_session *session);
-void grdev_session_restore(grdev_session *session);
-
-void grdev_session_add_drm(grdev_session *session, struct udev_device *ud);
-void grdev_session_remove_drm(grdev_session *session, struct udev_device *ud);
-void grdev_session_hotplug_drm(grdev_session *session, struct udev_device *ud);
-
-/*
- * Contexts
- */
-
-int grdev_context_new(grdev_context **out, sd_event *event, sd_bus *sysbus);
-grdev_context *grdev_context_ref(grdev_context *context);
-grdev_context *grdev_context_unref(grdev_context *context);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(grdev_context*, grdev_context_unref);
diff --git a/src/libsystemd-terminal/idev-evdev.c b/src/libsystemd-terminal/idev-evdev.c
deleted file mode 100644 (file)
index 91ae507..0000000
+++ /dev/null
@@ -1,860 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <fcntl.h>
-#include <libevdev/libevdev.h>
-#include <libudev.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <systemd/sd-bus.h>
-#include <systemd/sd-event.h>
-#include "bus-util.h"
-#include "idev.h"
-#include "idev-internal.h"
-#include "macro.h"
-#include "util.h"
-
-typedef struct idev_evdev idev_evdev;
-typedef struct unmanaged_evdev unmanaged_evdev;
-typedef struct managed_evdev managed_evdev;
-
-struct idev_evdev {
-        idev_element element;
-        struct libevdev *evdev;
-        int fd;
-        sd_event_source *fd_src;
-        sd_event_source *idle_src;
-
-        bool unsync : 1;                /* not in-sync with kernel */
-        bool resync : 1;                /* re-syncing with kernel */
-        bool running : 1;
-};
-
-struct unmanaged_evdev {
-        idev_evdev evdev;
-        char *devnode;
-};
-
-struct managed_evdev {
-        idev_evdev evdev;
-        dev_t devnum;
-        sd_bus_slot *slot_take_device;
-
-        bool requested : 1;             /* TakeDevice() was sent */
-        bool acquired : 1;              /* TakeDevice() was successful */
-};
-
-#define idev_evdev_from_element(_e) container_of((_e), idev_evdev, element)
-#define unmanaged_evdev_from_element(_e) \
-        container_of(idev_evdev_from_element(_e), unmanaged_evdev, evdev)
-#define managed_evdev_from_element(_e) \
-        container_of(idev_evdev_from_element(_e), managed_evdev, evdev)
-
-#define IDEV_EVDEV_INIT(_vtable, _session) ((idev_evdev){ \
-                .element = IDEV_ELEMENT_INIT((_vtable), (_session)), \
-                .fd = -1, \
-        })
-
-#define IDEV_EVDEV_NAME_MAX (8 + DECIMAL_STR_MAX(unsigned) * 2)
-
-static const idev_element_vtable unmanaged_evdev_vtable;
-static const idev_element_vtable managed_evdev_vtable;
-
-static int idev_evdev_resume(idev_evdev *evdev, int dev_fd);
-static void idev_evdev_pause(idev_evdev *evdev, bool release);
-
-/*
- * Virtual Evdev Element
- * The virtual evdev element is the base class of all other evdev elements. It
- * uses libevdev to access the kernel evdev API. It supports asynchronous
- * access revocation, re-syncing if events got dropped and more.
- * This element cannot be used by itself. There must be a wrapper around it
- * which opens a file-descriptor and passes it to the virtual evdev element.
- */
-
-static void idev_evdev_name(char *out, dev_t devnum) {
-        /* @out must be at least of size IDEV_EVDEV_NAME_MAX */
-        sprintf(out, "evdev/%u:%u", major(devnum), minor(devnum));
-}
-
-static int idev_evdev_feed_resync(idev_evdev *evdev) {
-        idev_data data = {
-                .type = IDEV_DATA_RESYNC,
-                .resync = evdev->resync,
-        };
-
-        return idev_element_feed(&evdev->element, &data);
-}
-
-static int idev_evdev_feed_evdev(idev_evdev *evdev, struct input_event *event) {
-        idev_data data = {
-                .type = IDEV_DATA_EVDEV,
-                .resync = evdev->resync,
-                .evdev = {
-                        .event = *event,
-                },
-        };
-
-        return idev_element_feed(&evdev->element, &data);
-}
-
-static void idev_evdev_hup(idev_evdev *evdev) {
-        /*
-         * On HUP, we close the current fd via idev_evdev_pause(). This drops
-         * the event-sources from the main-loop and effectively puts the
-         * element asleep. If the HUP is part of a hotplug-event, a following
-         * udev-notification will destroy the element. Otherwise, the HUP is
-         * either result of access-revokation or a serious error.
-         * For unmanaged devices, we should never receive HUP (except for
-         * unplug-events). But if we do, something went seriously wrong and we
-         * shouldn't try to be clever.
-         * Instead, we simply stay asleep and wait for the device to be
-         * disabled and then re-enabled (or closed and re-opened). This will
-         * re-open the device node and restart the device.
-         * For managed devices, a HUP usually means our device-access was
-         * revoked. In that case, we simply put the device asleep and wait for
-         * logind to notify us once the device is alive again. logind also
-         * passes us a new fd. Hence, we don't have to re-enable the device.
-         *
-         * Long story short: The only thing we have to do here, is close() the
-         * file-descriptor and remove it from the main-loop. Everything else is
-         * handled via additional events we receive.
-         */
-
-        idev_evdev_pause(evdev, true);
-}
-
-static int idev_evdev_io(idev_evdev *evdev) {
-        idev_element *e = &evdev->element;
-        struct input_event ev;
-        unsigned int flags;
-        int r, error = 0;
-
-        /*
-         * Read input-events via libevdev until the input-queue is drained. In
-         * case we're disabled, don't do anything. The input-queue might
-         * overflow, but we don't care as we have to resync after wake-up,
-         * anyway.
-         * TODO: libevdev should give us a hint how many events to read. We
-         * really want to avoid starvation, so we shouldn't read forever in
-         * case we cannot keep up with the kernel.
-         * TODO: Make sure libevdev always reports SYN_DROPPED to us, regardless
-         * whether any event was synced afterwards.
-         */
-
-        flags = LIBEVDEV_READ_FLAG_NORMAL;
-        while (e->enabled) {
-                if (evdev->unsync) {
-                        /* immediately resync, even if in sync right now */
-                        evdev->unsync = false;
-                        evdev->resync = false;
-                        flags = LIBEVDEV_READ_FLAG_NORMAL;
-                        r = libevdev_next_event(evdev->evdev, flags | LIBEVDEV_READ_FLAG_FORCE_SYNC, &ev);
-                        if (r < 0 && r != -EAGAIN) {
-                                r = 0;
-                                goto error;
-                        } else if (r != LIBEVDEV_READ_STATUS_SYNC) {
-                                log_debug("idev-evdev: %s/%s: cannot force resync: %d",
-                                          e->session->name, e->name, r);
-                        }
-                } else {
-                        r = libevdev_next_event(evdev->evdev, flags, &ev);
-                }
-
-                if (evdev->resync && r == -EAGAIN) {
-                        /* end of re-sync */
-                        evdev->resync = false;
-                        flags = LIBEVDEV_READ_FLAG_NORMAL;
-                } else if (r == -EAGAIN) {
-                        /* no data available */
-                        break;
-                } else if (r < 0) {
-                        /* read error */
-                        goto error;
-                } else if (r == LIBEVDEV_READ_STATUS_SYNC) {
-                        if (evdev->resync) {
-                                /* sync-event */
-                                r = idev_evdev_feed_evdev(evdev, &ev);
-                                if (r != 0) {
-                                        error = r;
-                                        break;
-                                }
-                        } else {
-                                /* start of sync */
-                                evdev->resync = true;
-                                flags = LIBEVDEV_READ_FLAG_SYNC;
-                                r = idev_evdev_feed_resync(evdev);
-                                if (r != 0) {
-                                        error = r;
-                                        break;
-                                }
-                        }
-                } else {
-                        /* normal event */
-                        r = idev_evdev_feed_evdev(evdev, &ev);
-                        if (r != 0) {
-                                error = r;
-                                break;
-                        }
-                }
-        }
-
-        if (error < 0)
-                log_debug_errno(error, "idev-evdev: %s/%s: error on data event: %m",
-                                e->session->name, e->name);
-        return error;
-
-error:
-        idev_evdev_hup(evdev);
-        return 0; /* idev_evdev_hup() handles the error so discard it */
-}
-
-static int idev_evdev_event_fn(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-        idev_evdev *evdev = userdata;
-
-        /* fetch data as long as EPOLLIN is signalled */
-        if (revents & EPOLLIN)
-                return idev_evdev_io(evdev);
-
-        if (revents & (EPOLLHUP | EPOLLERR))
-                idev_evdev_hup(evdev);
-
-        return 0;
-}
-
-static int idev_evdev_idle_fn(sd_event_source *s, void *userdata) {
-        idev_evdev *evdev = userdata;
-
-        /*
-         * The idle-event is raised whenever we have to re-sync the libevdev
-         * state from the kernel. We simply call into idev_evdev_io() which
-         * flushes the state and re-syncs it if @unsync is set.
-         * State has to be synced whenever our view of the kernel device is
-         * out of date. This is the case when we open the device, if the
-         * kernel's receive buffer overflows, or on other exceptional
-         * situations. Events during re-syncs must be forwarded to the upper
-         * layers so they can update their view of the device. However, such
-         * events must only be handled passively, as they might be out-of-order
-         * and/or re-ordered. Therefore, we mark them as 'sync' events.
-         */
-
-        if (!evdev->unsync)
-                return 0;
-
-        return idev_evdev_io(evdev);
-}
-
-static void idev_evdev_destroy(idev_evdev *evdev) {
-        assert(evdev);
-        assert(evdev->fd < 0);
-
-        libevdev_free(evdev->evdev);
-        evdev->evdev = NULL;
-}
-
-static void idev_evdev_enable(idev_evdev *evdev) {
-        assert(evdev);
-        assert(evdev->fd_src);
-        assert(evdev->idle_src);
-
-        if (evdev->running)
-                return;
-        if (evdev->fd < 0 || evdev->element.n_open < 1 || !evdev->element.enabled)
-                return;
-
-        evdev->running = true;
-        sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_ON);
-        sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_ONESHOT);
-}
-
-static void idev_evdev_disable(idev_evdev *evdev) {
-        assert(evdev);
-        assert(evdev->fd_src);
-        assert(evdev->idle_src);
-
-        if (!evdev->running)
-                return;
-
-        evdev->running = false;
-        idev_evdev_feed_resync(evdev);
-        sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_OFF);
-        sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_OFF);
-}
-
-static int idev_evdev_resume(idev_evdev *evdev, int dev_fd) {
-        idev_element *e = &evdev->element;
-        _cleanup_close_ int fd = dev_fd;
-        int r, flags;
-
-        if (fd < 0 || evdev->fd == fd) {
-                fd = -1;
-                idev_evdev_enable(evdev);
-                return 0;
-        }
-
-        idev_evdev_pause(evdev, true);
-        log_debug("idev-evdev: %s/%s: resume", e->session->name, e->name);
-
-        r = fd_nonblock(fd, true);
-        if (r < 0)
-                return r;
-
-        r = fd_cloexec(fd, true);
-        if (r < 0)
-                return r;
-
-        flags = fcntl(fd, F_GETFL, 0);
-        if (flags < 0)
-                return -errno;
-
-        flags &= O_ACCMODE;
-        if (flags == O_WRONLY)
-                return -EACCES;
-
-        evdev->element.readable = true;
-        evdev->element.writable = !(flags & O_RDONLY);
-
-        /*
-         * TODO: We *MUST* re-sync the device so we get a delta of the changed
-         * state while we didn't read events from the device. This works just
-         * fine with libevdev_change_fd(), however, libevdev_new_from_fd() (or
-         * libevdev_set_fd()) don't pass us events for the initial device
-         * state. So even if we force a re-sync, we will not get the delta for
-         * the initial device state.
-         * We really need to fix libevdev to support that!
-         */
-        if (evdev->evdev)
-                r = libevdev_change_fd(evdev->evdev, fd);
-        else
-                r = libevdev_new_from_fd(fd, &evdev->evdev);
-
-        if (r < 0)
-                return r;
-
-        r = sd_event_add_io(e->session->context->event,
-                            &evdev->fd_src,
-                            fd,
-                            EPOLLHUP | EPOLLERR | EPOLLIN,
-                            idev_evdev_event_fn,
-                            evdev);
-        if (r < 0)
-                return r;
-
-        r = sd_event_add_defer(e->session->context->event,
-                               &evdev->idle_src,
-                               idev_evdev_idle_fn,
-                               evdev);
-        if (r < 0) {
-                evdev->fd_src = sd_event_source_unref(evdev->fd_src);
-                return r;
-        }
-
-        sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_OFF);
-        sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_OFF);
-
-        evdev->unsync = true;
-        evdev->fd = fd;
-        fd = -1;
-
-        idev_evdev_enable(evdev);
-        return 0;
-}
-
-static void idev_evdev_pause(idev_evdev *evdev, bool release) {
-        idev_element *e = &evdev->element;
-
-        if (evdev->fd < 0)
-                return;
-
-        log_debug("idev-evdev: %s/%s: pause", e->session->name, e->name);
-
-        idev_evdev_disable(evdev);
-        if (release) {
-                evdev->idle_src = sd_event_source_unref(evdev->idle_src);
-                evdev->fd_src = sd_event_source_unref(evdev->fd_src);
-                evdev->fd = safe_close(evdev->fd);
-        }
-}
-
-/*
- * Unmanaged Evdev Element
- * The unmanaged evdev element opens the evdev node for a given input device
- * directly (/dev/input/eventX) and thus needs sufficient privileges. It opens
- * the device only if we really require it and releases it as soon as we're
- * disabled or closed.
- * The unmanaged element can be used in all situations where you have direct
- * access to input device nodes. Unlike managed evdev elements, it can be used
- * outside of user sessions and in emergency situations where logind is not
- * available.
- */
-
-static void unmanaged_evdev_resume(idev_element *e) {
-        unmanaged_evdev *eu = unmanaged_evdev_from_element(e);
-        int r, fd;
-
-        /*
-         * Unmanaged devices can be acquired on-demand. Therefore, don't
-         * acquire it unless someone opened the device *and* we're enabled.
-         */
-        if (e->n_open < 1 || !e->enabled)
-                return;
-
-        fd = eu->evdev.fd;
-        if (fd < 0) {
-                fd = open(eu->devnode, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK);
-                if (fd < 0) {
-                        if (errno != EACCES && errno != EPERM) {
-                                log_debug_errno(errno, "idev-evdev: %s/%s: cannot open node %s: %m",
-                                                e->session->name, e->name, eu->devnode);
-                                return;
-                        }
-
-                        fd = open(eu->devnode, O_RDONLY | O_CLOEXEC | O_NOCTTY | O_NONBLOCK);
-                        if (fd < 0) {
-                                log_debug_errno(errno, "idev-evdev: %s/%s: cannot open node %s: %m",
-                                                e->session->name, e->name, eu->devnode);
-                                return;
-                        }
-
-                        e->readable = true;
-                        e->writable = false;
-                } else {
-                        e->readable = true;
-                        e->writable = true;
-                }
-        }
-
-        r = idev_evdev_resume(&eu->evdev, fd);
-        if (r < 0)
-                log_debug_errno(r, "idev-evdev: %s/%s: cannot resume: %m",
-                                e->session->name, e->name);
-}
-
-static void unmanaged_evdev_pause(idev_element *e) {
-        unmanaged_evdev *eu = unmanaged_evdev_from_element(e);
-
-        /*
-         * Release the device if the device is disabled or there is no-one who
-         * opened it. This guarantees we stay only available if we're opened
-         * *and* enabled.
-         */
-
-        idev_evdev_pause(&eu->evdev, true);
-}
-
-static int unmanaged_evdev_new(idev_element **out, idev_session *s, struct udev_device *ud) {
-        _cleanup_(idev_element_freep) idev_element *e = NULL;
-        char name[IDEV_EVDEV_NAME_MAX];
-        unmanaged_evdev *eu;
-        const char *devnode;
-        dev_t devnum;
-        int r;
-
-        assert_return(s, -EINVAL);
-        assert_return(ud, -EINVAL);
-
-        devnode = udev_device_get_devnode(ud);
-        devnum = udev_device_get_devnum(ud);
-        if (!devnode || devnum == 0)
-                return -ENODEV;
-
-        idev_evdev_name(name, devnum);
-
-        eu = new0(unmanaged_evdev, 1);
-        if (!eu)
-                return -ENOMEM;
-
-        e = &eu->evdev.element;
-        eu->evdev = IDEV_EVDEV_INIT(&unmanaged_evdev_vtable, s);
-
-        eu->devnode = strdup(devnode);
-        if (!eu->devnode)
-                return -ENOMEM;
-
-        r = idev_element_add(e, name);
-        if (r < 0)
-                return r;
-
-        if (out)
-                *out = e;
-        e = NULL;
-        return 0;
-}
-
-static void unmanaged_evdev_free(idev_element *e) {
-        unmanaged_evdev *eu = unmanaged_evdev_from_element(e);
-
-        idev_evdev_destroy(&eu->evdev);
-        free(eu->devnode);
-        free(eu);
-}
-
-static const idev_element_vtable unmanaged_evdev_vtable = {
-        .free                   = unmanaged_evdev_free,
-        .enable                 = unmanaged_evdev_resume,
-        .disable                = unmanaged_evdev_pause,
-        .open                   = unmanaged_evdev_resume,
-        .close                  = unmanaged_evdev_pause,
-};
-
-/*
- * Managed Evdev Element
- * The managed evdev element uses systemd-logind to acquire evdev devices. This
- * means, we do not open the device node /dev/input/eventX directly. Instead,
- * logind passes us a file-descriptor whenever our session is activated. Thus,
- * we don't need access to the device node directly.
- * Furthermore, whenever the session is put asleep, logind revokes the
- * file-descriptor so we loose access to the device.
- * Managed evdev elements should be preferred over unmanaged elements whenever
- * you run inside a user session with exclusive device access.
- */
-
-static int managed_evdev_take_device_fn(sd_bus *bus,
-                                        sd_bus_message *reply,
-                                        void *userdata,
-                                        sd_bus_error *ret_error) {
-        managed_evdev *em = userdata;
-        idev_element *e = &em->evdev.element;
-        idev_session *s = e->session;
-        int r, paused, fd;
-
-        em->slot_take_device = sd_bus_slot_unref(em->slot_take_device);
-
-        if (sd_bus_message_is_method_error(reply, NULL)) {
-                const sd_bus_error *error = sd_bus_message_get_error(reply);
-
-                log_debug("idev-evdev: %s/%s: TakeDevice failed: %s: %s",
-                          s->name, e->name, error->name, error->message);
-                return 0;
-        }
-
-        em->acquired = true;
-
-        r = sd_bus_message_read(reply, "hb", &fd, &paused);
-        if (r < 0) {
-                log_debug("idev-evdev: %s/%s: erroneous TakeDevice reply", s->name, e->name);
-                return 0;
-        }
-
-        /* If the device is paused, ignore it; we will get the next fd via
-         * ResumeDevice signals. */
-        if (paused)
-                return 0;
-
-        fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
-        if (fd < 0) {
-                log_debug_errno(errno, "idev-evdev: %s/%s: cannot duplicate evdev fd: %m", s->name, e->name);
-                return 0;
-        }
-
-        r = idev_evdev_resume(&em->evdev, fd);
-        if (r < 0)
-                log_debug_errno(r, "idev-evdev: %s/%s: cannot resume: %m",
-                                s->name, e->name);
-
-        return 0;
-}
-
-static void managed_evdev_enable(idev_element *e) {
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        managed_evdev *em = managed_evdev_from_element(e);
-        idev_session *s = e->session;
-        idev_context *c = s->context;
-        int r;
-
-        /*
-         * Acquiring managed devices is heavy, so do it only once we're
-         * enabled *and* opened by someone.
-         */
-        if (e->n_open < 1 || !e->enabled)
-                return;
-
-        /* bail out if already pending */
-        if (em->requested)
-                return;
-
-        r = sd_bus_message_new_method_call(c->sysbus,
-                                           &m,
-                                           "org.freedesktop.login1",
-                                           s->path,
-                                           "org.freedesktop.login1.Session",
-                                           "TakeDevice");
-        if (r < 0)
-                goto error;
-
-        r = sd_bus_message_append(m, "uu", major(em->devnum), minor(em->devnum));
-        if (r < 0)
-                goto error;
-
-        r = sd_bus_call_async(c->sysbus,
-                              &em->slot_take_device,
-                              m,
-                              managed_evdev_take_device_fn,
-                              em,
-                              0);
-        if (r < 0)
-                goto error;
-
-        em->requested = true;
-        return;
-
-error:
-        log_debug_errno(r, "idev-evdev: %s/%s: cannot send TakeDevice request: %m",
-                        s->name, e->name);
-}
-
-static void managed_evdev_disable(idev_element *e) {
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        managed_evdev *em = managed_evdev_from_element(e);
-        idev_session *s = e->session;
-        idev_context *c = s->context;
-        int r;
-
-        /*
-         * Releasing managed devices is heavy. Once acquired, we get
-         * notifications for sleep/wake-up events, so there's no reason to
-         * release it if disabled but opened. However, if a device is closed,
-         * we release it immediately as we don't care for sleep/wake-up events
-         * then (even if we're actually enabled).
-         */
-
-        idev_evdev_pause(&em->evdev, false);
-
-        if (e->n_open > 0 || !em->requested)
-                return;
-
-        /*
-         * If TakeDevice() is pending or was successful, make sure to
-         * release the device again. We don't care for return-values,
-         * so send it without waiting or callbacks.
-         * If a failed TakeDevice() is pending, but someone else took
-         * the device on the same bus-connection, we might incorrectly
-         * release their device. This is an unlikely race, though.
-         * Furthermore, you really shouldn't have two users of the
-         * controller-API on the same session, on the same devices, *AND* on
-         * the same bus-connection. So we don't care for that race..
-         */
-
-        idev_evdev_pause(&em->evdev, true);
-        em->requested = false;
-
-        if (!em->acquired && !em->slot_take_device)
-                return;
-
-        em->slot_take_device = sd_bus_slot_unref(em->slot_take_device);
-        em->acquired = false;
-
-        r = sd_bus_message_new_method_call(c->sysbus,
-                                           &m,
-                                           "org.freedesktop.login1",
-                                           s->path,
-                                           "org.freedesktop.login1.Session",
-                                           "ReleaseDevice");
-        if (r >= 0) {
-                r = sd_bus_message_append(m, "uu", major(em->devnum), minor(em->devnum));
-                if (r >= 0)
-                        r = sd_bus_send(c->sysbus, m, NULL);
-        }
-
-        if (r < 0 && r != -ENOTCONN)
-                log_debug_errno(r, "idev-evdev: %s/%s: cannot send ReleaseDevice: %m",
-                                s->name, e->name);
-}
-
-static void managed_evdev_resume(idev_element *e, int fd) {
-        managed_evdev *em = managed_evdev_from_element(e);
-        idev_session *s = e->session;
-        int r;
-
-        /*
-         * We get ResumeDevice signals whenever logind resumed a previously
-         * paused device. The arguments contain the major/minor number of the
-         * related device and a new file-descriptor for the freshly opened
-         * device-node. We take the file-descriptor and immediately resume the
-         * device.
-         */
-
-        fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
-        if (fd < 0) {
-                log_debug_errno(errno, "idev-evdev: %s/%s: cannot duplicate evdev fd: %m",
-                                s->name, e->name);
-                return;
-        }
-
-        r = idev_evdev_resume(&em->evdev, fd);
-        if (r < 0)
-                log_debug_errno(r, "idev-evdev: %s/%s: cannot resume: %m",
-                                s->name, e->name);
-
-        return;
-}
-
-static void managed_evdev_pause(idev_element *e, const char *mode) {
-        managed_evdev *em = managed_evdev_from_element(e);
-        idev_session *s = e->session;
-        idev_context *c = s->context;
-        int r;
-
-        /*
-         * We get PauseDevice() signals from logind whenever a device we
-         * requested was, or is about to be, paused. Arguments are major/minor
-         * number of the device and the mode of the operation.
-         * We treat it as asynchronous access-revocation (as if we got HUP on
-         * the device fd). Note that we might have already treated the HUP
-         * event via EPOLLHUP, whichever comes first.
-         *
-         * @mode can be one of the following:
-         *   "pause": The device is about to be paused. We must react
-         *            immediately and respond with PauseDeviceComplete(). Once
-         *            we replied, logind will pause the device. Note that
-         *            logind might apply any kind of timeout and force pause
-         *            the device if we don't respond in a timely manner. In
-         *            this case, we will receive a second PauseDevice event
-         *            with @mode set to "force" (or similar).
-         *   "force": The device was disabled forecfully by logind. Access is
-         *            already revoked. This is just an asynchronous
-         *            notification so we can put the device asleep (in case
-         *            we didn't already notice the access revocation).
-         *    "gone": This is like "force" but is sent if the device was
-         *            paused due to a device-removal event.
-         *
-         * We always handle PauseDevice signals as "force" as we properly
-         * support asynchronous access revocation, anyway. But in case logind
-         * sent mode "pause", we also call PauseDeviceComplete() to immediately
-         * acknowledge the request.
-         */
-
-        idev_evdev_pause(&em->evdev, true);
-
-        if (streq(mode, "pause")) {
-                _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-
-                /*
-                 * Sending PauseDeviceComplete() is racy if logind triggers the
-                 * timeout. That is, if we take too long and logind pauses the
-                 * device by sending a forced PauseDevice, our
-                 * PauseDeviceComplete call will be stray. That's fine, though.
-                 * logind ignores such stray calls. Only if logind also sent a
-                 * further PauseDevice() signal, it might match our call
-                 * incorrectly to the newer PauseDevice(). That's fine, too, as
-                 * we handle that event asynchronously, anyway. Therefore,
-                 * whatever happens, we're fine. Yay!
-                 */
-
-                r = sd_bus_message_new_method_call(c->sysbus,
-                                                   &m,
-                                                   "org.freedesktop.login1",
-                                                   s->path,
-                                                   "org.freedesktop.login1.Session",
-                                                   "PauseDeviceComplete");
-                if (r >= 0) {
-                        r = sd_bus_message_append(m, "uu", major(em->devnum), minor(em->devnum));
-                        if (r >= 0)
-                                r = sd_bus_send(c->sysbus, m, NULL);
-                }
-
-                if (r < 0)
-                        log_debug_errno(r, "idev-evdev: %s/%s: cannot send PauseDeviceComplete: %m",
-                                        s->name, e->name);
-        }
-}
-
-static int managed_evdev_new(idev_element **out, idev_session *s, struct udev_device *ud) {
-        _cleanup_(idev_element_freep) idev_element *e = NULL;
-        char name[IDEV_EVDEV_NAME_MAX];
-        managed_evdev *em;
-        dev_t devnum;
-        int r;
-
-        assert_return(s, -EINVAL);
-        assert_return(s->managed, -EINVAL);
-        assert_return(s->context->sysbus, -EINVAL);
-        assert_return(ud, -EINVAL);
-
-        devnum = udev_device_get_devnum(ud);
-        if (devnum == 0)
-                return -ENODEV;
-
-        idev_evdev_name(name, devnum);
-
-        em = new0(managed_evdev, 1);
-        if (!em)
-                return -ENOMEM;
-
-        e = &em->evdev.element;
-        em->evdev = IDEV_EVDEV_INIT(&managed_evdev_vtable, s);
-        em->devnum = devnum;
-
-        r = idev_element_add(e, name);
-        if (r < 0)
-                return r;
-
-        if (out)
-                *out = e;
-        e = NULL;
-        return 0;
-}
-
-static void managed_evdev_free(idev_element *e) {
-        managed_evdev *em = managed_evdev_from_element(e);
-
-        idev_evdev_destroy(&em->evdev);
-        free(em);
-}
-
-static const idev_element_vtable managed_evdev_vtable = {
-        .free                   = managed_evdev_free,
-        .enable                 = managed_evdev_enable,
-        .disable                = managed_evdev_disable,
-        .open                   = managed_evdev_enable,
-        .close                  = managed_evdev_disable,
-        .resume                 = managed_evdev_resume,
-        .pause                  = managed_evdev_pause,
-};
-
-/*
- * Generic Constructor
- * Instead of relying on the caller to choose between managed and unmanaged
- * evdev devices, the idev_evdev_new() constructor does that for you (by
- * looking at s->managed).
- */
-
-bool idev_is_evdev(idev_element *e) {
-        return e && (e->vtable == &unmanaged_evdev_vtable ||
-                     e->vtable == &managed_evdev_vtable);
-}
-
-idev_element *idev_find_evdev(idev_session *s, dev_t devnum) {
-        char name[IDEV_EVDEV_NAME_MAX];
-
-        assert_return(s, NULL);
-        assert_return(devnum != 0, NULL);
-
-        idev_evdev_name(name, devnum);
-        return idev_find_element(s, name);
-}
-
-int idev_evdev_new(idev_element **out, idev_session *s, struct udev_device *ud) {
-        assert_return(s, -EINVAL);
-        assert_return(ud, -EINVAL);
-
-        return s->managed ? managed_evdev_new(out, s, ud) : unmanaged_evdev_new(out, s, ud);
-}
diff --git a/src/libsystemd-terminal/idev-internal.h b/src/libsystemd-terminal/idev-internal.h
deleted file mode 100644 (file)
index a159aef..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#pragma once
-
-#include <inttypes.h>
-#include <libudev.h>
-#include <linux/input.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <systemd/sd-bus.h>
-#include <systemd/sd-event.h>
-#include <xkbcommon/xkbcommon.h>
-#include "hashmap.h"
-#include "idev.h"
-#include "list.h"
-#include "util.h"
-
-typedef struct idev_link                idev_link;
-typedef struct idev_device_vtable       idev_device_vtable;
-typedef struct idev_element             idev_element;
-typedef struct idev_element_vtable      idev_element_vtable;
-
-/*
- * Evdev Elements
- */
-
-bool idev_is_evdev(idev_element *e);
-idev_element *idev_find_evdev(idev_session *s, dev_t devnum);
-int idev_evdev_new(idev_element **out, idev_session *s, struct udev_device *ud);
-
-/*
- * Keyboard Devices
- */
-
-bool idev_is_keyboard(idev_device *d);
-idev_device *idev_find_keyboard(idev_session *s, const char *name);
-int idev_keyboard_new(idev_device **out, idev_session *s, const char *name);
-
-/*
- * Element Links
- */
-
-struct idev_link {
-        /* element-to-device connection */
-        LIST_FIELDS(idev_link, links_by_element);
-        idev_element *element;
-
-        /* device-to-element connection */
-        LIST_FIELDS(idev_link, links_by_device);
-        idev_device *device;
-};
-
-/*
- * Devices
- */
-
-struct idev_device_vtable {
-        void (*free) (idev_device *d);
-        void (*attach) (idev_device *d, idev_link *l);
-        void (*detach) (idev_device *d, idev_link *l);
-        int (*feed) (idev_device *d, idev_data *data);
-};
-
-struct idev_device {
-        const idev_device_vtable *vtable;
-        idev_session *session;
-        char *name;
-
-        LIST_HEAD(idev_link, links);
-
-        bool public : 1;
-        bool enabled : 1;
-};
-
-#define IDEV_DEVICE_INIT(_vtable, _session) ((idev_device){ \
-                .vtable = (_vtable), \
-                .session = (_session), \
-        })
-
-idev_device *idev_find_device(idev_session *s, const char *name);
-
-int idev_device_add(idev_device *d, const char *name);
-idev_device *idev_device_free(idev_device *d);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(idev_device*, idev_device_free);
-
-int idev_device_feed(idev_device *d, idev_data *data);
-void idev_device_feedback(idev_device *d, idev_data *data);
-
-/*
- * Elements
- */
-
-struct idev_element_vtable {
-        void (*free) (idev_element *e);
-        void (*enable) (idev_element *e);
-        void (*disable) (idev_element *e);
-        void (*open) (idev_element *e);
-        void (*close) (idev_element *e);
-        void (*resume) (idev_element *e, int fd);
-        void (*pause) (idev_element *e, const char *mode);
-        void (*feedback) (idev_element *e, idev_data *data);
-};
-
-struct idev_element {
-        const idev_element_vtable *vtable;
-        idev_session *session;
-        unsigned long n_open;
-        char *name;
-
-        LIST_HEAD(idev_link, links);
-
-        bool enabled : 1;
-        bool readable : 1;
-        bool writable : 1;
-};
-
-#define IDEV_ELEMENT_INIT(_vtable, _session) ((idev_element){ \
-                .vtable = (_vtable), \
-                .session = (_session), \
-        })
-
-idev_element *idev_find_element(idev_session *s, const char *name);
-
-int idev_element_add(idev_element *e, const char *name);
-idev_element *idev_element_free(idev_element *e);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(idev_element*, idev_element_free);
-
-int idev_element_feed(idev_element *e, idev_data *data);
-void idev_element_feedback(idev_element *e, idev_data *data);
-
-/*
- * Sessions
- */
-
-struct idev_session {
-        idev_context *context;
-        char *name;
-        char *path;
-        sd_bus_slot *slot_resume_device;
-        sd_bus_slot *slot_pause_device;
-
-        Hashmap *element_map;
-        Hashmap *device_map;
-
-        idev_event_fn event_fn;
-        void *userdata;
-
-        bool custom : 1;
-        bool managed : 1;
-        bool enabled : 1;
-};
-
-idev_session *idev_find_session(idev_context *c, const char *name);
-int idev_session_raise_device_data(idev_session *s, idev_device *d, idev_data *data);
-
-/*
- * Contexts
- */
-
-struct idev_context {
-        unsigned long ref;
-        sd_event *event;
-        sd_bus *sysbus;
-
-        Hashmap *session_map;
-        Hashmap *data_map;
-};
diff --git a/src/libsystemd-terminal/idev-keyboard.c b/src/libsystemd-terminal/idev-keyboard.c
deleted file mode 100644 (file)
index f90f1b5..0000000
+++ /dev/null
@@ -1,1160 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-#include <stdlib.h>
-#include <systemd/sd-bus.h>
-#include <systemd/sd-event.h>
-#include <xkbcommon/xkbcommon.h>
-#include <xkbcommon/xkbcommon-compose.h>
-#include "bus-util.h"
-#include "hashmap.h"
-#include "idev.h"
-#include "idev-internal.h"
-#include "macro.h"
-#include "term-internal.h"
-#include "util.h"
-
-typedef struct kbdtbl kbdtbl;
-typedef struct kbdmap kbdmap;
-typedef struct kbdctx kbdctx;
-typedef struct idev_keyboard idev_keyboard;
-
-struct kbdtbl {
-        unsigned long ref;
-        struct xkb_compose_table *xkb_compose_table;
-};
-
-struct kbdmap {
-        unsigned long ref;
-        struct xkb_keymap *xkb_keymap;
-        xkb_mod_index_t modmap[IDEV_KBDMOD_CNT];
-        xkb_led_index_t ledmap[IDEV_KBDLED_CNT];
-};
-
-struct kbdctx {
-        unsigned long ref;
-        idev_context *context;
-        struct xkb_context *xkb_context;
-        struct kbdmap *kbdmap;
-        struct kbdtbl *kbdtbl;
-
-        sd_bus_slot *slot_locale_props_changed;
-        sd_bus_slot *slot_locale_get_all;
-
-        char *locale_lang;
-        char *locale_x11_model;
-        char *locale_x11_layout;
-        char *locale_x11_variant;
-        char *locale_x11_options;
-        char *last_x11_model;
-        char *last_x11_layout;
-        char *last_x11_variant;
-        char *last_x11_options;
-};
-
-struct idev_keyboard {
-        idev_device device;
-        kbdctx *kbdctx;
-        kbdmap *kbdmap;
-        kbdtbl *kbdtbl;
-
-        struct xkb_state *xkb_state;
-        struct xkb_compose_state *xkb_compose;
-
-        usec_t repeat_delay;
-        usec_t repeat_rate;
-        sd_event_source *repeat_timer;
-
-        uint32_t n_syms;
-        idev_data evdata;
-        idev_data repdata;
-        uint32_t *compose_res;
-
-        bool repeating : 1;
-};
-
-#define keyboard_from_device(_d) container_of((_d), idev_keyboard, device)
-
-#define KBDCTX_KEY "keyboard.context"           /* hashmap key for global kbdctx */
-#define KBDXKB_SHIFT (8)                        /* xkb shifts evdev key-codes by 8 */
-#define KBDKEY_UP (0)                           /* KEY UP event value */
-#define KBDKEY_DOWN (1)                         /* KEY DOWN event value */
-#define KBDKEY_REPEAT (2)                       /* KEY REPEAT event value */
-
-static const idev_device_vtable keyboard_vtable;
-
-static int keyboard_update_kbdmap(idev_keyboard *k);
-static int keyboard_update_kbdtbl(idev_keyboard *k);
-
-/*
- * Keyboard Compose Tables
- */
-
-static kbdtbl *kbdtbl_ref(kbdtbl *kt) {
-        if (kt) {
-                assert_return(kt->ref > 0, NULL);
-                ++kt->ref;
-        }
-
-        return kt;
-}
-
-static kbdtbl *kbdtbl_unref(kbdtbl *kt) {
-        if (!kt)
-                return NULL;
-
-        assert_return(kt->ref > 0, NULL);
-
-        if (--kt->ref > 0)
-                return NULL;
-
-        xkb_compose_table_unref(kt->xkb_compose_table);
-        free(kt);
-
-        return 0;
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(kbdtbl*, kbdtbl_unref);
-
-static int kbdtbl_new_from_locale(kbdtbl **out, kbdctx *kc, const char *locale) {
-        _cleanup_(kbdtbl_unrefp) kbdtbl *kt = NULL;
-
-        assert_return(out, -EINVAL);
-        assert_return(locale, -EINVAL);
-
-        kt = new0(kbdtbl, 1);
-        if (!kt)
-                return -ENOMEM;
-
-        kt->ref = 1;
-
-        kt->xkb_compose_table = xkb_compose_table_new_from_locale(kc->xkb_context,
-                                                                  locale,
-                                                                  XKB_COMPOSE_COMPILE_NO_FLAGS);
-        if (!kt->xkb_compose_table)
-                return errno > 0 ? -errno : -EFAULT;
-
-        *out = kt;
-        kt = NULL;
-        return 0;
-}
-
-/*
- * Keyboard Keymaps
- */
-
-static const char * const kbdmap_modmap[IDEV_KBDMOD_CNT] = {
-        [IDEV_KBDMOD_IDX_SHIFT]                 = XKB_MOD_NAME_SHIFT,
-        [IDEV_KBDMOD_IDX_CTRL]                  = XKB_MOD_NAME_CTRL,
-        [IDEV_KBDMOD_IDX_ALT]                   = XKB_MOD_NAME_ALT,
-        [IDEV_KBDMOD_IDX_LINUX]                 = XKB_MOD_NAME_LOGO,
-        [IDEV_KBDMOD_IDX_CAPS]                  = XKB_MOD_NAME_CAPS,
-};
-
-static const char * const kbdmap_ledmap[IDEV_KBDLED_CNT] = {
-        [IDEV_KBDLED_IDX_NUM]                   = XKB_LED_NAME_NUM,
-        [IDEV_KBDLED_IDX_CAPS]                  = XKB_LED_NAME_CAPS,
-        [IDEV_KBDLED_IDX_SCROLL]                = XKB_LED_NAME_SCROLL,
-};
-
-static kbdmap *kbdmap_ref(kbdmap *km) {
-        assert_return(km, NULL);
-        assert_return(km->ref > 0, NULL);
-
-        ++km->ref;
-        return km;
-}
-
-static kbdmap *kbdmap_unref(kbdmap *km) {
-        if (!km)
-                return NULL;
-
-        assert_return(km->ref > 0, NULL);
-
-        if (--km->ref > 0)
-                return NULL;
-
-        xkb_keymap_unref(km->xkb_keymap);
-        free(km);
-
-        return 0;
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(kbdmap*, kbdmap_unref);
-
-static int kbdmap_new_from_names(kbdmap **out,
-                                 kbdctx *kc,
-                                 const char *model,
-                                 const char *layout,
-                                 const char *variant,
-                                 const char *options) {
-        _cleanup_(kbdmap_unrefp) kbdmap *km = NULL;
-        struct xkb_rule_names rmlvo = { };
-        unsigned int i;
-
-        assert_return(out, -EINVAL);
-
-        km = new0(kbdmap, 1);
-        if (!km)
-                return -ENOMEM;
-
-        km->ref = 1;
-
-        rmlvo.rules = "evdev";
-        rmlvo.model = model;
-        rmlvo.layout = layout;
-        rmlvo.variant = variant;
-        rmlvo.options = options;
-
-        errno = 0;
-        km->xkb_keymap = xkb_keymap_new_from_names(kc->xkb_context, &rmlvo, 0);
-        if (!km->xkb_keymap)
-                return errno > 0 ? -errno : -EFAULT;
-
-        for (i = 0; i < IDEV_KBDMOD_CNT; ++i) {
-                const char *t = kbdmap_modmap[i];
-
-                if (t)
-                        km->modmap[i] = xkb_keymap_mod_get_index(km->xkb_keymap, t);
-                else
-                        km->modmap[i] = XKB_MOD_INVALID;
-        }
-
-        for (i = 0; i < IDEV_KBDLED_CNT; ++i) {
-                const char *t = kbdmap_ledmap[i];
-
-                if (t)
-                        km->ledmap[i] = xkb_keymap_led_get_index(km->xkb_keymap, t);
-                else
-                        km->ledmap[i] = XKB_LED_INVALID;
-        }
-
-        *out = km;
-        km = NULL;
-        return 0;
-}
-
-/*
- * Keyboard Context
- */
-
-static int kbdctx_refresh_compose_table(kbdctx *kc, const char *lang) {
-        kbdtbl *kt;
-        idev_session *s;
-        idev_device *d;
-        Iterator i, j;
-        int r;
-
-        if (!lang)
-                lang = "C";
-
-        if (streq_ptr(kc->locale_lang, lang))
-                return 0;
-
-        r = free_and_strdup(&kc->locale_lang, lang);
-        if (r < 0)
-                return r;
-
-        log_debug("idev-keyboard: new default compose table: [ %s ]", lang);
-
-        r = kbdtbl_new_from_locale(&kt, kc, lang);
-        if (r < 0) {
-                /* TODO: We need to catch the case where no compose-file is
-                 * available. xkb doesn't tell us so far.. so we must not treat
-                 * it as a hard-failure but just continue. Preferably, we want
-                 * xkb to tell us exactly whether compilation failed or whether
-                 * there is no compose file available for this locale. */
-                log_debug_errno(r, "idev-keyboard: cannot load compose-table for '%s': %m",
-                                lang);
-                r = 0;
-                kt = NULL;
-        }
-
-        kbdtbl_unref(kc->kbdtbl);
-        kc->kbdtbl = kt;
-
-        HASHMAP_FOREACH(s, kc->context->session_map, i)
-                HASHMAP_FOREACH(d, s->device_map, j)
-                        if (idev_is_keyboard(d))
-                                keyboard_update_kbdtbl(keyboard_from_device(d));
-
-        return 0;
-}
-
-static void move_str(char **dest, char **src) {
-        free(*dest);
-        *dest = *src;
-        *src = NULL;
-}
-
-static int kbdctx_refresh_keymap(kbdctx *kc) {
-        idev_session *s;
-        idev_device *d;
-        Iterator i, j;
-        kbdmap *km;
-        int r;
-
-        if (kc->kbdmap &&
-            streq_ptr(kc->locale_x11_model, kc->last_x11_model) &&
-            streq_ptr(kc->locale_x11_layout, kc->last_x11_layout) &&
-            streq_ptr(kc->locale_x11_variant, kc->last_x11_variant) &&
-            streq_ptr(kc->locale_x11_options, kc->last_x11_options))
-                return 0 ;
-
-        move_str(&kc->last_x11_model, &kc->locale_x11_model);
-        move_str(&kc->last_x11_layout, &kc->locale_x11_layout);
-        move_str(&kc->last_x11_variant, &kc->locale_x11_variant);
-        move_str(&kc->last_x11_options, &kc->locale_x11_options);
-
-        log_debug("idev-keyboard: new default keymap: [%s / %s / %s / %s]",
-                  kc->last_x11_model, kc->last_x11_layout, kc->last_x11_variant, kc->last_x11_options);
-
-        /* TODO: add a fallback keymap that's compiled-in */
-        r = kbdmap_new_from_names(&km, kc, kc->last_x11_model, kc->last_x11_layout,
-                                  kc->last_x11_variant, kc->last_x11_options);
-        if (r < 0)
-                return log_debug_errno(r, "idev-keyboard: cannot create keymap from locale1: %m");
-
-        kbdmap_unref(kc->kbdmap);
-        kc->kbdmap = km;
-
-        HASHMAP_FOREACH(s, kc->context->session_map, i)
-                HASHMAP_FOREACH(d, s->device_map, j)
-                        if (idev_is_keyboard(d))
-                                keyboard_update_kbdmap(keyboard_from_device(d));
-
-        return 0;
-}
-
-static int kbdctx_set_locale(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
-        kbdctx *kc = userdata;
-        const char *s, *ctype = NULL, *lang = NULL;
-        int r;
-
-        r = sd_bus_message_enter_container(m, 'a', "s");
-        if (r < 0)
-                goto error;
-
-        while ((r = sd_bus_message_read(m, "s", &s)) > 0) {
-                if (!ctype)
-                        ctype = startswith(s, "LC_CTYPE=");
-                if (!lang)
-                        lang = startswith(s, "LANG=");
-        }
-
-        if (r < 0)
-                goto error;
-
-        r = sd_bus_message_exit_container(m);
-        if (r < 0)
-                goto error;
-
-        kbdctx_refresh_compose_table(kc, ctype ? : lang);
-        r = 0;
-
-error:
-        if (r < 0)
-                log_debug_errno(r, "idev-keyboard: cannot parse locale property from locale1: %m");
-
-        return r;
-}
-
-static const struct bus_properties_map kbdctx_locale_map[] = {
-        { "Locale",     "as",   kbdctx_set_locale, 0 },
-        { "X11Model",   "s",    NULL, offsetof(kbdctx, locale_x11_model) },
-        { "X11Layout",  "s",    NULL, offsetof(kbdctx, locale_x11_layout) },
-        { "X11Variant", "s",    NULL, offsetof(kbdctx, locale_x11_variant) },
-        { "X11Options", "s",    NULL, offsetof(kbdctx, locale_x11_options) },
-};
-
-static int kbdctx_locale_get_all_fn(sd_bus *bus,
-                                    sd_bus_message *m,
-                                    void *userdata,
-                                    sd_bus_error *ret_err) {
-        kbdctx *kc = userdata;
-        int r;
-
-        kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all);
-
-        if (sd_bus_message_is_method_error(m, NULL)) {
-                const sd_bus_error *error = sd_bus_message_get_error(m);
-
-                log_debug("idev-keyboard: GetAll() on locale1 failed: %s: %s",
-                          error->name, error->message);
-                return 0;
-        }
-
-        r = bus_message_map_all_properties(bus, m, kbdctx_locale_map, kc);
-        if (r < 0) {
-                log_debug("idev-keyboard: erroneous GetAll() reply from locale1");
-                return 0;
-        }
-
-        kbdctx_refresh_keymap(kc);
-        return 0;
-}
-
-static int kbdctx_query_locale(kbdctx *kc) {
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        int r;
-
-        kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all);
-
-        r = sd_bus_message_new_method_call(kc->context->sysbus,
-                                           &m,
-                                           "org.freedesktop.locale1",
-                                           "/org/freedesktop/locale1",
-                                           "org.freedesktop.DBus.Properties",
-                                           "GetAll");
-        if (r < 0)
-                goto error;
-
-        r = sd_bus_message_append(m, "s", "org.freedesktop.locale1");
-        if (r < 0)
-                goto error;
-
-        r = sd_bus_call_async(kc->context->sysbus,
-                              &kc->slot_locale_get_all,
-                              m,
-                              kbdctx_locale_get_all_fn,
-                              kc,
-                              0);
-        if (r < 0)
-                goto error;
-
-        return 0;
-
-error:
-        return log_debug_errno(r, "idev-keyboard: cannot send GetAll to locale1: %m");
-}
-
-static int kbdctx_locale_props_changed_fn(sd_bus *bus,
-                                          sd_bus_message *signal,
-                                          void *userdata,
-                                          sd_bus_error *ret_err) {
-        kbdctx *kc = userdata;
-        int r;
-
-        kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all);
-
-        /* skip interface name */
-        r = sd_bus_message_skip(signal, "s");
-        if (r < 0)
-                goto error;
-
-        r = bus_message_map_properties_changed(bus, signal, kbdctx_locale_map, kc);
-        if (r < 0)
-                goto error;
-
-        if (r > 0) {
-                r = kbdctx_query_locale(kc);
-                if (r < 0)
-                        return r;
-        }
-
-        kbdctx_refresh_keymap(kc);
-        return 0;
-
-error:
-        return log_debug_errno(r, "idev-keyboard: cannot handle PropertiesChanged from locale1: %m");
-}
-
-static int kbdctx_setup_bus(kbdctx *kc) {
-        int r;
-
-        r = sd_bus_add_match(kc->context->sysbus,
-                             &kc->slot_locale_props_changed,
-                             "type='signal',"
-                             "sender='org.freedesktop.locale1',"
-                             "interface='org.freedesktop.DBus.Properties',"
-                             "member='PropertiesChanged',"
-                             "path='/org/freedesktop/locale1'",
-                             kbdctx_locale_props_changed_fn,
-                             kc);
-        if (r < 0)
-                return log_debug_errno(r, "idev-keyboard: cannot setup locale1 link: %m");
-
-        return kbdctx_query_locale(kc);
-}
-
-static void kbdctx_log_fn(struct xkb_context *ctx, enum xkb_log_level lvl, const char *format, va_list args) {
-        char buf[LINE_MAX];
-        int sd_lvl;
-
-        if (lvl >= XKB_LOG_LEVEL_DEBUG)
-                sd_lvl = LOG_DEBUG;
-        else if (lvl >= XKB_LOG_LEVEL_INFO)
-                sd_lvl = LOG_INFO;
-        else if (lvl >= XKB_LOG_LEVEL_WARNING)
-                sd_lvl = LOG_INFO; /* most XKB warnings really are informational */
-        else
-                /* XKB_LOG_LEVEL_ERROR and worse */
-                sd_lvl = LOG_ERR;
-
-        snprintf(buf, sizeof(buf), "idev-xkb: %s", format);
-        log_internalv(sd_lvl, 0, __FILE__, __LINE__, __func__, buf, args);
-}
-
-static kbdctx *kbdctx_ref(kbdctx *kc) {
-        assert_return(kc, NULL);
-        assert_return(kc->ref > 0, NULL);
-
-        ++kc->ref;
-        return kc;
-}
-
-static kbdctx *kbdctx_unref(kbdctx *kc) {
-        if (!kc)
-                return NULL;
-
-        assert_return(kc->ref > 0, NULL);
-
-        if (--kc->ref > 0)
-                return NULL;
-
-        free(kc->last_x11_options);
-        free(kc->last_x11_variant);
-        free(kc->last_x11_layout);
-        free(kc->last_x11_model);
-        free(kc->locale_x11_options);
-        free(kc->locale_x11_variant);
-        free(kc->locale_x11_layout);
-        free(kc->locale_x11_model);
-        free(kc->locale_lang);
-        kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all);
-        kc->slot_locale_props_changed = sd_bus_slot_unref(kc->slot_locale_props_changed);
-        kc->kbdtbl = kbdtbl_unref(kc->kbdtbl);
-        kc->kbdmap = kbdmap_unref(kc->kbdmap);
-        xkb_context_unref(kc->xkb_context);
-        hashmap_remove_value(kc->context->data_map, KBDCTX_KEY, kc);
-        free(kc);
-
-        return NULL;
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(kbdctx*, kbdctx_unref);
-
-static int kbdctx_new(kbdctx **out, idev_context *c) {
-        _cleanup_(kbdctx_unrefp) kbdctx *kc = NULL;
-        int r;
-
-        assert_return(out, -EINVAL);
-        assert_return(c, -EINVAL);
-
-        kc = new0(kbdctx, 1);
-        if (!kc)
-                return -ENOMEM;
-
-        kc->ref = 1;
-        kc->context = c;
-
-        errno = 0;
-        kc->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
-        if (!kc->xkb_context)
-                return errno > 0 ? -errno : -EFAULT;
-
-        xkb_context_set_log_fn(kc->xkb_context, kbdctx_log_fn);
-        xkb_context_set_log_level(kc->xkb_context, XKB_LOG_LEVEL_DEBUG);
-
-        r = kbdctx_refresh_keymap(kc);
-        if (r < 0)
-                return r;
-
-        r = kbdctx_refresh_compose_table(kc, NULL);
-        if (r < 0)
-                return r;
-
-        if (c->sysbus) {
-                r = kbdctx_setup_bus(kc);
-                if (r < 0)
-                        return r;
-        }
-
-        r = hashmap_put(c->data_map, KBDCTX_KEY, kc);
-        if (r < 0)
-                return r;
-
-        *out = kc;
-        kc = NULL;
-        return 0;
-}
-
-static int get_kbdctx(idev_context *c, kbdctx **out) {
-        kbdctx *kc;
-
-        assert_return(c, -EINVAL);
-        assert_return(out, -EINVAL);
-
-        kc = hashmap_get(c->data_map, KBDCTX_KEY);
-        if (kc) {
-                *out = kbdctx_ref(kc);
-                return 0;
-        }
-
-        return kbdctx_new(out, c);
-}
-
-/*
- * Keyboard Devices
- */
-
-bool idev_is_keyboard(idev_device *d) {
-        return d && d->vtable == &keyboard_vtable;
-}
-
-idev_device *idev_find_keyboard(idev_session *s, const char *name) {
-        char *kname;
-
-        assert_return(s, NULL);
-        assert_return(name, NULL);
-
-        kname = strjoina("keyboard/", name);
-        return hashmap_get(s->device_map, kname);
-}
-
-static int keyboard_raise_data(idev_keyboard *k, idev_data *data) {
-        idev_device *d = &k->device;
-        int r;
-
-        r = idev_session_raise_device_data(d->session, d, data);
-        if (r < 0)
-                log_debug_errno(r, "idev-keyboard: %s/%s: error while raising data event: %m",
-                                d->session->name, d->name);
-
-        return r;
-}
-
-static int keyboard_resize_bufs(idev_keyboard *k, uint32_t n_syms) {
-        uint32_t *t;
-
-        if (n_syms <= k->n_syms)
-                return 0;
-
-        t = realloc(k->compose_res, sizeof(*t) * n_syms);
-        if (!t)
-                return -ENOMEM;
-        k->compose_res = t;
-
-        t = realloc(k->evdata.keyboard.keysyms, sizeof(*t) * n_syms);
-        if (!t)
-                return -ENOMEM;
-        k->evdata.keyboard.keysyms = t;
-
-        t = realloc(k->evdata.keyboard.codepoints, sizeof(*t) * n_syms);
-        if (!t)
-                return -ENOMEM;
-        k->evdata.keyboard.codepoints = t;
-
-        t = realloc(k->repdata.keyboard.keysyms, sizeof(*t) * n_syms);
-        if (!t)
-                return -ENOMEM;
-        k->repdata.keyboard.keysyms = t;
-
-        t = realloc(k->repdata.keyboard.codepoints, sizeof(*t) * n_syms);
-        if (!t)
-                return -ENOMEM;
-        k->repdata.keyboard.codepoints = t;
-
-        k->n_syms = n_syms;
-        return 0;
-}
-
-static unsigned int keyboard_read_compose(idev_keyboard *k, const xkb_keysym_t **out) {
-        _cleanup_free_ char *t = NULL;
-        term_utf8 u8 = { };
-        char buf[256], *p;
-        size_t flen = 0;
-        int i, r;
-
-        r = xkb_compose_state_get_utf8(k->xkb_compose, buf, sizeof(buf));
-        if (r >= (int)sizeof(buf)) {
-                t = malloc(r + 1);
-                if (!t)
-                        return 0;
-
-                xkb_compose_state_get_utf8(k->xkb_compose, t, r + 1);
-                p = t;
-        } else {
-                p = buf;
-        }
-
-        for (i = 0; i < r; ++i) {
-                uint32_t *ucs;
-                size_t len, j;
-
-                len = term_utf8_decode(&u8, &ucs, p[i]);
-                if (len > 0) {
-                        r = keyboard_resize_bufs(k, flen + len);
-                        if (r < 0)
-                                return 0;
-
-                        for (j = 0; j < len; ++j)
-                                k->compose_res[flen++] = ucs[j];
-                }
-        }
-
-        *out = k->compose_res;
-        return flen;
-}
-
-static void keyboard_arm(idev_keyboard *k, usec_t usecs) {
-        int r;
-
-        if (usecs != 0) {
-                usecs += now(CLOCK_MONOTONIC);
-                r = sd_event_source_set_time(k->repeat_timer, usecs);
-                if (r >= 0)
-                        sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_ONESHOT);
-        } else {
-                sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_OFF);
-        }
-}
-
-static int keyboard_repeat_timer_fn(sd_event_source *source, uint64_t usec, void *userdata) {
-        idev_keyboard *k = userdata;
-
-        /* never feed REPEAT keys into COMPOSE */
-
-        keyboard_arm(k, k->repeat_rate);
-        return keyboard_raise_data(k, &k->repdata);
-}
-
-int idev_keyboard_new(idev_device **out, idev_session *s, const char *name) {
-        _cleanup_(idev_device_freep) idev_device *d = NULL;
-        idev_keyboard *k;
-        char *kname;
-        int r;
-
-        assert_return(out, -EINVAL);
-        assert_return(s, -EINVAL);
-        assert_return(name, -EINVAL);
-
-        k = new0(idev_keyboard, 1);
-        if (!k)
-                return -ENOMEM;
-
-        d = &k->device;
-        k->device = IDEV_DEVICE_INIT(&keyboard_vtable, s);
-        k->repeat_delay = 250 * USEC_PER_MSEC;
-        k->repeat_rate = 30 * USEC_PER_MSEC;
-
-        /* TODO: add key-repeat configuration */
-
-        r = get_kbdctx(s->context, &k->kbdctx);
-        if (r < 0)
-                return r;
-
-        r = keyboard_update_kbdmap(k);
-        if (r < 0)
-                return r;
-
-        r = keyboard_update_kbdtbl(k);
-        if (r < 0)
-                return r;
-
-        r = keyboard_resize_bufs(k, 8);
-        if (r < 0)
-                return r;
-
-        r = sd_event_add_time(s->context->event,
-                              &k->repeat_timer,
-                              CLOCK_MONOTONIC,
-                              0,
-                              10 * USEC_PER_MSEC,
-                              keyboard_repeat_timer_fn,
-                              k);
-        if (r < 0)
-                return r;
-
-        r = sd_event_source_set_enabled(k->repeat_timer, SD_EVENT_OFF);
-        if (r < 0)
-                return r;
-
-        kname = strjoina("keyboard/", name);
-        r = idev_device_add(d, kname);
-        if (r < 0)
-                return r;
-
-        if (out)
-                *out = d;
-        d = NULL;
-        return 0;
-}
-
-static void keyboard_free(idev_device *d) {
-        idev_keyboard *k = keyboard_from_device(d);
-
-        xkb_compose_state_unref(k->xkb_compose);
-        xkb_state_unref(k->xkb_state);
-        free(k->repdata.keyboard.codepoints);
-        free(k->repdata.keyboard.keysyms);
-        free(k->evdata.keyboard.codepoints);
-        free(k->evdata.keyboard.keysyms);
-        free(k->compose_res);
-        k->repeat_timer = sd_event_source_unref(k->repeat_timer);
-        k->kbdtbl = kbdtbl_unref(k->kbdtbl);
-        k->kbdmap = kbdmap_unref(k->kbdmap);
-        k->kbdctx = kbdctx_unref(k->kbdctx);
-        free(k);
-}
-
-static int8_t guess_ascii(struct xkb_state *state, uint32_t code, uint32_t n_syms, const uint32_t *syms) {
-        xkb_layout_index_t n_lo, lo;
-        xkb_level_index_t lv;
-        struct xkb_keymap *keymap;
-        const xkb_keysym_t *s;
-        int num;
-
-        if (n_syms == 1 && syms[0] < 128 && syms[0] > 0)
-                return syms[0];
-
-        keymap = xkb_state_get_keymap(state);
-        n_lo = xkb_keymap_num_layouts_for_key(keymap, code + KBDXKB_SHIFT);
-
-        for (lo = 0; lo < n_lo; ++lo) {
-                lv = xkb_state_key_get_level(state, code + KBDXKB_SHIFT, lo);
-                num = xkb_keymap_key_get_syms_by_level(keymap, code + KBDXKB_SHIFT, lo, lv, &s);
-                if (num == 1 && s[0] < 128 && s[0] > 0)
-                        return s[0];
-        }
-
-        return -1;
-}
-
-static int keyboard_fill(idev_keyboard *k,
-                         idev_data *dst,
-                         bool resync,
-                         uint16_t code,
-                         uint32_t value,
-                         uint32_t n_syms,
-                         const uint32_t *keysyms) {
-        idev_data_keyboard *kev;
-        uint32_t i;
-        int r;
-
-        assert(dst == &k->evdata || dst == &k->repdata);
-
-        r = keyboard_resize_bufs(k, n_syms);
-        if (r < 0)
-                return r;
-
-        dst->type = IDEV_DATA_KEYBOARD;
-        dst->resync = resync;
-        kev = &dst->keyboard;
-        kev->ascii = guess_ascii(k->xkb_state, code, n_syms, keysyms);
-        kev->value = value;
-        kev->keycode = code;
-        kev->mods = 0;
-        kev->consumed_mods = 0;
-        kev->n_syms = n_syms;
-        memcpy(kev->keysyms, keysyms, sizeof(*keysyms) * n_syms);
-
-        for (i = 0; i < n_syms; ++i) {
-                kev->codepoints[i] = xkb_keysym_to_utf32(keysyms[i]);
-                if (!kev->codepoints[i])
-                        kev->codepoints[i] = 0xffffffffUL;
-        }
-
-        for (i = 0; i < IDEV_KBDMOD_CNT; ++i) {
-                if (k->kbdmap->modmap[i] == XKB_MOD_INVALID)
-                        continue;
-
-                r = xkb_state_mod_index_is_active(k->xkb_state, k->kbdmap->modmap[i], XKB_STATE_MODS_EFFECTIVE);
-                if (r > 0)
-                        kev->mods |= 1 << i;
-
-                r = xkb_state_mod_index_is_consumed(k->xkb_state, code + KBDXKB_SHIFT, k->kbdmap->modmap[i]);
-                if (r > 0)
-                        kev->consumed_mods |= 1 << i;
-        }
-
-        return 0;
-}
-
-static void keyboard_repeat(idev_keyboard *k) {
-        idev_data *evdata = &k->evdata;
-        idev_data *repdata = &k->repdata;
-        idev_data_keyboard *evkbd = &evdata->keyboard;
-        idev_data_keyboard *repkbd = &repdata->keyboard;
-        const xkb_keysym_t *keysyms;
-        idev_device *d = &k->device;
-        bool repeats;
-        int r, num;
-
-        if (evdata->resync) {
-                /*
-                 * We received a re-sync event. During re-sync, any number of
-                 * key-events may have been lost and sync-events may be
-                 * re-ordered. Always disable key-repeat for those events. Any
-                 * following event will trigger it again.
-                 */
-
-                k->repeating = false;
-                keyboard_arm(k, 0);
-                return;
-        }
-
-        repeats = xkb_keymap_key_repeats(k->kbdmap->xkb_keymap, evkbd->keycode + KBDXKB_SHIFT);
-
-        if (k->repeating && repkbd->keycode == evkbd->keycode) {
-                /*
-                 * We received an event for the key we currently repeat. If it
-                 * was released, stop key-repeat. Otherwise, ignore the event.
-                 */
-
-                if (evkbd->value == KBDKEY_UP) {
-                        k->repeating = false;
-                        keyboard_arm(k, 0);
-                }
-        } else if (evkbd->value == KBDKEY_DOWN && repeats) {
-                /*
-                 * We received a key-down event for a key that repeats. The
-                 * previous condition caught keys we already repeat, so we know
-                 * this is a different key or no key-repeat is running. Start
-                 * new key-repeat.
-                 */
-
-                errno = 0;
-                num = xkb_state_key_get_syms(k->xkb_state, evkbd->keycode + KBDXKB_SHIFT, &keysyms);
-                if (num < 0)
-                        r = errno > 0 ? errno : -EFAULT;
-                else
-                        r = keyboard_fill(k, repdata, false, evkbd->keycode, KBDKEY_REPEAT, num, keysyms);
-
-                if (r < 0) {
-                        log_debug_errno(r, "idev-keyboard: %s/%s: cannot set key-repeat: %m",
-                                        d->session->name, d->name);
-                        k->repeating = false;
-                        keyboard_arm(k, 0);
-                } else {
-                        k->repeating = true;
-                        keyboard_arm(k, k->repeat_delay);
-                }
-        } else if (k->repeating && !repeats) {
-                /*
-                 * We received an event for a key that does not repeat, but we
-                 * currently repeat a previously received key. The new key is
-                 * usually a modifier, but might be any kind of key. In this
-                 * case, we continue repeating the old key, but update the
-                 * symbols according to the new state.
-                 */
-
-                errno = 0;
-                num = xkb_state_key_get_syms(k->xkb_state, repkbd->keycode + KBDXKB_SHIFT, &keysyms);
-                if (num < 0)
-                        r = errno > 0 ? errno : -EFAULT;
-                else
-                        r = keyboard_fill(k, repdata, false, repkbd->keycode, KBDKEY_REPEAT, num, keysyms);
-
-                if (r < 0) {
-                        log_debug_errno(r, "idev-keyboard: %s/%s: cannot update key-repeat: %m",
-                                        d->session->name, d->name);
-                        k->repeating = false;
-                        keyboard_arm(k, 0);
-                }
-        }
-}
-
-static int keyboard_feed_evdev(idev_keyboard *k, idev_data *data) {
-        struct input_event *ev = &data->evdev.event;
-        enum xkb_state_component compch;
-        enum xkb_compose_status cstatus;
-        const xkb_keysym_t *keysyms;
-        idev_device *d = &k->device;
-        int num, r;
-
-        if (ev->type != EV_KEY || ev->value > KBDKEY_DOWN)
-                return 0;
-
-        /* TODO: We should audit xkb-actions, whether they need @resync as
-         * flag. Most actions should just be executed, however, there might
-         * be actions that depend on modifier-orders. Those should be
-         * suppressed. */
-
-        num = xkb_state_key_get_syms(k->xkb_state, ev->code + KBDXKB_SHIFT, &keysyms);
-        compch = xkb_state_update_key(k->xkb_state, ev->code + KBDXKB_SHIFT, ev->value);
-
-        if (compch & XKB_STATE_LEDS) {
-                /* TODO: update LEDs */
-        }
-
-        if (num < 0) {
-                r = num;
-                goto error;
-        }
-
-        if (k->xkb_compose && ev->value == KBDKEY_DOWN) {
-                if (num == 1 && !data->resync) {
-                        xkb_compose_state_feed(k->xkb_compose, keysyms[0]);
-                        cstatus = xkb_compose_state_get_status(k->xkb_compose);
-                } else {
-                        cstatus = XKB_COMPOSE_CANCELLED;
-                }
-
-                switch (cstatus) {
-                case XKB_COMPOSE_NOTHING:
-                        /* keep produced keysyms and forward unchanged */
-                        break;
-                case XKB_COMPOSE_COMPOSING:
-                        /* consumed by compose-state, drop keysym */
-                        keysyms = NULL;
-                        num = 0;
-                        break;
-                case XKB_COMPOSE_COMPOSED:
-                        /* compose-state produced sth, replace keysym */
-                        num = keyboard_read_compose(k, &keysyms);
-                        xkb_compose_state_reset(k->xkb_compose);
-                        break;
-                case XKB_COMPOSE_CANCELLED:
-                        /* canceled compose, reset, forward cancellation sym */
-                        xkb_compose_state_reset(k->xkb_compose);
-                        break;
-                }
-        } else if (k->xkb_compose &&
-                   num == 1 &&
-                   keysyms[0] == XKB_KEY_Multi_key &&
-                   !data->resync &&
-                   ev->value == KBDKEY_UP) {
-                /* Reset compose state on Multi-Key UP events. This effectively
-                 * requires you to hold the key during the whole sequence. I
-                 * think it's pretty handy to avoid accidental
-                 * Compose-sequences, but this may break Compose for disabled
-                 * people. We really need to make this opional! (TODO) */
-                xkb_compose_state_reset(k->xkb_compose);
-        }
-
-        if (ev->value == KBDKEY_UP) {
-                /* never produce keysyms for UP */
-                keysyms = NULL;
-                num = 0;
-        }
-
-        r = keyboard_fill(k, &k->evdata, data->resync, ev->code, ev->value, num, keysyms);
-        if (r < 0)
-                goto error;
-
-        keyboard_repeat(k);
-        return keyboard_raise_data(k, &k->evdata);
-
-error:
-        log_debug_errno(r, "idev-keyboard: %s/%s: cannot handle event: %m",
-                        d->session->name, d->name);
-        k->repeating = false;
-        keyboard_arm(k, 0);
-        return 0;
-}
-
-static int keyboard_feed(idev_device *d, idev_data *data) {
-        idev_keyboard *k = keyboard_from_device(d);
-
-        switch (data->type) {
-        case IDEV_DATA_RESYNC:
-                /*
-                 * If the underlying device is re-synced, key-events might be
-                 * sent re-ordered. Thus, we don't know which key was pressed
-                 * last. Key-repeat might get confused, hence, disable it
-                 * during re-syncs. The first following event will enable it
-                 * again.
-                 */
-
-                k->repeating = false;
-                keyboard_arm(k, 0);
-                return 0;
-        case IDEV_DATA_EVDEV:
-                return keyboard_feed_evdev(k, data);
-        default:
-                return 0;
-        }
-}
-
-static int keyboard_update_kbdmap(idev_keyboard *k) {
-        idev_device *d = &k->device;
-        struct xkb_state *state;
-        kbdmap *km;
-        int r;
-
-        assert(k);
-
-        km = k->kbdctx->kbdmap;
-        if (km == k->kbdmap)
-                return 0;
-
-        errno = 0;
-        state = xkb_state_new(km->xkb_keymap);
-        if (!state) {
-                r = errno > 0 ? -errno : -EFAULT;
-                goto error;
-        }
-
-        kbdmap_unref(k->kbdmap);
-        k->kbdmap = kbdmap_ref(km);
-        xkb_state_unref(k->xkb_state);
-        k->xkb_state = state;
-
-        /* TODO: On state-change, we should trigger a resync so the whole
-         * event-state is flushed into the new xkb-state. libevdev currently
-         * does not support that, though. */
-
-        return 0;
-
-error:
-        return log_debug_errno(r, "idev-keyboard: %s/%s: cannot adopt new keymap: %m",
-                               d->session->name, d->name);
-}
-
-static int keyboard_update_kbdtbl(idev_keyboard *k) {
-        idev_device *d = &k->device;
-        struct xkb_compose_state *compose = NULL;
-        kbdtbl *kt;
-        int r;
-
-        assert(k);
-
-        kt = k->kbdctx->kbdtbl;
-        if (kt == k->kbdtbl)
-                return 0;
-
-        if (kt) {
-                errno = 0;
-                compose = xkb_compose_state_new(kt->xkb_compose_table, XKB_COMPOSE_STATE_NO_FLAGS);
-                if (!compose) {
-                        r = errno > 0 ? -errno : -EFAULT;
-                        goto error;
-                }
-        }
-
-        kbdtbl_unref(k->kbdtbl);
-        k->kbdtbl = kbdtbl_ref(kt);
-        xkb_compose_state_unref(k->xkb_compose);
-        k->xkb_compose = compose;
-
-        return 0;
-
-error:
-        return log_debug_errno(r, "idev-keyboard: %s/%s: cannot adopt new compose table: %m",
-                               d->session->name, d->name);
-}
-
-static const idev_device_vtable keyboard_vtable = {
-        .free                   = keyboard_free,
-        .feed                   = keyboard_feed,
-};
diff --git a/src/libsystemd-terminal/idev.c b/src/libsystemd-terminal/idev.c
deleted file mode 100644 (file)
index 44be7c3..0000000
+++ /dev/null
@@ -1,801 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <libudev.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <systemd/sd-bus.h>
-#include <systemd/sd-event.h>
-#include "hashmap.h"
-#include "idev.h"
-#include "idev-internal.h"
-#include "login-shared.h"
-#include "macro.h"
-#include "util.h"
-
-static void element_open(idev_element *e);
-static void element_close(idev_element *e);
-
-/*
- * Devices
- */
-
-idev_device *idev_find_device(idev_session *s, const char *name) {
-        assert_return(s, NULL);
-        assert_return(name, NULL);
-
-        return hashmap_get(s->device_map, name);
-}
-
-int idev_device_add(idev_device *d, const char *name) {
-        int r;
-
-        assert_return(d, -EINVAL);
-        assert_return(d->vtable, -EINVAL);
-        assert_return(d->session, -EINVAL);
-        assert_return(name, -EINVAL);
-
-        d->name = strdup(name);
-        if (!d->name)
-                return -ENOMEM;
-
-        r = hashmap_put(d->session->device_map, d->name, d);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-idev_device *idev_device_free(idev_device *d) {
-        idev_device tmp;
-
-        if (!d)
-                return NULL;
-
-        assert(!d->enabled);
-        assert(!d->public);
-        assert(!d->links);
-        assert(d->vtable);
-        assert(d->vtable->free);
-
-        if (d->name)
-                hashmap_remove_value(d->session->device_map, d->name, d);
-
-        tmp = *d;
-        d->vtable->free(d);
-
-        free(tmp.name);
-
-        return NULL;
-}
-
-int idev_device_feed(idev_device *d, idev_data *data) {
-        assert(d);
-        assert(data);
-        assert(data->type < IDEV_DATA_CNT);
-
-        if (d->vtable->feed)
-                return d->vtable->feed(d, data);
-        else
-                return 0;
-}
-
-void idev_device_feedback(idev_device *d, idev_data *data) {
-        idev_link *l;
-
-        assert(d);
-        assert(data);
-        assert(data->type < IDEV_DATA_CNT);
-
-        LIST_FOREACH(links_by_device, l, d->links)
-                idev_element_feedback(l->element, data);
-}
-
-static void device_attach(idev_device *d, idev_link *l) {
-        assert(d);
-        assert(l);
-
-        if (d->vtable->attach)
-                d->vtable->attach(d, l);
-
-        if (d->enabled)
-                element_open(l->element);
-}
-
-static void device_detach(idev_device *d, idev_link *l) {
-        assert(d);
-        assert(l);
-
-        if (d->enabled)
-                element_close(l->element);
-
-        if (d->vtable->detach)
-                d->vtable->detach(d, l);
-}
-
-void idev_device_enable(idev_device *d) {
-        idev_link *l;
-
-        assert(d);
-
-        if (!d->enabled) {
-                d->enabled = true;
-                LIST_FOREACH(links_by_device, l, d->links)
-                        element_open(l->element);
-        }
-}
-
-void idev_device_disable(idev_device *d) {
-        idev_link *l;
-
-        assert(d);
-
-        if (d->enabled) {
-                d->enabled = false;
-                LIST_FOREACH(links_by_device, l, d->links)
-                        element_close(l->element);
-        }
-}
-
-/*
- * Elements
- */
-
-idev_element *idev_find_element(idev_session *s, const char *name) {
-        assert_return(s, NULL);
-        assert_return(name, NULL);
-
-        return hashmap_get(s->element_map, name);
-}
-
-int idev_element_add(idev_element *e, const char *name) {
-        int r;
-
-        assert_return(e, -EINVAL);
-        assert_return(e->vtable, -EINVAL);
-        assert_return(e->session, -EINVAL);
-        assert_return(name, -EINVAL);
-
-        e->name = strdup(name);
-        if (!e->name)
-                return -ENOMEM;
-
-        r = hashmap_put(e->session->element_map, e->name, e);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-idev_element *idev_element_free(idev_element *e) {
-        idev_element tmp;
-
-        if (!e)
-                return NULL;
-
-        assert(!e->enabled);
-        assert(!e->links);
-        assert(e->n_open == 0);
-        assert(e->vtable);
-        assert(e->vtable->free);
-
-        if (e->name)
-                hashmap_remove_value(e->session->element_map, e->name, e);
-
-        tmp = *e;
-        e->vtable->free(e);
-
-        free(tmp.name);
-
-        return NULL;
-}
-
-int idev_element_feed(idev_element *e, idev_data *data) {
-        int r, error = 0;
-        idev_link *l;
-
-        assert(e);
-        assert(data);
-        assert(data->type < IDEV_DATA_CNT);
-
-        LIST_FOREACH(links_by_element, l, e->links) {
-                r = idev_device_feed(l->device, data);
-                if (r != 0)
-                        error = r;
-        }
-
-        return error;
-}
-
-void idev_element_feedback(idev_element *e, idev_data *data) {
-        assert(e);
-        assert(data);
-        assert(data->type < IDEV_DATA_CNT);
-
-        if (e->vtable->feedback)
-               e->vtable->feedback(e, data);
-}
-
-static void element_open(idev_element *e) {
-        assert(e);
-
-        if (e->n_open++ == 0 && e->vtable->open)
-                e->vtable->open(e);
-}
-
-static void element_close(idev_element *e) {
-        assert(e);
-        assert(e->n_open > 0);
-
-        if (--e->n_open == 0 && e->vtable->close)
-                e->vtable->close(e);
-}
-
-static void element_enable(idev_element *e) {
-        assert(e);
-
-        if (!e->enabled) {
-                e->enabled = true;
-                if (e->vtable->enable)
-                        e->vtable->enable(e);
-        }
-}
-
-static void element_disable(idev_element *e) {
-        assert(e);
-
-        if (e->enabled) {
-                e->enabled = false;
-                if (e->vtable->disable)
-                        e->vtable->disable(e);
-        }
-}
-
-static void element_resume(idev_element *e, int fd) {
-        assert(e);
-        assert(fd >= 0);
-
-        if (e->vtable->resume)
-                e->vtable->resume(e, fd);
-}
-
-static void element_pause(idev_element *e, const char *mode) {
-        assert(e);
-        assert(mode);
-
-        if (e->vtable->pause)
-                e->vtable->pause(e, mode);
-}
-
-/*
- * Sessions
- */
-
-static int session_raise(idev_session *s, idev_event *ev) {
-        return s->event_fn(s, s->userdata, ev);
-}
-
-static int session_raise_device_add(idev_session *s, idev_device *d) {
-        idev_event event = {
-                .type = IDEV_EVENT_DEVICE_ADD,
-                .device_add = {
-                        .device = d,
-                },
-        };
-
-        return session_raise(s, &event);
-}
-
-static int session_raise_device_remove(idev_session *s, idev_device *d) {
-        idev_event event = {
-                .type = IDEV_EVENT_DEVICE_REMOVE,
-                .device_remove = {
-                        .device = d,
-                },
-        };
-
-        return session_raise(s, &event);
-}
-
-int idev_session_raise_device_data(idev_session *s, idev_device *d, idev_data *data) {
-        idev_event event = {
-                .type = IDEV_EVENT_DEVICE_DATA,
-                .device_data = {
-                        .device = d,
-                        .data = *data,
-                },
-        };
-
-        return session_raise(s, &event);
-}
-
-static int session_add_device(idev_session *s, idev_device *d) {
-        int r;
-
-        assert(s);
-        assert(d);
-
-        log_debug("idev: %s: add device '%s'", s->name, d->name);
-
-        d->public = true;
-        r = session_raise_device_add(s, d);
-        if (r != 0) {
-                d->public = false;
-                goto error;
-        }
-
-        return 0;
-
-error:
-        if (r < 0)
-                log_debug_errno(r, "idev: %s: error while adding device '%s': %m",
-                                s->name, d->name);
-        return r;
-}
-
-static int session_remove_device(idev_session *s, idev_device *d) {
-        int r, error = 0;
-
-        assert(s);
-        assert(d);
-
-        log_debug("idev: %s: remove device '%s'", s->name, d->name);
-
-        d->public = false;
-        r = session_raise_device_remove(s, d);
-        if (r != 0)
-                error = r;
-
-        idev_device_disable(d);
-
-        if (error < 0)
-                log_debug_errno(error, "idev: %s: error while removing device '%s': %m",
-                                s->name, d->name);
-        idev_device_free(d);
-        return error;
-}
-
-static int session_add_element(idev_session *s, idev_element *e) {
-        assert(s);
-        assert(e);
-
-        log_debug("idev: %s: add element '%s'", s->name, e->name);
-
-        if (s->enabled)
-                element_enable(e);
-
-        return 0;
-}
-
-static int session_remove_element(idev_session *s, idev_element *e) {
-        int r, error = 0;
-        idev_device *d;
-        idev_link *l;
-
-        assert(s);
-        assert(e);
-
-        log_debug("idev: %s: remove element '%s'", s->name, e->name);
-
-        while ((l = e->links)) {
-                d = l->device;
-                LIST_REMOVE(links_by_device, d->links, l);
-                LIST_REMOVE(links_by_element, e->links, l);
-                device_detach(d, l);
-
-                if (!d->links) {
-                        r = session_remove_device(s, d);
-                        if (r != 0)
-                                error = r;
-                }
-
-                l->device = NULL;
-                l->element = NULL;
-                free(l);
-        }
-
-        element_disable(e);
-
-        if (error < 0)
-                log_debug_errno(r, "idev: %s: error while removing element '%s': %m",
-                                s->name, e->name);
-        idev_element_free(e);
-        return error;
-}
-
-idev_session *idev_find_session(idev_context *c, const char *name) {
-        assert_return(c, NULL);
-        assert_return(name, NULL);
-
-        return hashmap_get(c->session_map, name);
-}
-
-static int session_resume_device_fn(sd_bus *bus,
-                                    sd_bus_message *signal,
-                                    void *userdata,
-                                    sd_bus_error *ret_error) {
-        idev_session *s = userdata;
-        idev_element *e;
-        uint32_t major, minor;
-        int r, fd;
-
-        r = sd_bus_message_read(signal, "uuh", &major, &minor, &fd);
-        if (r < 0) {
-                log_debug("idev: %s: erroneous ResumeDevice signal", s->name);
-                return 0;
-        }
-
-        e = idev_find_evdev(s, makedev(major, minor));
-        if (!e)
-                return 0;
-
-        element_resume(e, fd);
-        return 0;
-}
-
-static int session_pause_device_fn(sd_bus *bus,
-                                   sd_bus_message *signal,
-                                   void *userdata,
-                                   sd_bus_error *ret_error) {
-        idev_session *s = userdata;
-        idev_element *e;
-        uint32_t major, minor;
-        const char *mode;
-        int r;
-
-        r = sd_bus_message_read(signal, "uus", &major, &minor, &mode);
-        if (r < 0) {
-                log_debug("idev: %s: erroneous PauseDevice signal", s->name);
-                return 0;
-        }
-
-        e = idev_find_evdev(s, makedev(major, minor));
-        if (!e)
-                return 0;
-
-        element_pause(e, mode);
-        return 0;
-}
-
-static int session_setup_bus(idev_session *s) {
-        _cleanup_free_ char *match = NULL;
-        int r;
-
-        if (!s->managed)
-                return 0;
-
-        match = strjoin("type='signal',"
-                        "sender='org.freedesktop.login1',"
-                        "interface='org.freedesktop.login1.Session',"
-                        "member='ResumeDevice',"
-                        "path='", s->path, "'",
-                        NULL);
-        if (!match)
-                return -ENOMEM;
-
-        r = sd_bus_add_match(s->context->sysbus,
-                             &s->slot_resume_device,
-                             match,
-                             session_resume_device_fn,
-                             s);
-        if (r < 0)
-                return r;
-
-        free(match);
-        match = strjoin("type='signal',"
-                        "sender='org.freedesktop.login1',"
-                        "interface='org.freedesktop.login1.Session',"
-                        "member='PauseDevice',"
-                        "path='", s->path, "'",
-                        NULL);
-        if (!match)
-                return -ENOMEM;
-
-        r = sd_bus_add_match(s->context->sysbus,
-                             &s->slot_pause_device,
-                             match,
-                             session_pause_device_fn,
-                             s);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-int idev_session_new(idev_session **out,
-                     idev_context *c,
-                     unsigned int flags,
-                     const char *name,
-                     idev_event_fn event_fn,
-                     void *userdata) {
-        _cleanup_(idev_session_freep) idev_session *s = NULL;
-        int r;
-
-        assert_return(out, -EINVAL);
-        assert_return(c, -EINVAL);
-        assert_return(name, -EINVAL);
-        assert_return(event_fn, -EINVAL);
-        assert_return((flags & IDEV_SESSION_CUSTOM) == !session_id_valid(name), -EINVAL);
-        assert_return(!(flags & IDEV_SESSION_CUSTOM) || !(flags & IDEV_SESSION_MANAGED), -EINVAL);
-        assert_return(!(flags & IDEV_SESSION_MANAGED) || c->sysbus, -EINVAL);
-
-        s = new0(idev_session, 1);
-        if (!s)
-                return -ENOMEM;
-
-        s->context = idev_context_ref(c);
-        s->custom = flags & IDEV_SESSION_CUSTOM;
-        s->managed = flags & IDEV_SESSION_MANAGED;
-        s->event_fn = event_fn;
-        s->userdata = userdata;
-
-        s->name = strdup(name);
-        if (!s->name)
-                return -ENOMEM;
-
-        if (s->managed) {
-                r = sd_bus_path_encode("/org/freedesktop/login1/session", s->name, &s->path);
-                if (r < 0)
-                        return r;
-        }
-
-        s->element_map = hashmap_new(&string_hash_ops);
-        if (!s->element_map)
-                return -ENOMEM;
-
-        s->device_map = hashmap_new(&string_hash_ops);
-        if (!s->device_map)
-                return -ENOMEM;
-
-        r = session_setup_bus(s);
-        if (r < 0)
-                return r;
-
-        r = hashmap_put(c->session_map, s->name, s);
-        if (r < 0)
-                return r;
-
-        *out = s;
-        s = NULL;
-        return 0;
-}
-
-idev_session *idev_session_free(idev_session *s) {
-        idev_element *e;
-
-        if (!s)
-                return NULL;
-
-        while ((e = hashmap_first(s->element_map)))
-                session_remove_element(s, e);
-
-        assert(hashmap_size(s->device_map) == 0);
-
-        if (s->name)
-                hashmap_remove_value(s->context->session_map, s->name, s);
-
-        s->slot_pause_device = sd_bus_slot_unref(s->slot_pause_device);
-        s->slot_resume_device = sd_bus_slot_unref(s->slot_resume_device);
-        s->context = idev_context_unref(s->context);
-        hashmap_free(s->device_map);
-        hashmap_free(s->element_map);
-        free(s->path);
-        free(s->name);
-        free(s);
-
-        return NULL;
-}
-
-bool idev_session_is_enabled(idev_session *s) {
-        return s && s->enabled;
-}
-
-void idev_session_enable(idev_session *s) {
-        idev_element *e;
-        Iterator i;
-
-        assert(s);
-
-        if (!s->enabled) {
-                s->enabled = true;
-                HASHMAP_FOREACH(e, s->element_map, i)
-                        element_enable(e);
-        }
-}
-
-void idev_session_disable(idev_session *s) {
-        idev_element *e;
-        Iterator i;
-
-        assert(s);
-
-        if (s->enabled) {
-                s->enabled = false;
-                HASHMAP_FOREACH(e, s->element_map, i)
-                        element_disable(e);
-        }
-}
-
-static int add_link(idev_element *e, idev_device *d) {
-        idev_link *l;
-
-        assert(e);
-        assert(d);
-
-        l = new0(idev_link, 1);
-        if (!l)
-                return -ENOMEM;
-
-        l->element = e;
-        l->device = d;
-        LIST_PREPEND(links_by_element, e->links, l);
-        LIST_PREPEND(links_by_device, d->links, l);
-        device_attach(d, l);
-
-        return 0;
-}
-
-static int guess_type(struct udev_device *d) {
-        const char *id_key;
-
-        id_key = udev_device_get_property_value(d, "ID_INPUT_KEY");
-        if (streq_ptr(id_key, "1"))
-                return IDEV_DEVICE_KEYBOARD;
-
-        return IDEV_DEVICE_CNT;
-}
-
-int idev_session_add_evdev(idev_session *s, struct udev_device *ud) {
-        idev_element *e;
-        idev_device *d;
-        dev_t devnum;
-        int r, type;
-
-        assert_return(s, -EINVAL);
-        assert_return(ud, -EINVAL);
-
-        devnum = udev_device_get_devnum(ud);
-        if (devnum == 0)
-                return 0;
-
-        e = idev_find_evdev(s, devnum);
-        if (e)
-                return 0;
-
-        r = idev_evdev_new(&e, s, ud);
-        if (r < 0)
-                return r;
-
-        r = session_add_element(s, e);
-        if (r != 0)
-                return r;
-
-        type = guess_type(ud);
-        if (type < 0)
-                return type;
-
-        switch (type) {
-        case IDEV_DEVICE_KEYBOARD:
-                d = idev_find_keyboard(s, e->name);
-                if (d) {
-                        log_debug("idev: %s: keyboard for new evdev element '%s' already available",
-                                  s->name, e->name);
-                        return 0;
-                }
-
-                r = idev_keyboard_new(&d, s, e->name);
-                if (r < 0)
-                        return r;
-
-                r = add_link(e, d);
-                if (r < 0) {
-                        idev_device_free(d);
-                        return r;
-                }
-
-                return session_add_device(s, d);
-        default:
-                /* unknown elements are silently ignored */
-                return 0;
-        }
-}
-
-int idev_session_remove_evdev(idev_session *s, struct udev_device *ud) {
-        idev_element *e;
-        dev_t devnum;
-
-        assert(s);
-        assert(ud);
-
-        devnum = udev_device_get_devnum(ud);
-        if (devnum == 0)
-                return 0;
-
-        e = idev_find_evdev(s, devnum);
-        if (!e)
-                return 0;
-
-        return session_remove_element(s, e);
-}
-
-/*
- * Contexts
- */
-
-int idev_context_new(idev_context **out, sd_event *event, sd_bus *sysbus) {
-        _cleanup_(idev_context_unrefp) idev_context *c = NULL;
-
-        assert_return(out, -EINVAL);
-        assert_return(event, -EINVAL);
-
-        c = new0(idev_context, 1);
-        if (!c)
-                return -ENOMEM;
-
-        c->ref = 1;
-        c->event = sd_event_ref(event);
-
-        if (sysbus)
-                c->sysbus = sd_bus_ref(sysbus);
-
-        c->session_map = hashmap_new(&string_hash_ops);
-        if (!c->session_map)
-                return -ENOMEM;
-
-        c->data_map = hashmap_new(&string_hash_ops);
-        if (!c->data_map)
-                return -ENOMEM;
-
-        *out = c;
-        c = NULL;
-        return 0;
-}
-
-static void context_cleanup(idev_context *c) {
-        assert(hashmap_size(c->data_map) == 0);
-        assert(hashmap_size(c->session_map) == 0);
-
-        hashmap_free(c->data_map);
-        hashmap_free(c->session_map);
-        c->sysbus = sd_bus_unref(c->sysbus);
-        c->event = sd_event_unref(c->event);
-        free(c);
-}
-
-idev_context *idev_context_ref(idev_context *c) {
-        assert_return(c, NULL);
-        assert_return(c->ref > 0, NULL);
-
-        ++c->ref;
-        return c;
-}
-
-idev_context *idev_context_unref(idev_context *c) {
-        if (!c)
-                return NULL;
-
-        assert_return(c->ref > 0, NULL);
-
-        if (--c->ref == 0)
-                context_cleanup(c);
-
-        return NULL;
-}
diff --git a/src/libsystemd-terminal/idev.h b/src/libsystemd-terminal/idev.h
deleted file mode 100644 (file)
index 0e84617..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-/*
- * IDev
- */
-
-#pragma once
-
-#include <libudev.h>
-#include <linux/input.h>
-#include <stdbool.h>
-#include <systemd/sd-bus.h>
-#include <systemd/sd-event.h>
-#include <xkbcommon/xkbcommon.h>
-
-typedef struct idev_data                idev_data;
-typedef struct idev_data_evdev          idev_data_evdev;
-typedef struct idev_data_keyboard       idev_data_keyboard;
-
-typedef struct idev_event               idev_event;
-typedef struct idev_device              idev_device;
-typedef struct idev_session             idev_session;
-typedef struct idev_context             idev_context;
-
-/*
- * Types
- */
-
-enum {
-        IDEV_ELEMENT_EVDEV,
-        IDEV_ELEMENT_CNT
-};
-
-enum {
-        IDEV_DEVICE_KEYBOARD,
-     &n