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