t* My version of sent
       
   URI git clone git://git.codevoid.de/sent-sdk.git
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit fd303ee9c1c969c4a50c6fcf0397973ea6f37dc7
   DIR parent 44a50ad94828d6375ebba9560109d06e9a163e5d
   URI Author: Hiltjo Posthuma <hiltjo@codemadness.org>
       Date:   Sat,  4 Jun 2016 21:47:39 +0200
       
       load slide image on-demand
       
       On Sat, Jun 04, 2016 at 05:28:31PM +0200, Markus Teich wrote:
       > Hiltjo Posthuma wrote:
       > > previously an image file would be opened but only ffread when advancing to
       > > the slide, but when the slide was not used it gave an error:
       > >
       > >         /usr/local/bin/2ff: failed to convert image/png
       >
       > Heyho Hiltjo,
       >
       > thanks for the patch. Unfortunately it does not work if the first slide contains
       > an image (ffopen is only called in advance). I think it would be good to merge
       > ffopen and ffread instead into a single function ffload. This makes the `LOADED`
       > state clearer and also enforces that the fd is closed in the same function where
       > it is opened. This ffload function should then be called in advance() replacing
       > the ffread() calls if the image is not loaded yet and once in load() for the
       > first slide if it is an image.
       >
       
       Ah yes, sorry for the oversight.
       
       > If you want to take this new approach, go for it, otherwise I'll look into it
       > myself.
       >
       
       I have attached a patch that does this, I hope you'll like it.
       
       Also I'm not sure if we need the below code in advance(), I have removed it in
       tthe patch:
       
               if (slidecount > idx + 1 && slides[idx + 1].img)
                       ffread(slides[idx + 1].img);
               if (0 < idx && slides[idx - 1].img)
                       ffread(slides[idx - 1].img);
       
       That seems to preload the next and previous slide image right? A minor issue I
       notice also is that images seem to flicker, it uses XPutImage directly to
       xw.win. Maybe it can be replaced with a backbuffer then XCopyArea? What do you
       tthink?
       
       In advance() it should also not always be needed to rescale the image.
       
       --
       Kind regards,
       Hiltjo
       
       From 97bebdcab4003f9acdfdd4bdf424449299ffd61d Mon Sep 17 00:00:00 2001
       From: Hiltjo Posthuma <hiltjo@codemadness.org>
       Date: Sat, 4 Jun 2016 21:34:25 +0200
       Subject: [PATCH] merge ffread and ffopen into one function
       
       Diffstat:
         M sent.c                              |      77 +++++++++++--------------------
       
       1 file changed, 27 insertions(+), 50 deletions(-)
       ---
   DIR diff --git a/sent.c b/sent.c
       t@@ -89,9 +89,8 @@ typedef struct {
                const Arg arg;
        } Shortcut;
        
       -static Image *ffopen(char *filename);
        static void fffree(Image *img);
       -static void ffread(Image *img);
       +static Image *ffread(char *filename);
        static void ffprepare(Image *img);
        static void ffscale(Image *img);
        static void ffdraw(Image *img);
       t@@ -159,14 +158,27 @@ filter(int fd, const char *cmd)
                return fds[0];
        }
        
       +void
       +fffree(Image *img)
       +{
       +        free(img->buf);
       +        if (img->ximg)
       +                XDestroyImage(img->ximg);
       +        free(img);
       +}
       +
        Image *
       -ffopen(char *filename)
       +ffread(char *filename)
        {
       +        uint32_t y, x;
       +        uint16_t *row;
       +        uint8_t opac, fg_r, fg_g, fg_b, bg_r, bg_g, bg_b;
       +        size_t rowlen, off, nbytes, i;
       +        ssize_t count;
                unsigned char hdr[16];
                char *bin = NULL;
                regex_t regex;
                Image *img;
       -        size_t i;
                int tmpfd, fd;
        
                for (i = 0; i < LEN(filters); i++) {
       t@@ -178,13 +190,11 @@ ffopen(char *filename)
                                break;
                        }
                }
       -
                if (!bin)
                        return NULL;
        
       -        if ((fd = open(filename, O_RDONLY)) < 0) {
       +        if ((fd = open(filename, O_RDONLY)) < 0)
                        die("sent: Unable to open file %s:", filename);
       -        }
        
                tmpfd = fd;
                fd = filter(fd, bin);
       t@@ -192,10 +202,7 @@ ffopen(char *filename)
                        die("sent: Unable to filter %s:", filename);
                close(tmpfd);
        
       -        if (read(fd, hdr, 16) != 16)
       -                return NULL;
       -
       -        if (memcmp("farbfeld", hdr, 8))
       +        if (read(fd, hdr, 16) != 16 || memcmp("farbfeld", hdr, 8))
                        return NULL;
        
                img = calloc(1, sizeof(Image));
       t@@ -203,31 +210,6 @@ ffopen(char *filename)
                img->bufwidth = ntohl(*(uint32_t *)&hdr[8]);
                img->bufheight = ntohl(*(uint32_t *)&hdr[12]);
        
       -        return img;
       -}
       -
       -void
       -fffree(Image *img)
       -{
       -        free(img->buf);
       -        if (img->ximg)
       -                XDestroyImage(img->ximg);
       -        free(img);
       -}
       -
       -void
       -ffread(Image *img)
       -{
       -        uint32_t y, x;
       -        uint16_t *row;
       -        uint8_t opac;
       -        uint8_t fg_r, fg_g, fg_b, bg_r, bg_g, bg_b;
       -        size_t rowlen, off, nbytes;
       -        ssize_t count;
       -
       -        if (img->state & LOADED)
       -                return;
       -
                if (img->buf)
                        free(img->buf);
                /* internally the image is stored in 888 format */
       t@@ -237,9 +219,8 @@ ffread(Image *img)
                /* scratch buffer to read row by row */
                rowlen = img->bufwidth * 2 * strlen("RGBA");
                row = malloc(rowlen);
       -        if (!row) {
       +        if (!row)
                        die("sent: Unable to malloc buffer for image row.\n");
       -        }
        
                /* extract window background color channels for transparency */
                bg_r = (sc[ColBg].pixel >> 16) % 256;
       t@@ -270,6 +251,8 @@ ffread(Image *img)
                free(row);
                close(img->fd);
                img->state |= LOADED;
       +
       +        return img;
        }
        
        void
       t@@ -444,13 +427,11 @@ load(FILE *fp)
                                        memmove(s->lines[s->linecount], &s->lines[s->linecount][1], blen);
                                s->linecount++;
                        } while ((p = fgets(buf, sizeof(buf), fp)) && strcmp(buf, "\n") != 0);
       +
                        slidecount++;
                        if (!p)
                                break;
                }
       -
       -        if (slidecount && slides[0].embed && slides[0].embed[0])
       -                slides[0].img = ffopen(slides[0].embed);
        }
        
        void
       t@@ -462,13 +443,7 @@ advance(const Arg *arg)
                        if (slides[idx].img)
                                slides[idx].img->state &= ~(DRAWN | SCALED);
                        idx = new_idx;
       -                if (!slides[idx].img && slides[idx].embed && slides[idx].embed[0])
       -                        slides[idx].img = ffopen(slides[idx].embed);
                        xdraw();
       -                if (slidecount > idx + 1 && slides[idx + 1].img)
       -                        ffread(slides[idx + 1].img);
       -                if (0 < idx && slides[idx - 1].img)
       -                        ffread(slides[idx - 1].img);
                }
        }
        
       t@@ -514,7 +489,11 @@ void
        xdraw()
        {
                unsigned int height, width, i;
       -        Image *im = slides[idx].img;
       +        Image *im;
       +
       +        if (!slides[idx].img && slides[idx].embed && slides[idx].embed[0])
       +                slides[idx].img = ffread(slides[idx].embed);
       +        im = slides[idx].img;
        
                getfontsize(&slides[idx], &width, &height);
                XClearWindow(xw.dpy, xw.win);
       t@@ -532,8 +511,6 @@ xdraw()
                                         0);
                        drw_map(d, xw.win, 0, 0, xw.w, xw.h);
                } else {
       -                if (!(im->state & LOADED))
       -                        ffread(im);
                        if (!(im->state & SCALED))
                                ffprepare(im);
                        if (!(im->state & DRAWN))