nixos-dotfiles

nixos-dotfiles

https://git.tonybtw.com/nixos-dotfiles.git git://git.tonybtw.com/nixos-dotfiles.git
8,102 bytes raw
1
/*
2
 * drwl - https://codeberg.org/sewn/drwl
3
 *
4
 * Copyright (c) 2023-2025 sewn <sewn@disroot.org>
5
 * Copyright (c) 2024 notchoc <notchoc@disroot.org>
6
 * 
7
 * Permission is hereby granted, free of charge, to any person obtaining
8
 * a copy of this software and associated documentation files (the
9
 * "Software"), to deal in the Software without restriction, including
10
 * without limitation the rights to use, copy, modify, merge, publish,
11
 * distribute, sublicense, and/or sell copies of the Software, and to
12
 * permit persons to whom the Software is furnished to do so, subject to
13
 * the following conditions:
14
 * 
15
 * The above copyright notice and this permission notice shall be
16
 * included in all copies or substantial portions of the Software.
17
 * 
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
 *
26
 * The UTF-8 Decoder included is from Bjoern Hoehrmann:
27
 * Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
28
 * See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
29
 */
30
#pragma once
31
32
#include <stdlib.h>
33
#include <fcft/fcft.h>
34
#include <pixman-1/pixman.h>
35
36
enum { ColFg, ColBg, ColBorder }; /* colorscheme index */
37
38
typedef struct fcft_font Fnt;
39
typedef pixman_image_t Img;
40
41
typedef struct {
42
	Img *image;
43
	Fnt *font;
44
	uint32_t *scheme;
45
} Drwl;
46
47
48
#define UTF8_ACCEPT 0
49
#define UTF8_REJECT 12
50
#define UTF8_INVALID 0xFFFD
51
52
static const uint8_t utf8d[] = {
53
	 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
54
	 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
55
	 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
56
	 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
57
	 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,  9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
58
	 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
59
	 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
60
	10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
61
62
	 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
63
	12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
64
	12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
65
	12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
66
	12,36,12,12,12,12,12,12,12,12,12,12,
67
};
68
69
static inline uint32_t
70
utf8decode(uint32_t *state, uint32_t *codep, uint8_t byte)
71
{
72
	uint32_t type = utf8d[byte];
73
74
	*codep = (*state != UTF8_ACCEPT) ?
75
		(byte & 0x3fu) | (*codep << 6) :
76
		(0xff >> type) & (byte);
77
78
	*state = utf8d[256 + *state + type];
79
	return *state;
80
}
81
82
static int
83
drwl_init(void)
84
{
85
	fcft_set_scaling_filter(FCFT_SCALING_FILTER_LANCZOS3);
86
	return fcft_init(FCFT_LOG_COLORIZE_AUTO, 0, FCFT_LOG_CLASS_ERROR);
87
}
88
89
static Drwl *
90
drwl_create(void)
91
{
92
	Drwl *drwl;
93
	
94
	if (!(drwl = calloc(1, sizeof(Drwl))))
95
		return NULL;
96
97
	return drwl;
98
}
99
100
static void
101
drwl_setfont(Drwl *drwl, Fnt *font)
102
{
103
	if (drwl)
104
		drwl->font = font;
105
}
106
107
static void
108
drwl_setimage(Drwl *drwl, Img *image)
109
{
110
	if (drwl)
111
		drwl->image = image;
112
}
113
114
static Fnt *
115
drwl_font_create(Drwl *drwl, size_t count,
116
		const char *names[static count], const char *attributes)
117
{
118
	Fnt *font = fcft_from_name(count, names, attributes);
119
	if (drwl)
120
		drwl_setfont(drwl, font);
121
	return font;
122
}
123
124
static void
125
drwl_font_destroy(Fnt *font)
126
{
127
	fcft_destroy(font);
128
}
129
130
static inline pixman_color_t
131
convert_color(uint32_t clr)
132
{
133
	return (pixman_color_t){
134
		((clr >> 24) & 0xFF) * 0x101 * (clr & 0xFF) / 0xFF,
135
		((clr >> 16) & 0xFF) * 0x101 * (clr & 0xFF) / 0xFF,
136
		((clr >> 8) & 0xFF) * 0x101 * (clr & 0xFF) / 0xFF,
137
		(clr & 0xFF) * 0x101
138
	};
139
}
140
141
static void
142
drwl_setscheme(Drwl *drwl, uint32_t *scm)
143
{
144
	if (drwl)
145
		drwl->scheme = scm;
146
}
147
148
static Img *
149
drwl_image_create(Drwl *drwl, unsigned int w, unsigned int h, uint32_t *bits)
150
{
151
	Img *image;
152
	pixman_region32_t clip;
153
154
	image = pixman_image_create_bits_no_clear(
155
		PIXMAN_a8r8g8b8, w, h, bits, w * 4);
156
	if (!image)
157
		return NULL;
158
	pixman_region32_init_rect(&clip, 0, 0, w, h);
159
	pixman_image_set_clip_region32(image, &clip);
160
	pixman_region32_fini(&clip);
161
162
	if (drwl)
163
		drwl_setimage(drwl, image);
164
	return image;
165
}
166
167
static void
168
drwl_rect(Drwl *drwl,
169
		int x, int y, unsigned int w, unsigned int h,
170
		int filled, int invert)
171
{
172
	pixman_color_t clr;
173
	if (!drwl || !drwl->scheme || !drwl->image)
174
		return;
175
176
	clr = convert_color(drwl->scheme[invert ? ColBg : ColFg]);
177
	if (filled)
178
		pixman_image_fill_rectangles(PIXMAN_OP_SRC, drwl->image, &clr, 1,
179
			&(pixman_rectangle16_t){x, y, w, h});
180
	else
181
		pixman_image_fill_rectangles(PIXMAN_OP_SRC, drwl->image, &clr, 4,
182
			(pixman_rectangle16_t[4]){
183
				{ x,         y,         w, 1 },
184
				{ x,         y + h - 1, w, 1 },
185
				{ x,         y,         1, h },
186
				{ x + w - 1, y,         1, h }});
187
}
188
189
static int
190
drwl_text(Drwl *drwl,
191
		int x, int y, unsigned int w, unsigned int h,
192
		unsigned int lpad, const char *text, int invert)
193
{
194
	int ty;
195
	int render = x || y || w || h;
196
	long x_kern;
197
	uint32_t cp = 0, last_cp = 0, state;
198
	pixman_color_t clr;
199
	pixman_image_t *fg_pix = NULL;
200
	int noellipsis = 0;
201
	const struct fcft_glyph *glyph, *eg = NULL;
202
	int fcft_subpixel_mode = FCFT_SUBPIXEL_DEFAULT;
203
204
	if (!drwl || (render && (!drwl->scheme || !w || !drwl->image)) || !text || !drwl->font)
205
		return 0;
206
207
	if (!render) {
208
		w = invert ? invert : ~invert;
209
	} else {
210
		clr = convert_color(drwl->scheme[invert ? ColBg : ColFg]);
211
		fg_pix = pixman_image_create_solid_fill(&clr);
212
213
		drwl_rect(drwl, x, y, w, h, 1, !invert);
214
215
		x += lpad;
216
		w -= lpad;
217
	}
218
219
	if (render && (drwl->scheme[ColBg] & 0xFF) != 0xFF)
220
		fcft_subpixel_mode = FCFT_SUBPIXEL_NONE;
221
222
	if (render)
223
		eg = fcft_rasterize_char_utf32(drwl->font, 0x2026 /* … */, fcft_subpixel_mode);
224
225
	for (const char *p = text, *pp; pp = p, *p; p++) {
226
		for (state = UTF8_ACCEPT; *p &&
227
		     utf8decode(&state, &cp, *p) > UTF8_REJECT; p++)
228
			;
229
		if (!*p || state == UTF8_REJECT) {
230
			cp = UTF8_INVALID;
231
			if (p > pp)
232
				p--;
233
		}
234
235
		glyph = fcft_rasterize_char_utf32(drwl->font, cp, fcft_subpixel_mode);
236
		if (!glyph)
237
			continue;
238
239
		x_kern = 0;
240
		if (last_cp)
241
			fcft_kerning(drwl->font, last_cp, cp, &x_kern, NULL);
242
		last_cp = cp;
243
244
		ty = y + (h - drwl->font->height) / 2 + drwl->font->ascent;
245
246
		if (render && !noellipsis && x_kern + glyph->advance.x + eg->advance.x > w &&
247
		    *(p + 1) != '\0') {
248
			/* cannot fit ellipsis after current codepoint */
249
			if (drwl_text(drwl, 0, 0, 0, 0, 0, pp, 0) + x_kern <= w) {
250
				noellipsis = 1;
251
			} else {
252
				w -= eg->advance.x;
253
				pixman_image_composite32(
254
					PIXMAN_OP_OVER, fg_pix, eg->pix, drwl->image, 0, 0, 0, 0,
255
					x + eg->x, ty - eg->y, eg->width, eg->height);
256
			}
257
		}
258
259
		if ((x_kern + glyph->advance.x) > w)
260
			break;
261
262
		x += x_kern;
263
264
		if (render && pixman_image_get_format(glyph->pix) == PIXMAN_a8r8g8b8)
265
			/* pre-rendered glyphs (eg. emoji) */
266
			pixman_image_composite32(
267
				PIXMAN_OP_OVER, glyph->pix, NULL, drwl->image, 0, 0, 0, 0,
268
				x + glyph->x, ty - glyph->y, glyph->width, glyph->height);
269
		else if (render)
270
			pixman_image_composite32(
271
				PIXMAN_OP_OVER, fg_pix, glyph->pix, drwl->image, 0, 0, 0, 0,
272
				x + glyph->x, ty - glyph->y, glyph->width, glyph->height);
273
274
		x += glyph->advance.x;
275
		w -= glyph->advance.x;
276
	}
277
278
	if (render)
279
		pixman_image_unref(fg_pix);
280
281
	return x + (render ? w : 0);
282
}
283
284
static unsigned int
285
drwl_font_getwidth(Drwl *drwl, const char *text)
286
{
287
	if (!drwl || !drwl->font || !text)
288
		return 0;
289
	return drwl_text(drwl, 0, 0, 0, 0, 0, text, 0);
290
}
291
292
static void
293
drwl_image_destroy(Img *image)
294
{
295
	pixman_image_unref(image);
296
}
297
298
static void
299
drwl_destroy(Drwl *drwl)
300
{
301
	if (drwl->font)
302
		drwl_font_destroy(drwl->font);
303
	if (drwl->image)
304
		drwl_image_destroy(drwl->image);
305
	free(drwl);
306
}
307
308
static void
309
drwl_fini(void)
310
{
311
	fcft_fini();
312
}