Considering the possibility of re-running an event loop via run_ondemand
then it's more correct to say that the loop is about to exit without
assuming it's going to be destroyed.
This renames all internal implementations of pump_events_with_timeout
to pump_events and makes them public.
Since all platforms that support pump_events support timeouts there's
no need to have a separate API.
This layers pump_events on a pump_events_with_timeout API, like we have
for Linux and Android.
This is just an internal implementation detail for now but we could
consider making pump_events_with_timeout public, or just making it so
that pump_events() takes the timeout argument.
Considering the strict requirement that applications can't keep windows
across run_ondemand calls, this tries to make the window_ondemand example
explicitly wait for its Window to be destroyed before exiting each
run_ondemand iteration.
This updates the example to only `.set_exit()` after it gets a
`Destroyed` event after the Window has been dropped.
On Windows this works to ensure the Window is destroyed before the
example waits for 5 seconds.
Unfortunately though:
1. The Wayland backend doesn't emit `Destroyed` events for windows
2. The macOS backend emits `Destroyed` events before the window is
really destroyed.
and so the example isn't currently portable.
Although we document that applications can't keep windows between
separate run_ondemand calls it's possible that the application has only
just dropped their windows and we need to flush these requests to the
server/compositor.
This fixes the window_ondemand example - by ensuring the window from
the first loop really is destroyed before waiting for 5 seconds
and starting the second loop.
A minimal example that shows an application running the event loop more
than once via `run_ondemand`
There is a 5 second delay between each run to help highlight problems
with destroying the window from the first loop.
This re-works the portable `run()` API that consumes the `EventLoop` and
runs the loop on the calling thread until the app exits.
This can be supported across _all_ platforms and compared to the
previous `run() -> !` API is now able to return a `Result` status on all
platforms except iOS and Web. Fixes: #2709
By moving away from `run() -> !` we stop calling `std::process::exit()`
internally as a means to kill the process without returning which means
it's possible to return an exit status and applications can return from
their `main()` function normally.
This also fixes Android support where an Activity runs in a thread but
we can't assume to have full ownership of the process (other services
could be running in separate threads).
Additionally all examples have generally been updated so that `main()`
returns a `Result` from `run()`
Fixes: #2709
Wayland:
I found the calloop abstraction a little awkward to work with while I was
trying to understand why there was surprising workaround code in the wayland
backend for manually dispatching pending events.
Investigating this further it looks like there may currently be several issues
with the calloop WaylandSource (with how prepare_read is used and with (not)
flushing writes before polling)
Considering the current minimal needs for polling in all winit backends I do
personally tend to think it would be simpler to just own the responsibility for
polling more directly, so the logic for wayland-client `prepare_read` wouldn't
be in a separate crate (and in this current situation would also be easier to fix)
I've tried to maintain the status quo with calloop + workarounds.
X11:
I found that the recent changes (4ac2006cbc) to port the X11 backend
from mio to calloop lost the ability to check for pending events before
needing to poll/dispatch. (The `has_pending` state being queried
before dispatching() was based on state that was filled in during
dispatching)
As part of the rebase this re-introduces the PeekableReceiver and
WakeSender which are small utilities on top of
`std::sync::mpsc::channel()`. This adds a calloop `PingSource`
so we can use a `Ping` as a generic event loop waker.
For taking into account false positive wake ups the X11 source now
tracks when the file descriptor is readable so after we poll via
calloop we can then specifically check if there are new X11 events
or pending redraw/user events when deciding whether to skip the
event loop iteration.
The implementation of `pump_events` essentially works by hooking into the
`RunLoopObserver` and requesting that the app should be stopped the next time
that the `RunLoop` prepares to wait for new events.
Originally I had thought I would poke the `CFRunLoop` for the app directly and
I was originally going to implement `pump_events` based on a timeout which I'd
seen SDL doing.
I found that `[NSApp run]` wasn't actually being stopped by asking the RunLoop
to stop directly and inferred that `NSApp run` will actually catch this and
re-start the loop.
Hooking into the observer and calling `[NSApp stop]` actually seems like a
better solution that doesn't need a hacky constant timeout.
The end result is quite similar to what happens with existing apps that
call `run_return` inside an external loop and cause the loop to exit for
each iteration (that also results in the `NSApp` stopping each
iteration).
A surprising amount of work was required to enable these extensions
on Windows.
I had originally assumed that pump_events was going to be very similar
to run except would use PeekMessageW instead of GetMessageW to avoid
blocking the external loop but I found the Windows backend broke
several assumptions I had.
Overall I think these changes can hopefully be considered a quite a
significant simplification (I think it's a net deletion of a fair amount
of code) and I think it also helps bring it into slightly closer alignment
with other backends too
Key changes:
- I have removed the `wait_thread` that was a fairly fiddly way of handling
`ControlFlow::WaitUntil` timeouts in favor of using `SetTimer` which works
with the same messages picked up by `GetMessage` and `PeekMessage`.
- I have removed the ordering guarantees between `MainEventsCleared`,
`RedrawRequested` and `RedrawEventsCleared` events due to the complexity in
maintaining this artificial ordering, which is already not supported
consistently across backends anyway (in particular this ordering already
isn't compatible with how MacOS / iOS work).
- `RedrawRequested` events are now directly dispatched via `WM_PAINT` messages
- comparable to how `RedrawRequested` is dispatched via `drawRect` in the
MacOS backend.
- I have re-worked how `NewEvents`, `MainEventsCleared`, and `RedrawEventsCleared`
get dispatched to be more in line with the MacOS backend and also more in line
with how we have recently discussed defining them for all platforms.
`NewEvents` is conceptually delivered when the event loop "wakes up" and
`MainEventsCleared` gets dispatched when the event loop is about to ask the
OS to wait for new events.
This is a more portable model, and is already how these events work in the
MacOS backend.
`RedrawEventsCleared` are just delivered after `MainEventsCleared` but this
event no longer has a useful meaning.
Probably the most controversial thing here is that this "breaks" the ordering
rules for redraw event handling, but since my changes interacted with how the
order is maintained I was very reluctant to figure out how to continue
maintaining something that we have recently been discussing changing:
https://github.com/rust-windowing/winit/issues/2640.
Additionally, since the MacOS backend already doesn't strictly maintain this
order it's somewhat academic to see this as a breakage if Winit applications
can't really rely on it already.
This updates the documentation for `request_redraw()` to reflect that we
no longer guarantee that `RedrawRequested` events must be dispatched
after `MainEventsCleared`.
This adds two new extensions for running a Winit event loop which will
replace `EventLoopExtRunReturn`
The `run_return` API is trying to solve multiple problems and address
multiple, unrelated, use cases but in doing so it is not succeeding
at addressing any of them fully.
The notable use cases we have are:
1. Applications want to be able to implement their own external
event loop and call some Winit API to poll / pump events, once
per iteration of their own loop, without blocking the outer,
external loop. Addressing #2706
2. Applications want to be able to re-run separate instantiations
of some Winit-based GUI and want to allow the event loop to exit with
a status, and then later be able to run the loop again for a new
instantiation of their GUI. Addressing #2431
It's very notable that these use cases can't be supported across
all platforms and so they are extensions, similar to
`EventLoopExtRunReturn`
The intention is to support these extensions on:
- Windows
- Linux (X11 + Wayland)
- macOS
- Android
These extensions aren't compatible with Web or iOS though.
Each method of running the loop will behave consistently in terms of how
`NewEvents(Init)`, `Resumed` and `LoopDestroyed` events are dispatched
(so portable application code wouldn't necessarily need to have any awareness
of which method of running the loop was being used)
Once all backends have support for these extensions then we can
remove `EventLoopExtRunReturn`
For simplicity, the extensions are documented with the assumption that
the above platforms will be supported.
This patch makes no functional change, it only introduces these new
extensions so we can then handle adding platform-specific backends
in separate pull requests, so the work can be landed in stages.
Unfortunately this isn't a total removal, for two reasons:
- We still need "libc" for the Xlib XIM implementation, for locales.
- BSD requires libc to check for main-threadedness.
First one we can likely resolve in the near future, not so sure about
the second one without using some weird pthreads trick.
The utils in this module should help the users to activate the windows
they create, as well as manage activation tokens environment variables.
The API is essential for Wayland in the first place, since some
compositors may decide initial focus of the window based on whether
the activation token was during the window creation.
Fixes#2279.
Co-authored-by: John Nunley <jtnunley01@gmail.com>
It was discovered that on GNOME the click sometimes being swallowed
by the mutter's `wl_pointer::enter/leave` sequences. This was happening
due to `xdg_toplevel::move` making the pointer to leave the surface.
To make handling of that more robust, we could start the
`xdg_toplevel::move` when the actual pointer motion is being performed.
Links: https://github.com/alacritty/alacritty/issues/7011
Links: https://gitlab.gnome.org/GNOME/mutter/-/issues/2669#note_1790825
This should provide a way to iterate all the tabs and select the last
tab. The tab indicies are now zero based as any other sane index.
Follow-up-to: c5941d105f (add tabbing API)
Winit now supports tabbing identifiers, thus set that we prefer tabbing,
in particular it'll make windows tab when using the same tabbing identifiers,
which is desirable for the end users.
Some systems could resize the window immediately and we'd rather
inform the users right away if that was the case, so they could
create e.g. EGLSurface without waiting for resize, which is really
important for Wayland.
Fixes#2868.
Instead of a single `bool` indicating that a key press has occured and
no key has been released since then, we store the scancode of the last
pressed key (if it is a key that repeats when held). This fixes a bug
where pressing a new key while one is already held down will be flagged
as a repeat even though it is obviously not a repeat.
* Make iOS declared classes not use &mut
* Prepare `init` methods for not having access to &mut self
* Prepare WinitWindow methods for not having access to &mut self
* Convert a bit of WinitView's to use interior mutability
* Convert a bit more of WinitView's to use interior mutability
* Convert the rest of WinitView to use interior mutability
* Use interior mutability instead of a Mutex for the CursorState
* Use interior mutability in WinitWindowDelegate
The change to xinput2 completely disabled IME support, thus we've got
a dead keys reporting, because nothing was eating the key events
anymore, however that's not what we really need, given that not
working IME makes it impossible for some users to type.
The proper solution is to not use Xlib at all for that and rely on
xcb and its tooling around the XIM and text compose stuff, so
we'll have full control over what is getting sent to the XIM/IC or not.
Fixes#2888.