Compare commits
6 Commits
master
...
transient-
Author | SHA1 | Date |
---|---|---|
Andri Yngvason | b927394490 | |
Andri Yngvason | c302c20939 | |
Andri Yngvason | 842da93de4 | |
Andri Yngvason | 0414e1fd87 | |
Andri Yngvason | 75173ea838 | |
Andri Yngvason | 1ef290d2d4 |
|
@ -21,10 +21,13 @@
|
||||||
struct ctl;
|
struct ctl;
|
||||||
struct cmd_response;
|
struct cmd_response;
|
||||||
|
|
||||||
struct ctl_server_vnc_client {
|
struct ctl_server_client;
|
||||||
char id[64];
|
|
||||||
char hostname[256];
|
struct ctl_server_client_info {
|
||||||
char username[256];
|
int id;
|
||||||
|
const char *hostname;
|
||||||
|
const char *username;
|
||||||
|
const char *seat;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ctl_server_output {
|
struct ctl_server_output {
|
||||||
|
@ -46,11 +49,10 @@ struct ctl_server_actions {
|
||||||
const char* id);
|
const char* id);
|
||||||
struct cmd_response* (*on_wayvnc_exit)(struct ctl*);
|
struct cmd_response* (*on_wayvnc_exit)(struct ctl*);
|
||||||
|
|
||||||
// Return number of elements created
|
struct ctl_server_client *(*client_next)(struct ctl*,
|
||||||
// Allocate 'clients' array or set ton ULL if none
|
struct ctl_server_client* prev);
|
||||||
// Receiver will free(clients) when done.
|
void (*client_info)(const struct ctl_server_client*,
|
||||||
int (*get_client_list)(struct ctl*,
|
struct ctl_server_client_info* info);
|
||||||
struct ctl_server_vnc_client** clients);
|
|
||||||
|
|
||||||
// Return number of elements created
|
// Return number of elements created
|
||||||
// Allocate 'outputs' array or set to NULL if none
|
// Allocate 'outputs' array or set to NULL if none
|
||||||
|
@ -68,15 +70,11 @@ struct cmd_response* cmd_ok(void);
|
||||||
struct cmd_response* cmd_failed(const char* fmt, ...);
|
struct cmd_response* cmd_failed(const char* fmt, ...);
|
||||||
|
|
||||||
void ctl_server_event_connected(struct ctl*,
|
void ctl_server_event_connected(struct ctl*,
|
||||||
const char* client_id,
|
const struct ctl_server_client_info *info,
|
||||||
const char* client_hostname,
|
|
||||||
const char* client_username,
|
|
||||||
int new_connection_count);
|
int new_connection_count);
|
||||||
|
|
||||||
void ctl_server_event_disconnected(struct ctl*,
|
void ctl_server_event_disconnected(struct ctl*,
|
||||||
const char* client_id,
|
const struct ctl_server_client_info *info,
|
||||||
const char* client_hostname,
|
|
||||||
const char* client_username,
|
|
||||||
int new_connection_count);
|
int new_connection_count);
|
||||||
|
|
||||||
void ctl_server_event_capture_changed(struct ctl*,
|
void ctl_server_event_capture_changed(struct ctl*,
|
||||||
|
|
|
@ -22,6 +22,7 @@ client_protocols = [
|
||||||
'linux-dmabuf-unstable-v1.xml',
|
'linux-dmabuf-unstable-v1.xml',
|
||||||
'wlr-data-control-unstable-v1.xml',
|
'wlr-data-control-unstable-v1.xml',
|
||||||
'wlr-output-power-management-unstable-v1.xml',
|
'wlr-output-power-management-unstable-v1.xml',
|
||||||
|
'transient-seat-v1.xml',
|
||||||
]
|
]
|
||||||
|
|
||||||
client_protos_src = []
|
client_protos_src = []
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<protocol name="transient_seat_v1">
|
||||||
|
<copyright>
|
||||||
|
Copyright © 2020 - 2023 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 privileved clients to create
|
||||||
|
independent seats that will be removed from the compositor when the client
|
||||||
|
destroys its seat.
|
||||||
|
|
||||||
|
This protocol is intended for use with virtual input protocols such as
|
||||||
|
"virtual_keyboard_unstable_v1" or "wlr_virtual_pointer_unstable_v1", both
|
||||||
|
of which allow the user to select a seat.
|
||||||
|
|
||||||
|
The "wl_seat" global created by this protocol does not generate input events
|
||||||
|
on its own, or have any capabilities except those assigned to it by other
|
||||||
|
protocol extensions, such as the ones mentioned above.
|
||||||
|
|
||||||
|
For example, a remote desktop server can create a seat with virtual inputs
|
||||||
|
for each remote user by following these steps for each new connection:
|
||||||
|
* Create a transient seat
|
||||||
|
* Wait for the transient seat to be created
|
||||||
|
* Locate a "wl_seat" global with a matching name
|
||||||
|
* Create virtual inputs using the resulting "wl_seat" global
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<interface name="ext_transient_seat_manager_v1" version="1">
|
||||||
|
<description summary="transient seat manager">
|
||||||
|
The transient seat manager creates short-lived seats.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<request name="create">
|
||||||
|
<description summary="create a transient seat">
|
||||||
|
Create a new seat that is removed when the client side object is
|
||||||
|
destroyed.
|
||||||
|
</description>
|
||||||
|
<arg name="seat" type="new_id" interface="ext_transient_seat_v1"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the manager">
|
||||||
|
Destroy the manager.
|
||||||
|
|
||||||
|
All objects created by the manager will remain valid until they are
|
||||||
|
destroyed themselves.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="ext_transient_seat_v1" version="1">
|
||||||
|
<description summary="transient seat handle">
|
||||||
|
The life time of the transient seat handle is equal to that of the seat
|
||||||
|
itself.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<event name="ready">
|
||||||
|
<description summary="transient seat is ready">
|
||||||
|
This event advertises the global name for the wl_seat to be used with
|
||||||
|
wl_registry_bind.
|
||||||
|
|
||||||
|
It is sent exactly once, immediately after the transient seat is created
|
||||||
|
and the new "wl_seat" global is advertised, if and only if the creation
|
||||||
|
of the transient seat was allowed.
|
||||||
|
</description>
|
||||||
|
<arg name="global_name" type="uint"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="denied">
|
||||||
|
<description summary="transient seat creation denied">
|
||||||
|
The event informs the client that the compositor denied its request to
|
||||||
|
create a transient seat.
|
||||||
|
|
||||||
|
It is sent exactly once, immediately after the transient seat object is
|
||||||
|
created, if and only if the creation of the transient seat was denied.
|
||||||
|
|
||||||
|
After receiving this event, the client should destroy the object.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy transient seat">
|
||||||
|
When the transient seat object is destroyed by the client, the
|
||||||
|
associated seat created by the compositor is also destroyed.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
</protocol>
|
|
@ -328,24 +328,51 @@ static struct cmd_response* generate_version_object()
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct ctl_server_client* ctl_server_client_first(struct ctl* self)
|
||||||
|
{
|
||||||
|
return self->actions.client_next(self, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ctl_server_client* ctl_server_client_next(struct ctl* self,
|
||||||
|
struct ctl_server_client* prev)
|
||||||
|
{
|
||||||
|
return self->actions.client_next(self, prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ctl_server_client_get_info(struct ctl* self,
|
||||||
|
const struct ctl_server_client* client,
|
||||||
|
struct ctl_server_client_info* info)
|
||||||
|
{
|
||||||
|
return self->actions.client_info(client, info);
|
||||||
|
}
|
||||||
|
|
||||||
static struct cmd_response* generate_vnc_client_list(struct ctl* self)
|
static struct cmd_response* generate_vnc_client_list(struct ctl* self)
|
||||||
{
|
{
|
||||||
struct ctl_server_vnc_client* clients;
|
|
||||||
size_t num_clients = self->actions.get_client_list(self, &clients);
|
|
||||||
struct cmd_response* response = cmd_ok();
|
struct cmd_response* response = cmd_ok();
|
||||||
|
|
||||||
response->data = json_array();
|
response->data = json_array();
|
||||||
for (size_t i = 0; i < num_clients; ++i) {
|
|
||||||
json_t* packed = json_pack("{s:s}", "id", clients[i].id);
|
struct ctl_server_client* client;
|
||||||
if (clients[i].hostname[0] != '\0')
|
for (client = ctl_server_client_first(self); client;
|
||||||
|
client = ctl_server_client_next(self, client)) {
|
||||||
|
struct ctl_server_client_info info = {};
|
||||||
|
ctl_server_client_get_info(self, client, &info);
|
||||||
|
|
||||||
|
char id_str[64];
|
||||||
|
snprintf(id_str, sizeof(id_str), "%d", info.id);
|
||||||
|
json_t* packed = json_pack("{s:s}", "id", id_str);
|
||||||
|
|
||||||
|
if (info.hostname)
|
||||||
json_object_set_new(packed, "hostname",
|
json_object_set_new(packed, "hostname",
|
||||||
json_string(clients[i].hostname));
|
json_string(info.hostname));
|
||||||
if (clients[i].username[0] != '\0')
|
|
||||||
|
if (info.username)
|
||||||
json_object_set_new(packed, "username",
|
json_object_set_new(packed, "username",
|
||||||
json_string(clients[i].username));
|
json_string(info.username));
|
||||||
|
|
||||||
|
json_object_set_new(packed, "seat", json_string(info.seat));
|
||||||
json_array_append_new(response->data, packed);
|
json_array_append_new(response->data, packed);
|
||||||
}
|
}
|
||||||
free(clients);
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -829,15 +856,18 @@ struct cmd_response* cmd_failed(const char* fmt, ...)
|
||||||
}
|
}
|
||||||
|
|
||||||
json_t* pack_connection_event_params(
|
json_t* pack_connection_event_params(
|
||||||
const char* client_id,
|
const struct ctl_server_client_info *info,
|
||||||
const char* client_hostname,
|
|
||||||
const char* client_username,
|
|
||||||
int new_connection_count)
|
int new_connection_count)
|
||||||
{
|
{
|
||||||
return json_pack("{s:s, s:s?, s:s?, s:i}",
|
// TODO: Why is the id a string?
|
||||||
"id", client_id,
|
char id_str[64];
|
||||||
"hostname", client_hostname,
|
snprintf(id_str, sizeof(id_str), "%d", info->id);
|
||||||
"username", client_username,
|
|
||||||
|
return json_pack("{s:s, s:s?, s:s?, s:s?, s:i}",
|
||||||
|
"id", id_str,
|
||||||
|
"hostname", info->hostname,
|
||||||
|
"username", info->username,
|
||||||
|
"seat", info->seat,
|
||||||
"connection_count", new_connection_count);
|
"connection_count", new_connection_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -879,34 +909,28 @@ int ctl_server_enqueue_event(struct ctl* self, enum event_type evt_type,
|
||||||
|
|
||||||
static void ctl_server_event_connect(struct ctl* self,
|
static void ctl_server_event_connect(struct ctl* self,
|
||||||
enum event_type evt_type,
|
enum event_type evt_type,
|
||||||
const char* client_id,
|
const struct ctl_server_client_info *info,
|
||||||
const char* client_hostname,
|
|
||||||
const char* client_username,
|
|
||||||
int new_connection_count)
|
int new_connection_count)
|
||||||
{
|
{
|
||||||
json_t* params = pack_connection_event_params(client_id, client_hostname,
|
json_t* params =
|
||||||
client_username, new_connection_count);
|
pack_connection_event_params(info, new_connection_count);
|
||||||
ctl_server_enqueue_event(self, evt_type, params);
|
ctl_server_enqueue_event(self, evt_type, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ctl_server_event_connected(struct ctl* self,
|
void ctl_server_event_connected(struct ctl* self,
|
||||||
const char* client_id,
|
const struct ctl_server_client_info *info,
|
||||||
const char* client_hostname,
|
|
||||||
const char* client_username,
|
|
||||||
int new_connection_count)
|
int new_connection_count)
|
||||||
{
|
{
|
||||||
ctl_server_event_connect(self, EVT_CLIENT_CONNECTED, client_id,
|
ctl_server_event_connect(self, EVT_CLIENT_CONNECTED, info,
|
||||||
client_hostname, client_username, new_connection_count);
|
new_connection_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ctl_server_event_disconnected(struct ctl* self,
|
void ctl_server_event_disconnected(struct ctl* self,
|
||||||
const char* client_id,
|
const struct ctl_server_client_info *info,
|
||||||
const char* client_hostname,
|
|
||||||
const char* client_username,
|
|
||||||
int new_connection_count)
|
int new_connection_count)
|
||||||
{
|
{
|
||||||
ctl_server_event_connect(self, EVT_CLIENT_DISCONNECTED, client_id,
|
ctl_server_event_connect(self, EVT_CLIENT_DISCONNECTED, info,
|
||||||
client_hostname, client_username, new_connection_count);
|
new_connection_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ctl_server_event_capture_changed(struct ctl* self,
|
void ctl_server_event_capture_changed(struct ctl* self,
|
||||||
|
|
181
src/main.c
181
src/main.c
|
@ -40,6 +40,7 @@
|
||||||
#include "xdg-output-unstable-v1.h"
|
#include "xdg-output-unstable-v1.h"
|
||||||
#include "wlr-output-power-management-unstable-v1.h"
|
#include "wlr-output-power-management-unstable-v1.h"
|
||||||
#include "linux-dmabuf-unstable-v1.h"
|
#include "linux-dmabuf-unstable-v1.h"
|
||||||
|
#include "transient-seat-v1.h"
|
||||||
#include "screencopy.h"
|
#include "screencopy.h"
|
||||||
#include "data-control.h"
|
#include "data-control.h"
|
||||||
#include "strlcpy.h"
|
#include "strlcpy.h"
|
||||||
|
@ -83,9 +84,10 @@ struct wayvnc {
|
||||||
struct zwp_virtual_keyboard_manager_v1* keyboard_manager;
|
struct zwp_virtual_keyboard_manager_v1* keyboard_manager;
|
||||||
struct zwlr_virtual_pointer_manager_v1* pointer_manager;
|
struct zwlr_virtual_pointer_manager_v1* pointer_manager;
|
||||||
struct zwlr_data_control_manager_v1* data_control_manager;
|
struct zwlr_data_control_manager_v1* data_control_manager;
|
||||||
|
struct ext_transient_seat_manager_v1* transient_seat_manager;
|
||||||
|
|
||||||
struct output* selected_output;
|
struct output* selected_output;
|
||||||
const struct seat* selected_seat;
|
struct seat* selected_seat;
|
||||||
|
|
||||||
struct screencopy screencopy;
|
struct screencopy screencopy;
|
||||||
|
|
||||||
|
@ -102,6 +104,7 @@ struct wayvnc {
|
||||||
uint32_t n_frames_captured;
|
uint32_t n_frames_captured;
|
||||||
|
|
||||||
bool disable_input;
|
bool disable_input;
|
||||||
|
bool use_transient_seat;
|
||||||
|
|
||||||
int nr_clients;
|
int nr_clients;
|
||||||
struct aml_ticker* performance_ticker;
|
struct aml_ticker* performance_ticker;
|
||||||
|
@ -116,6 +119,9 @@ struct wayvnc_client {
|
||||||
struct wayvnc* server;
|
struct wayvnc* server;
|
||||||
struct nvnc_client* nvnc_client;
|
struct nvnc_client* nvnc_client;
|
||||||
|
|
||||||
|
struct seat* seat;
|
||||||
|
struct ext_transient_seat_v1* transient_seat;
|
||||||
|
|
||||||
unsigned id;
|
unsigned id;
|
||||||
struct pointer pointer;
|
struct pointer pointer;
|
||||||
struct keyboard keyboard;
|
struct keyboard keyboard;
|
||||||
|
@ -128,6 +134,7 @@ static void on_nvnc_client_new(struct nvnc_client* client);
|
||||||
void switch_to_output(struct wayvnc*, struct output*);
|
void switch_to_output(struct wayvnc*, struct output*);
|
||||||
void switch_to_next_output(struct wayvnc*);
|
void switch_to_next_output(struct wayvnc*);
|
||||||
void switch_to_prev_output(struct wayvnc*);
|
void switch_to_prev_output(struct wayvnc*);
|
||||||
|
static void client_init_seat(struct wayvnc_client* self);
|
||||||
static void client_init_pointer(struct wayvnc_client* self);
|
static void client_init_pointer(struct wayvnc_client* self);
|
||||||
static void client_init_keyboard(struct wayvnc_client* self);
|
static void client_init_keyboard(struct wayvnc_client* self);
|
||||||
static void client_init_data_control(struct wayvnc_client* self);
|
static void client_init_data_control(struct wayvnc_client* self);
|
||||||
|
@ -155,7 +162,7 @@ static bool registry_add_input(void* data, struct wl_registry* registry,
|
||||||
|
|
||||||
struct seat* seat = seat_new(wl_seat, id);
|
struct seat* seat = seat_new(wl_seat, id);
|
||||||
if (!seat) {
|
if (!seat) {
|
||||||
wl_seat_destroy(wl_seat);
|
wl_seat_release(wl_seat);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,6 +190,12 @@ static bool registry_add_input(void* data, struct wl_registry* registry,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strcmp(interface, ext_transient_seat_manager_v1_interface.name) == 0) {
|
||||||
|
self->transient_seat_manager = wl_registry_bind(registry, id,
|
||||||
|
&ext_transient_seat_manager_v1_interface, 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -416,6 +429,11 @@ static int init_wayland(struct wayvnc* self)
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!self->transient_seat_manager && self->use_transient_seat) {
|
||||||
|
nvnc_log(NVNC_LOG_ERROR, "Transient seat protocol not supported by compositor.");
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
if (!self->screencopy.manager) {
|
if (!self->screencopy.manager) {
|
||||||
nvnc_log(NVNC_LOG_ERROR, "Screencopy protocol not supported by compositor. Exiting. Refer to FAQ section in man page.");
|
nvnc_log(NVNC_LOG_ERROR, "Screencopy protocol not supported by compositor. Exiting. Refer to FAQ section in man page.");
|
||||||
goto failure;
|
goto failure;
|
||||||
|
@ -489,33 +507,27 @@ struct cmd_response* on_output_switch(struct ctl* ctl,
|
||||||
return cmd_ok();
|
return cmd_ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_client_list(struct ctl* ctl,
|
static struct ctl_server_client *client_next(struct ctl* ctl,
|
||||||
struct ctl_server_vnc_client** clients)
|
struct ctl_server_client *prev)
|
||||||
{
|
{
|
||||||
struct wayvnc* self = ctl_server_userdata(ctl);
|
struct wayvnc* self = ctl_server_userdata(ctl);
|
||||||
if (self->nr_clients == 0) {
|
struct nvnc_client* vnc_prev = (struct nvnc_client*)prev;
|
||||||
*clients = NULL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*clients = calloc(self->nr_clients, sizeof(**clients));
|
|
||||||
struct nvnc_client* nvnc_client = nvnc_client_first(self->nvnc);
|
|
||||||
for (int i = 0; i < self->nr_clients && nvnc_client; ++i) {
|
|
||||||
struct wayvnc_client* client = nvnc_get_userdata(nvnc_client);
|
|
||||||
struct ctl_server_vnc_client* ctl_client =&(*clients)[i];
|
|
||||||
|
|
||||||
snprintf(ctl_client->id, sizeof(ctl_client->id), "%u",
|
return prev ? (struct ctl_server_client*)nvnc_client_next(vnc_prev) :
|
||||||
client->id);
|
(struct ctl_server_client*)nvnc_client_first(self->nvnc);
|
||||||
const char* hostname = nvnc_client_get_hostname(nvnc_client);
|
|
||||||
if (hostname)
|
|
||||||
strlcpy(ctl_client->hostname, hostname,
|
|
||||||
sizeof(ctl_client->hostname));
|
|
||||||
const char* username = nvnc_client_get_auth_username(nvnc_client);
|
|
||||||
if (username)
|
|
||||||
strlcpy(ctl_client->username, username,
|
|
||||||
sizeof(ctl_client->username));
|
|
||||||
nvnc_client = nvnc_client_next(nvnc_client);
|
|
||||||
}
|
}
|
||||||
return self->nr_clients;
|
|
||||||
|
static void client_info(const struct ctl_server_client* client_handle,
|
||||||
|
struct ctl_server_client_info* info)
|
||||||
|
{
|
||||||
|
const struct nvnc_client *vnc_client =
|
||||||
|
(const struct nvnc_client*)client_handle;
|
||||||
|
const struct wayvnc_client *client = nvnc_get_userdata(vnc_client);
|
||||||
|
|
||||||
|
info->id = client->id;
|
||||||
|
info->hostname = nvnc_client_get_hostname(vnc_client);
|
||||||
|
info->username = nvnc_client_get_auth_username(vnc_client);
|
||||||
|
info->seat = client->seat->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_output_list(struct ctl* ctl,
|
static int get_output_list(struct ctl* ctl,
|
||||||
|
@ -1000,6 +1012,7 @@ static struct wayvnc_client* client_create(struct wayvnc* wayvnc,
|
||||||
self->nvnc_client = nvnc_client;
|
self->nvnc_client = nvnc_client;
|
||||||
|
|
||||||
self->id = next_client_id++;
|
self->id = next_client_id++;
|
||||||
|
client_init_seat(self);
|
||||||
client_init_keyboard(self);
|
client_init_keyboard(self);
|
||||||
client_init_pointer(self);
|
client_init_pointer(self);
|
||||||
client_init_data_control(self);
|
client_init_data_control(self);
|
||||||
|
@ -1023,6 +1036,10 @@ static void client_destroy(void* obj)
|
||||||
if (self->data_control.manager)
|
if (self->data_control.manager)
|
||||||
data_control_destroy(&self->data_control);
|
data_control_destroy(&self->data_control);
|
||||||
|
|
||||||
|
if (self->server->use_transient_seat) {
|
||||||
|
ext_transient_seat_v1_destroy(self->transient_seat);
|
||||||
|
}
|
||||||
|
|
||||||
free(self);
|
free(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1036,12 +1053,14 @@ static void on_nvnc_client_cleanup(struct nvnc_client* client)
|
||||||
nvnc_log(NVNC_LOG_DEBUG, "Client disconnected, new client count: %d",
|
nvnc_log(NVNC_LOG_DEBUG, "Client disconnected, new client count: %d",
|
||||||
self->nr_clients);
|
self->nr_clients);
|
||||||
|
|
||||||
char id[64];
|
struct ctl_server_client_info info = {
|
||||||
snprintf(id, sizeof(id), "%u", wayvnc_client->id);
|
.id = wayvnc_client->id,
|
||||||
ctl_server_event_disconnected(self->ctl, id,
|
.hostname = nvnc_client_get_hostname(client),
|
||||||
nvnc_client_get_hostname(client),
|
.username = nvnc_client_get_auth_username(client),
|
||||||
nvnc_client_get_auth_username(client),
|
.seat = wayvnc_client->seat->name,
|
||||||
self->nr_clients);
|
};
|
||||||
|
|
||||||
|
ctl_server_event_disconnected(self->ctl, &info, self->nr_clients);
|
||||||
|
|
||||||
if (self->nr_clients == 0) {
|
if (self->nr_clients == 0) {
|
||||||
nvnc_log(NVNC_LOG_INFO, "Stopping screen capture");
|
nvnc_log(NVNC_LOG_INFO, "Stopping screen capture");
|
||||||
|
@ -1069,12 +1088,14 @@ static void on_nvnc_client_new(struct nvnc_client* client)
|
||||||
nvnc_log(NVNC_LOG_DEBUG, "Client connected, new client count: %d",
|
nvnc_log(NVNC_LOG_DEBUG, "Client connected, new client count: %d",
|
||||||
self->nr_clients);
|
self->nr_clients);
|
||||||
|
|
||||||
char id[64];
|
struct ctl_server_client_info info = {
|
||||||
snprintf(id, sizeof(id), "%u", wayvnc_client->id);
|
.id = wayvnc_client->id,
|
||||||
ctl_server_event_connected(self->ctl, id,
|
.hostname = nvnc_client_get_hostname(client),
|
||||||
nvnc_client_get_hostname(client),
|
.username = nvnc_client_get_auth_username(client),
|
||||||
nvnc_client_get_auth_username(client),
|
.seat = wayvnc_client->seat->name,
|
||||||
self->nr_clients);
|
};
|
||||||
|
|
||||||
|
ctl_server_event_connected(self->ctl, &info, self->nr_clients);
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_keyboard_option(struct wayvnc* self, const char* arg)
|
void parse_keyboard_option(struct wayvnc* self, const char* arg)
|
||||||
|
@ -1107,16 +1128,73 @@ static void client_init_pointer(struct wayvnc_client* self)
|
||||||
|
|
||||||
self->pointer.pointer = pointer_manager_version >= 2
|
self->pointer.pointer = pointer_manager_version >= 2
|
||||||
? zwlr_virtual_pointer_manager_v1_create_virtual_pointer_with_output(
|
? zwlr_virtual_pointer_manager_v1_create_virtual_pointer_with_output(
|
||||||
wayvnc->pointer_manager, wayvnc->selected_seat->wl_seat,
|
wayvnc->pointer_manager, self->seat->wl_seat,
|
||||||
wayvnc->selected_output->wl_output)
|
wayvnc->selected_output->wl_output)
|
||||||
: zwlr_virtual_pointer_manager_v1_create_virtual_pointer(
|
: zwlr_virtual_pointer_manager_v1_create_virtual_pointer(
|
||||||
wayvnc->pointer_manager, wayvnc->selected_seat->wl_seat);
|
wayvnc->pointer_manager, self->seat->wl_seat);
|
||||||
|
|
||||||
if (pointer_init(&self->pointer) < 0) {
|
if (pointer_init(&self->pointer) < 0) {
|
||||||
nvnc_log(NVNC_LOG_ERROR, "Failed to initialise pointer");
|
nvnc_log(NVNC_LOG_ERROR, "Failed to initialise pointer");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_transient_seat_ready(void* data,
|
||||||
|
struct ext_transient_seat_v1* transient_seat,
|
||||||
|
uint32_t global_name)
|
||||||
|
{
|
||||||
|
(void)transient_seat;
|
||||||
|
|
||||||
|
struct wayvnc_client* client = data;
|
||||||
|
struct wayvnc* wayvnc = client->server;
|
||||||
|
|
||||||
|
struct seat* seat = seat_find_by_id(&wayvnc->seats, global_name);
|
||||||
|
assert(seat);
|
||||||
|
|
||||||
|
client->seat = seat;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_transient_seat_denied(void* data,
|
||||||
|
struct ext_transient_seat_v1* transient_seat)
|
||||||
|
{
|
||||||
|
(void)transient_seat;
|
||||||
|
|
||||||
|
struct wayvnc_client* client = data;
|
||||||
|
struct wayvnc* wayvnc = client->server;
|
||||||
|
|
||||||
|
// TODO: Should this perhaps be fatal?
|
||||||
|
nvnc_log(NVNC_LOG_WARNING, "Transient seat denied");
|
||||||
|
|
||||||
|
client->seat = wayvnc->selected_seat;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void client_init_seat(struct wayvnc_client* self)
|
||||||
|
{
|
||||||
|
struct wayvnc* wayvnc = self->server;
|
||||||
|
|
||||||
|
if (wayvnc->disable_input)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (wayvnc->use_transient_seat) {
|
||||||
|
self->transient_seat = ext_transient_seat_manager_v1_create(
|
||||||
|
wayvnc->transient_seat_manager);
|
||||||
|
|
||||||
|
static const struct ext_transient_seat_v1_listener listener = {
|
||||||
|
.ready = handle_transient_seat_ready,
|
||||||
|
.denied = handle_transient_seat_denied,
|
||||||
|
};
|
||||||
|
ext_transient_seat_v1_add_listener(self->transient_seat,
|
||||||
|
&listener, self);
|
||||||
|
|
||||||
|
// TODO: Make this asynchronous
|
||||||
|
wl_display_roundtrip(wayvnc->display);
|
||||||
|
wl_display_dispatch(wayvnc->display);
|
||||||
|
|
||||||
|
assert(self->seat);
|
||||||
|
} else {
|
||||||
|
self->seat = wayvnc->selected_seat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void client_init_keyboard(struct wayvnc_client* self)
|
static void client_init_keyboard(struct wayvnc_client* self)
|
||||||
{
|
{
|
||||||
struct wayvnc* wayvnc = self->server;
|
struct wayvnc* wayvnc = self->server;
|
||||||
|
@ -1126,8 +1204,7 @@ static void client_init_keyboard(struct wayvnc_client* self)
|
||||||
|
|
||||||
self->keyboard.virtual_keyboard =
|
self->keyboard.virtual_keyboard =
|
||||||
zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(
|
zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(
|
||||||
wayvnc->keyboard_manager,
|
wayvnc->keyboard_manager, self->seat->wl_seat);
|
||||||
wayvnc->selected_seat->wl_seat);
|
|
||||||
|
|
||||||
struct xkb_rule_names rule_names = {
|
struct xkb_rule_names rule_names = {
|
||||||
.rules = wayvnc->cfg.xkb_rules,
|
.rules = wayvnc->cfg.xkb_rules,
|
||||||
|
@ -1163,7 +1240,7 @@ static void client_init_data_control(struct wayvnc_client* self)
|
||||||
|
|
||||||
self->data_control.manager = wayvnc->data_control_manager;
|
self->data_control.manager = wayvnc->data_control_manager;
|
||||||
data_control_init(&self->data_control, wayvnc->display, wayvnc->nvnc,
|
data_control_init(&self->data_control, wayvnc->display, wayvnc->nvnc,
|
||||||
wayvnc->selected_seat->wl_seat);
|
self->seat->wl_seat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_selected_output(struct wayvnc* self)
|
void log_selected_output(struct wayvnc* self)
|
||||||
|
@ -1266,6 +1343,7 @@ int main(int argc, char* argv[])
|
||||||
bool show_performance = false;
|
bool show_performance = false;
|
||||||
int max_rate = 30;
|
int max_rate = 30;
|
||||||
bool disable_input = false;
|
bool disable_input = false;
|
||||||
|
bool use_transient_seat = false;
|
||||||
|
|
||||||
int drm_fd MAYBE_UNUSED = -1;
|
int drm_fd MAYBE_UNUSED = -1;
|
||||||
|
|
||||||
|
@ -1290,6 +1368,8 @@ int main(int argc, char* argv[])
|
||||||
"Select seat by name." },
|
"Select seat by name." },
|
||||||
{ 'S', "socket", "<path>",
|
{ 'S', "socket", "<path>",
|
||||||
"Control socket path." },
|
"Control socket path." },
|
||||||
|
{ 't', "transient-seat", NULL,
|
||||||
|
"Use transient seat." },
|
||||||
{ 'r', "render-cursor", NULL,
|
{ 'r', "render-cursor", NULL,
|
||||||
"Enable overlay cursor rendering." },
|
"Enable overlay cursor rendering." },
|
||||||
{ 'f', "max-fps", "<fps>",
|
{ 'f', "max-fps", "<fps>",
|
||||||
|
@ -1342,6 +1422,7 @@ int main(int argc, char* argv[])
|
||||||
log_level = log_level_from_string(
|
log_level = log_level_from_string(
|
||||||
option_parser_get_value(&option_parser, "log-level"));
|
option_parser_get_value(&option_parser, "log-level"));
|
||||||
max_rate = atoi(option_parser_get_value(&option_parser, "max-fps"));
|
max_rate = atoi(option_parser_get_value(&option_parser, "max-fps"));
|
||||||
|
use_transient_seat = option_parser_get_value(&option_parser, "transient-seat");
|
||||||
|
|
||||||
keyboard_options = option_parser_get_value(&option_parser, "keyboard");
|
keyboard_options = option_parser_get_value(&option_parser, "keyboard");
|
||||||
if (keyboard_options)
|
if (keyboard_options)
|
||||||
|
@ -1361,6 +1442,16 @@ int main(int argc, char* argv[])
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (use_transient_seat && disable_input) {
|
||||||
|
nvnc_log(NVNC_LOG_ERROR, "transient-seat and disable-input are conflicting options");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seat_name && use_transient_seat) {
|
||||||
|
nvnc_log(NVNC_LOG_ERROR, "transient seat and seat are conflicting options");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
int cfg_rc = cfg_load(&self.cfg, cfg_file);
|
int cfg_rc = cfg_load(&self.cfg, cfg_file);
|
||||||
if (cfg_rc != 0 && (cfg_file || errno != ENOENT)) {
|
if (cfg_rc != 0 && (cfg_file || errno != ENOENT)) {
|
||||||
|
@ -1386,6 +1477,7 @@ int main(int argc, char* argv[])
|
||||||
if (!port) port = DEFAULT_PORT;
|
if (!port) port = DEFAULT_PORT;
|
||||||
|
|
||||||
self.disable_input = disable_input;
|
self.disable_input = disable_input;
|
||||||
|
self.use_transient_seat = use_transient_seat;
|
||||||
|
|
||||||
if (init_wayland(&self) < 0) {
|
if (init_wayland(&self) < 0) {
|
||||||
nvnc_log(NVNC_LOG_ERROR, "Failed to initialise wayland");
|
nvnc_log(NVNC_LOG_ERROR, "Failed to initialise wayland");
|
||||||
|
@ -1415,7 +1507,7 @@ int main(int argc, char* argv[])
|
||||||
nvnc_log(NVNC_LOG_ERROR, "No such seat");
|
nvnc_log(NVNC_LOG_ERROR, "No such seat");
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
} else if (!self.disable_input) {
|
} else if (!self.disable_input && !self.use_transient_seat) {
|
||||||
seat = seat_first(&self.seats);
|
seat = seat_first(&self.seats);
|
||||||
if (!seat) {
|
if (!seat) {
|
||||||
nvnc_log(NVNC_LOG_ERROR, "No seat found");
|
nvnc_log(NVNC_LOG_ERROR, "No seat found");
|
||||||
|
@ -1466,7 +1558,8 @@ int main(int argc, char* argv[])
|
||||||
.userdata = &self,
|
.userdata = &self,
|
||||||
.on_output_cycle = on_output_cycle,
|
.on_output_cycle = on_output_cycle,
|
||||||
.on_output_switch = on_output_switch,
|
.on_output_switch = on_output_switch,
|
||||||
.get_client_list = get_client_list,
|
.client_next = client_next,
|
||||||
|
.client_info = client_info,
|
||||||
.get_output_list = get_output_list,
|
.get_output_list = get_output_list,
|
||||||
.on_disconnect_client = on_disconnect_client,
|
.on_disconnect_client = on_disconnect_client,
|
||||||
.on_wayvnc_exit = on_wayvnc_exit,
|
.on_wayvnc_exit = on_wayvnc_exit,
|
||||||
|
|
Loading…
Reference in New Issue