stevee

My wayland statusbar
git clone git://gtms.dev/stevee
Log | Files | Refs | README | LICENSE

wayland_server_core.zig (24520B)


      1 pub const Object = common.Object;
      2 pub const Message = common.Message;
      3 pub const Interface = common.Interface;
      4 pub const list = common.list;
      5 pub const Array = common.Array;
      6 pub const Fixed = common.Fixed;
      7 pub const Argument = common.Argument;
      8 
      9 /// This is wayland-server's wl_display. It has been renamed as zig-wayland has
     10 /// decided to hide wl_resources with opaque pointers in the same way that
     11 /// wayland-client does with wl_proxys. This of course creates a name conflict.
     12 pub const Server = opaque {
     13     extern fn wl_display_create() ?*Server;
     14     pub fn create() !*Server {
     15         return wl_display_create() orelse error.ServerCreateFailed;
     16     }
     17 
     18     extern fn wl_display_destroy(server: *Server) void;
     19     pub const destroy = wl_display_destroy;
     20 
     21     extern fn wl_display_get_event_loop(server: *Server) *EventLoop;
     22     pub const getEventLoop = wl_display_get_event_loop;
     23 
     24     extern fn wl_display_add_socket(server: *Server, name: [*:0]const u8) c_int;
     25     pub fn addSocket(_server: *Server, name: [*:0]const u8) !void {
     26         if (wl_display_add_socket(_server, name) == -1)
     27             return error.AddSocketFailed;
     28     }
     29 
     30     // wayland-client will connect to wayland-0 even if WAYLAND_DISPLAY is
     31     // unset due to an unfortunate piece of code that was not removed before
     32     // the library was stabilized. Because of this, it is a good idea to never
     33     // call the socket wayland-0. So, instead of binding to wayland-server's
     34     // wl_display_add_socket_auto we implement a version which skips wayland-0.
     35     pub fn addSocketAuto(_server: *Server, buf: *[11]u8) ![:0]const u8 {
     36         // Don't use wayland-0
     37         var i: u32 = 1;
     38         while (i <= 32) : (i += 1) {
     39             const name = std.fmt.bufPrintZ(buf, "wayland-{}", .{i}) catch unreachable;
     40             _server.addSocket(name.ptr) catch continue;
     41             return name;
     42         }
     43         return error.AddSocketFailed;
     44     }
     45 
     46     extern fn wl_display_add_socket_fd(_server: *Server, sock_fd: c_int) c_int;
     47     pub fn addSocketFd(_server: *Server, sock_fd: c_int) !void {
     48         if (wl_display_add_socket_fd(_server, sock_fd) == -1)
     49             return error.AddSocketFailed;
     50     }
     51 
     52     extern fn wl_display_terminate(_server: *Server) void;
     53     pub const terminate = wl_display_terminate;
     54 
     55     extern fn wl_display_run(_server: *Server) void;
     56     pub const run = wl_display_run;
     57 
     58     extern fn wl_display_flush_clients(_server: *Server) void;
     59     pub const flushClients = wl_display_flush_clients;
     60 
     61     extern fn wl_display_destroy_clients(_server: *Server) void;
     62     pub const destroyClients = wl_display_destroy_clients;
     63 
     64     extern fn wl_display_get_serial(_server: *Server) u32;
     65     pub const getSerial = wl_display_get_serial;
     66 
     67     extern fn wl_display_next_serial(_server: *Server) u32;
     68     pub const nextSerial = wl_display_next_serial;
     69 
     70     extern fn wl_display_add_destroy_listener(_server: *Server, listener: *Listener(*Server)) void;
     71     pub const addDestroyListener = wl_display_add_destroy_listener;
     72 
     73     extern fn wl_display_add_client_created_listener(_server: *Server, listener: *Listener(*Client)) void;
     74     pub const addClientCreatedListener = wl_display_add_client_created_listener;
     75 
     76     // Doesn't really make sense with our Listener API as we would need to
     77     // pass a pointer to the wrapper function
     78     //extern fn wl_display_get_destroy_listener(_server: *Server, notify: @TypeOf(Listener(*Server).notify)) ?*Listener(*Server);
     79 
     80     extern fn wl_display_set_global_filter(
     81         _server: *Server,
     82         filter: *const fn (_client: *const Client, global: *const Global, data: ?*anyopaque) callconv(.C) bool,
     83         data: ?*anyopaque,
     84     ) void;
     85     pub inline fn setGlobalFilter(
     86         _server: *Server,
     87         comptime T: type,
     88         comptime filter: fn (_client: *const Client, global: *const Global, data: T) bool,
     89         data: T,
     90     ) void {
     91         wl_display_set_global_filter(
     92             _server,
     93             struct {
     94                 fn _wrapper(_client: *const Client, _global: *const Global, _data: ?*anyopaque) callconv(.C) bool {
     95                     return filter(_client, _global, @ptrCast(@alignCast(_data)));
     96                 }
     97             }._wrapper,
     98             data,
     99         );
    100     }
    101 
    102     extern fn wl_display_get_client_list(_server: *Server) *list.Head(Client, null);
    103     pub const getClientList = wl_display_get_client_list;
    104 
    105     extern fn wl_display_init_shm(_server: *Server) c_int;
    106     pub fn initShm(_server: *Server) !void {
    107         if (wl_display_init_shm(_server) == -1) return error.OutOfMemory;
    108     }
    109 
    110     extern fn wl_display_add_shm_format(_server: *Server, format: u32) ?*u32;
    111     pub fn addShmFormat(_server: *Server, format: u32) !*u32 {
    112         return wl_display_add_shm_format(_server, format) orelse error.OutOfMemory;
    113     }
    114 
    115     extern fn wl_display_add_protocol_logger(
    116         _server: *Server,
    117         func: *const fn (data: ?*anyopaque, direction: ProtocolLogger.Type, message: *const ProtocolLogger.LogMessage) callconv(.C) void,
    118         data: ?*anyopaque,
    119     ) void;
    120     pub inline fn addProtocolLogger(
    121         _server: *Server,
    122         comptime T: type,
    123         comptime func: fn (data: T, direction: ProtocolLogger.Type, message: *const ProtocolLogger.LogMessage) void,
    124         data: T,
    125     ) void {
    126         wl_display_add_protocol_logger(
    127             _server,
    128             struct {
    129                 fn _wrapper(_data: ?*anyopaque, _direction: ProtocolLogger.Type, _message: *const ProtocolLogger.LogMessage) callconv(.C) void {
    130                     func(@ptrCast(@alignCast(_data)), _direction, _message);
    131                 }
    132             }._wrapper,
    133             data,
    134         );
    135     }
    136 };
    137 
    138 pub const Client = opaque {
    139     extern fn wl_client_create(_server: *Server, fd: c_int) ?*Client;
    140     pub const create = wl_client_create;
    141 
    142     extern fn wl_client_destroy(_client: *Client) void;
    143     pub const destroy = wl_client_destroy;
    144 
    145     extern fn wl_client_flush(_client: *Client) void;
    146     pub const flush = wl_client_flush;
    147 
    148     extern fn wl_client_get_link(_client: *Client) *list.Link;
    149     pub const getLink = wl_client_get_link;
    150 
    151     extern fn wl_client_from_link(link: *list.Link) *Client;
    152     pub const fromLink = wl_client_from_link;
    153 
    154     const Credentials = struct {
    155         pid: posix.pid_t,
    156         gid: posix.gid_t,
    157         uid: posix.uid_t,
    158     };
    159     extern fn wl_client_get_credentials(_client: *Client, pid: *posix.pid_t, uid: *posix.uid_t, gid: *posix.gid_t) void;
    160     pub fn getCredentials(_client: *Client) Credentials {
    161         var credentials: Credentials = undefined;
    162         wl_client_get_credentials(_client, &credentials.pid, &credentials.uid, &credentials.gid);
    163         return credentials;
    164     }
    165 
    166     extern fn wl_client_add_destroy_listener(_client: *Client, listener: *Listener(*Client)) void;
    167     pub const addDestroyListener = wl_client_add_destroy_listener;
    168 
    169     // Doesn't really make sense with our Listener API as we would need to
    170     // pass a pointer to the wrapper function
    171     //extern fn wl_client_get_destroy_listener(_client: *Client, notify: @TypeOf(Listener(*Client).notify)) ?*Listener(*Client);
    172 
    173     extern fn wl_client_get_object(_client: *Client, id: u32) ?*Resource;
    174     pub const getObject = wl_client_get_object;
    175 
    176     extern fn wl_client_post_no_memory(_client: *Client) void;
    177     pub const postNoMemory = wl_client_post_no_memory;
    178 
    179     extern fn wl_client_post_implementation_error(_client: *Client, msg: [*:0]const u8, ...) void;
    180     pub const postImplementationError = wl_client_post_implementation_error;
    181 
    182     extern fn wl_client_add_resource_created_listener(_client: *Client, listener: *Listener(*Resource)) void;
    183     pub const addResourceCreatedListener = wl_client_add_resource_created_listener;
    184 
    185     const IteratorResult = enum(c_int) { stop, cont };
    186     extern fn wl_client_for_each_resource(
    187         _client: *Client,
    188         iterator: *const fn (resource: *Resource, data: ?*anyopaque) callconv(.C) IteratorResult,
    189         data: ?*anyopaque,
    190     ) void;
    191     pub inline fn forEachResource(
    192         _client: *Client,
    193         comptime T: type,
    194         comptime iterator: fn (resource: *Resource, data: T) IteratorResult,
    195         data: T,
    196     ) void {
    197         wl_client_for_each_resource(
    198             _client,
    199             struct {
    200                 fn _wrapper(_resource: *Resource, _data: ?*anyopaque) callconv(.C) IteratorResult {
    201                     return iterator(_resource, @ptrCast(@alignCast(_data)));
    202                 }
    203             }._wrapper,
    204             data,
    205         );
    206     }
    207 
    208     extern fn wl_client_get_fd(_client: *Client) c_int;
    209     pub const getFd = wl_client_get_fd;
    210 
    211     extern fn wl_client_get_display(_client: *Client) *Server;
    212     pub const getDisplay = wl_client_get_display;
    213 };
    214 
    215 pub const Global = opaque {
    216     extern fn wl_global_create(
    217         _server: *Server,
    218         interface: *const Interface,
    219         version: c_int,
    220         data: ?*anyopaque,
    221         bind: *const fn (_client: *Client, data: ?*anyopaque, version: u32, id: u32) callconv(.C) void,
    222     ) ?*Global;
    223     pub inline fn create(
    224         _server: *Server,
    225         comptime T: type,
    226         version: u32,
    227         comptime DataT: type,
    228         data: DataT,
    229         comptime bind: fn (_client: *Client, data: DataT, version: u32, id: u32) void,
    230     ) error{GlobalCreateFailed}!*Global {
    231         return wl_global_create(
    232             _server,
    233             T.interface,
    234             @as(c_int, @intCast(version)),
    235             data,
    236             struct {
    237                 fn _wrapper(_client: *Client, _data: ?*anyopaque, _version: u32, _id: u32) callconv(.C) void {
    238                     bind(_client, @ptrCast(@alignCast(_data)), _version, _id);
    239                 }
    240             }._wrapper,
    241         ) orelse error.GlobalCreateFailed;
    242     }
    243 
    244     extern fn wl_global_remove(global: *Global) void;
    245     pub const remove = wl_global_remove;
    246 
    247     extern fn wl_global_destroy(global: *Global) void;
    248     pub const destroy = wl_global_destroy;
    249 
    250     extern fn wl_global_get_interface(global: *const Global) *const Interface;
    251     pub const getInterface = wl_global_get_interface;
    252 
    253     extern fn wl_global_get_name(global: *const Global, _client: *const Client) u32;
    254     pub const getName = wl_global_get_name;
    255 
    256     extern fn wl_global_get_user_data(global: *const Global) ?*anyopaque;
    257     pub const getUserData = wl_global_get_user_data;
    258 };
    259 
    260 pub const Resource = opaque {
    261     extern fn wl_resource_create(_client: *Client, interface: *const Interface, version: c_int, id: u32) ?*Resource;
    262     pub inline fn create(_client: *Client, comptime T: type, version: u32, id: u32) error{ResourceCreateFailed}!*Resource {
    263         // This is only a c_int because of legacy libwayland reasons. Negative versions are invalid.
    264         // Version is a u32 on the wire and for wl_global, wl_proxy, etc.
    265         return wl_resource_create(_client, T.interface, @as(c_int, @intCast(version)), id) orelse error.ResourceCreateFailed;
    266     }
    267 
    268     extern fn wl_resource_destroy(resource: *Resource) void;
    269     pub const destroy = wl_resource_destroy;
    270 
    271     extern fn wl_resource_post_event_array(resource: *Resource, opcode: u32, args: ?[*]Argument) void;
    272     pub const postEvent = wl_resource_post_event_array;
    273 
    274     extern fn wl_resource_queue_event_array(resource: *Resource, opcode: u32, args: ?[*]Argument) void;
    275     pub const queueEvent = wl_resource_queue_event_array;
    276 
    277     extern fn wl_resource_post_error(resource: *Resource, code: u32, message: [*:0]const u8, ...) void;
    278     pub const postError = wl_resource_post_error;
    279 
    280     extern fn wl_resource_post_no_memory(resource: *Resource) void;
    281     pub const postNoMemory = wl_resource_post_no_memory;
    282 
    283     const DispatcherFn = fn (
    284         implementation: ?*const anyopaque,
    285         resource: *Resource,
    286         opcode: u32,
    287         message: *const Message,
    288         args: [*]Argument,
    289     ) callconv(.C) c_int;
    290     pub const DestroyFn = fn (resource: *Resource) callconv(.C) void;
    291     extern fn wl_resource_set_dispatcher(
    292         resource: *Resource,
    293         dispatcher: ?*const DispatcherFn,
    294         implementation: ?*const anyopaque,
    295         data: ?*anyopaque,
    296         destroy_fn: ?*const DestroyFn,
    297     ) void;
    298     pub fn setDispatcher(
    299         resource: *Resource,
    300         dispatcher: ?*const DispatcherFn,
    301         implementation: ?*const anyopaque,
    302         data: ?*anyopaque,
    303         destroy_fn: ?*const DestroyFn,
    304     ) void {
    305         wl_resource_set_dispatcher(resource, dispatcher, implementation, data, destroy_fn);
    306     }
    307 
    308     extern fn wl_resource_get_user_data(resource: *Resource) ?*anyopaque;
    309     pub const getUserData = wl_resource_get_user_data;
    310 
    311     extern fn wl_resource_get_id(resource: *Resource) u32;
    312     pub const getId = wl_resource_get_id;
    313 
    314     extern fn wl_resource_get_link(resource: *Resource) *list.Link;
    315     pub const getLink = wl_resource_get_link;
    316 
    317     extern fn wl_resource_from_link(link: *list.Link) *Resource;
    318     pub const fromLink = wl_resource_from_link;
    319 
    320     extern fn wl_resource_find_for_client(list: *list.Head(Resource, null), _client: *Client) ?*Resource;
    321     pub const findForClient = wl_resource_find_for_client;
    322 
    323     extern fn wl_resource_get_client(resource: *Resource) *Client;
    324     pub const getClient = wl_resource_get_client;
    325 
    326     extern fn wl_resource_get_version(resource: *Resource) c_int;
    327     pub fn getVersion(resource: *Resource) u32 {
    328         // The fact that wl_resource.version is a int in libwayland is
    329         // a mistake. Negative versions are impossible and u32 is used
    330         // everywhere else in libwayland
    331         return @as(u32, @intCast(wl_resource_get_version(resource)));
    332     }
    333 
    334     // TOOD: unsure if this should be bound
    335     extern fn wl_resource_set_destructor(resource: *Resource, destroy: DestroyFn) void;
    336 
    337     extern fn wl_resource_get_class(resource: *Resource) [*:0]const u8;
    338     pub const getClass = wl_resource_get_class;
    339 
    340     extern fn wl_resource_add_destroy_listener(resource: *Resource, listener: *Listener(*Resource)) void;
    341     pub const addDestroyListener = wl_resource_add_destroy_listener;
    342 
    343     // Doesn't really make sense with our Listener API as we would need to
    344     // pass a pointer to the wrapper function
    345     //extern fn wl_resource_get_destroy_listener(resource: *Resource, notify: @TypeOf(Listener(*Resource).notify)) ?*Listener(*Resource);
    346 };
    347 
    348 pub const ProtocolLogger = opaque {
    349     pub const Type = enum(c_int) {
    350         request,
    351         event,
    352     };
    353 
    354     pub const LogMessage = extern struct {
    355         resource: *Resource,
    356         message_opcode: c_int,
    357         message: *Message,
    358         arguments_count: c_int,
    359         arguments: ?[*]Argument,
    360     };
    361 
    362     extern fn wl_protocol_logger_destroy(logger: *ProtocolLogger) void;
    363     pub const destroy = wl_protocol_logger_destroy;
    364 };
    365 
    366 pub fn Listener(comptime T: type) type {
    367     return extern struct {
    368         const Self = @This();
    369 
    370         pub const NotifyFn = if (T == void)
    371             fn (listener: *Self) void
    372         else
    373             fn (listener: *Self, data: T) void;
    374 
    375         link: list.Link,
    376         notify: *const fn (listener: *Self, data: ?*anyopaque) callconv(.C) void,
    377 
    378         pub fn init(comptime notify: NotifyFn) Self {
    379             var self: Self = undefined;
    380             self.setNotify(notify);
    381             return self;
    382         }
    383 
    384         pub fn setNotify(self: *Self, comptime notify: NotifyFn) void {
    385             self.notify = if (T == void)
    386                 struct {
    387                     fn wrapper(listener: *Self, _: ?*anyopaque) callconv(.C) void {
    388                         @call(.always_inline, notify, .{listener});
    389                     }
    390                 }.wrapper
    391             else
    392                 struct {
    393                     fn wrapper(listener: *Self, data: ?*anyopaque) callconv(.C) void {
    394                         @call(.always_inline, notify, .{ listener, @as(T, @ptrFromInt(@intFromPtr(data))) });
    395                     }
    396                 }.wrapper;
    397         }
    398     };
    399 }
    400 
    401 pub fn Signal(comptime T: type) type {
    402     return extern struct {
    403         const Self = @This();
    404 
    405         listener_list: list.Head(Listener(T), .link),
    406 
    407         pub fn init(signal: *Self) void {
    408             signal.listener_list.init();
    409         }
    410 
    411         pub fn add(signal: *Self, listener: *Listener(T)) void {
    412             signal.listener_list.append(listener);
    413         }
    414 
    415         pub fn get(signal: *Self, notify: @TypeOf(Listener(T).notify)) ?*Listener(T) {
    416             var it = signal.listener_list.iterator(.forward);
    417             return while (it.next()) |listener| {
    418                 if (listener.notify == notify) break listener;
    419             } else null;
    420         }
    421 
    422         pub const emit = if (T == void)
    423             struct {
    424                 pub inline fn emit(signal: *Self) void {
    425                     emitInner(signal, null);
    426                 }
    427             }.emit
    428         else
    429             struct {
    430                 pub inline fn emit(signal: *Self, data: T) void {
    431                     emitInner(signal, data);
    432                 }
    433             }.emit;
    434 
    435         /// This is similar to wlroots' wlr_signal_emit_safe. It handles
    436         /// removal of any element in the list during iteration and stops at
    437         /// whatever the last element was when iteration started.
    438         fn emitInner(signal: *Self, data: ?*anyopaque) void {
    439             var cursor: Listener(T) = undefined;
    440             signal.listener_list.prepend(&cursor);
    441 
    442             var end: Listener(T) = undefined;
    443             signal.listener_list.append(&end);
    444 
    445             while (cursor.link.next != &end.link) {
    446                 const pos = cursor.link.next.?;
    447                 const listener: *Listener(T) = @fieldParentPtr("link", pos);
    448 
    449                 cursor.link.remove();
    450                 pos.insert(&cursor.link);
    451 
    452                 listener.notify(listener, data);
    453             }
    454 
    455             cursor.link.remove();
    456             end.link.remove();
    457         }
    458     };
    459 }
    460 
    461 pub const EventLoop = opaque {
    462     extern fn wl_event_loop_create() ?*EventLoop;
    463     pub fn create() !*EventLoop {
    464         return wl_event_loop_create() orelse error.EventLoopCreateFailed;
    465     }
    466 
    467     extern fn wl_event_loop_destroy(loop: *EventLoop) void;
    468     pub const destroy = wl_event_loop_destroy;
    469 
    470     extern fn wl_event_loop_add_fd(
    471         loop: *EventLoop,
    472         fd: c_int,
    473         mask: u32,
    474         func: *const fn (fd: c_int, mask: u32, data: ?*anyopaque) callconv(.C) c_int,
    475         data: ?*anyopaque,
    476     ) ?*EventSource;
    477     pub inline fn addFd(
    478         loop: *EventLoop,
    479         comptime T: type,
    480         fd: c_int,
    481         mask: u32,
    482         comptime func: fn (fd: c_int, mask: u32, data: T) c_int,
    483         data: T,
    484     ) error{AddFdFailed}!*EventSource {
    485         return wl_event_loop_add_fd(
    486             loop,
    487             fd,
    488             mask,
    489             struct {
    490                 fn _wrapper(_fd: c_int, _mask: u32, _data: ?*anyopaque) callconv(.C) c_int {
    491                     return func(_fd, _mask, @ptrCast(@alignCast(_data)));
    492                 }
    493             }._wrapper,
    494             data,
    495         ) orelse error.AddFdFailed;
    496     }
    497 
    498     extern fn wl_event_loop_add_timer(
    499         loop: *EventLoop,
    500         func: *const fn (data: ?*anyopaque) callconv(.C) c_int,
    501         data: ?*anyopaque,
    502     ) ?*EventSource;
    503     pub inline fn addTimer(
    504         loop: *EventLoop,
    505         comptime T: type,
    506         comptime func: fn (data: T) c_int,
    507         data: T,
    508     ) error{AddTimerFailed}!*EventSource {
    509         return wl_event_loop_add_timer(
    510             loop,
    511             struct {
    512                 fn _wrapper(_data: ?*anyopaque) callconv(.C) c_int {
    513                     return func(@ptrCast(@alignCast(_data)));
    514                 }
    515             }._wrapper,
    516             data,
    517         ) orelse error.AddTimerFailed;
    518     }
    519 
    520     extern fn wl_event_loop_add_signal(
    521         loop: *EventLoop,
    522         signal_number: c_int,
    523         func: *const fn (c_int, ?*anyopaque) callconv(.C) c_int,
    524         data: ?*anyopaque,
    525     ) ?*EventSource;
    526     pub inline fn addSignal(
    527         loop: *EventLoop,
    528         comptime T: type,
    529         signal_number: c_int,
    530         comptime func: fn (signal_number: c_int, data: T) c_int,
    531         data: T,
    532     ) error{AddSignalFailed}!*EventSource {
    533         return wl_event_loop_add_signal(
    534             loop,
    535             signal_number,
    536             struct {
    537                 fn _wrapper(_signal_number: c_int, _data: ?*anyopaque) callconv(.C) c_int {
    538                     return func(_signal_number, @ptrCast(@alignCast(_data)));
    539                 }
    540             }._wrapper,
    541             data,
    542         ) orelse error.AddSignalFailed;
    543     }
    544 
    545     extern fn wl_event_loop_add_idle(
    546         loop: *EventLoop,
    547         func: *const fn (data: ?*anyopaque) callconv(.C) void,
    548         data: ?*anyopaque,
    549     ) ?*EventSource;
    550     pub inline fn addIdle(
    551         loop: *EventLoop,
    552         comptime T: type,
    553         comptime func: fn (data: T) void,
    554         data: T,
    555     ) error{OutOfMemory}!*EventSource {
    556         return wl_event_loop_add_idle(
    557             loop,
    558             struct {
    559                 fn _wrapper(_data: ?*anyopaque) callconv(.C) void {
    560                     return func(@ptrCast(@alignCast(_data)));
    561                 }
    562             }._wrapper,
    563             data,
    564         ) orelse error.OutOfMemory;
    565     }
    566 
    567     extern fn wl_event_loop_dispatch(loop: *EventLoop, timeout: c_int) c_int;
    568     pub fn dispatch(loop: *EventLoop, timeout: c_int) !void {
    569         const rc = wl_event_loop_dispatch(loop, timeout);
    570         switch (posix.errno(rc)) {
    571             .SUCCESS => return,
    572             // TODO
    573             else => |err| return posix.unexpectedErrno(err),
    574         }
    575     }
    576 
    577     extern fn wl_event_loop_dispatch_idle(loop: *EventLoop) void;
    578     pub const dispatchIdle = wl_event_loop_dispatch_idle;
    579 
    580     extern fn wl_event_loop_get_fd(loop: *EventLoop) c_int;
    581     pub const getFd = wl_event_loop_get_fd;
    582 
    583     extern fn wl_event_loop_add_destroy_listener(loop: *EventLoop, listener: *Listener(*EventLoop)) void;
    584     pub const addDestroyListener = wl_event_loop_add_destroy_listener;
    585 
    586     //extern fn wl_event_loop_get_destroy_listener(loop: *EventLoop, notify: @TypeOf(Listener(*EventLoop).notify)) ?*Listener;
    587     //pub const getDestroyListener = wl_event_loop_get_destroy_listener;
    588 };
    589 
    590 pub const EventSource = opaque {
    591     extern fn wl_event_source_remove(source: *EventSource) c_int;
    592     pub fn remove(source: *EventSource) void {
    593         if (wl_event_source_remove(source) != 0) unreachable;
    594     }
    595 
    596     extern fn wl_event_source_check(source: *EventSource) void;
    597     pub const check = wl_event_source_check;
    598 
    599     extern fn wl_event_source_fd_update(source: *EventSource, mask: u32) c_int;
    600     pub fn fdUpdate(source: *EventSource, mask: u32) !void {
    601         const rc = wl_event_source_fd_update(source, mask);
    602         switch (posix.errno(rc)) {
    603             .SUCCESS => return,
    604             // TODO
    605             else => |err| return posix.unexpectedErrno(err),
    606         }
    607     }
    608 
    609     extern fn wl_event_source_timer_update(source: *EventSource, ms_delay: c_int) c_int;
    610     pub fn timerUpdate(source: *EventSource, ms_delay: c_int) !void {
    611         const rc = wl_event_source_timer_update(source, ms_delay);
    612         switch (posix.errno(rc)) {
    613             .SUCCESS => return,
    614             // TODO
    615             else => |err| return posix.unexpectedErrno(err),
    616         }
    617     }
    618 };
    619 
    620 pub const shm = struct {
    621     pub const Buffer = opaque {
    622         extern fn wl_shm_buffer_get(resource: *Resource) ?*shm.Buffer;
    623         pub const get = wl_shm_buffer_get;
    624 
    625         extern fn wl_shm_buffer_begin_access(buffer: *shm.Buffer) void;
    626         pub const beginAccess = wl_shm_buffer_begin_access;
    627 
    628         extern fn wl_shm_buffer_end_access(buffer: *shm.Buffer) void;
    629         pub const endAccess = wl_shm_buffer_end_access;
    630 
    631         extern fn wl_shm_buffer_get_data(buffer: *shm.Buffer) ?*anyopaque;
    632         pub const getData = wl_shm_buffer_get_data;
    633 
    634         extern fn wl_shm_buffer_get_format(buffer: *shm.Buffer) u32;
    635         pub const getFormat = wl_shm_buffer_get_format;
    636 
    637         extern fn wl_shm_buffer_get_height(buffer: *shm.Buffer) i32;
    638         pub const getHeight = wl_shm_buffer_get_height;
    639 
    640         extern fn wl_shm_buffer_get_width(buffer: *shm.Buffer) i32;
    641         pub const getWidth = wl_shm_buffer_get_width;
    642 
    643         extern fn wl_shm_buffer_get_stride(buffer: *shm.Buffer) i32;
    644         pub const getStride = wl_shm_buffer_get_stride;
    645 
    646         extern fn wl_shm_buffer_ref_pool(buffer: *shm.Buffer) *Pool;
    647         pub const refPool = wl_shm_buffer_ref_pool;
    648     };
    649 
    650     pub const Pool = opaque {
    651         extern fn wl_shm_pool_unref(pool: *Pool) void;
    652         pub const unref = wl_shm_pool_unref;
    653     };
    654 };