diff options
-rw-r--r-- | src/login/logind-seat-dbus.c | 56 | ||||
-rw-r--r-- | src/login/logind-seat.c | 96 | ||||
-rw-r--r-- | src/login/logind-seat.h | 8 | ||||
-rw-r--r-- | src/login/logind-session.c | 13 | ||||
-rw-r--r-- | src/login/logind-session.h | 1 |
5 files changed, 174 insertions, 0 deletions
diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c index 236af5eb9e..909007c30c 100644 --- a/src/login/logind-seat-dbus.c +++ b/src/login/logind-seat-dbus.c @@ -236,6 +236,59 @@ static int method_activate_session(sd_bus *bus, sd_bus_message *message, void *u return sd_bus_reply_method_return(message, NULL); } +static int method_switch_to(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Seat *s = userdata; + unsigned int to; + int r; + + assert(bus); + assert(message); + assert(s); + + r = sd_bus_message_read(message, "u", &to); + if (r < 0) + return r; + + if (to <= 0) + return -EINVAL; + + r = seat_switch_to(s, to); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_switch_to_next(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Seat *s = userdata; + int r; + + assert(bus); + assert(message); + assert(s); + + r = seat_switch_to_next(s); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_switch_to_previous(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Seat *s = userdata; + int r; + + assert(bus); + assert(message); + assert(s); + + r = seat_switch_to_previous(s); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + const sd_bus_vtable seat_vtable[] = { SD_BUS_VTABLE_START(0), @@ -251,6 +304,9 @@ const sd_bus_vtable seat_vtable[] = { SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)), SD_BUS_METHOD("ActivateSession", "s", NULL, method_activate_session, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SwitchTo", "u", NULL, method_switch_to, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SwitchToNext", NULL, NULL, method_switch_to_next, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SwitchToPrevious", NULL, NULL, method_switch_to_previous, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END }; diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c index c73860478d..b8f18c47a3 100644 --- a/src/login/logind-seat.c +++ b/src/login/logind-seat.c @@ -79,6 +79,7 @@ void seat_free(Seat *s) { hashmap_remove(s->manager->seats, s->id); + free(s->positions); free(s->state_file); free(s); } @@ -270,6 +271,60 @@ int seat_set_active(Seat *s, Session *session) { return 0; } +int seat_switch_to(Seat *s, unsigned int num) { + /* Public session positions skip 0 (there is only F1-F12). Maybe it + * will get reassigned in the future, so return error for now. */ + if (!num) + return -EINVAL; + + if (num >= s->position_count || !s->positions[num]) + return -EINVAL; + + return session_activate(s->positions[num]); +} + +int seat_switch_to_next(Seat *s) { + unsigned int start, i; + + if (!s->position_count) + return -EINVAL; + + start = 1; + if (s->active && s->active->pos > 0) + start = s->active->pos; + + for (i = start + 1; i < s->position_count; ++i) + if (s->positions[i]) + return session_activate(s->positions[i]); + + for (i = 1; i < start; ++i) + if (s->positions[i]) + return session_activate(s->positions[i]); + + return -EINVAL; +} + +int seat_switch_to_previous(Seat *s) { + unsigned int start, i; + + if (!s->position_count) + return -EINVAL; + + start = 1; + if (s->active && s->active->pos > 0) + start = s->active->pos; + + for (i = start - 1; i > 0; --i) + if (s->positions[i]) + return session_activate(s->positions[i]); + + for (i = s->position_count - 1; i > start; --i) + if (s->positions[i]) + return session_activate(s->positions[i]); + + return -EINVAL; +} + int seat_active_vt_changed(Seat *s, unsigned int vtnr) { Session *i, *new_active = NULL; int r; @@ -403,6 +458,46 @@ int seat_stop_sessions(Seat *s) { return r; } +void seat_evict_position(Seat *s, Session *session) { + unsigned int pos = session->pos; + + session->pos = 0; + + if (!pos) + return; + + if (pos < s->position_count && s->positions[pos] == session) + s->positions[pos] = NULL; +} + +void seat_claim_position(Seat *s, Session *session, unsigned int pos) { + /* with VTs, the position is always the same as the VTnr */ + if (seat_has_vts(s)) + pos = session->vtnr; + + if (!GREEDY_REALLOC0(s->positions, s->position_count, pos + 1)) + return; + + seat_evict_position(s, session); + + session->pos = pos; + if (pos > 0 && !s->positions[pos]) + s->positions[pos] = session; +} + +static void seat_assign_position(Seat *s, Session *session) { + unsigned int pos; + + if (session->pos > 0) + return; + + for (pos = 1; pos < s->position_count; ++pos) + if (!s->positions[pos]) + break; + + seat_claim_position(s, session, pos); +} + int seat_attach_session(Seat *s, Session *session) { assert(s); assert(session); @@ -413,6 +508,7 @@ int seat_attach_session(Seat *s, Session *session) { session->seat = s; LIST_PREPEND(sessions_by_seat, s->sessions, session); + seat_assign_position(s, session); seat_send_changed(s, "Sessions", NULL); diff --git a/src/login/logind-seat.h b/src/login/logind-seat.h index 1254268f10..9e21e3a8a3 100644 --- a/src/login/logind-seat.h +++ b/src/login/logind-seat.h @@ -41,6 +41,9 @@ struct Seat { Session *pending_switch; LIST_HEAD(Session, sessions); + Session **positions; + size_t position_count; + bool in_gc_queue:1; bool started:1; @@ -55,12 +58,17 @@ int seat_load(Seat *s); int seat_apply_acls(Seat *s, Session *old_active); int seat_set_active(Seat *s, Session *session); +int seat_switch_to(Seat *s, unsigned int num); +int seat_switch_to_next(Seat *s); +int seat_switch_to_previous(Seat *s); int seat_active_vt_changed(Seat *s, unsigned int vtnr); int seat_read_active_vt(Seat *s); int seat_preallocate_vts(Seat *s); int seat_attach_session(Seat *s, Session *session); void seat_complete_switch(Seat *s); +void seat_evict_position(Seat *s, Session *session); +void seat_claim_position(Seat *s, Session *session, unsigned int pos); bool seat_has_vts(Seat *s); bool seat_is_seat0(Seat *s); diff --git a/src/login/logind-session.c b/src/login/logind-session.c index 4476f5820a..ff0a7a4f2e 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -125,6 +125,7 @@ void session_free(Session *s) { if (s->seat->pending_switch == s) s->seat->pending_switch = NULL; + seat_evict_position(s->seat, s); LIST_REMOVE(sessions_by_seat, s->seat->sessions, s); } @@ -231,6 +232,9 @@ int session_save(Session *s) { if (s->seat && seat_has_vts(s->seat)) fprintf(f, "VTNR=%u\n", s->vtnr); + if (!s->vtnr) + fprintf(f, "POS=%u\n", s->pos); + if (s->leader > 0) fprintf(f, "LEADER=%lu\n", (unsigned long) s->leader); @@ -266,6 +270,7 @@ int session_load(Session *s) { _cleanup_free_ char *remote = NULL, *seat = NULL, *vtnr = NULL, + *pos = NULL, *leader = NULL, *type = NULL, *class = NULL, @@ -290,6 +295,7 @@ int session_load(Session *s) { "REMOTE_USER", &s->remote_user, "SERVICE", &s->service, "VTNR", &vtnr, + "POS", &pos, "LEADER", &leader, "TYPE", &type, "CLASS", &class, @@ -350,6 +356,13 @@ int session_load(Session *s) { if (!s->seat || !seat_has_vts(s->seat)) s->vtnr = 0; + if (pos && s->seat) { + unsigned int npos; + + safe_atou(pos, &npos); + seat_claim_position(s->seat, s, npos); + } + if (leader) { k = parse_pid(leader, &s->leader); if (k >= 0) diff --git a/src/login/logind-session.h b/src/login/logind-session.h index ee931013dd..d724e20e7f 100644 --- a/src/login/logind-session.h +++ b/src/login/logind-session.h @@ -69,6 +69,7 @@ struct Session { Manager *manager; char *id; + unsigned int pos; SessionType type; SessionClass class; |