1 // Copyright © 2017-2021 Rémi Thebault
2 module wayland.server.eventloop;
3 
4 import wayland.native.server;
5 import wayland.native.util;
6 import wayland.util;
7 
8 class WlEventLoop : Native!wl_event_loop
9 {
10     mixin nativeImpl!(wl_event_loop);
11 
12     alias DestroyDg = void delegate(WlEventLoop loop);
13     alias FdDg = int delegate (int fd, uint mask);
14     alias TimerDg = int delegate ();
15     alias SignalDg = int delegate (int sigNum);
16     alias IdleDg = void delegate ();
17 
18     private wl_listener _destroyListener;
19     private DestroyDg _onDestroy;
20 
21     this (wl_event_loop* native)
22     {
23         _native = native;
24         ObjectCache.set(native, this);
25 
26         wl_list_init(&_destroyListener.link);
27         _destroyListener.notify = &wl_d_eventloop_destroy;
28         wl_event_loop_add_destroy_listener(native, &_destroyListener);
29     }
30 
31     this()
32     {
33         this(wl_event_loop_create());
34     }
35 
36     void destroy()
37     {
38         wl_event_loop_destroy(_native);
39     }
40 
41     @property void destroyListener(DestroyDg dg)
42     {
43         _onDestroy = dg;
44     }
45 
46     @property int fd()
47     {
48         return wl_event_loop_get_fd(native);
49     }
50 
51     int dispatch(int timeout)
52     {
53         return wl_event_loop_dispatch(native, timeout);
54     }
55 
56     void dispatchIdle()
57     {
58         wl_event_loop_dispatch_idle(native);
59     }
60 
61     WlFdEventSource addFd(int fd, uint mask, FdDg dg)
62     {
63         return new WlFdEventSource(native, fd, mask, dg);
64     }
65 
66     WlTimerEventSource addTimer(TimerDg dg)
67     {
68         return new WlTimerEventSource(native, dg);
69     }
70 
71     WlSignalEventSource addSignal(int signalNum, SignalDg dg)
72     {
73         return new WlSignalEventSource(native, signalNum, dg);
74     }
75 
76     WlIdleEventSource addIdle(IdleDg dg)
77     {
78         return new WlIdleEventSource(native, dg);
79     }
80 }
81 
82 abstract class WlEventSource : Native!wl_event_source
83 {
84     mixin nativeImpl!(wl_event_source);
85 
86     this(wl_event_source* native)
87     {
88         _native = native;
89     }
90 
91     int remove ()
92     {
93         return wl_event_source_remove(native);
94     }
95 
96     void check()
97     {
98         wl_event_source_check(native);
99     }
100 }
101 
102 class WlFdEventSource : WlEventSource
103 {
104     private WlEventLoop.FdDg dg;
105 
106     this (wl_event_loop* nativeLoop, int fd, uint mask, WlEventLoop.FdDg dg)
107     {
108         this.dg = dg;
109         super(wl_event_loop_add_fd(
110             nativeLoop, fd, mask, &wl_d_eventloop_fd, cast(void*)this
111         ));
112     }
113 
114     int update(uint mask)
115     {
116         return wl_event_source_fd_update(native, mask);
117     }
118 }
119 
120 class WlTimerEventSource : WlEventSource
121 {
122     private WlEventLoop.TimerDg dg;
123 
124     this (wl_event_loop* nativeLoop, WlEventLoop.TimerDg dg)
125     {
126         this.dg = dg;
127         super(wl_event_loop_add_timer(
128             nativeLoop, &wl_d_eventloop_timer, cast(void*)this
129         ));
130     }
131 
132     int update(uint msDelay)
133     {
134         return wl_event_source_timer_update(native, msDelay);
135     }
136 }
137 
138 class WlSignalEventSource : WlEventSource
139 {
140     private WlEventLoop.SignalDg dg;
141 
142     this (wl_event_loop* nativeLoop, int signalNum, WlEventLoop.SignalDg dg)
143     {
144         this.dg = dg;
145         super(wl_event_loop_add_signal(
146             nativeLoop, signalNum, &wl_d_eventloop_signal, cast(void*)this
147         ));
148     }
149 }
150 
151 class WlIdleEventSource : WlEventSource
152 {
153     private WlEventLoop.IdleDg dg;
154 
155     this (wl_event_loop* nativeLoop, WlEventLoop.IdleDg dg)
156     {
157         this.dg = dg;
158         super(wl_event_loop_add_idle(
159             nativeLoop, &wl_d_eventloop_idle, cast(void*)this
160         ));
161     }
162 }
163 
164 
165 private extern(C) nothrow
166 {
167 
168     void wl_d_eventloop_destroy(wl_listener*, void* data)
169     {
170         nothrowFnWrapper!({
171             auto el = cast(WlEventLoop)ObjectCache.get(data);
172             assert(el, "wl_d_eventloop_destroy: could not get event loop from cache");
173             if (el._onDestroy) el._onDestroy(el);
174             ObjectCache.remove(data);
175         });
176     }
177 
178     int wl_d_eventloop_fd(int fd, uint mask, void* data)
179     {
180         return nothrowFnWrapper!({
181             auto src = cast(WlFdEventSource)data;
182             return src.dg(fd, mask);
183         });
184     }
185 
186     int wl_d_eventloop_timer(void* data)
187     {
188         return nothrowFnWrapper!({
189             auto src = cast(WlTimerEventSource)data;
190             return src.dg();
191         });
192     }
193 
194     int wl_d_eventloop_signal(int sigNumber, void* data)
195     {
196         return nothrowFnWrapper!({
197             auto src = cast(WlSignalEventSource)data;
198             return src.dg(sigNumber);
199         });
200     }
201 
202     void wl_d_eventloop_idle(void* data)
203     {
204         nothrowFnWrapper!({
205             auto src = cast(WlIdleEventSource)data;
206             src.dg();
207         });
208     }
209 }