uvtd: seat: implement session IDs
authorDavid Herrmann <dh.herrmann@gmail.com>
Wed, 6 Mar 2013 17:21:25 +0000 (18:21 +0100)
committerDavid Herrmann <dh.herrmann@gmail.com>
Wed, 6 Mar 2013 17:21:25 +0000 (18:21 +0100)
Session IDs provide a unique ID for each registered session. They are used
to sort the sessions so next/prev return the correct neighbour-sessions.
Furthermore, they can be used by outside users to refer to a session
directly without knowing the session implementation.
Sessions with ID=0 are always linked at the end and considered to be
"unnamed".

The algorithm to switch to a session with a given ID is:
  Try to find the first session with the exact same ID. If there is none,
  return the session with the next higher ID. If there is none, return the
  ID'th session in the list. If there is none, return the last session.

This provides a fairly predictable way of switching between session. It is
modeled after the classic VT F1-F12 keys that switch between sessions. If
a session is not given, these keys will switch to the next higher session
instead.
All "unnamed" sessions are put at the end. So if you have only F1-F4, then
F5-F12 will map to unnamed sessions.

Please note that new sessions are always linked at the end of their group.
So new unnamed sessions are at the far end, new named sessions are linked
in the sorted list but behind all sessions with the same ID.
Hence, the caller should avoid multiple sessions with the same ID,
otherwise, some sessions might not be reachable even though they're named
(unless you use next/prev of course).

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
src/uvtd_seat.c

index 2ef3180..0a1d71c 100644 (file)
@@ -64,6 +64,7 @@ struct uvtd_session {
        struct shl_dlist list;
        unsigned long ref;
        struct uvtd_seat *seat;
+       unsigned int id;
 
        bool enabled;
        bool deactivating;
@@ -426,12 +427,36 @@ void uvtd_seat_wake_up(struct uvtd_seat *seat)
        seat_run(seat);
 }
 
+void uvtd_seat_schedule(struct uvtd_seat *seat, unsigned int id)
+{
+       struct shl_dlist *iter;
+       struct uvtd_session *session;
+       unsigned int i;
+
+       if (!seat || !id)
+               return;
+
+       session = NULL;
+       i = id;
+       shl_dlist_for_each(iter, &seat->sessions) {
+               session = shl_dlist_entry(iter, struct uvtd_session, list);
+               if (!--i)
+                       break;
+               if (session->id >= id)
+                       break;
+       }
+
+       if (session)
+               seat_schedule(seat, session);
+}
+
 int uvtd_seat_register_session(struct uvtd_seat *seat,
                               struct uvtd_session **out,
                               unsigned int id, uvtd_session_cb_t cb,
                               void *data)
 {
-       struct uvtd_session *sess;
+       struct uvtd_session *sess, *s;
+       struct shl_dlist *iter;
 
        if (!seat || !out)
                return -EINVAL;
@@ -440,23 +465,34 @@ int uvtd_seat_register_session(struct uvtd_seat *seat,
        if (!sess)
                return -ENOMEM;
 
-       log_debug("register session %p", sess);
+       log_debug("register session %p with id %u on seat %p",
+                 sess, id, seat);
 
        memset(sess, 0, sizeof(*sess));
        sess->ref = 1;
        sess->seat = seat;
        sess->cb = cb;
        sess->data = data;
-
-       /* TODO: add support for \ids */
-       /* register new sessions next to the current one */
-       if (seat->current_sess)
-               shl_dlist_link(&seat->current_sess->list, &sess->list);
-       else
-               shl_dlist_link_tail(&seat->sessions, &sess->list);
+       sess->id = id;
 
        ++seat->session_count;
        *out = sess;
+
+       if (sess->id) {
+               shl_dlist_for_each(iter, &seat->sessions) {
+                       s = shl_dlist_entry(iter, struct uvtd_session, list);
+                       if (!s->id || s->id > sess->id) {
+                               shl_dlist_link_tail(iter, &sess->list);
+                               return 0;
+                       }
+
+                       if (s->id == sess->id)
+                               log_warning("session %p shadowed by %p",
+                                           sess, s);
+               }
+       }
+
+       shl_dlist_link_tail(&seat->sessions, &sess->list);
        return 0;
 }