wayland-mandelbrot.c (11930B)
1 #include "wayland-mandelbrot.h" 2 #include "mandelbrot.h" 3 4 static bool should_close = false; 5 6 #define WIDTH 512 7 #define HEIGHT 512 8 #define ITERS 255 9 10 #define PIXEL_ARGB8888_BUFFER_SIZE WIDTH * HEIGHT * sizeof(pixel_argb8888_t) 11 12 static const struct viewrect view = { 13 .x0 = -2.0, 14 .y0 = -1.5, 15 .x1 = +1.2, 16 .y1 = +1.5, 17 }; 18 19 static const struct drawrect draw = { 20 .width = WIDTH, 21 .height = HEIGHT, 22 .maxiters = ITERS, 23 .x0 = 0, 24 .y0 = 0, 25 .x1 = WIDTH - 1, 26 .y1 = HEIGHT - 1, 27 }; 28 29 static pixel_p8_t pix[WIDTH * HEIGHT]; 30 31 static pixel_argb8888_t pal[UINT8_MAX]; 32 33 static void 34 init_palette() { 35 for (size_t i = 0; i < UINT8_MAX; i++) { 36 if (i < ITERS) { 37 u8 v = scaleu8((f32)i / (f32)ITERS, 0x0, 0xff); 38 pal[i] = pixel_argb8888(0xff, v, v, v); 39 } else { 40 pal[i] = pixel_argb8888(0xff, 0, 0, 0); 41 } 42 } 43 } 44 45 static struct xkb_context *xkb_context = NULL; 46 static struct xkb_keymap *xkb_keymap = NULL; 47 static struct xkb_state *xkb_state = NULL; 48 49 static struct wl_compositor *compositor = NULL; 50 static struct wl_seat *seat = NULL; 51 static struct wl_shm *shm = NULL; 52 static struct wl_shm_pool *shm_pool = NULL; 53 static struct wl_buffer *buffer = NULL; 54 55 static struct wl_surface *surface = NULL; 56 57 static struct wl_surface *cursor_surface = NULL; 58 static struct wl_cursor_image *cursor_image = NULL; 59 60 static struct wl_pointer *pointer = NULL; 61 static struct wl_keyboard *keyboard = NULL; 62 63 static struct xdg_wm_base *xdg_wm_base = NULL; 64 static struct xdg_surface *xdg_surface = NULL; 65 static struct xdg_toplevel *xdg_toplevel = NULL; 66 67 static void 68 wl_registry_global_handler(void *data, struct wl_registry *registry, u32 name, char const *interface, u32 version) { 69 (void) data; 70 71 printf("Interface: '%s', version: %u, name: %u\n", interface, version, name); 72 73 if (strcmp(interface, "wl_compositor") == 0) { 74 compositor = wl_registry_bind(registry, name, &wl_compositor_interface, version); 75 } else if (strcmp(interface, "wl_seat") == 0) { 76 seat = wl_registry_bind(registry, name, &wl_seat_interface, version); 77 } else if (strcmp(interface, "wl_shm") == 0) { 78 shm = wl_registry_bind(registry, name, &wl_shm_interface, version); 79 } else if (strcmp(interface, "xdg_wm_base") == 0) { 80 xdg_wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, version); 81 } 82 } 83 84 static void 85 wl_registry_global_remove_handler(void *data, struct wl_registry *registry, u32 name) { 86 (void) data; 87 (void) registry; 88 89 printf("Removed: %u\n", name); 90 } 91 92 static const struct wl_registry_listener registry_listener = { 93 .global = wl_registry_global_handler, 94 .global_remove = wl_registry_global_remove_handler, 95 }; 96 97 static void 98 wl_pointer_enter_handler(void *data, struct wl_pointer *pointer, u32 serial, struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y) { 99 (void) data; 100 (void) surface; 101 (void) x; 102 (void) y; 103 104 wl_pointer_set_cursor(pointer, serial, cursor_surface, cursor_image->hotspot_x, cursor_image->hotspot_y); 105 } 106 107 static void 108 wl_pointer_leave_handler(void *data, struct wl_pointer *pointer, u32 serial, struct wl_surface *surface) { 109 (void) data; 110 (void) pointer; 111 (void) serial; 112 (void) surface; 113 } 114 115 static void 116 wl_pointer_motion_handler(void *data, struct wl_pointer *pointer, u32 time, wl_fixed_t x, wl_fixed_t y) { 117 (void) data; 118 (void) pointer; 119 (void) time; 120 (void) x; 121 (void) y; 122 } 123 124 static void 125 wl_pointer_button_handler(void *data, struct wl_pointer *pointer, u32 serial, u32 time, u32 button, u32 state) { 126 (void) data; 127 (void) pointer; 128 (void) serial; 129 (void) time; 130 131 printf("button: %" PRIu32 ", state: %" PRIu32"\n", button, state); 132 } 133 134 static void 135 wl_pointer_axis_handler(void *data, struct wl_pointer *pointer, u32 time, u32 axis, wl_fixed_t value) { 136 (void) data; 137 (void) pointer; 138 (void) time; 139 (void) axis; 140 (void) value; 141 } 142 143 static void 144 wl_pointer_frame_handler(void *data, struct wl_pointer *pointer) { 145 (void) data; 146 (void) pointer; 147 } 148 149 static void 150 wl_pointer_axis_source_handler(void *data, struct wl_pointer *pointer, u32 axis_source) { 151 (void) data; 152 (void) pointer; 153 (void) axis_source; 154 } 155 156 static void 157 wl_pointer_axis_stop_handler(void *data, struct wl_pointer *pointer, u32 time, u32 axis) { 158 (void) data; 159 (void) pointer; 160 (void) time; 161 (void) axis; 162 } 163 164 static void 165 wl_pointer_axis_discrete_handler(void *data, struct wl_pointer *pointer, u32 axis, wl_fixed_t discrete) { 166 (void) data; 167 (void) pointer; 168 (void) axis; 169 (void) discrete; 170 } 171 172 static void 173 wl_pointer_axis_value120_handler(void *data, struct wl_pointer *pointer, u32 axis, wl_fixed_t discrete) { 174 (void) data; 175 (void) pointer; 176 (void) axis; 177 (void) discrete; 178 } 179 180 static void 181 wl_pointer_axis_relative_direction_handler(void *data, struct wl_pointer *pointer, u32 axis, u32 direction) { 182 (void) data; 183 (void) pointer; 184 (void) axis; 185 (void) direction; 186 } 187 188 static const struct wl_pointer_listener wl_pointer_listener = { 189 .enter = wl_pointer_enter_handler, 190 .leave = wl_pointer_leave_handler, 191 .motion = wl_pointer_motion_handler, 192 .button = wl_pointer_button_handler, 193 .axis = wl_pointer_axis_handler, 194 .frame = wl_pointer_frame_handler, 195 .axis_source = wl_pointer_axis_source_handler, 196 .axis_stop = wl_pointer_axis_stop_handler, 197 .axis_discrete = wl_pointer_axis_discrete_handler, 198 .axis_value120 = wl_pointer_axis_value120_handler, 199 .axis_relative_direction = wl_pointer_axis_relative_direction_handler, 200 }; 201 202 static void 203 wl_keyboard_keymap_handler(void *data, struct wl_keyboard *keyboard, u32 format, wl_fixed_t fd, u32 size) { 204 (void) data; 205 (void) keyboard; 206 207 assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1); 208 209 char *map_shm = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); 210 assert(map_shm != MAP_FAILED); 211 212 xkb_keymap = xkb_keymap_new_from_string(xkb_context, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); 213 xkb_state = xkb_state_new(xkb_keymap); 214 215 munmap(map_shm, size); 216 close(fd); 217 } 218 219 static void 220 wl_keyboard_enter_handler(void *data, struct wl_keyboard *keyboard, u32 serial, struct wl_surface *surface, struct wl_array *keys) { 221 (void) data; 222 (void) keyboard; 223 (void) serial; 224 (void) surface; 225 (void) keys; 226 } 227 228 static void 229 wl_keyboard_leave_handler(void *data, struct wl_keyboard *keyboard, u32 serial, struct wl_surface *surface) { 230 (void) data; 231 (void) keyboard; 232 (void) serial; 233 (void) surface; 234 } 235 236 static void 237 wl_keyboard_key_handler(void *data, struct wl_keyboard *keyboard, u32 serial, u32 time, u32 key, u32 state) { 238 (void) data; 239 (void) keyboard; 240 (void) serial; 241 (void) time; 242 243 xkb_keysym_t sym = xkb_state_key_get_one_sym(xkb_state, key + 8); 244 245 char sym_name[128]; 246 xkb_keysym_get_name(sym, sym_name, sizeof sym_name); 247 248 printf("key: %" PRIu32 ", state: %" PRIu32", sym: %" PRIu32 " (%s)\n", key, state, sym, sym_name); 249 250 if (sym == XKB_KEY_Escape) { 251 printf("Pressed the 'Escape' key\n"); 252 should_close = true; 253 } 254 } 255 256 static void 257 wl_keyboard_modifiers_handler(void *data, struct wl_keyboard *keyboard, u32 serial, u32 mods_depressed, u32 mods_latched, u32 mods_locked, u32 group) { 258 (void) data; 259 (void) keyboard; 260 (void) serial; 261 (void) mods_depressed; 262 (void) mods_latched; 263 (void) mods_locked; 264 (void) group; 265 } 266 267 static void 268 wl_keyboard_repeat_info_handler(void *data, struct wl_keyboard *keyboard, wl_fixed_t rate, wl_fixed_t delay) { 269 (void) data; 270 (void) keyboard; 271 (void) rate; 272 (void) delay; 273 } 274 275 static const struct wl_keyboard_listener wl_keyboard_listener = { 276 .keymap = wl_keyboard_keymap_handler, 277 .enter = wl_keyboard_enter_handler, 278 .leave = wl_keyboard_leave_handler, 279 .key = wl_keyboard_key_handler, 280 .modifiers = wl_keyboard_modifiers_handler, 281 .repeat_info = wl_keyboard_repeat_info_handler, 282 }; 283 284 static void 285 xdg_wm_base_ping_handler(void *data, struct xdg_wm_base *wm_base, u32 serial) { 286 (void) data; 287 288 xdg_wm_base_pong(wm_base, serial); 289 } 290 291 static const struct xdg_wm_base_listener xdg_wm_base_listener = { 292 .ping = xdg_wm_base_ping_handler, 293 }; 294 295 static void 296 xdg_surface_configure_handler(void *data, struct xdg_surface *surface, u32 serial) { 297 (void) data; 298 299 xdg_surface_ack_configure(surface, serial); 300 } 301 302 static const struct xdg_surface_listener xdg_surface_listener = { 303 .configure = xdg_surface_configure_handler, 304 }; 305 306 static void 307 xdg_toplevel_configure_handler(void *data, struct xdg_toplevel *toplevel, s32 width, s32 height, struct wl_array *states) { 308 (void) data; 309 (void) toplevel; 310 (void) width; 311 (void) height; 312 (void) states; 313 } 314 315 static void 316 xdg_toplevel_close_handler(void *data, struct xdg_toplevel *toplevel) { 317 (void) data; 318 (void) toplevel; 319 320 should_close = true; 321 } 322 323 static void 324 xdg_toplevel_configure_bounds_handler(void *data, struct xdg_toplevel *toplevel, s32 width, s32 height) { 325 (void) data; 326 (void) toplevel; 327 (void) width; 328 (void) height; 329 } 330 331 static void 332 xdg_toplevel_wm_capabilities_handler(void *data, struct xdg_toplevel *toplevel, struct wl_array *capabilities) { 333 (void) data; 334 (void) toplevel; 335 (void) capabilities; 336 } 337 338 static const struct xdg_toplevel_listener xdg_toplevel_listener = { 339 .configure = xdg_toplevel_configure_handler, 340 .close = xdg_toplevel_close_handler, 341 .configure_bounds = xdg_toplevel_configure_bounds_handler, 342 .wm_capabilities = xdg_toplevel_wm_capabilities_handler, 343 }; 344 345 s32 346 main(s32 argc, char **argv) { 347 (void) argc; 348 (void) argv; 349 350 init_palette(); 351 352 printf("Initialised palette!\n"); 353 354 mandelbrot_render(view, draw, pix); 355 356 printf("Rendered mandelbrot set!\n"); 357 358 xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); 359 360 struct wl_display *display = wl_display_connect(NULL); 361 if (!display) { 362 fprintf(stderr, "Failed to connect to wayland display!\n"); 363 return 1; 364 } 365 366 printf("Connected to wayland display!\n"); 367 368 struct wl_registry *registry = wl_display_get_registry(display); 369 wl_registry_add_listener(registry, ®istry_listener, NULL); 370 371 wl_display_roundtrip(display); 372 373 if (!compositor || !seat || !shm || !xdg_wm_base) { 374 fprintf(stderr, "Failed to bind required wayland registry globals!\n"); 375 return 1; 376 } 377 378 pointer = wl_seat_get_pointer(seat); 379 wl_pointer_add_listener(pointer, &wl_pointer_listener, NULL); 380 381 keyboard = wl_seat_get_keyboard(seat); 382 wl_keyboard_add_listener(keyboard, &wl_keyboard_listener, NULL); 383 384 xdg_wm_base_add_listener(xdg_wm_base, &xdg_wm_base_listener, NULL); 385 386 surface = wl_compositor_create_surface(compositor); 387 388 xdg_surface = xdg_wm_base_get_xdg_surface(xdg_wm_base, surface); 389 xdg_surface_add_listener(xdg_surface, &xdg_surface_listener, NULL); 390 391 xdg_toplevel = xdg_surface_get_toplevel(xdg_surface); 392 xdg_toplevel_add_listener(xdg_toplevel, &xdg_toplevel_listener, NULL); 393 xdg_toplevel_set_title(xdg_toplevel, "mandelbrot-wl"); 394 395 wl_surface_commit(surface); 396 397 size_t stride = WIDTH * sizeof(pixel_argb8888_t); 398 size_t size = PIXEL_ARGB8888_BUFFER_SIZE; 399 400 int mempool_fd = memfd_create("buffer", 0); 401 ftruncate(mempool_fd, size); 402 403 u8 *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, mempool_fd, 0); 404 (void) data; 405 406 shm_pool = wl_shm_create_pool(shm, mempool_fd, size); 407 if (!shm_pool) { 408 fprintf(stderr, "Failed to create shared memory pool of size %zu!\n", size); 409 return 1; 410 } 411 412 buffer = wl_shm_pool_create_buffer(shm_pool, 0, WIDTH, HEIGHT, stride, WL_SHM_FORMAT_ARGB8888); 413 if (!buffer) { 414 fprintf(stderr, "Failed to create buffer!\n"); 415 return 1; 416 } 417 418 u32 *out = (u32 *)data; 419 for (size_t j = 0; j < HEIGHT; j++) { 420 for (size_t i = 0; i < WIDTH; i++) { 421 *out++ = pal[pix[(j * WIDTH) + i]]; 422 } 423 } 424 425 struct wl_cursor_theme *cursor_theme = wl_cursor_theme_load(NULL, 24, shm); 426 struct wl_cursor *cursor = wl_cursor_theme_get_cursor(cursor_theme, "left_ptr"); 427 cursor_image = cursor->images[0]; 428 struct wl_buffer *cursor_buffer = wl_cursor_image_get_buffer(cursor_image); 429 430 cursor_surface = wl_compositor_create_surface(compositor); 431 432 wl_display_roundtrip(display); 433 434 wl_surface_attach(surface, buffer, 0, 0); 435 wl_surface_commit(surface); 436 437 wl_surface_attach(cursor_surface, cursor_buffer, 0, 0); 438 wl_surface_commit(cursor_surface); 439 440 do { 441 wl_display_dispatch(display); 442 } while (!should_close); 443 444 wl_display_disconnect(display); 445 446 printf("Disconnected from wayland display!\n"); 447 448 return 0; 449 }