duration_until_next_timer_update saturates an already-expired deadline instead of subtracting two Slint instants directly, which could underflow in debug builds when a timer was due.
The 16 ms frame throttle was applied to every timeout, including when no redraw was pending, so the loop still woke at ~60 Hz after the timer change. Gate the throttle on a pending redraw and on a visible surface so an idle window sleeps until the next Slint timer or the one-second fallback.
Log system-font registration time so startup work can be attributed, and add a CI check that the Slint UI and mail-renderer fallback script lists stay identical. The two collections are separate, so this catches a script being added to only one side.
A stalled compositor could keep the Slint thread blocked in poll() for a full second. Cap the wait at 250 ms, abort the unready buffer, and drop the frame so the next redraw can retry instead of writing into a buffer whose fence never signalled.
Use SlintContext::next_timer_timeout to compute the next deadline; use a one-second fallback only when there is no timer or animation. This removes the fixed 100 ms idle wake-up while keeping timers accurate.
The caret rectangle is relative to the XComponent, but the cached window origin was only read when the page appeared. After maximizing a floating 2-in-1 window, the old floating origin was still added to every cursor update, so the IME candidate stayed at the previous window position. Listen for window rect/status changes and use a zero origin for maximized or full-screen windows.
Raise the mail-import selection and file-size limits, use a one-hour picker timeout, prefer FileUri.name for the display name, and align the bridge result argument order with the native signature.
Expose pickOpenMany on the bridge, stage selected files as one JSON result, and implement DocumentProvider::import_many so compose attachments can import several files in one picker action.