Newsletter, August 2023
Nice Custom Windows on Windows, Consistent Text Truncation, and Bugfixes

This month brings us Gio v0.3.0, which features richer integration of custom window decorations on Windows, changes to make text truncation behave consistently, and many other bugfixes.

Additionally, Gio-x v0.3.0 features RTL-aware layout helpers, rich/styled-text improvements, and some bugfixes for WASM and Go 1.21.

See each repo’s section for further details.


This month, Gio thanks the following organizations and community members for their ongoing support!

Supporting the whole team:

Supporting a maintainer:

Sponsorship money given to Gio enables Elias and I to cover the costs of running Gio’s infrastructure, to pay for some of our time spent maintaining and improving Gio, and to plan for funding significant feature work. You can support Gio by contributing on OpenCollective or GitHub Sponsors.

On Windows, Gio applications using app.Decorated(false) now cast drop shadows and snap to the edges of the screen like other applications. We thank Plato Team for supporting this work financially.

Additionally, the way that text truncation interacts with newlines has been changed. Previously if text had a limited number of lines and the final allowed line ended with a newline (but no following content) the truncator would not be displayed. However, if the final allowed line ended with a newline and had content after it, the truncator would be displayed. This was convenient for some use-cases, but the inconsistency in behavior could be extremely confusing for widget authors. Now a newline at the end of the final allowed line will always display a truncator symbol.

Veikko Sariola fixed a confusing interaction in which pressing space or enter could trigger a click event of the wrong button if the keyboard focus changed before release. This is technically a breaking behavior change, but it is unlikely that any applications were taking advantage of this behavior deliberately.

Dominik Honnef fixed a number of pointer input problems only affecting macOS users trying to use secondary and tertiary mouse features.

Elias (with the assistance of Dominik Honnef) hunted and fixed a number of application window lifecycle bugs on several platforms.

Breaking Changes by Author

Chris Waldon:

  • text: [API] be absolutely consistent about newline truncation. This commit changes the shaper’s behavior when truncating text. Previously, if the final line allowed by MaxLines ended with a newline, whether or not that newline was truncated depended upon whether we knew that there was more text after the current paragraph. However, this makes reasoning about what the shaper will do quite difficult. It seems better to be consistent. Now we will insert a truncator at the end of the final line if it has a trailing newline character, regardless of whether it ends the input text. 8679f49f

Veikko Sariola:

  • widget: click button only if key pressed and released. This commit fixes the non-intuitive behaviour, where hitting return or space with a button focused, then tabbing to another button and releasing the key causes the second button to trigger. It feels wrong, as the “gesture” was never initiated on the second button. The fix makes widget.Clickable track which key was pressed, in a variable called pressedKey, and only considers a key release if the released key matches the pressed key. Finally, if the widget loses focus, pressedKey is cleared. 290b5fe8

Non-Breaking Changes by Author

Elias Naur:

  • app: [Windows] make custom decorated windows behave like regular windows. 63550cc8
  • app: [Windows] enable drop shadows for custom decorated windows. 0e77a2b5
  • app: [macOS] fix display link callback race. Commit c0c25b777 replaced the synchronizing of the display link callback from a sync.Map to a cgo.Handle. However, the change didn’t take into account the lifecycle issues: a callback may happen just as the cgo.Handle is freed, leading to a misuse crash. 2e524200
  • app: [macOS] stop display after any events that may access it. Fixes: #527 e9d06196
  • app: [Wayland] avoid a race on the send side of the wakeup pipe. Discovered while debugging #528 with -race. 7fde80e8
  • internal/egl: call eglTerminate after context release. Without eglTerminate, using EGL will crash or report spurious errors after creating and destroying enough contexts. The test program in #528 takes 5-10 window cycles before errors show up for me. cf5ae4aa

Chris Waldon:

  • text: add android portability notice to NewShaper. NewShaper cannot be called prior to opening an application window on Android unless the application does not want system font support. Add a note to this effect to the constructor. 03c21dc1
  • io/router: fix system action routing logic. When running ActionAt, the router used to only consider the topmost clip area, even if that clip area had no input handlers attached whatsoever. This change updates the logic for that test to use the same traversal as normal event handling, ensuring that action inputs behave intuitively like any other pointer input area. Included is a test catching the problematic behavior that prompted this change. e9cb0b32
  • app: [Windows] ensure custom window decorations allow resize. This commit fixes a platform inconsistency that prevented custom-decorated windows from being resizable on edges where their custom decorations placed a draggable system.ActionInputOp. cc477e9c
  • text: simplify truncation accounting. This commit reverts the work of several previous attempts to resolve truncation-related rune accounting problems and adopts a simpler approach. Instead of taking a special codepath when shaping only a newline, we shape the empty string to get its line metrics. Instead of modifying the final glyph conditionally to account for runes we never actually shaped, we track that count on the document type and handle it withing the NextGlyph method. 83202263
  • io/router: fix semantic area traversal. This commit updates the logic behind SemanticAt to use the same hit area traversal as normal event routing, which should result in more accurate results for screen readers trying to resolve widgets that might be partially obscured by non-semantic content. f437aaf3

Dominik Honnef:

  • app: [macOS] handle middle mouse button correctly. NSView only has events for left, right, and other. Also, the Go side wasn’t actually checking for buttons other than left and right. 14bab8ef
  • app: [macOS] handle mouse dragging with buttons other than the left one. 89d20c7d

In x, the styledtext and richtext packages now offer some control over the line wrapping policy in use. This helps prevent words from being awkwardly broken over lines (the prior default behavior). However, this feature is not able to be implemented as intelligently as the line wrapping algorithm within the text shaper itself, so there is no equivalent of the text.WrapHeuristically option. Long term, this will be fixed by enabling rich text styling in core Gio widgets so that the styledtext package becomes unnecessary.

Ged Web reported a WASM breakage in introduced by Go 1.21. I was able to fix the opening of files, but it appears that saving files from your application to the host OS also needs some attention. I have not been able to resolve this yet, so WASM applications may not be able to save files on Go 1.21.

Additionally, now features some locale-aware layout helpers: outlay.Flex and outlay.Inset behave like layout.Flex and layout.Inset, but invert correctly when gtx.Locale.Direction == system.RTL. This makes it easier to build RTL-aware layouts. As a demonstration, has been updated to use these. I haven’t had the bandwidth to build locale-aware analogues of the other primitives in package layout, nor to convert the remainder of to use them, but both are possible and worthy goals. If you’re interested in helping out, patches are welcome!

Breaking Changes by Author

Chris Waldon:

  • styledtext: [API] allow configurable wrap policy. This commit enhances styledtext to allow the user to configure a line wrapping policy. The prior default behavior was equivalent to text.WrapGraphemes, which is often not desired. This commit changes the default to text.WrapWords and allows switching back. As such, this is a breaking behavior change. d5fa381

Non-Breaking Changes by Author

Chris Waldon:

  • component: make contextual overlay smarter. This commit updates the logic used to position the contextual widget given to ContextArea.Layout. Previously the context area would attempt to position it within the constraints given to the context area, but this could result in incorrect positioning if the context area did not actually fill those constraints within the final layout. 3234468
  • richtext: surface wrap policy in richtext API. This commit allows configuring the wrapping policy of a richtext.Text using the policies defined within styledtext.WrapPolicy. 2fe51d0
  • styledtext: handle gio text shaper behavior change. This commit updates styledtext to expect the Gio text shaper to truncate trailing newlines and adds a test for a pathological issue that these changes address. 3df1368
  • styledtext: handle too-long single words. If wrapping on words and a world longer than the max line length is encountered, we would previously mis-handle this case and corrupt the displayed text. Now such words are handled by allowing them to extend (invisibly) beyond the bounds of the styled text, as we cannot intelligently break them on grapheme clusters in this package. cc46c49
  • go.*: update gio for latest text changes. 92d9df4
  • outlay: add locale aware flex and inset types. This commit adds analogs to layout.Inset and layout.Flex that automatically respond to the system text direction provided by gtx.Locale and flip their visuals. This makes it easier to write RTL-aware layout code without significant logic changes. e2c1f14
  • component: make menu items RTL compatible. Thanks to Imran Iqbal for prompting me to do this. Imran submitted a great patch that manually flipped the presentation order of items based on locale, but I really didn’t want to have to do that everywhere. Instead, I defined some layout helpers that do the right thing based on the locale and used those to achieve the same effect for menu items. All of package component needs this conversion, but I can’t tackle the thorough testing required right now. 82c887a
  • explorer: fix byte copying from JS to Go. This commit updates our invocation of syscall/js.CopyBytesToGo to provide the expected concrete type of data. 27d6ce8
  • ci: use go 1.21. 9081dbd

The examples are all using the latest greatest APIs, but otherwise have no changes this month.

Changes by Author

Chris Waldon:

  • .builds: update linux version. d14eb12
  • kitchen: fix test theme constructor. a3f52ac
  • go.*: update to gio and gio-x v0.3.0. 3be33be


Thanks for reading!

Chris Waldon