1 // Copyright © 2017-2021 Rémi Thebault 2 module wayland.server.core; 3 4 import wayland.server.protocol : WlDisplay, WlShm; 5 import wayland.server.eventloop; 6 import wayland.server.listener; 7 import wayland.native.server; 8 import wayland.native.util; 9 import wayland.util; 10 11 import std..string; 12 import std.stdio; 13 import std.exception : enforce; 14 import core.sys.posix.sys.types; 15 16 17 enum : uint 18 { 19 WL_EVENT_READABLE = 0x01, 20 WL_EVENT_WRITABLE = 0x02, 21 WL_EVENT_HANGUP = 0x04, 22 WL_EVENT_ERROR = 0x08 23 } 24 25 26 class WlDisplayBase : Native!wl_display 27 { 28 mixin nativeImpl!(wl_display); 29 30 alias DestroySig = Signal!(); 31 alias ClientCreatedSig = Signal!(WlClient); 32 33 private wl_listener _destroyListener; 34 private DestroySig _destroySig; 35 36 private wl_listener _clientCreatedListener; 37 private ClientCreatedSig _clientCreatedSig; 38 39 // one loop per display, so no need to use the object store 40 private WlEventLoop _loop; 41 42 private WlClient[] _clients; 43 44 45 static WlDisplay create() 46 { 47 return new WlDisplay(wl_display_create()); 48 } 49 50 protected this (wl_display* native) 51 { 52 _native = native; 53 ObjectCache.set(native, this); 54 55 wl_list_init(&_destroyListener.link); 56 _destroyListener.notify = &wl_d_display_destroy; 57 wl_display_add_destroy_listener(native, &_destroyListener); 58 59 wl_list_init(&_clientCreatedListener.link); 60 _clientCreatedListener.notify = &wl_d_client_created; 61 wl_display_add_client_created_listener(native, &_clientCreatedListener); 62 } 63 64 void destroy() 65 { 66 wl_display_destroy(native); 67 } 68 69 private DestroySig destroySig() 70 { 71 if (!_destroySig) _destroySig = new DestroySig(); 72 return _destroySig; 73 } 74 75 private ClientCreatedSig clientCreatedSig() 76 { 77 if (!_clientCreatedSig) _clientCreatedSig = new ClientCreatedSig(); 78 return _clientCreatedSig; 79 } 80 81 void addDestroyListener(DestroySig.Listener listener) 82 { 83 destroySig.add(listener); 84 } 85 86 void addClientCreatedListener(ClientCreatedSig.Listener listener) 87 { 88 clientCreatedSig.add(listener); 89 } 90 91 @property WlEventLoop eventLoop() 92 { 93 if (!_loop) _loop = new WlEventLoop(wl_display_get_event_loop(native)); 94 return _loop; 95 } 96 97 int addSocket(string name) 98 { 99 return wl_display_add_socket(native, toStringz(name)); 100 } 101 102 string addSocketAuto() 103 { 104 return fromStringz(wl_display_add_socket_auto(native)).idup; 105 } 106 107 int addSocketFd(int fd) 108 { 109 return wl_display_add_socket_fd(native, fd); 110 } 111 112 void terminate() 113 { 114 wl_display_terminate(native); 115 } 116 117 void run() 118 { 119 wl_display_run(native); 120 } 121 122 void flushClients() 123 { 124 wl_display_flush_clients(native); 125 } 126 127 @property uint serial() 128 { 129 return wl_display_get_serial(native); 130 } 131 132 uint nextSerial() 133 { 134 return wl_display_next_serial(native); 135 } 136 137 WlClient createClient(int fd) 138 { 139 auto natCl = wl_client_create(native, fd); 140 WlClient cl = cast(WlClient)ObjectCache.get(natCl); 141 assert(cl, "could not retrieve client from obj cache"); 142 return cl; 143 } 144 145 @property WlClient[] clients() 146 { 147 return _clients; 148 } 149 150 void initShm() 151 { 152 wl_display_init_shm(native); 153 } 154 155 void addShmFormat(WlShm.Format format) 156 { 157 wl_display_add_shm_format(native, cast(uint)format); 158 } 159 } 160 161 162 abstract class WlGlobal : Native!wl_global 163 { 164 mixin nativeImpl!wl_global; 165 166 this (wl_global* native) 167 { 168 _native = native; 169 ObjectCache.set(native, this); 170 } 171 172 void destroy() 173 { 174 wl_global_destroy(_native); 175 } 176 } 177 178 179 struct Credentials 180 { 181 pid_t pid; 182 uid_t uid; 183 gid_t gid; 184 } 185 186 final class WlClient : Native!wl_client 187 { 188 mixin nativeImpl!wl_client; 189 190 alias DestroySig = Signal!(WlClient); 191 alias NativeResourceCreatedSig = Signal!(wl_resource*); 192 193 private wl_listener _destroyListener; 194 private DestroySig _destroySig; 195 196 private wl_listener _resourceCreatedListener; 197 private NativeResourceCreatedSig _nativeResourceCreatedSig; 198 199 this (wl_client* native) 200 { 201 _native = native; 202 ObjectCache.set(native, this); 203 204 wl_list_init(&_destroyListener.link); 205 _destroyListener.notify = &wl_d_client_destroy; 206 wl_client_add_destroy_listener(native, &_destroyListener); 207 208 wl_list_init(&_resourceCreatedListener.link); 209 _resourceCreatedListener.notify = &wl_d_client_resource_created; 210 wl_client_add_resource_created_listener(native, &_resourceCreatedListener); 211 } 212 213 void destroy() 214 { 215 wl_client_destroy(native); 216 } 217 218 private DestroySig destroySig() 219 { 220 if (!_destroySig) _destroySig = new DestroySig(); 221 return _destroySig; 222 } 223 224 private NativeResourceCreatedSig nativeResourceCreatedSig() 225 { 226 if (!_nativeResourceCreatedSig) _nativeResourceCreatedSig = new NativeResourceCreatedSig(); 227 return _nativeResourceCreatedSig; 228 } 229 230 void addDestroyListener(DestroySig.Listener listener) 231 { 232 destroySig.add(listener); 233 } 234 235 void addNativeResourceCreatedListener(NativeResourceCreatedSig.Listener listener) 236 { 237 nativeResourceCreatedSig.add(listener); 238 } 239 240 void flush() 241 { 242 wl_client_flush(native); 243 } 244 245 @property Credentials credentials() 246 { 247 Credentials res; 248 wl_client_get_credentials(native, &res.pid, &res.uid, &res.gid); 249 return res; 250 } 251 252 @property int fd() 253 { 254 return wl_client_get_fd(native); 255 } 256 257 WlResource object(uint id) 258 { 259 auto natRes = wl_client_get_object(native, id); 260 if (!natRes) return null; 261 auto res = cast(WlResource)ObjectCache.get(natRes); 262 assert(res); 263 return res; 264 } 265 266 void postNoMemory() 267 { 268 wl_client_post_no_memory(native); 269 } 270 271 @property WlDisplay display() 272 { 273 auto natDpy = wl_client_get_display(native); 274 assert(natDpy); 275 auto dpy = cast(WlDisplay)ObjectCache.get(natDpy); 276 assert(dpy); 277 return dpy; 278 } 279 } 280 281 abstract class WlResource : Native!wl_resource 282 { 283 mixin nativeImpl!wl_resource; 284 285 alias DestroySig = Signal!(WlResource); 286 287 private wl_listener _destroyListener; 288 private DestroySig _destroySig; 289 290 this (wl_resource* native) 291 { 292 _native = native; 293 ObjectCache.set(native, this); 294 295 wl_list_init(&_destroyListener.link); 296 _destroyListener.notify = &wl_d_resource_destroy; 297 wl_resource_add_destroy_listener(native, &_destroyListener); 298 } 299 300 void destroy() 301 { 302 wl_resource_destroy(native); 303 } 304 305 private DestroySig destroySig() 306 { 307 if (!_destroySig) _destroySig = new DestroySig(); 308 return _destroySig; 309 } 310 311 void addDestroyListener(DestroySig.Listener listener) 312 { 313 destroySig.add(listener); 314 } 315 316 @property uint id() 317 { 318 return wl_resource_get_id(native); 319 } 320 321 @property WlClient client() 322 { 323 auto natCl = wl_resource_get_client(native); 324 assert(natCl); 325 auto cl = cast(WlClient)ObjectCache.get(natCl); 326 assert(cl); 327 return cl; 328 } 329 330 @property int ver() 331 { 332 return wl_resource_get_version(native); 333 } 334 335 @property string cls() 336 { 337 return fromStringz(wl_resource_get_class(native)).idup; 338 } 339 340 void postError(Args...)(uint code, string fmt, Args args) 341 { 342 wl_resource_post_error(native, code, toStringz(format(fmt, args))); 343 } 344 } 345 346 private extern(C) nothrow 347 { 348 void wl_d_display_destroy(wl_listener*, void* data) 349 { 350 nothrowFnWrapper!({ 351 auto dpy = cast(WlDisplayBase)ObjectCache.get(data); 352 assert(dpy, "wl_d_display_destroy: could not get display from cache"); 353 if (dpy._destroySig) dpy._destroySig.emit(); 354 ObjectCache.remove(data); 355 }); 356 } 357 358 void wl_d_client_created(wl_listener*, void* data) 359 { 360 nothrowFnWrapper!({ 361 auto natCl = cast(wl_client*)data; 362 auto natDpy = wl_client_get_display(natCl); 363 auto dpy = cast(WlDisplayBase)ObjectCache.get(natDpy); 364 assert(dpy, "wl_d_client_created: could not get display from cache"); 365 366 auto cl = new WlClient(natCl); 367 dpy._clients ~= cl; 368 if (dpy._clientCreatedSig) dpy._clientCreatedSig.emit(cl); 369 }); 370 } 371 372 void wl_d_client_destroy(wl_listener*, void* data) 373 { 374 nothrowFnWrapper!({ 375 auto natCl = cast(wl_client*)data; 376 auto natDpy = wl_client_get_display(natCl); 377 auto dpy = cast(WlDisplayBase)ObjectCache.get(natDpy); 378 assert(dpy, "wl_d_client_destroy: could not get display from cache"); 379 WlClient cl = cast(WlClient)ObjectCache.get(natCl); 380 assert(cl, "wl_d_client_destroy: could not get client from cache"); 381 382 import std.algorithm : remove; 383 if (cl._destroySig) cl._destroySig.emit(cl); 384 dpy._clients = dpy._clients.remove!(c => c is cl); 385 ObjectCache.remove(natCl); 386 }); 387 } 388 389 void wl_d_client_resource_created(wl_listener*, void* data) 390 { 391 nothrowFnWrapper!({ 392 auto natRes = cast(wl_resource*)data; 393 auto natCl = wl_resource_get_client(natRes); 394 auto cl = cast(WlClient)ObjectCache.get(natCl); 395 assert(cl); 396 if (cl._nativeResourceCreatedSig) cl._nativeResourceCreatedSig.emit(natRes); 397 }); 398 } 399 400 void wl_d_resource_destroy(wl_listener*, void* data) 401 { 402 nothrowFnWrapper!({ 403 auto natRes = cast(wl_resource*)data; 404 405 auto res = cast(WlResource)ObjectCache.get(natRes); 406 if (res && res._destroySig) res._destroySig.emit(res); 407 408 ObjectCache.remove(natRes); 409 }); 410 } 411 }