seatd: Tear down VT when disabled client closes
If a client closed while it was disabled, the VT would not be torn down. If the user navigated back to the VT it belonged to, they would be stuck. When a client is disabled, open the fd for the VT it belonged to and perform regular teardown on it.
This commit is contained in:
parent
45bab8b258
commit
65d91351ab
2 changed files with 45 additions and 23 deletions
|
@ -44,7 +44,6 @@ void seat_destroy(struct seat *seat);
|
|||
int seat_add_client(struct seat *seat, struct client *client);
|
||||
int seat_remove_client(struct client *client);
|
||||
int seat_open_client(struct seat *seat, struct client *client);
|
||||
int seat_close_client(struct client *client);
|
||||
int seat_ack_disable_client(struct client *client);
|
||||
|
||||
struct seat_device *seat_open_device(struct client *client, const char *path);
|
||||
|
|
65
seatd/seat.c
65
seatd/seat.c
|
@ -18,6 +18,8 @@
|
|||
#include "seat.h"
|
||||
#include "terminal.h"
|
||||
|
||||
static int seat_close_client(struct client *client);
|
||||
|
||||
struct seat *seat_create(const char *seat_name, bool vt_bound) {
|
||||
struct seat *seat = calloc(1, sizeof(struct seat));
|
||||
if (seat == NULL) {
|
||||
|
@ -77,19 +79,33 @@ static int vt_open(struct seat *seat, int vt) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void vt_close_fd(int fd) {
|
||||
terminal_set_process_switching(fd, true);
|
||||
terminal_set_keyboard(fd, true);
|
||||
terminal_set_graphics(fd, false);
|
||||
}
|
||||
|
||||
static void vt_close(struct seat *seat) {
|
||||
if (seat->cur_ttyfd == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
terminal_set_process_switching(seat->cur_ttyfd, true);
|
||||
terminal_set_keyboard(seat->cur_ttyfd, true);
|
||||
terminal_set_graphics(seat->cur_ttyfd, false);
|
||||
|
||||
vt_close_fd(seat->cur_ttyfd);
|
||||
close(seat->cur_ttyfd);
|
||||
seat->cur_ttyfd = -1;
|
||||
}
|
||||
|
||||
static int vt_close_num(int vt) {
|
||||
int ttyfd = terminal_open(vt);
|
||||
if (ttyfd == -1) {
|
||||
log_errorf("could not open terminal %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
vt_close_fd(ttyfd);
|
||||
close(ttyfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vt_switch(struct seat *seat, int vt) {
|
||||
int ttyfd = terminal_open(seat->cur_vt);
|
||||
if (ttyfd == -1) {
|
||||
|
@ -168,9 +184,7 @@ int seat_remove_client(struct client *client) {
|
|||
seat_close_device(client, device);
|
||||
}
|
||||
|
||||
if (seat->active_client == client) {
|
||||
seat_close_client(client);
|
||||
}
|
||||
|
||||
client->seat = NULL;
|
||||
log_debug("removed client");
|
||||
|
@ -458,18 +472,12 @@ error:
|
|||
return -1;
|
||||
}
|
||||
|
||||
int seat_close_client(struct client *client) {
|
||||
static int seat_close_client(struct client *client) {
|
||||
assert(client);
|
||||
assert(client->seat);
|
||||
|
||||
struct seat *seat = client->seat;
|
||||
|
||||
if (seat->active_client != client) {
|
||||
log_error("client not active");
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (!linked_list_empty(&client->devices)) {
|
||||
struct seat_device *device = (struct seat_device *)client->devices.next;
|
||||
if (seat_close_device(client, device) == -1) {
|
||||
|
@ -477,14 +485,29 @@ int seat_close_client(struct client *client) {
|
|||
}
|
||||
}
|
||||
|
||||
client->state = CLIENT_CLOSED;
|
||||
bool was_current = seat->active_client == client;
|
||||
if (was_current) {
|
||||
seat->active_client = NULL;
|
||||
seat_activate(seat);
|
||||
}
|
||||
|
||||
if (seat->vt_bound) {
|
||||
if (was_current && seat->active_client == NULL) {
|
||||
// This client was current, but there were no clients
|
||||
// waiting to take this VT, so clean it up.
|
||||
log_debug("closing active VT");
|
||||
vt_close(seat);
|
||||
} else if (!was_current && client->state != CLIENT_CLOSED) {
|
||||
// This client was not current, but as the client was
|
||||
// running, we need to clean up the VT.
|
||||
log_debug("closing inactive VT");
|
||||
vt_close_num(client->session);
|
||||
}
|
||||
}
|
||||
|
||||
client->state = CLIENT_CLOSED;
|
||||
log_debug("closed client");
|
||||
|
||||
seat_activate(seat);
|
||||
if (seat->vt_bound && seat->active_client == NULL) {
|
||||
vt_close(seat);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -543,10 +566,10 @@ int seat_ack_disable_client(struct client *client) {
|
|||
|
||||
seat->active_client = NULL;
|
||||
seat_activate(seat);
|
||||
if (seat->vt_bound && seat->active_client == NULL) {
|
||||
vt_close(seat);
|
||||
}
|
||||
|
||||
// If we're VT-bound, we've either de-activated a client on a foreign
|
||||
// VT, in which case we need to do nothing, or disabled the current VT,
|
||||
// in which case seat_activate would just immediately re-enable it.
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue