diff options
| author | nasr <nsrddyn@gmail.com> | 2026-10-06 23:32:02 +0200 |
|---|---|---|
| committer | nasr <nsrddyn@gmail.com> | 2026-10-06 23:32:02 +0200 |
| commit | e467661baf3d035fb4726559abee52a0c8897ab0 (patch) | |
| tree | f51bb6caf00a6bde1234fb58cd1285891fe4b4e6 /source/base/base_platform_linux_wayland.cpp | |
| parent | f6d3090f7fa76eb8e0dbe060b8490cb49c001c39 (diff) | |
feature: wayland connection
Diffstat (limited to 'source/base/base_platform_linux_wayland.cpp')
| -rw-r--r-- | source/base/base_platform_linux_wayland.cpp | 200 |
1 files changed, 169 insertions, 31 deletions
diff --git a/source/base/base_platform_linux_wayland.cpp b/source/base/base_platform_linux_wayland.cpp index cd1fde8..772080b 100644 --- a/source/base/base_platform_linux_wayland.cpp +++ b/source/base/base_platform_linux_wayland.cpp | |||
| @@ -1,55 +1,193 @@ | |||
| 1 | // https://gaultier.github.io/blog/wayland_from_scratch.html#creating-a-registry | ||
| 1 | // TODO: replace unix_get_env with a generic macro | 2 | // TODO: replace unix_get_env with a generic macro |
| 2 | 3 | ||
| 3 | //- wayland | ||
| 4 | internal void wayland_display_connect(MemArena *arena) { | ||
| 5 | |||
| 6 | 4 | ||
| 7 | ScratchArena env_scratch = scratch_start(arena); | ||
| 8 | 5 | ||
| 6 | //- wayland | ||
| 7 | internal int wayland_display_connect(MemArena *arena) { | ||
| 9 | 8 | ||
| 10 | String8 str8_xdg_runtime_dir = unix_get_env("XDG_RUNTIME_DIR"); | 9 | String8 str8_xdg_runtime_dir = unix_get_env("XDG_RUNTIME_DIR"); |
| 11 | char *xdg_runtime_dir = null_terminate(arena, &str8_xdg_runtime_dir); | 10 | char *xdg_runtime_dir = null_terminate(arena, &str8_xdg_runtime_dir); |
| 11 | sockaddr_un addr = {}; | ||
| 12 | u64 socket_path_len = 0; | ||
| 12 | 13 | ||
| 13 | u64 xdg_runtime_dir_len = str8_xdg_runtime_dir.size; | 14 | // copy the xdg_runtime_dir value to the beginning of the bfufer |
| 15 | { | ||
| 16 | addr.sun_family = AF_UNIX; | ||
| 17 | MemCpy(addr.sun_path, xdg_runtime_dir, str8_xdg_runtime_dir.size); | ||
| 18 | socket_path_len += str8_xdg_runtime_dir.size; | ||
| 19 | addr.sun_path[socket_path_len++] = '/'; // add an ending slash | ||
| 20 | } | ||
| 14 | 21 | ||
| 15 | sockaddr_un addr = {}; | 22 | String8 str8_wayland_display_value = unix_get_env("WAYLAND_DISPLAY"); |
| 16 | addr.sun_family = AF_UNIX; | 23 | Assert(str8_wayland_display_value.size != 0); |
| 24 | char *wayland_display = null_terminate(arena, &str8_wayland_display_value); | ||
| 17 | 25 | ||
| 18 | Assert(xdg_runtime_dir_len <= cstring8_length((u8 *)addr.sun_path)); | 26 | if(wayland_display == NULL) |
| 27 | { | ||
| 28 | const char *wayland_display_default = "wayland-0"; | ||
| 29 | u64 wayland_display_default_len = cstring8_length((u8 *)wayland_display_default); | ||
| 30 | MemCpy(addr.sun_path, wayland_display_default, wayland_display_default_len); | ||
| 31 | } | ||
| 32 | else | ||
| 33 | { | ||
| 34 | MemCpy(addr.sun_path + str8_xdg_runtime_dir.size + 1, wayland_display, str8_wayland_display_value.size); | ||
| 35 | } | ||
| 19 | 36 | ||
| 20 | u64 socket_path_len = 0; | 37 | int fd = socket(AF_UNIX, SOCK_STREAM, 0); |
| 21 | MemCpy(addr.sun_path, xdg_runtime_dir, str8_xdg_runtime_dir.size); | ||
| 22 | socket_path_len += xdg_runtime_dir_len; | ||
| 23 | 38 | ||
| 39 | #if DEBUG // helps to read those errors? i guess i can just read stderr? | ||
| 24 | 40 | ||
| 25 | addr.sun_path[socket_path_len++] = '/'; | ||
| 26 | String8 str8_wayland_display_value = unix_get_env("WAYLAND_DISPLAY"); | ||
| 27 | char *wayland_display = null_terminate(arena, &str8_wayland_display_value); | ||
| 28 | if(wayland_display == NULL) | ||
| 29 | { | ||
| 30 | const char *wayland_display_default = "wayland-0"; | ||
| 31 | u64 wayland_display_default_len = cstring8_length((u8 *)wayland_display_default); | ||
| 32 | MemCpy(addr.sun_path + socket_path_len, wayland_display_default, wayland_display_default_len); | ||
| 33 | } | ||
| 34 | else | ||
| 35 | { | ||
| 36 | u64 wayland_display_len = cstring8_length((u8 *)wayland_display); | ||
| 37 | MemCpy(addr.sun_path + socket_path_len, wayland_display, wayland_display_len); | ||
| 38 | socket_path_len += wayland_display_len; | ||
| 39 | } | ||
| 40 | 41 | ||
| 41 | scratch_end(&env_scratch); | ||
| 42 | 42 | ||
| 43 | int fd = socket(AF_UNIX, SOCK_STREAM, 0); | ||
| 44 | if(fd == -1) | 43 | if(fd == -1) |
| 45 | { | 44 | { |
| 46 | exit(1); | 45 | perror("failed to open socket"); |
| 47 | } | 46 | } |
| 48 | 47 | ||
| 48 | |||
| 49 | if(connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) | 49 | if(connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) |
| 50 | { | 50 | { |
| 51 | exit(1); | 51 | perror("failed to connect to socket"); |
| 52 | |||
| 53 | } | ||
| 54 | |||
| 55 | #endif | ||
| 56 | |||
| 57 | |||
| 58 | AssertLog((fd != -1), "failed to open socket\n"); | ||
| 59 | AssertLog((connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1), "failed to connect to socket\n"); | ||
| 60 | |||
| 61 | return fd; | ||
| 62 | |||
| 63 | } | ||
| 64 | |||
| 65 | |||
| 66 | //- helper functions | ||
| 67 | |||
| 68 | internal void buf_write_u32(char *buf, u64 *buf_size, u64 buf_cap, | ||
| 69 | u32 x) { | ||
| 70 | Assert(*buf_size + sizeof(x) <= buf_cap); | ||
| 71 | Assert(((size_t)buf + *buf_size) % sizeof(x) == 0); | ||
| 72 | |||
| 73 | *(u32 *)(buf + *buf_size) = x; | ||
| 74 | *buf_size += sizeof(x); | ||
| 75 | } | ||
| 76 | |||
| 77 | internal void buf_write_u16(char *buf, u64 *buf_size, u64 buf_cap, | ||
| 78 | u16 x) { | ||
| 79 | Assert(*buf_size + sizeof(x) <= buf_cap); | ||
| 80 | Assert(((size_t)buf + *buf_size) % sizeof(x) == 0); | ||
| 81 | |||
| 82 | *(u16 *)(buf + *buf_size) = x; | ||
| 83 | *buf_size += sizeof(x); | ||
| 84 | } | ||
| 85 | |||
| 86 | internal void buf_write_string(char *buf, u64 *buf_size, u64 buf_cap, | ||
| 87 | char *src, u32 src_len) { | ||
| 88 | Assert(*buf_size + src_len <= buf_cap); | ||
| 89 | |||
| 90 | buf_write_u32(buf, buf_size, buf_cap, src_len); | ||
| 91 | memcpy(buf + *buf_size, src, roundup_4(src_len)); | ||
| 92 | *buf_size += roundup_4(src_len); | ||
| 93 | } | ||
| 94 | |||
| 95 | internal u32 buf_read_u32(char **buf, u64 *buf_size) { | ||
| 96 | Assert(*buf_size >= sizeof(u32)); | ||
| 97 | Assert((size_t)*buf % sizeof(u32) == 0); | ||
| 98 | |||
| 99 | u32 res = *(u32 *)(*buf); | ||
| 100 | *buf += sizeof(res); | ||
| 101 | *buf_size -= sizeof(res); | ||
| 102 | |||
| 103 | return res; | ||
| 104 | } | ||
| 105 | |||
| 106 | internal u16 buf_read_u16(char **buf, u64 *buf_size) { | ||
| 107 | Assert(*buf_size >= sizeof(u16)); | ||
| 108 | Assert((size_t)*buf % sizeof(u16) == 0); | ||
| 109 | |||
| 110 | u16 res = *(u16 *)(*buf); | ||
| 111 | *buf += sizeof(res); | ||
| 112 | *buf_size -= sizeof(res); | ||
| 113 | |||
| 114 | return res; | ||
| 115 | } | ||
| 116 | |||
| 117 | internal void buf_read_n(char **buf, u64 *buf_size, char *dst, u64 n) { | ||
| 118 | Assert(*buf_size >= n); | ||
| 119 | |||
| 120 | memcpy(dst, *buf, n); | ||
| 121 | |||
| 122 | *buf += n; | ||
| 123 | *buf_size -= n; | ||
| 52 | } | 124 | } |
| 53 | 125 | ||
| 126 | global_variable u64 wayland_current_id = 1; | ||
| 54 | 127 | ||
| 55 | } \ No newline at end of file | 128 | internal u32 wayland_wl_display_get_registry(int fd) { |
| 129 | uint64_t msg_size = 0; | ||
| 130 | char msg[128] = ""; | ||
| 131 | buf_write_u32(msg, &msg_size, sizeof(msg), wayland_display_object_id); | ||
| 132 | |||
| 133 | buf_write_u16(msg, &msg_size, sizeof(msg), | ||
| 134 | wayland_wl_display_get_registry_opcode); | ||
| 135 | |||
| 136 | u16 msg_announced_size = wayland_header_size + sizeof(wayland_current_id); | ||
| 137 | Assert(roundup_4(msg_announced_size) == msg_announced_size); | ||
| 138 | buf_write_u16(msg, &msg_size, sizeof(msg), msg_announced_size); | ||
| 139 | |||
| 140 | wayland_current_id++; | ||
| 141 | buf_write_u32(msg, &msg_size, sizeof(msg), wayland_current_id); | ||
| 142 | |||
| 143 | if ((s64)msg_size != send(fd, msg, msg_size, MSG_DONTWAIT)) | ||
| 144 | exit(1); | ||
| 145 | |||
| 146 | Log("-> wl_display@%u.get_registry: wl_registry=%u\n", | ||
| 147 | wayland_display_object_id, wayland_current_id); | ||
| 148 | |||
| 149 | return wayland_current_id; | ||
| 150 | } | ||
| 151 | |||
| 152 | |||
| 153 | |||
| 154 | internal void create_shared_memory_file(u64 size, state_t *state) { | ||
| 155 | char name[255] = "/"; | ||
| 156 | for (u64 index = 1; index < cstring8_length((u8 *)name); ++index) { | ||
| 157 | name[index] = ((double)rand()) / (double)RAND_MAX * 26 + 'a'; | ||
| 158 | } | ||
| 159 | |||
| 160 | int fd = shm_open(name, O_RDWR | O_EXCL | O_CREAT, 0600); | ||
| 161 | AssertLog((fd != -1), "Failed to open buffer for shared memory."); | ||
| 162 | |||
| 163 | Assert(shm_unlink(name) != -1); | ||
| 164 | |||
| 165 | AssertLog((ftruncate(fd, size) != -1), "Failed to truncate buffer."); | ||
| 166 | |||
| 167 | state->shm_pool_data = (u8 *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); | ||
| 168 | Assert((void*)-1 != state->shm_pool_data); | ||
| 169 | Assert(state->shm_pool_data != NULL); | ||
| 170 | state->shm_fd = fd; | ||
| 171 | } | ||
| 172 | |||
| 173 | internal void wayland_handle_message(int fd, state_t *state, char **msg, | ||
| 174 | uint64_t *msg_len) { | ||
| 175 | Assert(*msg_len >= 8); | ||
| 176 | |||
| 177 | u32 object_id = buf_read_u32(msg, msg_len); | ||
| 178 | Assert(object_id <= wayland_current_id); | ||
| 179 | |||
| 180 | u16 opcode = buf_read_u16(msg, msg_len); | ||
| 181 | |||
| 182 | u16 announced_size = buf_read_u16(msg, msg_len); | ||
| 183 | Assert(roundup_4(announced_size) <= announced_size); | ||
| 184 | |||
| 185 | u32 header_size = sizeof(object_id) + sizeof(opcode) + sizeof(announced_size); | ||
| 186 | Assert(announced_size <= header_size + *msg_len); | ||
| 187 | |||
| 188 | if (object_id == state->wl_registry && | ||
| 189 | opcode == wayland_wl_registry_event_global) { | ||
| 190 | // TODO | ||
| 191 | } | ||
| 192 | // Following: Lots of `if (opcode == ...) {... } else if (opcode = ...) { ... } [...]` | ||
| 193 | } | ||
