diff options
Diffstat (limited to '')
-rw-r--r-- | src/login/logind-device.c | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/src/login/logind-device.c b/src/login/logind-device.c new file mode 100644 index 0000000..e724365 --- /dev/null +++ b/src/login/logind-device.c @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include <string.h> + +#include "alloc-util.h" +#include "logind-device.h" +#include "util.h" + +Device* device_new(Manager *m, const char *sysfs, bool master) { + Device *d; + + assert(m); + assert(sysfs); + + d = new0(Device, 1); + if (!d) + return NULL; + + d->sysfs = strdup(sysfs); + if (!d->sysfs) + return mfree(d); + + if (hashmap_put(m->devices, d->sysfs, d) < 0) { + free(d->sysfs); + return mfree(d); + } + + d->manager = m; + d->master = master; + dual_timestamp_get(&d->timestamp); + + return d; +} + +static void device_detach(Device *d) { + Seat *s; + SessionDevice *sd; + + assert(d); + + if (!d->seat) + return; + + while ((sd = d->session_devices)) + session_device_free(sd); + + s = d->seat; + LIST_REMOVE(devices, d->seat->devices, d); + d->seat = NULL; + + if (!seat_has_master_device(s)) { + seat_add_to_gc_queue(s); + seat_send_changed(s, "CanGraphical", NULL); + } +} + +void device_free(Device *d) { + assert(d); + + device_detach(d); + + hashmap_remove(d->manager->devices, d->sysfs); + + free(d->sysfs); + free(d); +} + +void device_attach(Device *d, Seat *s) { + Device *i; + bool had_master; + + assert(d); + assert(s); + + if (d->seat == s) + return; + + if (d->seat) + device_detach(d); + + d->seat = s; + had_master = seat_has_master_device(s); + + /* We keep the device list sorted by the "master" flag. That is, master + * devices are at the front, other devices at the tail. As there is no + * way to easily add devices at the list-tail, we need to iterate the + * list to find the first non-master device when adding non-master + * devices. We assume there is only a few (normally 1) master devices + * per seat, so we iterate only a few times. */ + + if (d->master || !s->devices) + LIST_PREPEND(devices, s->devices, d); + else { + LIST_FOREACH(devices, i, s->devices) { + if (!i->devices_next || !i->master) { + LIST_INSERT_AFTER(devices, s->devices, i, d); + break; + } + } + } + + if (!had_master && d->master && s->started) { + seat_save(s); + seat_send_changed(s, "CanGraphical", NULL); + } +} |