chiark / gitweb /
terminal: move unifont-map to datadir
[elogind.git] / src / libsystemd-terminal / sysview.c
index fde87d11174b73bdc09a46114a812cb105e99064..70a6ca726c5184ec3decea93b37708c6309dff53 100644 (file)
@@ -104,6 +104,12 @@ sysview_device *sysview_device_free(sysview_device *device) {
         return NULL;
 }
 
+const char *sysview_device_get_name(sysview_device *device) {
+        assert_return(device, NULL);
+
+        return device->name;
+}
+
 unsigned int sysview_device_get_type(sysview_device *device) {
         assert_return(device, (unsigned)-1);
 
@@ -243,18 +249,36 @@ sysview_session *sysview_session_free(sysview_session *session) {
         return NULL;
 }
 
+void sysview_session_set_userdata(sysview_session *session, void *userdata) {
+        assert(session);
+
+        session->userdata = userdata;
+}
+
+void *sysview_session_get_userdata(sysview_session *session) {
+        assert_return(session, NULL);
+
+        return session->userdata;
+}
+
 const char *sysview_session_get_name(sysview_session *session) {
         assert_return(session, NULL);
 
         return session->name;
 }
 
+sysview_seat *sysview_session_get_seat(sysview_session *session) {
+        assert_return(session, NULL);
+
+        return session->seat;
+}
+
 static int session_take_control_fn(sd_bus *bus,
                                    sd_bus_message *reply,
                                    void *userdata,
                                    sd_bus_error *ret_error) {
         sysview_session *session = userdata;
-        int error;
+        int r, error;
 
         session->slot_take_control = sd_bus_slot_unref(session->slot_take_control);
 
@@ -269,7 +293,12 @@ static int session_take_control_fn(sd_bus *bus,
                 error = 0;
         }
 
-        return context_raise_session_control(session->seat->context, session, error);
+        r = context_raise_session_control(session->seat->context, session, error);
+        if (r < 0)
+                log_debug("sysview: callback failed while signalling session control '%d' on session '%s': %s",
+                          error, session->name, strerror(-r));
+
+        return 0;
 }
 
 int sysview_session_take_control(sysview_session *session) {
@@ -368,6 +397,10 @@ int sysview_seat_new(sysview_seat **out, sysview_context *c, const char *name) {
         if (!seat->name)
                 return -ENOMEM;
 
+        r = sd_bus_path_encode("/org/freedesktop/login1/seat", seat->name, &seat->path);
+        if (r < 0)
+                return r;
+
         seat->session_map = hashmap_new(&string_hash_ops);
         if (!seat->session_map)
                 return -ENOMEM;
@@ -399,6 +432,7 @@ sysview_seat *sysview_seat_free(sysview_seat *seat) {
 
         hashmap_free(seat->device_map);
         hashmap_free(seat->session_map);
+        free(seat->path);
         free(seat->name);
         free(seat);
 
@@ -411,6 +445,29 @@ const char *sysview_seat_get_name(sysview_seat *seat) {
         return seat->name;
 }
 
+int sysview_seat_switch_to(sysview_seat *seat, uint32_t nr) {
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        int r;
+
+        assert_return(seat, -EINVAL);
+        assert_return(seat->context->sysbus, -EINVAL);
+
+        r = sd_bus_message_new_method_call(seat->context->sysbus,
+                                           &m,
+                                           "org.freedesktop.login1",
+                                           seat->path,
+                                           "org.freedesktop.login1.Seat",
+                                           "SwitchTo");
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_append(m, "u", nr);
+        if (r < 0)
+                return r;
+
+        return sd_bus_send(seat->context->sysbus, m, NULL);
+}
+
 /*
  * Contexts
  */
@@ -517,10 +574,23 @@ static int context_raise_session_detach(sysview_context *c, sysview_session *ses
         return context_raise(c, &event, 0);
 }
 
-static int context_add_device(sysview_context *c, sysview_device *device) {
+static int context_raise_session_refresh(sysview_context *c, sysview_session *session, sysview_device *device, struct udev_device *ud) {
+        sysview_event event = {
+                .type = SYSVIEW_EVENT_SESSION_REFRESH,
+                .session_refresh = {
+                        .session = session,
+                        .device = device,
+                        .ud = ud,
+                }
+        };
+
+        return context_raise(c, &event, 0);
+}
+
+static void context_add_device(sysview_context *c, sysview_device *device) {
         sysview_session *session;
-        int r, error = 0;
         Iterator i;
+        int r;
 
         assert(c);
         assert(device);
@@ -533,20 +603,16 @@ static int context_add_device(sysview_context *c, sysview_device *device) {
                         continue;
 
                 r = context_raise_session_attach(c, session, device);
-                if (r != 0)
-                        error = r;
+                if (r < 0)
+                        log_debug("sysview: callback failed while attaching device '%s' to session '%s': %s",
+                                  device->name, session->name, strerror(-r));
         }
-
-        if (error < 0)
-                log_debug("sysview: error while adding device '%s': %s",
-                          device->name, strerror(-r));
-        return error;
 }
 
-static int context_remove_device(sysview_context *c, sysview_device *device) {
+static void context_remove_device(sysview_context *c, sysview_device *device) {
         sysview_session *session;
-        int r, error = 0;
         Iterator i;
+        int r;
 
         assert(c);
         assert(device);
@@ -558,22 +624,40 @@ static int context_remove_device(sysview_context *c, sysview_device *device) {
                         continue;
 
                 r = context_raise_session_detach(c, session, device);
-                if (r != 0)
-                        error = r;
+                if (r < 0)
+                        log_debug("sysview: callback failed while detaching device '%s' from session '%s': %s",
+                                  device->name, session->name, strerror(-r));
         }
 
-        if (error < 0)
-                log_debug("sysview: error while removing device '%s': %s",
-                          device->name, strerror(-r));
         sysview_device_free(device);
-        return error;
 }
 
-static int context_add_session(sysview_context *c, sysview_seat *seat, const char *id) {
+static void context_change_device(sysview_context *c, sysview_device *device, struct udev_device *ud) {
+        sysview_session *session;
+        Iterator i;
+        int r;
+
+        assert(c);
+        assert(device);
+
+        log_debug("sysview: change device '%s'", device->name);
+
+        HASHMAP_FOREACH(session, device->seat->session_map, i) {
+                if (!session->public)
+                        continue;
+
+                r = context_raise_session_refresh(c, session, device, ud);
+                if (r < 0)
+                        log_debug("sysview: callback failed while changing device '%s' on session '%s': %s",
+                                  device->name, session->name, strerror(-r));
+        }
+}
+
+static void context_add_session(sysview_context *c, sysview_seat *seat, const char *id) {
         sysview_session *session;
         sysview_device *device;
-        int r, error = 0;
         Iterator i;
+        int r;
 
         assert(c);
         assert(seat);
@@ -581,7 +665,7 @@ static int context_add_session(sysview_context *c, sysview_seat *seat, const cha
 
         session = sysview_find_session(c, id);
         if (session)
-                return 0;
+                return;
 
         log_debug("sysview: add session '%s' on seat '%s'", id, seat->name);
 
@@ -598,35 +682,33 @@ static int context_add_session(sysview_context *c, sysview_seat *seat, const cha
         if (seat->public) {
                 session->public = true;
                 r = context_raise_session_add(c, session);
-                if (r != 0) {
+                if (r < 0) {
+                        log_debug("sysview: callback failed while adding session '%s': %s",
+                                  session->name, strerror(-r));
                         session->public = false;
                         goto error;
                 }
 
                 HASHMAP_FOREACH(device, seat->device_map, i) {
                         r = context_raise_session_attach(c, session, device);
-                        if (r != 0)
-                                error = r;
+                        if (r < 0)
+                                log_debug("sysview: callback failed while attaching device '%s' to new session '%s': %s",
+                                          device->name, session->name, strerror(-r));
                 }
-
-                r = error;
-                if (r != 0)
-                        goto error;
         }
 
-        return 0;
+        return;
 
 error:
         if (r < 0)
                 log_debug("sysview: error while adding session '%s': %s",
                           id, strerror(-r));
-        return r;
 }
 
-static int context_remove_session(sysview_context *c, sysview_session *session) {
+static void context_remove_session(sysview_context *c, sysview_session *session) {
         sysview_device *device;
-        int r, error = 0;
         Iterator i;
+        int r;
 
         assert(c);
         assert(session);
@@ -636,27 +718,25 @@ static int context_remove_session(sysview_context *c, sysview_session *session)
         if (session->public) {
                 HASHMAP_FOREACH(device, session->seat->device_map, i) {
                         r = context_raise_session_detach(c, session, device);
-                        if (r != 0)
-                                error = r;
+                        if (r < 0)
+                                log_debug("sysview: callback failed while detaching device '%s' from old session '%s': %s",
+                                          device->name, session->name, strerror(-r));
                 }
 
                 session->public = false;
                 r = context_raise_session_remove(c, session);
-                if (r != 0)
-                        error = r;
+                if (r < 0)
+                        log_debug("sysview: callback failed while removing session '%s': %s",
+                                  session->name, strerror(-r));
         }
 
         if (!session->custom)
                 sysview_session_release_control(session);
 
-        if (error < 0)
-                log_debug("sysview: error while removing session '%s': %s",
-                          session->name, strerror(-error));
         sysview_session_free(session);
-        return error;
 }
 
-static int context_add_seat(sysview_context *c, const char *id) {
+static void context_add_seat(sysview_context *c, const char *id) {
         sysview_seat *seat;
         int r;
 
@@ -665,7 +745,7 @@ static int context_add_seat(sysview_context *c, const char *id) {
 
         seat = sysview_find_seat(c, id);
         if (seat)
-                return 0;
+                return;
 
         log_debug("sysview: add seat '%s'", id);
 
@@ -675,54 +755,45 @@ static int context_add_seat(sysview_context *c, const char *id) {
 
         seat->public = true;
         r = context_raise_seat_add(c, seat);
-        if (r != 0) {
+        if (r < 0) {
+                log_debug("sysview: callback failed while adding seat '%s': %s",
+                          seat->name, strerror(-r));
                 seat->public = false;
-                goto error;
         }
 
-        return 0;
+        return;
 
 error:
         if (r < 0)
                 log_debug("sysview: error while adding seat '%s': %s",
                           id, strerror(-r));
-        return r;
 }
 
-static int context_remove_seat(sysview_context *c, sysview_seat *seat) {
+static void context_remove_seat(sysview_context *c, sysview_seat *seat) {
         sysview_session *session;
         sysview_device *device;
-        int r, error = 0;
+        int r;
 
         assert(c);
         assert(seat);
 
         log_debug("sysview: remove seat '%s'", seat->name);
 
-        while ((device = hashmap_first(seat->device_map))) {
-                r = context_remove_device(c, device);
-                if (r != 0)
-                        error = r;
-        }
+        while ((device = hashmap_first(seat->device_map)))
+                context_remove_device(c, device);
 
-        while ((session = hashmap_first(seat->session_map))) {
-                r = context_remove_session(c, session);
-                if (r != 0)
-                        error = r;
-        }
+        while ((session = hashmap_first(seat->session_map)))
+                context_remove_session(c, session);
 
         if (seat->public) {
                 seat->public = false;
                 r = context_raise_seat_remove(c, seat);
-                if (r != 0)
-                        error = r;
+                if (r < 0)
+                        log_debug("sysview: callback failed while removing seat '%s': %s",
+                                  seat->name, strerror(-r));
         }
 
-        if (error < 0)
-                log_debug("sysview: error while removing seat '%s': %s",
-                          seat->name, strerror(-error));
         sysview_seat_free(seat);
-        return error;
 }
 
 int sysview_context_new(sysview_context **out,
@@ -867,12 +938,12 @@ static int context_ud_hotplug(sysview_context *c, struct udev_device *d) {
                 if (!device)
                         return 0;
 
-                return context_remove_device(c, device);
+                context_remove_device(c, device);
         } else if (streq_ptr(action, "change")) {
                 if (!device)
                         return 0;
 
-                /* TODO: send REFRESH event */
+                context_change_device(c, device, d);
         } else if (!action || streq_ptr(action, "add")) {
                 struct udev_device *p;
                 unsigned int type, t;
@@ -883,7 +954,7 @@ static int context_ud_hotplug(sysview_context *c, struct udev_device *d) {
 
                 if (streq(subsystem, "input") && startswith(sysname, "event") && safe_atou(sysname + 5, &t) >= 0)
                         type = SYSVIEW_DEVICE_EVDEV;
-                else if (streq(subsystem, "drm") && startswith(sysname, "card") && safe_atou(sysname + 4, &t) >= 0)
+                else if (streq(subsystem, "drm") && startswith(sysname, "card"))
                         type = SYSVIEW_DEVICE_DRM;
                 else
                         type = (unsigned)-1;
@@ -893,11 +964,11 @@ static int context_ud_hotplug(sysview_context *c, struct udev_device *d) {
 
                 p = d;
                 seatname = NULL;
-                while ((p = udev_device_get_parent(p))) {
+                do {
                         seatname = udev_device_get_property_value(p, "ID_SEAT");
                         if (seatname)
                                 break;
-                }
+                } while ((p = udev_device_get_parent(p)));
 
                 seat = sysview_find_seat(c, seatname ? : "seat0");
                 if (!seat)
@@ -910,7 +981,7 @@ static int context_ud_hotplug(sysview_context *c, struct udev_device *d) {
                         return r;
                 }
 
-                return context_add_device(c, device);
+                context_add_device(c, device);
         }
 
         return 0;
@@ -1037,7 +1108,8 @@ static int context_ld_seat_new(sysview_context *c, sd_bus_message *signal) {
                 return r;
         }
 
-        return context_add_seat(c, id);
+        context_add_seat(c, id);
+        return 0;
 }
 
 static int context_ld_seat_removed(sysview_context *c, sd_bus_message *signal) {
@@ -1056,7 +1128,8 @@ static int context_ld_seat_removed(sysview_context *c, sd_bus_message *signal) {
         if (!seat)
                 return 0;
 
-        return context_remove_seat(c, seat);
+        context_remove_seat(c, seat);
+        return 0;
 }
 
 static int context_ld_session_new(sysview_context *c, sd_bus_message *signal) {
@@ -1103,14 +1176,13 @@ static int context_ld_session_new(sysview_context *c, sd_bus_message *signal) {
         }
 
         r = context_raise_session_filter(c, id, seatid, username, uid);
-        if (r <= 0) {
-                if (r < 0)
-                        log_debug("sysview: cannot filter new session '%s' on seat '%s': %s",
-                                  id, seatid, strerror(-r));
-                return r;
-        }
+        if (r < 0)
+                log_debug("sysview: callback failed while filtering session '%s': %s",
+                          id, strerror(-r));
+        else if (r > 0)
+                context_add_session(c, seat, id);
 
-        return context_add_session(c, seat, id);
+        return 0;
 
 error:
         log_debug("sysview: failed retrieving information for new session '%s': %s",
@@ -1134,7 +1206,8 @@ static int context_ld_session_removed(sysview_context *c, sd_bus_message *signal
         if (!session)
                 return 0;
 
-        return context_remove_session(c, session);
+        context_remove_session(c, session);
+        return 0;
 }
 
 static int context_ld_manager_signal_fn(sd_bus *bus,
@@ -1209,9 +1282,7 @@ static int context_ld_list_seats_fn(sd_bus *bus,
                 if (r < 0)
                         goto error;
 
-                r = context_add_seat(c, id);
-                if (r != 0)
-                        return r;
+                context_add_seat(c, id);
 
                 r = sd_bus_message_exit_container(reply);
                 if (r < 0)
@@ -1272,15 +1343,11 @@ static int context_ld_list_sessions_fn(sd_bus *bus,
                 seat = sysview_find_seat(c, seatid);
                 if (seat) {
                         r = context_raise_session_filter(c, id, seatid, username, uid);
-                        if (r < 0) {
-                                log_debug("sysview: cannot filter listed session '%s' on seat '%s': %s",
-                                          id, seatid, strerror(-r));
-                                return r;
-                        } else if (r > 0) {
-                                r = context_add_session(c, seat, id);
-                                if (r != 0)
-                                        return r;
-                        }
+                        if (r < 0)
+                                log_debug("sysview: callback failed while filtering session '%s': %s",
+                                          id, strerror(-r));
+                        else if (r > 0)
+                                context_add_session(c, seat, id);
                 }
 
                 r = sd_bus_message_exit_container(reply);
@@ -1404,20 +1471,6 @@ void sysview_context_stop(sysview_context *c) {
 
         log_debug("sysview: stop");
 
-        c->running = false;
-        c->scanned = false;
-        c->event_fn = NULL;
-        c->userdata = NULL;
-        c->scan_src = sd_event_source_unref(c->scan_src);
-        context_ud_stop(c);
-        context_ld_stop(c);
-
-        /*
-         * Event-callbacks are already cleared, hence we can safely ignore
-         * return codes of the context_remove_*() helpers. They cannot be
-         * originated from user-callbacks, so we already handled them.
-         */
-
         while ((device = hashmap_first(c->device_map)))
                 context_remove_device(c, device);
 
@@ -1426,6 +1479,14 @@ void sysview_context_stop(sysview_context *c) {
 
         while ((seat = hashmap_first(c->seat_map)))
                 context_remove_seat(c, seat);
+
+        c->running = false;
+        c->scanned = false;
+        c->event_fn = NULL;
+        c->userdata = NULL;
+        c->scan_src = sd_event_source_unref(c->scan_src);
+        context_ud_stop(c);
+        context_ld_stop(c);
 }
 
 static int context_scan_fn(sd_event_source *s, void *userdata) {