- (when (event-availablep notify)
- (read-event notify)))
-
-(defmacro! do-events ((var o!notify) &body body)
- "Loops BODY with VAR bound to the events retrieved from NOTIFY. The macro
-uses NEXT-EVENT, so that reading an event won't block."
- `(loop as ,var = (next-event ,g!notify)
- while ,var
- do (progn ,.body)))
-
-(defun next-events (notify)
- "Reads all available events from the queue. Returns a list of events."
- (let (result)
- (do-events (event notify)
- (push event result))
- (nreverse result)))
+ (when (event-available-p inotify)
+ (read-event inotify)))
+
+(defmacro do-events ((var inotify &key blocking-p) &body body)
+ "Loops BODY with VAR bound to the next events retrieved from INOTIFY.
+The macro uses NEXT-EVENT, so reading an event won't block and the loop
+terminates if no events are available. If BLOCKING-P is set, the loop
+blocks if no events are available, otherwise it exits as soon as no
+events were encountered."
+ (check-type var symbol)
+ (let ((inotify-sym (gensym)))
+ `(loop
+ with ,var and ,inotify-sym = ,inotify
+ ,.(unless blocking-p
+ `(while (event-available-p ,inotify-sym)))
+ do (progn
+ (setf ,var (read-event ,inotify-sym))
+ ,@body))))
+
+(defun next-events (inotify)
+ "Reads all available events from the queue. Returns a LIST of events."
+ (loop
+ while (event-available-p inotify)
+ collect (read-event inotify)))
+
+;;; this has the longer name, because this way you actually have to read
+;;; about the differences, at least i hope so
+(defmacro with-unregistered-inotify ((inotify &optional (nonblocking T) &rest rest) &body body)
+ "Like WITH-INOTIFY, but uses MAKE-UNREGISTERED-INOTIFY and WATCH-RAW
+instead. Useful if you need to monitor just a fixed set of paths."
+ `(let ((,inotify (make-unregistered-inotify ,nonblocking)))
+ (unwind-protect
+ (progn
+ ,.(mapcar (lambda (specifier)
+ `(watch-raw ,inotify ,@specifier))
+ rest)
+ (values)
+ ,@body)
+ (close-inotify ,inotify))))
+
+(defmacro with-inotify ((inotify &optional (nonblocking T) &rest rest) &body body)
+ "Executes BODY with a newly created queue bound to INOTIFY if true.
+See MAKE-INOTIFY for more information about possible arguments.
+
+The REST is a list of argument forms for the WATCH function, i.e. one or
+more forms (PATHNAME FLAGS &KEY (REPLACE-P T)).
+
+Since the QUEUE is closed on unwinding, this macro doesn't bother with
+UNWATCH calls on all WATCHed paths."
+ `(let ((,inotify (make-inotify ,nonblocking)))
+ (unwind-protect
+ (progn
+ ,.(mapcar (lambda (specifier)
+ `(watch ,inotify ,@specifier))
+ rest)
+ (values)
+ ,@body)
+ (close-inotify ,inotify))))