mandelbrot-wl.c (21117B)
1 #define _XOPEN_SOURCE 700 2 3 #include "mandelbrot-wl.h" 4 5 struct application { 6 /* wayland globals */ 7 struct wl_display *wl_display; 8 struct wl_registry *wl_registry; 9 struct wl_compositor *wl_compositor; 10 struct wl_seat *wl_seat; 11 struct wl_shm *wl_shm; 12 13 /* memory buffer */ 14 int wl_shm_pool_fd; 15 struct wl_shm_pool *wl_shm_pool; 16 17 /* wayland objects */ 18 struct wl_surface *wl_surface, *wl_cursor_surface; 19 struct wl_cursor_image *wl_cursor_image; 20 struct wl_pointer *wl_pointer; 21 struct wl_keyboard *wl_keyboard; 22 struct wl_touch *wl_touch; 23 24 /* xdg globals */ 25 struct xdg_wm_base *xdg_wm_base; 26 27 /* xdg objects */ 28 struct xdg_surface *xdg_surface; 29 struct xdg_toplevel *xdg_toplevel; 30 31 /* application input */ 32 struct pointer_ev pointer_ev; 33 struct xkb_context *xkb_context; 34 struct xkb_keymap *xkb_keymap; 35 struct xkb_state *xkb_state; 36 struct touch_ev touch_ev; 37 38 /* application state */ 39 b32 should_close; 40 s32 width, height; 41 f32 offset; 42 u32 last_frame; 43 }; 44 45 static void 46 wl_buffer_release(void *data, struct wl_buffer *self) { 47 (void) data; 48 49 wl_buffer_destroy(self); 50 } 51 52 static const struct wl_buffer_listener wl_buffer_listener = { 53 .release = wl_buffer_release, 54 }; 55 56 static void 57 init_shm_pool(struct application *state, u64 sz) { 58 int fd = memfd_create("buffer", 0); 59 ftruncate(fd, sz); 60 61 state->wl_shm_pool_fd = fd; 62 state->wl_shm_pool = wl_shm_create_pool(state->wl_shm, fd, sz); 63 } 64 65 static void 66 free_shm_pool(struct application *state) { 67 wl_shm_pool_destroy(state->wl_shm_pool); 68 close(state->wl_shm_pool_fd); 69 } 70 71 static struct wl_buffer * 72 draw_frame(struct application *state) { 73 const s32 stride = state->width * sizeof(pixel_argb8888_t); 74 const s32 sz = stride * state->height; 75 76 u8 *data = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, state->wl_shm_pool_fd, 0); 77 78 struct wl_buffer *buffer = wl_shm_pool_create_buffer(state->wl_shm_pool, 0, state->width, state->height, stride, WL_SHM_FORMAT_ARGB8888); 79 80 u32 *out = (u32 *)data; 81 82 s32 offset = (s32)state->offset; 83 for (s32 j = 0; j < state->height; j++) { 84 for (s32 i = 0; i < state->width; i++) { 85 u8 r = (i + offset) % 256, g = (j + offset) % 256, b = 0; 86 87 *out++ = ((pixel_argb8888_t){ .a = 255, .r = r, .g = g, .b = b, }).v; 88 } 89 } 90 91 munmap(data, sz); 92 wl_buffer_add_listener(buffer, &wl_buffer_listener, NULL); 93 94 return buffer; 95 } 96 97 static void 98 xdg_surface_configure(void *data, struct xdg_surface *self, u32 serial) { 99 struct application *state = data; 100 101 xdg_surface_ack_configure(self, serial); 102 103 struct wl_buffer *buffer = draw_frame(state); 104 wl_surface_attach(state->wl_surface, buffer, 0, 0); 105 wl_surface_commit(state->wl_surface); 106 } 107 108 static const struct xdg_surface_listener xdg_surface_listener = { 109 .configure = xdg_surface_configure, 110 }; 111 112 static void 113 xdg_wm_base_ping(void *data, struct xdg_wm_base *self, u32 serial) { 114 (void) data; 115 116 xdg_wm_base_pong(self, serial); 117 } 118 119 static const struct xdg_wm_base_listener xdg_wm_base_listener = { 120 .ping = xdg_wm_base_ping, 121 }; 122 123 static void 124 xdg_toplevel_configure_handler(void *data, struct xdg_toplevel *self, s32 width, s32 height, struct wl_array *states) { 125 (void) self; 126 (void) states; 127 128 struct application *state = data; 129 130 if (width == 0 || height == 0) { 131 return; 132 } 133 134 state->width = width; 135 state->height = height; 136 } 137 138 static void 139 xdg_toplevel_close_handler(void *data, struct xdg_toplevel *self) { 140 (void) self; 141 142 struct application *state = data; 143 144 state->should_close = true; 145 } 146 147 static void 148 xdg_toplevel_configure_bounds_handler(void *data, struct xdg_toplevel *self, s32 width, s32 height) { 149 (void) data; 150 (void) self; 151 (void) width; 152 (void) height; 153 } 154 155 static void 156 xdg_toplevel_wm_capabilities_handler(void *data, struct xdg_toplevel *self, struct wl_array *capabilities) { 157 (void) data; 158 (void) self; 159 (void) capabilities; 160 } 161 162 static const struct xdg_toplevel_listener xdg_toplevel_listener = { 163 .configure = xdg_toplevel_configure_handler, 164 .close = xdg_toplevel_close_handler, 165 .configure_bounds = xdg_toplevel_configure_bounds_handler, 166 .wm_capabilities = xdg_toplevel_wm_capabilities_handler, 167 }; 168 169 static const struct wl_callback_listener wl_surface_frame_listener; 170 171 static void 172 wl_surface_frame_done(void *data, struct wl_callback *callback, u32 time) { 173 wl_callback_destroy(callback); 174 175 struct application *state = data; 176 177 callback = wl_surface_frame(state->wl_surface); 178 wl_callback_add_listener(callback, &wl_surface_frame_listener, state); 179 180 if (state->last_frame) { 181 int elapsed = time - state->last_frame; 182 state->offset += elapsed / 1000.0 * 64; 183 } 184 185 struct wl_buffer *buffer = draw_frame(state); 186 wl_surface_attach(state->wl_surface, buffer, 0, 0); 187 wl_surface_damage_buffer(state->wl_surface, 0, 0, INT32_MAX, INT32_MAX); 188 wl_surface_commit(state->wl_surface); 189 190 state->last_frame = time; 191 } 192 193 static const struct wl_callback_listener wl_surface_frame_listener = { 194 .done = wl_surface_frame_done, 195 }; 196 197 static void 198 wl_pointer_enter(void *data, struct wl_pointer *self, u32 serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { 199 struct application *state = data; 200 201 state->pointer_ev.ev_mask |= POINTER_EV_ENTER; 202 state->pointer_ev.serial = serial; 203 state->pointer_ev.px = surface_x; 204 state->pointer_ev.py = surface_y; 205 206 wl_pointer_set_cursor(self, serial, state->wl_cursor_surface, state->wl_cursor_image->hotspot_x, state->wl_cursor_image->hotspot_y); 207 208 (void) self; 209 (void) surface; 210 } 211 212 static void 213 wl_pointer_leave(void *data, struct wl_pointer *self, u32 serial, struct wl_surface *surface) { 214 struct application *state = data; 215 216 state->pointer_ev.ev_mask |= POINTER_EV_LEAVE; 217 state->pointer_ev.serial = serial; 218 219 (void) self; 220 (void) surface; 221 } 222 223 static void 224 wl_pointer_motion(void *data, struct wl_pointer *self, u32 time, wl_fixed_t surface_x, wl_fixed_t surface_y) { 225 struct application *state = data; 226 227 state->pointer_ev.ev_mask |= POINTER_EV_MOTION; 228 state->pointer_ev.time = time; 229 state->pointer_ev.px = surface_x; 230 state->pointer_ev.py = surface_y; 231 232 (void) self; 233 } 234 235 static void 236 wl_pointer_button(void *data, struct wl_pointer *self, u32 serial, u32 time, u32 button, u32 button_state) { 237 struct application *state = data; 238 239 state->pointer_ev.ev_mask |= POINTER_EV_BUTTON; 240 state->pointer_ev.serial = serial; 241 state->pointer_ev.time = time; 242 state->pointer_ev.button = button; 243 state->pointer_ev.button_state = button_state; 244 245 (void) self; 246 } 247 248 static void 249 wl_pointer_axis(void *data, struct wl_pointer *self, u32 time, u32 axis, wl_fixed_t value) { 250 struct application *state = data; 251 252 state->pointer_ev.ev_mask |= POINTER_EV_AXIS; 253 state->pointer_ev.time = time; 254 state->pointer_ev.axes[axis].dirty = true; 255 state->pointer_ev.axes[axis].value = value; 256 257 (void) self; 258 } 259 260 static void 261 wl_pointer_axis_source(void *data, struct wl_pointer *self, u32 axis_source) { 262 struct application *state = data; 263 264 state->pointer_ev.ev_mask |= POINTER_EV_AXIS_SOURCE; 265 state->pointer_ev.axis_source = axis_source; 266 267 (void) self; 268 } 269 270 static void 271 wl_pointer_axis_stop(void *data, struct wl_pointer *self, u32 time, u32 axis) { 272 struct application *state = data; 273 274 state->pointer_ev.ev_mask |= POINTER_EV_AXIS_STOP; 275 state->pointer_ev.time = time; 276 state->pointer_ev.axes[axis].dirty = true; 277 278 (void) self; 279 } 280 281 static void 282 wl_pointer_axis_discrete(void *data, struct wl_pointer *self, u32 axis, s32 discrete) { 283 struct application *state = data; 284 285 state->pointer_ev.ev_mask |= POINTER_EV_AXIS_DISCRETE; 286 state->pointer_ev.axes[axis].dirty = true; 287 state->pointer_ev.axes[axis].discrete = discrete; 288 289 (void) self; 290 } 291 292 static void 293 wl_pointer_frame(void *data, struct wl_pointer *self) { 294 struct application *state = data; 295 struct pointer_ev *ev = &state->pointer_ev; 296 297 // fprintf(stderr, "pointer frame @ %" PRIu32 ": ", ev->time); 298 299 if (ev->ev_mask & POINTER_EV_ENTER) { 300 // fprintf(stderr, "entered %f, %f ", wl_fixed_to_double(ev->px), wl_fixed_to_double(ev->py)); 301 } 302 303 if (ev->ev_mask & POINTER_EV_LEAVE) { 304 // fprintf(stderr, "leave"); 305 } 306 307 if (ev->ev_mask & POINTER_EV_MOTION) { 308 // fprintf(stderr, "motion %f, %f ", wl_fixed_to_double(ev->px), wl_fixed_to_double(ev->py)); 309 } 310 311 if (ev->ev_mask & POINTER_EV_BUTTON) { 312 //char *button_state_name = (ev->button_state == WL_POINTER_BUTTON_STATE_RELEASED) ? "released" : "pressed"; 313 // fprintf(stderr, "button %d %s ", ev->button, button_state_name); 314 } 315 316 u32 axis_evs = POINTER_EV_AXIS | POINTER_EV_AXIS_SOURCE | POINTER_EV_AXIS_STOP | POINTER_EV_AXIS_DISCRETE; 317 if (ev->ev_mask & axis_evs) { 318 char *axis_name[] = { 319 [WL_POINTER_AXIS_VERTICAL_SCROLL] = "vertical", 320 [WL_POINTER_AXIS_HORIZONTAL_SCROLL] = "horizontal", 321 }; 322 323 char *axis_source_name[] = { 324 [WL_POINTER_AXIS_SOURCE_WHEEL] = "wheel", 325 [WL_POINTER_AXIS_SOURCE_FINGER] = "finger", 326 [WL_POINTER_AXIS_SOURCE_CONTINUOUS] = "continuous", 327 [WL_POINTER_AXIS_SOURCE_WHEEL_TILT] = "wheel tilt", 328 }; 329 330 (void) axis_name; 331 (void) axis_source_name; 332 333 for (u32 i = 0; i < ARRLEN(ev->axes); i++) { 334 if (!ev->axes[i].dirty) continue; 335 336 // fprintf(stderr, "%s axis ", axis_name[i]); 337 338 if (ev->ev_mask & POINTER_EV_AXIS) { 339 // fprintf(stderr, "value %f ", wl_fixed_to_double(ev->axes[i].value)); 340 } 341 342 if (ev->ev_mask & POINTER_EV_AXIS_DISCRETE) { 343 // fprintf(stderr, "discrete %d ", ev->axes[i].discrete); 344 } 345 346 if (ev->ev_mask & POINTER_EV_AXIS_SOURCE) { 347 // fprintf(stderr, "via %s ", axis_source_name[i]); 348 } 349 350 if (ev->ev_mask & POINTER_EV_AXIS_STOP) { 351 // fprintf(stderr, "(stopped)"); 352 } 353 } 354 } 355 356 // fprintf(stderr, "\n"); 357 memset(ev, 0, sizeof *ev); 358 359 (void) self; 360 } 361 362 static const struct wl_pointer_listener wl_pointer_listener = { 363 .enter = wl_pointer_enter, 364 .leave = wl_pointer_leave, 365 .motion = wl_pointer_motion, 366 .button = wl_pointer_button, 367 .axis = wl_pointer_axis, 368 .axis_source = wl_pointer_axis_source, 369 .axis_stop = wl_pointer_axis_stop, 370 .axis_discrete = wl_pointer_axis_discrete, 371 .frame = wl_pointer_frame, 372 }; 373 374 static void 375 wl_keyboard_keymap(void *data, struct wl_keyboard *self, u32 format, int fd, u32 size) { 376 struct application *state = data; 377 378 assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1); 379 380 char *map_shm = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); 381 assert(map_shm != MAP_FAILED); 382 383 struct xkb_keymap *xkb_keymap = xkb_keymap_new_from_string(state->xkb_context, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); 384 385 munmap(map_shm, size); 386 close(fd); 387 388 struct xkb_state *xkb_state = xkb_state_new(xkb_keymap); 389 390 xkb_keymap_unref(state->xkb_keymap); 391 xkb_state_unref(state->xkb_state); 392 393 state->xkb_keymap = xkb_keymap; 394 state->xkb_state = xkb_state; 395 396 (void) self; 397 } 398 399 static void 400 wl_keyboard_enter(void *data, struct wl_keyboard *self, u32 serial, struct wl_surface *surface, struct wl_array *keys) { 401 struct application *state = data; 402 403 // fprintf(stderr, "keyboard enter; keys pressed are:\n"); 404 405 u32 *key; 406 wl_array_for_each(key, keys) { 407 char buf[128]; 408 xkb_keysym_t sym = xkb_state_key_get_one_sym(state->xkb_state, *key + 8); 409 xkb_keysym_get_name(sym, buf, ARRLEN(buf)); 410 // fprintf(stderr, "sym: %-12s (%" PRIu32 "), ", buf, sym); 411 xkb_state_key_get_utf8(state->xkb_state, *key + 8, buf, ARRLEN(buf)); 412 // fprintf(stderr, "utf8: '%s'\n", buf); 413 } 414 415 (void) self; 416 (void) serial; 417 (void) surface; 418 } 419 420 static void 421 wl_keyboard_key(void *data, struct wl_keyboard *self, u32 serial, u32 time, u32 key, u32 key_state) { 422 struct application *state = data; 423 424 u32 keycode = key + 8; 425 xkb_keysym_t keysym = xkb_state_key_get_one_sym(state->xkb_state, keycode); 426 427 char buf[128]; 428 xkb_keysym_get_name(keysym, buf, ARRLEN(buf)); 429 430 //char *action = (key_state == WL_KEYBOARD_KEY_STATE_PRESSED) ? "pressed" : "released"; 431 // fprintf(stderr, "key %s: sym: %-12s (%" PRIu32 "), ", action, buf, keycode); 432 433 xkb_state_key_get_utf8(state->xkb_state, keycode, buf, ARRLEN(buf)); 434 // fprintf(stderr, "utf8: '%s'\n", buf); 435 436 (void) self; 437 (void) serial; 438 (void) time; 439 (void) key_state; 440 } 441 442 static void 443 wl_keyboard_leave(void *data, struct wl_keyboard *self, u32 serial, struct wl_surface *surface) { 444 // fprintf(stderr, "keyboard leave\n"); 445 446 (void) data; 447 (void) self; 448 (void) serial; 449 (void) surface; 450 } 451 452 static void 453 wl_keyboard_modifiers(void *data, struct wl_keyboard *self, u32 serial, u32 modifiers_depressed, u32 modifiers_latched, u32 modifiers_locked, u32 group) { 454 struct application *state = data; 455 456 xkb_state_update_mask(state->xkb_state, modifiers_depressed, modifiers_latched, modifiers_locked, 0, 0, group); 457 458 (void) self; 459 (void) serial; 460 } 461 462 static void 463 wl_keyboard_repeat_info(void *data, struct wl_keyboard *self, s32 rate, s32 delay) { 464 (void) data; 465 (void) self; 466 (void) rate; 467 (void) delay; 468 } 469 470 static const struct wl_keyboard_listener wl_keyboard_listener = { 471 .keymap = wl_keyboard_keymap, 472 .enter = wl_keyboard_enter, 473 .key = wl_keyboard_key, 474 .leave = wl_keyboard_leave, 475 .modifiers = wl_keyboard_modifiers, 476 .repeat_info = wl_keyboard_repeat_info, 477 }; 478 479 static struct touch_point * 480 get_touch_point(struct application *state, s32 touch_id) { 481 struct touch_ev *ev = &state->touch_ev; 482 483 u32 first_dirty = 0; 484 for (u32 i = 0; i < ARRLEN(ev->points); i++) { 485 if (ev->points[i].id == touch_id) return &ev->points[i]; 486 487 if (first_dirty == ARRLEN(ev->points) && !ev->points[i].dirty) 488 first_dirty = i; 489 } 490 491 if (first_dirty == ARRLEN(ev->points)) return NULL; 492 493 ev->points[first_dirty].dirty = true; 494 ev->points[first_dirty].id = touch_id; 495 return &ev->points[first_dirty]; 496 497 return NULL; 498 } 499 500 static void 501 wl_touch_down(void *data, struct wl_touch *self, u32 serial, u32 time, struct wl_surface *surface, s32 id, wl_fixed_t x, wl_fixed_t y) { 502 struct application *state = data; 503 504 struct touch_point *point = get_touch_point(state, id); 505 if (!point) return; 506 507 point->ev_mask |= TOUCH_EV_DOWN; 508 point->px = x; 509 point->py = y; 510 state->touch_ev.serial = serial; 511 state->touch_ev.time = time; 512 513 (void) self; 514 (void) surface; 515 } 516 517 static void 518 wl_touch_up(void *data, struct wl_touch *self, u32 serial, u32 time, s32 id) { 519 struct application *state = data; 520 521 struct touch_point *point = get_touch_point(state, id); 522 if (!point) return; 523 524 point->ev_mask |= TOUCH_EV_UP; 525 state->touch_ev.serial = serial; 526 state->touch_ev.time = time; 527 528 (void) self; 529 } 530 531 static void 532 wl_touch_motion(void *data, struct wl_touch *self, u32 time, s32 id, wl_fixed_t x, wl_fixed_t y) { 533 struct application *state = data; 534 535 struct touch_point *point = get_touch_point(state, id); 536 if (!point) return; 537 538 point->ev_mask |= TOUCH_EV_MOTION; 539 point->px = x; 540 point->py = y; 541 state->touch_ev.time = time; 542 543 (void) self; 544 } 545 546 static void 547 wl_touch_cancel(void *data, struct wl_touch *self) { 548 struct application *state = data; 549 550 state->touch_ev.ev_mask |= TOUCH_EV_CANCEL; 551 552 (void) self; 553 } 554 555 static void 556 wl_touch_shape(void *data, struct wl_touch *self, s32 id, wl_fixed_t major, wl_fixed_t minor) { 557 struct application *state = data; 558 559 struct touch_point *point = get_touch_point(state, id); 560 if (!point) return; 561 562 point->ev_mask |= TOUCH_EV_SHAPE; 563 point->major = major; 564 point->minor = minor; 565 566 (void) self; 567 } 568 569 static void 570 wl_touch_orientation(void *data, struct wl_touch *self, s32 id, wl_fixed_t orientation) { 571 struct application *state = data; 572 573 struct touch_point *point = get_touch_point(state, id); 574 if (!point) return; 575 576 point->ev_mask |= TOUCH_EV_ORIENTATION; 577 point->orientation = orientation; 578 579 (void) self; 580 } 581 582 static void 583 wl_touch_frame(void *data, struct wl_touch *self) { 584 struct application *state = data; 585 586 struct touch_ev *ev = &state->touch_ev; 587 // fprintf(stderr, "touch event @ %" PRIu32 ":\n", ev->time); 588 589 // TODO: handle cancelled touch events 590 // TODO: test out touch input logic 591 592 for (u32 i = 0; i < ARRLEN(ev->points); i++) { 593 struct touch_point *point = &ev->points[i]; 594 if (!point->dirty) continue; 595 596 // fprintf(stderr, "point %" PRIi32 ": ", point->id); 597 598 if (point->ev_mask & TOUCH_EV_DOWN) { 599 // fprintf(stderr, "down %f, %f ", wl_fixed_to_double(point->px), wl_fixed_to_double(point->py)); 600 } 601 602 if (point->ev_mask & TOUCH_EV_UP) { 603 // fprintf(stderr, "up "); 604 } 605 606 if (point->ev_mask & TOUCH_EV_MOTION) { 607 // fprintf(stderr, "motion %f, %f ", wl_fixed_to_double(point->px), wl_fixed_to_double(point->py)); 608 } 609 610 if (point->ev_mask & TOUCH_EV_SHAPE) { 611 // fprintf(stderr, "shape %fx%f ", wl_fixed_to_double(point->major), wl_fixed_to_double(point->minor)); 612 } 613 614 if (point->ev_mask & TOUCH_EV_ORIENTATION) { 615 // fprintf(stderr, "orientation %f ", wl_fixed_to_double(point->orientation)); 616 } 617 618 point->dirty = 0; 619 // fprintf(stderr, "\n"); 620 } 621 622 (void) self; 623 } 624 625 static const struct wl_touch_listener wl_touch_listener = { 626 .down = wl_touch_down, 627 .up = wl_touch_up, 628 .motion = wl_touch_motion, 629 .cancel = wl_touch_cancel, 630 .shape = wl_touch_shape, 631 .orientation = wl_touch_orientation, 632 .frame = wl_touch_frame, 633 }; 634 635 static void 636 wl_seat_capabilities(void *data, struct wl_seat *self, u32 capabilities) { 637 struct application *state = data; 638 639 b32 have_pointer = capabilities & WL_SEAT_CAPABILITY_POINTER; 640 b32 have_keyboard = capabilities & WL_SEAT_CAPABILITY_KEYBOARD; 641 b32 have_touch = capabilities & WL_SEAT_CAPABILITY_TOUCH; 642 643 if (have_pointer && !state->wl_pointer) { 644 state->wl_pointer = wl_seat_get_pointer(self); 645 wl_pointer_add_listener(state->wl_pointer, &wl_pointer_listener, state); 646 } else if (!have_pointer && state->wl_pointer) { 647 wl_pointer_release(state->wl_pointer); 648 state->wl_pointer = NULL; 649 } 650 651 if (have_keyboard && !state->wl_keyboard) { 652 state->wl_keyboard = wl_seat_get_keyboard(self); 653 wl_keyboard_add_listener(state->wl_keyboard, &wl_keyboard_listener, state); 654 } else if (!have_keyboard && state->wl_keyboard) { 655 wl_keyboard_release(state->wl_keyboard); 656 state->wl_keyboard = NULL; 657 } 658 659 if (have_touch && !state->wl_touch) { 660 state->wl_touch = wl_seat_get_touch(self); 661 wl_touch_add_listener(state->wl_touch, &wl_touch_listener, state); 662 } else if (!have_touch && state->wl_touch) { 663 wl_touch_release(state->wl_touch); 664 state->wl_touch = NULL; 665 } 666 } 667 668 static void 669 wl_seat_name(void *data, struct wl_seat *self, char const *name) { 670 (void) data; 671 (void) self; 672 (void) name; 673 } 674 675 static const struct wl_seat_listener wl_seat_listener = { 676 .capabilities = wl_seat_capabilities, 677 .name = wl_seat_name, 678 }; 679 680 static void 681 wl_registry_global(void *data, struct wl_registry *self, u32 name, char const *interface, u32 version) { 682 struct application *state = data; 683 684 if (strcmp(interface, wl_compositor_interface.name) == 0) { 685 state->wl_compositor = wl_registry_bind(self, name, &wl_compositor_interface, version); 686 } else if (strcmp(interface, wl_seat_interface.name) == 0) { 687 state->wl_seat = wl_registry_bind(self, name, &wl_seat_interface, version); 688 wl_seat_add_listener(state->wl_seat, &wl_seat_listener, state); 689 } else if (strcmp(interface, wl_shm_interface.name) == 0) { 690 state->wl_shm = wl_registry_bind(self, name, &wl_shm_interface, version); 691 } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { 692 state->xdg_wm_base = wl_registry_bind(self, name, &xdg_wm_base_interface, version); 693 xdg_wm_base_add_listener(state->xdg_wm_base, &xdg_wm_base_listener, state); 694 } 695 } 696 697 static void 698 wl_registry_global_remove(void *data, struct wl_registry *self, u32 name) { 699 (void) data; 700 (void) self; 701 (void) name; 702 } 703 704 static const struct wl_registry_listener wl_registry_listener = { 705 .global = wl_registry_global, 706 .global_remove = wl_registry_global_remove, 707 }; 708 709 int main(int argc, char **argv) { 710 (void) argc; 711 (void) argv; 712 713 struct application state = { .width = 640, .height = 480, }; 714 715 state.wl_display = wl_display_connect(NULL); 716 717 state.wl_registry = wl_display_get_registry(state.wl_display); 718 wl_registry_add_listener(state.wl_registry, &wl_registry_listener, &state); 719 720 state.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); 721 722 wl_display_roundtrip(state.wl_display); 723 724 if (!state.wl_compositor || !state.wl_seat || !state.wl_shm || !state.xdg_wm_base) { 725 fprintf(stderr, "Failed to register required globals!\n"); 726 exit(EXIT_FAILURE); 727 } 728 729 init_shm_pool(&state, WL_SHM_POOL_SZ); 730 731 state.wl_surface = wl_compositor_create_surface(state.wl_compositor); 732 733 struct wl_cursor_theme *cursor_theme = wl_cursor_theme_load(NULL, 24, state.wl_shm); 734 struct wl_cursor *cursor = wl_cursor_theme_get_cursor(cursor_theme, "left_ptr"); 735 state.wl_cursor_image = cursor->images[0]; 736 struct wl_buffer *cursor_buffer = wl_cursor_image_get_buffer(state.wl_cursor_image); 737 738 state.wl_cursor_surface = wl_compositor_create_surface(state.wl_compositor); 739 wl_surface_attach(state.wl_cursor_surface, cursor_buffer, 0, 0); 740 wl_surface_commit(state.wl_cursor_surface); 741 742 state.xdg_surface = xdg_wm_base_get_xdg_surface(state.xdg_wm_base, state.wl_surface); 743 xdg_surface_add_listener(state.xdg_surface, &xdg_surface_listener, &state); 744 745 state.xdg_toplevel = xdg_surface_get_toplevel(state.xdg_surface); 746 xdg_toplevel_add_listener(state.xdg_toplevel, &xdg_toplevel_listener, &state); 747 xdg_toplevel_set_title(state.xdg_toplevel, "mandelbrot-wl"); 748 wl_surface_commit(state.wl_surface); 749 750 struct wl_callback *callback = wl_surface_frame(state.wl_surface); 751 wl_callback_add_listener(callback, &wl_surface_frame_listener, &state); 752 753 do { 754 wl_display_dispatch(state.wl_display); 755 } while (!state.should_close); 756 757 free_shm_pool(&state); 758 759 return 0; 760 }