4 * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files
8 * (the "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 * A seat is a single session that is self-hosting and provides all the
29 * interaction for a single logged-in user.
37 #include "kmscon_cdev.h"
38 #include "kmscon_conf.h"
39 #include "kmscon_dummy.h"
40 #include "kmscon_seat.h"
41 #include "kmscon_terminal.h"
42 #include "shl_dlist.h"
44 #include "uterm_input.h"
45 #include "uterm_video.h"
48 #define LOG_SUBSYSTEM "seat"
50 struct kmscon_session {
51 struct shl_dlist list;
53 struct kmscon_seat *seat;
59 struct ev_timer *timer;
61 kmscon_session_cb_t cb;
65 struct kmscon_display {
66 struct shl_dlist list;
67 struct kmscon_seat *seat;
68 struct uterm_display *disp;
72 enum kmscon_async_schedule {
79 struct ev_eloop *eloop;
80 struct uterm_vt_master *vtm;
81 struct conf_ctx *conf_ctx;
82 struct kmscon_conf_t *conf;
85 struct uterm_input *input;
87 struct shl_dlist displays;
90 struct shl_dlist sessions;
94 struct kmscon_session *current_sess;
95 struct kmscon_session *scheduled_sess;
96 struct kmscon_session *dummy_sess;
98 unsigned int async_schedule;
104 static int session_call(struct kmscon_session *sess, unsigned int event,
105 struct uterm_display *disp)
107 struct kmscon_session_event ev;
112 memset(&ev, 0, sizeof(ev));
115 return sess->cb(sess, &ev, sess->data);
118 static int session_call_activate(struct kmscon_session *sess)
120 log_debug("activate session %p", sess);
121 return session_call(sess, KMSCON_SESSION_ACTIVATE, NULL);
124 static int session_call_deactivate(struct kmscon_session *sess)
126 log_debug("deactivate session %p", sess);
127 return session_call(sess, KMSCON_SESSION_DEACTIVATE, NULL);
130 static void session_call_display_new(struct kmscon_session *sess,
131 struct uterm_display *disp)
133 session_call(sess, KMSCON_SESSION_DISPLAY_NEW, disp);
136 static void session_call_display_gone(struct kmscon_session *sess,
137 struct uterm_display *disp)
139 session_call(sess, KMSCON_SESSION_DISPLAY_GONE, disp);
142 static void session_call_display_refresh(struct kmscon_session *sess,
143 struct uterm_display *disp)
145 session_call(sess, KMSCON_SESSION_DISPLAY_REFRESH, disp);
148 static void activate_display(struct kmscon_display *d)
151 struct shl_dlist *iter, *tmp;
152 struct kmscon_session *s;
153 struct kmscon_seat *seat = d->seat;
155 if (d->activated || !d->seat->awake || !d->seat->foreground)
158 /* TODO: We always use the default mode for new displays but we should
159 * rather allow the user to specify different modes in the configuration
161 if (uterm_display_get_state(d->disp) == UTERM_DISPLAY_INACTIVE) {
162 ret = uterm_display_activate(d->disp, NULL);
168 ret = uterm_display_set_dpms(d->disp, UTERM_DPMS_ON);
170 log_warning("cannot set DPMS state to on for display: %d",
173 shl_dlist_for_each_safe(iter, tmp, &seat->sessions) {
174 s = shl_dlist_entry(iter, struct kmscon_session, list);
175 session_call_display_new(s, d->disp);
180 static int seat_go_foreground(struct kmscon_seat *seat, bool force)
183 struct shl_dlist *iter;
184 struct kmscon_display *d;
186 if (seat->foreground)
188 if (!seat->awake || (!force && seat->current_sess))
192 ret = seat->cb(seat, KMSCON_SEAT_FOREGROUND, seat->data);
194 log_warning("cannot put seat %s into foreground: %d",
200 seat->foreground = true;
202 shl_dlist_for_each(iter, &seat->displays) {
203 d = shl_dlist_entry(iter, struct kmscon_display, list);
210 static int seat_go_background(struct kmscon_seat *seat, bool force)
214 if (!seat->foreground)
216 if (!seat->awake || (!force && seat->current_sess))
220 ret = seat->cb(seat, KMSCON_SEAT_BACKGROUND, seat->data);
222 log_warning("cannot put seat %s into background: %d",
228 seat->foreground = false;
232 static int seat_go_asleep(struct kmscon_seat *seat, bool force)
238 if (seat->current_sess || seat->foreground) {
240 seat->foreground = false;
241 seat->current_sess = NULL;
249 ret = seat->cb(seat, KMSCON_SEAT_SLEEP, seat->data);
251 log_warning("cannot put seat %s asleep: %d",
259 uterm_input_sleep(seat->input);
264 static int seat_go_awake(struct kmscon_seat *seat)
272 ret = seat->cb(seat, KMSCON_SEAT_WAKE_UP, seat->data);
274 log_warning("cannot wake up seat %s: %d", seat->name,
281 uterm_input_wake_up(seat->input);
286 static int seat_run(struct kmscon_seat *seat)
289 struct kmscon_session *session;
293 if (seat->current_sess)
296 if (!seat->scheduled_sess) {
297 log_debug("no session scheduled to run (num %zu)",
298 seat->session_count);
301 session = seat->scheduled_sess;
303 if (session->foreground && !seat->foreground) {
304 ret = seat_go_foreground(seat, false);
306 log_warning("cannot put seat %s into foreground for session %p",
307 seat->name, session);
310 } else if (!session->foreground && seat->foreground) {
311 ret = seat_go_background(seat, false);
313 log_warning("cannot put seat %s into background for session %p",
314 seat->name, session);
319 ret = session_call_activate(session);
321 log_warning("cannot activate session %p: %d", session, ret);
325 seat->current_sess = session;
330 static void session_deactivate(struct kmscon_session *sess)
332 if (sess->seat->current_sess != sess)
335 sess->seat->async_schedule = SCHEDULE_SWITCH;
336 sess->deactivating = false;
337 sess->seat->current_sess = NULL;
340 static int seat_pause(struct kmscon_seat *seat, bool force)
344 if (!seat->current_sess)
347 seat->current_sess->deactivating = true;
348 ret = session_call_deactivate(seat->current_sess);
350 if (ret == -EINPROGRESS)
351 log_debug("pending deactivation for session %p",
354 log_warning("cannot deactivate session %p: %d",
355 seat->current_sess, ret);
360 session_deactivate(seat->current_sess);
365 static void seat_reschedule(struct kmscon_seat *seat)
367 struct shl_dlist *iter, *start;
368 struct kmscon_session *sess;
370 if (seat->scheduled_sess && seat->scheduled_sess->enabled)
373 if (seat->current_sess && seat->current_sess->enabled) {
374 seat->scheduled_sess = seat->current_sess;
378 if (seat->current_sess)
379 start = &seat->current_sess->list;
381 start = &seat->sessions;
383 shl_dlist_for_each_but_one(iter, start, &seat->sessions) {
384 sess = shl_dlist_entry(iter, struct kmscon_session, list);
385 if (sess == seat->dummy_sess || !sess->enabled)
387 seat->scheduled_sess = sess;
391 if (seat->dummy_sess && seat->dummy_sess->enabled)
392 seat->scheduled_sess = seat->dummy_sess;
394 seat->scheduled_sess = NULL;
397 static bool seat_has_schedule(struct kmscon_seat *seat)
399 return seat->scheduled_sess &&
400 seat->scheduled_sess != seat->current_sess;
403 static int seat_switch(struct kmscon_seat *seat)
407 seat->async_schedule = SCHEDULE_SWITCH;
408 ret = seat_pause(seat, false);
412 return seat_run(seat);
415 static void seat_next(struct kmscon_seat *seat)
417 struct shl_dlist *cur, *iter;
418 struct kmscon_session *s, *next;
420 if (seat->current_sess)
421 cur = &seat->current_sess->list;
422 else if (seat->session_count)
423 cur = &seat->sessions;
428 if (!seat->current_sess && seat->dummy_sess &&
429 seat->dummy_sess->enabled)
430 next = seat->dummy_sess;
432 shl_dlist_for_each_but_one(iter, cur, &seat->sessions) {
433 s = shl_dlist_entry(iter, struct kmscon_session, list);
434 if (!s->enabled || seat->dummy_sess == s)
444 seat->scheduled_sess = next;
448 static void seat_prev(struct kmscon_seat *seat)
450 struct shl_dlist *cur, *iter;
451 struct kmscon_session *s, *prev;
453 if (seat->current_sess)
454 cur = &seat->current_sess->list;
455 else if (seat->session_count)
456 cur = &seat->sessions;
461 if (!seat->current_sess && seat->dummy_sess &&
462 seat->dummy_sess->enabled)
463 prev = seat->dummy_sess;
465 shl_dlist_for_each_reverse_but_one(iter, cur, &seat->sessions) {
466 s = shl_dlist_entry(iter, struct kmscon_session, list);
467 if (!s->enabled || seat->dummy_sess == s)
477 seat->scheduled_sess = prev;
481 static int seat_add_display(struct kmscon_seat *seat,
482 struct uterm_display *disp)
484 struct kmscon_display *d;
486 log_debug("add display %p to seat %s", disp, seat->name);
488 d = malloc(sizeof(*d));
491 memset(d, 0, sizeof(*d));
495 uterm_display_ref(d->disp);
496 shl_dlist_link(&seat->displays, &d->list);
501 static void seat_remove_display(struct kmscon_seat *seat,
502 struct kmscon_display *d)
504 struct shl_dlist *iter, *tmp;
505 struct kmscon_session *s;
507 log_debug("remove display %p from seat %s", d->disp, seat->name);
509 shl_dlist_unlink(&d->list);
512 shl_dlist_for_each_safe(iter, tmp, &seat->sessions) {
513 s = shl_dlist_entry(iter, struct kmscon_session, list);
514 session_call_display_gone(s, d->disp);
518 uterm_display_unref(d->disp);
522 static void seat_refresh_display(struct kmscon_seat *seat,
523 struct kmscon_display *d)
525 struct shl_dlist *iter;
526 struct kmscon_session *s;
528 log_debug("refresh display %p from seat %s", d->disp, seat->name);
531 shl_dlist_for_each(iter, &seat->sessions) {
532 s = shl_dlist_entry(iter, struct kmscon_session, list);
533 session_call_display_refresh(s, d->disp);
538 static int seat_vt_event(struct uterm_vt *vt, struct uterm_vt_event *ev,
541 struct kmscon_seat *seat = data;
544 switch (ev->action) {
545 case UTERM_VT_ACTIVATE:
546 ret = seat_go_awake(seat);
551 case UTERM_VT_DEACTIVATE:
552 seat->async_schedule = SCHEDULE_VT;
553 ret = seat_pause(seat, false);
556 ret = seat_go_background(seat, false);
559 ret = seat_go_asleep(seat, false);
565 seat->cb(seat, KMSCON_SEAT_HUP, seat->data);
572 static void seat_input_event(struct uterm_input *input,
573 struct uterm_input_event *ev,
576 struct kmscon_seat *seat = data;
577 struct kmscon_session *s;
580 if (ev->handled || !seat->awake)
583 if (conf_grab_matches(seat->conf->grab_session_next,
584 ev->mods, ev->num_syms, ev->keysyms)) {
586 if (!seat->conf->session_control)
591 if (conf_grab_matches(seat->conf->grab_session_prev,
592 ev->mods, ev->num_syms, ev->keysyms)) {
594 if (!seat->conf->session_control)
599 if (conf_grab_matches(seat->conf->grab_session_dummy,
600 ev->mods, ev->num_syms, ev->keysyms)) {
602 if (!seat->conf->session_control)
604 seat->scheduled_sess = seat->dummy_sess;
608 if (conf_grab_matches(seat->conf->grab_session_close,
609 ev->mods, ev->num_syms, ev->keysyms)) {
611 if (!seat->conf->session_control)
613 s = seat->current_sess;
616 if (s == seat->dummy_sess)
619 /* First time this is invoked on a session, we simply try
620 * unloading it. If it fails, we give it some time. If this is
621 * invoked a second time, we notice that we already tried
622 * removing it and so we go straight to unregistering the
623 * session unconditionally. */
624 if (!s->deactivating) {
625 seat->async_schedule = SCHEDULE_UNREGISTER;
626 ret = seat_pause(seat, false);
631 kmscon_session_unregister(s);
634 if (conf_grab_matches(seat->conf->grab_terminal_new,
635 ev->mods, ev->num_syms, ev->keysyms)) {
637 if (!seat->conf->session_control)
639 ret = kmscon_terminal_register(&s, seat,
640 uterm_vt_get_num(seat->vt));
641 if (ret == -EOPNOTSUPP) {
642 log_notice("terminal support not compiled in");
644 log_error("cannot register terminal session: %d", ret);
647 seat->scheduled_sess = s;
654 int kmscon_seat_new(struct kmscon_seat **out,
655 struct conf_ctx *main_conf,
656 struct ev_eloop *eloop,
657 struct uterm_vt_master *vtm,
658 unsigned int vt_types,
659 const char *seatname,
663 struct kmscon_seat *seat;
667 if (!out || !eloop || !vtm || !seatname)
670 seat = malloc(sizeof(*seat));
673 memset(seat, 0, sizeof(*seat));
678 shl_dlist_init(&seat->displays);
679 shl_dlist_init(&seat->sessions);
681 seat->name = strdup(seatname);
683 log_error("cannot copy string");
688 ret = kmscon_conf_new(&seat->conf_ctx);
690 log_error("cannot create seat configuration object: %d", ret);
693 seat->conf = conf_ctx_get_mem(seat->conf_ctx);
695 ret = kmscon_conf_load_seat(seat->conf_ctx, main_conf, seat->name);
697 log_error("cannot parse seat configuration on seat %s: %d",
702 /* TODO: The XKB-API currently requires zero-terminated strings as
703 * keymap input. Hence, we have to read it in instead of using mmap().
704 * We should fix this upstream! */
706 if (seat->conf->xkb_keymap && *seat->conf->xkb_keymap) {
707 ret = shl_read_file(seat->conf->xkb_keymap, &keymap, NULL);
709 log_error("cannot read keymap file %s: %d",
710 seat->conf->xkb_keymap, ret);
713 ret = uterm_input_new(&seat->input, seat->eloop,
714 seat->conf->xkb_model,
715 seat->conf->xkb_layout,
716 seat->conf->xkb_variant,
717 seat->conf->xkb_options,
719 seat->conf->xkb_repeat_delay,
720 seat->conf->xkb_repeat_rate);
726 ret = uterm_input_register_cb(seat->input, seat_input_event, seat);
730 ret = uterm_vt_allocate(seat->vtm, &seat->vt,
731 vt_types, seat->name,
732 seat->input, seat->conf->vt, seat_vt_event,
737 ev_eloop_ref(seat->eloop);
738 uterm_vt_master_ref(seat->vtm);
743 uterm_input_unregister_cb(seat->input, seat_input_event, seat);
745 uterm_input_unref(seat->input);
747 kmscon_conf_free(seat->conf_ctx);
755 void kmscon_seat_free(struct kmscon_seat *seat)
757 struct kmscon_display *d;
758 struct kmscon_session *s;
764 ret = seat_pause(seat, true);
766 log_warning("destroying seat %s while session %p is active",
767 seat->name, seat->current_sess);
769 ret = seat_go_asleep(seat, true);
771 log_warning("destroying seat %s while still awake: %d",
774 while (!shl_dlist_empty(&seat->sessions)) {
775 s = shl_dlist_entry(seat->sessions.next,
776 struct kmscon_session,
778 kmscon_session_unregister(s);
781 while (!shl_dlist_empty(&seat->displays)) {
782 d = shl_dlist_entry(seat->displays.next,
783 struct kmscon_display,
785 seat_remove_display(seat, d);
788 uterm_vt_deallocate(seat->vt);
789 uterm_input_unregister_cb(seat->input, seat_input_event, seat);
790 uterm_input_unref(seat->input);
791 kmscon_conf_free(seat->conf_ctx);
793 uterm_vt_master_unref(seat->vtm);
794 ev_eloop_unref(seat->eloop);
798 void kmscon_seat_startup(struct kmscon_seat *seat)
801 struct kmscon_session *s;
806 ret = kmscon_dummy_register(&s, seat);
807 if (ret == -EOPNOTSUPP) {
808 log_notice("dummy sessions not compiled in");
810 log_error("cannot register dummy session: %d", ret);
812 seat->dummy_sess = s;
813 kmscon_session_enable(s);
816 if (seat->conf->terminal_session) {
817 ret = kmscon_terminal_register(&s, seat,
818 uterm_vt_get_num(seat->vt));
819 if (ret == -EOPNOTSUPP)
820 log_notice("terminal support not compiled in");
822 log_error("cannot register terminal session");
824 kmscon_session_enable(s);
827 if (seat->conf->cdev_session) {
828 ret = kmscon_cdev_register(&s, seat);
829 if (ret == -EOPNOTSUPP)
830 log_notice("cdev sessions not compiled in");
832 log_error("cannot register cdev session");
835 if (seat->conf->switchvt ||
836 uterm_vt_get_type(seat->vt) == UTERM_VT_FAKE)
837 uterm_vt_activate(seat->vt);
840 int kmscon_seat_add_display(struct kmscon_seat *seat,
841 struct uterm_display *disp)
846 return seat_add_display(seat, disp);
849 void kmscon_seat_remove_display(struct kmscon_seat *seat,
850 struct uterm_display *disp)
852 struct shl_dlist *iter;
853 struct kmscon_display *d;
858 shl_dlist_for_each(iter, &seat->displays) {
859 d = shl_dlist_entry(iter, struct kmscon_display, list);
863 seat_remove_display(seat, d);
868 void kmscon_seat_refresh_display(struct kmscon_seat *seat,
869 struct uterm_display *disp)
871 struct shl_dlist *iter;
872 struct kmscon_display *d;
877 shl_dlist_for_each(iter, &seat->displays) {
878 d = shl_dlist_entry(iter, struct kmscon_display, list);
882 seat_refresh_display(seat, d);
887 int kmscon_seat_add_input(struct kmscon_seat *seat, const char *node)
892 uterm_input_add_dev(seat->input, node);
896 void kmscon_seat_remove_input(struct kmscon_seat *seat, const char *node)
901 uterm_input_remove_dev(seat->input, node);
904 const char *kmscon_seat_get_name(struct kmscon_seat *seat)
912 struct uterm_input *kmscon_seat_get_input(struct kmscon_seat *seat)
920 struct ev_eloop *kmscon_seat_get_eloop(struct kmscon_seat *seat)
928 struct conf_ctx *kmscon_seat_get_conf(struct kmscon_seat *seat)
933 return seat->conf_ctx;
936 void kmscon_seat_schedule(struct kmscon_seat *seat, unsigned int id)
938 struct shl_dlist *iter;
939 struct kmscon_session *s, *next;
944 next = seat->dummy_sess;
945 shl_dlist_for_each(iter, &seat->sessions) {
946 s = shl_dlist_entry(iter, struct kmscon_session, list);
947 if (!s->enabled || seat->dummy_sess == s ||
948 seat->current_sess == s)
956 seat->scheduled_sess = next;
957 if (seat_has_schedule(seat))
961 int kmscon_seat_register_session(struct kmscon_seat *seat,
962 struct kmscon_session **out,
963 kmscon_session_cb_t cb,
966 struct kmscon_session *sess;
967 struct shl_dlist *iter;
968 struct kmscon_display *d;
973 if (seat->conf->session_max &&
974 seat->session_count >= seat->conf->session_max) {
975 log_warning("maximum number of sessions reached (%d), dropping new session",
976 seat->conf->session_max);
980 sess = malloc(sizeof(*sess));
982 log_error("cannot allocate memory for new session on seat %s",
987 log_debug("register session %p", sess);
989 memset(sess, 0, sizeof(*sess));
994 sess->foreground = true;
996 /* register new sessions next to the current one */
997 if (seat->current_sess)
998 shl_dlist_link(&seat->current_sess->list, &sess->list);
1000 shl_dlist_link_tail(&seat->sessions, &sess->list);
1002 ++seat->session_count;
1005 shl_dlist_for_each(iter, &seat->displays) {
1006 d = shl_dlist_entry(iter, struct kmscon_display, list);
1007 session_call_display_new(sess, d->disp);
1013 void kmscon_session_ref(struct kmscon_session *sess)
1015 if (!sess || !sess->ref)
1021 void kmscon_session_unref(struct kmscon_session *sess)
1023 if (!sess || !sess->ref || --sess->ref)
1026 kmscon_session_unregister(sess);
1030 void kmscon_session_unregister(struct kmscon_session *sess)
1032 struct kmscon_seat *seat;
1034 bool forced = false;
1036 if (!sess || !sess->seat)
1039 log_debug("unregister session %p", sess);
1042 sess->enabled = false;
1043 if (seat->dummy_sess == sess)
1044 seat->dummy_sess = NULL;
1045 seat_reschedule(seat);
1047 if (seat->current_sess == sess) {
1048 ret = seat_pause(seat, true);
1051 log_warning("unregistering active session %p; skipping automatic session-switch",
1056 shl_dlist_unlink(&sess->list);
1057 --seat->session_count;
1060 session_call(sess, KMSCON_SESSION_UNREGISTER, NULL);
1061 kmscon_session_unref(sess);
1063 /* If this session was active and we couldn't deactivate it, then it
1064 * might still have resources allocated that couldn't get freed. In this
1065 * case we should not automatically switch to the next session as it is
1066 * very likely that it will not be able to start.
1067 * Instead, we stay inactive and wait for user/external input to switch
1068 * to another session. This delay will then hopefully be long enough so
1069 * all resources got freed. */
1074 bool kmscon_session_is_registered(struct kmscon_session *sess)
1076 return sess && sess->seat;
1079 bool kmscon_session_is_active(struct kmscon_session *sess)
1081 return sess && sess->seat && sess->seat->current_sess == sess;
1084 int kmscon_session_set_foreground(struct kmscon_session *sess)
1086 struct kmscon_seat *seat;
1091 if (sess->foreground)
1095 if (seat && seat->current_sess == sess && !seat->foreground) {
1096 ret = seat_go_foreground(seat, true);
1101 sess->foreground = true;
1105 int kmscon_session_set_background(struct kmscon_session *sess)
1107 struct kmscon_seat *seat;
1112 if (!sess->foreground)
1116 if (seat && seat->current_sess == sess && seat->foreground) {
1117 ret = seat_go_background(seat, true);
1122 sess->foreground = false;
1126 void kmscon_session_schedule(struct kmscon_session *sess)
1128 struct kmscon_seat *seat;
1130 if (!sess || !sess->seat)
1134 seat->scheduled_sess = sess;
1135 seat_reschedule(seat);
1136 if (seat_has_schedule(seat))
1140 void kmscon_session_enable(struct kmscon_session *sess)
1142 if (!sess || sess->enabled)
1145 log_debug("enable session %p", sess);
1146 sess->enabled = true;
1148 (!sess->seat->current_sess ||
1149 sess->seat->current_sess == sess->seat->dummy_sess)) {
1150 sess->seat->scheduled_sess = sess;
1151 if (seat_has_schedule(sess->seat))
1152 seat_switch(sess->seat);
1156 void kmscon_session_disable(struct kmscon_session *sess)
1158 if (!sess || !sess->enabled)
1161 log_debug("disable session %p", sess);
1162 sess->enabled = false;
1165 bool kmscon_session_is_enabled(struct kmscon_session *sess)
1167 return sess && sess->enabled;
1170 void kmscon_session_notify_deactivated(struct kmscon_session *sess)
1172 struct kmscon_seat *seat;
1176 if (!sess || !sess->seat)
1180 if (seat->current_sess != sess)
1183 sched = seat->async_schedule;
1184 log_debug("session %p notified core about deactivation (schedule: %u)",
1186 session_deactivate(sess);
1187 seat_reschedule(seat);
1189 if (sched == SCHEDULE_VT) {
1190 ret = seat_go_background(seat, false);
1193 ret = seat_go_asleep(seat, false);
1196 uterm_vt_retry(seat->vt);
1197 } else if (sched == SCHEDULE_UNREGISTER) {
1198 kmscon_session_unregister(sess);