1 // Copyright 2022 Garrett D'Amore 2 // 3 // Distributed under the Boost Software License, Version 1.0. 4 // (See accompanying file LICENSE or https://www.boost.org/LICENSE_1_0.txt) 5 6 module dcell.evqueue; 7 8 import core.sync.condition; 9 import core.sync.mutex; 10 import core.time; 11 import std.concurrency; 12 13 import dcell.event; 14 15 package class EventQueue 16 { 17 this() 18 { 19 mx = new Mutex(); 20 cv = new Condition(mx); 21 } 22 23 Event receive(this Q)(Duration dur) 24 if (is(Q == EventQueue) || is(Q == shared EventQueue)) 25 { 26 Event ev; 27 synchronized (mx) 28 { 29 while ((q.length == 0) && !closed) 30 { 31 if (!cv.wait(dur)) 32 { 33 return (ev); 34 } 35 } 36 37 if (closed) 38 { 39 return Event(EventType.closed); 40 } 41 ev = q[0]; 42 q = q[1 .. $]; 43 } 44 45 return ev; 46 } 47 48 Event receive(this Q)() if (is(Q == EventQueue) || is(Q == shared EventQueue)) 49 { 50 Event ev; 51 synchronized (mx) 52 { 53 while ((q.length == 0) && !closed) 54 { 55 cv.wait(); 56 } 57 if (closed) 58 { 59 return Event(EventType.closed); 60 } 61 62 ev = q[0]; 63 q = q[1 .. $]; 64 } 65 66 return ev; 67 } 68 69 void close(this Q)() if (is(Q == EventQueue) || is(Q == shared EventQueue)) 70 { 71 synchronized (mx) 72 { 73 closed = true; 74 cv.notifyAll(); 75 } 76 } 77 78 void send(this Q)(Event ev) if (is(Q == EventQueue) || is(Q == shared EventQueue)) 79 { 80 synchronized (mx) 81 { 82 if (!closed) // cannot send any more events after close 83 { 84 q ~= ev; 85 cv.notify(); 86 } 87 } 88 } 89 90 private: 91 92 Mutex mx; 93 Condition cv; 94 Event[] q; 95 bool closed; 96 } 97 98 unittest 99 { 100 import core.thread; 101 auto eq = new EventQueue(); 102 103 eq.send(Event(EventType.key)); 104 assert(eq.receive().type == EventType.key); 105 106 assert(eq.receive(msecs(10)).type == EventType.none); 107 108 spawn(function(shared EventQueue eq){ 109 Thread.sleep(msecs(50)); 110 eq.send(Event(EventType.mouse)); 111 }, cast(shared EventQueue)eq); 112 assert(eq.receive().type == EventType.mouse); 113 eq.close(); 114 assert(eq.receive().type == EventType.closed); 115 }