summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbuild.sh19
-rw-r--r--source/base/base_arena.cpp2
-rw-r--r--source/base/base_core.h73
-rw-r--r--source/base/base_include.h69
-rw-r--r--source/base/base_platform.cpp5
-rw-r--r--source/base/base_platform.h134
-rw-r--r--source/base/base_platform_linux.cpp7
-rw-r--r--source/base/base_platform_linux_wayland.cpp365
-rw-r--r--source/base/base_platform_linux_wayland_input.cpp159
-rw-r--r--source/base/base_render_vulkan.cpp2
-rw-r--r--source/base/base_stack.cpp2
-rw-r--r--source/loo/loo.cpp26
12 files changed, 580 insertions, 283 deletions
diff --git a/build.sh b/build.sh
index 73373e2..4465cec 100755
--- a/build.sh
+++ b/build.sh
@@ -8,18 +8,27 @@ echo
8BUILD_DIR=build 8BUILD_DIR=build
9SOURCE_DIR=source 9SOURCE_DIR=source
10INCLUDES="-I${SOURCE_DIR}/loo -I${SOURCE_DIR} -I${SOURCE_DIR}/base" 10INCLUDES="-I${SOURCE_DIR}/loo -I${SOURCE_DIR} -I${SOURCE_DIR}/base"
11CFLAGS="-fno-rtti -fno-exceptions -Wall -Werror -fanalyzer -no-pie -Wno-unused-function -Wno-unused-variable -O0" 11CFLAGS="-fno-rtti -fno-exceptions -Wall -Wundef -Werror -fanalyzer -no-pie -Wno-unused-function -Wno-unused-variable -O0 "
12LIBS="" 12LIBS=""
13 13
14DEBUG=1 14DEBUG=1
15 15
16VULKAN=1 16VULKAN=0
17WAYLAND=1 17WAYLAND=1
18X11=0 18X11=0
19 19
20if [ $WAYLAND -eq 1 ]; then 20if [ $WAYLAND -eq 1 ]; then
21 LIBS+=" $(pkg-config --libs wayland-client)" 21 CFLAGS+=" -DWAYLAND=1 -DX11=0"
22 CFLAGS+=" $(pkg-config --cflags wayland-client) -DWAYLAND=1 -DX11=0" 22 LIBS+="-lwayland-client -lxkbcommon"
23
24# TODO: how often do we need the xdg protocol?
25 GENERATED_DIR="${BUILD_DIR}/generated"
26 XDG_SHELL_XML=/usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml
27 mkdir -p "$GENERATED_DIR"
28 wayland-scanner client-header "$XDG_SHELL_XML" "${GENERATED_DIR}/xdg-shell-client-protocol.h"
29 wayland-scanner private-code "$XDG_SHELL_XML" "${GENERATED_DIR}/xdg-shell-protocol.c"
30 INCLUDES+=" -I${GENERATED_DIR}"
31
23elif [ $X11 -eq 1 ]; then 32elif [ $X11 -eq 1 ]; then
24 LIBS+=" -lX11" 33 LIBS+=" -lX11"
25 CFLAGS+=" -DX11=1 -DWAYLAND=0" 34 CFLAGS+=" -DX11=1 -DWAYLAND=0"
@@ -37,4 +46,4 @@ fi
37mkdir -p "$BUILD_DIR" 46mkdir -p "$BUILD_DIR"
38 47
39echo "Building ${BUILD_DIR}/loo..." 48echo "Building ${BUILD_DIR}/loo..."
40g++ $INCLUDES $CFLAGS "${SOURCE_DIR}/loo/loo.cpp" -o "${BUILD_DIR}/loo" $LIBS \ No newline at end of file 49g++ $INCLUDES $CFLAGS "${SOURCE_DIR}/loo/loo.cpp" -o "${BUILD_DIR}/loo" $LIBS
diff --git a/source/base/base_arena.cpp b/source/base/base_arena.cpp
index b4235e6..759080c 100644
--- a/source/base/base_arena.cpp
+++ b/source/base/base_arena.cpp
@@ -125,7 +125,7 @@ arena_resize_block_align(MemArena *arena, void *old_memory, u64 new_size, u64 ol
125 if((arena->base_position + arena->previous_position) == old_memory) { 125 if((arena->base_position + arena->previous_position) == old_memory) {
126 arena->current_position = arena->previous_position + new_size; 126 arena->current_position = arena->previous_position + new_size;
127 if(new_size > old_size) { 127 if(new_size > old_size) {
128 MemSet(&arena->current_position, new_size - old_size); 128 MemSetZero(old_mem + old_size, new_size - old_size);
129 } 129 }
130 130
131 return (MemArena *)old_memory; 131 return (MemArena *)old_memory;
diff --git a/source/base/base_core.h b/source/base/base_core.h
index 9d0f5e7..d708ce1 100644
--- a/source/base/base_core.h
+++ b/source/base/base_core.h
@@ -14,10 +14,31 @@
14 14
15//- architecture definitions 15//- architecture definitions
16 16
17#if defined(__arm__) || defined(__aarch64__) 17#if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM64)
18#define ARCH_ARM 1 18#define ARCH_ARM 1
19#elif defined(__i386__) || defined(__x86_64__) 19#elif defined(__x86_64__) || defined(_M_X64)
20#define ARCH_x86_64 1 20#define ARCH_x86_64 1
21#elif defined(__i386__) || defined(_M_IX86)
22#define ARCH_X86 1
23#endif
24
25#ifndef COMPILER_MSVC
26#define COMPILER_MSVC 0
27#endif
28#ifndef COMPILER_CLANG
29#define COMPILER_CLANG 0
30#endif
31#ifndef COMPILER_GCC
32#define COMPILER_GCC 0
33#endif
34#ifndef ARCH_ARM
35#define ARCH_ARM 0
36#endif
37#ifndef ARCH_x86_64
38#define ARCH_x86_64 0
39#endif
40#ifndef ARCH_X86
41#define ARCH_X86 0
21#endif 42#endif
22 43
23//- compiler definitions 44//- compiler definitions
@@ -39,26 +60,27 @@
39#define Unused(x) (void)(x) 60#define Unused(x) (void)(x)
40#define Nil 0 61#define Nil 0
41 62
42#define Deprecated __attribute__((__deprecated__)) 63#define Deprecated [[deprecated]]
43 64
44//- breakpoints 65//- breakpoints
45#if ARCH_ARM
46#define breakpoint() __asm__ volatile("brk #0")
47#elif ARCH_x86_64
48
49#if COMPILER_GCC
50#define breakpoint() __asm__ volatile("int3")
51#endif
52#endif
53
54#if COMPILER_MSVC 66#if COMPILER_MSVC
55#include <intrin.h> 67#include <intrin.h>
56#define breakpoint() __debugbreak() 68#define breakpoint() __debugbreak()
69#define Trap() __fastfail(0)
70#elif COMPILER_CLANG
71#define breakpoint() __builtin_debugtrap()
72#define Trap() __builtin_trap()
73#elif ARCH_ARM
74#define breakpoint() __asm__ volatile("brk #0")
75#define Trap() __builtin_trap()
76#else
77#define breakpoint() __asm__ volatile("int3")
78#define Trap() __builtin_trap()
57#endif 79#endif
58 80
59//- 81//-
60#define MemCpy(dest, src, len) memcpy((dest), (src), (len)) 82#define MemCpy(dest, src, len) memcpy((dest), (src), (len))
61#define MemSet(dest, len) memset((dest), (1), (len)) 83#define MemSet(dest, val, len) memset((dest), (val), (len))
62#define MemSetZero(dest, len) memset((dest), (0), (len)) 84#define MemSetZero(dest, len) memset((dest), (0), (len))
63 85
64//- 86//-
@@ -107,11 +129,17 @@ typedef intptr_t smm;
107 129
108//- 130//-
109 131
110#define Assert(expression) _assert(expression) 132#define Assert(expression) do { \
133 if (!(expression)) { \
134 breakpoint(); \
135 Trap(); \
136 } \
137 } \
138 while(0)
111 139
112// NOTE: apparantly in macros this strinifys whataever you put after the # 140// NOTE: apparantly in macros this strinifys whataever you put after the #
113#define AssertLog(expression, ...) do { \ 141#define AssertLog(expression, ...) do { \
114 if (!expression) { \ 142 if (!(expression)) { \
115 Log("%s:%d: %s\n", __FILE__, __LINE__, #expression); \ 143 Log("%s:%d: %s\n", __FILE__, __LINE__, #expression); \
116 Log(__VA_ARGS__);\ 144 Log(__VA_ARGS__);\
117 Assert(false);\ 145 Assert(false);\
@@ -119,21 +147,6 @@ typedef intptr_t smm;
119 } \ 147 } \
120 while(0) 148 while(0)
121 149
122internal void _assert(bool expression);
123
124
125internal void _assert(bool expression)
126{
127
128 if (!expression) {
129 breakpoint();
130#if COMPILER_MSVC
131 __fastfail(0);
132#else
133 __builtin_trap(); // NOTE: always stop, breakpoint() is empty on arm without DEBUG
134#endif
135 }
136}
137 150
138 151
139 152
diff --git a/source/base/base_include.h b/source/base/base_include.h
index 401f682..22727f5 100644
--- a/source/base/base_include.h
+++ b/source/base/base_include.h
@@ -1,47 +1,70 @@
1#ifndef BASE_INCLUDE_H 1#ifndef BASE_INCLUDE_H
2#define BASE_INCLUDE_H 2#define BASE_INCLUDE_H
3 3
4#if defined(__linux__) || defined(__APPLE__) 4#if defined(__APPLE__)
5// #message "PLATFORM LINUX APPLE" 5#define PLATFORM_APPLE 1
6#define PLATFORM_UNIX 1 6#define PLATFORM_UNIX 1
7#elif defined(__linux__)
7#define PLATFORM_LINUX 1 8#define PLATFORM_LINUX 1
8#elif defined(__linux__) && !defined(__APPLE__) 9#define PLATFORM_UNIX 1
9#message "PLATFORM LINUX" 10#elif defined(_WIN32)
10#define PLATFORM_LINUX 1
11#elif defined(_WIN32) || defined(_WIN64)
12#message "PLATFORM WINDOWS"
13#define PLATFORM_WINDOWS 1 11#define PLATFORM_WINDOWS 1
14#elif defined(__APPLE__)
15#define PLATFORM_APPLE 1
16#message "PLATFORM APPLE"
17#else 12#else
18#message platform unknown 13#error Unsupported platform
19#endif // platform definitions 14#endif // platform definitions
20 15
16#ifndef PLATFORM_APPLE
17#define PLATFORM_APPLE 0
18#endif
19#ifndef PLATFORM_LINUX
20#define PLATFORM_LINUX 0
21#endif
22#ifndef PLATFORM_UNIX
23#define PLATFORM_UNIX 0
24#endif
25#ifndef PLATFORM_WINDOWS
26#define PLATFORM_WINDOWS 0
27#endif
28#ifndef DEBUG
29#define DEBUG 0
30#endif
31#ifndef X11
32#define X11 0
33#endif
34#ifndef WAYLAND
35#define WAYLAND 0
36#endif
37#ifndef VULKAN
38#define VULKAN 0
39#endif
40#ifndef OPENGL
41#define OPENGL 0
42#endif
43
21#if PLATFORM_UNIX 44#if PLATFORM_UNIX
22#include <unistd.h> 45#include <unistd.h>
23#include <dirent.h> 46#include <dirent.h>
24#include <sys/syscall.h>
25#include <sys/mman.h> 47#include <sys/mman.h>
26#include <sys/socket.h> // needed for making a connection to displays (wayland) 48#include <sys/socket.h> // needed for making a connection to displays (wayland)
27#include <sys/stat.h> 49#include <sys/stat.h>
28#include <sys/types.h>
29#include <sys/un.h> 50#include <sys/un.h>
30#include <fcntl.h> 51#include <fcntl.h>
31#include <dlfcn.h> 52#include <dlfcn.h>
32 53
33#if DEBUG
34#include <errno.h>
35#endif
36
37#if PLATFORM_LINUX 54#if PLATFORM_LINUX
38 55
56#include <linux/input-event-codes.h>
57
39#if X11 58#if X11
40#include <X11/X.h> 59#include <X11/X.h>
41#include <X11/Xlib.h> 60#include <X11/Xlib.h>
42#include <X11/keysym.h> 61#include <X11/keysym.h>
43#elif WAYLAND 62#elif WAYLAND
44#include <wayland-client.h> 63
64
65#include <wayland-client.h> // wl_display, wl_surface, wl_seat, wl_keyboard, ... (core protocol)
66#include "xdg-shell-client-protocol.h" // xdg_wm_base, xdg_surface, xdg_toplevel (generated by build.sh)
67#include <xkbcommon/xkbcommon.h> // the only types of inputs the server will probably send on wayland
45#endif 68#endif
46 69
47#endif // PLATFORM_LINUX 70#endif // PLATFORM_LINUX
@@ -59,12 +82,11 @@
59//- 82//-
60 83
61#include <time.h> 84#include <time.h>
62#include <math.h>
63#include <string.h> 85#include <string.h>
64#include <stdint.h> 86#include <stdint.h>
65#include <stddef.h>
66#include <stdio.h> 87#include <stdio.h>
67#include <stdarg.h> 88#include <stdarg.h>
89#include <errno.h>
68 90
69//- 91//-
70#include "base_core.h" 92#include "base_core.h"
@@ -80,7 +102,12 @@
80#include "base_arena.cpp" 102#include "base_arena.cpp"
81#include "base_stack.cpp" 103#include "base_stack.cpp"
82#include "base_string.cpp" 104#include "base_string.cpp"
83#include "base_platform.cpp" 105
106#if PLATFORM_LINUX
107#include "base_platform_linux.cpp"
108#elif PLATFORM_WINDOWS
109#include "base_platform_win32.cpp"
110#endif
84 111
85#include "base_rand.cpp" 112#include "base_rand.cpp"
86#include "base_simd.cpp" 113#include "base_simd.cpp"
diff --git a/source/base/base_platform.cpp b/source/base/base_platform.cpp
deleted file mode 100644
index ae5b2e9..0000000
--- a/source/base/base_platform.cpp
+++ /dev/null
@@ -1,5 +0,0 @@
1#if PLATFORM_LINUX
2#include "base_platform_linux.cpp"
3#elif PLATFORM_WINDOWS
4#include "base_platform_win32.cpp"
5#endif \ No newline at end of file
diff --git a/source/base/base_platform.h b/source/base/base_platform.h
index 10f90b0..875986d 100644
--- a/source/base/base_platform.h
+++ b/source/base/base_platform.h
@@ -16,14 +16,30 @@ struct Directory {
16 String8List *file_names; 16 String8List *file_names;
17}; 17};
18 18
19#if 0 // TODO: @WAYLAND and @X11 implementation 19#if 1 // TODO: @WAYLAND and @X11 implementation
20typedef struct LinuxWindowHandle LinuxWindowHandle; 20
21struct LinuxWindowHandle { 21typedef struct Display Display;
22struct Display
23{
24 int width;
25 int height;
26};
27
28typedef struct Window Window;
29struct Window
30{
31 int width;
32 int height;
33};
34
35typedef struct LinuxWindowParams LinuxWindowParams;
36struct LinuxWindowParams {
37 cstring name;
22 Display *display; 38 Display *display;
23 Window window; 39 Window window;
24}; 40};
25 41
26#define LinuxLoadSharedLibrary(library, name) unix_ 42#define LinuxLoadSharedLibrary(arena, library) unix_load_shared_library(arena, library)
27#endif 43#endif
28 44
29//- Shared libraries 45//- Shared libraries
@@ -51,14 +67,16 @@ internal void unix_log_with_args(const char *format, ...);
51#define FileExists(path) unix_file_exists(path) 67#define FileExists(path) unix_file_exists(path)
52#define DirLoad(arena, path) unix_open_dir(arena, path) 68#define DirLoad(arena, path) unix_open_dir(arena, path)
53 69
54#define OSExit() unix_os_exit();
55 70
56#if COMPILER_GCC || COMPILER_CLANG 71#if DEBUG
57// TODO: __VA_ARGS__ CLANG 72#define OSExit(code) _exit(code)
58#define Log(...) unix_log_with_args(__VA_ARGS__) 73#define Log(...) unix_log_with_args(__VA_ARGS__)
59#define LogStr8(message) \ 74#define LogStr8(message) Log(Str8Fmt, Str8Arg(message))
60 Log(Str8Fmt, Str8Arg(message)) // NOTE: for this to wwork we need the /analyze argument 75#else
61#endif // COMPILER_GCC || COMPILER_CLANG 76#define OSExit(code) Unused(code)
77#define Log(...) ((void)0)
78#define LogStr8(message) ((void)0)
79#endif // disable comments when debug mode is disabled
62 80
63//- Entrypoint and platform window layer 81//- Entrypoint and platform window layer
64#define ENTRYPOINT() int main(int count, char **args) 82#define ENTRYPOINT() int main(int count, char **args)
@@ -95,59 +113,55 @@ internal s32 x11_read_input();
95//- Wayland 113//- Wayland
96#elif WAYLAND 114#elif WAYLAND
97 115
98//- protocol values defined in the wayland library. it's a library load less i guess 116typedef struct WaylandState WaylandState;
99global_variable const u32 wayland_display_object_id = 1; 117struct WaylandState {
100global_variable const u16 wayland_wl_registry_event_global = 0; 118 //- connection
101global_variable const u16 wayland_shm_pool_event_format = 0; 119 struct wl_display *display;
102global_variable const u16 wayland_wl_buffer_event_release = 0; 120 struct wl_registry *registry;
103global_variable const u16 wayland_xdg_wm_base_event_ping = 0;
104global_variable const u16 wayland_xdg_toplevel_event_configure = 0;
105global_variable const u16 wayland_xdg_toplevel_event_close = 1;
106global_variable const u16 wayland_xdg_surface_event_configure = 0;
107global_variable const u16 wayland_wl_display_get_registry_opcode = 1;
108global_variable const u16 wayland_wl_registry_bind_opcode = 0;
109global_variable const u16 wayland_wl_compositor_create_surface_opcode = 0;
110global_variable const u16 wayland_xdg_wm_base_pong_opcode = 3;
111global_variable const u16 wayland_xdg_surface_ack_configure_opcode = 4;
112global_variable const u16 wayland_wl_shm_create_pool_opcode = 0;
113global_variable const u16 wayland_xdg_wm_base_get_xdg_surface_opcode = 2;
114global_variable const u16 wayland_wl_shm_pool_create_buffer_opcode = 0;
115global_variable const u16 wayland_wl_surface_attach_opcode = 1;
116global_variable const u16 wayland_xdg_surface_get_toplevel_opcode = 1;
117global_variable const u16 wayland_wl_surface_commit_opcode = 6;
118global_variable const u16 wayland_wl_display_error_event = 0;
119global_variable const u32 wayland_format_xrgb8888 = 1;
120global_variable const u32 wayland_header_size = 8;
121global_variable const u32 color_channels = 4;
122 121
123enum state_state_t: u16 { 122 struct wl_compositor *compositor;
124 STATE_NONE, 123 struct wl_shm *shm;
125 STATE_SURFACE_ACKED_CONFIGURE, 124 struct xdg_wm_base *xdg_wm_base;
126 STATE_SURFACE_ATTACHED, 125 struct wl_seat *seat;
127}; 126
127 //- window objects
128 128
129typedef struct state_t state_t; 129 struct wl_surface *surface;
130struct state_t { 130 struct xdg_surface *xdg_surface;
131 uint32_t wl_registry; 131 struct xdg_toplevel *xdg_toplevel;
132 uint32_t wl_shm; 132
133 uint32_t wl_shm_pool; 133 //- keyboard input
134 uint32_t wl_buffer; 134 struct wl_keyboard *keyboard;
135 uint32_t xdg_wm_base; 135 b32 keys_down[256]; // indexed by linux scancode
136 uint32_t xdg_surface; 136
137 uint32_t wl_compositor; 137//- mouse (pointer) input
138 uint32_t wl_surface; 138
139 uint32_t xdg_toplevel; 139struct wl_pointer *pointer; // wl_pointer is a predefined <wayland-client.h> struct
140 uint32_t stride; 140f32 mouse_x, mouse_y;
141 uint32_t w; 141b32 mouse_buttons[3];
142 uint32_t h; 142f32 x_offset, y_offset;
143 uint32_t shm_pool_size; 143b32 mouse_in_window;
144 int shm_fd; 144
145 uint8_t *shm_pool_data; 145
146 146
147 state_state_t state; 147 //- software framebuffer
148 struct wl_buffer *buffer;
149 u8 *pixels;
150 u32 width;
151 u32 height;
152 u32 stride;
153 u32 size;
154
155 b32 should_close;
148}; 156};
149 157
158#pragma GCC diagnostic push
159#pragma GCC diagnostic ignored "-Wattributes"
160#include "xdg-shell-protocol.c"
161#pragma GCC diagnostic pop
162
150 163
164#include "base_platform_linux_wayland_input.cpp"
151#include "base_platform_linux_wayland.cpp" 165#include "base_platform_linux_wayland.cpp"
152 166
153#endif // X11 and Wayland -- set by build params 167#endif // X11 and Wayland -- set by build params
@@ -190,7 +204,7 @@ internal void win32_log(String8List messages);
190#define FileExists(path) win32_file_exists(path) 204#define FileExists(path) win32_file_exists(path)
191#define Win32FileExists(path) win32_file_exists(path) 205#define Win32FileExists(path) win32_file_exists(path)
192#define DirLoad(arena, path) win32_open_dir(arena, original_path); 206#define DirLoad(arena, path) win32_open_dir(arena, original_path);
193#define OSExit() win32_os_exit(); 207#define OSExit(code) win32_os_exit()
194 208
195#if COMPILER_GCC || COMPILER_CLANG 209#if COMPILER_GCC || COMPILER_CLANG
196 210
@@ -200,7 +214,7 @@ internal void win32_logf(const char *fmt, ...) PRINTF_FORMAT;
200#elif COMPILER_MSVC 214#elif COMPILER_MSVC
201internal void win32_logf(_Printf_format_string_ const char *fmt, ...); 215internal void win32_logf(_Printf_format_string_ const char *fmt, ...);
202 216
203#define Log(fmt, ...) win32_logf(fmt, __VA_ARGS__) 217#define Log(fmt, ...) win32_logf(fmt, ##__VA_ARGS__)
204 218
205#endif // COMPILER_GCC || COMPILER_CLANG 219#endif // COMPILER_GCC || COMPILER_CLANG
206 220
diff --git a/source/base/base_platform_linux.cpp b/source/base/base_platform_linux.cpp
index c0bf879..61a4bea 100644
--- a/source/base/base_platform_linux.cpp
+++ b/source/base/base_platform_linux.cpp
@@ -17,9 +17,9 @@ internal String8 unix_get_env(const char *var) {
17 buffer = str8_chop_left(buffer, equal_sign_pos + 1); 17 buffer = str8_chop_left(buffer, equal_sign_pos + 1);
18 } 18 }
19 19
20 return buffer; 20 return buffer;
21} 21 }
22 ++index; 22 ++index;
23 } 23 }
24 24
25 AssertLog(buffer.size != 0, "env value not found\n"); 25 AssertLog(buffer.size != 0, "env value not found\n");
@@ -149,7 +149,6 @@ internal void unix_log_with_args(const char *format, ...)
149 va_end(arguments); 149 va_end(arguments);
150} 150}
151 151
152internal void unix_os_exit() { _exit(0); }
153 152
154// TODO: rewrite this 153// TODO: rewrite this
155internal String8List *unix_open_dir(MemArena *arena, String8 *path) 154internal String8List *unix_open_dir(MemArena *arena, String8 *path)
diff --git a/source/base/base_platform_linux_wayland.cpp b/source/base/base_platform_linux_wayland.cpp
index 772080b..5823a69 100644
--- a/source/base/base_platform_linux_wayland.cpp
+++ b/source/base/base_platform_linux_wayland.cpp
@@ -1,193 +1,294 @@
1// https://gaultier.github.io/blog/wayland_from_scratch.html#creating-a-registry
2// TODO: replace unix_get_env with a generic macro
3 1
2//- software framebuffer
3// TODO: delete this section once vulkan is presenting. vkCreateWaylandSurfaceKHR only needs
4// state->display and state->surface, the driver then creates and attaches buffers itself.
4 5
6// creates a wl_buffer backed by shared memory that both we and the compositor can read.
7internal struct wl_buffer *wayland_create_shm_buffer(WaylandState *state) {
8 state->stride = state->width * 4; // 4 bytes per pixel (XRGB8888)
9 state->size = state->stride * state->height;
5 10
6//- wayland 11 int fd = memfd_create("loo-shared-memory", MFD_CLOEXEC);
7internal int wayland_display_connect(MemArena *arena) { 12 AssertLog((fd != -1), "Failed to open buffer for shared memory.");
13 AssertLog((ftruncate(fd, state->size) != -1), "Failed to truncate buffer.");
8 14
9 String8 str8_xdg_runtime_dir = unix_get_env("XDG_RUNTIME_DIR"); 15 state->pixels = (u8 *)mmap(NULL, state->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
10 char *xdg_runtime_dir = null_terminate(arena, &str8_xdg_runtime_dir); 16 AssertLog((state->pixels != MAP_FAILED), "Failed to mmap shared memory.");
11 sockaddr_un addr = {};
12 u64 socket_path_len = 0;
13 17
14// copy the xdg_runtime_dir value to the beginning of the bfufer 18 // a pool is the compositor-side view of our shared memory. libwayland sends the fd
15{ 19 // over the socket for us (the SCM_RIGHTS dance, in the other direction).
16 addr.sun_family = AF_UNIX; 20 struct wl_shm_pool *pool = wl_shm_create_pool(state->shm, fd, state->size);
17 MemCpy(addr.sun_path, xdg_runtime_dir, str8_xdg_runtime_dir.size); 21
18 socket_path_len += str8_xdg_runtime_dir.size; 22 // a buffer is a typed slice of the pool: offset, size, stride and pixel format
19 addr.sun_path[socket_path_len++] = '/'; // add an ending slash 23 struct wl_buffer *buffer = wl_shm_pool_create_buffer(pool, 0, state->width, state->height,
20} 24 state->stride, WL_SHM_FORMAT_XRGB8888);
21 25
22 String8 str8_wayland_display_value = unix_get_env("WAYLAND_DISPLAY"); 26 wl_shm_pool_destroy(pool);
23Assert(str8_wayland_display_value.size != 0); 27 close(fd);
24 char *wayland_display = null_terminate(arena, &str8_wayland_display_value); 28
29 return buffer;
30}
25 31
26 if(wayland_display == NULL) 32internal void wayland_draw_gradient(WaylandState *state) {
27 { 33 u32 *pixels = (u32 *)state->pixels;
28 const char *wayland_display_default = "wayland-0"; 34 for (u32 y = 0; y < state->height; y++) {
29 u64 wayland_display_default_len = cstring8_length((u8 *)wayland_display_default); 35 for (u32 x = 0; x < state->width; x++) {
30 MemCpy(addr.sun_path, wayland_display_default, wayland_display_default_len); 36 u8 r = (u8)(x * 255 / state->width);
37 u8 g = (u8)(y * 255 / state->height);
38 u8 b = 0x80;
39 pixels[y * state->width + x] = (r << 16) | (g << 8) | b;
40 }
31 } 41 }
32 else
33 {
34 MemCpy(addr.sun_path + str8_xdg_runtime_dir.size + 1, wayland_display, str8_wayland_display_value.size);
35} 42}
36 43
37 int fd = socket(AF_UNIX, SOCK_STREAM, 0); 44internal void draw_square(u32 *pixels, WaylandState *state, u32 x_position, u32 y_position) {
38 45
39#if DEBUG // helps to read those errors? i guess i can just read stderr? 46for(u32 y = y_position; y < y_position + 10; ++y) {
40 47
48for(u32 x = x_position; x < x_position + 10; ++x) {
41 49
50u8 r = 0xff;
51 u8 g = 0xff;
52u8 b = 0xff;
53 pixels[y * state->width + x] = (r << 16) | (g << 8) | b;
42 54
43if(fd == -1) 55}
44{
45perror("failed to open socket");
46} 56}
47 57
58}
48 59
49if(connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) 60internal void wayland_draw_weird_gradient(WaylandState *state) {
50{
51perror("failed to connect to socket");
52 61
53} 62local_persist u32 frame = 0;
63frame += 1;
54 64
55#endif 65 local_persist u32 start_x = state->width / 2;
66 local_persist u32 start_y = state->width / 2;
56 67
68start_x += frame;
57 69
58 AssertLog((fd != -1), "failed to open socket\n"); 70draw_square((u32 *)state->pixels, state, start_x , start_y);
59 AssertLog((connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1), "failed to connect to socket\n");
60 71
61return fd;
62 72
63} 73}
64 74
65 75
66//- helper functions 76//- xdg_wm_base events
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 77
73 *(u32 *)(buf + *buf_size) = x; 78// ping: the compositor checks we're still alive. if we don't pong, it may show the
74 *buf_size += sizeof(x); 79internal void wayland_xdg_wm_base_ping(void *data, struct xdg_wm_base *xdg_wm_base, u32 serial) {
80 xdg_wm_base_pong(xdg_wm_base, serial);
75} 81}
76 82
77internal void buf_write_u16(char *buf, u64 *buf_size, u64 buf_cap, 83global_variable const struct xdg_wm_base_listener wayland_xdg_wm_base_listener = {
78 u16 x) { 84 wayland_xdg_wm_base_ping,
79 Assert(*buf_size + sizeof(x) <= buf_cap); 85};
80 Assert(((size_t)buf + *buf_size) % sizeof(x) == 0); 86
87
88//- frame
89
90
91internal void wayland_frame_done(void *data, struct wl_callback *callback, u32 time_ms);
92
93global_variable const struct wl_callback_listener wayland_frame_listener = {
94wayland_frame_done,
95
96};
81 97
82 *(u16 *)(buf + *buf_size) = x;
83 *buf_size += sizeof(x);
84}
85 98
86internal void buf_write_string(char *buf, u64 *buf_size, u64 buf_cap, 99internal void wayland_frame_done(void *data, struct wl_callback *callback, u32 time_ms) {
87 char *src, u32 src_len) { 100
88 Assert(*buf_size + src_len <= buf_cap); 101WaylandState *state = (WaylandState *)data;
102wl_callback_destroy(callback);
103
104wayland_draw_weird_gradient(state);
105 struct wl_callback *next = wl_surface_frame(state->surface);
106 wl_callback_add_listener(next, &wayland_frame_listener, state);
107
108 wl_surface_attach(state->surface, state->buffer, 0, 0);
109 wl_surface_damage(state->surface, 0, 0, state->width, state->height);
110 wl_surface_commit(state->surface);
89 111
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} 112}
94 113
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 114
99 u32 res = *(u32 *)(*buf);
100 *buf += sizeof(res);
101 *buf_size -= sizeof(res);
102 115
103 return res; 116//- xdg_surface events
117
118internal void wayland_xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, u32 serial) {
119 WaylandState *state = (WaylandState *)data;
120
121 xdg_surface_ack_configure(xdg_surface, serial);
122
123 if (state->buffer == NULL) {
124 state->buffer = wayland_create_shm_buffer(state);
125wayland_draw_weird_gradient(state);
126
127 struct wl_callback *cb = wl_surface_frame(state->surface);
128 wl_callback_add_listener(cb, &wayland_frame_listener, state);
129 wl_surface_attach(state->surface, state->buffer, 0, 0);
130 wl_surface_damage(state->surface, 0, 0, state->width, state->height);
131 wl_surface_commit(state->surface);
132 }
133
134 // attach = "this buffer is the surface's content", damage = "this region changed",
135 // commit = "apply everything I sent since the last commit, atomically".
136 // a wl_surface has pending state and current state, nothing is visible until commit.
137 wl_surface_attach(state->surface, state->buffer, 0, 0);
138 wl_surface_damage(state->surface, 0, 0, state->width, state->height);
139 wl_surface_commit(state->surface);
104} 140}
105 141
106internal u16 buf_read_u16(char **buf, u64 *buf_size) { 142global_variable const struct xdg_surface_listener wayland_xdg_surface_listener = {
107 Assert(*buf_size >= sizeof(u16)); 143 wayland_xdg_surface_configure,
108 Assert((size_t)*buf % sizeof(u16) == 0); 144};
145
146
147//- xdg_toplevel events
109 148
110 u16 res = *(u16 *)(*buf); 149// TODO: handle resizing. with vulkan that means recreating the swapchain.
111 *buf += sizeof(res); 150internal void wayland_xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel,
112 *buf_size -= sizeof(res); 151 s32 width, s32 height, struct wl_array *states) {
152
153WaylandState *state = (WaylandState *)data;
154 Log("<- xdg_toplevel.configure: width=%d height=%d\n", width, height);
155state->height = height;
156state->width = width;
157
158}
113 159
114 return res; 160internal void wayland_xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel) {
161 WaylandState *state = (WaylandState *)data;
162 Log("<- xdg_toplevel.close\n");
163 state->should_close = true;
115} 164}
116 165
117internal void buf_read_n(char **buf, u64 *buf_size, char *dst, u64 n) { 166internal void wayland_xdg_toplevel_resize_edge(void *data, struct xdg_toplevel *xdg_toplevel,
118 Assert(*buf_size >= n); 167 s32 width, s32 height, struct wl_array *states) {
119 168
120 memcpy(dst, *buf, n);
121 169
122 *buf += n; 170}
123 *buf_size -= n; 171internal void wayland_xdg_toplevel_configure_bounds(void *data, struct xdg_toplevel *xdg_toplevel,
172 s32 width, s32 height) {
124} 173}
125 174
126global_variable u64 wayland_current_id = 1; 175internal void wayland_xdg_toplevel_wm_capabilities(void *data, struct xdg_toplevel *xdg_toplevel,
176 struct wl_array *capabilities) {
177}
127 178
128internal u32 wayland_wl_display_get_registry(int fd) { 179global_variable const struct xdg_toplevel_listener wayland_xdg_toplevel_listener = {
129 uint64_t msg_size = 0; 180 wayland_xdg_toplevel_configure,
130 char msg[128] = ""; 181 wayland_xdg_toplevel_close,
131 buf_write_u32(msg, &msg_size, sizeof(msg), wayland_display_object_id); 182 wayland_xdg_toplevel_configure_bounds,
183 wayland_xdg_toplevel_wm_capabilities,
184};
132 185
133 buf_write_u16(msg, &msg_size, sizeof(msg),
134 wayland_wl_display_get_registry_opcode);
135 186
136 u16 msg_announced_size = wayland_header_size + sizeof(wayland_current_id); 187//- wl_registry events
137 Assert(roundup_4(msg_announced_size) == msg_announced_size);
138 buf_write_u16(msg, &msg_size, sizeof(msg), msg_announced_size);
139 188
140 wayland_current_id++; 189internal void wayland_registry_global(void *data, struct wl_registry *registry, u32 name,
141 buf_write_u32(msg, &msg_size, sizeof(msg), wayland_current_id); 190 const char *interface, u32 version) {
191 WaylandState *state = (WaylandState *)data;
142 192
143 if ((s64)msg_size != send(fd, msg, msg_size, MSG_DONTWAIT)) 193 Log("<- wl_registry.global: name=%u interface=%s version=%u\n", name, interface, version);
144 exit(1);
145 194
146 Log("-> wl_display@%u.get_registry: wl_registry=%u\n", 195 if (CstringIsMatch(interface, wl_compositor_interface.name)) {
147 wayland_display_object_id, wayland_current_id); 196 state->compositor = (struct wl_compositor *)
197 wl_registry_bind(registry, name, &wl_compositor_interface, Min(version, 4));
198 } else if (CstringIsMatch(interface, wl_shm_interface.name)) {
199 state->shm = (struct wl_shm *)
200 wl_registry_bind(registry, name, &wl_shm_interface, 1);
201 } else if(CstringIsMatch(interface, xdg_wm_base_interface.name)) {
202 state->xdg_wm_base = (struct xdg_wm_base *)
203 wl_registry_bind(registry, name, &xdg_wm_base_interface, 1);
204 xdg_wm_base_add_listener(state->xdg_wm_base, &wayland_xdg_wm_base_listener, state);
205 } else if (CstringIsMatch(interface, wl_seat_interface.name)) {
206 state->seat = (struct wl_seat *)
207 wl_registry_bind(registry, name, &wl_seat_interface, Min(version, 5));
208 wl_seat_add_listener(state->seat, &wayland_seat_listener, state); // has the keyboard handler
209 }
210}
148 211
149 return wayland_current_id; 212internal void wayland_registry_global_remove(void *data, struct wl_registry *registry, u32 name) {
150} 213}
151 214
215global_variable const struct wl_registry_listener wayland_registry_listener = {
216 wayland_registry_global,
217 wayland_registry_global_remove,
218};
152 219
220//- entrypoint
153 221
154 internal void create_shared_memory_file(u64 size, state_t *state) { 222internal void wayland_entrypoint(MemArena *arena, LinuxWindowParams *params) {
155 char name[255] = "/"; 223
156 for (u64 index = 1; index < cstring8_length((u8 *)name); ++index) { 224 WaylandState state = {};
157 name[index] = ((double)rand()) / (double)RAND_MAX * 26 + 'a'; 225
158 } 226 state.display = wl_display_connect(NULL);
159 227 AssertLog((state.display != NULL), "failed to connect to wayland display\n");
160 int fd = shm_open(name, O_RDWR | O_EXCL | O_CREAT, 0600); 228
161 AssertLog((fd != -1), "Failed to open buffer for shared memory."); 229 // ask for the registry and listen to its global events
162 230 state.registry = wl_display_get_registry(state.display);
163 Assert(shm_unlink(name) != -1); 231 wl_registry_add_listener(state.registry, &wayland_registry_listener, &state);
164 232
165 AssertLog((ftruncate(fd, size) != -1), "Failed to truncate buffer."); 233 wl_display_roundtrip(state.display);
166 234
167 state->shm_pool_data = (u8 *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 235 AssertLog((state.compositor != NULL), "compositor has no wl_compositor\n");
168 Assert((void*)-1 != state->shm_pool_data); 236 AssertLog((state.shm != NULL), "compositor has no wl_shm\n");
169 Assert(state->shm_pool_data != NULL); 237 AssertLog((state.xdg_wm_base != NULL), "compositor has no xdg_wm_base\n");
170 state->shm_fd = fd; 238 if (state.seat == NULL) {
239 Log("no wl_seat: running without keyboard input\n");
240 }
241
242 // build the window: surface -> give it the xdg role -> make it a toplevel
243 state.surface = wl_compositor_create_surface(state.compositor);
244
245 state.xdg_surface = xdg_wm_base_get_xdg_surface(state.xdg_wm_base, state.surface);
246 xdg_surface_add_listener(state.xdg_surface, &wayland_xdg_surface_listener, &state);
247
248 state.xdg_toplevel = xdg_surface_get_toplevel(state.xdg_surface);
249 xdg_toplevel_add_listener(state.xdg_toplevel, &wayland_xdg_toplevel_listener, &state);
250 xdg_toplevel_set_title(state.xdg_toplevel, params->name);
251 xdg_toplevel_set_app_id(state.xdg_toplevel, params->name);
252
253 wl_surface_commit(state.surface);
254
255 //
256 // TODO: blocking is fine while the picture is static. for a game loop that renders
257 // every frame we'll instead use wl_display_dispatch_pending + a non blocking read
258 // (wl_display_prepare_read / wl_display_read_events with poll on wl_display_get_fd).
259 while (!state.should_close) {
260
261 if (wl_display_dispatch(state.display) == -1) {
262 Log("wayland connection lost\n");
263goto regular_exit;
264 }
265
266if(state.keys_down[KEY_W]) { Log("Move Forward"); }
267if(state.keys_down[KEY_A]) { Log("Move Left"); }
268 if(state.keys_down[KEY_D]) { Log("Move Right"); }
269 if(state.keys_down[KEY_S]) { Log("Move Back"); }
270if(state.keys_down[KEY_Q]) {
271goto cleanup_exit;
171} 272}
172 273
173 internal void wayland_handle_message(int fd, state_t *state, char **msg, 274}
174 uint64_t *msg_len) { 275
175 Assert(*msg_len >= 8); 276
176 277 cleanup_exit:
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 278
188 if (object_id == state->wl_registry && 279 if (state.keyboard) wl_keyboard_destroy(state.keyboard);
189 opcode == wayland_wl_registry_event_global) { 280 if (state.buffer) wl_buffer_destroy(state.buffer);
190 // TODO 281 if (state.pixels) munmap(state.pixels, state.size);
191 } 282 xdg_toplevel_destroy(state.xdg_toplevel);
192 // Following: Lots of `if (opcode == ...) {... } else if (opcode = ...) { ... } [...]` 283 xdg_surface_destroy(state.xdg_surface);
284 wl_surface_destroy(state.surface);
285 if (state.seat) wl_seat_destroy(state.seat);
286 xdg_wm_base_destroy(state.xdg_wm_base);
287 wl_shm_destroy(state.shm);
288 wl_compositor_destroy(state.compositor);
289 wl_registry_destroy(state.registry);
290return;
291
292regular_exit:
293return;
193} 294}
diff --git a/source/base/base_platform_linux_wayland_input.cpp b/source/base/base_platform_linux_wayland_input.cpp
new file mode 100644
index 0000000..0d66fb4
--- /dev/null
+++ b/source/base/base_platform_linux_wayland_input.cpp
@@ -0,0 +1,159 @@
1internal void wayland_keyboard_keymap(void *data, struct wl_keyboard *keyboard, u32 format, s32 fd, u32 size) {
2 Log("<- wl_keyboard.keymap: format=%u fd=%d size=%u\n", format, fd, size);
3 close(fd);
4}
5
6internal void wayland_keyboard_enter(void *data, struct wl_keyboard *keyboard, u32 serial,
7 struct wl_surface *surface, struct wl_array *keys) {
8 WaylandState *state = (WaylandState *)data;
9 Log("<- wl_keyboard.enter\n");
10
11 // wl_array is just { size_t size; size_t alloc; void *data; }. here data is a list of u32.
12 u32 *key = (u32 *)keys->data;
13 u32 key_count = keys->size / sizeof(u32);
14 for (u32 i = 0; i < key_count; ++i) {
15 if (key[i] < sizeof(state->keys_down) / sizeof(state->keys_down[0])) {
16 state->keys_down[key[i]] = true;
17 }
18 }
19}
20
21// leave: we lost focus. after this we will NOT receive release events for keys that
22// are still held, so we release everything ourselves. otherwise keys get "stuck".
23internal void wayland_keyboard_leave(void *data, struct wl_keyboard *keyboard, u32 serial,
24 struct wl_surface *surface) {
25 WaylandState *state = (WaylandState *)data;
26 Log("<- wl_keyboard.leave\n");
27
28 MemSetZero(state->keys_down, sizeof(state->keys_down));
29}
30
31internal void wayland_keyboard_key(void *data, struct wl_keyboard *keyboard, u32 serial,
32 u32 time, u32 key, u32 key_state) {
33 WaylandState *state = (WaylandState *)data;
34 b32 pressed = (key_state == WL_KEYBOARD_KEY_STATE_PRESSED);
35
36 Log("<- wl_keyboard.key: key=%u %s\n", key, pressed ? "pressed" : "released");
37
38 if (key < sizeof(state->keys_down) / sizeof(state->keys_down[0])) {
39 state->keys_down[key] = pressed;
40 }
41
42 if (key == KEY_ESC && pressed) {
43 state->should_close = true;
44 }
45}
46
47internal void wayland_keyboard_modifiers(void *data, struct wl_keyboard *keyboard, u32 serial, u32 mods_depressed, u32 mods_latched,
48 u32 mods_locked, u32 group) {
49}
50
51internal void wayland_keyboard_repeat_info(void *data, struct wl_keyboard *keyboard,
52 s32 rate, s32 delay) {
53 Log("<- wl_keyboard.repeat_info: rate=%d delay=%d\n", rate, delay);
54}
55
56// the listener: a struct of function pointers, one per event, in the order the events
57// are declared in wayland.xml (which is also their opcode). libwayland indexes into this
58// struct with the opcode it reads from the message header.
59global_variable const struct wl_keyboard_listener wayland_keyboard_listener = {
60 wayland_keyboard_keymap, // opcode 0
61 wayland_keyboard_enter, // opcode 1
62 wayland_keyboard_leave, // opcode 2
63 wayland_keyboard_key, // opcode 3
64 wayland_keyboard_modifiers, // opcode 4
65 wayland_keyboard_repeat_info, // opcode 5
66};
67
68//- mouse (pointer) input
69
70enum wayland_mouse_button_pressed: b32 {
71
72PRESSED,
73RELEASED,
74
75};
76
77internal void wayland_button_event(void *data, struct wl_pointer *pointer,
78 u32 serial, u32 time, u32 button, u32 state) {
79
80
81}
82
83
84internal void wayland_pointer_enter(void *data, struct wl_pointer *pointer,
85 u32 serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) {
86WaylandState *state = (WaylandState *)data;
87Log("<- pointer enteirng window");
88state->mouse_in_window = true;
89state->x_offset = surface_x;
90state->y_offset = surface_y;
91
92
93}
94internal void wayland_pointer_motion(void *data, struct wl_pointer *pointer, u32 time,
95 wl_fixed_t surface_x, wl_fixed_t surface_y) {
96 WaylandState *state = (WaylandState *)data;
97 state->x_offset = (f32)wl_fixed_to_double(surface_x);
98 state->y_offset = (f32)wl_fixed_to_double(surface_y);
99}
100
101internal void wayland_pointer_leave(void *data, struct wl_pointer *pointer, u32 serial, wl_surface *surface) {
102WaylandState *state = (WaylandState *)data;
103state->mouse_in_window = false;
104Log("<- pointer leaving window");
105}
106
107
108
109global_variable const struct wl_pointer_listener wayland_pointer_listener = {
110wayland_pointer_enter,
111wayland_pointer_leave,
112wayland_pointer_motion,
113 wayland_button_event,
114};
115
116
117
118
119
120//- wl_seat events
121
122// capabilities: tells us which devices this seat has, as a bitmask:
123// WL_SEAT_CAPABILITY_POINTER = 1, WL_SEAT_CAPABILITY_KEYBOARD = 2, WL_SEAT_CAPABILITY_TOUCH = 4
124// this can be sent again later (keyboard unplugged / plugged in), so we handle both directions.
125internal void wayland_seat_capabilities(void *data, struct wl_seat *seat, u32 capabilities) {
126
127 WaylandState *state = (WaylandState *)data;
128 b32 has_keyboard = (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) != 0;
129
130
131 Log("<- wl_seat.capabilities: %u\n", capabilities);
132
133 if (has_keyboard && state->keyboard == NULL) {
134 // get_keyboard is a request that creates a new object (a "new_id" argument).
135 // libwayland allocates the id, sends the message, and hands us the proxy.
136 state->keyboard = wl_seat_get_keyboard(seat);
137 wl_keyboard_add_listener(state->keyboard, &wayland_keyboard_listener, state);
138 } else if (!has_keyboard && state->keyboard != NULL) {
139 // keyboard went away: tell the compositor we're done with the object, free the proxy.
140 // the `release` request only exists since wl_seat version 3; before that we can
141 // only free our side of it with destroy.
142 if (wl_keyboard_get_version(state->keyboard) >= WL_KEYBOARD_RELEASE_SINCE_VERSION) {
143 wl_keyboard_release(state->keyboard);
144 } else {
145 wl_keyboard_destroy(state->keyboard);
146 }
147 state->keyboard = NULL;
148 }
149}
150
151// name: a human readable seat name like "seat0". only useful for multi-seat setups.
152internal void wayland_seat_name(void *data, struct wl_seat *seat, const char *name) {
153 Log("<- wl_seat.name: %s\n", name);
154}
155
156global_variable const struct wl_seat_listener wayland_seat_listener = {
157 wayland_seat_capabilities, // opcode 0
158 wayland_seat_name, // opcode 1 (since version 2)
159};
diff --git a/source/base/base_render_vulkan.cpp b/source/base/base_render_vulkan.cpp
index 9295d00..6b51fa1 100644
--- a/source/base/base_render_vulkan.cpp
+++ b/source/base/base_render_vulkan.cpp
@@ -38,7 +38,7 @@ vk_render_entrypoint(MemArena *arena, WinParams *window, Params *params)
38#endif 38#endif
39 } 39 }
40 40
41#ifdef BASE_DEBUG 41#if DEBUG
42 bool enable_validation_layer = true; 42 bool enable_validation_layer = true;
43#else 43#else
44 bool enable_validation_layer = false; 44 bool enable_validation_layer = false;
diff --git a/source/base/base_stack.cpp b/source/base/base_stack.cpp
index bf3f045..4516ae4 100644
--- a/source/base/base_stack.cpp
+++ b/source/base/base_stack.cpp
@@ -125,7 +125,7 @@ internal MemStack *stack_push_align(MemStack *stack, u64 size, u8 alignment)
125 125
126 stack->current_offset += size; 126 stack->current_offset += size;
127 127
128 return (MemStack *)MemSet((MemStack *)next_address, size); 128 return (MemStack *)MemSetZero((MemStack *)next_address, size);
129} 129}
130 130
131internal void *stack_push(MemStack *stack, u64 size) 131internal void *stack_push(MemStack *stack, u64 size)
diff --git a/source/loo/loo.cpp b/source/loo/loo.cpp
index e2de702..3a2cfef 100644
--- a/source/loo/loo.cpp
+++ b/source/loo/loo.cpp
@@ -5,30 +5,10 @@ ENTRYPOINT()
5 MemArena *arena = ArenaCreate(MiB(100)); 5 MemArena *arena = ArenaCreate(MiB(100));
6 Assert(arena); 6 Assert(arena);
7 7
8int fd = wayland_display_connect(arena); 8 LinuxWindowParams *params = PushStruct(arena, LinuxWindowParams);
9params->name = (cstring)"Loo";
9 10
10 state_t state = {0}; 11 wayland_entrypoint(arena, params);
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 12
31 return 0; 13 return 0;
32
33
34} 14}