Introduction
Introduction Statistics Contact Development Disclaimer Help
dmenu-png-images-5.3.diff - sites - public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log
Files
Refs
---
dmenu-png-images-5.3.diff (13922B)
---
1 From 743d86e56e0c1eb4255a08fe338db03752cc99e7 Mon Sep 17 00:00:00 2001
2 From: Max Schillinger <[email protected]>
3 Date: Fri, 1 Nov 2024 08:58:49 +0100
4 Subject: [PATCH] Support PNG images using libspng
5
6 ---
7 config.mk | 2 +-
8 dmenu.c | 62 +++++++++++++++---
9 drw.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
10 drw.h | 5 ++
11 util.c | 6 ++
12 util.h | 1 +
13 6 files changed, 254 insertions(+), 11 deletions(-)
14
15 diff --git a/config.mk b/config.mk
16 index 137f7c8..3217090 100644
17 --- a/config.mk
18 +++ b/config.mk
19 @@ -21,7 +21,7 @@ FREETYPEINC = /usr/include/freetype2
20
21 # includes and libs
22 INCS = -I$(X11INC) -I$(FREETYPEINC)
23 -LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS)
24 +LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) -lspng
25
26 # flags
27 CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX…
28 diff --git a/dmenu.c b/dmenu.c
29 index 804da64..b0e4109 100644
30 --- a/dmenu.c
31 +++ b/dmenu.c
32 @@ -38,11 +38,14 @@ static char *embed;
33 static int bh, mw, mh;
34 static int inputw = 0, promptw;
35 static int lrpad; /* sum of left and right padding */
36 +static int tbpad; /* sum of top and bottom padding for images */
37 static size_t cursor;
38 static struct item *items = NULL;
39 static struct item *matches, *matchend;
40 static struct item *prev, *curr, *next, *sel;
41 static int mon = -1, screen;
42 +static char *image_prefix = "PNG_IMAGE:";
43 +static int image_size = -1; /* in pixels */
44
45 static Atom clip, utf8;
46 static Display *dpy;
47 @@ -58,12 +61,26 @@ static int (*fstrncmp)(const char *, const char *, s…
48 static char *(*fstrstr)(const char *, const char *) = strstr;
49
50 static unsigned int
51 -textw_clamp(const char *str, unsigned int n)
52 +textw_clamp(const char *str, unsigned int n, unsigned int maxw, unsigne…
53 {
54 - unsigned int w = drw_fontset_getwidth_clamp(drw, str, n) + lrpa…
55 + unsigned int w;
56 + if (startswith(image_prefix, str) &&
57 + (w = drw_getimagewidth_clamp(drw, str + strlen(…
58 + return MIN(w + lrpad, n);
59 + w = drw_fontset_getwidth_clamp(drw, str, n) + lrpad;
60 return MIN(w, n);
61 }
62
63 +static unsigned int
64 +texth_clamp(const char *str, unsigned int n, unsigned int maxw, unsigne…
65 +{
66 + unsigned int h;
67 + if (startswith(image_prefix, str) &&
68 + (h = drw_getimageheight_clamp(drw, str + strlen…
69 + return MIN(h + tbpad, n);
70 + return MIN(bh, n);
71 +}
72 +
73 static void
74 appenditem(struct item *item, struct item **list, struct item **last)
75 {
76 @@ -83,15 +100,19 @@ calcoffsets(void)
77 int i, n;
78
79 if (lines > 0)
80 - n = lines * bh;
81 + n = mh - bh;
82 else
83 n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">"));
84 /* calculate which items will begin the next page and previous …
85 for (i = 0, next = curr; next; next = next->right)
86 - if ((i += (lines > 0) ? bh : textw_clamp(next->text, n)…
87 + if ((i += (lines > 0)
88 + ? texth_clamp(next->text, n, mw…
89 + : textw_clamp(next->text, n, im…
90 break;
91 for (i = 0, prev = curr; prev && prev->left; prev = prev->left)
92 - if ((i += (lines > 0) ? bh : textw_clamp(prev->left->te…
93 + if ((i += (lines > 0)
94 + ? texth_clamp(prev->left->text,…
95 + : textw_clamp(prev->left->text,…
96 break;
97 }
98
99 @@ -139,7 +160,18 @@ drawitem(struct item *item, int x, int y, int w)
100 else
101 drw_setscheme(drw, scheme[SchemeNorm]);
102
103 - return drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0);
104 + int vertical = lines > 0;
105 + if (startswith(image_prefix, item->text)) {
106 + char *path = item->text + strlen(image_prefix);
107 + unsigned int image_width = vertical ? w - lrpad : image…
108 + unsigned int image_height = vertical ? image_size : bh;
109 + drw_image(drw, &x, &y, &image_width, &image_height,
110 + lrpad, vertical ? tbpad : 0, path, vertical);
111 + if (image_width && image_height)
112 + return vertical ? y : x;
113 + }
114 + int nextx = drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0…
115 + return vertical ? y + bh : nextx;
116 }
117
118 static void
119 @@ -169,8 +201,9 @@ drawmenu(void)
120
121 if (lines > 0) {
122 /* draw vertical list */
123 + y = bh;
124 for (item = curr; item != next; item = item->right)
125 - drawitem(item, x, y += bh, mw - x);
126 + y = drawitem(item, x, y, mw - x);
127 } else if (matches) {
128 /* draw horizontal list */
129 x += inputw;
130 @@ -181,7 +214,7 @@ drawmenu(void)
131 }
132 x += w;
133 for (item = curr; item != next; item = item->right)
134 - x = drawitem(item, x, 0, textw_clamp(item->text…
135 + x = drawitem(item, x, 0, textw_clamp(item->text…
136 if (next) {
137 w = TEXTW(">");
138 drw_setscheme(drw, scheme[SchemeNorm]);
139 @@ -635,7 +668,10 @@ setup(void)
140 /* calculate menu geometry */
141 bh = drw->fonts->h + 2;
142 lines = MAX(lines, 0);
143 - mh = (lines + 1) * bh;
144 + /* default values for image_size */
145 + if (image_size < 0)
146 + image_size = (lines > 0) ? 2 * bh : 8 * bh;
147 + mh = bh + ((lines > 0) ? MAX(lines * bh, image_size) : 0);
148 #ifdef XINERAMA
149 i = 0;
150 if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))…
151 @@ -715,7 +751,8 @@ static void
152 usage(void)
153 {
154 die("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m…
155 - " [-nb color] [-nf color] [-sb color] [-sf colo…
156 + " [-nb color] [-nf color] [-sb color] [-sf colo…
157 + " [-ip image_prefix] [-is image_size]");
158 }
159
160 int
161 @@ -757,6 +794,10 @@ main(int argc, char *argv[])
162 colors[SchemeSel][ColFg] = argv[++i];
163 else if (!strcmp(argv[i], "-w")) /* embedding window …
164 embed = argv[++i];
165 + else if (!strcmp(argv[i], "-ip")) /* image prefix */
166 + image_prefix = argv[++i];
167 + else if (!strcmp(argv[i], "-is")) /* max. image previe…
168 + image_size = atoi(argv[++i]);
169 else
170 usage();
171
172 @@ -775,6 +816,7 @@ main(int argc, char *argv[])
173 if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
174 die("no fonts could be loaded.");
175 lrpad = drw->fonts->h;
176 + tbpad = lrpad / 2;
177
178 #ifdef __OpenBSD__
179 if (pledge("stdio rpath", NULL) == -1)
180 diff --git a/drw.c b/drw.c
181 index c41e6af..20c2125 100644
182 --- a/drw.c
183 +++ b/drw.c
184 @@ -4,12 +4,24 @@
185 #include <string.h>
186 #include <X11/Xlib.h>
187 #include <X11/Xft/Xft.h>
188 +#include <spng.h>
189
190 #include "drw.h"
191 #include "util.h"
192
193 #define UTF_INVALID 0xFFFD
194
195 +struct image_item {
196 + const char *path;
197 + int width;
198 + int height;
199 + char *buf;
200 + Pixmap pixmap;
201 + struct image_item *next;
202 +};
203 +
204 +static struct image_item *images = NULL;
205 +
206 static int
207 utf8decode(const char *s_in, long *u, int *err)
208 {
209 @@ -382,6 +394,163 @@ no_match:
210 return x + (render ? w : 0);
211 }
212
213 +static struct image_item *
214 +load_image(Drw *drw, unsigned int maxw, unsigned int maxh, const char *…
215 +{
216 + FILE *png;
217 + spng_ctx *ctx = NULL;
218 + int ret = 0;
219 + struct spng_ihdr ihdr;
220 + struct spng_plte plte = {0};
221 + struct spng_row_info row_info = {0};
222 + char *spng_buf;
223 + int fmt = SPNG_FMT_RGBA8;
224 + int crop_width;
225 + int crop_height;
226 +
227 + struct image_item *image = ecalloc(1, sizeof(struct image_item)…
228 + image->path = path;
229 + image->next = images;
230 + images = image;
231 +
232 + png = fopen(path, "rb");
233 + if (png == NULL) {
234 + fprintf(stderr, "error opening input file %s\n", path);
235 + return NULL;
236 + }
237 +
238 + /* Create a context */
239 + ctx = spng_ctx_new(0);
240 + if (ctx == NULL) {
241 + fprintf(stderr, "%s: spng_ctx_new() failed\n", path);
242 + return NULL;
243 + }
244 +
245 + /* Ignore and don't calculate chunk CRC's */
246 + spng_set_crc_action(ctx, SPNG_CRC_USE, SPNG_CRC_USE);
247 +
248 + /* Set memory usage limits for storing standard and unknown chu…
249 + this is important when reading untrusted files! */
250 + size_t limit = 1024 * 1024 * 64;
251 + spng_set_chunk_limits(ctx, limit, limit);
252 +
253 + spng_set_png_file(ctx, png);
254 +
255 + ret = spng_get_ihdr(ctx, &ihdr);
256 + if (ret) {
257 + fprintf(stderr, "%s: spng_get_ihdr() error: %s\n", path…
258 + return NULL;
259 + }
260 +
261 + ret = spng_get_plte(ctx, &plte);
262 + if (ret && ret != SPNG_ECHUNKAVAIL) {
263 + fprintf(stderr, "%s: spng_get_plte() error: %s\n", path…
264 + return NULL;
265 + }
266 +
267 + size_t image_size, bytes_per_row; /* size in bytes, not in pixe…
268 +
269 + ret = spng_decoded_image_size(ctx, fmt, &image_size);
270 + if (ret)
271 + return NULL;
272 +
273 + spng_buf = malloc(image_size);
274 + if (!spng_buf)
275 + return NULL;
276 +
277 + ret = spng_decode_image(ctx, NULL, 0, fmt, SPNG_DECODE_PROGRESS…
278 + if (ret) {
279 + fprintf(stderr, "%s: progressive spng_decode_image() er…
280 + path, spng_strerror(ret));
281 + return NULL;
282 + }
283 +
284 + /* ihdr.height will always be non-zero if spng_get_ihdr() succe…
285 + bytes_per_row = image_size / ihdr.height;
286 + crop_width = MIN(ihdr.width, maxw);
287 + crop_height = MIN(ihdr.height, maxh);
288 +
289 + do {
290 + ret = spng_get_row_info(ctx, &row_info);
291 + if (ret)
292 + break;
293 + ret = spng_decode_row(ctx, spng_buf + row_info.row_num …
294 + } while (!ret && row_info.row_num < crop_height);
295 +
296 + if (ret != SPNG_EOI && row_info.row_num < crop_height)
297 + fprintf(stderr, "%s: progressive decode error: %s\n", p…
298 +
299 + image->buf = calloc(ihdr.width * crop_height * 4, sizeof(char));
300 + for (int i = 0; i < ihdr.width * crop_height; i++) {
301 + /* RGBA to BGRA */
302 + image->buf[i*4+2] = spng_buf[i*4+0];
303 + image->buf[i*4+1] = spng_buf[i*4+1];
304 + image->buf[i*4+0] = spng_buf[i*4+2];
305 + image->buf[i*4+3] = spng_buf[i*4+3];
306 + }
307 + image->width = crop_width;
308 + image->height = crop_height;
309 +
310 + XImage *img = XCreateImage(drw->dpy, CopyFromParent, DefaultDep…
311 + ZPixmap, 0, image->buf, ihdr.width, …
312 + image->pixmap = XCreatePixmap(drw->dpy, drw->root, crop_width, …
313 + XPutImage(drw->dpy, image->pixmap, drw->gc, img, 0, 0, 0, 0, cr…
314 + spng_ctx_free(ctx);
315 + fclose(png);
316 + return image;
317 +}
318 +
319 +void
320 +drw_image(Drw *drw, int *x, int *y, unsigned int *w, unsigned int *h,
321 + unsigned int lrpad, unsigned int tbpad, const char *path, int…
322 +{
323 + /* *x and *y refer to box position including padding,
324 + * *w and *h are the maximum image width and height without pad…
325 + struct image_item *image = NULL;
326 + int render = *x || *y;
327 + int crop_width, crop_height;
328 +
329 + // find path in images
330 + for (struct image_item *item = images; item != NULL; item = ite…
331 + if (!strcmp(item->path, path)) {
332 + image = item;
333 + if (!image->buf)
334 + goto file_error;
335 + break;
336 + }
337 + }
338 +
339 + if (!image && !(image = load_image(drw, *w, *h, path)))
340 + goto file_error;
341 +
342 + if (!render) {
343 + *w = image->width;
344 + *h = image->height;
345 + return;
346 + }
347 +
348 + crop_width = MIN(image->width, *w);
349 + crop_height = MIN(image->height, *h);
350 + if (vertical)
351 + *h = crop_height;
352 + else
353 + *w = crop_width;
354 +
355 + XSetForeground(drw->dpy, drw->gc, drw->scheme[ColBg].pixel);
356 + XFillRectangle(drw->dpy, drw->drawable, drw->gc, *x, *y, *w + l…
357 + XCopyArea(drw->dpy, image->pixmap, drw->drawable, drw->gc, 0, 0,
358 + crop_width, crop_height, *x + lrpad/2, *y + tbpad/2);
359 +
360 + if (vertical)
361 + *y += *h + tbpad;
362 + else
363 + *x += *w + lrpad;
364 + return;
365 +
366 +file_error:
367 + *w = *h = 0;
368 +}
369 +
370 void
371 drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned in…
372 {
373 @@ -424,6 +593,26 @@ drw_font_getexts(Fnt *font, const char *text, unsig…
374 *h = font->h;
375 }
376
377 +unsigned int
378 +drw_getimagewidth_clamp(Drw *drw, const char *path, unsigned int maxw, …
379 +{
380 + int x = 0, y = 0;
381 + unsigned int w = maxw, h = maxh;
382 + if (drw && path && maxw && maxh)
383 + drw_image(drw, &x, &y, &w, &h, 0, 0, path, 0);
384 + return MIN(maxw, w);
385 +}
386 +
387 +unsigned int
388 +drw_getimageheight_clamp(Drw *drw, const char *path, unsigned int maxw,…
389 +{
390 + int x = 0, y = 0;
391 + unsigned int w = maxw, h = maxh;
392 + if (drw && path && maxw && maxh)
393 + drw_image(drw, &x, &y, &w, &h, 0, 0, path, 1);
394 + return MIN(maxh, h);
395 +}
396 +
397 Cur *
398 drw_cur_create(Drw *drw, int shape)
399 {
400 diff --git a/drw.h b/drw.h
401 index fd7631b..330722d 100644
402 --- a/drw.h
403 +++ b/drw.h
404 @@ -38,6 +38,10 @@ unsigned int drw_fontset_getwidth(Drw *drw, const cha…
405 unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, uns…
406 void drw_font_getexts(Fnt *font, const char *text, unsigned int len, un…
407
408 +/* Image abstraction */
409 +unsigned int drw_getimagewidth_clamp(Drw *drw, const char *path, unsign…
410 +unsigned int drw_getimageheight_clamp(Drw *drw, const char *path, unsig…
411 +
412 /* Colorscheme abstraction */
413 void drw_clr_create(Drw *drw, Clr *dest, const char *clrname);
414 Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount);
415 @@ -53,6 +57,7 @@ void drw_setscheme(Drw *drw, Clr *scm);
416 /* Drawing functions */
417 void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, i…
418 int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, un…
419 +void drw_image(Drw *drw, int *x, int *y, unsigned int *w, unsigned int …
420
421 /* Map functions */
422 void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsign…
423 diff --git a/util.c b/util.c
424 index 8e26a51..975735b 100644
425 --- a/util.c
426 +++ b/util.c
427 @@ -35,3 +35,9 @@ ecalloc(size_t nmemb, size_t size)
428 die("calloc:");
429 return p;
430 }
431 +
432 +int
433 +startswith(const char* prefix, const char* str)
434 +{
435 + return strncmp(prefix, str, strlen(prefix)) == 0;
436 +}
437 diff --git a/util.h b/util.h
438 index c0a50d4..6db39c8 100644
439 --- a/util.h
440 +++ b/util.h
441 @@ -7,3 +7,4 @@
442
443 void die(const char *fmt, ...);
444 void *ecalloc(size_t nmemb, size_t size);
445 +int startswith(const char* prefix, const char* str);
446 --
447 2.47.0
448
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.