Releases: gcfernando/glass
Release list
Glass.Message v1.0.5
A polish and code-quality release. The live progress dialog now animates more
smoothly, a hairline rendering artifact on the bar is gone, and the source has
been cleaned up to satisfy the Roslynator analyzer set. No public API changes.
Fixed
- Smoother live progress — calling
GlassProgressController.SetValue(...)now
eases the determinate fill toward the new value instead of snapping to it, so a
jump (e.g. 10 % → 60 %) glides across roughly half a second. The animation timer
spins up only while the bar is catching up and retires itself once it settles,
so an idle dialog still does no per-frame work. - Hairline "background edge" on the progress bar — the determinate fill was
drawn through an aliased region clip whose hard edge exposed a 1 px rim of the
lighter track behind the bar; the gradient also bled a thin seam at its edge.
The fill is now painted as an antialiased rounded path with an inset gradient,
so the bar reads as a clean, solid pill with no light fringe.
Changed
- Code-quality cleanup (internal only) — applied the Roslynator style/analyzer
fixes across the library and tests: conditional access (?.) over null-check
ternaries and chains, a read-only backing field, a static helper, concrete
field types for owner-drawn controls, and a trimmed empty type body. Behaviour
and the public API are unchanged.
Full Changelog: v1.0.4...v1.0.5
Glass.Message v1.0.4
A feature release that makes the live progress dialog activity-aware — the
bar can now animate to match the operation it represents (upload, download,
sync, compress, …) — plus visual-polish and performance fixes for the progress
bar.
Added
-
ProgressActivity(GlassProgressActivity)builder method and the new
GlassProgressActivityenum (17 activities). The progress bar paints a
distinct, eye-catching animation grouped into six visual families:Family Animation Activities Packets glowing dots glide along Upload·Download·StreamChevrons diagonal bands march FileTransfer·ImportSegments rounded blocks march Compress·Extract·ExportWave a sinusoidal ripple Backup·Restore·SyncPulse the fill breathes Encrypt·Decrypt·ConnectingComet a soft shine sweeps Install·Search·ProcessingStripes flow forward for outgoing work, backward for incoming, and ease both
ways for a two-way sync. Works on both determinate and indeterminate bars; use
GlassProgressActivity.Nonefor a plain bar. -
GlassProgressController.SetActivity(GlassProgressActivity)— change the
flow animation live as an operation moves between phases (e.g.Compressthen
Upload).
Fixed
- Progress bar "box" artifact — the progress panel now paints the dialog's
themed gradient behind itself (like every other custom control) instead of
clearing to a flat colour, so it blends into the window seamlessly rather than
showing a dark rectangle around the track. - Progress bar visibility — boosted the contrast of every activity animation
so the styles read clearly at the standard bar height.
Performance
- No per-frame allocations in the animated progress panel — the glow-dot
sprite, themed-background gradient, track border pen, flow brushes, and chevron
geometry are all cached/reused, so an animating progress dialog no longer
churns GDI+ objects at 30 fps.
Full Changelog: v1.0.3...v1.0.4
Glass.Message v1.0.3
A maintenance release — documentation, packaging, and CI only. No library code
or public API changes.
Changed
- Docs — removed an unsubstantiated adoption claim from the NuGet README
(README.nuget.md). - Packaging — switched to a more reliable NuGet version badge and refreshed
the README badges (camo cachecacheSecondslowered so the version badge
updates promptly). - CI — bumped the release workflow actions to Node 24:
actions/checkout@v6,
actions/upload-artifact@v7,actions/download-artifact@v8, and
actions/setup-dotnet@v5; step names normalised to PascalCase.
Full Changelog: v1.0.2...v1.0.3
Glass.Message v1.0.2
Added
showCapsLockHintparameter onInputPassword()— opt out of the Caps Lock
badge per dialog with.InputPassword("placeholder", showCapsLockHint: false).
The hint stays on by default; suppress it for PIN entry, kiosk flows, or anywhere
uppercase input is intentional. Showcased by the new Password — Caps Lock Hint
Off demo (Demo_PasswordNoCapsLock).
Fixed
Thread safety & concurrency
- Volatile static properties —
DefaultTheme,UseRoundedCorners, and
PlaySystemSoundsinGlassMessagenow usevolatilebacking fields, ensuring
writes from any thread are immediately visible on all architectures including ARM64. - CancellationToken callback crash (C1) — the
ct.Registercallback in
ShowModelessnow wrapsBeginInvokein atry/catchfor
InvalidOperationException/ObjectDisposedException, preventing an unhandled
exception that could crash the process when the dialog's handle is destroyed
concurrently with cancellation. - Hanging async tasks on shutdown (C2, C7) —
GlassMessage.ShowModelessand
GlassToast.ShowAsyncnow subscribe to the form'sDisposedevent and call
TrySetResultas a safety net, guaranteeing that every awaited task completes even
whenApplication.Exitdisposes forms without firingFormClosed. - Concurrent GDI+ bitmap access (C5) — system icons loaded from
SystemIcons/MessageBoxIconare now cloned per-dialog via a newResolveIcon
helper. The_ownsIconBitmapflag ensures clones are disposed while shared bitmaps
are left alone. - Toast options mutation —
GlassToast.Show/ShowAsyncresolved the theme into a
local variable instead of writing back into the caller'sGlassToastOptions, so
the same options object can be reused safely. - Toast race: form added to active list before handlers registered —
FormClosed
andDisposedare now registered before_active.Add, eliminating the window
where a fast OSWM_CLOSEcould leave a ghost entry in the stack. - Toast
OnClickexception suppressing dismiss — wrapped intry/finallyso a
throwing callback never prevents the toast from closing.
Animation & DPI
- Scale animation close-button hit-test (#5) —
_closeBtnBoundsis now
recalculated after every scale frame inApplyAnimationFrame, so the × button
remains clickable throughout the opening/closing animation. - DPI change corrupting animation state (#7) —
Rebuild()now resets all
animation flags (_scaleActive,_slideActive,_fadingOut) and disposes the
fade timer before rebuilding, preventing leftover state from corrupting the next
animation cycle. - Wrong initial DPI scale — the dialog now reads the DPI of the monitor under
the cursor at construction time viaGetDpiForMonitor+MonitorFromPoint
P/Invokes instead of using the primary monitor's device context. - Width cap using primary monitor —
MeasureFormnow accepts atargetScreen
parameter and caps width against the target screen's working area, not the primary.
GDI+ resource management
- Per-frame pen allocation (#11) — the input border pen is now pre-allocated
once in the constructor as_inputBorderPenand disposed inDispose(), avoiding
GDI+ handle churn on everyOnPaintcall. - Preset theme double-instantiation (#18) —
GlassTheme.Darkis now the same
object reference asGlassTheme.Default, halving font allocations for the default
case and making equality checks (Dark == Default) correct.
Drag behaviour
- Dialog draggable off-screen (#3) —
OnMouseMovenow callsClampToScreen
after each drag update, keeping the title bar (and drag handle) always reachable.
API correctness
GlassResultnull implicit conversion (#19) — theimplicit operator DialogResultnow usesr?.Button ?? DialogResult.Noneinstead ofr.Button,
preventing aNullReferenceExceptionwhen the result is assigned fromnull.InputDropdownnull argument crash (#1) — anullitemsenumerable no
longer throws; an empty dropdown is created instead.EM_SETCUEBANNERwParam — thewParamfor theEM_SETCUEBANNERmessage in
PlaceholderTextBoxis now1u(redraw even if focused), matching the MSDN spec
and ensuring placeholder text renders reliably.GlassDialogConfigproperty access modifiers (#17) — all properties on the
already-internalGlassDialogConfigclass are now explicitlyinternal,
removing misleadingpublicmodifiers that had no external effect but implied
wider accessibility than intended.
Docs & XML
Buttons(params string[])XML doc (#4) — updated to document the 3-label
maximum and explain that labels beyond the third are silently ignored.
Tests
- Added
[CollectionDefinition("GlassStaticState")]and applied
[Collection("GlassStaticState")]toGlassBuilderTestsand
GlassMessageStaticTests, serialising the classes that mutate global static state
so they cannot interfere with each other under xUnit parallel execution. - Added
CalcToastLocationTests— pure coordinate-math tests for all six
ToastPositionvalues plus stack-offset assertions. - Added
V102RegressionTests— targeted regression tests for theGlassResultnull
conversion,Dark == Defaultidentity, andInputDropdown(null)safety. - Updated xUnit packages:
xunitandxunit.runner.visualstudio→ 2.9.3,
Microsoft.NET.Test.Sdk→ 17.12.0.
Progress controller
- Documented the intentional fire-and-forget design of
BeginInvokein
GlassProgressController.Marshal—SetValue/SetMessageare best-effort UI
refreshes that must not block worker threads;Completionremains the correct
await point.
Marquee timer
- Halved marquee progress timer pressure: interval 16 ms → 33 ms (≈ 30 fps),
phase step scaled proportionally so visual speed is unchanged.
Full Changelog: v1.0.1...v1.0.2
Glass.Message v1.0.1
First public release. 🎉
Added
- Drop-in
MessageBoxreplacement —GlassMessage.Show(...)overloads that
are signature-compatible withSystem.Windows.Forms.MessageBox. - Fluent builder —
GlassMessage.Create(...)for composing dialogs. - Async dialogs — non-blocking, awaitable, and cancellable via
CancellationToken:GlassMessage.ShowAsync(...)for the basic message-box shape.GlassBuilder.ShowAsync()/ShowExAsync()so rich dialogs (input, checkbox,
dropdown) can be awaited too. Cancellation yieldsDialogResult.Cancel.
- Rich result —
ShowEx()/ShowExAsync()return aGlassResult(button +
checkbox state + typed input); implicitly converts toDialogResult. - Live progress —
GlassBuilder.ShowProgress()returns a thread-safe
GlassProgressControllerto update the bar (SetValue) and caption
(SetMessage) while work runs,Complete()it, awaitCompletion, and detect
user dismissal viaWasCanceledByUser. - Theming —
Dark,Light,Mica,HighContrast, andWindowsClassic
presets, plus fully customisableGlassThemeinstances. - Auto theme detection —
GlassTheme.AutoDetect()/IsSystemDark()follow
the Windows light / dark / high-contrast preference. - Modern chrome — Windows 11 rounded corners (DWM), Mica backdrop, and an
Acrylic blur fallback on Windows 10. - Inline inputs — single-line text, password (reveal eye + Caps Lock hint),
multi-line, and drop-down. - Checkbox, expandable detail panel, determinate / indeterminate
progress bars, countdown auto-close, and custom bitmap icons. - System sounds —
GlassBuilder.Sound()and the global
GlassMessage.PlaySystemSoundsplay the Windows sound matching the icon when a
dialog opens, like the classicMessageBox. - Animations —
Fade(default),SlideDown,Scale, andNone. - Keyboard —
Ctrl+Ccopies title + message;Enter/Escmap to sensible
results. - Right-to-left mirrored layout.
- Toast notifications —
GlassToastwith six anchor positions, auto-stacking,
click actions, and an async variant. Toasts are multi-monitor aware: they
auto-target the active window's screen (then the cursor's, then primary) and
stack per-screen; override withGlassToastOptions.Screen. - Cross-target build — .NET Framework 4.8.1 and .NET 8 / 9 / 10 (Windows);
AnyCPU, so the library runs in both x86 and x64 processes. - Release pipeline — pushing a
v*tag builds every target framework, runs
the tests, and publishes a GitHub Release with notes and downloadable assets.
Full Changelog: https://github.com/gcfernando/glass/commits/v1.0.1