2020-09-14 17:16:50 +10:00
|
|
|
/*
|
|
|
|
|
* Copyright © 2020 Red Hat, Inc.
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
|
|
|
*
|
|
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
|
* Software.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
|
* DEALINGS IN THE SOFTWARE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
|
|
#include "util-bits.h"
|
|
|
|
|
#include "util-macros.h"
|
|
|
|
|
#include "util-mem.h"
|
|
|
|
|
#include "util-io.h"
|
|
|
|
|
#include "util-strings.h"
|
|
|
|
|
|
|
|
|
|
#include "libei-private.h"
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ei_seat_destroy(struct ei_seat *seat)
|
|
|
|
|
{
|
|
|
|
|
free(seat->name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_public_
|
|
|
|
|
OBJECT_IMPLEMENT_REF(ei_seat);
|
|
|
|
|
_public_
|
|
|
|
|
OBJECT_IMPLEMENT_UNREF(ei_seat);
|
|
|
|
|
|
|
|
|
|
static
|
|
|
|
|
OBJECT_IMPLEMENT_CREATE(ei_seat);
|
|
|
|
|
static
|
|
|
|
|
OBJECT_IMPLEMENT_PARENT(ei_seat, ei);
|
|
|
|
|
_public_
|
|
|
|
|
OBJECT_IMPLEMENT_GETTER(ei_seat, name, const char *);
|
|
|
|
|
_public_
|
|
|
|
|
OBJECT_IMPLEMENT_SETTER(ei_seat, user_data, void *);
|
|
|
|
|
|
|
|
|
|
_public_ struct ei*
|
|
|
|
|
ei_seat_get_context(struct ei_seat *seat)
|
|
|
|
|
{
|
|
|
|
|
assert(seat);
|
|
|
|
|
return ei_seat_parent(seat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct ei_seat *
|
|
|
|
|
ei_seat_new(struct ei *ei, uint32_t id, const char *name, uint32_t capabilities)
|
|
|
|
|
{
|
|
|
|
|
struct ei_seat *seat = ei_seat_create(&ei->object);
|
|
|
|
|
|
2021-07-16 18:17:15 +10:00
|
|
|
seat->state = EI_SEAT_STATE_NEW;
|
2020-09-14 17:16:50 +10:00
|
|
|
seat->name = xstrdup(name);
|
|
|
|
|
seat->id = id;
|
|
|
|
|
seat->capabilities = capabilities;
|
2021-07-16 18:17:15 +10:00
|
|
|
seat->capabilities_mask = ~0; /* Masked out by client */
|
2020-09-14 17:16:50 +10:00
|
|
|
|
|
|
|
|
list_init(&seat->devices);
|
2021-07-21 09:27:18 +10:00
|
|
|
list_init(&seat->devices_removed);
|
2020-09-14 17:16:50 +10:00
|
|
|
list_init(&seat->link);
|
|
|
|
|
|
|
|
|
|
return seat; /* ref owned by caller */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ei_seat_remove(struct ei_seat *seat)
|
|
|
|
|
{
|
2020-10-28 15:32:42 +10:00
|
|
|
/* Sigh, this is terrible and needs to be fixed:
|
|
|
|
|
* if our fd is broken, trying to send any event causes an ei_disconnect(),
|
|
|
|
|
* which eventually calls in here. So we need to guard this function
|
|
|
|
|
* against nested callers. */
|
|
|
|
|
if (seat->state == EI_SEAT_STATE_REMOVED)
|
|
|
|
|
return;
|
|
|
|
|
|
2021-07-22 13:13:03 +10:00
|
|
|
struct ei_device *d;
|
2020-09-14 17:16:50 +10:00
|
|
|
|
|
|
|
|
/* If the server disconnects us before processing a new device, we
|
|
|
|
|
* need to clean this up in the library */
|
2021-07-22 13:13:03 +10:00
|
|
|
list_for_each_safe(d, &seat->devices, link) {
|
2020-10-28 15:32:42 +10:00
|
|
|
/* remove the device */
|
2021-07-16 18:17:15 +10:00
|
|
|
ei_device_close(d);
|
2020-10-28 15:32:42 +10:00
|
|
|
/* And pretend to process the removed message from
|
|
|
|
|
* the server */
|
2020-10-26 09:24:43 +10:00
|
|
|
ei_device_removed_by_server(d);
|
2020-09-14 17:16:50 +10:00
|
|
|
}
|
|
|
|
|
|
2020-10-28 15:32:42 +10:00
|
|
|
/* Check the seat state again, because the above device removal may
|
|
|
|
|
* have triggered ei_disconnect() */
|
|
|
|
|
if (seat->state != EI_SEAT_STATE_REMOVED) {
|
|
|
|
|
seat->state = EI_SEAT_STATE_REMOVED;
|
|
|
|
|
list_remove(&seat->link);
|
|
|
|
|
list_init(&seat->link);
|
|
|
|
|
ei_queue_seat_removed_event(seat);
|
|
|
|
|
ei_seat_unref(seat);
|
|
|
|
|
}
|
2020-09-14 17:16:50 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct ei_device *
|
|
|
|
|
ei_seat_find_device(struct ei_seat *seat, uint32_t deviceid)
|
|
|
|
|
{
|
|
|
|
|
struct ei_device *device;
|
|
|
|
|
|
|
|
|
|
list_for_each(device, &seat->devices, link) {
|
|
|
|
|
if (device->id == deviceid)
|
|
|
|
|
return device;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2021-07-16 18:17:15 +10:00
|
|
|
|
|
|
|
|
_public_ void
|
|
|
|
|
ei_seat_drop_capability(struct ei_seat *seat,
|
|
|
|
|
enum ei_device_capability cap)
|
|
|
|
|
{
|
2021-08-09 18:47:07 +10:00
|
|
|
if (seat->state != EI_SEAT_STATE_NEW) {
|
|
|
|
|
log_bug_client(ei_seat_get_context(seat), "Seat is already bound\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
flag_clear(seat->capabilities_mask, cap);
|
2021-07-16 18:17:15 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_public_ void
|
|
|
|
|
ei_seat_bind(struct ei_seat *seat)
|
|
|
|
|
{
|
2021-08-09 18:47:07 +10:00
|
|
|
if (seat->state != EI_SEAT_STATE_NEW) {
|
|
|
|
|
log_bug_client(ei_seat_get_context(seat), "Seat is already bound\n");
|
2021-07-16 18:17:15 +10:00
|
|
|
return;
|
2021-08-09 18:47:07 +10:00
|
|
|
}
|
2021-07-16 18:17:15 +10:00
|
|
|
|
|
|
|
|
ei_send_seat_bind(seat, seat->capabilities & seat->capabilities_mask);
|
|
|
|
|
seat->state = EI_SEAT_STATE_BOUND;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_public_ void
|
|
|
|
|
ei_seat_unbind(struct ei_seat *seat)
|
|
|
|
|
{
|
|
|
|
|
switch (seat->state) {
|
|
|
|
|
case EI_SEAT_STATE_NEW:
|
|
|
|
|
case EI_SEAT_STATE_BOUND:
|
|
|
|
|
break;
|
|
|
|
|
case EI_SEAT_STATE_UNBOUND:
|
|
|
|
|
case EI_SEAT_STATE_REMOVED:
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct ei_device *device;
|
|
|
|
|
list_for_each(device, &seat->devices, link) {
|
|
|
|
|
ei_device_close(device);
|
|
|
|
|
}
|
|
|
|
|
ei_send_seat_unbind(seat);
|
|
|
|
|
seat->state = EI_SEAT_STATE_UNBOUND;
|
|
|
|
|
}
|