Compare commits

...

8 Commits

Author SHA1 Message Date
Andri Yngvason 9e034fabbc Use transient-seat instead of seat-management 2020-12-29 19:24:12 +00:00
Andri Yngvason 5476e431bd protocols: Replace seat-management with transient-seat 2020-12-29 18:49:31 +00:00
Andri Yngvason e037ca32ec Also exit on ECONNRESET 2020-12-29 18:47:39 +00:00
Andri Yngvason b08a44e446 Create a seat for each client 2020-12-27 22:38:07 +00:00
Andri Yngvason e4412e4d52 protocols: Add wlr-seat-management 2020-12-27 22:37:37 +00:00
Andri Yngvason f818da7abe seat: Add on_ready callback 2020-12-27 22:33:43 +00:00
Andri Yngvason 3ff02f0681 Move ownership of pointer to client object
This means that there will be a virtual pointer per each client.
2020-12-27 20:37:15 +00:00
Andri Yngvason 013dabf41e Move ownership to keyboard to client object
This means that there will be a virtual keyboard per client
2020-12-27 20:23:45 +00:00
5 changed files with 277 additions and 41 deletions

View File

@ -17,6 +17,7 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <wayland-client.h>
struct seat {
@ -26,6 +27,12 @@ struct seat {
uint32_t id;
uint32_t capabilities;
char name[256];
bool has_capabilities;
bool has_name;
void (*on_ready)(struct seat*);
void* userdata;
};
struct seat* seat_new(struct wl_seat* wl_seat, uint32_t id);

View File

@ -21,6 +21,7 @@ client_protocols = [
'xdg-output-unstable-v1.xml',
'linux-dmabuf-unstable-v1.xml',
'wlr-data-control-unstable-v1.xml',
'transient-seat-unstable-v1.xml',
]
client_protos_src = []

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

@ -40,6 +40,7 @@
#include "virtual-keyboard-unstable-v1.h"
#include "xdg-output-unstable-v1.h"
#include "linux-dmabuf-unstable-v1.h"
#include "transient-seat-unstable-v1.h"
#include "screencopy.h"
#include "data-control.h"
#include "strlcpy.h"
@ -68,6 +69,17 @@
#define MAYBE_UNUSED __attribute__((unused))
struct wv_client {
struct wl_list link;
struct keyboard kb;
struct pointer pointer;
struct wl_seat* wl_seat;
char seat_name[256];
struct zext_transient_seat_v1* chair;
};
struct wayvnc {
bool do_exit;
@ -75,6 +87,7 @@ struct wayvnc {
struct wl_registry* registry;
struct wl_list outputs;
struct wl_list seats;
struct wl_list clients;
struct cfg cfg;
struct zxdg_output_manager_v1* xdg_output_manager;
@ -87,8 +100,6 @@ struct wayvnc {
const struct seat* selected_seat;
struct screencopy screencopy;
struct pointer pointer_backend;
struct keyboard keyboard_backend;
struct data_control data_control;
struct aml_handler* wayland_handler;
@ -112,6 +123,7 @@ struct wayvnc {
void wayvnc_exit(struct wayvnc* self);
void on_capture_done(struct screencopy* sc);
static void on_render(struct nvnc_display* display, struct nvnc_fb* fb);
static void on_seat_ready(struct seat*);
#if defined(GIT_VERSION)
static const char wayvnc_version[] = GIT_VERSION;
@ -124,6 +136,9 @@ static const char wayvnc_version[] = "UNKNOWN";
struct wl_shm* wl_shm = NULL;
struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf = NULL;
struct gbm_device* gbm_device = NULL;
struct zext_transient_seat_manager_v1* zext_transient_seat_manager = NULL;
static uint64_t seat_id = 0;
static void registry_add(void* data, struct wl_registry* registry,
uint32_t id, const char* interface,
@ -188,6 +203,9 @@ static void registry_add(void* data, struct wl_registry* registry,
return;
}
seat->on_ready = on_seat_ready;
seat->userdata = self;
wl_list_insert(&self->seats, &seat->link);
return;
}
@ -211,6 +229,12 @@ static void registry_add(void* data, struct wl_registry* registry,
&zwlr_data_control_manager_v1_interface, 2);
return;
}
if (strcmp(interface, zext_transient_seat_manager_v1_interface.name) == 0) {
zext_transient_seat_manager = wl_registry_bind(registry, id,
&zext_transient_seat_manager_v1_interface, 1);
return;
}
}
static void registry_remove(void* data, struct wl_registry* registry,
@ -292,16 +316,15 @@ void wayvnc_destroy(struct wayvnc* self)
output_list_destroy(&self->outputs);
seat_list_destroy(&self->seats);
zext_transient_seat_manager_v1_destroy(zext_transient_seat_manager);
zxdg_output_manager_v1_destroy(self->xdg_output_manager);
wl_shm_destroy(wl_shm);
zwp_virtual_keyboard_v1_destroy(self->keyboard_backend.virtual_keyboard);
zwp_virtual_keyboard_manager_v1_destroy(self->keyboard_manager);
keyboard_destroy(&self->keyboard_backend);
zwlr_virtual_pointer_manager_v1_destroy(self->pointer_manager);
pointer_destroy(&self->pointer_backend);
if (self->screencopy.manager)
zwlr_screencopy_manager_v1_destroy(self->screencopy.manager);
@ -337,6 +360,7 @@ static int init_wayland(struct wayvnc* self)
wl_list_init(&self->outputs);
wl_list_init(&self->seats);
wl_list_init(&self->clients);
self->registry = wl_display_get_registry(self->display);
if (!self->registry)
@ -385,7 +409,7 @@ void on_wayland_event(void* obj)
assert(rc == 0);
if (wl_display_read_events(self->display) < 0) {
if (errno == EPIPE) {
if (errno == EPIPE || errno == ECONNRESET) {
log_error("Compositor has gone away. Exiting...\n");
wayvnc_exit(self);
} else {
@ -436,6 +460,128 @@ int init_main_loop(struct wayvnc* self)
return 0;
}
static void on_client_destroy(struct nvnc_client* nvnc_client)
{
struct wv_client* client = nvnc_get_userdata(nvnc_client);
assert(client);
if (client->pointer.pointer)
pointer_destroy(&client->pointer);
if (client->kb.virtual_keyboard) {
zwp_virtual_keyboard_v1_destroy(client->kb.virtual_keyboard);
keyboard_destroy(&client->kb);
}
zext_transient_seat_v1_destroy(client->chair);
wl_list_remove(&client->link);
free(client);
}
static void init_client_inputs(struct wayvnc* wayvnc, struct wv_client* client)
{
// Keyboard
struct xkb_rule_names rule_names = {
.rules = wayvnc->cfg.xkb_rules,
.layout = wayvnc->kb_layout ? wayvnc->kb_layout :
wayvnc->cfg.xkb_layout,
.model = wayvnc->cfg.xkb_model ? wayvnc->cfg.xkb_model :
"pc105",
.variant = wayvnc->kb_variant ? wayvnc->kb_variant :
wayvnc->cfg.xkb_variant,
.options = wayvnc->cfg.xkb_options,
};
client->kb.virtual_keyboard =
zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(
wayvnc->keyboard_manager, client->wl_seat);
assert(client->kb.virtual_keyboard);
int rc MAYBE_UNUSED = keyboard_init(&client->kb, &rule_names);
assert(rc == 0);
// Pointer
client->pointer.vnc = wayvnc->nvnc;
client->pointer.output = wayvnc->selected_output;
client->pointer.pointer = wayvnc->pointer_manager_version == 2
? zwlr_virtual_pointer_manager_v1_create_virtual_pointer_with_output(
wayvnc->pointer_manager, client->wl_seat,
wayvnc->selected_output->wl_output)
: zwlr_virtual_pointer_manager_v1_create_virtual_pointer(
wayvnc->pointer_manager, client->wl_seat);
pointer_init(&client->pointer);
}
void on_seat_ready(struct seat* seat)
{
struct wayvnc* wayvnc = seat->userdata;
struct wv_client* client;
wl_list_for_each(client, &wayvnc->clients, link)
if (!client->wl_seat &&
strcmp(client->seat_name, seat->name) == 0) {
client->wl_seat = seat->wl_seat;
init_client_inputs(wayvnc, client);
}
}
void transient_seat_failed(void* data, struct zext_transient_seat_v1* seat,
uint32_t reason)
{
// TODO: Handle properly
abort();
}
void transient_seat_ready(void* data, struct zext_transient_seat_v1* chair,
const char* name)
{
struct nvnc_client* nvnc_client = data;
struct wv_client* client = nvnc_get_userdata(nvnc_client);
struct nvnc* nvnc = nvnc_client_get_server(nvnc_client);
struct wayvnc* wayvnc = nvnc_get_userdata(nvnc);
strlcpy(client->seat_name, name, sizeof(client->seat_name));
struct seat* seat = seat_find_by_name(&wayvnc->seats, name);
if (seat) {
client->wl_seat = seat->wl_seat;
init_client_inputs(wayvnc, client);
}
}
struct zext_transient_seat_v1_listener transient_seat_listener = {
.failed = transient_seat_failed,
.ready = transient_seat_ready,
};
static void on_new_client(struct nvnc_client* nvnc_client)
{
struct nvnc* nvnc = nvnc_client_get_server(nvnc_client);
struct wayvnc* wayvnc = nvnc_get_userdata(nvnc);
struct wv_client* client = calloc(1, sizeof(*client));
assert(client);
int pid = getpid();
char name[256];
snprintf(name, sizeof(name), "wayvnc-%d-%" PRIu64, pid, seat_id++);
client->chair = zext_transient_seat_manager_v1_create(
zext_transient_seat_manager, name);
zext_transient_seat_v1_add_listener(client->chair,
&transient_seat_listener, nvnc_client);
nvnc_set_userdata(nvnc_client, client);
nvnc_set_client_cleanup_fn(nvnc_client, on_client_destroy);
wl_list_insert(&wayvnc->clients, &client->link);
}
static void on_pointer_event(struct nvnc_client* client, uint16_t x, uint16_t y,
enum nvnc_button_mask button_mask)
{
@ -443,29 +589,39 @@ static void on_pointer_event(struct nvnc_client* client, uint16_t x, uint16_t y,
struct nvnc* nvnc = nvnc_client_get_server(client);
struct wayvnc* wayvnc = nvnc_get_userdata(nvnc);
struct wv_client* wv_client = nvnc_get_userdata(client);
if (!wv_client->pointer.pointer)
return; /* Client does not have a seat yet */
uint32_t xfx = 0, xfy = 0;
output_transform_coord(wayvnc->selected_output, x, y, &xfx, &xfy);
pointer_set(&wayvnc->pointer_backend, xfx, xfy, button_mask);
pointer_set(&wv_client->pointer, xfx, xfy, button_mask);
}
static void on_key_event(struct nvnc_client* client, uint32_t symbol,
bool is_pressed)
{
struct nvnc* nvnc = nvnc_client_get_server(client);
struct wayvnc* wayvnc = nvnc_get_userdata(nvnc);
struct wv_client* wv_client = nvnc_get_userdata(client);
assert(wv_client);
keyboard_feed(&wayvnc->keyboard_backend, symbol, is_pressed);
if (!wv_client->kb.virtual_keyboard)
return; /* Client does not have a seat yet */
keyboard_feed(&wv_client->kb, symbol, is_pressed);
}
static void on_key_code_event(struct nvnc_client* client, uint32_t code,
bool is_pressed)
{
struct nvnc* nvnc = nvnc_client_get_server(client);
struct wayvnc* wayvnc = nvnc_get_userdata(nvnc);
struct wv_client* wv_client = nvnc_get_userdata(client);
assert(wv_client);
keyboard_feed_code(&wayvnc->keyboard_backend, code + 8, is_pressed);
if (!wv_client->kb.virtual_keyboard)
return; /* Client does not have a seat yet */
keyboard_feed_code(&wv_client->kb, code + 8, is_pressed);
}
static void on_client_cut_text(struct nvnc* server, const char* text, uint32_t len)
@ -512,6 +668,8 @@ int init_nvnc(struct wayvnc* self, const char* addr, uint16_t port)
nvnc_display_set_render_fn(self->nvnc_display, on_render);
nvnc_set_new_client_fn(self->nvnc, on_new_client);
if (self->cfg.enable_auth &&
nvnc_enable_auth(self->nvnc, self->cfg.private_key_file,
self->cfg.certificate_file, on_auth, self) < 0) {
@ -522,7 +680,7 @@ int init_nvnc(struct wayvnc* self, const char* addr, uint16_t port)
if (self->pointer_manager)
nvnc_set_pointer_fn(self->nvnc, on_pointer_event);
if (self->keyboard_backend.virtual_keyboard) {
if (self->keyboard_manager) {
nvnc_set_key_fn(self->nvnc, on_key_event);
nvnc_set_key_code_fn(self->nvnc, on_key_code_event);
}
@ -941,33 +1099,6 @@ int main(int argc, char* argv[])
self.screencopy.wl_output = out->wl_output;
self.screencopy.rate_limit = max_rate;
self.keyboard_backend.virtual_keyboard =
zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(
self.keyboard_manager, self.selected_seat->wl_seat);
struct xkb_rule_names rule_names = {
.rules = self.cfg.xkb_rules,
.layout = self.kb_layout ? self.kb_layout : self.cfg.xkb_layout,
.model = self.cfg.xkb_model ? self.cfg.xkb_model : "pc105",
.variant = self.kb_variant ? self.kb_variant :
self.cfg.xkb_variant,
.options = self.cfg.xkb_options,
};
keyboard_init(&self.keyboard_backend, &rule_names);
self.pointer_backend.vnc = self.nvnc;
self.pointer_backend.output = self.selected_output;
self.pointer_backend.pointer = self.pointer_manager_version == 2
? zwlr_virtual_pointer_manager_v1_create_virtual_pointer_with_output(
self.pointer_manager, self.selected_seat->wl_seat,
out->wl_output)
: zwlr_virtual_pointer_manager_v1_create_virtual_pointer(
self.pointer_manager, self.selected_seat->wl_seat);
pointer_init(&self.pointer_backend);
out->on_dimension_change = on_output_dimension_change;
out->userdata = &self;

View File

@ -30,6 +30,10 @@ static void seat_capabilities(void* data, struct wl_seat* wl_seat,
struct seat* self = data;
self->capabilities = capabilities;
self->has_capabilities = true;
if (self->has_capabilities && self->has_name && self->on_ready)
self->on_ready(self);
}
static void seat_name(void* data, struct wl_seat* wl_seat, const char* name)
@ -37,6 +41,10 @@ static void seat_name(void* data, struct wl_seat* wl_seat, const char* name)
struct seat* self = data;
strlcpy(self->name, name, sizeof(self->name));
self->has_name = true;
if (self->has_capabilities && self->has_name && self->on_ready)
self->on_ready(self);
}
static const struct wl_seat_listener seat_listener = {