0

I use the libGD function gdImagePng(gdImagePtr im, FILE* fs) to pipe PNG images to the image viewer program feh from my program. I would like to be able to display an image and have control return to the calling process so that further images may be displayed in the same feh window.

I open a pipe to feh with

    FILE* fs = popen("feh -", "w");

(the "-" tells feh to read from stdin), and then call

    gdImagePng(im, fs);

to view the image. The image is indeed displayed in feh, but control does not return to the calling process until feh is closed.

Is there any way to force return of control to the caller, while keeping the pipe to the feh process open for subsequent image display? I have tried setting the pipe to non-blocking but this has no effect. Attempting to open the pipe with the "wb" attribute fails. Specifying the feh process as "feh - &" does not work either (the feh process does not appear to recognise the data as an image).

I do have a workaround: feh may be configured to auto-reload images when they change on disk, so I can start feh with a system() call to display an image written to a temporary file (say /tmp/tmp.png or /dev/shm/tmp.png) and repeatedly write different images to that file. This works, but is rather slow and clunky.

[Edit: this thread suggests to me that the implementation of feh may simply not accommodate what I am trying to achieve.]

Xerbla
  • 1
  • 1
  • 1
    _Is there any way to force return of control to the caller, while keeping the pipe to the feh process open for subsequent image display?_ The TL;DR: No. `feh` will read to EOF from `stdin`. It _has_ to do this--otherwise, how does it know that it has read the _complete_ image? And, you have to do `fclose` to flush the data to force the EOF. AFAICT, `feh` is _not_ designed to do what you want unless you do what you're proposing in your workaround. – Craig Estey Oct 21 '22 at 16:34
  • You could download the `feh` source, hack it up into a library (if it doesn't already have one) and then build the bulk of the `feh` source directly into your program. Then, you have complete control. – Craig Estey Oct 21 '22 at 16:37
  • Thanks, Craig, that's kind of what I suspected. One idea I've considered is hacking feh to listen for a signal indicating EOF (or even a key event might work for my usage scenario). On a brief skim, the code looks pretty clean, though not very library-like. – Xerbla Oct 21 '22 at 17:39

1 Answers1

0

Since you're willing to hack up feh, there's a simple way to do this.

Add an option that alerts feh to a special input mode (e.g. -p).

Then, in your program you do: popen("myfeh -p -","w");

The -p option says that the data will prefaced by a struct [that you design]:

enum cmd {
    CMD_NEWIMAGE,                       // new image file
    CMD_TERMINATE                       // terminate feh
};

struct control {
    enum cmd cmd;                       // command to execute
    size_t paylen;                      // payload length
};

Your program first fills in the struct with CMD_NEWFILE and the byte length of the image file you're sending and sends it to the pipe.

Then, it sends the image file data.

feh reads the struct and, now, it knows how much to read from the pipe (e.g. paylen).

It reads the image data and displays it.

feh then loops waiting for another control block.

Because feh supports auto reload, we know it already has code to reinit itself to take a new image.

When done, you can send a control message with CMD_TERMINATE to tell feh to [gracefully] terminate.

You can add other commands as needed.

If you do a clean enough job, you could upstream the patch to the original author and they might add it to feh so you wouldn't have to maintain it yourself.

Craig Estey
  • 30,627
  • 4
  • 24
  • 48