src/Pure/Concurrent/delay.scala
changeset 71704 b9a5eb0f3b43
child 73367 77ef8bef0593
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Pure/Concurrent/delay.scala	Mon Apr 06 12:53:45 2020 +0200
@@ -0,0 +1,66 @@
+/*  Title:      Pure/Concurrent/delay.scala
+    Author:     Makarius
+
+Delayed events.
+*/
+
+package isabelle
+
+
+object Delay
+{
+  // delayed event after first invocation
+  def first(delay: => Time, log: Logger = No_Logger, gui: Boolean = false)(event: => Unit): Delay =
+    new Delay(true, delay, log, if (gui) GUI_Thread.later { event } else event )
+
+  // delayed event after last invocation
+  def last(delay: => Time, log: Logger = No_Logger, gui: Boolean = false)(event: => Unit): Delay =
+    new Delay(false, delay, log, if (gui) GUI_Thread.later { event } else event )
+}
+
+final class Delay private(first: Boolean, delay: => Time, log: Logger, event: => Unit)
+{
+  private var running: Option[Event_Timer.Request] = None
+
+  private def run: Unit =
+  {
+    val do_run = synchronized {
+      if (running.isDefined) { running = None; true } else false
+    }
+    if (do_run) {
+      try { event }
+      catch { case exn: Throwable if !Exn.is_interrupt(exn) => log(Exn.message(exn)); throw exn }
+    }
+  }
+
+  def invoke(): Unit = synchronized
+  {
+    val new_run =
+      running match {
+        case Some(request) => if (first) false else { request.cancel; true }
+        case None => true
+      }
+    if (new_run)
+      running = Some(Event_Timer.request(Time.now() + delay)(run))
+  }
+
+  def revoke(): Unit = synchronized
+  {
+    running match {
+      case Some(request) => request.cancel; running = None
+      case None =>
+    }
+  }
+
+  def postpone(alt_delay: Time): Unit = synchronized
+  {
+    running match {
+      case Some(request) =>
+        val alt_time = Time.now() + alt_delay
+        if (request.time < alt_time && request.cancel) {
+          running = Some(Event_Timer.request(alt_time)(run))
+        }
+      case None =>
+    }
+  }
+}