chiark / gitweb /
terminal: forward evdev RESYNC events to linked devices
[elogind.git] / src / libsystemd-terminal / idev-evdev.c
index 6509d1011e59e1f5e6738e651240fafad52be6b8..719e18c316e369bbb399bfea06fd1e0f1aeba56e 100644 (file)
@@ -49,6 +49,7 @@ struct idev_evdev {
 
         bool unsync : 1;                /* not in-sync with kernel */
         bool resync : 1;                /* re-syncing with kernel */
+        bool running : 1;
 };
 
 struct unmanaged_evdev {
@@ -101,7 +102,16 @@ static void idev_evdev_name(char *out, dev_t devnum) {
         sprintf(out, "evdev/%u:%u", major(devnum), minor(devnum));
 }
 
-static int idev_evdev_raise(idev_evdev *evdev, struct input_event *event) {
+static int idev_evdev_feed_resync(idev_evdev *evdev) {
+        idev_data data = {
+                .type = IDEV_DATA_RESYNC,
+                .resync = evdev->resync,
+        };
+
+        return idev_element_feed(&evdev->element, &data);
+}
+
+static int idev_evdev_feed_evdev(idev_evdev *evdev, struct input_event *event) {
         idev_data data = {
                 .type = IDEV_DATA_EVDEV,
                 .resync = evdev->resync,
@@ -155,7 +165,6 @@ static int idev_evdev_io(idev_evdev *evdev) {
          * case we cannot keep up with the kernel.
          * TODO: Make sure libevdev always reports SYN_DROPPED to us, regardless
          * whether any event was synced afterwards.
-         * TODO: Forward SYN_DROPPED to attached devices.
          */
 
         flags = LIBEVDEV_READ_FLAG_NORMAL;
@@ -190,7 +199,7 @@ static int idev_evdev_io(idev_evdev *evdev) {
                 } else if (r == LIBEVDEV_READ_STATUS_SYNC) {
                         if (evdev->resync) {
                                 /* sync-event */
-                                r = idev_evdev_raise(evdev, &ev);
+                                r = idev_evdev_feed_evdev(evdev, &ev);
                                 if (r != 0) {
                                         error = r;
                                         break;
@@ -199,10 +208,15 @@ static int idev_evdev_io(idev_evdev *evdev) {
                                 /* start of sync */
                                 evdev->resync = true;
                                 flags = LIBEVDEV_READ_FLAG_SYNC;
+                                r = idev_evdev_feed_resync(evdev);
+                                if (r != 0) {
+                                        error = r;
+                                        break;
+                                }
                         }
                 } else {
                         /* normal event */
-                        r = idev_evdev_raise(evdev, &ev);
+                        r = idev_evdev_feed_evdev(evdev, &ev);
                         if (r != 0) {
                                 error = r;
                                 break;
@@ -268,6 +282,12 @@ static void idev_evdev_enable(idev_evdev *evdev) {
         assert(evdev->fd_src);
         assert(evdev->idle_src);
 
+        if (evdev->running)
+                return;
+        if (evdev->fd < 0 || evdev->element.n_open < 1 || !evdev->element.enabled)
+                return;
+
+        evdev->running = true;
         sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_ON);
         sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_ONESHOT);
 }
@@ -277,6 +297,11 @@ static void idev_evdev_disable(idev_evdev *evdev) {
         assert(evdev->fd_src);
         assert(evdev->idle_src);
 
+        if (!evdev->running)
+                return;
+
+        evdev->running = false;
+        idev_evdev_feed_resync(evdev);
         sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_OFF);
         sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_OFF);
 }
@@ -288,9 +313,7 @@ static int idev_evdev_resume(idev_evdev *evdev, int dev_fd) {
 
         if (fd < 0 || evdev->fd == fd) {
                 fd = -1;
-                if (evdev->fd >= 0 && e->n_open > 0 && e->enabled)
-                        idev_evdev_enable(evdev);
-
+                idev_evdev_enable(evdev);
                 return 0;
         }
 
@@ -314,11 +337,7 @@ static int idev_evdev_resume(idev_evdev *evdev, int dev_fd) {
                 return -EACCES;
 
         evdev->element.readable = true;
-        evdev->element.writable = true;
-        if (flags == O_RDONLY)
-                evdev->element.writable = false;
-        else if (flags == O_WRONLY)
-                evdev->element.readable = false;
+        evdev->element.writable = !(flags & O_RDONLY);
 
         /*
          * TODO: We *MUST* re-sync the device so we get a delta of the changed
@@ -355,15 +374,14 @@ static int idev_evdev_resume(idev_evdev *evdev, int dev_fd) {
                 return r;
         }
 
-        if (e->n_open < 1 || !e->enabled) {
-                sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_OFF);
-                sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_OFF);
-        }
+        sd_event_source_set_enabled(evdev->fd_src, SD_EVENT_OFF);
+        sd_event_source_set_enabled(evdev->idle_src, SD_EVENT_OFF);
 
         evdev->unsync = true;
         evdev->fd = fd;
-
         fd = -1;
+
+        idev_evdev_enable(evdev);
         return 0;
 }
 
@@ -375,12 +393,11 @@ static void idev_evdev_pause(idev_evdev *evdev, bool release) {
 
         log_debug("idev-evdev: %s/%s: pause", e->session->name, e->name);
 
+        idev_evdev_disable(evdev);
         if (release) {
                 evdev->idle_src = sd_event_source_unref(evdev->idle_src);
                 evdev->fd_src = sd_event_source_unref(evdev->fd_src);
                 evdev->fd = safe_close(evdev->fd);
-        } else {
-                idev_evdev_disable(evdev);
         }
 }