anchor.diff:                   (>= *idle-time* *screensaver-time*))
           (ignore-errors
             (funcall *screensaver-spawn-function*)))))
  -  ;; Redisplay only when the system framebuffer changes or when there's
  -  ;; nonempty clip rect.
  -  (when (or (not (eql *main-screen* (mezzano.supervisor:current-framebuffer)))
  -            (and (not (zerop *clip-rect-width*))
  -                 (not (zerop *clip-rect-height*)))
  -            (not (eql *prev-postprocess-matrix* *postprocess-matrix*)))
  -    (submit-compositor-event (make-instance 'redisplay-time-event))))
  -
  -(defun compositor-heartbeat-thread ()
  -  (loop (compositor-heartbeat-thread-body)))
  +  (when (or *redisplay-pending*
  +            (and (screen-dirty-p)
  +                 (>= (- (get-internal-run-time) *last-frame-timestamp*)
  +                     (* *compositor-update-interval* internal-time-units-per-second))))
  +    (setf *last-frame-timestamp* (get-internal-run-time))
  +    (recompose-windows (eql *redisplay-pending* :full))
  +    (setf *redisplay-pending* nil))
  +  (cond ((screen-dirty-p)
  +         ;; Only bother arming the frame timer if there's outstanding stuff to draw.
  +         (mezzano.supervisor:with-timer (frame-timer
  +                                         ;; Use an absolute time since the last frame instead of a
  +                                         ;; relative time to try to get a more consistent frame rate.
  +                                         :absolute (+ *last-frame-timestamp*
  +                                                       (truncate
  +                                                        (* *compositor-update-interval* internal-time-units-per-second))))
  +           (mezzano.sync:wait-for-objects frame-timer
  +                                          *event-queue*
  +                                          (mezzano.supervisor:framebuffer-boot-id *main-screen*))))
  +        (t
  +         (mezzano.sync:wait-for-objects *event-queue*
  +                                         (mezzano.supervisor:framebuffer-boot-id *main-screen*)))))
  +
  +(defun compositor-thread ()
  +  (loop (compositor-thread-body)))
   
   (when (not *compositor*)
     (setf *compositor* (mezzano.supervisor:make-thread 'compositor-thread
                                                        :name "Compositor")))
  -
  -(when (not *compositor-heartbeat*)
  -  (setf *compositor-heartbeat* (mezzano.supervisor:make-thread 'compositor-heartbeat-thread
  -                                                               :name "Compositor Heartbeat")))
  
positive.code: 
  (defvar *redisplay-pending* nil)
  
  (defclass redisplay-time-event (event)
    ((%fullp :initarg :full :reader redisplay-time-event-fullp))
    (:default-initargs :full nil))
  
  (defmethod process-event ((event redisplay-time-event))
    (when (not (eql *redisplay-pending* :full))
      (setf *redisplay-pending* (if (redisplay-time-event-fullp event) :full t))))
  
  (defun force-redisplay (&optional full)
    (submit-compositor-event (make-instance 'redisplay-time-event :full full)))
  
  ;;;; Notifications.
  
  
negative.code:           *screen-backbuffer* (mezzano.gui:make-surface
                                 (mezzano.supervisor:framebuffer-width *main-screen*)
                                 (mezzano.supervisor:framebuffer-height *main-screen*)))
      (setf *redisplay-pending* :full)
      (broadcast-notification :screen-geometry
                              (make-instance 'screen-geometry-update
                                             :width (mezzano.supervisor:framebuffer-width *main-screen*)
  