aboutsummaryrefslogtreecommitdiff
path: root/seatd/seat.c
diff options
context:
space:
mode:
Diffstat (limited to 'seatd/seat.c')
-rw-r--r--seatd/seat.c67
1 files changed, 45 insertions, 22 deletions
diff --git a/seatd/seat.c b/seatd/seat.c
index 0893db7..3e134b1 100644
--- a/seatd/seat.c
+++ b/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);
- }
+ 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) {
}
}
+ 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;
- seat->active_client = NULL;
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;
}