This change replace the global rand use with a local source, to avoid
the recently deprecated global rand.Seed function. At the same time, the
time-dependent seeds are replaced with static numbers to ensure
reproducible benchmarks numbers.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This reverts commit 7fde80e805, because
Wakeup can no longer be called after the window has been destroyed.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
The goroutine started by Window.run runs concurrently with the user
goroutine receiving from Window.Events, leading to races such as #543.
This change replaces the Window.run goroutine and the Window.Events
channel with an iterator API driven by the user goroutine directly.
Fixes: https://todo.sr.ht/~eliasnaur/gio/543
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This change removes the extra frame scheduled when events was delivered
during a frame. This extra frame was intended to paper over state changes
that happen later than the layout depending on it.
However, it is better for programs to never allow such state change skew,
and recent changes allows them to refresh and query state before layout.
This is an API change because programs may rely on the extra frames.
Those programs should ensure that state is updated before relying on it
in layout.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This change allows users of Float to determine its state before Layout
by calling Update.
While here, remove the value transformation represented by the min, max,
invert parameters; they're too many arguments for a computation that
may as well be done by the user.
Remove Float.Pos; it is better to compute its value from the dimensions
returned by Float.Layout.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Similar to an earlier change for other widgets, this change separate
Enum state changes for access earlier than Layout.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Similar to a previous change for Clickable and Bool this change separates
state changes from Decorations.Layout to Actions so that access may
happen before Layout.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Similar to a previous change for Clickable, this change separates Bool
state changes to its renamed method Update. This allows access to
the most recent state before calling Layout.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Before this change, Clickable state updates would happen in Layout.
However, that is too late in cases where clicks affects layout that
contiains the Clickable.
This change removes state changes from Layout and moves them to Clicks,
to allow users pre-layout access. Note that Layout itself processes
events, which means users can no longer access clicks after Layout.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
The double-negative DisabledOp is harder to understand than a
straightforward EnabledOp. Note that the absence of an EnabledOp
implies still means that the widget is enabled.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
The NSWindow.zoomed property is not reliable when a window is being
constructed. Only call it when necessary.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit prevents the insertion of LineTo and QuadTo path segments that have
no visible effect on the path (because the path's pen is already at their end state).
This eliminates whisker artifacts from some stroked paths. Thanks to Morlay for the
bug report leading to this fix.
Fixes: https://todo.sr.ht/~eliasnaur/gio/535
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
As described in https://devblogs.microsoft.com/oldnewthing/20150304-00/?p=44543
Windows extends maximized windows outside the visible display. This is
not appropriate for custom decorated windows, so this change implements
a workaround in the handling of WM_NCCALCSIZE.
While here, replace the deltas field from window state to fix issues
when switching between decoration modes.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
When storing a string in an interface value that escapes, Go has to heap
allocate space for the string header, as interface values can only store
pointers. In text-heavy applications, this can lead to hundreds of
allocations per frame due to semantic.LabelOp, the primary user of
string-typed references in ops.
Instead of allocating each string header individually, provide a slice
of strings to store string-typed references in, and store pointers into
this slice as the actual references. This only allocates when resizing
the slice's backing array, and averages out to no allocations, as the
backing array gets reused between calls to Ops.Reset.
We introduce two new functions, Write1String and Write2String, which
make use of this new slice for their last argument. We could've
automated this in the existing Write1 and Write2 methods, but that would
require type assertions on each call, and the vast majority of ops do
not make use of strings.
Signed-off-by: Dominik Honnef <dominik@honnef.co>
NSView only has events for left, right, and other. Also, the Go side
wasn't actually checking for buttons other than left and right.
Signed-off-by: Dominik Honnef <dominik@honnef.co>
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.
While here, I realized that the iteration of hit areas needed to stop at
the first matching semantic area, and I added that capability and updated
the ActionAt logic to leverage it as well.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
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.
Fixes: https://todo.sr.ht/~eliasnaur/gio/528
Signed-off-by: Elias Naur <mail@eliasnaur.com>
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.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
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.
These changes result in much simpler code, and resolve a real bug. We were accidentally corrupting
cached paragraphs when doing the truncation post-processing in Shaper.layoutText. The modification
made to the final glyph there actually did modify the cached copy, which would then be reused when
that string was shaped again (even if there were a different number of truncated runes after it).
This changeset ensures that the cached copy of a paragraph is never modified.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
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.
This change restores the sync.Map synchronization, which avoids the
lifecycle issue.
Fixes: https://todo.sr.ht/~eliasnaur/gio/526
Signed-off-by: Elias Naur <mail@eliasnaur.com>
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.
The prior behavior always checked for this action type before
checking if the cursor was potentially in a window resize area, which meant that
for windows with material.Decorations, it was impossible to resize those windows
from their top edge. The system.ActionMove handler would always win. This is not
the case on platforms like macOS, so this commit makes the behavior consistent by
prioritizing resize over drag.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
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.
Fixes: https://todo.sr.ht/~eliasnaur/gio/525
Signed-off-by: Veikko Sariola <5684185+vsariola@users.noreply.github.com>
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.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
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.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit ensures that multiple newlines in a row still produce expected
results when occuring within a truncated string. The problem was that we usually
wrap text that is truncated in a way that forces the truncator symbol to appear
at the end *unless* we know we're on the final paragraph of the input text. This
is the right behavior for text that will be displayed, but when shaping a paragraph
containing nothing but a newline, we do not want the truncator symbol in our line.
I simply had to disable the forced truncation contextually to make it work.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit updates us to a version of go-text that correctly provides text
dimensions for the empty string when laying it out with width zero. Previously,
zero width would result in text with no height.
Fixes: https://todo.sr.ht/~eliasnaur/gio/518
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit fixes another rune accounting bug that the fuzzer discovered. If we
shaped a space in order to acquire line metrics, but the space itself was truncated,
we would reset the truncated count to zero. This had the side effect of lying to
later logic about whether the truncator run was present at the end of the shaped
text.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit updates the shaper fuzzer to try truncating the text, exposing
new edge cases.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit fixes another rune accounting issue that only existed when shaping
a solitary newline with zero width while truncating the line.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit tests and fixes some edge cases that threw off rune accounting
when a newline character was the final rune in the input *and* the text was
being truncated. I imagine they were never previously reported because it's
rare to try to truncate such text.
Thanks to Dominik Honnef for the report and reproducer.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
We previously were not handling glyphs that extended vertically beyond the
ascent/descent declared by their font. This is done rarely with text fonts,
but is apparently common among symbol and emoji fonts.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit removes the logic that calculates the bounding box of a line.
We don't actually use this information anywhere, so computing it is just
a waste of CPU and memory. Widgets arrive at their own bounding boxes from
consuming the glyph stream anyway.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit updates the strategy of our cursor positioning index to eliminate
cursor positions *after* trailing whitespace characters on a line. Eliminating
such cursor positions enables us to collapse trailing whitespace visually without
impacting the editability of text (this will be done in a future commit).
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
The previous logic kept the y offset of a line as a fractional value
until the last possible moment in an effort to be as true to a fractional
line height as possible (minimize the error), but this interacts pathologically
with multi-line text selections, as the selections may have visibly different
gaps between lines. It's better to always shift lines by a fixed quantity of
whole pixels, even if it is technically less accurate to the desired line height.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>