~hp/d2tk

afa06021c23e8964623a7db6a56439edd23758e1 — Hanspeter Portner a month ago 5fb9373
base: add d2tk_base_wait_on_fd function and atom

This is handy to poll for arbitrary user-defined file descriptors.
5 files changed, 160 insertions(+), 12 deletions(-)

M d2tk/base.h
M example/d2tk_wayland_dock.c
M meson_options.txt
M src/base.c
M src/base_internal.h
M d2tk/base.h => d2tk/base.h +3 -0
@@ 302,6 302,9 @@ d2tk_pane_get_rect(d2tk_pane_t *pane);
		d2tk_pane_not_end((PANE)); \
		(PANE) = d2tk_pane_next((PANE)))

D2TK_API int
d2tk_base_wake_on_fd(d2tk_base_t *base, d2tk_id_t id, int fd);

D2TK_API void
d2tk_clip_int32(int32_t min, int32_t *value, int32_t max);


M example/d2tk_wayland_dock.c => example/d2tk_wayland_dock.c +101 -5
@@ 3,8 3,14 @@
 * SPDX-License-Identifier: Artistic-2.0
 */

#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <stdatomic.h>
#include <string.h>
#include <sys/eventfd.h>
#include <unistd.h>

#include <d2tk/frontend_wayland.h>



@@ 13,6 19,10 @@ typedef struct _app_t app_t;
struct _app_t {
	d2tk_frontend_t *dwayland;
	bool vertical;
	int fd [2];
	uint64_t counter [2];
	pthread_t thread [2];
	atomic_uint idx;
};

static sig_atomic_t done = false;


@@ 23,25 33,97 @@ _sig(int signum __attribute__((unused)))
	done = true;
}

static inline void
static void *
_thread(void *data)
{
	app_t *app = data;
	const unsigned i = atomic_fetch_add(&app->idx, 1);
	uint64_t counter = 0;

	while(!done)
	{
		const ssize_t sz = write(app->fd[i], &counter, sizeof(counter));
		switch(sz)
		{
			case -1:
				if(errno != EAGAIN)
				{
					fprintf(stderr, "[%s] write failed: %s\n", __func__, strerror(errno));
				}
				break;
			case sizeof(counter):
				counter++;
				break;
			default:
				fprintf(stderr, "[%s] write only %zi/8\n", __func__, sz);
				break;
		}

		sleep(i + 1);
	}

	return NULL;
}

static void
_expose_dock(app_t *app, d2tk_flag_t flag, const d2tk_rect_t *rect)
{
	d2tk_base_t *base = d2tk_frontend_get_base(app->dwayland);

	for(unsigned i = 0; i < 2; i++)
	{
		uint64_t counter = 0;
		const ssize_t sz = read(app->fd[i], &counter, sizeof(counter));
		switch(sz)
		{
			case -1:
				if(errno != EAGAIN)
				{
					fprintf(stderr, "[%s] read failed: %s\n", __func__, strerror(errno));
				}
				break;
			case sizeof(counter):
				app->counter[i] = counter;
				break;
			default:
				fprintf(stderr, "[%s] read only %zi/8\n", __func__, sz);
				break;
		}

		d2tk_base_wake_on_fd(base, D2TK_ID_IDX(i), app->fd[i]);
	}

	const d2tk_coord_t frac [8] = { 1, 1, 1, 4, 4, 1, 1, 1 };
	D2TK_BASE_LAYOUT(rect, 8, frac, flag, lay)
	{
		const d2tk_rect_t *lrect = d2tk_layout_get_rect(lay);
		const unsigned k = d2tk_layout_get_index(lay);

		if(d2tk_base_button_is_changed(base, D2TK_ID_IDX(k), lrect))
		if(k == 0)
		{
			fprintf(stderr, "press: %u\n", k);
			char lbl [32];
			const size_t lbl_len = snprintf(lbl, sizeof(lbl), "%"PRIu64, app->counter[0]);
			
			d2tk_base_label(base, lbl_len, lbl, 0.7f, lrect, D2TK_ALIGN_CENTERED);
		}
		else if(k == 7)
		{
			char lbl [32];
			const size_t lbl_len = snprintf(lbl, sizeof(lbl), "%"PRIu64, app->counter[1]);
			
			d2tk_base_label(base, lbl_len, lbl, 0.7f, lrect, D2TK_ALIGN_CENTERED);
		}
		else
		{
			if(d2tk_base_button_is_changed(base, D2TK_ID_IDX(k), lrect))
			{
				fprintf(stderr, "press: %u\n", k);
			}
		}
	}
}

static inline int
static int
_expose(void *data, d2tk_coord_t w, d2tk_coord_t h)
{
	app_t *app = data;


@@ 60,6 142,8 @@ main(int argc, char **argv)
{
	static app_t app;

	atomic_init(&app.idx, 0);

	const char *namespace = "wlroots";
	d2tk_coord_t w = 600;
	d2tk_coord_t h = 32;


@@ 204,6 288,12 @@ main(int argc, char **argv)
	signal(SIGQUIT, _sig);
	signal(SIGKILL, _sig);

	for(unsigned i = 0; i < 2; i++)
	{
		app.fd[i] = eventfd(0, EFD_NONBLOCK);
		pthread_create(&app.thread[i], NULL, _thread, &app);
	}

	app.dwayland = d2tk_wayland_new(&config);
	if(app.dwayland)
	{


@@ 214,5 304,11 @@ main(int argc, char **argv)
		return EXIT_SUCCESS;
	}

	for(unsigned i = 0; i < 2; i++)
	{
		pthread_join(app.thread[i], NULL);
		close(app.fd[i]);
	}

	return EXIT_FAILURE;
}

M meson_options.txt => meson_options.txt +1 -1
@@ 51,4 51,4 @@ option('use-vterm',
	value : 'disabled',
	yield : true)

option('version', type : 'string', value : '0.9.95')
option('version', type : 'string', value : '0.9.97')

M src/base.c => src/base.c +53 -4
@@ 12,6 12,14 @@

#include "base_internal.h"

typedef struct _d2tk_atom_body_fd_t d2tk_atom_body_fd_t;

struct _d2tk_atom_body_fd_t {
	int fd;
};

const size_t d2tk_atom_body_fd_sz = sizeof(d2tk_atom_body_fd_t);

static inline d2tk_id_t
_d2tk_flip_get_cur(d2tk_flip_t *flip)
{


@@ 123,10 131,10 @@ _d2tk_base_get_atom(d2tk_base_t *base, d2tk_id_t id, d2tk_atom_type_t type,
					len = d2tk_atom_body_lineedit_sz;
				} break;
#endif
				case D2TK_ATOM_FLOW_NODE:
					// fall-through
				case D2TK_ATOM_FLOW_ARC:
					// fall-through
				case D2TK_ATOM_FD:
				{
					len = d2tk_atom_body_fd_sz;
				} break;
				default:
				{
					len = 0;


@@ 163,6 171,47 @@ _d2tk_base_get_atom(d2tk_base_t *base, d2tk_id_t id, d2tk_atom_type_t type,
	return NULL; // no space left
}

static int
_fd_event(d2tk_atom_event_type_t event, void *data)
{
	d2tk_atom_body_fd_t *afd = data;

	switch(event)
	{
		case D2TK_ATOM_EVENT_FD:
		{
			return afd->fd;
		} break;

		case D2TK_ATOM_EVENT_DEINIT:
			// fall-through
		case D2TK_ATOM_EVENT_NONE:
			// fall-through
		default:
		{
			// nothing to do
		} break;
	}

	return 0;
}

D2TK_API int
d2tk_base_wake_on_fd(d2tk_base_t *base, d2tk_id_t id, int fd)
{
	d2tk_atom_body_fd_t *afd = _d2tk_base_get_atom(base, id, D2TK_ATOM_FD,
		_fd_event);

	if(!afd)
	{
		return 1;
	}

	afd->fd = fd;

	return 0;
}

D2TK_API void
d2tk_clip_int32(int32_t min, int32_t *value, int32_t max)
{

M src/base_internal.h => src/base_internal.h +2 -2
@@ 17,8 17,7 @@ typedef enum _d2tk_atom_type_t {
	D2TK_ATOM_SCROLL,
	D2TK_ATOM_PANE,
	D2TK_ATOM_FLOW,
	D2TK_ATOM_FLOW_NODE,
	D2TK_ATOM_FLOW_ARC,
	D2TK_ATOM_FD,
#if D2TK_VTERM
	D2TK_ATOM_PTY,
	D2TK_ATOM_LINEEDIT


@@ 110,6 109,7 @@ struct _d2tk_base_t {
extern const size_t d2tk_atom_body_flow_sz;
extern const size_t d2tk_atom_body_pane_sz;
extern const size_t d2tk_atom_body_scroll_sz;
extern const size_t d2tk_atom_body_fd_sz;
#if D2TK_VTERM
extern const size_t d2tk_atom_body_pty_sz;
extern const size_t d2tk_atom_body_lineedit_sz;