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_add_client(struct seat *seat, struct client *client);
|
||||||
int seat_remove_client(struct client *client);
|
int seat_remove_client(struct client *client);
|
||||||
int seat_open_client(struct seat *seat, 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);
|
int seat_ack_disable_client(struct client *client);
|
||||||
|
|
||||||
struct seat_device *seat_open_device(struct client *client, const char *path);
|
struct seat_device *seat_open_device(struct client *client, const char *path);
|
||||||
|
|
67
seatd/seat.c
67
seatd/seat.c
|
@ -18,6 +18,8 @@
|
||||||
#include "seat.h"
|
#include "seat.h"
|
||||||
#include "terminal.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_create(const char *seat_name, bool vt_bound) {
|
||||||
struct seat *seat = calloc(1, sizeof(struct seat));
|
struct seat *seat = calloc(1, sizeof(struct seat));
|
||||||
if (seat == NULL) {
|
if (seat == NULL) {
|
||||||
|
@ -77,19 +79,33 @@ static int vt_open(struct seat *seat, int vt) {
|
||||||
return 0;
|
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) {
|
static void vt_close(struct seat *seat) {
|
||||||
if (seat->cur_ttyfd == -1) {
|
if (seat->cur_ttyfd == -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
terminal_set_process_switching(seat->cur_ttyfd, true);
|
vt_close_fd(seat->cur_ttyfd);
|
||||||
terminal_set_keyboard(seat->cur_ttyfd, true);
|
|
||||||
terminal_set_graphics(seat->cur_ttyfd, false);
|
|
||||||
|
|
||||||
close(seat->cur_ttyfd);
|
close(seat->cur_ttyfd);
|
||||||
seat->cur_ttyfd = -1;
|
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) {
|
static int vt_switch(struct seat *seat, int vt) {
|
||||||
int ttyfd = terminal_open(seat->cur_vt);
|
int ttyfd = terminal_open(seat->cur_vt);
|
||||||
if (ttyfd == -1) {
|
if (ttyfd == -1) {
|
||||||
|
@ -168,9 +184,7 @@ int seat_remove_client(struct client *client) {
|
||||||
seat_close_device(client, device);
|
seat_close_device(client, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (seat->active_client == client) {
|
seat_close_client(client);
|
||||||
seat_close_client(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
client->seat = NULL;
|
client->seat = NULL;
|
||||||
log_debug("removed client");
|
log_debug("removed client");
|
||||||
|
@ -458,18 +472,12 @@ error:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int seat_close_client(struct client *client) {
|
static int seat_close_client(struct client *client) {
|
||||||
assert(client);
|
assert(client);
|
||||||
assert(client->seat);
|
assert(client->seat);
|
||||||
|
|
||||||
struct seat *seat = 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)) {
|
while (!linked_list_empty(&client->devices)) {
|
||||||
struct seat_device *device = (struct seat_device *)client->devices.next;
|
struct seat_device *device = (struct seat_device *)client->devices.next;
|
||||||
if (seat_close_device(client, device) == -1) {
|
if (seat_close_device(client, device) == -1) {
|
||||||
|
@ -477,14 +485,29 @@ int seat_close_client(struct client *client) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
client->state = CLIENT_CLOSED;
|
||||||
seat->active_client = NULL;
|
|
||||||
log_debug("closed client");
|
log_debug("closed client");
|
||||||
|
|
||||||
seat_activate(seat);
|
|
||||||
if (seat->vt_bound && seat->active_client == NULL) {
|
|
||||||
vt_close(seat);
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -543,10 +566,10 @@ int seat_ack_disable_client(struct client *client) {
|
||||||
|
|
||||||
seat->active_client = NULL;
|
seat->active_client = NULL;
|
||||||
seat_activate(seat);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue