Introduce session management
authorDavid Herrmann <dh.herrmann@googlemail.com>
Thu, 11 Oct 2012 08:54:01 +0000 (10:54 +0200)
committerDavid Herrmann <dh.herrmann@googlemail.com>
Thu, 11 Oct 2012 08:54:01 +0000 (10:54 +0200)
On seats other than seat0 we do not have any session-management, because
VTs are not available. Furthermore, if we want to get rid of CONFIG_VT
entirely, we also need to provide session-management for seat0.

This commit introduces sessions. Every seat (seats are now managed in
kmscon_seat.c) can have registered sessions. One of the sessions is active
and gets control over all displays. Session switching is entirely handled
inside of kmscon so there is always an active session (except if no
session is registered at all).

This also reworks the seat-management. kmscon_main.c now only manages the
seat allocation/deallocation and video-objects. The seat itself is handled
inside of kmscon_seat.c and does not know of uterm_video objects. Instead,
it is assigned a list of displays that it can use. Everything is still
hotplugging capable so user-experience should be the same as before.

The kmscon_terminal layer is reworked to be session based. So every
terminal is now a single session. By default, a single terminal-session is
created for each seat. This may be changed, though.

There is currently no input-control to change between session with
keyboard hotkeys. However, this will be added when we have more than one
session.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
Makefile.am
src/kmscon_main.c
src/kmscon_seat.c [new file with mode: 0644]
src/kmscon_seat.h [new file with mode: 0644]
src/kmscon_terminal.c
src/kmscon_terminal.h

index 7f44cbc..3860ec0 100644 (file)
@@ -418,8 +418,8 @@ kmscon_SOURCES = \
        $(SHL_MISC) \
        src/kmscon_terminal.h \
        src/kmscon_terminal.c \
-       src/kmscon_ui.h \
-       src/kmscon_ui.c \
+       src/kmscon_seat.h \
+       src/kmscon_seat.c \
        src/kmscon_conf.h \
        src/kmscon_conf.c \
        src/kmscon_main.c
index 6ec9cfb..86095a6 100644 (file)
 #include "conf.h"
 #include "eloop.h"
 #include "kmscon_conf.h"
-#include "kmscon_ui.h"
+#include "kmscon_seat.h"
 #include "log.h"
 #include "shl_dlist.h"
 #include "shl_misc.h"
 #include "text.h"
 #include "uterm.h"
 
-struct kmscon_app {
-       struct ev_eloop *eloop;
-       struct ev_eloop *vt_eloop;
-       unsigned int vt_exit_count;
+struct app_video {
+       struct shl_dlist list;
+       struct app_seat *seat;
 
-       struct uterm_vt_master *vtm;
-       struct uterm_monitor *mon;
-       struct shl_dlist seats;
+       char *node;
+       struct uterm_video *video;
 };
 
-struct kmscon_seat {
+struct app_seat {
        struct shl_dlist list;
        struct kmscon_app *app;
 
-       struct uterm_monitor_seat *useat;
-       char *sname;
-
        bool awake;
-       struct uterm_vt *vt;
-       struct uterm_input *input;
-       struct kmscon_ui *ui;
+       char *name;
+       struct kmscon_seat *seat;
        struct shl_dlist videos;
 };
 
-struct kmscon_video {
-       struct shl_dlist list;
-       struct uterm_monitor_dev *vdev;
-       struct uterm_video *video;
-};
-
-static void sig_generic(struct ev_eloop *eloop, struct signalfd_siginfo *info,
-                       void *data)
-{
-       struct kmscon_app *app = data;
+struct kmscon_app {
+       struct ev_eloop *eloop;
+       struct ev_eloop *vt_eloop;
+       unsigned int vt_exit_count;
 
-       ev_eloop_exit(app->eloop);
-       log_info("terminating due to caught signal %d", info->ssi_signo);
-}
+       struct uterm_vt_master *vtm;
+       struct uterm_monitor *mon;
+       struct shl_dlist seats;
+};
 
-static int vt_event(struct uterm_vt *vt, unsigned int action, void *data)
+static void app_seat_event(struct kmscon_seat *s, unsigned int event,
+                          void *data)
 {
-       struct kmscon_seat *seat = data;
-       struct shl_dlist *iter;
-       struct kmscon_video *vid;
+       struct app_seat *seat = data;
        struct kmscon_app *app = seat->app;
+       struct shl_dlist *iter;
+       struct app_video *vid;
 
-       if (action == UTERM_VT_ACTIVATE) {
+       switch (event) {
+       case KMSCON_SEAT_WAKE_UP:
                seat->awake = true;
-               uterm_input_wake_up(seat->input);
 
                shl_dlist_for_each(iter, &seat->videos) {
-                       vid = shl_dlist_entry(iter, struct kmscon_video, list);
+                       vid = shl_dlist_entry(iter, struct app_video, list);
                        uterm_video_wake_up(vid->video);
                }
-               kmscon_ui_wake_up(seat->ui);
-       } else if (action == UTERM_VT_DEACTIVATE) {
-               kmscon_ui_sleep(seat->ui);
+               break;
+       case KMSCON_SEAT_SLEEP:
                shl_dlist_for_each(iter, &seat->videos) {
-                       vid = shl_dlist_entry(iter, struct kmscon_video, list);
+                       vid = shl_dlist_entry(iter, struct app_video, list);
                        uterm_video_sleep(vid->video);
                }
 
-               uterm_input_sleep(seat->input);
-               seat->awake = false;
-
                if (app->vt_exit_count > 0) {
                        log_debug("deactivating VT on exit, %d to go",
                                  app->vt_exit_count - 1);
                        if (!--app->vt_exit_count)
                                ev_eloop_exit(app->vt_eloop);
                }
-       }
 
-       return 0;
+               seat->awake = false;
+               break;
+       }
 }
 
-static void seat_new(struct kmscon_app *app,
-                    struct uterm_monitor_seat *useat,
-                    const char *sname)
+static int app_seat_new(struct kmscon_app *app, struct app_seat **out,
+                       const char *sname)
 {
-       struct kmscon_seat *seat;
+       struct app_seat *seat;
        int ret;
        unsigned int i;
        bool found;
@@ -139,101 +125,116 @@ static void seat_new(struct kmscon_app *app,
        }
 
        if (!found) {
-               log_info("ignoring seat %s as not specified in seat-list",
+               log_info("ignoring new seat %s as not specified in seat-list",
                         sname);
-               return;
+               return -ERANGE;
        }
 
+       log_debug("new seat %s", sname);
+
        seat = malloc(sizeof(*seat));
-       if (!seat)
-               return;
+       if (!seat) {
+               log_error("cannot allocate memory for seat %s", sname);
+               return -ENOMEM;
+       }
        memset(seat, 0, sizeof(*seat));
        seat->app = app;
-       seat->useat = useat;
        shl_dlist_init(&seat->videos);
 
-       seat->sname = strdup(sname);
-       if (!seat->sname) {
-               log_err("cannot allocate memory for seat name");
+       seat->name = strdup(sname);
+       if (!seat->name) {
+               log_error("cannot copy seat name on seat %s", sname);
+               ret = -ENOMEM;
                goto err_free;
        }
 
-       ret = uterm_input_new(&seat->input, app->eloop,
-                             kmscon_conf.xkb_layout,
-                             kmscon_conf.xkb_variant,
-                             kmscon_conf.xkb_options,
-                             kmscon_conf.xkb_repeat_delay,
-                             kmscon_conf.xkb_repeat_rate);
-       if (ret)
+       ret = kmscon_seat_new(&seat->seat, app->eloop, app->vtm, sname,
+                             app_seat_event, seat);
+       if (ret) {
+               log_error("cannot create seat object on seat %s: %d",
+                         sname, ret);
                goto err_name;
+       }
 
-       ret = uterm_vt_allocate(app->vtm, &seat->vt, seat->sname,
-                               seat->input, kmscon_conf.vt, vt_event, seat);
-       if (ret)
-               goto err_input;
-
-       ret = kmscon_ui_new(&seat->ui, app->eloop, seat->input, seat->sname);
-       if (ret)
-               goto err_vt;
-
-       uterm_monitor_set_seat_data(seat->useat, seat);
        shl_dlist_link(&app->seats, &seat->list);
+       *out = seat;
+       return 0;
 
-       log_info("new seat %s", seat->sname);
-       return;
-
-err_vt:
-       uterm_vt_deallocate(seat->vt);
-err_input:
-       uterm_input_unref(seat->input);
 err_name:
-       free(seat->sname);
+       free(seat->name);
 err_free:
        free(seat);
+       return ret;
 }
 
-static void seat_free(struct kmscon_seat *seat)
+static void app_seat_free(struct app_seat *seat)
 {
-       log_info("free seat %s", seat->sname);
+       log_debug("free seat %s", seat->name);
 
        shl_dlist_unlink(&seat->list);
-       uterm_monitor_set_seat_data(seat->useat, NULL);
-       kmscon_ui_free(seat->ui);
-       uterm_input_unref(seat->input);
-       uterm_vt_deallocate(seat->vt);
-       free(seat->sname);
+       kmscon_seat_free(seat->seat);
+       free(seat->name);
        free(seat);
 }
 
-static void seat_add_video(struct kmscon_seat *seat,
-                          struct uterm_monitor_dev *dev,
-                          unsigned int type,
-                          const char *node)
+static void app_seat_video_event(struct uterm_video *video,
+                                struct uterm_video_hotplug *ev,
+                                void *data)
+{
+       struct app_video *vid = data;
+
+       switch (ev->action) {
+       case UTERM_NEW:
+               kmscon_seat_add_display(vid->seat->seat, ev->display);
+               break;
+       case UTERM_GONE:
+               kmscon_seat_remove_display(vid->seat->seat, ev->display);
+               break;
+       }
+}
+
+static int app_seat_add_video(struct app_seat *seat,
+                             struct app_video **out,
+                             unsigned int type,
+                             const char *node)
 {
        int ret;
        unsigned int mode;
-       struct kmscon_video *vid;
+       struct app_video *vid;
 
        if (kmscon_conf.use_fbdev) {
                if (type != UTERM_MONITOR_FBDEV &&
                    type != UTERM_MONITOR_FBDEV_DRM) {
-                       log_debug("ignoring %s as it is not fbdev device",
-                                 node);
-                       return;
+                       log_info("ignoring video device %s on seat %s as it is not an fbdev device",
+                                 node, seat->name);
+                       return -ERANGE;
                }
        } else {
                if (type == UTERM_MONITOR_FBDEV_DRM) {
-                       log_debug("ignoring %s as it is a DRM-fbdev device",
-                                 node);
-                       return;
+                       log_info("ignoring video device %s on seat %s as it is a DRM-fbdev device",
+                                 node, seat->name);
+                       return -ERANGE;
                }
        }
 
+       log_debug("new video device %s on seat %s", node, seat->name);
+
        vid = malloc(sizeof(*vid));
-       if (!vid)
-               return;
+       if (!vid) {
+               log_error("cannot allocate memory for video device %s on seat %s",
+                         node, seat->name);
+               return -ENOMEM;
+       }
        memset(vid, 0, sizeof(*vid));
-       vid->vdev = dev;
+       vid->seat = seat;
+
+       vid->node = strdup(node);
+       if (!vid->node) {
+               log_error("cannot copy video device name %s on seat %s",
+                         node, seat->name);
+               ret = -ENOMEM;
+               goto err_free;
+       }
 
        if (type == UTERM_MONITOR_DRM) {
                if (kmscon_conf.dumb)
@@ -247,122 +248,153 @@ static void seat_add_video(struct kmscon_seat *seat,
        ret = uterm_video_new(&vid->video, seat->app->eloop, mode, node);
        if (ret) {
                if (mode == UTERM_VIDEO_DRM) {
-                       log_info("cannot create drm device; trying dumb drm mode");
+                       log_info("cannot create drm device %s on seat %s (%d); trying dumb drm mode",
+                                vid->node, seat->name, ret);
                        ret = uterm_video_new(&vid->video, seat->app->eloop,
                                              UTERM_VIDEO_DUMB, node);
                        if (ret)
-                               goto err_free;
+                               goto err_node;
                } else {
-                       goto err_free;
+                       goto err_node;
                }
        }
 
-       kmscon_ui_add_video(seat->ui, vid->video);
+       ret = uterm_video_register_cb(vid->video, app_seat_video_event, vid);
+       if (ret) {
+               log_error("cannot register video callback for device %s on seat %s: %d",
+                         vid->node, seat->name, ret);
+               goto err_video;
+       }
+
        if (seat->awake)
                uterm_video_wake_up(vid->video);
-       shl_dlist_link(&seat->videos, &vid->list);
 
-       log_debug("new graphics device on seat %s", seat->sname);
-       return;
+       shl_dlist_link(&seat->videos, &vid->list);
+       *out = vid;
+       return 0;
 
+err_video:
+       uterm_video_unref(vid->video);
+err_node:
+       free(vid->node);
 err_free:
        free(vid);
-       log_warning("cannot add video object %s on %s", node, seat->sname);
-       return;
-}
-
-static void seat_rm_video(struct kmscon_seat *seat,
-                         struct uterm_monitor_dev *dev)
-{
-       struct shl_dlist *iter;
-       struct kmscon_video *vid;
-
-       shl_dlist_for_each(iter, &seat->videos) {
-               vid = shl_dlist_entry(iter, struct kmscon_video, list);
-               if (vid->vdev != dev)
-                       continue;
-
-               log_debug("free graphics device on seat %s", seat->sname);
-
-               kmscon_ui_remove_video(seat->ui, vid->video);
-               uterm_video_unref(vid->video);
-               shl_dlist_unlink(&vid->list);
-               free(vid);
-
-               break;
-       }
+       return ret;
 }
 
-static void seat_hotplug_video(struct kmscon_seat *seat,
-                              struct uterm_monitor_dev *dev)
+static void app_seat_remove_video(struct app_seat *seat, struct app_video *vid)
 {
-       struct shl_dlist *iter;
-       struct kmscon_video *vid;
+       log_debug("free video device %s on seat %s", vid->node, seat->name);
 
-       shl_dlist_for_each(iter, &seat->videos) {
-               vid = shl_dlist_entry(iter, struct kmscon_video, list);
-               if (vid->vdev != dev)
-                       continue;
-
-               uterm_video_poll(vid->video);
-               break;
-       }
+       shl_dlist_unlink(&vid->list);
+       uterm_video_unregister_cb(vid->video, app_seat_video_event, vid);
+       uterm_video_unref(vid->video);
+       free(vid->node);
+       free(vid);
 }
 
-static void monitor_event(struct uterm_monitor *mon,
-                         struct uterm_monitor_event *ev,
-                         void *data)
+static void app_monitor_event(struct uterm_monitor *mon,
+                             struct uterm_monitor_event *ev,
+                             void *data)
 {
        struct kmscon_app *app = data;
-       struct kmscon_seat *seat;
+       struct app_seat *seat;
+       struct app_video *vid;
+       int ret;
 
        switch (ev->type) {
        case UTERM_MONITOR_NEW_SEAT:
-               seat_new(app, ev->seat, ev->seat_name);
+               ret = app_seat_new(app, &seat, ev->seat_name);
+               if (ret)
+                       return;
+               uterm_monitor_set_seat_data(ev->seat, seat);
                break;
        case UTERM_MONITOR_FREE_SEAT:
                if (ev->seat_data)
-                       seat_free(ev->seat_data);
+                       app_seat_free(ev->seat_data);
                break;
        case UTERM_MONITOR_NEW_DEV:
                seat = ev->seat_data;
                if (!seat)
+                       return;
+
+               switch (ev->dev_type) {
+               case UTERM_MONITOR_DRM:
+               case UTERM_MONITOR_FBDEV:
+               case UTERM_MONITOR_FBDEV_DRM:
+                       ret = app_seat_add_video(seat, &vid, ev->dev_type,
+                                                ev->dev_node);
+                       if (ret)
+                               return;
+                       uterm_monitor_set_dev_data(ev->dev, vid);
                        break;
-               if (ev->dev_type == UTERM_MONITOR_DRM ||
-                   ev->dev_type == UTERM_MONITOR_FBDEV ||
-                   ev->dev_type == UTERM_MONITOR_FBDEV_DRM)
-                       seat_add_video(seat, ev->dev, ev->dev_type,
-                                      ev->dev_node);
-               else if (ev->dev_type == UTERM_MONITOR_INPUT)
-                       uterm_input_add_dev(seat->input, ev->dev_node);
+               case UTERM_MONITOR_INPUT:
+                       log_debug("new input device %s on seat %s",
+                                 ev->dev_node, seat->name);
+                       kmscon_seat_add_input(seat->seat, ev->dev_node);
+                       break;
+               }
                break;
        case UTERM_MONITOR_FREE_DEV:
                seat = ev->seat_data;
                if (!seat)
+                       return;
+
+               switch (ev->dev_type) {
+               case UTERM_MONITOR_DRM:
+               case UTERM_MONITOR_FBDEV:
+               case UTERM_MONITOR_FBDEV_DRM:
+                       if (ev->dev_data)
+                               app_seat_remove_video(seat, ev->dev_data);
                        break;
-               if (ev->dev_type == UTERM_MONITOR_DRM ||
-                   ev->dev_type == UTERM_MONITOR_FBDEV ||
-                   ev->dev_type == UTERM_MONITOR_FBDEV_DRM)
-                       seat_rm_video(seat, ev->dev);
-               else if (ev->dev_type == UTERM_MONITOR_INPUT)
-                       uterm_input_remove_dev(seat->input, ev->dev_node);
+               case UTERM_MONITOR_INPUT:
+                       log_debug("free input device %s on seat %s",
+                                 ev->dev_node, seat->name);
+                       kmscon_seat_remove_input(seat->seat, ev->dev_node);
+                       break;
+               }
                break;
        case UTERM_MONITOR_HOTPLUG_DEV:
                seat = ev->seat_data;
                if (!seat)
+                       return;
+
+               switch (ev->dev_type) {
+               case UTERM_MONITOR_DRM:
+               case UTERM_MONITOR_FBDEV:
+               case UTERM_MONITOR_FBDEV_DRM:
+                       vid = ev->dev_data;
+                       if (!vid)
+                               return;
+
+                       log_debug("video hotplug event on device %s on seat %s",
+                                 vid->node, seat->name);
+                       uterm_video_poll(vid->video);
                        break;
-               seat_hotplug_video(seat, ev->dev);
+               }
                break;
        }
 }
 
+static void app_sig_generic(struct ev_eloop *eloop,
+                           struct signalfd_siginfo *info,
+                           void *data)
+{
+       struct kmscon_app *app = data;
+
+       log_info("terminating due to caught signal %d", info->ssi_signo);
+       ev_eloop_exit(app->eloop);
+}
+
 static void destroy_app(struct kmscon_app *app)
 {
        uterm_monitor_unref(app->mon);
        uterm_vt_master_unref(app->vtm);
-       ev_eloop_unregister_signal_cb(app->eloop, SIGINT, sig_generic, app);
-       ev_eloop_unregister_signal_cb(app->eloop, SIGTERM, sig_generic, app);
        ev_eloop_rm_eloop(app->vt_eloop);
+       ev_eloop_unregister_signal_cb(app->eloop, SIGINT, app_sig_generic,
+                                     app);
+       ev_eloop_unregister_signal_cb(app->eloop, SIGTERM, app_sig_generic,
+                                     app);
        ev_eloop_unref(app->eloop);
 }
 
@@ -370,34 +402,47 @@ static int setup_app(struct kmscon_app *app)
 {
        int ret;
 
+       shl_dlist_init(&app->seats);
+
        ret = ev_eloop_new(&app->eloop, log_llog);
-       if (ret)
+       if (ret) {
+               log_error("cannot create eloop object: %d", ret);
                goto err_app;
+       }
 
        ret = ev_eloop_register_signal_cb(app->eloop, SIGTERM,
-                                               sig_generic, app);
-       if (ret)
+                                         app_sig_generic, app);
+       if (ret) {
+               log_error("cannot register SIGTERM signal handler: %d", ret);
                goto err_app;
+       }
 
        ret = ev_eloop_register_signal_cb(app->eloop, SIGINT,
-                                               sig_generic, app);
-       if (ret)
+                                         app_sig_generic, app);
+       if (ret) {
+               log_error("cannot register SIGINT signal handler: %d", ret);
                goto err_app;
+       }
 
        ret = ev_eloop_new_eloop(app->eloop, &app->vt_eloop);
-       if (ret)
+       if (ret) {
+               log_error("cannot create VT eloop object: %d", ret);
                goto err_app;
+       }
 
        ret = uterm_vt_master_new(&app->vtm, app->vt_eloop);
-       if (ret)
+       if (ret) {
+               log_error("cannot create VT master: %d", ret);
                goto err_app;
+       }
 
-       shl_dlist_init(&app->seats);
-
-       ret = uterm_monitor_new(&app->mon, app->eloop, monitor_event, app);
-       if (ret)
+       ret = uterm_monitor_new(&app->mon, app->eloop, app_monitor_event, app);
+       if (ret) {
+               log_error("cannot create device monitor: %d", ret);
                goto err_app;
+       }
 
+       log_debug("scanning for devices...");
        uterm_monitor_scan(app->mon);
 
        return 0;
diff --git a/src/kmscon_seat.c b/src/kmscon_seat.c
new file mode 100644 (file)
index 0000000..91a8a5d
--- /dev/null
@@ -0,0 +1,491 @@
+/*
+ * Seats
+ *
+ * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * Seats
+ * A seat is a single session that is self-hosting and provides all the
+ * interaction for a single logged-in user.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include "eloop.h"
+#include "kmscon_conf.h"
+#include "kmscon_seat.h"
+#include "kmscon_terminal.h"
+#include "log.h"
+#include "shl_dlist.h"
+#include "uterm.h"
+
+#define LOG_SUBSYSTEM "seat"
+
+struct kmscon_session {
+       struct shl_dlist list;
+       unsigned long ref;
+       struct kmscon_seat *seat;
+
+       kmscon_session_cb_t cb;
+       void *data;
+};
+
+struct kmscon_display {
+       struct shl_dlist list;
+       struct kmscon_seat *seat;
+       struct uterm_display *disp;
+       bool activated;
+};
+
+struct kmscon_seat {
+       struct ev_eloop *eloop;
+       struct uterm_vt_master *vtm;
+
+       char *name;
+       bool awake;
+       struct uterm_input *input;
+       struct uterm_vt *vt;
+       struct shl_dlist displays;
+
+       struct shl_dlist sessions;
+       struct kmscon_session *cur_sess;
+
+       kmscon_seat_cb_t cb;
+       void *data;
+};
+
+static void session_call(struct kmscon_session *sess, unsigned int event,
+                        struct uterm_display *disp)
+{
+       if (!sess->cb)
+               return;
+
+       sess->cb(sess, event, disp, sess->data);
+}
+
+static void session_wake_up(struct kmscon_session *sess)
+{
+       session_call(sess, KMSCON_SESSION_WAKE_UP, NULL);
+}
+
+static void session_sleep(struct kmscon_session *sess)
+{
+       session_call(sess, KMSCON_SESSION_SLEEP, NULL);
+}
+
+static void session_display_new(struct kmscon_session *sess,
+                               struct uterm_display *disp)
+{
+       session_call(sess, KMSCON_SESSION_DISPLAY_NEW, disp);
+}
+
+static void session_display_gone(struct kmscon_session *sess,
+                                struct uterm_display *disp)
+{
+       session_call(sess, KMSCON_SESSION_DISPLAY_GONE, disp);
+}
+
+static void session_activate(struct kmscon_session *sess)
+{
+       struct kmscon_seat *seat = sess->seat;
+
+       if (seat->cur_sess == sess)
+               return;
+
+       if (seat->cur_sess) {
+               if (seat->awake)
+                       session_sleep(seat->cur_sess);
+               seat->cur_sess = NULL;
+       }
+
+       seat->cur_sess = sess;
+       if (seat->awake)
+               session_wake_up(sess);
+}
+
+static void session_deactivate(struct kmscon_session *sess)
+{
+       struct kmscon_seat *seat = sess->seat;
+
+       if (seat->cur_sess != sess)
+               return;
+
+       if (seat->awake)
+               session_sleep(sess);
+
+       if (shl_dlist_empty(&seat->sessions)) {
+               seat->cur_sess = NULL;
+       } else {
+               seat->cur_sess = shl_dlist_entry(seat->sessions.next,
+                                                struct kmscon_session,
+                                                list);
+               if (seat->awake)
+                       session_wake_up(seat->cur_sess);
+       }
+}
+
+static void activate_display(struct kmscon_display *d)
+{
+       int ret;
+       struct shl_dlist *iter, *tmp;
+       struct kmscon_session *s;
+       struct kmscon_seat *seat = d->seat;
+
+       if (d->activated)
+               return;
+
+       if (uterm_display_get_state(d->disp) == UTERM_DISPLAY_INACTIVE) {
+               ret = uterm_display_activate(d->disp, NULL);
+               if (ret)
+                       return;
+
+               d->activated = true;
+
+               shl_dlist_for_each_safe(iter, tmp, &seat->sessions) {
+                       s = shl_dlist_entry(iter, struct kmscon_session, list);
+                       session_display_new(s, d->disp);
+               }
+
+               ret = uterm_display_set_dpms(d->disp, UTERM_DPMS_ON);
+               if (ret)
+                       log_warning("cannot set DPMS state to on for display: %d",
+                                   ret);
+       }
+}
+
+static int seat_add_display(struct kmscon_seat *seat,
+                           struct uterm_display *disp)
+{
+       struct kmscon_display *d;
+
+       log_debug("add display %p to seat %s", disp, seat->name);
+
+       d = malloc(sizeof(*d));
+       if (!d)
+               return -ENOMEM;
+       memset(d, 0, sizeof(*d));
+       d->disp = disp;
+       d->seat = seat;
+
+       uterm_display_ref(d->disp);
+       shl_dlist_link(&seat->displays, &d->list);
+       activate_display(d);
+       return 0;
+}
+
+static void seat_remove_display(struct kmscon_seat *seat,
+                               struct kmscon_display *d)
+{
+       struct shl_dlist *iter, *tmp;
+       struct kmscon_session *s;
+
+       log_debug("remove display %p from seat %s", d->disp, seat->name);
+
+       shl_dlist_unlink(&d->list);
+
+       if (d->activated) {
+               shl_dlist_for_each_safe(iter, tmp, &seat->sessions) {
+                       s = shl_dlist_entry(iter, struct kmscon_session, list);
+                       session_display_gone(s, d->disp);
+               }
+       }
+
+       uterm_display_unref(d->disp);
+       free(d);
+}
+
+static int seat_vt_event(struct uterm_vt *vt, unsigned int event, void *data)
+{
+       struct kmscon_seat *seat = data;
+       struct shl_dlist *iter;
+       struct kmscon_display *d;
+
+       switch (event) {
+       case UTERM_VT_ACTIVATE:
+               seat->awake = true;
+               if (seat->cb)
+                       seat->cb(seat, KMSCON_SEAT_WAKE_UP, seat->data);
+
+               uterm_input_wake_up(seat->input);
+
+               shl_dlist_for_each(iter, &seat->displays) {
+                       d = shl_dlist_entry(iter, struct kmscon_display, list);
+                       activate_display(d);
+               }
+
+               if (seat->cur_sess)
+                       session_wake_up(seat->cur_sess);
+               break;
+       case UTERM_VT_DEACTIVATE:
+               if (seat->cur_sess)
+                       session_sleep(seat->cur_sess);
+
+               uterm_input_sleep(seat->input);
+
+               if (seat->cb)
+                       seat->cb(seat, KMSCON_SEAT_SLEEP, seat->data);
+               seat->awake = false;
+               break;
+       }
+
+       return 0;
+}
+
+int kmscon_seat_new(struct kmscon_seat **out,
+                   struct ev_eloop *eloop,
+                   struct uterm_vt_master *vtm,
+                   const char *seatname,
+                   kmscon_seat_cb_t cb,
+                   void *data)
+{
+       struct kmscon_seat *seat;
+       int ret;
+       struct kmscon_session *s;
+
+       if (!out || !eloop || !vtm || !seatname)
+               return -EINVAL;
+
+       seat = malloc(sizeof(*seat));
+       if (!seat)
+               return -ENOMEM;
+       memset(seat, 0, sizeof(*seat));
+       seat->eloop = eloop;
+       seat->vtm = vtm;
+       seat->cb = cb;
+       seat->data = data;
+       shl_dlist_init(&seat->displays);
+       shl_dlist_init(&seat->sessions);
+
+       seat->name = strdup(seatname);
+       if (!seat->name) {
+               log_error("cannot copy string");
+               ret = -ENOMEM;
+               goto err_free;
+       }
+
+       ret = uterm_input_new(&seat->input, seat->eloop,
+                             kmscon_conf.xkb_layout,
+                             kmscon_conf.xkb_variant,
+                             kmscon_conf.xkb_options,
+                             kmscon_conf.xkb_repeat_delay,
+                             kmscon_conf.xkb_repeat_rate);
+       if (ret)
+               goto err_name;
+
+       ret = uterm_vt_allocate(seat->vtm, &seat->vt, seat->name,
+                               seat->input, kmscon_conf.vt, seat_vt_event,
+                               seat);
+       if (ret)
+               goto err_input;
+
+       ret = kmscon_terminal_register(&s, seat);
+       if (ret)
+               goto err_vt;
+
+       ev_eloop_ref(seat->eloop);
+       uterm_vt_master_ref(seat->vtm);
+       *out = seat;
+       return 0;
+
+err_vt:
+       uterm_vt_deallocate(seat->vt);
+err_input:
+       uterm_input_unref(seat->input);
+err_name:
+       free(seat->name);
+err_free:
+       free(seat);
+       return ret;
+}
+
+void kmscon_seat_free(struct kmscon_seat *seat)
+{
+       struct kmscon_display *d;
+       struct kmscon_session *s;
+
+       if (!seat)
+               return;
+
+       while (!shl_dlist_empty(&seat->sessions)) {
+               s = shl_dlist_entry(seat->sessions.next,
+                                   struct kmscon_session,
+                                   list);
+               kmscon_session_unregister(s);
+       }
+
+       while (!shl_dlist_empty(&seat->displays)) {
+               d = shl_dlist_entry(seat->displays.next,
+                                   struct kmscon_display,
+                                   list);
+               seat_remove_display(seat, d);
+       }
+
+       uterm_vt_deallocate(seat->vt);
+       uterm_input_unref(seat->input);
+       free(seat->name);
+       uterm_vt_master_unref(seat->vtm);
+       ev_eloop_unref(seat->eloop);
+       free(seat);
+}
+
+int kmscon_seat_add_display(struct kmscon_seat *seat,
+                           struct uterm_display *disp)
+{
+       if (!seat || !disp)
+               return -EINVAL;
+
+       return seat_add_display(seat, disp);
+}
+
+void kmscon_seat_remove_display(struct kmscon_seat *seat,
+                               struct uterm_display *disp)
+{
+       struct shl_dlist *iter;
+       struct kmscon_display *d;
+
+       shl_dlist_for_each(iter, &seat->displays) {
+               d = shl_dlist_entry(iter, struct kmscon_display, list);
+               if (d->disp != disp)
+                       continue;
+
+               seat_remove_display(seat, d);
+               break;
+       }
+}
+
+int kmscon_seat_add_input(struct kmscon_seat *seat, const char *node)
+{
+       if (!seat || !node)
+               return -EINVAL;
+
+       uterm_input_add_dev(seat->input, node);
+       return 0;
+}
+
+void kmscon_seat_remove_input(struct kmscon_seat *seat, const char *node)
+{
+       if (!seat || !node)
+               return;
+
+       uterm_input_remove_dev(seat->input, node);
+}
+
+const char *kmscon_seat_get_name(struct kmscon_seat *seat)
+{
+       if (!seat)
+               return NULL;
+
+       return seat->name;
+}
+
+struct uterm_input *kmscon_seat_get_input(struct kmscon_seat *seat)
+{
+       if (!seat)
+               return NULL;
+
+       return seat->input;
+}
+
+struct ev_eloop *kmscon_seat_get_eloop(struct kmscon_seat *seat)
+{
+       if (!seat)
+               return NULL;
+
+       return seat->eloop;
+}
+
+int kmscon_seat_register_session(struct kmscon_seat *seat,
+                                struct kmscon_session **out,
+                                kmscon_session_cb_t cb,
+                                void *data)
+{
+       struct kmscon_session *sess;
+
+       if (!seat || !out)
+               return -EINVAL;
+
+       sess = malloc(sizeof(*sess));
+       if (!sess) {
+               log_error("cannot allocate memory for new session on seat %s",
+                         seat->name);
+               return -ENOMEM;
+       }
+       memset(sess, 0, sizeof(*sess));
+       sess->ref = 1;
+       sess->seat = seat;
+       sess->cb = cb;
+       sess->data = data;
+
+       shl_dlist_link(&seat->sessions, &sess->list);
+       *out = sess;
+
+       if (!seat->cur_sess)
+               session_activate(sess);
+
+       return 0;
+}
+
+void kmscon_session_ref(struct kmscon_session *sess)
+{
+       if (!sess || !sess->ref)
+               return;
+
+       ++sess->ref;
+}
+
+void kmscon_session_unref(struct kmscon_session *sess)
+{
+       if (!sess || !sess->ref || --sess->ref)
+               return;
+
+       kmscon_session_unregister(sess);
+       free(sess);
+}
+
+void kmscon_session_unregister(struct kmscon_session *sess)
+{
+       if (!sess || !sess->seat)
+               return;
+
+       shl_dlist_unlink(&sess->list);
+       session_deactivate(sess);
+       sess->seat = NULL;
+       session_call(sess, KMSCON_SESSION_UNREGISTER, NULL);
+}
+
+void kmscon_session_activate(struct kmscon_session *sess)
+{
+       if (!sess || !sess->seat)
+               return;
+
+       session_activate(sess);
+}
+
+void kmscon_session_deactivate(struct kmscon_session *sess)
+{
+       if (!sess || !sess->seat)
+               return;
+
+       session_deactivate(sess);
+}
diff --git a/src/kmscon_seat.h b/src/kmscon_seat.h
new file mode 100644 (file)
index 0000000..76f8e76
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Seats
+ *
+ * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * Seats
+ * A seat is a single session that is self-hosting and provides all the
+ * interaction for a single logged-in user.
+ */
+
+#ifndef KMSCON_SEAT_H
+#define KMSCON_SEAT_H
+
+#include <stdlib.h>
+#include <unistd.h>
+#include "eloop.h"
+#include "uterm.h"
+
+struct kmscon_seat;
+struct kmscon_session;
+
+enum kmscon_seat_event {
+       KMSCON_SEAT_WAKE_UP,
+       KMSCON_SEAT_SLEEP,
+};
+
+typedef void (*kmscon_seat_cb_t) (struct kmscon_seat *seat,
+                                 unsigned int event,
+                                 void *data);
+
+enum kmscon_session_event {
+       KMSCON_SESSION_DISPLAY_NEW,
+       KMSCON_SESSION_DISPLAY_GONE,
+       KMSCON_SESSION_WAKE_UP,
+       KMSCON_SESSION_SLEEP,
+       KMSCON_SESSION_UNREGISTER,
+};
+
+typedef void (*kmscon_session_cb_t) (struct kmscon_session *session,
+                                    unsigned int event,
+                                    struct uterm_display *disp,
+                                    void *data);
+
+int kmscon_seat_new(struct kmscon_seat **out,
+                   struct ev_eloop *eloop,
+                   struct uterm_vt_master *vtm,
+                   const char *seatname,
+                   kmscon_seat_cb_t cb,
+                   void *data);
+void kmscon_seat_free(struct kmscon_seat *seat);
+
+int kmscon_seat_add_display(struct kmscon_seat *seat,
+                           struct uterm_display *disp);
+void kmscon_seat_remove_display(struct kmscon_seat *seat,
+                               struct uterm_display *disp);
+int kmscon_seat_add_input(struct kmscon_seat *seat, const char *node);
+void kmscon_seat_remove_input(struct kmscon_seat *seat, const char *node);
+
+const char *kmscon_seat_get_name(struct kmscon_seat *seat);
+struct uterm_input *kmscon_seat_get_input(struct kmscon_seat *seat);
+struct ev_eloop *kmscon_seat_get_eloop(struct kmscon_seat *seat);
+
+int kmscon_seat_register_session(struct kmscon_seat *seat,
+                                struct kmscon_session **out,
+                                kmscon_session_cb_t cb,
+                                void *data);
+
+void kmscon_session_ref(struct kmscon_session *sess);
+void kmscon_session_unref(struct kmscon_session *sess);
+void kmscon_session_unregister(struct kmscon_session *sess);
+
+void kmscon_session_activate(struct kmscon_session *sess);
+void kmscon_session_deactivate(struct kmscon_session *sess);
+
+#endif /* KMSCON_SEAT_H */
index a616899..6e4da08 100644 (file)
@@ -36,6 +36,7 @@
 #include <string.h>
 #include "eloop.h"
 #include "kmscon_conf.h"
+#include "kmscon_seat.h"
 #include "kmscon_terminal.h"
 #include "log.h"
 #include "pty.h"
@@ -62,6 +63,8 @@ struct kmscon_terminal {
        bool opened;
        bool awake;
 
+       struct kmscon_session *session;
+
        struct shl_dlist screens;
        unsigned int min_cols;
        unsigned int min_rows;
@@ -73,9 +76,6 @@ struct kmscon_terminal {
        struct tsm_vte *vte;
        struct kmscon_pty *pty;
        struct ev_fd *ptyfd;
-
-       kmscon_terminal_event_cb cb;
-       void *data;
 };
 
 static void redraw(struct kmscon_terminal *term)
@@ -180,6 +180,7 @@ static void terminal_resize(struct kmscon_terminal *term,
        /* shrinking always succeeds */
        tsm_screen_resize(term->console, term->min_cols, term->min_rows);
        kmscon_pty_resize(term->pty, term->min_cols, term->min_rows);
+       schedule_redraw(term);
 }
 
 static int add_display(struct kmscon_terminal *term, struct uterm_display *disp)
@@ -310,45 +311,6 @@ static void rm_display(struct kmscon_terminal *term, struct uterm_display *disp)
 
        log_debug("removed display %p from terminal %p", disp, term);
        free_screen(term, scr, true);
-       if (shl_dlist_empty(&term->screens) && term->cb)
-               term->cb(term, KMSCON_TERMINAL_NO_DISPLAY, term->data);
-}
-
-static void rm_all_screens(struct kmscon_terminal *term)
-{
-       struct shl_dlist *iter;
-       struct screen *scr;
-
-       while ((iter = term->screens.next) != &term->screens) {
-               scr = shl_dlist_entry(iter, struct screen, list);
-               free_screen(term, scr, false);
-       }
-
-       term->min_cols = 0;
-       term->min_rows = 0;
-}
-
-static void pty_input(struct kmscon_pty *pty, const char *u8, size_t len,
-                                                               void *data)
-{
-       struct kmscon_terminal *term = data;
-
-       if (!len) {
-               if (term->cb)
-                       term->cb(term, KMSCON_TERMINAL_HUP, term->data);
-               else
-                       kmscon_terminal_open(term, term->cb, term->data);
-       } else {
-               tsm_vte_input(term->vte, u8, len);
-               schedule_redraw(term);
-       }
-}
-
-static void pty_event(struct ev_fd *fd, int mask, void *data)
-{
-       struct kmscon_terminal *term = data;
-
-       kmscon_pty_dispatch(term->pty);
 }
 
 static void input_event(struct uterm_input *input,
@@ -403,6 +365,111 @@ static void input_event(struct uterm_input *input,
        }
 }
 
+static void rm_all_screens(struct kmscon_terminal *term)
+{
+       struct shl_dlist *iter;
+       struct screen *scr;
+
+       while ((iter = term->screens.next) != &term->screens) {
+               scr = shl_dlist_entry(iter, struct screen, list);
+               free_screen(term, scr, false);
+       }
+
+       term->min_cols = 0;
+       term->min_rows = 0;
+}
+
+static int terminal_open(struct kmscon_terminal *term)
+{
+       int ret;
+       unsigned short width, height;
+
+       kmscon_pty_close(term->pty);
+       tsm_vte_hard_reset(term->vte);
+       width = tsm_screen_get_width(term->console);
+       height = tsm_screen_get_height(term->console);
+       ret = kmscon_pty_open(term->pty, width, height);
+       if (ret) {
+               term->opened = false;
+               return ret;
+       }
+
+       term->opened = true;
+       schedule_redraw(term);
+       return 0;
+}
+
+static void terminal_close(struct kmscon_terminal *term)
+{
+       kmscon_pty_close(term->pty);
+       term->opened = false;
+}
+
+static void terminal_destroy(struct kmscon_terminal *term)
+{
+       log_debug("free terminal object %p", term);
+
+       terminal_close(term);
+       rm_all_screens(term);
+       ev_eloop_rm_timer(term->redraw_timer);
+       ev_timer_unref(term->redraw_timer);
+       uterm_input_unregister_cb(term->input, input_event, term);
+       ev_eloop_rm_fd(term->ptyfd);
+       kmscon_pty_unref(term->pty);
+       tsm_vte_unref(term->vte);
+       tsm_screen_unref(term->console);
+       uterm_input_unref(term->input);
+       ev_eloop_unref(term->eloop);
+       free(term);
+}
+
+static void session_event(struct kmscon_session *session, unsigned int event,
+                         struct uterm_display *disp, void *data)
+{
+       struct kmscon_terminal *term = data;
+
+       switch (event) {
+       case KMSCON_SESSION_DISPLAY_NEW:
+               add_display(term, disp);
+               break;
+       case KMSCON_SESSION_DISPLAY_GONE:
+               rm_display(term, disp);
+               break;
+       case KMSCON_SESSION_WAKE_UP:
+               term->awake = true;
+               if (!term->opened)
+                       terminal_open(term);
+               schedule_redraw(term);
+               break;
+       case KMSCON_SESSION_SLEEP:
+               term->awake = false;
+               break;
+       case KMSCON_SESSION_UNREGISTER:
+               terminal_destroy(term);
+               break;
+       }
+}
+
+static void pty_input(struct kmscon_pty *pty, const char *u8, size_t len,
+                                                               void *data)
+{
+       struct kmscon_terminal *term = data;
+
+       if (!len) {
+               terminal_open(term);
+       } else {
+               tsm_vte_input(term->vte, u8, len);
+               schedule_redraw(term);
+       }
+}
+
+static void pty_event(struct ev_fd *fd, int mask, void *data)
+{
+       struct kmscon_terminal *term = data;
+
+       kmscon_pty_dispatch(term->pty);
+}
+
 static void write_event(struct tsm_vte *vte, const char *u8, size_t len,
                        void *data)
 {
@@ -411,17 +478,15 @@ static void write_event(struct tsm_vte *vte, const char *u8, size_t len,
        kmscon_pty_write(term->pty, u8, len);
 }
 
-int kmscon_terminal_new(struct kmscon_terminal **out,
-                       struct ev_eloop *loop,
-                       struct uterm_input *input,
-                       const char *seat)
+int kmscon_terminal_register(struct kmscon_session **out,
+                            struct kmscon_seat *seat)
 {
        struct kmscon_terminal *term;
        int ret;
        struct itimerspec spec;
        unsigned long fps;
 
-       if (!out || !loop || !input)
+       if (!out || !seat)
                return -EINVAL;
 
        term = malloc(sizeof(*term));
@@ -430,8 +495,8 @@ int kmscon_terminal_new(struct kmscon_terminal **out,
 
        memset(term, 0, sizeof(*term));
        term->ref = 1;
-       term->eloop = loop;
-       term->input = input;
+       term->eloop = kmscon_seat_get_eloop(seat);
+       term->input = kmscon_seat_get_input(seat);
        shl_dlist_init(&term->screens);
 
        if (kmscon_conf.fps) {
@@ -473,7 +538,7 @@ int kmscon_terminal_new(struct kmscon_terminal **out,
        if (ret)
                goto err_pty;
 
-       ret = kmscon_pty_set_seat(term->pty, seat);
+       ret = kmscon_pty_set_seat(term->pty, kmscon_seat_get_name(seat));
        if (ret)
                goto err_pty;
 
@@ -501,13 +566,21 @@ int kmscon_terminal_new(struct kmscon_terminal **out,
        if (ret)
                goto err_timer;
 
+       ret = kmscon_seat_register_session(seat, &term->session, session_event,
+                                          term);
+       if (ret) {
+               log_error("cannot register session for terminal: %d", ret);
+               goto err_redraw;
+       }
+
        ev_eloop_ref(term->eloop);
        uterm_input_ref(term->input);
-       *out = term;
-
+       *out = term->session;
        log_debug("new terminal object %p", term);
        return 0;
 
+err_redraw:
+       ev_eloop_rm_timer(term->redraw_timer);
 err_timer:
        ev_timer_unref(term->redraw_timer);
 err_input:
@@ -524,116 +597,3 @@ err_free:
        free(term);
        return ret;
 }
-
-void kmscon_terminal_ref(struct kmscon_terminal *term)
-{
-       if (!term)
-               return;
-
-       term->ref++;
-}
-
-void kmscon_terminal_unref(struct kmscon_terminal *term)
-{
-       if (!term || !term->ref)
-               return;
-
-       if (--term->ref)
-               return;
-
-       log_debug("free terminal object %p", term);
-       kmscon_terminal_close(term);
-       rm_all_screens(term);
-       ev_eloop_rm_timer(term->redraw_timer);
-       ev_timer_unref(term->redraw_timer);
-       uterm_input_unregister_cb(term->input, input_event, term);
-       ev_eloop_rm_fd(term->ptyfd);
-       kmscon_pty_unref(term->pty);
-       tsm_vte_unref(term->vte);
-       tsm_screen_unref(term->console);
-       uterm_input_unref(term->input);
-       ev_eloop_unref(term->eloop);
-       free(term);
-}
-
-int kmscon_terminal_open(struct kmscon_terminal *term,
-                       kmscon_terminal_event_cb cb, void *data)
-{
-       int ret;
-       unsigned short width, height;
-
-       if (!term)
-               return -EINVAL;
-
-       kmscon_pty_close(term->pty);
-       tsm_vte_hard_reset(term->vte);
-       width = tsm_screen_get_width(term->console);
-       height = tsm_screen_get_height(term->console);
-       ret = kmscon_pty_open(term->pty, width, height);
-       if (ret)
-               return ret;
-
-       term->opened = true;
-       term->cb = cb;
-       term->data = data;
-       return 0;
-}
-
-void kmscon_terminal_close(struct kmscon_terminal *term)
-{
-       if (!term)
-               return;
-
-       kmscon_pty_close(term->pty);
-       term->data = NULL;
-       term->cb = NULL;
-       term->opened = false;
-}
-
-void kmscon_terminal_redraw(struct kmscon_terminal *term)
-{
-       if (!term)
-               return;
-
-       schedule_redraw(term);
-}
-
-int kmscon_terminal_add_display(struct kmscon_terminal *term,
-                               struct uterm_display *disp)
-{
-       if (!term || !disp)
-               return -EINVAL;
-
-       return add_display(term, disp);
-}
-
-void kmscon_terminal_remove_display(struct kmscon_terminal *term,
-                                   struct uterm_display *disp)
-{
-       if (!term || !disp)
-               return;
-
-       rm_display(term, disp);
-}
-
-void kmscon_terminal_wake_up(struct kmscon_terminal *term)
-{
-       if (!term || term->awake)
-               return;
-
-       term->awake = true;
-       schedule_redraw(term);
-}
-
-void kmscon_terminal_sleep(struct kmscon_terminal *term)
-{
-       if (!term || !term->awake)
-               return;
-
-       term->awake = false;
-}
-
-bool kmscon_terminal_is_awake(struct kmscon_terminal *term)
-{
-       return term && term->awake;
-}
index e41381d..6bdb4bf 100644 (file)
 #define KMSCON_TERMINAL_H
 
 #include <stdlib.h>
-#include "eloop.h"
-#include "tsm_screen.h"
-#include "uterm.h"
+#include "kmscon_seat.h"
 
-struct kmscon_terminal;
-
-enum kmscon_terminal_etype {
-       KMSCON_TERMINAL_HUP,            /* child closed */
-       KMSCON_TERMINAL_NO_DISPLAY,     /* no more display connected */
-};
-
-typedef void (*kmscon_terminal_event_cb)
-               (struct kmscon_terminal *term,
-               enum kmscon_terminal_etype type,
-               void *data);
-
-int kmscon_terminal_new(struct kmscon_terminal **out,
-                       struct ev_eloop *loop,
-                       struct uterm_input *input,
-                       const char *seat);
-void kmscon_terminal_ref(struct kmscon_terminal *term);
-void kmscon_terminal_unref(struct kmscon_terminal *term);
-
-int kmscon_terminal_open(struct kmscon_terminal *term,
-                       kmscon_terminal_event_cb event_cb, void *data);
-void kmscon_terminal_close(struct kmscon_terminal *term);
-void kmscon_terminal_redraw(struct kmscon_terminal *term);
-
-int kmscon_terminal_add_display(struct kmscon_terminal *term,
-                               struct uterm_display *disp);
-void kmscon_terminal_remove_display(struct kmscon_terminal *term,
-                                   struct uterm_display *disp);
-
-void kmscon_terminal_wake_up(struct kmscon_terminal *term);
-void kmscon_terminal_sleep(struct kmscon_terminal *term);
-bool kmscon_terminal_is_awake(struct kmscon_terminal *term);
+int kmscon_terminal_register(struct kmscon_session **out,
+                            struct kmscon_seat *seat);
 
 #endif /* KMSCON_TERMINAL_H */