Sitelet https://github.com/emoon/minifb/releases
Skip to content

Releases: emoon/minifb

v0.14.0: One input contract on every backend

Choose a tag to compare

@Darky-Lucera Darky-Lucera released this 24 Sep 18:42

This release adds a callback for the cursor entering and leaving the window. Adding it to every backend showed that the backends did not report mouse and keyboard input in the same way, so this release also fixes that.

Mouse and keyboard input now follow one contract on every backend. The same action produces the same callbacks, in the same order, with the same arguments and modifiers. Code tested on one platform now behaves the same on the others. The few differences that remain come from the platform, such as AltGr on native Windows.

Three interactive tests check the contract on any backend: tests/mouse_events.c, tests/keyboard_events.c and tests/window_events.c. Each one ends with a summary that you can compare between backends with diff.

Thanks to @cannedbeef for the color macro work in #142 and #143.

Heads up. Some values your application already receives change in this release:

  • MFB_RGB now sets alpha to 0xFF. Code that compares pixels with a raw value such as 0x00FF0000 has to include the alpha byte.
  • mfb_wait_sync now honours the target frame rate on Web and DOS. Call mfb_set_target_fps(0) to get the old behaviour back.
  • Android reports the real mouse button in the button argument, not the touch pointer id.
  • Windows reports AltGr as MFB_KB_KEY_LEFT_CONTROL followed by MFB_KB_KEY_RIGHT_ALT, every time.
  • On most X11 servers a key is now named by its position, so Dvorak or AZERTY layouts no longer move the letters.
  • The interactive tests are built by default. Set MINIFB_BUILD_TESTS=OFF if you add MiniFB with add_subdirectory.
  • macOS now links the Carbon framework. A build that does not use the CMake project has to add -framework Carbon.

Added

  • Cursor enter and leave: mfb_set_mouse_enter_callback and mfb_is_mouse_inside. The callback fires only on a real crossing. While a button is held the window keeps the pointer, so dragging out reports no leave until the button is released. The C++ wrapper has the same callback. iOS and DOS never fire it. On Android it needs a mouse, trackpad or hover capable stylus.
  • Color channel macros: MFB_GET_A, MFB_GET_R, MFB_GET_G and MFB_GET_B read one channel from a pixel, with the same platform layout as MFB_ARGB (#142, by @cannedbeef).
  • Web MFB_WF_RESIZABLE: the canvas follows its CSS layout box, scaled by devicePixelRatio.
  • Web text input: dead keys, input method composition and characters outside the Basic Multilingual Plane now reach mfb_set_char_input_callback.
  • X11 text input through xkbcommon: dead keys and Compose sequences come from the system Compose file, as on Wayland. The library is optional. -DMINIFB_X11_USE_IME=ON puts an X11 input method in front of it.
  • DOS mouse wheel: the wheel is read from the mouse driver through the CuteMouse API, so the arrow keys keep working.
  • Interactive tests for mouse, keyboard and window events, and the testing guides docs/testing-x11.md, docs/testing-dos.md and docs/testing-wayland.md.

Changed

  • MFB_RGB is now MFB_ARGB(0xFF, r, g, b) (#142, by @cannedbeef).
  • Web and DOS pace frames in mfb_wait_sync, like the other backends.
  • Android: a mouse click reports the real button. A mouse or hovering stylus reports the new MFB_POINTER_ID_MOUSE as its pointer id. Touch input works as before.
  • Windows: AltGr always reports the left Control that Windows presses for it. Before, the same keystroke reported one key on some runs and two on others.
  • macOS: the key next to left Shift reports MFB_KB_KEY_WORLD_2, like every other backend. MFB_KB_MOD_NUM_LOCK is never set, because macOS has no Num Lock. Each Caps Lock toggle reports a press and then a release.
  • DOS: with Num Lock off, the keypad reports the navigation keys, as DOS programs expect. Define MINIFB_DOS_KEYPAD_POSITIONAL to always report the physical keypad key.

Fixed

Mouse:

  • X11 no longer reports every wheel notch twice.
  • Windows reports the side buttons as MFB_MOUSE_BTN_4 and MFB_MOUSE_BTN_5, like the other backends.
  • On Web and Android the wheel axes now have the same sign as on the other backends.
  • On macOS one wheel notch is worth the same as on the other backends.
  • No scroll callback arrives with both axes at zero.
  • A button released outside the window is delivered on Windows. Before, it stayed held.

Keyboard:

  • Modifiers come from both the keys that are held and what the platform reports. Releasing one Shift while the other is held keeps Shift set, and AltGr always reports Alt. Mouse callbacks carry the same modifiers.
  • Losing the focus releases every key still held, with one callback for each key. Gaining the focus rebuilds the key buffer on Windows, X11 and macOS.
  • The physical key is reported before the character it produces.
  • The text callback no longer receives control characters. On Windows, Enter, Tab and Backspace used to arrive there.
  • Many backend specific key fixes: Shift and the Windows key getting stuck on Windows, Print Screen on Windows, X11 auto-repeat and lock state, left and right modifiers on macOS, ISO keyboards on macOS, AltGr and missing keys on Web, extended keys and the arrow keys on DOS.

Windows and the rest:

  • The window title is UTF-8 on every backend. An invalid title is reported once in the log. It no longer produces mojibake on Windows, an empty title on macOS or a protocol error on Wayland.
  • Frame pacing no longer stops for good after one long frame.
  • X11 and Windows call the resize callback only when the size changes.
  • Windows no longer warns about DPI awareness when the application manifest has already set it.
  • iOS multi-touch works.
  • The DOS mouse position is reported in window units.
  • Android big-endian builds use the color layout the Android documentation gives (#142, by @cannedbeef).

Build:

  • The Web examples build again when the build directory is outside the source tree.
  • GCC builds are warning free again.
  • DJGPP executables fit the DOS 8.3 name limit.

The full list of changes is in CHANGELOG.md.

v0.13.0: Client-side window decorations on Wayland

Choose a tag to compare

@Darky-Lucera Darky-Lucera released this 30 Aug 11:23

Until now, a window opened on a compositor without xdg-decoration had no frame at all: no title bar, no borders, no close button. GNOME is the main case. MiniFB now draws that frame itself with libdecor.

libdecor is optional and is never linked. MiniFB opens it with dlopen the first time a window needs it, so the same binary runs on machines that do not have it, and falls back to the old undecorated window when it is missing.

Nothing changes on compositors that do implement xdg-decoration, such as KDE. They keep drawing the frame themselves, as before.

Added

  • Wayland client-side decorations: when the compositor does not implement xdg-decoration, MiniFB now draws the window frame with libdecor instead of leaving the window bare. libdecor is opened with dlopen the first time a window needs it, so it is never a link-time dependency: a binary built on a machine that has libdecor still runs on one that does not. If the library, any symbol it needs, or the compositor support is missing, the window falls back to a plain undecorated toplevel and MiniFB says so in the log. CMake finds the headers with pkg-config and reports which case applies, including the common one where the runtime library is installed but the development package is not.

Changed

  • Wayland: the surface now declares its opaque region, and refreshes it whenever the surface changes size. The buffer format has no alpha channel, so the whole surface is opaque, but a compositor that is not told this may still blend it. Declaring it lets the compositor skip that work and discard whatever the window covers. GLFW and SDL do the same.

Known issues

  • Wayland on WSLg: maximizing a window that libdecor decorates leaves the drop shadow of the floating window drawn over the maximized one, at its previous size and position. MiniFB removes the shadow correctly and the compositor confirms it, so this is not specific to MiniFB: the same artifact appears with GLFW and was reported against FLTK in microsoft/wslg#914. It does not happen on native Linux compositors. Resizing the window by hand clears it.

Full Changelog: v0.12.0...v0.13.0

v0.12.0: Wayland fixes and diagnostics

Choose a tag to compare

@Darky-Lucera Darky-Lucera released this 28 Aug 19:35

Three fixes you may notice. A hidden window no longer uses a whole CPU core. Key repeat runs at the rate the compositor asks for. One mouse wheel notch reports 1.0 on every compositor.

Two new environment variables also make the version-dependent fallback paths testable without changing compositor.

This is the second half of the Wayland rework. The first half is in v0.11.0.

Heads up if you are on Wayland. The wheel change alters values your application already receives. And MINIFB_LOG_LEVEL deliberately overrides mfb_set_log_level().

Added

  • Log level from the environment: MINIFB_LOG_LEVEL sets the log threshold by name (trace, debug, info, warning, error) without touching the code. It deliberately wins over mfb_set_log_level(), so you can get more output from a program you cannot rebuild. An unknown value is reported as an error and then ignored, leaving the threshold where the program left it.
  • Wayland fallback testing: MINIFB_WAYLAND_FORCE_VERSIONS lowers the version MiniFB binds for one or more protocol globals, and MINIFB_WAYLAND_DISABLE_GLOBALS hides globals as if the compositor never advertised them. Both work in every build and are read only while globals are bound, so a single machine can exercise fallback paths that would otherwise need another compositor.
  • Added docs/wayland-testing.md: the interfaces each variable accepts, which versions are worth testing and what each one covers, the related variables from libwayland and xkbcommon, and what this approach cannot test.

Changed

  • Wayland mouse wheel: the continuous wl_pointer.axis value is now divided by the ratio Weston uses, which SDL and GLFW follow too. One notch reports 1.0, like the other backends. This only affects compositors that fall back to the continuous value. Those that send axis_value120 or axis_discrete already reported 1.0.
  • Every Wayland listener callback now carries a comment with its protocol interface and the version that introduced it, so the version-dependent paths can be found with grep.
  • Wayland: xdg_toplevel.configure now logs its state array at DEBUG (activated, suspended, maximized, resizing, ...) instead of discarding it.
  • Wayland: wl_keyboard.repeat_info now logs the advertised rate and delay at DEBUG. It also reports when client-side repeat is off, which happens when the compositor drives it instead.
  • Wayland: MiniFB now says when a window will have no frame. It logs the negotiated decoration mode at DEBUG. A client-side answer to a server-side request also raises a warning. The warning for a missing decoration manager now states the same fact instead of describing the protocol.
  • Wayland: a failed dispatch now reports what libwayland knows about the connection. A protocol error names the interface, the object and the error code. Any other failure reports the system error. Before, every case printed the same generic message.
  • Rewrote README.md in plainer English and corrected stale details: mfb_update return values, ESC handling, the macOS Metal default, the X11 default on Linux, the Wayland dependencies, and Web monitor scale and cursor support. Added a CMake options table, and replaced the per-platform "Beta" labels with what each backend actually supports.

Fixed

  • Wayland: wl_pointer.axis_discrete no longer marks an axis as valid when the compositor reports a discrete step of 0.
  • Wayland: a protocol error is no longer reported as EPIPE. The dispatch helpers gave up as soon as the flush failed. They never read the error the compositor had queued before closing the socket. They now continue to the read, as libwayland does in the function they derive from.
  • Wayland: key repeat now runs at the rate the compositor asks for. MiniFB computed the next deadline from the moment the previous repeat fired. Every interval then rounded up to the next poll. On KWin at 25 cps, the measured rate was 19.18 before the fix and 25.06 after.
  • Wayland: a hidden window no longer uses a whole CPU core. The frame throttle's wait budget belonged to the frame callback, and nothing refreshed it once it expired. Every later update then skipped without waiting. An application with no other frame pacing had nothing left to pace it. The budget now belongs to each update call. On KWin, a minimized window with no target FPS dropped from 100% of a core to 3.8%, and the visible frame rate did not change.

Full Changelog: v0.11.0...v0.12.0

v0.11.0: The Wayland rework, part one

Choose a tag to compare

@Darky-Lucera Darky-Lucera released this 28 Aug 19:34

Wayland becomes a first-class desktop backend, alongside Windows, macOS and X11. Presentation, event dispatch, frame pacing, scaling, input and resource lifecycle were all reworked. Part two is in v0.12.0.

The CMake build was also restructured, though the unprefixed option names were already deprecated back in v0.9.3 and still work.

Changed

  • Wayland backend modernization: promoted Wayland to a first-class desktop backend alongside Windows, macOS, and X11, with reworked SHM presentation, event dispatch, frame pacing, scaling, input, and resource lifecycle handling.
  • Updated the bundled Wayland protocol bindings to 1.49 and added viewporter-based fractional and per-surface HiDPI scaling.
  • CMake restructure: the build now checks the prefixed option names internally, adds MINIFB_BUILD_EXAMPLES, and uses cmake_dependent_option where one option depends on another. It also fixes the exported package config, the generated version header, and the Emscripten, iOS and macOS build paths. The unprefixed names were already deprecated in 0.9.3 and keep working.

Fixed

  • Improved Wayland reliability and responsiveness during initial mapping, resize, minimize, multi-output scale changes, buffer reuse, and compositor-driven configure sequences.
  • Completed Wayland keyboard, pointer, and scroll behavior, including compose/dead keys, key repeat, modifier and focus synchronization, stuck-input cleanup, and safe seat/global removal.
  • Hardened Wayland protocol negotiation and version-dependent object cleanup across older and newer environments.
  • Fixed macOS flagsChanged events produced by focus synchronization toggling alphanumeric keys.

Full Changelog: v0.10.1...v0.11.0

v0.10.1: A small follow-up to v0.10.0

Choose a tag to compare

@Darky-Lucera Darky-Lucera released this 28 Aug 20:04

mfb_set_title is new. It changes the window title after creation, on Windows, macOS, X11 and Wayland, and does nothing on iOS, Android, Web and DOS.

The rest is keyboard work. Dead-key compose on X11 now emits the standalone accent in the same order as Windows and macOS, and untranslated keys no longer fire callbacks on X11 or Wayland.

Added

  • Window title API: added mfb_set_title to change the window title after creation. Implemented on Windows, macOS, X11, and Wayland, with no-op stubs on iOS, Android, Web, and DOS.

Changed

  • Unified keycode-table initialization across Windows, macOS, X11, and Wayland with one-time setup and explicit reset to MFB_KB_KEY_UNKNOWN.
  • Moved the shared stretch_image declaration into src/MiniFB_internal.h.

Fixed

  • Fixed X11 dead-key compose cancellation so the standalone accent is emitted before the following character, matching Windows and macOS behavior.
  • Fixed X11 and Wayland keyboard handling to avoid updating key state or firing keyboard callbacks for untranslated keys.
  • Fixed DOS release completeness by adding the missing mfb_set_title backend stub required by the public API.

Full Changelog: v0.10.0...v0.10.1

v0.10.0: The release that gave the public API its MFB_ prefix

Choose a tag to compare

@Darky-Lucera Darky-Lucera released this 28 Aug 20:05

Every public enum constant was renamed. STATE_*, KB_*, MOUSE_* and WF_* are now MFB_*. The old names still compile, as deprecated aliases that warn.

Also new here: the logging API, display inset queries for mobile, and touch decoding. Several APIs were unified so that every backend behaves the same way, so a few details may differ from v0.9.x. The tests/ directory became examples/.

Added

  • Logging API: mfb_set_logger, mfb_set_log_level, mfb_log, mfb_log_level, mfb_log_info, and MFB_LOG* helper macros for runtime log control and source-location-aware diagnostics. Backend messages now route through the shared logger instead of ad-hoc fprintf/NSLog.
  • Display inset APIs: mfb_get_display_cutout_insets and mfb_get_display_safe_insets for mobile-safe layouts (Android API 28+, iOS, desktop stubs return zeros).
  • Touch pointer decoding: mfb_decode_touch, mfb_decode_touch_pos, and mfb_decode_touch_id to decode packed pointer id/position values from mobile mouse getters.
  • Monitor scale: implemented mfb_get_monitor_scale for Web (devicePixelRatio) and Android.
  • Cursor control: implemented mfb_show_cursor for Web.
  • X11 scale detection: layered fallbacks (XSettings, Xresources, XRandR, physical DPI).
  • DOS viewport: basic viewport support for the MS-DOS backend.
  • Android mfb_update_events: event-only pump without rendering, matching other backends.
  • Android example: new example project using Android Studio Narwhal (native2026).
  • New headers: MiniFB_macros.h (deprecation/pixel/logging macros), MiniFB_types.h (callback and logging typedefs), WindowData_Web.h.
  • Internal helpers: calculate_buffer_layout (overflow-safe buffer validation) and mfb_validate_viewport (unified viewport checks), used by all backends.

Changed

  • Standardized public enum naming to MFB_* prefixes across states, keys, modifiers, mouse buttons, and window flags.
  • Unified mfb_open_ex behavior across backends: consistent flag handling, NULL/empty title defaults to "minifb", mutually-exclusive fullscreen flags logged.
  • Unified mfb_set_viewport behavior across backends with shared validation and consistent destination recalculation.
  • Unified mfb_get_monitor_scale so window == NULL is accepted across backends, returning the primary monitor scale where available and 1.0 fallback otherwise.
  • Unified mouse wheel reset (mouse_wheel_x/y = 0) on every update across all backends.
  • Web backend: auto-creates missing canvas element; pumps events in mfb_wait_sync.
  • Moved accumulated_error_ticks into the timer struct (was static).
  • Replaced deprecated Android API ALooper_pollAll with ALooper_pollOnce.
  • Callback parameter names unified (is_active, is_pressed, delta_x, delta_y).
  • Renamed tests/ to examples/ and updated CMake/example project paths accordingly.
  • Reorganized Android examples into native2021/native2026 folders.
  • Moved DOS tools to tools/dos/, Wayland protocol generator to tools/wayland/.
  • Updated DJGPP GCC toolchain to 12.2.0.
  • Normalized line endings with .gitattributes.

Deprecated

  • All non-prefixed enum constants (STATE_*, KB_*, MOUSE_*, WF_*) in favor of MFB_* equivalents. Old names remain as deprecated aliases with compiler warnings.

Fixed

  • Fixed MFB_ARGB macro on Android little-endian (had 3 parameters instead of 4).
  • Fixed Web mfb_update_ex not updating buffer_width/buffer_height/buffer_stride.
  • Fixed integer overflow potential in buffer size calculations across all backends.
  • Fixed iOS: Metal safety, content scale, touch coordinates, window lookup, active/close event management, and safer cutout/safe-inset handling when no launch screen is configured.
  • Fixed Android: API 32-34 display cutout handling; surface transition and rotation edge cases.
  • Fixed macOS: improved robustness and replaced NSLog with mfb_log.
  • Fixed Windows: double-click messages now map to regular mouse button press events.
  • Fixed Windows: initial window sizing on high-DPI displays so the client area and viewport stay aligned.
  • Fixed X11: initial normal-window placement now centers on a real monitor instead of the combined virtual desktop.
  • Fixed C++ wrapper: callback stubs are released when windows are destroyed, preventing stale callback reuse after recreating windows.
  • Fixed Web: initialization/teardown robustness when document.body is not yet available.
  • Fixed Wayland wl_surface_attach: the viewport offset was passed as the buffer offset, so buffers are now attached at 0, 0.
  • Fixed Wayland seat and output handling: pointer and keyboard listeners are added only when the seat really provides the object, and a removed wl_output is compared with the current one before it is destroyed.
  • Fixed MS-DOS keyboard: completed the scancode table (numpad keys, F11/F12), read the initial Caps Lock state from the BIOS, applied Caps Lock to letters only, and stopped an out-of-bounds write for keys mapped to KB_KEY_UNKNOWN (-1, seen as 0xFFFFFFFF when indexing the key table).
  • Fixed MS-DOS mouse: the driver presence check uses the documented 0xFFFF reply, the pointer range follows the real VESA resolution instead of the requested window size, and the middle button fires its callback.
  • Fixed MS-DOS input under DPMI by locking the ring-buffer code used from the interrupt handler (_go32_dpmi_lock_code).
  • Fixed use-after-free during teardown: macOS clears the MTKView delegate before closing the window, the OpenGL path no longer closes the X11 display it does not own, and the DOS backend no longer frees window_data while the caller is still using it.

Full Changelog: v0.9.3...v0.10.0