Create & implement transient seat protocol

This commit is contained in:
Andri Yngvason 2020-02-08 15:52:59 +00:00
parent ad46e125d5
commit a22ed974f7
5 changed files with 296 additions and 0 deletions

View file

@ -0,0 +1,38 @@
/*
* This an unstable interface of wlroots. No guarantees are made regarding the
* future consistency of this API.
*/
#ifndef WLR_USE_UNSTABLE
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
#endif
#ifndef WLR_TYPES_WLR_TRANSIENT_SEAT_V1_H
#define WLR_TYPES_WLR_TRANSIENT_SEAT_V1_H
#include <wayland-server-core.h>
#include <wayland-server-protocol.h>
struct wlr_seat;
struct wlr_transient_seat_manager_v1 {
struct wl_global *global;
struct wl_listener display_destroy;
struct wlr_seat *(*find_seat)(const char *name);
struct wlr_seat *(*create_seat)(const char *name);
void (*destroy_seat)(struct wlr_seat *seat);
struct wl_list transient_seats;
};
struct wlr_transient_seat_v1 {
struct wlr_seat *seat;
struct wl_resource *resource;
struct wlr_transient_seat_manager_v1 *manager;
struct wl_list link;
};
struct wlr_transient_seat_manager_v1 *wlr_transient_seat_manager_v1_create(
struct wl_display *display);
#endif /* WLR_TYPES_WLR_TRANSIENT_SEAT_V1_H */

View file

@ -44,6 +44,7 @@ protocols = {
'wlr-output-power-management-unstable-v1': 'wlr-output-power-management-unstable-v1.xml',
'wlr-screencopy-unstable-v1': 'wlr-screencopy-unstable-v1.xml',
'wlr-virtual-pointer-unstable-v1': 'wlr-virtual-pointer-unstable-v1.xml',
'transient-seat-unstable-v1': 'transient-seat-unstable-v1.xml',
}
protocols_code = {}

View file

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="transient_seat_unstable_v1">
<copyright>
Copyright © 2020 Andri Yngvason
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.
</copyright>
<description summary="Protocol for creating temporary seats">
The transient seat protocol can be used by clients to create independent
seats that will be removed when the client disconnects. The client also gets
a handle to the seat which can be used to remove the seat.
</description>
<interface name="zext_transient_seat_manager_v1" version="1">
<request name="create">
<description summary="Create a transient seat">
Create a new seat that is removed when the client closes the connection.
The client may suggest a name for the seat, but the server may choose
whichever name it sees fit, except the name must not collide with the
name of another seat.
It is suggested that the client choose a sufficiently unique name, e.g.
something containing the pid and an incremental numeric value.
</description>
<arg name="suggested_name" type="string"/>
<arg name="seat" type="new_id" interface="zext_transient_seat_v1"/>
</request>
<request name="destroy" type="destructor">
<description summary="Destroy the manager">
Destroy the manager
</description>
</request>
</interface>
<interface name="zext_transient_seat_v1" version="1">
<enum name="error">
<entry name="unspec" value="0"
summary="Operation failed for unspecified reason"/>
<entry name="name_taken" value="1"
summary="The suggested name was already taken"/>
<entry name="invalid_name" value="2"
summary="The suggested name contains invalid characters"/>
</enum>
<event name="failed">
<description summary="seat creation failed">
This event indicates that the seat creation failed. No event is
generated after this and the client should destroy the transient seat
object.
</description>
<arg name="error" type="uint" enum="error"/>
</event>
<event name="ready">
<description summary="seat has been created">
This event indicates that the seat has been created and tells the client
which name was chosen for it. It is generated after the seat is created.
No event is generated after this.
</description>
<arg name="name" type="string"/>
</event>
<request name="destroy" type="destructor">
<description summary="Destroy the seat">
Destroy the seat
</description>
</request>
</interface>
</protocol>

View file

@ -59,6 +59,7 @@ wlr_files += files(
'wlr_tablet_tool.c',
'wlr_text_input_v3.c',
'wlr_touch.c',
'wlr_transient_seat_v1.c',
'wlr_viewporter.c',
'wlr_virtual_keyboard_v1.c',
'wlr_virtual_pointer_v1.c',

View file

@ -0,0 +1,167 @@
#include <assert.h>
#include <stdlib.h>
#include <wayland-util.h>
#include <wlr/types/wlr_seat.h>
#include <wlr/types/wlr_transient_seat_v1.h>
#include "transient-seat-unstable-v1-protocol.h"
static const struct zext_transient_seat_manager_v1_interface manager_impl;
static const struct zext_transient_seat_v1_interface transient_seat_impl;
void transient_seat_handle_destroy(struct wl_client *client,
struct wl_resource *resource);
static struct wlr_transient_seat_manager_v1 *manager_from_resource(
struct wl_resource *resource) {
assert(wl_resource_instance_of(resource,
&zext_transient_seat_manager_v1_interface, &manager_impl));
return wl_resource_get_user_data(resource);
}
static struct wlr_transient_seat_v1 *transient_seat_from_resource(
struct wl_resource *resource) {
assert(wl_resource_instance_of(resource,
&zext_transient_seat_v1_interface, &transient_seat_impl));
return wl_resource_get_user_data(resource);
}
static void manager_handle_destroy(struct wl_client *client,
struct wl_resource *manager_resource) {
wl_resource_destroy(manager_resource);
}
static void transient_seat_destroy(struct wlr_transient_seat_v1 *transient_seat) {
wl_list_remove(&transient_seat->link);
if (transient_seat->seat) {
transient_seat->manager->destroy_seat(transient_seat->seat);
}
wl_resource_set_user_data(transient_seat->resource, NULL);
free(transient_seat);
}
static void transient_seat_destroy_resource(struct wl_resource *resource) {
struct wlr_transient_seat_v1 *transient_seat =
transient_seat_from_resource(resource);
if (transient_seat) {
transient_seat_destroy(transient_seat);
}
}
void transient_seat_handle_destroy(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static const struct zext_transient_seat_v1_interface transient_seat_impl = {
.destroy = transient_seat_handle_destroy,
};
static void manager_create_transient_seat(struct wl_client *client,
struct wl_resource *manager_resource,
const char *suggested_name, uint32_t id) {
struct wlr_transient_seat_manager_v1 *manager =
manager_from_resource(manager_resource);
struct wlr_transient_seat_v1 *transient_seat =
calloc(1, sizeof(struct wlr_transient_seat_v1));
if (!transient_seat) {
wl_client_post_no_memory(client);
return;
}
transient_seat->manager = manager;
transient_seat->resource = wl_resource_create(client,
&zext_transient_seat_v1_interface,
wl_resource_get_version(manager_resource), id);
if (!transient_seat->resource) {
wl_client_post_no_memory(client);
free(transient_seat);
return;
}
wl_resource_set_implementation(transient_seat->resource,
&transient_seat_impl, transient_seat,
transient_seat_destroy_resource);
wl_list_insert(&manager->transient_seats, &transient_seat->link);
if (manager->find_seat(suggested_name)) {
zext_transient_seat_v1_send_failed(transient_seat->resource,
ZEXT_TRANSIENT_SEAT_V1_ERROR_NAME_TAKEN);
transient_seat_destroy(transient_seat);
return;
}
transient_seat->seat = manager->create_seat(suggested_name);
if (transient_seat->seat) {
zext_transient_seat_v1_send_ready(transient_seat->resource,
suggested_name);
} else {
zext_transient_seat_v1_send_failed(transient_seat->resource,
ZEXT_TRANSIENT_SEAT_V1_ERROR_UNSPEC);
transient_seat_destroy(transient_seat);
}
}
static const struct zext_transient_seat_manager_v1_interface manager_impl = {
.create = manager_create_transient_seat,
.destroy = manager_handle_destroy,
};
static void handle_display_destroy(struct wl_listener *listener, void *data) {
struct wlr_transient_seat_manager_v1 *manager =
wl_container_of(listener, manager, display_destroy);
struct wlr_transient_seat_v1 *transient_seat, *tmp_transient_seat;
wl_list_for_each_safe(transient_seat, tmp_transient_seat,
&manager->transient_seats, link) {
transient_seat_destroy(transient_seat);
}
wl_list_remove(&manager->display_destroy.link);
wl_global_destroy(manager->global);
free(manager);
}
static void transient_seat_manager_bind(struct wl_client *client, void *data,
uint32_t version, uint32_t id) {
struct wlr_virtual_pointer_manager_v1 *manager = data;
struct wl_resource *resource = wl_resource_create(client,
&zext_transient_seat_manager_v1_interface, version, id);
if (!resource) {
wl_client_post_no_memory(client);
return;
}
wl_resource_set_implementation(resource, &manager_impl, manager, NULL);
}
struct wlr_transient_seat_manager_v1 *wlr_transient_seat_manager_v1_create(
struct wl_display *display) {
struct wlr_transient_seat_manager_v1 *manager =
calloc(1, sizeof(struct wlr_transient_seat_manager_v1));
if (!manager) {
return NULL;
}
wl_list_init(&manager->transient_seats);
manager->global = wl_global_create(display,
&zext_transient_seat_manager_v1_interface, 1, manager,
transient_seat_manager_bind);
if (!manager->global) {
goto failure;
}
manager->display_destroy.notify = handle_display_destroy;
wl_display_add_destroy_listener(display, &manager->display_destroy);
return manager;
failure:
free(manager);
return NULL;
}