The Story Behind Fenster
72 points
10 months ago
| 8 comments
| zserge.com
| HN
Lerc
9 months ago
[-]
This has popped up because

Microui+fenster=Small GUI https://news.ycombinator.com/item?id=41477446

Was posted in the last day.

In that thread I suggested that API compatibility would be the way to go for more esoteric platforms, Since there's already comments here about BSD and Android targets.

All you need is

    struct fenster {
      const char *title; /* window title */
      const int width; /* window width */
      const int height; /* window height */
      uint32_t *buf; /* window pixels, 24-bit RGB, row by row, pixel by pixel */
      int keys[256]; /* keys are mostly ASCII, but arrows are 17..20 */
      int mod;       /* mod is 4 bits mask, ctrl=1, shift=2, alt=4, meta=8 */
      int x;         /* mouse X coordinate */
      int y;         /* mouse Y coordinate */
      int mouse;     /* 0 = no buttons pressed, 1 = left button pressed */
    };

    int fenster_open(struct fenster *f)
    int fenster_loop(struct fenster *f)
    void fenster_close(struct fenster *f) 
    void fenster_sleep(int ms)
    int64_t fenster_time() 
    fenster_pixel(f, x, y) 
    uint32_t px = fenster_pixel(f, x, y); 
A bit more for audio, but that's really it's own little API

As a mimimal API for doing interactive apps, it's hard to beat. I can see hobbyists who make their own operating systems taking advantage of this to get things working quickly.

reply
felipefar
10 months ago
[-]
Nice work! It wouldn't be much work to support Android with this library and keep the single source file, since the addition of native_app_glue. It'd require just an AndroidManifest.xml, and the API communication can be done by calling the functions provided by the NDK or in the worst case by calling JNI.
reply
immibis
10 months ago
[-]
You might want to use CLOCK_MONOTONIC on POSIX or changing the system time will screw up the refresh rate or freeze the window completely.
reply
teo_zero
9 months ago
[-]
The application can handle it changing

  if (ms > 0)
    fenster_sleep(ms);
to

  if (ms > 0 && ms <= 1000/60)
    fenster_sleep(ms);
reply
immibis
9 months ago
[-]
Wouldn't you rather make it correct to begin with, rather than introducing hacks to work around incorrectness?
reply
unwind
9 months ago
[-]
Very nice and very straight-forward. I really liked the part on getting "Doom" to run, impressive how easy such porting is now!

Any low-level C is kind of catnip for the old SO-powered part of my brain, but did not spend a lot of time and got a lot of confidence.i did find this bug:

    memset(f->buf, rgb, f->width*f->height*sizeoof(*f->buf));
This will not work to set a color in the general case (`rgb` is `uint32_t`) since `memset()` only uses the lower `CHAR_BIT` bits of the value, it is setting the memory byte by byte. For black or white it will work! :)
reply
onetom
9 months ago
[-]
Would it work on NetBSD/OpenBSD/FreeBSD/GhostBSD too?

Because if it does, it would worth mentioning it in the readme.

In Plan 9, Rio, the window manager, does a similar thing; it exposes a framebuffer to the process running in a window, simply as the /dev/draw device file, iirc.

reply
mrpippy
10 months ago
[-]
In the Mac/AppKit implementation it would be interesting to try using wantsUpdateLayer: and updateLayer: instead of drawRect. That should be more efficient.
reply
password4321
9 months ago
[-]
TIL: Our goal here is to have a framebuffer for a single window that would run and look the same on Linux, Windows and macOS.

Basically re-implementing enough SDL from scratch to run Doom, nice!

reply
igtztorrero
9 months ago
[-]
WASN + Fester, for Browser, it is possible?
reply