#+build linux #+vet explicit-allocators package wayland import intr "base:intrinsics" import rt "base:runtime" import "core:bufio" import "core:bytes" import "core:fmt" import "core:io" import "core:log" import "core:math/fixed" import "core:os" import "core:path/filepath" import "core:strconv" import "core:strings" import "core:sys/linux" DISPLAY :: Display_ID(1) // wl_display singleton is hardcoded to an ID of 1. init :: proc(session: ^Session, allocator := context.allocator, frame_allocator := context.temp_allocator) -> (ok: bool) { // Set up socket boilerplate. { socket_data := &session.socket_data socket_fd, socket_ok := _get_socket(allocator) if !socket_ok { return false } socket_data.fd = socket_fd socket_data.reader_stream = { procedure = _unix_socket_read, data = session, } bufio.reader_init(&socket_data.reader, socket_data.reader_stream, allocator=allocator) socket_data.writer_stream = { procedure = _unix_socket_write, data = session, } bufio.writer_init(&socket_data.writer, socket_data.writer_stream, allocator=allocator) bufio.read_writer_init(&socket_data.read_writer, &socket_data.reader, &socket_data.writer) session.socket_stream = bufio.read_writer_to_stream(&socket_data.read_writer) } bytes.buffer_init_allocator(&session.message_read_buffer, 0, 16, allocator=allocator) bytes.buffer_init_allocator(&session.message_write_buffer, 0, 16, allocator=allocator) strings.builder_init(&session.debug_log_builder, allocator=allocator) session.objects.allocator = allocator session.next_id = 1 // wl_display is hardcoded to an ID of 1 in Wayland. display_id := _allocate_object(session, .Display) ensure(display_id == Object_ID(DISPLAY)) session.allocator = allocator session.frame_allocator = frame_allocator wayland_debug_env := os.get_env("WAYLAND_DEBUG", allocator) session.debug_logging_enabled = wayland_debug_env == "1" delete(wayland_debug_env, allocator) return true } fini :: proc(session: ^Session) { delete(session.objects) bytes.buffer_destroy(&session.message_read_buffer) bytes.buffer_destroy(&session.message_write_buffer) strings.builder_destroy(&session.debug_log_builder) free_all(session.frame_allocator) } pump_events :: proc(session: ^Session) -> Error { io.flush(session.socket_stream) // TODO: Handle events until there are no more events to be handled! // for _handle_next_event(session) or_return {} _handle_next_event(session) or_return // free_all(session.frame_allocator) return nil } _on_event_internal :: proc(session: ^Session, object_id: Object_ID, opcode: Opcode, handler_info: Handler_Info) { // TODO: Gracefully handle if we don't have handler_info for a given object. ensure(object_id in session.objects) object_info := &session.objects[object_id] object_info.handlers[opcode] = handler_info } _handle_next_event :: proc(session: ^Session) -> (ok: bool, error: Error) { // TODO: Non-blocking message := _message_read(session) or_return // log.debug(message) object_id := message.header.object_id object_info, object_info_ok := session.objects[object_id] if !object_info_ok { log.errorf("Received event for unknown object ID '{}'", message.header.object_id) return true, nil } handler_info, handler_info_ok := object_info.handlers[message.header.opcode] if !handler_info_ok { log.error("Unhandled event:", message.header) // TODO: We will need to parse the event in order to log it, so we'll need a special code path for that. return true, nil } stream := bytes.buffer_to_stream(&session.message_read_buffer) handler_info.dispatcher(session, stream, object_id, message.header.opcode, handler_info) or_return return true, nil }