suggestion picker: a persistent layer to complement virtual keyboards like wvkbd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include <wayland-client.h>
#include <sys/mman.h>
#include <unistd.h>

#include "drw.h"
#include "shm_open.h"

void
drwsurf_resize(struct drwsurf *ds, uint32_t w, uint32_t h, uint32_t s) {
	if (ds->buf) {
		munmap(ds->pool_data, ds->size);
		wl_buffer_destroy(ds->buf);
		ds->buf = NULL;
	}

	ds->scale = s;
	ds->width = w * s;
	ds->height = h * s;

	setup_buffer(ds);
}

static void surface_frame_callback(void *data, struct wl_callback *cb,
                                   uint32_t time);

static struct wl_callback_listener frame_listener = {
    .done = surface_frame_callback
};

void
drwsurf_flip(struct drwsurf *ds) {
	struct wl_callback *cb = wl_surface_frame(ds->surf);
	wl_callback_add_listener(cb, &frame_listener, (void *)ds);

	wl_surface_attach(ds->surf, ds->buf, 0, 0);
	wl_surface_set_buffer_scale(ds->surf, ds->scale);
	wl_surface_commit(ds->surf);
}

void
surface_frame_callback(void *data, struct wl_callback *cb, uint32_t time) {
	struct drwsurf *ds = (struct drwsurf *)data;
	wl_callback_destroy(cb);

	drwsurf_flip(ds);
}

void
drw_draw_text(struct drwsurf *d, Color color,
	uint32_t x, uint32_t y,
	uint32_t w, uint32_t h,
	const char *label) {

	cairo_save(d->cairo);

    cairo_set_source_rgba (
		d->cairo,
		color.bgra[2] / (double)255,
		color.bgra[1] / (double)255,
		color.bgra[0] / (double)255,
		color.bgra[3] / (double)255
    );
	cairo_move_to(d->cairo, x + (double)w / 2.0, y + (double)h / 2.0);

	pango_layout_set_text(d->layout, label, -1);

	int width, height;
	pango_layout_get_size(d->layout, &width, &height);

	cairo_rel_move_to(d->cairo, - ((double)width / PANGO_SCALE) / 2, - ((double)height / PANGO_SCALE) / 2);
	pango_cairo_show_layout(d->cairo, d->layout);
	cairo_restore(d->cairo);

	wl_surface_damage(d->surf, x, y, w, h);
}

void
drw_fill_rectangle(struct drwsurf *d, Color color, uint32_t x, uint32_t y,
	uint32_t w, uint32_t h) {
	cairo_save(d->cairo);

	cairo_set_operator(d->cairo, CAIRO_OPERATOR_SOURCE);

	cairo_rectangle(d->cairo, x, y, w, h);
	cairo_set_source_rgba(
		d->cairo,
		color.bgra[2] / (double)255,
		color.bgra[1] / (double)255,
		color.bgra[0] / (double)255,
		color.bgra[3] / (double)255
	);
	cairo_fill(d->cairo);

	cairo_restore(d->cairo);

	wl_surface_damage(d->surf, x, y, w, h);
}

uint32_t
setup_buffer(struct drwsurf *drwsurf)
{
	int stride = drwsurf->width * 4;
	drwsurf->size = stride * drwsurf->height;

	int fd = allocate_shm_file(drwsurf->size);
	if (fd == -1) {
		return 1;
	}

	drwsurf->pool_data = mmap(NULL, drwsurf->size,
	PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
	if (drwsurf->pool_data == MAP_FAILED) {
		close(fd);
		return 1;
	}

	struct wl_shm_pool *pool = wl_shm_create_pool(drwsurf->ctx->shm, fd, drwsurf->size);
	drwsurf->buf = wl_shm_pool_create_buffer(pool, 0,
		drwsurf->width, drwsurf->height, stride, WL_SHM_FORMAT_ARGB8888);
	wl_shm_pool_destroy(pool);
	close(fd);

	cairo_surface_t *s = cairo_image_surface_create_for_data(drwsurf->pool_data,
		CAIRO_FORMAT_ARGB32,
	drwsurf->width, drwsurf->height, stride);

	drwsurf->cairo = cairo_create(s);
	cairo_scale(drwsurf->cairo, drwsurf->scale, drwsurf->scale);
	drwsurf->layout = pango_cairo_create_layout(drwsurf->cairo);
	pango_layout_set_font_description(drwsurf->layout, drwsurf->ctx->font_description);
	cairo_save(drwsurf->cairo);

	return 0;
}