mandelbrot-wl

mandelbrot-wl.git
git clone git://git.lenczewski.org/mandelbrot-wl.git
Log | Files | Refs

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 }