All notable changes to this project are recorded here, grouped as Added, Changed, Fixed, Removed and Security. The project uses Semantic Versioning. Before 1.0.0, any release may change the API, the ABI and the behavior.
The iOS device check, that a window shows no flash against the launch screen before its first frame, is waived by the owner for this release, which ships on the iOS simulator suite: its iOS changes leave the launch and the first frame alone.
mwinMessageButtons is now mwinMessageChoice, its
constants mwin_buttonsOk, mwin_buttonsOkCancel and
mwin_buttonsYesNo are now mwin_choiceOk, mwin_choiceOkCancel
and mwin_choiceYesNo, and mwinMessageBoxDef.buttons is now
mwinMessageBoxDef.choice. The type is a choice of one, but its
plural name read as a set of flags, as every other plural type in
the API is
(#489).mwinGamepad_GetTestRumble and
mwinGamepad_GetTestTriggerRumble take size_t* countOut instead
of uint32_t* countOut, as every other count the API reports is a
size_t
(#490).The iOS device check, that a window shows no flash against the launch screen before its first frame, is waived by the owner for this release, which ships on the iOS simulator suite: its iOS changes leave the launch and the first frame alone.
mwinMouseButton, the kind a button
record names, are now mwin_mouseButtonLeft,
mwin_mouseButtonRight, mwin_mouseButtonMiddle,
mwin_mouseButtonBack and mwin_mouseButtonForward, with the same
values; they were mwin_buttonLeft, mwin_buttonRight,
mwin_buttonMiddle, mwin_buttonBack and mwin_buttonForward.
Those names did not say they were the mouse's, and they agree with
the held-button flags mwin_mouseLeft to mwin_mouseForward for
left and right only: a program that tested
pointer.buttons & mwin_buttonMiddle tested left and right, with no
warning
(#485).The iOS device check, that a window shows no flash against the launch screen before its first frame, is waived by the owner for this release, which ships on the iOS simulator suite: its iOS changes leave the launch and the first frame alone.
MWIN_NODISCARD gives [[nodiscard]] in C under GCC 14, whose C23
mode reports __STDC_VERSION__ as 202000L. Before, it expanded to
nothing there, so no GCC build warned when a program dropped a
status a function returns
(#465).The iOS device check, that a window shows no flash against the launch screen before its first frame, is waived by the owner for this release, which ships on the iOS simulator suite: its iOS changes leave the launch and the first frame alone.
mwinRequest_GetDialogFiles takes a truncatedOut
argument after countOut. A dialog choice holding a file the
platform cannot give as a path now completes done with the other
paths and marked truncated; before, the whole dialog failed. Such a
file is a path that is not UTF-8, a portal's choice that is no local
file, an item with no file system path on Windows, or a document
Android could not read or copy. A choice where no chosen file can be
given as a path still fails. A choice past the dialogFiles or
dialogBytes limits is still too large as a whole
(#452).requestDragAndDropPermissions threw and nothing caught it. The drop
goes on without the drag's permissions. A drop with a document that
cannot be opened or copied now brings the other documents and is
marked truncated; before, it brought no files and was not marked
(#449).mwin_eventDragEntered and
its moves, the source was told the window would take it, and its drop
brought mwin_eventDragLeft instead of mwin_eventDropped, since the
reads belonged to the drop before it. The drop being read is
delivered as before
(#428).textBytesPerWindow), and posts mwin_eventInputStateReset after
its key past it. Before, it typed nothing, with no reset. On X11, a key
held for IBus's or Fcitx's answer keeps such a text in order behind
the keys before it, and a key whose text was lost goes through the
input method too, its reset posted after it
(#430).truncated set
(#426).textBytesPerWindow limit. A commit past it posts
mwin_eventInputStateReset; before, one past 1024 bytes was dropped
with no reset. A composition past it posts the reset, then ends;
before, one past 512 bytes ended without the reset
(#410).mwin_outcomeFailed
(#413).The iOS device check, that a window shows no flash against the launch screen before its first frame, is waived by the owner for this release, which ships on the iOS simulator suite: its iOS changes leave the launch and the first frame alone.
| 0.7.0 | 0.8.0 |
|---|---|
mwinEvent.type, mwinEventType |
mwinEvent.kind, mwinEventKind |
mwinGamepad_GetMotion |
mwinGamepad_TakeMotion |
mwinContext_HoldTestRequests |
mwinContext_EnableTestHold, read back with the new mwinContext_IsTestHoldEnabled |
mwinContext_GetDroppedFiles, mwinContext_GetDroppedText |
mwinDrop_GetFiles, mwinDrop_GetText |
a drop's uint32_t number (mwinDropEvent.drop) |
an mwinDropId |
The event kinds keep their names and numbers. A drop id answers
mwin_errorStale for the null id, another slot's id and a drop a
later one replaced, as the number did.
- Breaking: mwinWindow_RequestTextInput takes no caret;
mwinWindow_RequestTextInputCaret sets it, as its own request kind
(mwin_requestTextInputCaret), so a newer caret supersedes an older
one and never a text input request. A window keeps its caret while
text input is off and on again. On Wayland, moving the caret no
longer sends text-input-v3's enable again, which reset the input
method's state on every move
(#393).
- Breaking: text lengths and composition offsets are size_t:
mwinTextEvent.length, mwinPreeditEvent.length, selectionStart
and selectionEnd, mwinPreeditSegment.start and length, and the
web handles' selectorLength and accessibilityLength.
mwinPreeditEvent.caret is ptrdiff_t and keeps -1 for a hidden
caret (#388).
- Breaking: mwinRequest_GetDialogFiles and
mwinContext_GetTestIcon report their count in a size_t*, as the
listing calls do
(#394).
- Breaking: mwinPointerEvent.buttons is an mwinMouseButtons
(uint32_t, a named bit for each button, mwin_mouseLeft to
mwin_mouseForward), mwinGamepadState.buttons an
mwinGamepadButtons (uint32_t), and mwinPenEvent.button an
mwinPenButton (int32_t, mwin_penButtonNone and
mwin_penButtonBarrel). The pointer and pen records' layouts change
(#389).
- Breaking: the kinds, modes and choices of the public structs and
calls are int32_t, and the sets of bit flags (mwinModifiers,
mwinWindowStyle, mwinPenFlags, mwinDragContents,
mwinGamepadCapabilities) are uint32_t. This changes the layout of
the event, info and def structs. A negative kind is refused with
mwin_errorInvalid, and counted as a misuse on a context; a cursor
mode, window mode, window kind, dialog kind, hit region's kind,
message box's kind or buttons, or test answer of INT32_MIN used to
become 0 and go ahead. mwinGamepad_SetTestButton and
mwinGamepad_SetTestAxis answer mwin_errorInvalid for a value
below 0 or past 255
(#315).
- Breaking: four counts are named by the family's thingCount rule
(#315):
| 0.7.0 | 0.8.0 |
|---|---|
mwinPointerEvent.clicks |
mwinPointerEvent.clickCount |
mwinEvent.samples |
mwinEvent.sampleCount |
mwinGamepadInfo.rawButtons |
mwinGamepadInfo.rawButtonCount |
mwinGamepadInfo.rawAxes |
mwinGamepadInfo.rawAxisCount |
mwinRequest_GetClipboardText, GetClipboardData,
GetPrimaryText and GetDialogFiles; mwinDrop_GetFiles and
mwinDrop_GetText; mwinContext_GetKeyboardLayout,
GetPreferredLocales, GetGamepads and GetMonitors; and the test
platform's mwinWindow_GetTestTitle, mwinContext_GetTestClipboard,
GetTestClipboardData, GetTestPrimary, GetTestOpened and
GetTestDialog. Text is never NUL-terminated, so a program reads
only the length the call reports
(#313).mwinContext_NextEvent and mwinGamepad_TakeMotion,
refused with mwin_errorBusy because they were called from inside
the context's allocator while another call uses the context, leave
their output as it was; they used to zero it. The id of what a call
makes (a window, a cursor, a request) is still the null id on every
failure
(#290).localeBytes limit on every platform: the first tag
that does not fit is left out with every tag after it, and a list
whose first tag does not fit is empty. Windows hands over its list
only whole, so there a list that does not fit keeps only its first
language, the one Windows shows, where that fits. Before, Android,
the web and Windows left a list past the limit as it was, or empty,
without mwin_eventLocaleChanged. Linux held at most 256 bytes of
tags whatever the limit, and let a later, shorter tag in after one
that did not fit. When a desktop source named languages none of
which fit, it took AccountsService's Language or the starting list
instead; on Windows, a first language one byte past the limit kept
the old list
(#366,
#368,
#370,
#402).mwinContext_SetTestLocales takes a list past the
localeBytes limit as a platform's list, keeping its leading tags
that fit; it answered mwin_errorCapacity
(#366).mwinInitFunction, mwinFrameFunction and mwinQuitFunction type
mwinAppDef's init, frame and quit, so a program can declare
them; the def's layout is unchanged. mwinShowMessageBox says that a
failure leaves acceptedOut as it was
(#385)._, as each /
does
(#341).mwin_outcomeTooLarge, on every backend,
as the header says; it answered mwin_outcomeFailed
(#346).onBattery, choose a portal dialog's files, change
settings, or type text into the focused window. Each now hears only
the service's owner
(#347).droppedFiles at a cost growing with the
square of its paths. A medium of another kind is now let go unread
and the drop marked truncated
(#351).S_OK, a path left out took
a file's place, and a file list whose header pointed past its memory
delivered nothing without marking the drop truncated. The file list
is now read once, past paths left out, and checked against its
memory
(#356).mwin_errorStale
(#303).mwinDestroyWindow gave the window's blocks to the allocator's
free function, mwinWindow_GetState and mwinWindow_GetNativeHandles
called from there still answered for the window, and a cursor was
still found while mwinDestroyCursor freed its images. The window's
id is now stale before its blocks reach the free function, and the
cursor's before its images do
(#309).quit, the context's teardown gave its blocks to the
allocator's free function while its windows, cursors and payloads
were still found and the platform could still be reached; a call from
there could read a freed block. Once quit returns, every window,
cursor, request and drop id is stale there,
mwinContext_GetKeyReach and mwinContext_GetKeyboardLayout answer
mwin_errorState, and mwinContext_MapKeyCode answers no key
(#318).mwinWindow_GetTestTextInput and
mwinWindow_GetTestVirtualKeyboard left their outputs as they were
when they failed; they clear them now
(#283).mwinObject_Verb..., the object being the kind of its first id
(mwinWindow_RequestTitle, mwinGamepad_GetState,
mwinRequest_GetClipboardText); a call that takes no id acts on the
context (mwinContext_NextEvent). Creation, destruction, defaults and
calls on no object keep mwinVerbNoun, and the test platform's calls
put Test after the verb. Their parameters and behavior are
unchanged: code that calls them changes the names and nothing else
(#264).| 0.6.0 | 0.7.0 |
|---|---|
mwinTestAddGamepad |
mwinAddTestGamepad |
mwinTestAddMonitor |
mwinAddTestMonitor |
mwinGetDroppedFiles |
mwinContext_GetDroppedFiles |
mwinGetDroppedText |
mwinContext_GetDroppedText |
mwinGetGamepads |
mwinContext_GetGamepads |
mwinGetKeyReach |
mwinContext_GetKeyReach |
mwinGetKeyboardLayout |
mwinContext_GetKeyboardLayout |
mwinGetContextMisuse |
mwinContext_GetMisuse |
mwinGetMonitors |
mwinContext_GetMonitors |
mwinGetPreferredLocales |
mwinContext_GetPreferredLocales |
mwinGetSystemFacts |
mwinContext_GetSystemFacts |
mwinTestGetClipboard |
mwinContext_GetTestClipboard |
mwinTestGetClipboardData |
mwinContext_GetTestClipboardData |
mwinTestGetDialog |
mwinContext_GetTestDialog |
mwinTestGetIcon |
mwinContext_GetTestIcon |
mwinTestGetOpened |
mwinContext_GetTestOpened |
mwinTestGetPrimary |
mwinContext_GetTestPrimary |
mwinTestHold |
mwinContext_HoldTestRequests |
mwinMapKeyCode |
mwinContext_MapKeyCode |
mwinNextEvent |
mwinContext_NextEvent |
mwinTestPost |
mwinContext_PostTestEvent |
mwinTestSetAnswer |
mwinContext_SetTestAnswer |
mwinTestSetClipboard |
mwinContext_SetTestClipboard |
mwinTestSetClipboardData |
mwinContext_SetTestClipboardData |
mwinTestSetClipboardUtf16 |
mwinContext_SetTestClipboardUtf16 |
mwinTestSetDialogFiles |
mwinContext_SetTestDialogFiles |
mwinTestSetKeyReach |
mwinContext_SetTestKeyReach |
mwinTestSetLocales |
mwinContext_SetTestLocales |
mwinTestSetPrimary |
mwinContext_SetTestPrimary |
mwinTestSetScale |
mwinContext_SetTestScale |
mwinTestSetSystemFacts |
mwinContext_SetTestSystemFacts |
mwinTestSetTime |
mwinContext_SetTestTime |
mwinSetGamepadMotion |
mwinGamepad_EnableMotion |
mwinGetGamepadInfo |
mwinGamepad_GetInfo |
mwinGetGamepadMotion |
mwinGamepad_GetMotion |
mwinGetGamepadState |
mwinGamepad_GetState |
mwinTestGetRumble |
mwinGamepad_GetTestRumble |
mwinTestGetTriggerRumble |
mwinGamepad_GetTestTriggerRumble |
mwinTestGetMotionOn |
mwinGamepad_IsTestMotionEnabled |
mwinTestGamepadMotion |
mwinGamepad_PostTestMotion |
mwinSetGamepadRumble |
mwinGamepad_SetRumble |
mwinTestGamepadAxis |
mwinGamepad_SetTestAxis |
mwinTestGamepadButton |
mwinGamepad_SetTestButton |
mwinTestChangeGamepad |
mwinGamepad_SetTestInfo |
mwinSetGamepadTriggerRumble |
mwinGamepad_SetTriggerRumble |
mwinResultName |
mwinGetResultName |
mwinGetMonitorInfo |
mwinMonitor_GetInfo |
mwinTestChangeMonitor |
mwinMonitor_SetTestInfo |
mwinTestRemoveGamepad |
mwinRemoveTestGamepad |
mwinTestRemoveMonitor |
mwinRemoveTestMonitor |
mwinGetClipboardData |
mwinRequest_GetClipboardData |
mwinGetClipboardText |
mwinRequest_GetClipboardText |
mwinGetDialogFiles |
mwinRequest_GetDialogFiles |
mwinGetPrimaryText |
mwinRequest_GetPrimaryText |
mwinTestAskAccessibility |
mwinWindow_AskTestAccessibility |
mwinGetNativeHandles |
mwinWindow_GetNativeHandles |
mwinGetWindowState |
mwinWindow_GetState |
mwinTestGetCursor |
mwinWindow_GetTestCursor |
mwinTestGetTextInput |
mwinWindow_GetTestTextInput |
mwinTestGetTitle |
mwinWindow_GetTestTitle |
mwinTestGetVirtualKeyboard |
mwinWindow_GetTestVirtualKeyboard |
mwinTestDrop |
mwinWindow_PostTestDrop |
mwinRequestAccessibilityRoot |
mwinWindow_RequestAccessibilityRoot |
mwinRequestAspectRatio |
mwinWindow_RequestAspectRatio |
mwinRequestClipboardRead |
mwinWindow_RequestClipboardRead |
mwinRequestClipboardReadData |
mwinWindow_RequestClipboardReadData |
mwinRequestClipboardWrite |
mwinWindow_RequestClipboardWrite |
mwinRequestClipboardWriteData |
mwinWindow_RequestClipboardWriteData |
mwinRequestCursorImage |
mwinWindow_RequestCursorImage |
mwinRequestCursorMode |
mwinWindow_RequestCursorMode |
mwinRequestCursorShape |
mwinWindow_RequestCursorShape |
mwinRequestFileDialog |
mwinWindow_RequestFileDialog |
mwinRequestFocus |
mwinWindow_RequestFocus |
mwinRequestHitRegions |
mwinWindow_RequestHitRegions |
mwinRequestIcon |
mwinWindow_RequestIcon |
mwinRequestKeepAwake |
mwinWindow_RequestKeepAwake |
mwinRequestMode |
mwinWindow_RequestMode |
mwinRequestOpacity |
mwinWindow_RequestOpacity |
mwinRequestOpenUrl |
mwinWindow_RequestOpenUrl |
mwinRequestPosition |
mwinWindow_RequestPosition |
mwinRequestPrimaryRead |
mwinWindow_RequestPrimaryRead |
mwinRequestPrimaryWrite |
mwinWindow_RequestPrimaryWrite |
mwinRequestRevealFile |
mwinWindow_RequestRevealFile |
mwinRequestSize |
mwinWindow_RequestSize |
mwinRequestSizeLimits |
mwinWindow_RequestSizeLimits |
mwinRequestStyle |
mwinWindow_RequestStyle |
mwinRequestTextInput |
mwinWindow_RequestTextInput |
mwinRequestTitle |
mwinWindow_RequestTitle |
mwinRequestVirtualKeyboard |
mwinWindow_RequestVirtualKeyboard |
mwinRequestVisible |
mwinWindow_RequestVisible |
mwinRequest_GetClipboardText, mwinContext_GetDroppedFiles,
mwinContext_GetKeyboardLayout, mwinContext_GetPreferredLocales
and the others) write nothing into a buffer too short: they answer
mwin_errorCapacity with the length needed, and
mwinRequest_GetDialogFiles also with the number of paths, and leave
the buffer zeroed. They used to copy the part that fit, which could
end inside a character or a path. A program that read that part must
ask again with a buffer of the length given
(#269).mwinContext_GetGamepads and mwinContext_GetMonitors
answer mwin_success when the ids do not all fit, with the first
ones written and the total in countOut. They answered
mwin_errorCapacity; a program that tested for it compares the count
with its capacity instead
(#269).mwinGamepad_IsMotionEnabled tells whether a gamepad's motion
sensors are on
(#264).maul-window_UNICODE_VERSION from the installed package, set even
when the program's Maul Unicode is another version, and the cache
variable MAUL_WINDOW_UNICODE_VERSION when Maul Window is built from
source with add_subdirectory or FetchContent
(#277).The device checks on real hardware are waived by the owner for releases through 2026-10-29, so 0.6.0 ships on its other gates. The iOS check, that a window shows no flash against the launch screen before its first frame, runs against it in #254.
mwin_errorLimit (-9) instead of
mwin_errorInvalid, and counts one misuse. The bound is checked on
lengths and counts before any content is read. mwinCreateWindow
refuses a def whose title passes the titleBytes limit with
mwin_errorCapacity, as mwinRequestTitle already did. A program
that tests for mwin_errorInvalid on these refusals must test for
the new results
(#182).mwin_errorLimit are
renamed with the prefix MWIN_MAX_, with their values unchanged and
no aliases: MWIN_ADDRESS_BYTES, MWIN_CANVAS_SELECTOR_BYTES,
MWIN_CLIPBOARD_ITEMS, MWIN_CLIPBOARD_MIME, MWIN_CURSOR_IMAGES,
MWIN_CURSOR_SIZE, MWIN_DIALOG_FILTER_BYTES,
MWIN_DIALOG_FILTERS, MWIN_DIALOG_TITLE_BYTES,
MWIN_HIT_REGIONS, MWIN_ICON_IMAGES, MWIN_ICON_SIZE,
MWIN_MESSAGE_BYTES and MWIN_MESSAGE_TITLE_BYTES are now
MWIN_MAX_ADDRESS_BYTES and so on
(#186).mwinRequestClipboardWrite, mwinRequestIcon and
mwinRequestFileDialog run partway through, is refused with the new
mwin_errorBusy (-10) and counts one misuse. Every public function
that takes a non-const context refuses it. Such a call used to go
ahead, and could destroy the window, take a request slot or drain the
queue while the outer call was still using them
(#198).MWIN_INPUT_PURPOSES counts the input purposes: every purpose is
below it. mwinRequestVirtualKeyboard refuses a purpose from it on
(#228).mwin_eventInputStateReset ends its composition:
composing goes false, and the input method's next preedit starts
one again. After a composition that did not fit the window's text
storage, or one lost to full storage, the program used to keep
drawing the old one, and the
character keys that went down were left out as a composition's keys
until a later preedit
(#194).MSC_TIMESTAMP) are timed on the records' clock, as
mwinGamepadMotion.timeNs is documented. Their time used to count
from the device's first stamp
(#164).limits.gamepads was taken is
added once a slot is free. It used to be added only when plugged in
again
(#213,
#208).mwin_eventGamepadChanged. It
used to never offer motion, and mwinSetGamepadMotion answered
unsupported
(#225).mwin_success and leave the motors running until the time first
asked for ran out
(#240).mwin_eventDragEntered without a leave between them, as when an X11
source ended without a leave or another program started a drag
(#156).mwinMonitorInfo.variableRefresh is an mwinTristate
(mwin_yes, mwin_no, or mwin_unknown where the platform does not
tell) instead of a bool. A program testing it as a truth value must
compare it with mwin_yes. mwinTristate is now declared in
base.h. X11 tells it from vrr_capable, macOS 12 and later from
whether the screen's refresh interval can vary, iOS by a refresh
above 60 Hz, and Android 16 from hasArrSupport. Win32, Wayland, the
web, older macOS and Android, and an X11 output without
vrr_capable report unknown, where they used to report no
(#116).mwin_eventOccluded)
while it is minimized, cloaked by DWM (as on another virtual
desktop), while the session is locked or while the display is off,
and revealed when none of these holds; a dimmed display counts as on.
mwinGetWindowState says the same. Coverage by other windows is not
reported, since Windows tells it nowhere
(#117).mwin_eventOccluded) when
its scene goes to the background, and revealed
(mwin_eventRevealed) when the scene comes back to the foreground;
mwinGetWindowState says the same. The program hears of it in the
frame that tells of the suspending, after the suspending record, and
of the revealing after the resumed record. An inactive scene, under
Control Center, the app switcher or a system alert, is still seen and
stays revealed
(#110).mwin_eventOccluded)
while its activity is stopped, and revealed (mwin_eventRevealed)
when the activity starts again; mwinGetWindowState says the same.
The program hears of it in the frame that tells of the suspending,
after the suspending record, and of the revealing after the resumed
record. A pause alone, as under a translucent activity, in split
screen or in picture-in-picture, leaves the window revealed
(#109).mwin_eventOccluded), and revealed (mwin_eventRevealed)
once any part of it can be seen again, as the X server computes it;
mwinGetWindowState says the same. Under a compositing window
manager the X server reports no window covered, so there a window is
never occluded. The windows guide now lists when each platform
reports occlusion
(#107).timeNs promises, instead of the time the library handled it: input
that waited behind a long frame or a modal loop is no longer stamped
late by that wait. Touch and pen take the time Windows recorded with
the sample. Input times never go backwards, across all kinds of input
(#102).mwinMessageBoxDef carries the ABI version, like the application
def, and mwinShowMessageBox refuses a def from other headers with
mwin_errorVersion. A program must rebuild against the new headers
and build its def with mwinDefaultMessageBoxDef(), which now sets
the version; a def filled in field by field must also set
version = MWIN_ABI_VERSION
(#31).mwin_outcomeUnsupported where the application cannot show several
scenes (an iPhone, or an Info.plist without
UIApplicationSupportsMultipleScenes), instead of
mwin_outcomeFailed
(#69).mwin_outcomeFailed if the
system refuses or no scene comes. A scene the user closes asks its
window to close, and a window the program destroys while others remain
closes its scene
(#69).plasma-localerc replaces the list, and mwin_eventLocaleChanged
says so. The list still starts from the program's environment, and
without a system bus or a configuration folder it simply stays
(#67).The first release: windows, input, gamepads and platform services behind one contract on Windows, macOS, iOS, Android, Wayland, X11 and the web, with a headless test backend for programs' own tests.
mwinRun refuses from another release.java/proguard-rules.pro for Android applications that shrink their
code with R8 or ProGuard.