summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornasr <nsrddyn@gmail.com>2026-10-06 23:32:02 +0200
committernasr <nsrddyn@gmail.com>2026-10-06 23:32:02 +0200
commite467661baf3d035fb4726559abee52a0c8897ab0 (patch)
treef51bb6caf00a6bde1234fb58cd1285891fe4b4e6
parentf6d3090f7fa76eb8e0dbe060b8490cb49c001c39 (diff)
feature: wayland connection
-rw-r--r--.gitignore1
-rwxr-xr-xbuild.sh9
-rw-r--r--project.4coder2
-rw-r--r--source/base/base_core.h2
-rw-r--r--source/base/base_include.h7
-rw-r--r--source/base/base_platform.h32
-rw-r--r--source/base/base_platform_linux.cpp16
-rw-r--r--source/base/base_platform_linux_wayland.cpp200
-rw-r--r--source/base/base_render.h4
-rw-r--r--source/loo/loo.cpp34
10 files changed, 259 insertions, 48 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
/build
diff --git a/build.sh b/build.sh
index 096cffd..73373e2 100755
--- a/build.sh
+++ b/build.sh
@@ -1,7 +1,6 @@
1#!/bin/bash 1#!/bin/bash
2set -e 2set -e
3 3
4echo
5date 4date
6echo "author: Abdellah El Morabit" 5echo "author: Abdellah El Morabit"
7echo 6echo
@@ -9,9 +8,11 @@ echo
9BUILD_DIR=build 8BUILD_DIR=build
10SOURCE_DIR=source 9SOURCE_DIR=source
11INCLUDES="-I${SOURCE_DIR}/loo -I${SOURCE_DIR} -I${SOURCE_DIR}/base" 10INCLUDES="-I${SOURCE_DIR}/loo -I${SOURCE_DIR} -I${SOURCE_DIR}/base"
12CFLAGS="-g -fno-rtti -fno-exceptions -Wall -Werror -fanalyzer -no-pie -Wno-unused-function -Wno-unused-variable -O0" 11CFLAGS="-fno-rtti -fno-exceptions -Wall -Werror -fanalyzer -no-pie -Wno-unused-function -Wno-unused-variable -O0"
13LIBS="" 12LIBS=""
14 13
14DEBUG=1
15
15VULKAN=1 16VULKAN=1
16WAYLAND=1 17WAYLAND=1
17X11=0 18X11=0
@@ -29,6 +30,10 @@ if [ $VULKAN -eq 1 ]; then
29 CFLAGS+=" -DVULKAN=1" 30 CFLAGS+=" -DVULKAN=1"
30fi 31fi
31 32
33if [ $DEBUG -eq 1 ]; then
34 CFLAGS+=" -g -DDEBUG=1"
35fi
36
32mkdir -p "$BUILD_DIR" 37mkdir -p "$BUILD_DIR"
33 38
34echo "Building ${BUILD_DIR}/loo..." 39echo "Building ${BUILD_DIR}/loo..."
diff --git a/project.4coder b/project.4coder
index e392f5b..4f699d3 100644
--- a/project.4coder
+++ b/project.4coder
@@ -32,7 +32,7 @@ linux_paths = {
32load_paths = { 32load_paths = {
33 .win = paths, 33 .win = paths,
34 .linux = linux_paths, 34 .linux = linux_paths,
35 .mac = paths, 35 .mac = linux_paths,
36}; 36};
37 37
38commands = { 38commands = {
diff --git a/source/base/base_core.h b/source/base/base_core.h
index a4531a5..9d0f5e7 100644
--- a/source/base/base_core.h
+++ b/source/base/base_core.h
@@ -31,6 +31,8 @@
31 31
32#define arena_align (2 * sizeof(void *)) 32#define arena_align (2 * sizeof(void *))
33 33
34#define roundup_4(n) (((n) + 3) & -4)
35
34#define Min(a, b) (((a) < (b)) ? (a) : (b)) 36#define Min(a, b) (((a) < (b)) ? (a) : (b))
35#define Max(a, b) (((a) > (b)) ? (a) : (b)) 37#define Max(a, b) (((a) > (b)) ? (a) : (b))
36 38
diff --git a/source/base/base_include.h b/source/base/base_include.h
index 9c928f2..401f682 100644
--- a/source/base/base_include.h
+++ b/source/base/base_include.h
@@ -29,6 +29,11 @@
29#include <sys/un.h> 29#include <sys/un.h>
30#include <fcntl.h> 30#include <fcntl.h>
31#include <dlfcn.h> 31#include <dlfcn.h>
32
33#if DEBUG
34#include <errno.h>
35#endif
36
32#if PLATFORM_LINUX 37#if PLATFORM_LINUX
33 38
34#if X11 39#if X11
@@ -46,7 +51,7 @@
46#endif // PLATFORM_UNIX - PLATFORM_WINDOWS 51#endif // PLATFORM_UNIX - PLATFORM_WINDOWS
47 52
48#if VULKAN 53#if VULKAN
49#include <vulkan/vulkan.h> 54// #include <vulkan/vulkan.h>
50#elif OPENGL 55#elif OPENGL
51... 56...
52#endif 57#endif
diff --git a/source/base/base_platform.h b/source/base/base_platform.h
index aa7ba4b..10f90b0 100644
--- a/source/base/base_platform.h
+++ b/source/base/base_platform.h
@@ -88,7 +88,7 @@ internal s32 x11_read_input();
88#define LinuxGetDisplayWdith(display, screen_num) DisplayWidth(display, screen_num) 88#define LinuxGetDisplayWdith(display, screen_num) DisplayWidth(display, screen_num)
89#define LinuxGetDisplayHeight(display, screen_num) DisplayHeight(display, screen_num); 89#define LinuxGetDisplayHeight(display, screen_num) DisplayHeight(display, screen_num);
90#define LinuxLoadBitMapFromFile(display, window, path, width, height, out, hotspot_x, hotspot_y) \ 90#define LinuxLoadBitMapFromFile(display, window, path, width, height, out, hotspot_x, hotspot_y) \
91XReadBitmapFile(display, window, ) 91 XReadBitmapFile(display, window, )
92 92
93#include "base_platform_linux_x11.cpp" 93#include "base_platform_linux_x11.cpp"
94 94
@@ -120,6 +120,34 @@ global_variable const u32 wayland_format_xrgb8888 = 1;
120global_variable const u32 wayland_header_size = 8; 120global_variable const u32 wayland_header_size = 8;
121global_variable const u32 color_channels = 4; 121global_variable const u32 color_channels = 4;
122 122
123enum state_state_t: u16 {
124 STATE_NONE,
125 STATE_SURFACE_ACKED_CONFIGURE,
126 STATE_SURFACE_ATTACHED,
127};
128
129typedef struct state_t state_t;
130struct state_t {
131 uint32_t wl_registry;
132 uint32_t wl_shm;
133 uint32_t wl_shm_pool;
134 uint32_t wl_buffer;
135 uint32_t xdg_wm_base;
136 uint32_t xdg_surface;
137 uint32_t wl_compositor;
138 uint32_t wl_surface;
139 uint32_t xdg_toplevel;
140 uint32_t stride;
141 uint32_t w;
142 uint32_t h;
143 uint32_t shm_pool_size;
144 int shm_fd;
145 uint8_t *shm_pool_data;
146
147 state_state_t state;
148};
149
150
123#include "base_platform_linux_wayland.cpp" 151#include "base_platform_linux_wayland.cpp"
124 152
125#endif // X11 and Wayland -- set by build params 153#endif // X11 and Wayland -- set by build params
@@ -189,7 +217,7 @@ internal HWND win32_create_window(HINSTANCE instance, int height, int width, int
189 int display_y, const char *window_name); 217 int display_y, const char *window_name);
190 218
191#define Win32CreateWindow(instance, height, width, display_x, display_y) \ 219#define Win32CreateWindow(instance, height, width, display_x, display_y) \
192win32_create_window(instance, height, width, display_x, display_y) 220 win32_create_window(instance, height, width, display_x, display_y)
193 221
194#define PlatformCreateWindow(instance, height, width, display_x, display_y) \ 222#define PlatformCreateWindow(instance, height, width, display_x, display_y) \
195 Win32CreateWindow(instance, height, width, display_x, display_y) 223 Win32CreateWindow(instance, height, width, display_x, display_y)
diff --git a/source/base/base_platform_linux.cpp b/source/base/base_platform_linux.cpp
index 8fb190a..c0bf879 100644
--- a/source/base/base_platform_linux.cpp
+++ b/source/base/base_platform_linux.cpp
@@ -8,24 +8,22 @@ internal String8 unix_get_env(const char *var) {
8 char *current = environ[index]; 8 char *current = environ[index];
9 while(environ[index] != NULL) { 9 while(environ[index] != NULL) {
10 if(CstringAnyMatch(environ[index], var)) { 10 if(CstringAnyMatch(environ[index], var)) {
11 String8 buffer = str8(environ[index]); 11 buffer = str8(environ[index]);
12 12
13 u64 equal_sign_pos = 0; 13 u64 equal_sign_pos = 0;
14 b32 found_equal_sign = str8_find(&buffer, 0, str8("="), &equal_sign_pos); 14 b32 found_equal_sign = str8_find(&buffer, 0, str8("="), &equal_sign_pos);
15 15
16 if(equal_sign_pos) { 16 if(equal_sign_pos) {
17 buffer = str8_chop_left(buffer, equal_sign_pos); 17 buffer = str8_chop_left(buffer, equal_sign_pos + 1);
18 } 18 }
19 19
20 20 return buffer;
21 } else { 21}
22 Assert(0); 22 ++index;
23 }
24 ++index;
25 } 23 }
26 return buffer;
27
28 24
25 AssertLog(buffer.size != 0, "env value not found\n");
26 return {0};
29} 27}
30 28
31 29
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
4internal void wayland_display_connect(MemArena *arena) {
5
6 4
7ScratchArena env_scratch = scratch_start(arena);
8 5
6//- wayland
7internal 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
13u64 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");
16addr.sun_family = AF_UNIX; 23Assert(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
20u64 socket_path_len = 0; 37 int fd = socket(AF_UNIX, SOCK_STREAM, 0);
21MemCpy(addr.sun_path, xdg_runtime_dir, str8_xdg_runtime_dir.size);
22socket_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
25addr.sun_path[socket_path_len++] = '/';
26String8 str8_wayland_display_value = unix_get_env("WAYLAND_DISPLAY");
27char *wayland_display = null_terminate(arena, &str8_wayland_display_value);
28if(wayland_display == NULL)
29{
30const char *wayland_display_default = "wayland-0";
31u64 wayland_display_default_len = cstring8_length((u8 *)wayland_display_default);
32MemCpy(addr.sun_path + socket_path_len, wayland_display_default, wayland_display_default_len);
33}
34else
35{
36u64 wayland_display_len = cstring8_length((u8 *)wayland_display);
37MemCpy(addr.sun_path + socket_path_len, wayland_display, wayland_display_len);
38socket_path_len += wayland_display_len;
39}
40 41
41scratch_end(&env_scratch);
42 42
43int fd = socket(AF_UNIX, SOCK_STREAM, 0);
44if(fd == -1) 43if(fd == -1)
45{ 44{
46exit(1); 45perror("failed to open socket");
47} 46}
48 47
48
49if(connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) 49if(connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
50{ 50{
51exit(1); 51perror("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
61return fd;
62
63}
64
65
66//- helper functions
67
68internal 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
77internal 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
86internal 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
95internal 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
106internal 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
117internal 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
126global_variable u64 wayland_current_id = 1;
54 127
55} \ No newline at end of file 128internal 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);
186Assert(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}
diff --git a/source/base/base_render.h b/source/base/base_render.h
index c3d2c33..53d215d 100644
--- a/source/base/base_render.h
+++ b/source/base/base_render.h
@@ -18,8 +18,8 @@ struct Params {
18 const char *name; 18 const char *name;
19 int width; 19 int width;
20 int height; 20 int height;
21 VkExtensionProperties *vk_properties; 21 // VkExtensionProperties *vk_properties;
22 VkInstance *vk_instance; 22 // VkInstance *vk_instance;
23}; 23};
24 24
25internal void vk_render_entrypoint(MemArena *arena, WinParams *engine, Params *window); 25internal void vk_render_entrypoint(MemArena *arena, WinParams *engine, Params *window);
diff --git a/source/loo/loo.cpp b/source/loo/loo.cpp
new file mode 100644
index 0000000..e2de702
--- /dev/null
+++ b/source/loo/loo.cpp
@@ -0,0 +1,34 @@
1#include "base/base_include.h"
2
3ENTRYPOINT()
4{
5 MemArena *arena = ArenaCreate(MiB(100));
6 Assert(arena);
7
8int fd = wayland_display_connect(arena);
9
10 state_t state = {0};
11 state.wl_registry = wayland_wl_display_get_registry(fd),
12 state.w = 117,
13 state.h = 150,
14 state.stride = 117 * color_channels,
15 state.shm_pool_size = state.h * state.stride;
16
17
18 while (1) {
19 char read_buf[4096] = "";
20 int64_t read_bytes = recv(fd, read_buf, sizeof(read_buf), 0);
21 if (read_bytes == -1)
22 exit(errno);
23
24 char *msg = read_buf;
25 uint64_t msg_len = (uint64_t)read_bytes;
26
27 while (msg_len > 0)
28 wayland_handle_message(fd, &state, &msg, &msg_len);
29 }
30
31 return 0;
32
33
34}