Compare commits

..

911 Commits

Author SHA1 Message Date
dependabot[bot]
ba6da05252 chore: bump the github-actions group across 1 directory with 3 updates
Bumps the github-actions group with 3 updates in the / directory: [actions/cache](https://github.com/actions/cache), [actions/checkout](https://github.com/actions/checkout) and [actions/upload-pages-artifact](https://github.com/actions/upload-pages-artifact).


Updates `actions/cache` from 5 to 6
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v5...v6)

Updates `actions/checkout` from 6 to 7
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

Updates `actions/upload-pages-artifact` from 4 to 5
- [Release notes](https://github.com/actions/upload-pages-artifact/releases)
- [Commits](https://github.com/actions/upload-pages-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/upload-pages-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-24 18:53:04 +00:00
Vitaly Kravchenko
27e17e3f29 Fix AppKit live resize redraw timing 2026-06-24 17:03:24 +02:00
Simon Hausmann
56fde0791b Fix CI
Pin wayland-protocols to the previous version that still compiles with
our MSRV.
2026-06-24 16:58:57 +02:00
William-Selna
4ef144b519 macOS: make Ime::Preedit cursor range surrogate-safe in setMarkedText
`setMarkedText:selectedRange:replacementRange:` converted the IME's UTF-16
`selectedRange` into UTF-8 byte offsets by taking `substringToIndex:` prefixes
and measuring them with `NSString::len()`
(`lengthOfBytesUsingEncoding:NSUTF8StringEncoding`). When an index falls inside
a surrogate pair, the prefix ends in a lone high surrogate, which UTF-8 cannot
represent, so `lengthOfBytesUsingEncoding:` returns 0 for the entire prefix and
the offset silently collapses to 0.
2026-06-20 01:34:43 +09:00
Mads Marquart
7fe8c206ae chore: avoid unsafe in examples
By using `OwnedDisplayHandle`, which uses reference-counting, instead of
`DisplayHandle<'static>` (where the user has to guarantee that the
Application doesn't outlive the event loop).
2026-06-15 03:36:22 +09:00
Sergey Kikevich
fb78ecbb03 windows: fix freeze on keyboard layout switch
Any winit app on Windows freezes when the keyboard layout is switched by
tools such as Punto Switcher. A minidump of the frozen process shows the
main thread blocked in MsgWaitForMultipleObjectsEx (winit's event-loop
wait), re-entered during message dispatch through the switcher's injected
global hook (pshook64.dll, via CallNextHookEx) — a re-entrant Win32
message-loop wait, not a mutex deadlock (no LAYOUT_CACHE frames present).

Handle WM_INPUTLANGCHANGE to refresh the cached keyboard layout, then
defer to DefWindowProc so the message still propagates to first-level
child windows as the Win32 docs require. The cache refresh is the minimal
change that stops the freeze (verified on Windows 11 by isolation
variants); update_modifiers and swallowing the message are not needed.
2026-06-15 03:29:35 +09:00
Martin Marmsoler
850d5f59a7 winit-wayland: add pointer gesture hold 2026-06-13 02:36:23 +09:00
Martin Marmsoler
81b2729765 winit-x11: fix clippy lint 2026-06-05 02:25:58 +09:00
Kirill Chibisov
c4afadbfab winit-wayland: use ext-background-effect if available
A more modern protocol compared to the KDE one.
2026-04-04 23:59:33 +09:00
dependabot[bot]
b5252f1366 chore: bump actions/configure-pages (#4550) 2026-03-28 07:44:01 +01:00
Mads Marquart
f93a223da9 Clean up cargo-deny
Remove the matrix in the CI action; EmbarkStudios/cargo-deny#324 hasn't been resolved yet, but since we've split Winit out into multiple crates, there's still value in minimizing dependency conflicts even if they won't be hit by users, since e.g. Rust-Analyzer will by default check the entire workspace (and thus download and compile duplicate dependencies).
2026-03-28 10:28:31 +09:00
dependabot[bot]
d75a0dada0 chore: bump actions/deploy-pages from 4 to 5 (#4545) 2026-03-26 06:32:41 +01:00
Mads Marquart
9bf46af6f7 AppKit: Use fn_addr_eq now that it's in MSRV (#4532) 2026-03-26 05:50:16 +01:00
Mads Marquart
464c37a94e Remove leftover apple/appkit/mod.rs (#4533) 2026-03-26 05:49:49 +01:00
Mads Marquart
557d285170 Remove symlinking between winit-appkit and winit-uikit (#4530) 2026-03-26 05:49:12 +01:00
Mads Marquart
ba856e127a Fix CI (#4546)
* Fix cargo-deny erroring on new jni-sys version
* Fix unicode-segmentation bumping MSRV
* Fix cargo-deny finding new script in android-activity
2026-03-26 05:26:54 +01:00
Charlie Tonneslan
0ffd303db6 fix(typo): dependant -> dependent (#4540) 2026-03-24 15:54:31 +01:00
Mads Marquart
5a74bf0aab Android: Add further scancode conversions (#4023)
Firefox' source at:
https://searchfox.org/mozilla-central/rev/c597e9c789ad36af84a0370d395be066b7dc94f4/widget/NativeKeyToDOMCodeName.h

Seems to use some other form of scan code? So instead we try to map as
many of the codes available on `Keycode` that they do as possible.
2026-03-19 02:27:23 +01:00
Mads Marquart
117ec364f9 examples: Always use tracing helper module 2026-03-18 22:55:47 +01:00
Mads Marquart
9f789e56ee examples: Use tracing macros instead of println!
This allows the examples to work a bit better in WASM and on iOS.
2026-03-18 22:55:47 +01:00
Mads Marquart
91558169d2 example: Fix tracing registration in pump_events
Tracing subscribers must be set up before `EventLoop::new()`.
2026-03-18 22:55:47 +01:00
Mads Marquart
4998cb990f AppKit: Trace sendEvent: calls
Most events in AppKit go through `sendEvent:`, and they contain a lot of
information, so it's nice to surface this when debugging.

We could override `sendEvent:` in UIKit and track this in there too, but
that's much less important, since there the relevant events are fairly
narrowly scoped, see the link below, other events go through CFRunLoop.
https://developer.apple.com/documentation/uikit/uievent/eventtype
2026-03-18 22:55:47 +01:00
Mads Marquart
98692641c4 UIKit: Add tracing spans 2026-03-18 22:55:47 +01:00
Mads Marquart
a630b5333c Apple: Track spans across queued closures 2026-03-18 22:55:47 +01:00
Mads Marquart
ca7735f10b Apple: Use tracing spans instead of custom trace_scope! macro
Spans are more powerful, and can even optionally be emitted as events by
using `.with_span_events(tracing_subscriber::fmt::format::FmtSpan::*)`.
2026-03-18 22:55:47 +01:00
Mads Marquart
7adb805011 Apple: Trace CFRunLoop activities
Add two run loop observers that:
- Create a TRACE-level span when the run loop enters a new state.
- Drops the span when the run loop exits that state.

These spans attach information to events, such that e.g. resizing a view
produces messages like:
```
TRACE inside runloop{mode=NSEventTrackingRunLoopMode}:timers:
  winit_appkit::util: Triggered `drawRect:` target="winit_appkit::view"
TRACE inside runloop{mode=NSEventTrackingRunLoopMode}:timers:
  winit_appkit::util: Completed `drawRect:` target="winit_appkit::view"
```
2026-03-18 22:55:47 +01:00
Mads Marquart
a8c7d809b9 Use new macOS 15 cursors for resize icons (#4422)
These look slightly different from the old ones. Verified that we now
use the same cursor icons as those used in Safari 26.
2026-03-18 22:33:53 +01:00
RandomScientist
4d81f4aa62 internal(macOS) use NSTrackingArea instead of trackingRect (#4514) 2026-03-18 02:03:16 +01:00
Mads Marquart
4f29aed5ee Synchronize changelogs with v0.30.13 2026-03-17 23:22:47 +09:00
Mads Marquart
7864d02077 Remove indentation in fill.rs helper 2026-03-17 04:34:15 +01:00
Mads Marquart
0f2d59cbba Allow building examples using softbuffer on Android
These probably aren't runnable in the current state, but it should at
least allow us to get rid of a bunch of cfgs.
2026-03-17 04:34:15 +01:00
Mads Marquart
f0c4adc58c Update to softbuffer v0.4.8 2026-03-17 04:34:15 +01:00
junglie85
8e38112ad3 Add Send and Sync to OwnedDisplayHandle (#4509) 2026-03-17 03:54:42 +01:00
RandomScientist
6f3d763650 Document potential user expectation of ctrl+left click behavior on macOS. (#4518) 2026-03-17 03:39:12 +01:00
Ali
7a11ff8766 Add missing scancodes for orbital (#4515)
add missing keymaps
2026-03-17 03:29:27 +01:00
jgcodes2020
211ae8f6c7 winit-x11: replace XQueryKeymap with equivalent x11rb call (#4497)
And slightly optimize the first_bit helper function.
2026-03-17 03:15:48 +01:00
RandomScientist
0b6b794f01 fix(macOS) "fix" toggling IME on appkit backend (#4512)
Co-authored-by: Random-Scientist <Random-Scientist@users.noreply.github.com>
2026-03-14 02:50:13 +01:00
Marijn Suijten
5e2f421e34 fix(android): Populate KeyEvent.text via Key::to_text()
The `text` field on `KeyEvent` was hardcoded to `None` on Android,
making it impossible for custom `NativeActivity` subclasses that
show the IME to receive functional text input using *for example* the
existing `winit-egui` crate which relies on this field being set.

Use `Key::to_text()` on press events to derive `text` from
`logical_key`, matching the convention used by the Windows and macOS
backends.

Supposedly that doesn't include all kinds of special virtual unicode
keys, but at least the basics work this way.
2026-03-02 22:37:30 +09:00
Pedro Macedo
41f4265957 wayland: implement resize increments 2026-03-01 22:28:35 +09:00
Kotomine Shiki
c535968128 win32: fix ime setcontext lparam
Fixes #3893.
2026-03-01 22:08:45 +09:00
Takaranoao
85ff2fa093 fix(macOS): clamp IME selected_range to prevent substringToIndex crash
macOS native Pinyin IME can send a selected_range that exceeds the
marked text string length (e.g. index 8 for a 6-character string).
This caused an NSRangeException in substringToIndex:, crashing the
application with SIGABRT.

Clamp both location and end to the string's UTF-16 length before
calling substringToIndex.
2026-03-01 21:55:06 +09:00
voxelmagpie
44865be79d wayland: fix panic when fancy wacom tablet is connected
With some setups certain events were not handled leading to crashes,
thus add missing handles.

Fixes #4493.
2026-02-28 15:07:40 +09:00
SuchAFuriousDeath
f3fb2fe3a6 winit-x11: fix debug mode overflow panic in set_timestamp
Fixes #4484
2026-02-24 23:15:49 +09:00
Mads Marquart
fa10ca1764 Refactor usage of CFRunLoopObserver (#4349)
Added a common interface that:
- Uses closures instead of static functions. This should allow easier
  refactoring in the future.
- Returns a handle which is invalidated on `Drop`. This should avoid
  situations where the event loop has exited, but an observer is still
  called because the user spawned the application later on.
- Is properly main-thread safe.

This interface is placed in winit-common, to allow using it in both
winit-appkit and winit-uikit.
2026-02-17 16:21:18 +01:00
Mads Marquart
4fda048729 Reduce duplication in dpi module (#2148)
* Deduplicate Pixel impl for integers using a macro
* Deduplicate [Logical|Physical][Size|Position] From impls using a macro

Co-authored-by: Osspial <osspial@gmail.com>
2026-02-17 15:45:53 +01:00
Tarek Abdel Sater
983e50971d macOS: fix borderless game resetting after switching spaces (#4482) 2026-02-11 22:14:10 +01:00
DorotaC
cf9daedb18 wayland IME: Discard completed delete request
Co-authored-by: dcz <gilapfco.dcz@porcupinefactory.org>
2026-02-07 00:31:07 +09:00
isan
5218e11e55 reafactor(orbital): Reimplement Orbital support using std::fs and redox_event (#4470)
Implemented Send and Sync for EventQueue
2026-02-03 16:23:40 +01:00
John Nunley
b8f28efd04 wayland: Move hash algorithm to foldhash
At the moment, the wayland code uses ahash to perform hashing
in its various hash mas. This was done because ahash was seen as
the best default in the Rust community at the time. However, most
Rust crates (including `hashbrown`) have since moved to using
foldhash instead.

This move is done for two primary reasons:

- This reduces the number of dependencies in the tree for most GUI
  projects. As other projects use foldhash now, this removes ahash
  (as well as its five dependencies) from the tree.
- In most cases, foldhash is faster than ahash.

Signed-off-by: John Nunley <dev@notgull.net>
2026-01-29 09:15:25 +09:00
dependabot[bot]
eced28824b chore: bump taiki-e/cache-cargo-install-action (#4456) 2026-01-28 19:34:50 +01:00
Jack
b3c7635bba Add Apple Pencil support on iOS (#4449)
With force, altitude, and azimuth data handling
2026-01-28 19:24:38 +01:00
Mads Marquart
4aac778d2a chore: appease clippy (#4471) 2026-01-28 19:12:39 +01:00
Colin Finck
043c8635a9 Upgrade windows-sys dependency to 0.61 (#4464) 2026-01-20 20:49:03 +01:00
dependabot[bot]
da6220060e chore: bump the github-actions version 2025-12-21 19:44:09 +09:00
Anhad Singh
50f9b84f6b fix(winit-orbital): handle EINTR when reading from event_socket
Signed-off-by: Anhad Singh <andypython@protonmail.com>
2025-12-18 18:42:54 +09:00
itsamine27
56333064ac winit-win32: Fix ABI mismatch in INIT_MAIN_THREAD_ID
Fixes #4435.
2025-12-16 22:50:14 +09:00
Silico_Biomancer
de78ffdfed winit-x11: replace xfixes with x11rb in set_hittest
The xfixes implementation is not that reliable and rather simple to
replace, so use x11rb to implement the same functionality.

Fixes #4120.
Co-authored-by: avitran0 <holyhades64@gmail.com>
2025-11-25 11:06:39 +09:00
Mads Marquart
2d56ed1099 Fix issue template labels (#4421) 2025-11-24 13:50:34 +01:00
Diggory Hardy
7b1dd52ad1 winit-core/ime: implement Error for ImeSurroundingTextError 2025-11-20 19:18:48 +09:00
richerfu
6a46610632 feat(core): add keyboard for ohos 2025-11-17 15:56:20 +09:00
Kirill Chibisov
27233f575f Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2025-11-17 15:45:12 +09:00
Kirill Chibisov
f2ba68771f winit-core: fix set_ime_allowed always panicing 2025-11-16 16:39:15 +09:00
Mads Marquart
cc23fbf3be winit/event_loop: Add register_app and run_app_never_return
To allow users to explicitly choose the run semantics that they want.
2025-11-16 16:25:44 +09:00
Mads Marquart
c98d880a1c winit-web: return immediately from run_app on web
This avoids using JavaScript exceptions to support `EventLoop::run_app`
on the web, which is a huge hack, and doesn't work with the Exception
Handling Proposal for WebAssembly:
https://github.com/WebAssembly/exception-handling

This needs the application handler passed to `run_app` to be `'static`,
but that works better on iOS too anyhow (since you can't accidentally
forget to pass in state that then wouldn't be dropped when terminating).
2025-11-16 16:25:44 +09:00
Kirill Chibisov
165c163f01 Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2025-11-16 13:53:23 +09:00
Kirill Chibisov
0a59e4b905 chore: fix clippy on X11 2025-11-16 13:07:23 +09:00
ShikiSuen
d837c88855 winit-appkit: fix tests on systems without MonitorId(1)
Use `CGMainDisplayID` instead of `1` to make tests pass on systems
without `MonitorId(1)`.
2025-11-06 14:46:28 +09:00
Dan Harris
82eab465e0 macOS: fix a crash when dragging non-file content onto window
Winit only supports text, thus we should ignore the rest
instead of crashing.
2025-11-05 13:20:01 +09:00
Diggory Hardy
a9c189a423 winit-win32: prevent inner size reported as (0,0) when minimized 2025-11-01 23:39:57 +09:00
Diggory Hardy
9d9d21cfdb winit-core: revise MouseButton type
Unify the values of `MouseButton` and thus remove `Other` variant in
limit possible buttons to 32, which was picked based on platform
capabilities, where 32 is the highest.

For the reference, SDL has identical limit.
2025-11-01 21:00:39 +09:00
Kirill Chibisov
779f52a21f chore: latest typos 2025-11-01 21:00:39 +09:00
mfluehr
7a21858d29 windows: don't confine hidden cursor 2025-11-01 13:03:11 +09:00
Kirill Chibisov
a3f7e6566a ci: fix eslint version to 9.38.0
9.39.0 has an issue with unified-signatures.

Links: https://github.com/eslint/eslint/issues/20272
2025-11-01 12:52:30 +09:00
DorotaC
f41897cfa4 examples/ime: fix crash on wayland
When pressing Ctrl+Space, KeyEvent::text_with_all_modifiers would return
\0. That would get included in the text-input text. When an input method
gets activated, the invalid string returning \0 would get sent as
surrounding text, resulting in a Wayland protocol error and crashing the
application.
2025-10-29 13:40:30 +09:00
Timon
bd6fef1d80 wayland: add prefer_csd attribute 2025-10-24 21:35:51 +09:00
Kirill Chibisov
42d256e926 ci: fix version of smol_str 2025-10-24 21:01:20 +09:00
Pavel Strakhov
03dad26c43 x11: ignore mouse scroll button release events 2025-10-24 20:07:10 +09:00
Kirill Chibisov
1e7ab0cd25 wayland: handle wl_seat v10 repeated state
Fixes #4382.
2025-10-20 00:01:36 +09:00
Kirill Chibisov
c333003514 Bump MSRV to 1.85 and edition to 2024 2025-10-20 00:01:36 +09:00
Arthur Cosentino
10f21090ce x11: fix deadlock in request_ime_update 2025-10-09 16:57:20 +09:00
Timon
5575f51483 wayland: add wayland-csd-adwaita-notitlebar feature
Addition to already present `notitle` feature.
2025-10-08 12:11:55 +09:00
Ian Douglas Scott
2ede84ab2f wayland: handle axis_value120 scroll events
This can be tested with the `application` example, looking at the events
shown for mouse wheel movement.

`wl_pointer::axis_discrete` isn't sent in version 8 or higher of
`wl_pointer`. And `sctk` doesn't convert the `value120` events, so
on compositors advertising version 8, only pixel scroll events were
being sent.

This sends `MouseScrollDelta::LineDelta` with a fractional value,
without doing any accumulation. Given `LineDelta` contains `f32` values,
this presumably is expected?

Though it might be good to change the definition of `MouseScrollDelta`
to include both discrete and pixel values, when the compositor sends
both. I'm not familiar with how this works on non-Wayland backends
though.
2025-10-08 11:53:57 +09:00
Kirill Chibisov
f046e778aa winit-core:winit: add tablet input support
The API is integrated into the `WindowEvent::Pointer*` API and is
present in form of `TabletTool` variant on corresponding data entries.

For now implemented for Web, Windows, and with limitations for Wayland.

Fixes #99.

Co-authored-by: daxpedda <daxpedda@gmail.com>
2025-10-07 21:42:36 +09:00
sachharine
ffcdf80192 chore: fix typos causing dead links 2025-10-07 19:25:41 +09:00
Mads Marquart
b811e9d878 chore: update to objc2 frameworks v0.3.2 2025-10-07 17:56:05 +09:00
Kirill Chibisov
d815bc089c chore: fix nightly clippy 2025-10-07 17:56:05 +09:00
Kirill Chibisov
66283a79bd wayland: reduce amount of empty preedits
If we send empty preedit before, don't send it again.
2025-09-13 06:53:29 +09:00
Alan Everett
3be30affe4 wayland: support for pinch, rotation, and pan gestures
Co-Authored-By: linkmauve <linkmauve@linkmauve.fr>
Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
2025-09-07 11:45:35 +09:00
Kirill Chibisov
a68f1a664b winit-wayland: bump sctk and sctk-adwaita 2025-09-06 22:25:24 +09:00
DorotaC
6de5041a94 winit-core/ime: add more purposes and content hints
Also move IME example into `ime.rs` thus making IME integrations more
easily comprehendible.

Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
2025-09-06 13:27:55 +09:00
Mads Marquart
014fb68a26 Fix using Rust-Analyzer on non-macOS platforms (#4347) 2025-09-05 22:32:20 +02:00
Mads Marquart
9a03dacbde linux: align scancode conversions with Chromium 2025-09-05 10:17:34 +09:00
Jeremy Soller
4d9302b33c Add borderless fullscreen mode for orbital (#4343) 2025-09-04 22:14:41 +02:00
moooozi
488c036a05 win32: disable DPI re-adjustments on Windows 11
For earlier Windows 10 builds (pre-22000), a workaround was necessary
to fix dragging window onto a monitor with different DPI. This commit makes
the old DPI workaround  to only apply conditionally on affected Windows versions.

Fixes #4041.
2025-08-24 12:57:31 +09:00
Tony
a4af50ec13 win32: refresh title bar on Window::set_theme 2025-08-23 21:55:54 +09:00
Tony
317d62fb93 win32: account for mouse wheel speed setting
Also adds a method to toggle this behavior during runtime.
2025-08-23 21:38:56 +09:00
dependabot[bot]
b13b39aa0b chore: bump ci deps versions 2025-08-23 21:19:46 +09:00
Sanjay
abea6e64e4 macOS: default menu uses bundle name
Use the bundle name in the default menu or fall back
to using the process name as before.
2025-08-23 20:35:45 +09:00
Jeremiah S
d6f7a28499 macOS: fix crash due during window drop
On macOS 26+ the window drop was leading to unwrap, since
events were coming after the window was already destroyed,
while it sounds rather strange, guard against such things just
in case.

Fixes #4333.
2025-08-15 09:52:23 +09:00
Kirill Chibisov
bd98561b38 chore: fix typos from recent typos-cli (#4329) 2025-08-12 16:30:34 +09:00
John Nunley
ca6f523924 m: remove self from CODEOWNERS
This is making official what's basically been the
case for the past few months at this point. I no
longer have the capacity to effectively review
and merge PRs for the Windows and X11 backends.

Thanks again for having me.

Signed-off-by: John Nunley <dev@notgull.net>
2025-08-04 02:50:06 +09:00
DorotaC
d7fdfb1bca winit-core: add Ime::DeleteSurroundingText API
This completes the basic API required for e.g. Wayland.
2025-08-02 19:17:27 +09:00
Kirill Chibisov
120f21a010 Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2025-07-27 22:13:06 +09:00
Robert Wallis
5904529ba1 macOS: fix runtime crash on macos26 "type code 'q', but found 'Q'"
Fixes #4299.
2025-07-20 17:04:04 +09:00
DorotaC
e7a6034b55 winit-core: add surrounding_text for IME
Allow communicating surrounding text to IME to better handle user input
and account for content around for preedit.
2025-07-13 14:57:10 +09:00
DorotaC
eb66c25980 chore: fix typos
Latest typos found more issues.
2025-07-03 08:30:22 +09:00
DorotaC
0ccb8a9f87 example: fix toggling IME 2025-06-30 11:51:46 +09:00
DorotaC
abed32eb80 winit-core/window: wrap ImeCapabilities in struct
To prevent user from using `::all()` and thus writing not forward
compatible code wrap the bitflags struct and provide simpler interface
to it.
2025-06-29 13:53:47 +09:00
DorotaC
08907148ec winit-core/window: add Window::request_ime_update
Allow updating IME state atomically to make it easier for platforms
where it's atomic by its nature, like Wayland. The old API is marked
as deprecated and is routed to the new atomic API.

Co-authored-by: dcz <gilapfco.dcz@porcupinefactory.org>
2025-06-28 13:14:20 +09:00
Kirill Chibisov
fa0795a50c examples/application: fix running on wasm
Was using `time` unconditionally.
2025-06-24 19:15:46 +09:00
Enn3Developer
fe1eab07ae wayland: add xdg_toplevel_icon_v1 support
Closes: #3859.
2025-06-22 19:40:05 +09:00
Kirill Chibisov
552c7a6252 winit: silence wasm on nightly
The lint is needed for stable, but is no longer present on nightly, so
silence it for the time being.
2025-06-22 19:29:27 +09:00
Jeremy Soller
50c0180af3 winit-orbital: update to new path format 2025-06-17 14:46:09 +09:00
Mads Marquart
4f33643509 chore: make git checkout build on Windows with symlinks disabled 2025-06-10 07:37:36 +09:00
Kirill Chibisov
0b21c55b72 winit-core/as_any: fix Box<AsAny> casting
The casting was doing an incorrect check on the `ref` instead of
actually trying to downcast a ref as `cast_ref` does. So use `cast_ref`
to check whether we can safely `cast` to owned type.
2025-06-08 22:11:02 +09:00
Mads Marquart
e1bccb68d8 chore: use a shared version number for all winit-* crates 2025-06-08 09:22:58 +09:00
Mads Marquart
e540062ac0 iOS: Avoid RefCell and static mut (#4255)
* iOS: Refactor queued_gpu_redraws out from AppStateImpl

To allow AppStateImpl to be Copy, and to move redraws into the window in
the future.

* iOS AppState: Avoid RefCell and static mut

Instead, prefer Cell and Copy types, as those will never have crashes
on re-entrancy / if forgetting to make a state transition.
2025-06-07 23:16:41 +02:00
Martin Fischer
f1e0f6c646 icon: add PartialEq and Hash for RgbaIcon 2025-06-08 01:18:55 +09:00
Mads Marquart
3218316420 Document platform-specific modules 2025-06-07 22:43:38 +09:00
Mads Marquart
2900ecab93 winit-core/keyboard: use keyboard_types
Closes #2394.
2025-06-07 16:47:47 +09:00
Kirill Chibisov
3a84da6951 Move winit itself to crate
That way we use top-level Cargo.toml only for the workspace management
purposes.
2025-06-07 13:07:12 +09:00
Mads Marquart
478427b0bd Remove the need for cfg_aliases in winit-core (#4271) 2025-06-06 13:24:01 +02:00
Mads Marquart
b0f26c79ff Fix CI (#4270)
* Fix typos
* Remove OsError in winit-web
2025-06-05 13:10:30 +02:00
Kirill Chibisov
969237f422 Bump rustix to 1.0.0 2025-05-27 16:31:11 +09:00
Mads Marquart
e542a78deb Move Web backend to winit-web 2025-05-26 14:56:00 +09:00
Kirill Chibisov
2d4b9938f0 ci/deny: add rustix
Will take a while to move to 1.0 for everyone.
2025-05-26 14:56:00 +09:00
Mads Marquart
8ad016362a chore: move event loop recreation check into backends themselves 2025-05-26 13:48:52 +09:00
Mads Marquart
5f2c7350e9 Move AppKit (macOS) backend to winit-appkit (#4248) 2025-05-25 17:37:40 +02:00
Mads Marquart
256bbe949e Move X11 backend to winit-x11 (#4253) 2025-05-25 17:24:00 +02:00
Mads Marquart
1126e9ea2f Move Wayland backend to winit-wayland (#4252) 2025-05-25 16:48:07 +02:00
Mads Marquart
927af44aa4 Move UIKit backend to winit-uikit 2025-05-25 23:19:30 +09:00
Mads Marquart
0adc0898f0 Move shared code to a new crate winit-common 2025-05-25 20:41:28 +09:00
Mads Marquart
3b986f5583 Move Windows backend to winit-win32 2025-05-25 12:13:25 +09:00
Mads Marquart
b1f8d778a1 Move Android backend to winit-android (#4250) 2025-05-24 13:29:53 +02:00
Mads Marquart
04482d5a2e fix: Allow unknown bit-depth on macOS (#4190)
It is unclear what values CGDisplayModeCopyPixelEncoding is allowed to
return, so let's make sure to handle unknown cases.
2025-05-23 16:07:09 +02:00
Mads Marquart
3e50911adb macOS: Remove panic wrapper (#4147)
This is unnecessary nowadays, unwinding in CF observer callbacks is safe
(and is safe in Rust after the introduction of `extern "C-unwind"`).

Panicking elsewhere (such as in NSNotificationCenter callbacks or
delegate methods) _may_ still lead to an abort, if AppKit tries to catch
it with libc++, since Rust panics are not compatible with those.
That's "just" a quality-of-implementation detail of current Rust though,
not an inherent limitation, and should really be solved in rustc.
2025-05-23 15:53:12 +02:00
Evgeny
f51a470872 doc: add info on sticky vs toggle modifier behavior (#4251) 2025-05-22 21:57:10 +02:00
Mads Marquart
47b938dbe7 Split Orbital backend out into winit-orbital (#4243) 2025-05-21 13:12:55 +02:00
Kirill Chibisov
e2b883d215 Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2025-05-21 18:04:10 +09:00
Evgeny
38fd3c6a99 winit-core/keyboard: clarify modifier docs
Emphasize the difference between logical and physical state, reference sticky mods.
2025-05-21 17:40:28 +09:00
Mads Marquart
5190472bee chore: use workspace dependencies everywhere
To reduce the amount of duplication in 'Cargo.toml's when we split into
different crates.
2025-05-21 15:45:12 +09:00
Mads Marquart
eab03dca80 Move EventLoopExt* to winit-core (#4228)
* Move EventLoopExtPumpEvents and PumpStatus to winit-core
* Move EventLoopExtRunOnDemand to winit-core
2025-05-20 16:56:53 +02:00
Kirill Chibisov
59e3dda89f wayland: fix pump events's loop drop deadlock 2025-05-17 13:23:01 +09:00
Mads Marquart
c846f67bcb chore: import from winit-core instead of the top-level crate
Reproduce with:
find ./src/platform_impl -type f -exec sed -i '' 's/crate::/winit_core::/g' {} \;
find ./src/platform_impl -type f -exec sed -i '' 's/winit_core::platform/crate::platform/g' {} \;
find ./src/platform_impl -type f -exec sed -i '' 's/winit_core::dpi::/dpi::/g' {} \;
cargo +nightly fmt
2025-05-17 11:26:09 +09:00
Mads Marquart
03c01e038b chose: appease clippy 2025-05-17 10:56:51 +09:00
Varphone Wong
ed4ebd4242 windows: Fix crash in for Windows versions < 17763
In Windows versions < 17763, `GetProcAddress("#132")` from `uxtheme.dll`
also returns a non-null pointer. However, the function does not match
the expected `extern "system" fn() -> bool` prototype, which causes a
crash when it is called.

This fix ensures compatibility by adding proper checks to prevent such
crashes on older Windows versions.
2025-05-14 21:31:48 +09:00
Kirill Chibisov
b5921d89f2 winit-core: add top-level doc 2025-05-14 21:18:44 +09:00
Kirill Chibisov
b5a6a4e616 ci: test winit-core 2025-05-14 21:18:44 +09:00
Kirill Chibisov
9598eb371c winit-core: fix tests 2025-05-14 21:18:44 +09:00
Kirill Chibisov
634b9baea2 winit-core: drop all cfg except web 2025-05-14 21:18:44 +09:00
Kirill Chibisov
cf5e422dc8 winit-core: drop broken docs
Generally, winit-core doesn't know about underlying platforms, though,
some general information which will true for any implementation was
left in place.
2025-05-14 21:18:44 +09:00
Kirill Chibisov
276597e009 winit-core: cleanup event loop docs 2025-05-14 21:18:44 +09:00
Kirill Chibisov
c0b737de4a winit-core: move application 2025-05-14 21:18:44 +09:00
Kirill Chibisov
79fa4061cb winit-core: move event 2025-05-14 21:18:44 +09:00
Kirill Chibisov
056421546a winit-core: move ActiveEventLoop 2025-05-14 21:18:44 +09:00
Kirill Chibisov
b4c5b76155 winit-core: move window
Create `WindowAttributes` for respective platform specific window
attributes in `winit` due to move of `WindowAttributes`.
2025-05-14 21:18:44 +09:00
Kirill Chibisov
c8b9a86885 winit-core: partially split event_loop 2025-05-14 21:18:44 +09:00
Kirill Chibisov
fe2df61884 winit-core: move error 2025-05-14 21:18:44 +09:00
Kirill Chibisov
446482367b winit-core: move cursor 2025-05-14 21:18:44 +09:00
Kirill Chibisov
cbb29ab526 winit-core: move icon 2025-05-14 21:18:44 +09:00
Kirill Chibisov
a491c2abed winit-core: move keyboard 2025-05-14 21:18:44 +09:00
Kirill Chibisov
3142355417 winit-core: move monitor handle 2025-05-14 21:18:44 +09:00
Kirill Chibisov
3493a20173 winit-core: new crate + split out as_any 2025-05-14 21:18:44 +09:00
Kirill Chibisov
bf0bde8067 ci/deny: allow scripts in zerocopy 2025-05-14 21:18:44 +09:00
Kirill Chibisov
519947463f Bump MSRV to 1.80 2025-05-05 21:55:12 +09:00
Kirill Chibisov
8c36ed4900 x11: drop dead code
Fixes #4214.
2025-05-04 00:03:31 +09:00
Bruce Mitchener
7b2c9d42b4 Fix typos from updated typos tool (#4213) 2025-05-03 13:38:15 +02:00
Kirill Chibisov
587ade844d DPI version 0.1.2 2025-05-02 16:18:37 +09:00
Kirill Chibisov
6756549ac9 clippy: fix casing in windows backend 2025-05-02 16:18:37 +09:00
Kirill Chibisov
17666e3171 Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2025-04-30 21:01:32 +09:00
Kirill Chibisov
f6ca06cd58 wayland: bump wayland-rs to avoid yanked release 2025-04-30 02:09:44 +09:00
Mitoma Ryo
e634cc609f windows: fix incorrect cursor_range calculation in Ime::Preedit
The `text` is retrieved as UTF-8 while `attributes` are based on UTF-16,
thus the offset was getting out of sync on some unicode payloads
like surrogate pairs.

Fixes #3967.
2025-04-29 21:11:54 +09:00
Mads Marquart
aa83726c72 macOS: Fix monitors connected via certain Thunderbolt hubs (#4207)
Instead of panicking, raise a warning and return `None` or similar.

Co-authored-by: RJ <rj@metabrew.com>
2025-04-29 13:25:46 +02:00
Mads Marquart
1800fa1670 macOS: Store UUID in MonitorHandle instead of CGDirectDisplayID (#4167)
The monitor UUID is what actually represents the monitor,
CGDirectDisplayID is closer in correspondence to a specific framebuffer.
2025-04-29 12:26:03 +02:00
Mads Marquart
a5e6d0aaaf fix: Support fractional refresh rates in video modes on macOS (#4191)
We were rounding the refresh rate before converting it to millihertz.
2025-04-29 12:02:07 +02:00
jpy794
4fe4ce3d77 wayland: support fractional scale for custom cursor 2025-04-29 14:12:43 +09:00
Putta Khunchalee
078c4c0c4f wayland: add WindowExtWayland::xdg_toplevel
Fixes #4068.
2025-04-29 13:31:49 +09:00
Kirill Chibisov
c8579a1882 wayland: ensure external loop is notified with pump_events
Spawn a thread when pump_events is used, so the external thread will
get woken-up correctly. This only happens when timeout was given.

Fixes #4183.
2025-04-29 11:43:36 +09:00
robtfm
ab96fa8395 windows: add locked cursor 2025-04-25 19:41:56 +09:00
Life Adventurer
6461cfa9b1 docs: fix incorrect markdown link syntax 2025-04-22 16:26:28 +09:00
Kirill Chibisov
6c214e71ae wayland/fix: crash due consequent calls to set_cursor_grab
Only mark that the grab was applied when it actually got applied.
Previously there was an issue with grab being marked as applied without
a pointer over the window, when in reality it wasn't.

Fixes #4073.
2025-04-20 19:47:11 +09:00
Daniel McNab
ecc884ac91 dpi: make no_std compatible 2025-04-20 14:46:15 +09:00
Mads Marquart
24e2c6914a macOS:ios: use next objc2 version
A lot of CoreFoundation methods have been marked safe, and converted
into methods. Note that the old functions are still available, just
deprecated.
2025-04-20 14:36:49 +09:00
Kirill Chibisov
ed4d70fdd4 chore: fix clippy issues 2025-04-20 10:48:22 +09:00
Kirill Chibisov
07c25b9703 icon: refactor Icon to be dyn
Same as for `CustomCursor`. However, the API uses `dyn` stuff only
because of `Windows` backend at the time of writing, generally, platforms
should just have a separate method that deals with all of that, and e.g.
top-level winit only guarantees `Rgba`.
2025-04-20 10:48:22 +09:00
Mads Marquart
cdbdd974fb Align NamedKey and KeyCode more closely with the W3C specs (#4018)
By removing `NamedKey::Space` and rename "super" key to "meta".

- `NamedKey::Space` is not in the spec, and doesn't make sense to
  special-case. We use `Key::Character("")` instead..

  I've added an extra check on the Windows backend, to ensure that the code
  functionally works the same before and after. Whether that check is
  desirable or not can be figured out later.

- "super" is inconsistent with the W3C spec, and while it's arguably not the
  best name, it's worse that Winit is diverging and choosing a different name.

  List of renamings:
  - `KeyCode::SuperLeft` -> `KeyCode::MetaLeft`
  - `KeyCode::SuperRight` -> `KeyCode::MetaRight`
  - `KeyCode::Meta` -> `KeyCode::Super`
  - `NamedKey::Meta` -> `NamedKey::Super`
  - `NamedKey::Super` -> `NamedKey::Meta`
  - `ModifiersState::SUPER` -> `ModifiersState::META` (deprecated)
  - `ModifiersState::super_key` -> `ModifiersState::meta_key`
  - `ModifiersKeys::LSUPER` -> `ModifiersKeys::LMETA`
  - `ModifiersKeys::RSUPER` -> `ModifiersKeys::RMETA`
2025-03-23 12:56:01 +01:00
aloucks
7e13248be3 example/application: fix alt binding on macOS 2025-03-20 11:14:33 +03:00
ShikiSuen
b15a40cd14 Document markdown wrapping policy (#3680)
And add note to README.md about CONTRIBUTING.md existing.
2025-03-17 13:04:24 +01:00
Mads Marquart
8db4a9cc61 macOS: Close windows automatically when exiting (#4154)
This disallows carrying over open windows between calls of `run_app_on_demand`
(which wasn't intended to be supported anyhow).
2025-03-17 11:29:53 +01:00
Kirill Chibisov
a4ab7dc64c x11:wayland: fix pump_events blocking with Wait
Using `Duration::Zero` with `Wait` polling mode was still blocking until
the event was actually delivered. Thus when `pump_events` API is used,
ensure that it's not happening.

Fixes #4130.
2025-03-17 13:20:17 +03:00
Mads Marquart
afb731bb52 Drop application handler on run loop exit (#4149)
Calling the `Drop` impl of the user's `ApplicationHandler` is important on
iOS and Web, since they don't return from `EventLoop::run_app`.

And now that we reliably call `Drop`, the `ApplicationHandler::exited`
event/callback is unnecessary; using `Drop` composes much better (open files
etc. stored in the app state will be automatically flushed), and prevents
weirdness like attempting to create a new window while exiting.
2025-03-17 10:56:00 +01:00
aloucks
ef37b1d5dd macOS: Make set_simple_fullscreen honor set_borderless_game (#4164)
* Prevent panic when calling set_simple_fullscreen(false) on macos

Calling `set_simple_fullscreen(false)` to restore the window after
a previous call to `set_simple_fullscreen(true)` panics with
`view must be installed in a window` in the call to `set_style_mask`
with the old style.

Moving the `set_style_mask` call after the frame has been resized
fixes the issue.

* Hide the doc and menubar on macos when using set_borderless_game
with set_simple_fullscreen
2025-03-17 02:58:47 +01:00
aloucks
2b4e8ef916 Fix a pause in the event loop when clicking the title bar on windows (#4136)
* Fix a pause in the event loop when clicking the title bar on windows

When clicking the title bar on Windows, to drag the window, there is
a noticible pause in continuous redraw requests. This was fixed
in #839 and then regressed in #1852. The cursor blinks in both
cases and is unrelated. The regression made the blink happen after
the pause instead of immediately.

* Update the event loop pause note on the WM_NCLBUTTONDOWN handler

The application example was also updated to optionally animate the fill color
in order to demonstrate continuous redraw without pauses in the event
loop.
2025-03-17 02:27:27 +01:00
Kirill Chibisov
ae28eea406 cursor: refactor CustomCursor to be dyn
cursor: refactor `CustomCursor` to be `dyn`

Same as for `MonitorHandle`, the source was changed to support
all kinds of sources.
2025-03-13 17:18:37 +03:00
Aaron Muir Hamilton
a0464ae83b x11: implement true cursor area with XNArea attribute 2025-03-11 21:04:50 +03:00
Mads Marquart
16d5f46db1 utils: add cast_* methods to allow more type-safe casting
Relying on just `as_any` was error prone and will become redundant in
the future, once upcasting will be stable, we also won't to impose a
restriction on to which concrete type we're casting, since casting
to a type that doesn't implement a base trait doesn't make much
sense.

Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
2025-03-11 16:35:25 +03:00
Kirill Chibisov
5cada36ae8 x11: move x11 specific code to x11 from linux/mod.rs 2025-03-08 10:14:08 +03:00
Kirill Chibisov
b3dcfa1275 docs: don't build platform docs for docsrs
Due to casts and use of platform specific crates in those modules
it's not really feasible to build docs for them.

After separating crates, thus should become way easier to navigate,
since backends information would be publicly available.
2025-03-07 19:22:12 +03:00
Kirill Chibisov
f1c5afd84e monitor: refactor MonitorHandle to store dyn object
This also alters `VideoMode` to be a regular object and not reference
the `MonitorHandle`, since it's a static data.

Given that `VideoMode` set may change during runtime keeping the
reference as a some sort of validity may not be idea and propagating
errors when changing video mode could be more reliable.
2025-03-07 19:22:12 +03:00
Mads Marquart
be1baf164c Properly implement Debug for Window and EventLoop types (#3297)
For EventLoop, EventLoopBuilder, EventLoopProxy and by requiring it as
a supertrait of Window and ActiveEventLoop.

It is especially useful for user to be able to know that Window is Debug.
2025-03-03 08:40:04 +01:00
Mads Marquart
39c0862198 apple: Implement wake-ups using system mechanisms (#4146)
Do the wake-up inside the perform callback on `CFRunLoopSource`.
2025-03-01 20:18:28 +01:00
Mads Marquart
aa8ebdc795 Remove top-level Event enum (#4153) 2025-03-01 13:16:39 +01:00
Mads Marquart
ea68916055 macOS: Parse more key codes into named keys (#4148) 2025-03-01 12:41:46 +01:00
Mads Marquart
e26b831f23 Windows: Use ApplicationHandler (#4141)
* Make ActiveEventLoop a thin wrapper over EventLoopRunner
* Use ApplicationHandler instead of Event
2025-03-01 12:09:59 +01:00
Mads Marquart
8c3e69c08b macOS: Fix crash when reconnecting monitors (#4151)
CFArrayGetValueAtIndex does not return a retained value, so we must
retain ourselves.
2025-02-28 17:32:24 +01:00
rctlmk
46879429ed Windows: add IconExtWindows::from_resource_name (#4137) 2025-02-26 22:02:32 +01:00
Mads Marquart
0c89ea7386 Merge KeyEventExtra into KeyEvent (#4029)
To make the fields easier to use, and to allow constructing KeyEvent in
user test code.
2025-02-26 17:51:49 +01:00
dependabot[bot]
6c0e3c3b15 Remove @types/eslint__js (#4133)
It is deprecated.
2025-02-24 20:17:44 +01:00
Mads Marquart
675582bd46 Swizzle sendEvent: instead of subclassing NSApplication (#4036)
This is done to avoid order-dependent behavior that you'd otherwise
encounter where `EventLoop::new` had to be called at the beginning of
`fn main` to ensure that Winit's application was the one being
registered as the main application by calling `sharedApplication`.

Fixes https://github.com/rust-windowing/winit/issues/3772.

This should also make it (more) possible to use multiple versions of
Winit in the same application (though that's still untested).

Finally, it should allow the user to override `NSApplication` themselves
if they need to do that for some reason.
2025-02-24 10:38:10 +01:00
Mads Marquart
4d6fe7e35c web: Avoid top-level Event 2025-02-24 11:21:55 +03:00
Mads Marquart
f9912baf09 x11: Call ApplicationHandler directly
Instead of going through the Event enum.
2025-02-24 11:13:25 +03:00
Mads Marquart
f290619dce wayland: use custom Event enum for buffered events 2025-02-24 10:56:11 +03:00
valadaptive
23011c6b0a Update to windows-sys 0.59 (#4098) 2025-02-24 04:40:11 +01:00
Kirill Chibisov
3a39a6ddb0 examples: make default example simple
The old example is in application for more sophisticated use of winit
and for maintainers to test things, since it does pretty much
everything.
2025-02-21 20:35:22 +03:00
Kirill Chibisov
90cf9a3398 docs: remove dead doc link 2025-02-20 22:03:03 +03:00
Kirill Chibisov
05d8fa0b91 chore: fix clippy lints 2025-02-20 22:03:03 +03:00
Kirill Chibisov
d7d20507ed ci: disable 32-bit windows gnu on nightly 2025-02-20 22:03:03 +03:00
Bruce Mitchener
f6e66a71f8 doc: remove spurious derive directive
This was unintentionally added in eccd9e415.
2025-02-18 14:53:16 +03:00
Kirill Chibisov
c09160d1a8 Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.

This also includes 0.30.8 sync, since it was forgotten.
2025-02-06 13:26:30 +03:00
Mads Marquart
2230e71093 ios: fix timers
Fixes #4074.
Fixes #3816.
2025-02-06 12:56:10 +03:00
Kirill Chibisov
5e6350d142 x11: fix modifiers replay
The serial was not unique, thus leading to issues and replay being
triggered for normal input. Track modifiers based on they keycodes
instead, since it's more unique.

Links: https://github.com/alacritty/alacritty/issues/8461
2025-02-05 09:04:09 +03:00
Kirill Chibisov
a6998af997 x11: fix crash with uim
Let's just not forward events to the IME once the user requested that
it should be disabled, though, still try to change its state explicitly.

Fixes #4082.
2025-02-03 20:43:43 +03:00
Mads Marquart
5c48ec7977 Document that we require cargo +nightly fmt (#4105) 2025-01-31 18:24:33 +01:00
Mads Marquart
953d9b4268 Update to objc2 v0.6 (#4092)
* Use available! macro
* Use objc2-core-foundation and objc2-core-graphics
* Use MainThreadBound instead of StaticMainThreadBound hack
2025-01-28 21:31:14 +01:00
valadaptive
f5dcd2aabe Rework Drag-And-Drop API (#4079)
* Add cursor position drag and drop events.
* Reword drag events to match pointer ones.
* appkit: Use `convertPoint_fromView` for coordinate conversion.
* appkit: use ProtocolObject<dyn NSDraggingInfo>.
* x11: store dnd.position as pair of i16

  It's what translate_coords takes anyway, so the extra precision is
  misleading if we're going to cast it to i16 everywhere it's used.

  We can also simplify the "unpacking" from the XdndPosition message--we
  can and should use the value of 16 as the shift instead of
  size_of::<c_short> * 2 or something like that, because the specification
  gives us the constant 16.
* x11: store translated DnD coords.
* x11: don't emit DragLeave without DragEnter.
* windows: only emit DragEnter if valid.
* windows: in DnD, always set pdwEffect.

  It appears other apps (like Chromium) set pdwEffect on Drop too:
  61a391b86b/ui/base/dragdrop/drop_target_win.cc
* docs: make it clearer that drag events are for dragged *files*.
* examples/dnd: handle RedrawRequested event.

Co-authored-by: amrbashir <amr.bashir2015@gmail.com>
2025-01-28 21:10:40 +01:00
Tom Churchman
77f1c73f06 wayland: clear IME preedit only when necessary
When all we'll be doing is setting a new preedit, the preedit doesn't
have to be explicitly cleared first. This change is perhaps debatable.

The direct reason for this is to make it easier to work around
quirks/bugs: in Masonry we've found IBus appears to resend
the IME preedit in response to `Window::set_ime_cursor_area`
(`zwp_text_input_v3::set_cursor_rectangle`). Because currently the
preedit is first cleared, a new IME cursor area is sent, which again
causes IBus to resend the preedit. This can loop for a while.

The Wayland protocol is mechanically quite prescriptive,
it says for zwp_text_input_v3:event:done.

> 1. Replace existing preedit string with the cursor. 
> 2. Delete requested surrounding text.
> 3. Insert commit string with the cursor at its end.
> 4. Calculate surrounding text to send.
> 5. Insert new preedit text in cursor position.
> 6. Place cursor inside preedit text.

Winit currently doesn't do surrounding text, so 2. and 4. can be
ignored. In Winit's IME model, without a commit, sending just the
`Ime::Preedit` event without explicitly clearing is arguably still
equivalent to doing 1., 5., and 6.
2025-01-17 19:29:10 +03:00
Pascal Hertleif
24c226416e Use wrapper type for CFUUID (#4032)
This no longer exposes `CGDisplayCreateUUIDFromDisplayID` and instead
uses `CFUUID` to avoid a leak.

Monitor comparisons should also be more stable now.
2025-01-17 12:38:42 +01:00
Sl-L
69382fda9a examples/child_window: use distinct color/position for children
This should help with understanding how they work.
2025-01-10 18:07:17 +03:00
Kirill Chibisov
ee245c569d api: make VideoModeHandle into VideoMode
The video mode is generally a static data and not a reference to some
video mode. This changes the exclusive fullscreen API to match that an
accept a monitor now.
2025-01-02 03:29:42 +03:00
Kirill Chibisov
5462f27dda api: add ActivationToken::{from,into}_raw
This is needed when passing and getting token from the IPC to activate
the window.
2024-12-31 06:08:18 +03:00
Kirill Chibisov
927deb030f x11: fix cursor grab mode tracking on error
Fixes #4064.
2024-12-31 05:52:12 +03:00
Kirill Chibisov
5ea81efc74 x11: add workaround for disabling IME on gnome
GNOME doesn't list that there's a _NONE_ style at all, but it still
works if you use it.
2024-12-28 14:25:56 -08:00
Matt Campbell
6896de5b73 windows: fix the event loop not waking on accessibility requests
Fixes #4055.
2024-12-24 00:23:44 +03:00
Kirill Chibisov
d736763216 Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2024-12-22 23:13:25 +03:00
Kirill Chibisov
e316a89847 x11: fix KeyboardInput delivered twice with IME
The filtered events were still processed even though they shouldn't once
we know that they're filtered.

Fixes #4048.
2024-12-22 17:51:44 +03:00
Kirill Chibisov
f0d8689039 Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2024-12-21 09:39:09 +03:00
Exidex
4d5e68c6e2 Implement ability to make non-activating window on macOS (#4035)
Fixes #3894
2024-12-13 00:56:39 +01:00
Skip R.
5835c9102e macOS: Fix checking for undocumented cursors (#4033)
`AnyClass::responds_to` delegates to `class_respondsToSelector`, a
function provided by the Objective-C runtime. However, at some point,
this began to return `false` for selectors referring to undocumented
cursors, despite the cursors remaining accessible via said selectors.
That this check fails prevents the cursors from being used.

We can instead send `respondsToSelector:` to the `NSCursor` class
itself. As an instance method, this is nominally impossible; however,
Apple grants an exemption[1] that permits class objects to perform
instance methods defined in the root class.

Checking for the undocumented cursors in this way gets them working
again, at least on macOS Sequoia 15.1.1.

[1]: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocObjectsClasses.html#//apple_ref/doc/uid/TP30001163-CH11-TPXREF120
2024-12-08 22:01:57 +01:00
Mads Marquart
e47081e385 docs: show less of the unstable docs in the README 2024-12-06 13:16:30 +03:00
Benjamin Brienen
171d53c042 Update smol_str (#3991) 2024-12-03 23:07:19 +01:00
Mads Marquart
35379f305a Remove feature description in FEATURES.md (#3479)
It easily becomes out of date.
2024-12-03 21:24:57 +01:00
Mads Marquart
4d2a0dd2b3 iOS: Never queue application-level events (#3905)
Events like `resumed`, `new_events`, `about_to_wait`, and so on will
never happen as a result of programmer action, so we'll never need to
queue those. This allows us to remove the need for the old `Event`
struct in the iOS backend.

Furthermore, we can now remove `InUserCallback`, since that state is
already stored inside `EventHandler`.

I've tried to otherwise keep the semantics as close to the original by
calling `handle_nonuser_events(mtm, [])`, which flushes pending events.
2024-12-03 19:53:29 +01:00
Mads Marquart
4a8b659228 Fix MonitorHandle PartialEq and Hash on iOS (#4013) 2024-12-03 19:02:53 +01:00
Mads Marquart
f314cd2b9a macOS: Fix crash when pressing Caps Lock (#4024)
Events emitted by `flagsChanged:` cannot access
`charactersIgnoringModifiers`. We were previously doing this because we
were trying to re-use the `create_key_event` function, but that is unsuited
for this purpose, so I have separated the `flagsChanged:` logic out from it.
2024-12-03 18:48:23 +01:00
Mads Marquart
3657506f6e macOS: Avoid redundant initial resize event (#3913)
The `NSViewFrameDidChangeNotification` that we listen to is emitted when
`-[NSWindow setContentView]` is called, since that sets the frame of the
view as well.

So now we register the notification later, so that it's not triggered at
window creation.

This behaviour is well described in the documentation:
https://developer.apple.com/documentation/appkit/nsview/postsframechangednotifications?language=objc
2024-12-03 18:35:04 +01:00
Mads Marquart
edca3ebc41 macOS: Align scancode conversions with Chromium and Firefox (#4019)
Also fix missing codes in physicalkey_to_scancode - This had become out of
sync with scancode_to_physicalkey.
2024-12-03 18:17:57 +01:00
Mads Marquart
ca46e29203 macOS: Fix surface position (#4027) 2024-12-03 17:31:32 +01:00
Mads Marquart
132fbe14d5 macOS: Fix safe area on macOS 10.14 and below (#4028) 2024-12-03 17:19:45 +01:00
Mads Marquart
164bf85b5b Windows: Add scancode conversions from Chromium sources (#4020) 2024-12-03 11:05:22 +01:00
Mads Marquart
cfa8f027cc AppKit/UIKit: Do not emit default state events upon window creation (#3912)
Do not emit redundant ScaleFactorChanged, SurfaceResized and Focused.
2024-12-02 23:10:33 +01:00
Mads Marquart
2e5db75101 Linux: Align scancode conversions with Firefox (#4021) 2024-12-02 13:38:37 +01:00
Mads Marquart
19e5bee3d1 chore: fix clippy lints 2024-12-02 14:51:26 +03:00
Hamir Mahal
fc6cf89ac0 style: simplify string formatting for readability (#4001) 2024-11-22 22:14:11 +01:00
Mads Marquart
dbcdb6f1b4 Add safe area and document coordinate systems (#3890)
Added `Window::safe_area`, which describes the area of the surface that
is unobstructed by notches, bezels etc. The drawing code in the examples
have been updated to draw a star inside the safe area, and the plain
background outside of it.

Also renamed `Window::inner_position` to `Window::surface_position`, and
changed it to from screen coordinates to window coordinates, to better
align how these coordinate systems work together.

Finally, added some SVG images and documentation to describe how all of
this works.

This is fully implemented on macOS and iOS, and partially on the web.

Co-authored-by: daxpedda <daxpedda@gmail.com>
2024-11-21 17:37:03 +01:00
Rodrigo Rivas Costa
d0c6c34eaa x11: move up XInput2 event registration
It should be done before mapping the window, or we could
lose the firsst XInput2 events, such as the first FocusIn.

Fixes #2841.
2024-11-21 14:04:55 +03:00
Mads Marquart
f2688d94ea ci: fix cargo deny 2024-11-21 10:28:32 +03:00
Nico Burns
f6b20852bf macOS: set activation policy by default if app is not bundled (#3961) 2024-11-18 21:19:45 +01:00
Kirill Chibisov
59b1eb5410 api: make OwnedDisplayHandle wrap an opaque type
This will help in case we want to linger the event loop during drop
to prevent use after free in the consumers code.
2024-11-13 15:29:05 +03:00
Aaron Muir Hamilton
f781e13166 X11: Use bottom-right corner of IME cursor area as caret position
XIM servers currently do not support preedit area reporting from
clients and there may be no standard way to report it.

Fcitx and iBus both place the candidate window descending descending
from the caret, with the reported X font; but since winit does not
report a font, the height of the line is assumed 0, so when we report
the top left corner of the cursor area they will tend to obscure it.

Taking this into account, the best default option is to report the
bottom right corner of the cursor area, because it will tend not to
obscure the preedit area when using `Window::set_ime_cursor_area` in
the way suggested by documentation.
2024-11-13 15:13:09 +03:00
Piotr Podusowski
9f8ac8feb5 android: use show_soft_input to summon the keyboard
Route it via the `Window::set_ime_allowed` like on iOS.
2024-11-13 14:43:59 +03:00
Mads Marquart
74958ecc6f docs: add fn main to root examples
This is not strictly required, but makes the examples a bit easier to
read understand (especially since the `EventLoop` really _should_ be
created inside `fn main`, and not in some random function potentially
running on a random thread).
2024-11-12 16:52:48 +03:00
Kirill Chibisov
3a60cbaba5 api: make EventLoopProxy wrap an opaque type
The proxy is intended to be Clone, thus use `Arc` for it internally and
don't require backends for it to be `Clone`. Use `EventLoopProxyProvider`
to hide the backend's proxy implementation details.

Co-authored-by: daxpedda <daxpedda@gmail.com>
2024-11-12 10:56:20 +03:00
Matěj Laitl
ae4c449670 x11: fix WindowAttributesExtX11::with_x11_screen()
Based on https://github.com/rust-windowing/winit/pull/3973, which should be merged first.

There's an API to programmatically specify X11 screen id (override what is determined from the `DISPLAY` env variable), but it doesn't work.

Seeting up X Server with 2 screens and calling `DISPLAY=:0 X11_SCREEN_ID=1 cargo run --example window` should be equivalent to calling `DISPLAY=:0.1 cargo run --example window`

The latter works (and places the window on the correct screen), but the former yields

`failed to create initial window: Os(OsError { line: 620, file: "src/platform_impl/linux/x11/window.rs", error: X11Error(X11Error { error_kind: Match, error_code: 8, sequence: 219, bad_value: 1319, minor_opcode: 0, major_opcode: 1, extension_name: None, request_name: Some("CreateWindow") }) })`

_Here `1319` is the root window id for screen 0, which doesn't match the screen 1 that we request._

The problem is that we need to factor in the screen id when determining the parent (root) window when not explicitly set. This patch does that.

---

Also: Extend the window example with X11_{SCREEN,VISUAL}_ID env variables
2024-11-06 08:30:25 -08:00
Kirill Chibisov
b2896d7408 chore: always pull raw-window-handle
Winit is not useful without it and we don't provide older versions
anymore.
2024-11-03 00:39:01 +03:00
Kirill Chibisov
edfb4b03f4 chore: remove platform FingerId
The same as for `WindowId`.
2024-11-02 17:10:32 +03:00
Kirill Chibisov
c8c1eca3c7 api: move primary from FingerId to Pointer events
Whether the pointer event is primary or not generally matters for the
context where all input is done by the same event, so users can
_ignore_ non-primary events since they are likely from users clicking
something else with their other fingers.

Having it only on a FingerId made it useless, since it's usually used
to avoid multi-touch, but if you start mapping on touch event you
already can track things like that yourself.

Fixes #3943.

Co-authored-by: daxpedda <daxpedda@gmail.com>
2024-11-02 17:10:32 +03:00
Matěj Laitl
d3207a8d76 Apply @notgull's suggestion 2024-10-29 17:54:21 -07:00
Matěj Laitl
9d347b72d9 Add changelog entry 2024-10-29 17:54:21 -07:00
Matěj Laitl
13bb51c7e0 x11: iterate only visuals from the matching screen 2024-10-29 17:54:21 -07:00
AngelicosPhosphoros
bb4aa22cf9 Improve waiting for messages on Windows
Previous version used [`SetTimer`] with `GetMessageW` for waiting.
The downside of UI timers like ones created by `SetTimer`,
is that they may be late by up to 15-16 ms.

To fix this behaviour, I added use of high resolution timers created by [`CreateWaitableTimerExW`] with the flag `CREATE_WAITABLE_TIMER_HIGH_RESOLUTION`.
In my previous experience, waiting on such timers have precision of roundly 0.5 ms which is the best available on Windows at the moment.
I use [`MsgWaitForMultipleObjectsEx`] to wait simultaneously for both timer and newly arriving events.

Unfortunately, high resolution timers are available only since Windows 10 1803. However:

1. Win 10 is already getting to the end of support, like all previous versions, so it is OK to rely on APIs introduced in it;
2. I use `dwMilliseconds` parameter of `MsgWaitForMultipleObjectsEx` as a fallback. It should perform not worse compared to waiting for events from `SetTimer`.

I also refactored code to remove event dispatching from function responsible for waiting for events. This provides more clear separations of concern and avoids unnecessary duplication of dispatching logic.

After [review] from @rib, I also moved the waiting itself from `wait_for_messages` method to separate function, so it is clearly seen that `wait_for_messages` do 3 things: notify app that we about to wait, wait, notify that we have new events.

I have tested behaviour using a egui app with Vulkan rendering with `VK_PRESENT_MODE_IMMEDIATE_KHR`, and older version consistently have twice less FPS than requested (e.g. 30 FPS when limit is 60 and 60 FPS when limit is 120) while newer version works more correctly (almost always 60 FPS when limit is 60, and only 5-10 frames missing when FPS is set to 120 or more).

Fixes https://github.com/rust-windowing/winit/issues/1610

[`CreateWaitableTimerExW`]: https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createwaitabletimerexw
[`MsgWaitForMultipleObjectsEx`]: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-msgwaitformultipleobjectsex
[`SetTimer`]: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-settimer
[review]: https://github.com/rust-windowing/winit/pull/3950#discussion_r1800184479
2024-10-28 16:38:17 -07:00
Valentine Briese
3e9b80d47a macOS: add ability to make titlebar unified (#3960)
Adds `WindowExtMacOS::set_unified_titlebar` and
`WindowAttributesExtMacOS::with_unified_titlebar`,
which allow you to use a larger titlebar style on macOS.
2024-10-25 23:22:52 +02:00
Nico Burns
c913cdab0b macOS: add a way to hook standard keybinding events
Add macOS specific application handler to deliver macOS specific
events.

Co-authored-by: Mads Marquart <mads@marquart.dk>
2024-10-23 08:33:42 +00:00
Shane Celis
a5f5ce6a3d macOS: fix panic during drag_window
Return error from it instead of unwrapping.
2024-10-22 11:00:53 +00:00
Kirill Chibisov
fb6b1d487b deps: bump redox-syscall to 0.5.7 2024-10-21 21:33:51 +00:00
Marijn Suijten
7d77ccfad3 android: Forward suspended() and resumed() events and patch up platform-specific documentation (#3786)
Key them off of `onStop()` and `onStart()` which seems to match the
other backends most closely.  These [Android Activity lifecycle] events
denote when the application is visible on-screen, and recommend that any
heavy lifting for startup and shutdown happens here, as the application
may be demoted to the background and later shut down entirely unless the
user navigates back to it.

[Android Activity lifecycle]: https://developer.android.com/guide/components/activities/activity-lifecycle
2024-10-16 12:17:59 +02:00
Kirill Chibisov
c23bed20b8 x11: don't forward key events to IME when it's disabled
Fixes #3815.
2024-10-13 21:57:02 +03:00
Hiroaki Yutani
8fe2b62adf docs: fix function name of with_any_thread 2024-10-13 21:34:11 +03:00
Kirill Chibisov
4e3165f3d8 chore: remove platform DeviceId
The same as for `WindowId`.
2024-10-11 11:15:54 +03:00
Mads Marquart
da2268ae22 chore: remove platform WindowId's
WindowId is a window _identifier_, and as such doesn't store anything
(unlike a _handle_). So we can safely make only be defined once, in the
core crate.

There are a few backends where we still use `into_raw` internally; I
consider these patterns discouraged, we should not be passing around
important state in the window id.
2024-10-08 16:29:40 +03:00
daxpedda
eccd9e415d api: overhaul pointer API
- Rename `CursorMoved` to `PointerMoved`.
- Rename `CursorEntered` to `PointerEntered`.
- Rename `CursorLeft` to `PointerLeft`.
- Rename `MouseInput` to `PointerButton`.
- Add `position` to every `PointerEvent`.
- Remove `Touch`, which is folded into the `Pointer*` events.
- New `PointerType` added to `PointerEntered` and `PointerLeft`,
  signifying which pointer type is the source of this event.
- New `PointerSource` added to `PointerMoved`, similar to `PointerType`
  but holding additional data.
- New `ButtonSource` added to `PointerButton`, similar to `PointerType`
  but holding pointer type specific buttons. Use
  `ButtonSource::mouse_button()` to easily normalize any pointer button
  type to a generic mouse button.
- In the same spirit rename `DeviceEvent::MouseMotion` to `PointerMotion`.
- Remove `Force::Calibrated::altitude_angle`.

Fixes #3833.
Fixes #883.
Fixes #336.

Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
2024-10-08 15:19:00 +03:00
daxpedda
32cd1ad9a7 api: remove ::dummy from Id types
`::dummy` was used for testing purposes and became redundant after
adding e.g. `from_raw` and `into_raw` methods on `Id` types.
2024-09-29 16:49:45 +03:00
daxpedda
6e1b9fa24d api: replace WindowId From/Into u64 with WindowId::{from,into}_raw()
Co-authored-by: Mads Marquart <mads@marquart.dk>
Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
2024-09-27 23:12:50 +03:00
Mads Marquart
380eea0072 macOS: Fix move event sometimes being triggered on resize (#3914) 2024-09-24 01:06:10 +02:00
Kirill Chibisov
a18658284c chore: fix nightly CI on linux/ios
Co-authored-by: Mads Marquart <mads@marquart.dk>
2024-09-23 22:26:21 +03:00
Philpax
8ddd10a7f9 doc: link DeviceEvent::MouseMotion from cursor moved 2024-09-22 17:02:40 +03:00
John Nunley
4f1c5b6129 docs: Explicitly demarcate platform support
As discussed in today's meeting, this commit creates two tiers of
support. Tier 1, which is what we actively test, and Tier 2, what we
hope compiles.

Signed-off-by: John Nunley <dev@notgull.net>
Co-authored-by: daxpedda <daxpedda@gmail.com>
2024-09-19 17:09:10 -07:00
purajit
7e819bb2ce Prevent winit from overriding LSUIElement in package manifests (#3920) 2024-09-16 15:49:18 +02:00
Mads Marquart
dfea49f488 Support drawing on iOS in examples
Softbuffer v0.4.6 added support for iOS.
2024-09-10 17:36:04 +03:00
Kirill Chibisov
b674d20edf api: unify error handling
Make error infrastructure more backend agnostic and let backends
just forward the os errors opaquely.
2024-09-06 17:20:11 +03:00
Mads Marquart
8db3e0e043 Rename "inner size" to "surface size" (#3889)
* Rename `WindowEvent::Resized` to `SurfaceResized`
* Rename `InnerSizeWriter` to `SurfaceSizeWriter`
* Replace `inner_size` with `surface_size`
* Rename `resize_increments` to `surface_resize_increments`
2024-09-04 15:04:48 +02:00
Tarek Abdel Sater
d37c591378 macOS: add option to explicitly hide menu/dock in Borderless (#3882) 2024-09-04 14:44:05 +02:00
Bruce Mitchener
9419e4e1a7 Fix spelling of "inner" (#3896) 2024-09-01 23:31:45 +02:00
Kirill Chibisov
241b7a80bb api: convert Window to dyn Window
This should allow us to make future split of backends much easier.
The `Box<dyn Window>` is a _temporary_ solution, which will be
removed with the future updates when we decide on how the Window
should be stored.
2024-08-23 23:40:27 +03:00
John Nunley
e716adcc0a x11: use more information in X11 "not supported" errors
This makes it so, when X11 fails to initialize due to not loading a
library, it provides more verbose information on what exactly happened.

Fixes #3883.
Signed-off-by: John Nunley <dev@notgull.net>
Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
2024-08-23 14:47:40 +03:00
John Nunley
aee95114db m: Replace libxcursor with custom cursor code
Another one bites the dust.

This replaces the code dependent on libxcursor with equivalent code
written using x11rb, featuring its special "cursor" module.

cc #3198

Signed-off-by: John Nunley <dev@notgull.net>
2024-08-22 19:30:43 -07:00
John Nunley
8f4a8efa99 m: Ignore mutex poisoning in X11_BACKEND
A panic doesn't really put any of the fields in XConnection into an invalid
state, so there is no real reason to panic when poisoning is detected.
So just ignore the poison.

Closes #3870

Signed-off-by: John Nunley <dev@notgull.net>
2024-08-22 18:03:22 -07:00
lucasmerlin
1e1f0fd7e9 Basic iOS IME support (#3823)
This implements basic iOS IME support (typing, backspace, support for emojis
etc but no autocomplete or copy / paste menu).

Co-authored-by: Mads Marquart <mads@marquart.dk>
2024-08-19 22:04:29 +02:00
Mads Marquart
6e008b39e9 Improve iOS documentation (#3873)
* Update version docs to link to `rustc`'s supported versions

* Document how to run Winit on Mac Catalyst

* Improve instructions for building iOS applications

The old instructions are outdated, and suggested a workaround that is
unnecessary.

The user-story in the ecosystem is sadly not very clear-cut, so the
instructions here are still woefully incomplete.

* iOS: Clean up notes on main thread safety

These platform-specific notes on `Window` methods were unnecessary, as
it's already discussed in the top-level `Window` docs.
2024-08-19 12:41:29 +02:00
Mads Marquart
6c4da19197 macOS/iOS: Remove window activation hacks (#3872)
No longer necessary after a8c7109 and facb809.
2024-08-18 23:50:10 +02:00
Mads Marquart
a61e7bb4f4 iOS: Refactor event handling to share code with macOS (#3865)
Instead of storing the event handler within the AppState, and extracting
it our every time we need it, we now use the same event handling
implementation as for macOS that ensures we don't re-entrantly call the
event handler, and that we un-register the handler again after we're
done using it (`UIApplicationMain` won't return, but may still unwind,
so this is very important for panic safety).
2024-08-15 23:19:57 +02:00
daxpedda
7fbc2118b6 Add support for MacOS ARM64 (#3862) 2024-08-13 23:01:17 +02:00
daxpedda
a96491f302 Web: return MonitorHandle in Window::fullscreen() (#3861)
- Change `OrientationData::natural` type from `bool` to `Orientation`, just telling the user what the natural orientation is.
- Fix and improve some monitor related documentation.
2024-08-13 22:13:12 +02:00
daxpedda
d96fd02f33 Update minimum version of wasm-bindgen (#3860) 2024-08-13 21:54:03 +02:00
Mads Marquart
92e9bfe0fc Allow the user to register the application delegate on macOS and iOS (#3758)
This allows the user to override the application delegate themselves,
which opens several doors for customization that were previously closed.

To do this, we use notifications instead of top-level application delegate
methods.

One effect of not providing an application delegate on iOS is that we no
longer act as-if the application successfully open all URLs there.

This is a breaking change, although unlikely to matter in practice, since the
return value of `application:didFinishLaunchingWithOptions:` is seldom used by
the system (and is likely the preferred behaviour anyhow).
2024-08-11 23:14:18 +02:00
Kirill Chibisov
3392e9c1de chore: use our own AsAny to provide &dyn Any
This removes the direct requirement to implement `as_any` and it could
be just derived.

Also implement HasDisplayHandle for dyn ActiveEventLoop + '_.

Suggested-by: daxpedda <daxpedda@gmail.com>
2024-08-11 21:24:34 +03:00
Mads Marquart
038ef5c3ad Properly implement event loop extension traits
This was implemented for `&dyn ActiveEventLoop` before, but that's less
general than implementing it directly for `dyn ActiveEventLoop`.

The `+ '_` is required to tell the compiler that we want to implement
this for all `dyn ActiveEventLoop`s, not just `'static` ones (even
though they're all going to be `'static`).
2024-08-11 19:33:12 +03:00
Kirill Chibisov
70c54ee0ff Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2024-08-08 21:40:08 +03:00
daxpedda
3bab4ef4fb Android: remove MonitorHandle support
Because we don't want to force all methods on `VideoModeHandle` to return `Option`, we decided to remove the already incomplete support in Android for both types.
2024-08-08 01:29:53 +02:00
daxpedda
58142680ce Various Monitor/VideoModeHandle methods now return an Option
`VideoModeHandle::refresh_rate_millihertz()` and `bit_depth()` now return a `Option<NonZero*>`.
`MonitorHandle::position()` now returns an `Option`.
On Orbital `MonitorHandle::name()` now returns `None` instead of a dummy name.
2024-08-08 01:29:51 +02:00
daxpedda
0ffcfd8a3a Remove MonitorHandle::size/refresh_rate_millihertz() 2024-08-08 00:53:01 +02:00
daxpedda
2e53533cc1 Add MonitorHandle::current_video_mode() 2024-08-08 00:47:20 +02:00
daxpedda
1168cd4113 Implement common Std traits on many types (#3796) 2024-08-08 00:46:28 +02:00
daxpedda
9dff801f93 Introduce FingerId (#3783) 2024-08-08 00:36:36 +02:00
Kirill Chibisov
f07153b8e0 api: refactor ActiveEventLoop into trait
This should help with further extensions because the backend event
loops are used directly now.
2024-08-06 21:02:53 +03:00
daxpedda
f5304815a1 Change create_custom_cursor() to return Result (#3844) 2024-08-06 18:57:03 +02:00
Kirill Chibisov
29e1041987 chore: drop libera link
It has low amount of users and not active, so better direct people
straight to matrix at this point.
2024-08-06 15:04:58 +03:00
daxpedda
15b79b18e1 Add ActiveEventLoop::system_theme()
This also fixes macOS returning `None` in `Window::theme()` if no theme
override is set, instead it now returns the system theme.

MacOS and Wayland were the only ones working correctly according to the
documentation, which was an oversight. The documentation was "fixed"
now.

Fixes #3837.
2024-08-05 21:51:38 +03:00
Pascal Hertleif
54ff9c3bb5 macOS: skip releasing unavailable monitors
Prevent assertion error when trying to close a fullscreen window that
was on a display that got disconnected.
2024-08-05 13:44:18 +03:00
daxpedda
546962c904 Remove DeviceEvent::Motion and WindowEvent::AxisMotion
We decided to remove them because they contained too little information
for the user to be useful. The assumption is that they were originally
implemented to enable gamepad support, which we already decided we are
not going to add directly to Winit.
2024-08-05 13:15:53 +03:00
daxpedda
b7a7f59298 Remove DeviceEvent::Added and Removed
This had no real use because we don't expose any information on
`DeviceId` except on Windows. But there we only expose the name. The
assumption is that this was originally added for gamepad support, which
never made it into Winit.
2024-08-05 13:01:31 +03:00
daxpedda
586255ac0a Web: monitor API improvements (#3847)
- Improved the documentation to point users into the right direction from all kinds of methods and types.
- De-duplicated some code and added more comments.
- Implement an ID system to correctly and efficiently implement `Eq`, `Hash`, `Ord`, `PartialEq` and `PartialOrd`.
- Fixed screen locking support being cached thread local, ergo calling from a different thread would require to make the check again, not fulfilling its purpose as a fast-path at all.
2024-08-04 16:49:19 +02:00
dependabot[bot]
42ba0a74e0 build(deps): bump EmbarkStudios/cargo-deny-action
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: daxpedda <daxpedda@gmail.com>
2024-08-04 15:14:12 +03:00
daxpedda
34a37b8747 Windows: use Box::leak() instead of Box::into_raw()
This was detected by a new change in Nightly Rust that applied
`#[must_use]` to the return value of `Box::into_raw()`.
2024-08-04 13:03:26 +03:00
daxpedda
02a0a91a94 Remove raw-window-handle v0.4 and v0.5 support (#3831) 2024-08-04 00:18:39 +02:00
dependabot[bot]
e3fbfb81d7 Web: bump ESLint to v9 (#3843) 2024-07-31 20:37:10 +02:00
daxpedda
0909bf3d9d Add to .git-blame-ignore-revs file 2024-07-28 17:39:04 +02:00
daxpedda
3398ebe467 Use Taplo for TOML formatting 2024-07-28 17:38:44 +02:00
dependabot[bot]
21c121f9b3 Bump GitHub Actions actions/cache and actions/configure-pages (#3836) 2024-07-28 17:06:44 +02:00
daxpedda
ce0d1dfe1b Add GitHub Actions to Dependabot (#3834)
Add GitHub Issues label to NPM package upgrades.
2024-07-28 16:55:49 +02:00
daxpedda
7892e86731 Move to TypeScript (#3830)
This moves our JS file to use TS instead, which allows us to use a proper linter to check the code.
All related files where moved out from the root in a dedicated folder to avoid polluting the Rust environment.
2024-07-27 18:26:52 +02:00
Kirill Chibisov
7b0104b54c android: add {Active,}EventLoopExtAndroid::android_app
This type comes from the user and stored for the entire lifetime, so
no need to hide it from them after they've passed it to winit.

Fixes #3818.
2024-07-26 21:49:32 +03:00
Kirill Chibisov
facb809f12 chore: drop v0.30 deprecated APIs
Co-authored-by: daxpedda <daxpedda@gmail.com>
2024-07-26 16:44:47 +03:00
daxpedda
4e2e764e4a Fix CI for Rust v1.80 (#3822)
`clippy::doc_lazy_continuation` was added, which needed some fixing from our side.
2024-07-25 15:15:21 +02:00
daxpedda
a0bc3e5dc8 Web: Implement MonitorHandle (#3801)
Requires getting permission from the user to get "detailed" support.
Also enables users to go fullscreen on specific monitors.
Exposes platform-specific orientation API.

Most functionality depends on browser support, currently only Chromium.
2024-07-23 20:33:10 +02:00
daxpedda
2e97ab3d4f Web: use raw data in DeviceEvent::MouseMotion (#3803)
Only supported on Chrome MacOS and Windows.
2024-07-23 17:05:55 +02:00
daxpedda
ef580b817d Web: async improvements (#3805)
- Internal: Fix dropping `Notifier` without sending a result causing `Future`s to never complete. This should never happen anyway, but now we get a panic instead of nothing if we hit a bug.
- Internal: Remove a bunch of `unwrap()`s that aren't required when correctly using `MainThreadMarker`.
- `Window::canvas()` is now able to return a reference instead of an owned value.

Extracted from #3801.
2024-07-23 16:47:35 +02:00
daxpedda
5ec934b1b0 Web: don't block pen input (#3813) 2024-07-23 15:32:20 +02:00
daxpedda
c9c260ca08 Exclude Redox OS from the MSRV policy (#3811)
Redox OS requires a Rust nightly toolchain to compile at the moment.
2024-07-23 13:46:35 +02:00
daxpedda
b6109d4a17 macOS: fix building with feature = "rwh_04" 2024-07-22 13:11:27 +03:00
Speykious
eef2848c98 feat: Implement smooth resizing on X11 with _NET_WM_SYNC_REQUEST
Without smooth resizing, the window will appear to jitter when it is being
resized. This is because X11 completes the resize before the client gets a
chance to draw a new frame.

This is fixed by using the "sync" extension to ensure that the resize of the
X11 window is synchronized with the server.

Closes #2153
2024-07-21 09:39:43 -07:00
daxpedda
73c01fff96 Run doc tests on Web as well (#3799) 2024-07-20 21:20:18 +02:00
daxpedda
88bbdb33da Web: avoid using js_sys::Reflect (#3804) 2024-07-20 20:33:21 +02:00
daxpedda
652ff7576c Web: remove unused CustomCursorError::Animation (#3794) 2024-07-17 10:38:30 +02:00
daxpedda
d741c58ac3 Web: implement Error for CustomCursorError (#3793) 2024-07-17 02:33:06 +02:00
Kirill Chibisov
944ab60eda Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2024-07-16 22:04:12 +03:00
daxpedda
8e23d1608a Web: fix WindowEvent::Resized not using rAF (#3790) 2024-07-16 12:29:27 +02:00
Kirill Chibisov
dc99920612 wayland: bump dependencies
Update SCTK as a follow-up to 1170554dbd (ignore events to dead
objects) fixing it for wl_output.
2024-07-16 12:58:03 +03:00
Mads Marquart
ee3ab33a7c Remove internal ActiveEventLoop::clear_exit
How to store and clear the internal state should be internal to the
implementation on each backend.
2024-07-14 21:51:38 +03:00
daxpedda
5b8f5cb54a Make DeviceId/WindowId::dummy() safe (#3784) 2024-07-14 13:14:32 +02:00
Mads Marquart
bf97def398 Change run_app(app: &mut A) to run_app(app: A) (#3721)
This allows the user more control over how they pass their application state
to Winit, and will hopefully allow `Drop` implementations on the application
handler to work in the future on all platforms.
2024-07-11 15:38:09 +02:00
daxpedda
d5fd8682eb Web: use the word "Web" correctly and consistently (#3785) 2024-07-10 16:17:39 +02:00
daxpedda
39a7d5b738 Add to .git-blame-ignore-revs file 2024-07-07 18:43:32 +02:00
daxpedda
2665c12098 Rustfmt: use group_imports 2024-07-07 18:38:50 +02:00
daxpedda
936da131c2 Web: fix MouseMotion coordinate space (#3770) 2024-07-05 16:07:01 +02:00
daxpedda
850dd97177 Fix CI (#3775) 2024-07-05 15:54:46 +02:00
Kirill Chibisov
1170554dbd wayland: ignore events for dead objects
Nothing wrong will happen if we ignore events when compositor is at
wrong, at least crashing because compositor is just _wrong_ probably is
not a great option.

Links: https://github.com/alacritty/alacritty/issues/8065
2024-07-05 13:09:23 +03:00
daxpedda
75ce71f05a Implement ApplicationHandler::can_create|destroy_surfaces() (#3765) 2024-06-30 00:41:57 +02:00
daxpedda
a0d69c782a add: ActiveEventLoop::create_proxy()
Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
2024-06-29 18:19:09 +03:00
daxpedda
2e93e48a3b Web: Remove some unnecessary compatibility code (#3766) 2024-06-29 00:52:05 +02:00
Mads Marquart
82d9bbe559 Remove EventLoopExtIOS::idiom and ios::Idiom (#2924)
Introduced in 3a7350c with unclear motivation.

Nowadays, this feature is incomplete and unsound, and the equivalent
functionality can be trivially achieved outside of `winit` using
`objc2-ui-kit`.
2024-06-24 22:56:20 +02:00
Mads Marquart
8bdd4d620e Use self:: when re-importing local module (#3757)
Follow-up to https://github.com/rust-windowing/winit/pull/3755.
2024-06-24 22:40:49 +02:00
Mads Marquart
9d5412ffe1 Move iOS and macOS implementations into new apple module (#3756)
Move iOS and macOS implementations to a shared folder called `apple`, to allow
us to reduce the code-duplication between these platforms in the future.

The folder structure is now:
- `src/platform_impl/apple/`
  - `appkit/`
  - `uikit/`
  - `example_shared_file.rs`
  - `mod.rs`

* Add preliminary support for tvOS, watchOS and visionOS
* Reduce duplication in Cargo.toml when specifying dependencies
2024-06-24 13:26:49 +02:00
Kirill Chibisov
ecb887e5c3 event_loop: remove generic user event
Let the users wake up the event loop and then they could poll their
user sources.

Co-authored-by: Mads Marquart <mads@marquart.dk>
Co-authored-by: daxpedda <daxpedda@gmail.com>
2024-06-24 13:04:55 +03:00
Mads Marquart
7d1287958f Avoid path when importing modules (#3755)
Rust tooling generally works better this way. This includes
rust-analyzer, but more noticeably the output from `tracing` typically
prints the module path, which did not correspond to the actual file
system before.

Concretely, tracing output from the macOS backend changes from printing:
`winit::platform_impl::platform::util`
To printing:
`winit::platform_impl::macos::util`
2024-06-24 03:57:48 +02:00
Mads Marquart
c0c14aaf00 macOS: Call ApplicationHandler directly instead of using Event (#3753)
Additionally, always queue events in `handle_scale_factor_changed`.

These events were intentionally not queued before, since they are
executed inside `handle_scale_factor_changed`, which is itself queued.
Though that's a bit too subtle, so let's just take the minuscule perf
hit of redundantly checking whether we need to queue again.

Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
2024-06-23 23:14:22 +02:00
John Nunley
10dc0674bb ci: Use taiki-e/checkout-action
taiki-e/checkout-action has a few advantages over actions/checkout,
such as:

- It is written in Bash rather than Node.js
- It does not have frequent breaking changes, reducing churn

Signed-off-by: John Nunley <dev@notgull.net>
2024-06-23 12:28:58 -07:00
msiglreith
4f59796e8a Add notgull as Windows maintainer 2024-06-22 08:41:37 -07:00
msiglreith
32097d75c7 Update codeowner list 2024-06-22 08:41:37 -07:00
Bruce Mitchener
c6c4395c3b Use default-features, not default_features (#3746)
The latter syntax is deprecated and will be removed in Rust
2024 edition. This also generates a warning with current
versions of Rust.
2024-06-22 11:38:42 +02:00
Kirill Chibisov
38e6f9ad84 Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2024-06-21 21:40:16 +03:00
daxpedda
3e6092b8ed Web: implement WaitUntilStrategy (#3739) 2024-06-20 23:07:42 +02:00
daxpedda
b4e83a5966 Web: set control flow strategies on EventLoop (#3740) 2024-06-20 22:56:08 +02:00
Mads Marquart
db2c97a995 macOS: set the theme on the NSWindow, instead of application-wide
This new implementation uses:
- The NSAppearanceCustomization protocol for retrieving the appearance
  of the window, instead of using the application-wide
  `-[NSApplication effectiveAppearance]`.
- Key-Value observing for observing the `effectiveAppearance` to compute
  the `ThemeChanged` event, instead of using the undocumented
  `AppleInterfaceThemeChangedNotification` notification.

This also fixes `WindowBuilder::with_theme` not having any effect, and
the conversion between `Theme` and `NSAppearance` is made a bit more
robust.
2024-06-20 17:05:34 +03:00
daxpedda
1552eb21f7 Bump MSRV to v1.73 (#3743) 2024-06-20 11:09:15 +02:00
Kirill Chibisov
d8ffd4bb26 x11: fix build on arm
The c_char type, which was used under the hood is different depending
on arch, thus use it directly instead of i8.

Fixes #3735.
2024-06-17 13:51:08 +03:00
Kirill Chibisov
34c15608e0 Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2024-06-15 23:50:40 +03:00
Kirill Chibisov
eef6977f45 macOS: fix opacity handling
Not using `NSColor::clearColor()` results in Quartz thinking that the
window is not transparent at all, which results in artifacts.

However, not setting the `windowBackgroundColor` in
`Window::set_transparent` results in border not properly rendered.

Fixes: 94664ff687 (Don't set the background color)
2024-06-15 15:41:34 +03:00
Kirill Chibisov
078b46720b chore: address 1.79 clippy lints 2024-06-15 15:26:26 +03:00
daxpedda
3b4e064a07 Web: fix crash InnerSizeWriter::request_inner_size() (#3727) 2024-06-12 00:22:03 +02:00
daxpedda
39bc139500 Web: don't overwrite cursor with CursorIcon::Default (#3729) 2024-06-12 00:12:14 +02:00
daxpedda
9522670081 Web: queue EventLoopProxy::send_event() to microtask 2024-06-12 00:02:26 +02:00
Kirill Chibisov
9a1ef49dc3 Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2024-06-10 17:13:33 -07:00
Mads Marquart
3a624e0f52 macOS/iOS: Various refactorings in application state (#3720)
I'm preparing to get rid of our application delegate in favour of registering
notification observers, to do so I'm renaming `app_delegate.rs` to
`app_state.rs`, and moving the functionality out of the Objective-C method
into a normal method.

Additionally, `AppState` previously implemented `Default`, but really, this
was a hack done because someone (probably myself) was too lazy to write out
the full initialization in `AppDelegate::new`.
2024-06-06 14:39:31 +02:00
Mads Marquart
279e3edc54 macOS: Improve event queuing (#3708)
* Use AppKit's internal queuing mechanisms

This allows events to be queued in a more consistent order, they're now
interleaved with events that we handle immediately (like redraw events),
instead of being handled afterwards.

* Only queue events if necessary

This makes the call stack / backtraces easier to understand whenever
possible, and generally improves upon the order in which events are
delivered.
2024-06-06 12:32:02 +02:00
Philippe Renon
0e74d37ff5 doc: clarify Window::pre_present_notify availability
Fixes #3703.
2024-06-06 12:11:06 +03:00
ShikiSuen
2d1382f7d6 Handle _selected_range sent to NSTextInputClient.setMarkedText(). (#3619)
Co-authored-by: Mads Marquart <mads@marquart.dk>
2024-05-31 08:54:20 +02:00
Mads Marquart
5d8091fc7f Implement ApplicationHandler for &mut A and Box<A> (#3709) 2024-05-29 11:51:53 +02:00
Mads Marquart
d7abe0316e Update objc2 to v0.2.2 (#3702)
- Use new `bitflags!` support.
- Use `objc2-ui-kit`.
- Change usage of `Id` to `Retained`.
2024-05-27 14:49:22 +02:00
Diggory Hardy
5ea20fc905 event_loop: add is_x11 and is_wayland on EventLoop 2024-05-26 17:38:10 +04:00
Golden Water
e108fa2fbf Resize when size changes on scale change on macOS
This fixes an issue where the window glitched due to resize
when the user doesn't actually change the window, but macOS
function to update window size was still called.
2024-05-23 20:40:07 +04:00
Kirill Chibisov
fff6788c12 chore: explicitly use cfg_aliases 0.2.1
This correctly handles recent nightly lint that requires to explicitly
define the CFG guards.
2024-05-22 15:51:29 +04:00
Kirill Chibisov
3e8fa41073 event_loop: remove deprecated run APIs
The APIs are not well suited for the `&dyn ApplicationHandler` model and
`Box<dyn EventLoop>` structure, thus remove them.
2024-05-20 20:27:36 +04:00
Kevin Müller
2b1c8cea1b bugfix: Replace pointer dereference with read_unaligned
On Raspberry Pi, using the Rust crate eframe caused the program to crash on
mouse movement. The Backtrace lead to this specific line of code, and the exact
error was a "misaligned pointer dereference: address must be a multiple of 0x8
but is xxxx"

The edit has been tested with the Raspberry Pi, which works now.
2024-05-19 15:08:14 -07:00
Ryan Burleson
ab33fb8eda fix doc typo in application.rs (#3676) 2024-05-07 21:24:02 +02:00
linkmauve
b0b64a9a15 Reexport older versions of raw-window-handle
When the user decides to use an older version of raw-window-handle,
through the rwh_04 or rwh_05 features, it makes sense to reexport the
crate so they don’t have to depend on it manually and can instead use
winit::raw_window_handle.
2024-05-06 19:50:25 +04:00
Mads Marquart
d5d202d60e Reduce usage of direct msg_send! 2024-05-06 19:09:38 +04:00
Mads Marquart
cb39ab29f4 macOS: Move util::EMPTY_RANGE to usage spot (#3685) 2024-05-06 16:54:52 +02:00
Mads Marquart
0a3cacd577 Retain ApplicationDelegate in NSWindowDelegate and NSView
The delegate is only weakly referenced by NSApplication, so getting it
from there may fail if the event loop has been dropped.

Fixes #3668.
2024-05-06 18:29:07 +04:00
Mads Marquart
16fd2baba0 Use rustc-check-cfg (#3682) 2024-05-06 07:11:57 +02:00
daxpedda
7f8771a362 Web: fix Clippy v1.78 FPs (#3678) 2024-05-03 22:24:54 +02:00
Kirill Chibisov
337d50779c Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2024-04-27 20:02:40 +04:00
Joshua Pedrick
fd477986de Add UIGestureRecognizerDelegate and PanGestureRecogniser (#3597)
- Allow all gestures simultaneously recognized.
- Add PanGestureRecogniser with min/max number of touches.
- Fix sending delta values relative to Update instead to match macOS.
- Fix rotation gesture units from iOS to be in degrees instead of radians.

Co-authored-by: Mads Marquart <mads@marquart.dk>
2024-04-27 15:55:04 +02:00
Mads Marquart
94664ff687 Don't set the background color when initializing with transparency (#3657)
Setting the background color changes how the window title bar appears,
which is something that the application should customize itself if it
wants this behaviour (and also, it wasn't set when calling
`set_transparent`, so the behaviour wasn't consistent).
2024-04-27 15:41:14 +02:00
growfrow
0fc8c37721 chore: fix some typos in comments (#3635)
Signed-off-by: growfrow <growfrow@outlook.com>
2024-04-27 15:29:11 +02:00
Kirill Chibisov
ec29c81ad2 chore: ensure that .cargo config is not published
Just in case, so the correct changelog will be rendered when pulling
the crate from the crates.io as archive and trying to build it.
2024-04-27 17:03:28 +04:00
Marijn Suijten
304a585493 android: bump to ndk 0.9.0 and android-activity 0.6.0 2024-04-27 13:35:11 +04:00
John Nunley
1682703b5c bugfix(win32): Only return win handle on OK thread
On Windows, it is generally unsafe to use the HWND outside of the thread
that it originates from. In reality, the HWND is an index into a
thread-local table, so using it outside of the GUI thread can result in
another window being used instead, following by code unsoundness. This
is why the WindowHandle type is !Send. However, Window is Send and Sync,
which means we have to account for this.

Thus far the best solution seems to be to check if we are not in the GUI
thread. If we aren't, refuse the return the window handle.

For users who want to ensure the safety themselves, the unsafe API
was added.

Signed-off-by: John Nunley <dev@notgull.net>
2024-04-26 20:28:10 +04:00
Mads Marquart
bdd80c8af2 Add .git-blame-ignore-revs
The user has to explicitly opt into this, the file itself documents how
to do so.
2024-04-26 20:19:45 +04:00
Kirill Chibisov
7b0c7b6cb2 chore(rustfmt): use nightly (#2325)
Stable rustfmt lacks a lot of features resulting in worse formatted
code, thus use nightly formatter.
2024-04-26 17:11:44 +02:00
Marijn Suijten
7006c7ceca bugfix(android): Allow Volume* keys to be passed to the user 2024-04-23 21:51:23 +04:00
Kirill Chibisov
2491f2bbd6 windows: bump windows-sys to 0.52 2024-04-22 17:21:53 +04:00
tetra
babbb715c5 Windows: implement resize increments (#3623) 2024-04-21 15:05:41 +02:00
John Nunley
be79e8979a docs: Don't reference EventLoopBuilderExtUnix
This replaces a reference to EventLoopBuilderExtUnix in a panic
message with EventLoopBuilderExtX11 or EventLoopBuilderExtWayland.

Closes #3488

Signed-off-by: John Nunley <dev@notgull.net>
2024-04-20 19:45:07 -07:00
Kirill Chibisov
9ab4c03e89 wayland: fix CSD decorations glitch when closing
In rare cases destroying subsurfaces before the main surface could
result in a frame where the window is still shown, but decorations
got hidden, right before the window itself disappears.
2024-04-19 14:40:00 +04:00
daxpedda
4f47a4e793 Update dev-dependencies (#3641) 2024-04-18 21:52:38 +02:00
daxpedda
c15fa6e433 Re-introduce Web examples (#3637) 2024-04-18 19:43:39 +02:00
Kirill Chibisov
24faacf497 docs: fix release steps in CONTRIBUTING.md
The steps were rebased incorrectly.

Fixes: 575d978202 (docs: Rework CONTRIBUTING guidelines)
2024-04-18 20:27:31 +04:00
Mads Marquart
080556f2c8 Fix icrate's clippy customization 2024-04-18 20:04:42 +04:00
Mads Marquart
259e868c05 Update objc2 crates (#3634)
Changes relevant to Winit:
- `icrate` has been deprecated in favour of separate crates per
  framework, in our case `objc2-foundation` and `objc2-app-kit` (and in
  the future `objc2-ui-kit` on iOS).
- Moved `MainThreadMarker::run_on_main` to free-standing function
  `run_on_main`.
- Changed how features work, this should result in less code that we
  need to compile.
- Enums are now real structs instead of type-aliases and free constants.
2024-04-18 17:34:19 +02:00
Kirill Chibisov
575d978202 docs: Rework CONTRIBUTING guidelines
Give better recommendations for contributors on how to propose start the
work, write commit messages, and handle review by explicitly stating
expectations, however make it clear that maintainers will help you if
you have issues.

Write down the guidelines for maintainers on how they should handle
contributions and interact with other maintainers to help maintaining
good code quality level by listing maintainers responsibilities and
providing suggestions on how to handle various situations.

Co-authored-by: John Nunley <dev@notgull.net>
Signed-off-by: John Nunley <dev@notgull.net>
2024-04-16 17:06:36 -07:00
Bruce Mitchener
7dd7dc1fc8 example: Fix typo: "fosus" -> "focus" (#3629) 2024-04-15 23:59:58 +02:00
Bruce Mitchener
df7c496a5d chore: more concise Debug output for WindowId 2024-04-14 21:06:18 +04:00
Kirill Chibisov
0086d7153b wayland: bump sctk-adwaita to 0.9.0
This is a breaking change, because the system versions of the libraries
used by sctk-adwaita were changed. Such changes cascade through all
the deps, so all libraries using winit MUST do a breaking change.
2024-04-14 20:38:20 +04:00
Bruce Mitchener
b79acd8a5a ci: Update all jobs to actions/checkout@v4
Updates the checkout action to the latest version
2024-04-13 20:50:41 -07:00
Bruce Mitchener
c2951e0194 docs: Fix copy/paste error in changelog
Due to a copy/paste error a comment in the migration in the changelog mentioned
"window events" in a context that was clearly meant for device events. This
commit fixes this issue.
2024-04-13 18:12:39 -07:00
Kirill Chibisov
8998e36994 chore(changelog): write migrations for 0.30
Add a migrations for the big API changes showcasing how to upgrade
some common snippets of old code to new APIs.

Co-authored-by: Mads Marquart <mads@marquart.dk>
2024-04-12 21:55:44 +04:00
Kirill Chibisov
5a7169c7a6 chore(changelog): use 'keep a changelog' format
Links: https://keepachangelog.com/en/1.0.0/
Co-authored-by: Mads Marquart <mads@marquart.dk>
2024-04-12 21:38:50 +04:00
Mads Marquart
4cd6877e8e Fix CI failing when updating typos to 1.20.3 (#3620) 2024-04-03 00:38:55 +02:00
Colin Kinloch
44aabdddcc example: add an example of request_inner_size
Add the shortcut "Alt + R" to swap the size of the window axes in
window example.
2024-03-28 23:39:19 +04:00
James Tucker
c4415009c0 windows: remove github URLs from binaries
There are  AV rules out there which cause almost any
program that contains github URLs to become marked as malware.

While those rules are spurious, they're years old, and AV vendors have a
very poor reputation at appropriately following up with these problems.

Remove these strings from the panic data present in the binary
prevents binaries linking the winit from being spuriously marked as
Trojan:Win32/Wacatac.B!ml.
2024-03-28 22:45:34 +04:00
Mads Marquart
63a7c02492 Consistently emit extra mouse motion events (#3601)
In particular, we don't want to emit those events inside of
`pressureChangeWithEvent:`, since the mouse motion value is sometimes
outdated.

Additionally, we want to ensure the events have been emitted during
other gestures.

Fixes https://github.com/rust-windowing/winit/issues/3516
2024-03-28 19:18:03 +01:00
John Nunley
7b0ef160fc chore: silence clippy
It appears that clippy's dead code detection has gotten better. This
commit fixes winit's code to match.

Signed-off-by: John Nunley <dev@notgull.net>
2024-03-27 12:20:21 +04:00
wannacu
962241e2a0 bugfix(x11): Fix window position calculation overflow during dragging
Closes #3594

Signed-off-by: wannacu <wannacu2049@gmail.com>
2024-03-25 21:16:29 -07:00
Mads Marquart
3efa6d855d chore: Fix Clippy after Rust 1.77
- There are some thread_local instances that can be made constant.
- An inner attribute can be moved to an outer one.
2024-03-21 19:32:20 -07:00
Smith Chang
9067426dca chore: remove repetitive words (#3599) 2024-03-21 18:44:23 +01:00
Fredrik Fornwall
ba10c35240 fix(windows): configure hidden and grabbed cursor
This fixes issues where a hidden and grabbed cursor could leave the
window and become visible on top of the windows taskbar (and potentially
leave the window altogether if the taskbar is clicked) under at least
two occasions:

    - When a window is overlapping the taskbar.
    - When a window is maximized and Automatically hide the taskbar has
      been enabled.

This approach of confining the cursor to the center of the window is
used in SDL.
2024-03-18 23:50:40 +04:00
daxpedda
baf10de958 Prefer [foo][bar] over [foo](bar) for intra-doc links (#3191) 2024-03-16 10:22:29 +01:00
Kirill Chibisov
c10f9c32d3 DPI version 0.1.1 2024-03-15 18:42:52 +04:00
Mads Marquart
975cf068c7 chore: add issue templates
Provide issue templates to ask for platform specific information to
make bugs more actionable.
2024-03-15 18:15:49 +04:00
amrbashir
8e69a8fa40 dpi: derive common traits for PixelUnit
Derive `Debug`, `Copy`, `Clone`	, `PartialEq`, `Serialize`,
`Deserialize` for `PixelUnit`, which follows other types in dpi crate.
2024-03-15 17:57:55 +04:00
Mads Marquart
fedb944d57 chore(docs): make changelogs visible on docsrs
Split changelog file to make it more comprehensible when reading and
also make it a part of documentation so it'll be more discoverable
by the users. This change also makes it possible for rust code inside
the changelogs to be tested with `cargo`.

Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
2024-03-15 17:19:19 +04:00
Kirill Chibisov
a63b04385a Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2024-03-13 14:48:20 +04:00
Kirill Chibisov
06f4e28de9 DPI version 0.1.0 2024-03-13 13:56:58 +04:00
Kirill Chibisov
249d5d8bff bugfix(dpi): PhysicalUnit::to_logical computation
The conversion of PhysicalUnit was wrongly computed and the tests were
not running on the CI for the dpi crate, thus it was missed, even though
the test was correctly failing.

Signed-off-by: John Nunley <dev@notgull.net>
Signed-off-by: Kirill Chibisov <contact@kchibisov.com>
2024-03-13 12:58:39 +04:00
Kirill Chibisov
66df2c22ba chore(nigthly): fix errors
The structure is used by other backends, `cfg`-out it is pointless.
2024-03-13 12:58:39 +04:00
Kirill Chibisov
359a38844b bugfix(x11): crash when querying xsettings prop fails
Don't crash when xsettings query fails with _present_ xsettings.

Closes: https://github.com/rust-windowing/winit/issues/3573
2024-03-10 21:43:53 -07:00
amrbashir
563b0bf5e3 dpi: add LogicalUnit, PhysicalUnit, and Unit
Part-off: https://github.com/rust-windowing/winit/issues/2395
2024-03-08 21:15:27 +04:00
AmeKnite
b2f9fad654 ci: add typos-cli
Given that typos are frequent and may appear in the public API spell
check code on CI.
2024-03-07 18:03:38 +04:00
John Nunley
4ade1a7518 docs: add a code of conduct
As previously discussed in today's meeting, this commit adds a code
of conduct to winit. I've elected to re-use the Rust project's Code
of Conduct, as it is also in use by other popular Rust projects and I
agree with its intentions. The goal is to set forward a set of explicit
expectations for how discourse in the rust-windowing project should be
conducted.

I've deliberately left out a mechanism for enforcing this code of
conduct. My hope is that, by the act of setting these expectations,
contributors will voluntarily follow them. In addition I have no
interest in being an internet janitor. If this becomes necessary in the
future we can look into it later.

rust-windowing collaborators, please read the linked Code of Conduct.
Not only for expectations of behavior, but also for expectations of how
it will be enforced should it come to it.

Signed-off-by: John Nunley <dev@notgull.net>
2024-03-07 17:32:06 +04:00
Kirill Chibisov
e06ecf4d72 Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2024-03-06 14:37:46 +04:00
Kirill Chibisov
4a8050289d fix(xkb): text not being None when composing
When composing the text was not reset to `None` leading to input in
some applications e.g. alacritty.

Links: https://github.com/alacritty/alacritty/issues/7806
2024-03-05 20:34:59 +04:00
daxpedda
99e238065e Bump x11-dl to v2.19.1 2024-03-05 16:53:35 +04:00
Kirill Chibisov
d123cd2f8e api: add ApplicationHandler and matching run APIs
Add a simple `ApplicationHandler` trait since winit is moving towards
trait based API. Add `run_app` group of APIs to accept `&mut impl
ApplicationHandler` deprecating the old `run` APIs.

Part-of: https://github.com/rust-windowing/winit/issues/3432
2024-03-05 16:13:14 +04:00
Kirill Chibisov
fc8a008b25 chore(wayland): don't reapply same cursor grab
Some compositors break when re-taking the same grab.

Closes: https://github.com/rust-windowing/winit/issues/3566
2024-03-05 15:38:08 +04:00
John Nunley
f6f1c45a72 bugfix(x11): fix incorrect delta filtering
Invert the mouse delta filter, so it aligns with the intention of
filtering values lower than epsilon.

Signed-off-by: John Nunley <dev@notgull.net>
Closes: https://github.com/rust-windowing/winit/issues/3558
2024-03-04 20:49:04 +04:00
daxpedda
388c40b1e0 Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2024-03-02 13:22:36 +01:00
daxpedda
7a40aa43dc Web: fix crash with ControlFlow::Wait|WaitUntil 2024-03-02 12:26:26 +01:00
John Nunley
944347696a Replace log with tracing
Tracing is a modern replacement for the log crate that allows for
annotating log messages with the function that they come from.

Signed-off-by: John Nunley <dev@notgull.net>
Closes: #3482
2024-03-01 20:45:31 +04:00
Kirill Chibisov
96172693fe Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2024-03-01 15:21:06 +04:00
Mads Marquart
32004405ee Add documentation example of ignoring key repeats (#3538) 2024-03-01 11:27:47 +01:00
Kirill Chibisov
22e932b5ab On X11, fix use after free during xinput2 processing
Fixes #3536.
2024-03-01 13:40:20 +04:00
John Nunley
3d4c53459a On X11, filter out tiny device mouse events
Usually, if mouse events are equal to (0, 0) we filter them out.
However, if the event is very close to zero it will still be given to
the user. In some cases this can be caused by bad float math on the X11
server side.

Fix it by filtering absolute values smaller than floating point epsilon.

Signed-off-by: John Nunley <dev@notgull.net>
Closes: #3500
2024-03-01 13:11:28 +04:00
Kirill Chibisov
f0b4889227 Add LICENSE file to dpi crate
While the license was set to follow workspace the file itself should
be present to make package shippable in e.g. Debian/Fedora.
2024-02-28 23:13:14 +04:00
Kirill Chibisov
c81448e0b8 Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2024-02-28 22:54:37 +04:00
Dimitris Apostolou
f498ff0369 Fix feature = "cargo-clippy" deprecation 2024-02-28 21:50:05 +04:00
Mads Marquart
c4e6e94b80 Remove a few unnecessary usages of Lazy (#3531)
* Convert usage of Lazy to OnceLock on macOS and iOS

* Remove a few uses of Lazy that wrapped Mutex or RwLock

The `new` functions on these were made `const` in Rust 1.63.0

* Use AtomicBool instead of RwLock
2024-02-28 12:28:26 +01:00
Mads Marquart
a5dbd3ee52 macOS: Refactor event handler storage (#3532)
This makes our use of `unsafe` to make the event handler temporarily 'static be local to a module, in a way that's (hopefully) much easier to reason about.
2024-02-28 04:33:47 +01:00
Mads Marquart
a4480a0652 Clean up iOS ffi.rs (#3530)
This makes it easier to transition to a future autogenerated version of UIKit.
2024-02-27 21:07:52 +01:00
Mads Marquart
e41f0eabb1 Split dpi module out into a separate crate (#3518)
Co-authored-by: John Nunley <dev@notgull.net>
2024-02-26 14:52:00 +01:00
Kirill Chibisov
7e28d7615e On X11, replay modifiers consumed by XIM 2024-02-26 12:59:41 +04:00
daxpedda
010787a430 Fix nightly CI (#3526) 2024-02-26 09:46:12 +01:00
James Liu
352e70b8ac m: Remove once_cell dependency
Removes the once_cell dependency, instead using std::sync::OnceLock and a
minimal polyfill for std::sync::LazyLock, which may be stabilized soon
(see rust-lang/rust#121377).

This should not require a bump in MSRV, as OnceLock was stabilized in 1.70,
which this crate is using.
2024-02-25 08:19:27 -08:00
Friz64
990bbf178f Update documentation regarding set_cursor_position (#3521) 2024-02-24 23:15:38 +01:00
Mads Marquart
97cfdd4b09 Move some of our documentation to docs.rs (#3478)
* Move platform-specific documentation to `winit::platform` module

* Document cargo features in crate docs

* Move version requirements to crate-level docs
2024-02-23 15:35:18 +01:00
Mads Marquart
a127bd6f66 iOS: Split classes in view.rs into separate files (#3511)
* Move application delegate to its own file
* Move window subclass to window.rs
* Split view controller to separate file
2024-02-22 22:28:49 +01:00
Kirill Chibisov
4a8648be57 On X11, force resend modifiers when focus changes
Given that `ModifiersChanged` is a window event, it means that clients
may track it for each window individually, thus not sending it between
focus changes may result in modifiers getting desynced on the consumer
side.
2024-02-22 08:30:39 +04:00
Kirill Chibisov
a8c7109e89 Pin bumpalo to 3.14.0 on CI 2024-02-21 14:44:29 +04:00
Kirill Chibisov
7abd427216 Create custom cursor with directly with event loop
Replace the `CustomCursorBuilder` with the `CustomCursorSource` and
perform the loading of the cursor via the
`EventLoop::create_custom_cursor` instead of passing it to the builder
itself.

This follows the `EventLoop::create_window` API.
2024-02-21 14:44:29 +04:00
Kirill Chibisov
3fb93b4f83 Deprecate window creation with stale event loop
Creating window when event loop is not running generally doesn't work,
since a bunch of events and sync OS requests can't be processed. This
is also an issue on e.g. Android, since window can't be created outside
event loop easily.

Thus deprecate the window creation when event loop is not running,
as well as other resource creation to running event loop.

Given that all the examples use the bad pattern of creating the window
when event loop is not running and also most example existence is
questionable, since they show single thing and the majority of their
code is window/event loop initialization, they wore merged into
a single example 'window.rs' example that showcases very simple
application using winit.

Fixes #3399.
2024-02-21 14:44:29 +04:00
Andriy
19190a95a0 On Wayland, send DeviceEvent::Motion 2024-02-20 13:34:05 +04:00
Bruce Mitchener
c4310af83c Fix various typos
Mainly fix typos in comments, but also some minor code changes:

* Rename `apply_on_poiner` to `apply_on_pointer`.
* Rename `ImeState::Commited` to `ImeState::Committed`
* Correct `cfg_attr` usage: `wayland_platfrom` -> `wayland_platform`.
2024-02-19 08:58:44 +04:00
Kirill Chibisov
542d1938ce Fix warnings with latest nightly 2024-02-19 08:47:32 +04:00
Mads Marquart
31f8b816bd Make EventLoopProxy Sync
Co-authored-by: daxpedda <daxpedda@gmail.com>
Closes: #3448
2024-02-19 08:47:32 +04:00
Kirill Chibisov
e61a7320a2 On X11, use events modifiers to detect state
While there's a separate event to deliver modifiers for keyboard,
unfortunately, it's not even remotely reflects the modifiers state.

Thus use events along side regular modifier updates to correctly
detect the state. Also, apply the modifiers from the regular
key event by converting their state to xkb modifiers state.

Links: https://github.com/alacritty/alacritty/issues/7549
Closes: #3388
2024-02-18 01:39:42 +04:00
Mads Marquart
db41938deb Remove Testers and Contributors table (#3497) 2024-02-17 09:54:29 +01:00
Mads Marquart
2bc1943188 Pin ahash in CI (#3498)
Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
2024-02-16 17:51:48 +01:00
Kirill Chibisov
385c4b3c88 On Wayland, update title from AboutToWait
Fixes #3472.
2024-02-14 00:48:52 +04:00
Kirill Chibisov
ea70f773d3 On X11, don't require XIM to be present
In general, we may want to use xinput v2 for keyboard input in such
cases, so we have compose going, but for now just don't crash if
there's no XIM.
2024-02-13 07:49:58 +04:00
AryaveerSR
83012f4c1c Fix Documentation for ScaleFactorChanged in WindowEvent. (#3489) 2024-02-12 18:20:03 +01:00
Jeremy Soller
6825fed073 On Orbital, implement various Window methods
Implement the following methods on the `Window`:
  - `Window::set_cursor_grab`.
  - `Window::set_cursor_visible`.
  - `Window::drag_window`.
  - `Window::drag_resize_window`.
  - `Window::set_transparent`.
  - `Window::set_visible`.
  - `Window::is_visible`.
  - `Window::set_resizable`.
  - `Window::is_resizable`.
  - `Window::set_maximized`.
  - `Window::is_maximized`.
  - `Window::set_decorations`.
  - `Window::is_decorated`.
  - `Window::set_window_level`.

To make locked pointer useful, the `DeviceEvent::MouseMotion`
event was also implemented.
2024-02-11 04:40:06 +04:00
Kirill Chibisov
273984a385 On X11, extract event handlers
Make code more clear wrt explicit returns during event handling,
which may lead to skipped IME event handling.
2024-02-11 03:31:47 +04:00
Kirill Chibisov
dbe0f852da On X11, store window target on EventProcessor
Remove the redundant `Rc` to access the window target.
2024-02-11 03:31:47 +04:00
Kirill Chibisov
d1902aa15a On X11, don't require XSETTINGS
We could fail to setup property watcher and fail to start, thus
don't require XSETTINGS to work.

Fixes: df8805c0 (On X11, reload DPI on _XSETTINGS_SETTINGS)
2024-02-10 00:24:03 +04:00
Mads Marquart
4112fccc12 Update meeting time (#3475) 2024-02-09 17:20:46 +01:00
Jeremy Soller
bd6ce32860 On Orbital, map keys to NamedKey when possible 2024-02-09 11:28:30 +04:00
Kirill Chibisov
8936fe1acd Fix nightly CI dead_code warnings 2024-02-08 13:28:26 +04:00
Jeremy Soller
fedb86ea5a On Orbital, implement KeyEventExtModifiersSupplement
This also fixes `logical_key` and `text` not reported in `KeyEvent`.
2024-02-08 12:55:11 +04:00
Kirill Chibisov
20687fef1c Fix compatibility with platforms without AtomicU64
Fixes #3456.
2024-02-08 00:58:43 +04:00
Kirill Chibisov
56035e1f13 Account for WAYLAND_SOCKET when detecting Wayland
Fixes #3459.
2024-02-07 06:41:23 +04:00
Amr Bashir
08fc4099e8 On Windows, apply ScaleFactorChanged new size if different than OS (#3408)
This fixes an issue when setting the position of the window on a new monitor and immediately maximizing it

```rs
window.set_outer_position::<PhysicalPosition<u32>>((2000, 200).into());
window.set_maximized(true);
```

Due to the nature of the event loop, the requested position and maximization state will apply correctly but due to the fact that the new position is a different monitor, a `ScaleFactorChanged` is emitted afterwards to the evenloop and a new size is set while the window is still maximized which results in a window that has `WS_MAXIMZE` window style but doesn't cover the whole monitor.
2024-02-06 20:46:30 +01:00
Kirill Chibisov
4d4d6e5052 On Wayland, fix min/max inner size setting
The size is only applied on the next `wl_surface::commit` thus we
must trigger the redraw.
2024-02-01 00:11:31 +04:00
Kirill Chibisov
cf5f4de19e Specify that alpha channel is not premultiplied 2024-01-30 21:31:17 +04:00
Kirill Chibisov
21df84b7f4 On Wayland, pre-multiply alpha for custom cursor
Fixes: #3360
2024-01-30 21:31:17 +04:00
Kirill Chibisov
dd13ccda4c On Wayland, send Focused(false) once seats left
Given that we merge all the seats, we should consider that window
is not focused once all seats wl_keyboards are no longer present.

We use seats instead of keyboards to track focus to protect against
wl_keyboard::leave not being delivered when removing the seat
(usually it's not the case though).

Fixes: #3376
2024-01-30 18:28:13 +04:00
John Nunley
df8805c0d2 On X11, reload DPI on _XSETTINGS_SETTINGS
This also fixes the deadlock when such reload may happen.

Fixes: #3383
Signed-off-by: John Nunley <dev@notgull.net>
Signed-off-by: Kirill Chibisov <contact@kchibisov.com>
2024-01-30 16:52:29 +04:00
Kirill Chibisov
db1ca45a17 Move ::builder changes to the correct release
They were added to 0.29.2 release.

Fixes: 8862ce01 (Add EventLoop::builder)
Fixes: 569c44a6 (Add Window::builder)
2024-01-30 14:28:42 +04:00
Kirill Chibisov
ff731197dc On Wayland, disable Occluded handling
Change in state requires a redraw, however drawing when getting
`Occluded` with vsync will block indefinitely, thus the event in
it's current state is rather useless.

To solve this issue winit needs a way to determine whether the user
paused/continued their render loop, so it can commit on their behalf.

This commit also forces redraw when getting configure.

Links: https://github.com/rust-windowing/winit/issues/3442
2024-01-30 13:00:10 +04:00
Mads Marquart
f526a47152 Remove EventLoopError::AlreadyRunning
This is already prevented by the type-system, and as such it doesn't
make sense to have an error case for this.
2024-01-29 22:06:03 +04:00
Mads Marquart
f204467838 Add a note about winit team meetings 2024-01-29 21:41:05 +04:00
Bruce Mitchener
6641dfa412 Bump cfg_aliases to 0.2.0 2024-01-29 21:27:23 +04:00
John Nunley
c1168b4f58 Remove drm/kms features from softbuffer (#3439)
We use softbuffer as a dev-dependency for rendering into our windows in
examples. However, we do not support a DRM/KMS backend yet, while
softbuffer comes with a DRM/KMS backend by default. This commit removes
the DRM/KMS feature from softbuffer to save some build time during
testing
2024-01-28 22:40:01 +01:00
Ulrik de Muelenaere
f8b7c4b78f bugfix: Fix swapped instance and general class names on X11
This let statement swapped the two names, resulting in incorrect
behavior since commit d7ec899d. That commit did not actually introduce
the swap, but the previous code swapped it again before setting the
WM_CLASS property, so no issue was ever observed.

It also brings the documentation in line with the implementation since the
parent commit, and with the ICCCM standard, which states the following
about the WM_CLASS property [1]:

  The two strings, respectively, are:
  * A string that names the particular instance of the application [...]
  * A string that names the general class of applications [...]

[1] https://www.x.org/releases/current/doc/xorg-docs/icccm/icccm.html#WM_CLASS_Property
2024-01-27 18:40:28 -08:00
John Nunley
3830b492c4 Update new builders for latest master
Signed-off-by: John Nunley <dev@notgull.net>
2024-01-27 10:16:52 -08:00
Mads Marquart
8862ce0163 Add EventLoop::builder, which replaces EventLoopBuilder::new
Similarly for EventLoop::with_user_event and EventLoopBuilder::with_user_event
2024-01-27 10:16:52 -08:00
Mads Marquart
569c44a632 Add Window::builder, which replaces WindowBuilder::new 2024-01-27 10:16:52 -08:00
Mads Marquart
ef2ec904ce Fix iOS gesture deltas (#3426) 2024-01-25 23:46:48 +01:00
Dubzer
98d3391f2d Add DWMWA_SYSTEMBACKDROP_TYPE support on Windows (#3257) 2024-01-25 18:59:10 +01:00
Diggory Hardy
d0a1917603 Improve error when X11/Wayland is not present 2024-01-25 14:49:36 +04:00
Mads Marquart
b36d8d1e52 Refactor user event handling on macOS/iOS (#3422)
Move user event handling to inside main event loop
2024-01-25 05:26:50 +01:00
Nick
a5b08fc48c Send the event before waking up the message pump. (#3418) 2024-01-24 21:38:20 +01:00
Mads Marquart
0482d9cfce Fix Android examples link in README (#3420) 2024-01-24 20:41:33 +01:00
Amr Bashir
10a785019c Add option to enable/disable WS_CLIPCHILDREN window style (#3212) 2024-01-22 18:55:37 +01:00
Amr Bashir
0cc19716f3 On Windows, Remove WS_CAPTION, WS_BORDER and WS_EX_WINDOWEDGE styles for child windows (#3410) 2024-01-20 13:07:03 +01:00
白山風露
572d7ee77c On Windows, set fullscreen/maximized creating window 2024-01-19 21:43:08 +04:00
sidit77
b0c59c8416 On Windows, expose DWM attributes (#3409) 2024-01-19 12:43:39 +01:00
daxpedda
d7c7ba1d6c Move PlatformSpecificWindowBuilderAttributes (#3318) 2024-01-17 23:37:28 +01:00
daxpedda
aec608f93c Document Window Drop behavior (#3315) 2024-01-17 23:17:36 +01:00
daxpedda
d1717b6a01 X11: cache custom cursors (#3366) 2024-01-17 18:17:49 +01:00
François
6b29253797 Support pinch, double tap and rotation gestures on iOS (#3130)
This is off by default on iOS. Note that pinch delta may be NaN.

Co-authored-by: Mads Marquart <mads@marquart.dk>
2024-01-16 21:31:18 +01:00
Kirill Chibisov
30775f4982 Update platform and core maintainers 2024-01-16 21:45:29 +04:00
Mads Marquart
41070d7c67 Make DeviceId simpler on iOS (#3402)
This previously contained a UIScreen for some weird reason; perhaps
because `DeviceId` was confused for `UIDevice`?
2024-01-15 21:51:01 +01:00
John Nunley
6df972d108 feat: Add an owned display handle type
This was supposed to be rolled out with the rwh v0.6 update, but it
was left behind for some reason. I've added this type back.

Signed-off-by: John Nunley <dev@notgull.net>
2024-01-15 11:58:11 -08:00
Kirill Chibisov
73910d20cc Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2024-01-15 13:10:46 +04:00
daxpedda
16d860736b Platform is called Web not Wasm (#3393) 2024-01-14 18:54:52 +01:00
daxpedda
2ee44246ae Bump web-time to v1 (#3392) 2024-01-14 18:37:32 +01:00
Mads Marquart
14b418a3a7 macOS: Merge window and delegate state (#3391)
Previously we had a sort of artificial split between these, but both were accessing each other's state, since it's really the same state!
It was especially difficult to follow what happens to the fullscreen state.
So instead, we basically merge the window and the delegate files.

This does unfortunately screw a bit with the git history, apologies to whoever reads this in the future!
2024-01-14 05:19:23 +01:00
Mads Marquart
c86b0daf7f macOS: Remove unnecessary Mutex in window state (#3390) 2024-01-14 04:44:10 +01:00
Mads Marquart
40b61d2d92 macOS: Remove global HANDLER and AppState (#3389) 2024-01-14 03:37:53 +01:00
Mads Marquart
22311802b5 Remove generic parameter T from EventLoopWindowTarget (#3298) 2024-01-13 21:36:53 +01:00
daxpedda
169cd39f93 Web: improve custom cursor handling and add animated cursors (#3384) 2024-01-12 11:51:19 +01:00
Alexander Medvedev
bdeb2574dc Update Redox (#3368) 2024-01-10 20:05:52 +01:00
daxpedda
4fe38d8067 Web: increase cursor position accuracy (#3380) 2024-01-10 13:38:32 +01:00
daxpedda
816798bfd1 Web: support Firefox privacy.resistFingerprinting (#3371) 2024-01-06 23:05:51 +01:00
daxpedda
f99c810bec ci: Fix dead code error on nightly
See https://github.com/rust-lang/rust/pull/118297
2024-01-06 07:54:29 -08:00
daxpedda
d39528aa69 Web: account for canvas being focused already (#3369) 2024-01-06 16:14:27 +01:00
daxpedda
787b2d7362 Windows: cache custom cursors (#3293) 2024-01-05 17:02:08 +01:00
daxpedda
37b6243289 Deploy master docs to GitHub Pages (#3359) 2024-01-05 15:05:12 +01:00
Kirill Chibisov
8ea1da7879 Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2024-01-05 15:18:55 +04:00
Emil Ernerfeldt
b1209bc253 On macOS, reported shifted key with shift+Ctrl/Cmd
Fixes #3078.
2024-01-05 14:53:47 +04:00
Kirill Chibisov
021fd23c34 On X11, fix error propagation in EventLoop::new
Fixes #3350.
2024-01-05 08:33:23 +04:00
nerditation
dd127463c5 Windows: Make EventLoopWindowTarget independent of UserEvent type (#3061)
* make `EventLoopWindowTarget` independent of UserEvent type

the `EventLoopWindowTarget` is needed for window creation. conceptually,
only `EventLoop` and `EventLoopProxy` need to be parameterized, and all
other parts of the backend should be agnostic about the user event type,
parallel to how `Event<T>` is parameterized, but `WindowEvent` is not.

this change removes the dependency on the type of user events from the
`EventLoopWindowTarget` for the Windows backend, but keep a phantom data
to keep the API intact. to achieve this, I moved the `Receiver` end of
the mpsc channel from `ThreadMsgTargetData` into `EventLoop` itself, so
the `UserEvent` is only passed between `EventLoop` and `EventLoopProxy`,
all other part of the backend just use unit type as a placeholder for
user events.

it's similar to the macos backend where an erased `EventHandler` trait
object is used so all component except `EventLoop` and `EventLoopProxy`
need to be parameterized. however `EventLoop` of the Windows backend
already use an `Box<dyn FnMut>` to wrap the user provided event handler
callback, so no need for an dedicated trait object, I just modified the
wrapper to replace the placeholder user event with real value pulled
from the channel. I find this is the approach which need minimum change
to be made to existing code. but it does the job and could serve as a
starting point to future Windows backend re-works.

* fix CI clippy failure.

* make UserEventPlaceholder a new type instead of alias

* invariance is maintained by top-level EventLoopWindowTarget<T>

this field is transitional and her to keep API compatibility only.
the correct variance and such is already ensured by the top-level
`EventLoopWindowTarget`, just use `PhantomData<T>` here.
2024-01-04 16:47:07 +01:00
daxpedda
ac247cd081 Fix missing target in docs.rs test (#3358) 2024-01-04 14:40:06 +01:00
daxpedda
ea1bfd254d Add Wasm atomic target to CI (#3357) 2024-01-04 14:21:19 +01:00
daxpedda
178f5fda05 Test all docs.rs deployments (#3356) 2024-01-04 13:59:31 +01:00
Mads Marquart
42dbc4748e Display all platform-specific documentation on docs.rs (#3076) 2024-01-04 12:54:35 +01:00
Kirill Chibisov
8b3de7cedf Issue resize due to scale change on Wayland
This is a regression from 8f6de4ef.

Links: https://github.com/alacritty/alacritty/issues/7559
2024-01-03 21:49:11 +04:00
Kirill Chibisov
8b0ffb7e7d On X11 and Wayland, fix numpad up being ArrowLeft
Links: https://github.com/alacritty/alacritty/issues/7533
2024-01-02 23:55:51 +04:00
Kirill Chibisov
c55a2c779b Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2023-12-31 20:25:19 +04:00
Kirill Chibisov
c5a422eed6 On X11, fix IME input lagging behind
IME events and requests where drained on one-by-one basis, however
we should drain all of them at once and send to user.

Links: https://github.com/alacritty/alacritty/issues/7514
2023-12-31 07:43:02 +04:00
John Nunley
1893b0ec42 On X11, cache the XRandR extension version 2023-12-30 10:04:27 +04:00
Kirill Chibisov
5e106b4dbb On X11, fix ModifiersChanged from xdotool
xdotool will update modifiers before Xkb will actually send event
updating them, thus the modifiers will be updating even before the
actual update, which is unfortunate.

Links: https://github.com/alacritty/alacritty/issues/7502
2023-12-30 09:05:03 +04:00
Kirill Chibisov
5a1d3e4656 On X11, update keymap on XkbMapNotify
This is required to handle xmodmap.

Fixes #3338.
2023-12-30 01:10:38 +04:00
Kirill Chibisov
8f6de4ef4b On Wayland, fix Window::request_inner_size during resize
The user may change the size during the on-going resize, meaning that
the size will desync with winit's internal loop which breaks viewporter
setup with fractional scaling.

Links: https://github.com/alacritty/alacritty/issues/7474
2023-12-29 21:28:06 +04:00
John Nunley
ad1843aea6 On X11, query for higher Xrandr version
This appears to be the solution for the elusive #3335 issue. Previously,
in the Xlib backend, we used the "XRRQueryVersion" function to query for
the Xrandr version, and used that to determine whether we should use the
"GetScreenResources" call or the "GetScreenResourcesCurrent" call.

However, we passed the version "0, 0" into "XRRQueryVersion".
Previously with Xlib this wasn't a problem, as Xlib ignores the version
you pass in and substitutes it with the version of RandR it expects.

https://gitlab.freedesktop.org/xorg/lib/libxrandr/-/blob/master/src/Xrandr.c?ref_type=heads#L386-387

The way that "XRRQueryVersion" is implemented on the server end, it
compares the version passed into the request with the version supported
by the server. If the server's version is greater than the client
version, it just returns the client version. If the client's version is
greater, it passes the server's version. Since we were passing in "0, 0"
this means that the server returned "0, 0".

https://gitlab.freedesktop.org/xorg/xserver/-/blob/master/randr/rrdispatch.c?ref_type=heads#L50-59

To determine whether we use "GetScreenResources" or
"GetScreenResourcesCurrent", we compare the version returned by the
server against "1, 3". Since we got "0, 0"- a version of XRandR so old
it doesn't even exist- we use "GetScreenResources".

The problem manifests in that "GetScreenResources" can take several
seconds to query the screen state based on the current hardware
configuration. On the other hand, "GetScreenResourcesCurrent" is fast;
it uses the server's hardware cache if it is available.

This problem is visible in XTrace. On the latest `master`:

```
000:<:00c2: 12: RANDR-Request(140,0): QueryVersion major-version=0 minor-version=0
000:>:00c2:32: Reply to QueryVersion: major-version=0 minor-version=0
000:<:00c3:  8: RANDR-Request(140,8): GetScreenResources window=0x0000076e
000:>:00c3:1600: Reply to GetScreenResources:
```

On the `v0.28.0` tag:

```
000:<:0019: 12: RANDR-Request(140,0): QueryVersion major-version=1 minor-version=6
000:>:0019:32: Reply to QueryVersion: major-version=1 minor-version=6
...later
000:<:002d:  8: RANDR-Request(140,25): GetScreenResourcesCurrent window=0x0000076e
000:>:002d:1600: Reply to GetScreenResourcesCurrent
```

This commit fixes this issue by requesting "1, 3" instead. This returns
the version we expect, where we can now use "GetScreenResourcesCurrent"
properly.

Fixes #3335

Signed-off-by: John Nunley <dev@notgull.net>
2023-12-29 20:13:06 +04:00
Kirill Chibisov
ca1674519a Bump version on master (#3332)
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2023-12-27 10:30:59 +04:00
John Nunley
f78edc7ef1 bugfix: Change value sent to X server during minimize
Closes #3327

Signed-off-by: John Nunley <dev@notgull.net>
2023-12-26 21:25:27 -08:00
daxpedda
4f295e0c94 Add deprecated Window::set_cursor_icon() (#3329) 2023-12-26 22:40:43 +01:00
daxpedda
658f49b014 Rename VideoMode to VideoModeHandle (#3328) 2023-12-26 22:12:33 +01:00
daxpedda
34e42ff94d Remove unsound SendSyncWrapper (#3303) 2023-12-26 20:13:02 +01:00
daxpedda
ba654bb61e Add WindowBuilder::with_cursor() (#3319) 2023-12-26 19:50:58 +01:00
daxpedda
f5c691467b MacOS: check if cursor changed before applying (#3324) 2023-12-26 19:26:50 +01:00
John Nunley
a87cfb62c3 bugfix: Reload Xft database on DPI change
Closes #1228
2023-12-25 21:25:55 -08:00
daxpedda
25d6a1d46d Web: improve custom cursor loading (#3321) 2023-12-26 03:49:20 +01:00
daxpedda
e0fea25b06 Make canvas in WindowBuilder safe (#3320) 2023-12-26 01:22:10 +01:00
daxpedda
843d7904d6 On Web, add Window::(set_)prevent_default() (#3307) 2023-12-25 09:37:35 +01:00
daxpedda
28a811bbba Remove extern crate statements (#3310) 2023-12-25 09:25:09 +01:00
daxpedda
61a873d79a Remove wrong documentation on EventLoop::run() (#3314) 2023-12-25 08:27:34 +01:00
daxpedda
be4a660011 Merge Window::set_cursor_icon() and Window::set_custom_cursor() (#3308) 2023-12-25 07:20:52 +01:00
daxpedda
34dd2cdba9 Doc fixes (#3312) 2023-12-25 00:54:01 +01:00
Kirill Chibisov
775c8ece70 Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2023-12-25 00:30:59 +04:00
Uli Schlachter
c12c7b82e8 On X11, simplify available_monitors() impl
This code confused me. I tried to understand it. I tried to simplify it
while keeping the functional style. But in the end, this just seems too
complicated for its own good. Just doing the exact same thing with a
match statement and the question mark operator makes it sooo much more
obvious what is happening.

Signed-off-by: Uli Schlachter <psychon@znc.in>
2023-12-24 22:27:02 +04:00
Kirill Chibisov
8cc5cb9d9b Fix run_on_demand exiting on consequent call
Fixes #3284.
2023-12-24 22:21:45 +04:00
Kirill Chibisov
9a28bb4b49 On Wayland, fix WindowEvent::Destroyed delivery 2023-12-24 22:21:45 +04:00
Mads Marquart
4f6fd44c6c macOS: Clean up coordinate system calculations (#3302)
* Clean up macOS and iOS monitor code a bit

* Clean up window size methods

Use `setContentSize`, `setContentMinSize`, `setContentMaxSize` and `contentRectForFrameRect` to let the windowing system figure out the required scaling, instead of us doing it manually.

* Use a flipped NSView coordinate system

* Clean up window position methods
2023-12-24 10:12:09 +01:00
Alex Butler
5a43ea8cd6 bugfix(rwh): Bump rwh_05 min version to 0.5.2
Correct min version to support "std" feature
2023-12-23 22:37:35 -08:00
Mads Marquart
e9a25a4c91 Replace remaining AppKit bindings with icrate's (#3296)
* Use icrate's window structs and enums

* Properly implement protocols

* Use icrate's NSWindow

We were previously using undocumented methods on `NSWindowTabGroup`

* Use icrate's NSApplication

And clean up some doc comments regarding NSApplication
2023-12-23 23:07:55 +01:00
Mads Marquart
674657efb6 Partially replace custom AppKit bindings with icrate's autogenerated bindings (#2982)
* Refactor winit-specific cursor logic out of appkit module

* Add relevant AppKit features that we depend on

* Use icrate's NSImageRep and NSBitmapImageRep

* Use icrate's NSImage

* Use icrate's NSCursor

* Use icrate's NSAppearance

* Use icrate's NSScreen

* Use icrate's NSButton

* Use icrate's NSAppKitVersionNumber

* Use icrate's NSTextInputContext

* Use icrate's NSColor

* Use icrate's NSEvent

* Use icrate's NSMenu and NSMenuItem

* Use icrate's NSPasteboard

* Use icrate's NSResponder

* Use icrate's NSTextInputClient

* Use icrate's NSView
2023-12-23 20:58:38 +01:00
Mads Marquart
7d5bee767c Update objc2 and icrate versions (#3256) 2023-12-23 18:04:24 +01:00
Markus Siglreithmaier
745cfaab2c On Windows, remove internal WindowWrapper (#3294)
HWND in windows-sys doesn't require a newtype wrapper for Send/Sync.
2023-12-23 17:06:43 +01:00
daxpedda
a8f49dc8ef MacOS: cache custom cursors (#3291) 2023-12-23 16:34:32 +01:00
daxpedda
e5310ade08 Custom cursor improvements (#3292) 2023-12-23 16:12:29 +01:00
daxpedda
37946e0a3a Use std::cell::OnceCell (#3290) 2023-12-22 23:49:25 +01:00
daxpedda
86b737f5e7 Fix changelog (#3289) 2023-12-22 23:36:58 +01:00
daxpedda
e37585e5bc Bump MSRV to 1.70 (#3287) 2023-12-22 23:27:36 +01:00
Mads Marquart
4aeeb24745 Window handle: Return an error when not on main thread on macOS and iOS (#3288) 2023-12-22 23:18:35 +01:00
daxpedda
8cd3aaa8a2 On Web, use the new WebCanvasWindowHandle (#3270) 2023-12-22 22:33:50 +01:00
daxpedda
2c15de7cf9 Allow custom cursor caching (#3276) 2023-12-22 22:20:41 +01:00
daxpedda
0a7ea61834 Fix some doc nits (#3274) 2023-12-22 21:46:00 +01:00
Markus Siglreithmaier
4ee11018c2 On Windows, refactor dynamic function definitions and raw input keyboard handling (#3286) 2023-12-22 18:42:17 +01:00
daxpedda
4f669ebbd2 On Web, fix context menu not being disabled (#3282) 2023-12-22 00:11:36 +01:00
Kirill Chibisov
7761b2b16c Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2023-12-22 00:55:52 +04:00
daxpedda
ae41e3265f On Web, correctly mark breaking changes in the changelog 2023-12-22 00:39:06 +04:00
wjian23
8702a09333 On Windows, fix IME area not working 2023-12-21 23:44:30 +04:00
Kirill Chibisov
8b5c84f404 On Wayland, ensure initial resize delivery
While we correctly configure the sizes, we also need to actually resize
the frame on initial configure and send geometry.

Fixes #3277.
2023-12-21 22:29:36 +04:00
Kirill Chibisov
a676d0018b On windows, remove empty file 2023-12-20 19:12:44 +04:00
Kirill Chibisov
04ca85a909 On Wayland, fix resize being sent on focus change
Fixes #3263.
2023-12-20 18:48:50 +04:00
daxpedda
cc33212479 On Web, fix setting cursor icon overriding cursor visibility (#3269) 2023-12-17 18:49:45 +01:00
daxpedda
f2c5127f27 Web: remove queuing fullscreen request (#3242) 2023-12-17 13:31:48 +01:00
Eero Lehtinen
af93167237 feat(all): Custom cursor images for all desktop platforms
There seems to be many PRs relating to this issue, but they don't include all
platforms and for some reason lost steam. This PR again tries to make this
feature happen, and does it for all desktop platforms (x11, wayland, macos,
windows, web).

I think the best user of this feature and the reason I'm doing this is Bevy and
game engines in general. There non laggy hardware cursors with custom images are
very important. Game devs also like their PNGs so supporting platform native
cursor files is not that important, but I guess could be added too.

Co-authored-by: daxpedda <daxpedda@gmail.com>
Co-authored-by: Mads Marquart <mads@marquart.dk>
Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
2023-12-16 12:02:17 -08:00
Amr Bashir
7f6b16a6af On Windows, fix set_fullscreen early return for Fullscreen::Borderless(None) 2023-12-16 20:34:18 +04:00
Friz64
bf5806a9b2 Update sctk-adwaita to 0.8 2023-12-16 20:16:39 +04:00
Héctor Ramón
2a9c593e01 Fix typo in get_xft_dpi 2023-12-15 16:12:50 +04:00
Marijn Suijten
becdd0dbd2 On Wayland, make wl_subcompositor protocol optional
This protocol is only used for (optional) Client Side Decorations
(where) the compositor still takes the burden of compositing various
window parts together, via subsurfaces that all belong to a single
window.

If this core protocol is not available, as is the case on gamescope,
disable CSD.
2023-12-14 21:04:15 +04:00
Uli Schlachter
3eea505440 m: Update to x11rb 0.13.0
The only breaking change is that x11rb no longer reports an error when
querying the WmSizeHints of a window that does not have this property
set. For this reason, the return type of WmSizeHintsCookie::Reply()
changed from Result<WmSizeHints, SomeError> to
Result<Option<WmSizeHints>, SomeError>.

In update_normal_hints(), previously a cryptic error would be reported
to the caller. Instead, this now uses unwrap_or_default() to get a
WmSizeHints. All fields of WmSizeHints are Options, so this produces an
empty object.

resize_increments() queries a value from the window and returns an
Option. Previously, the error for "missing property" was turned into
None via .ok(). This commit adds a call to flatten() to also turn
"property not set" into None.

Finally, request_user_attention() queries a window's WmHints property
and updates one field of it. The code already uses unwrap_or_default()
to deal with missing properties, so just a call to flatten() is needed
to merge "missing property" and "error while querying" into one.

Other changes in x11rb do not seem to affect this crate.

x11rb's MSRV increased from 1.56 to 1.63, which is still below the MSRV
of this crate, which is 1.65.

Signed-off-by: Uli Schlachter <psychon@znc.in>
2023-12-09 07:02:30 -08:00
Fredrik Fornwall
b863283c38 On Windows, avoid panic in video_modes() 2023-12-06 20:47:33 +04:00
Leon
73718c9f2f Changes and improvements to the documentation (#3253)
* FEATURES.md improvements

* docs improvements

* typo fix: 'mean' -> 'main'

Co-authored-by: daxpedda <daxpedda@gmail.com>

---------

Co-authored-by: daxpedda <daxpedda@gmail.com>
2023-12-03 18:39:08 +01:00
Xiaopeng Li
f735f028a1 fix refresh_rate_millihertz on macOS (#3254)
* fix refresh_rate_millihertz on macOS

* round after conversion to mHz

* add changelog entry
2023-12-01 15:52:16 +01:00
John Nunley
da947992ac bugfix(x11): Use the right atom type in focus_window()
Closes #3248 by removing an Xlibism I forgot about

Signed-off-by: John Nunley <dev@notgull.net>
2023-11-28 16:20:36 -08:00
John Nunley
e9784127df bugfix(x11): Properly interpret float data in drag ops
Closes #3245

notgull forgot to properly interpret float data from the X server,
making him tonight's biggest loser.

Signed-off-by: John Nunley <dev@notgull.net>
2023-11-28 15:08:14 -08:00
Mads Marquart
0be2bb0a8c Remove unused .gitmodules 2023-11-29 00:56:11 +04:00
OG
075996b1fa feat: macos services menu added (#3231) 2023-11-28 21:39:12 +01:00
Emil Ernerfeldt
a7241b3db3 On macOS, remove spurious error logging when handling Fn
Fixes #3246.
2023-11-28 23:19:16 +04:00
Kirill Chibisov
17296e9878 Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2023-11-24 18:32:53 +04:00
John Nunley
b3c87caa7c On X11, reload DPI on PropertyChange
Signed-off-by: John Nunley <dev@notgull.net>
Fixes #1228.
2023-11-24 12:14:06 +04:00
Kirill Chibisov
81a1d9c396 Fix infinite recursion in BadIcon reporting (#3237) 2023-11-23 19:15:17 +01:00
Mads Marquart
5612626944 Make Android docs build on docs.rs (#3236) 2023-11-23 08:18:05 +01:00
Arend van Beelen jr
d3ca685b77 Fix crash when running iPad build on macOS 2023-11-22 16:14:51 +04:00
Kirill Chibisov
7bed5eecfd On macOS, fix assertion when pressing Fn key 2023-11-17 15:56:03 +04:00
Kirill Chibisov
14140607d1 On Wayland, fix wl_surface being dropped first
The surface was automatically dropped due to new RAII type in SCTK
when dropping the Window, which was not the case at some point with
SCTK.

Thus destroying objects associated with it where causing issues
with some window managers.

Links: https://github.com/neovide/neovide/issues/2109
2023-11-11 20:35:30 +04:00
daxpedda
eab982c402 Web: forbid additional functions in favor of caching them (#3219) 2023-11-10 22:46:51 +01:00
Olivier Goffart
21701a33de On Windows, fix set_control_flow from `AboutToWait
In case the AboutToWait event sets the control flow to another value
it's not being used on this iteration.

Fixes #3215.
2023-11-08 19:21:33 +04:00
Nathan Lilienthal
c89e6df758 On macOS, send a Resized event after ScaleFactorChanged
Fixes #3213.
2023-11-07 02:26:02 +04:00
Kirill Chibisov
e9210555c1 On X11, try alternative cursor icon names as well
This should cover more icons.
2023-11-04 15:19:15 +04:00
Marijn Suijten
0994b5ceb8 Disable default-features for the ndk crate
We decided to add `rwh_06` to the `default` list of features in the
`ndk` to [nudge users to upgrade], but this forces `winit` to always
(transitively) include `raw-window-handle 0.6` even if the user has
set a different `rwh_xx` feature on the `winit` crate.  `winit` already
forwards the respective `rwh_xx` feaure to the `ndk` crate anyway, so
this default should just be turned off.

At the time of writing this is the only `default` feature of the `ndk`.

Links: https://github.com/rust-mobile/ndk/pull/434#issuecomment-1752089087
2023-11-04 15:18:55 +04:00
DevJac
bcce5134e1 Fix typo in pre_present_notify docs
Fix typo and other small grammar corrections.
2023-11-02 01:07:35 +04:00
Linda_pp
d333dd8664 Fix crash when minimizing example on Windows 2023-10-31 19:21:36 +04:00
Jasper Bekkers
52af1b4a77 On Windows, fix MT safety when starting drag 2023-10-31 19:20:34 +04:00
Kirill Chibisov
3c9f9da19e Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2023-10-28 21:09:28 +04:00
Kirill Chibisov
075dfcea19 Clarify scale_factor docs
Wayland scales each window individually, thus make it clear. Also
recommend against using the `MonitorHandle::scale_factor`.

Fixes #3183.
2023-10-28 14:23:20 +04:00
Kirill Chibisov
92b7dcccc1 On macOS, add support for Window::set_blur 2023-10-28 14:22:10 +04:00
Kirill Chibisov
5a3be586f4 On Windows, add support for Window::set_transparent 2023-10-28 02:22:45 +04:00
Kirill Chibisov
12dbbf8012 On Wayland, improve initial user size handling
Keep the user provided size in the original values and convert only
when we're getting a `configure` event. On some compositors will
have a scale available, so it'll work, however with some we'll
still have old 'pick 1` as default.

Also configure_bounds when compositor tells the user to pick the size,
that will ensure that initial `with_inner_size` won't grow beyond the
working area.

Fixes #3187.
2023-10-27 00:56:23 +04:00
Kirill Chibisov
53ca5af48f On Wayland, fix RedrawRequsted loop
The `dirty` is never cleared when decorations are hidden without
`sctk-adwaita`.

Fixes #3177.
2023-10-25 20:59:39 +04:00
Marijn Suijten
c235bd154a On wasm, provide intradoc-link for spawn() function in EventLoop docs (#3178) 2023-10-25 17:42:51 +02:00
J-P Nurmi
f4e71a1d9c On macOS, fix deadlock during nested event loops (e.g. rfd) 2023-10-25 19:13:44 +04:00
Kirill Chibisov
62ed51a138 On Winows, Fix deedlock with WM_MOUSEMOVE
The lock was still present in `None` path.

Fixes: d37d1a03b(On Windows, fix deadlock during `Cursor{Enter,Leave}`)
2023-10-25 18:32:16 +04:00
Kirill Chibisov
b2a2ec91ae Fix unused import warnings on nightly 2023-10-25 15:58:31 +04:00
Kirill Chibisov
d37d1a03b2 On Windows, fix deadlock during Cursor{Enter,Leave}
The lock was not released when calling back to the user.

Fixes #3171.
2023-10-22 19:38:54 +04:00
Kirill Chibisov
772b21ce09 Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2023-10-21 11:58:17 +04:00
Kirill Chibisov
2edcd09704 On X11, fix cursor_hittest not reloaded on Resize
The cursor hittest was not reloaded on window size changes, only
when `Window::request_inner_size` was called leading to regions
of the window being not clickable.

Also, don't try to apply hittest logic when user never requested a
hittest.

Links: https://github.com/alacritty/alacritty/pull/7220
2023-10-21 11:09:53 +04:00
Diggory Hardy
d35c3bea42 Fix rwhd_05 doc links 2023-10-21 08:13:58 +04:00
Valaphee The Meerkat
89a184ed84 feat(windows): Fix inconsistency in mouse button device events, add hwheel device event on Windows
While working with device events, I noticed that there was an inconsistency in the mouse button device events between Windows/X11 and for example web, because web uses the same ids/order as the MouseButton enum, and Windows/X11 are using the X11 ids, and hwheel device event was ignored on Windows.

Mouse button device events are now using the same order as the MouseButton enum, and I also added hwheel device events for Windows.
2023-10-20 10:03:05 -07:00
Kirill Chibisov
36d4907da8 On Windows, fix IME APIs MT-safety
Execute the calls to the IME from the main thread.

Fixes #3123.
2023-10-20 15:46:57 +04:00
Kirill Chibisov
98b3508aca On Windows, fix RedrawRequested delivery
When calling `Window::request_redraw` from the `RedrawRequested`
handler the `RedrawWindow` won't result in `WM_PAINT` being delivered
due since user callback is run before `DefWindowProcW` is called.

Track whether the user called `Window::request_redraw` and ask for
`RedrawWindow` after running the said function during `WM_PAINT`
handling.

Fixes #3150.
2023-10-20 14:52:01 +04:00
Diggory Hardy
c0db53a516 Implement Ord/PartialOrd for ModifiersState 2023-10-20 14:51:42 +04:00
Xiaopeng Li
52b7205b75 On Windows, fix invalid hmonitor panic
Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
2023-10-20 14:51:04 +04:00
Arend van Beelen jr
41dbbc27a0 On iOS, add configuration for status bar style
Co-authored-by: Mads Marquart <mads@marquart.dk>
2023-10-20 14:26:10 +04:00
Kirill Chibisov
c346fb7e61 On macOS, fix tabGroup misuse
The property is marked as `Weak`, however we used strong `Id`.

Links: https://github.com/alacritty/alacritty/issues/7249
2023-10-20 14:05:57 +04:00
Kirill Chibisov
6a041f84ba Remove garbage from README
The docs are in the src/lib.rs anyway and are present on docs.rs.
2023-10-19 19:25:30 +04:00
Diggory Hardy
acfeff5327 Revise Key and KeyCode enums
Split `Key` into clear categories, like `Named`, `Dead`, Character`, `Unidentified`
removing the `#[non_exhaustive]` from the `Key` itself.

Similar action was done for the `KeyCode`.

Fixes: #2995
Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
2023-10-19 18:27:49 +04:00
Kirill Chibisov
b9e1e96eaa Ensure that DISPLAY vars are non-empty before using
It's common to disable Wayland by `WAYLAND_DISPLAY= <application>`.
2023-10-19 17:03:15 +04:00
Kirill Chibisov
880238a24f Fix examples not render on Wayland
The `rwh_05` feature was not enabled.

Fixes: e41fac825c (Update to new raw-window-handle strategy)
2023-10-17 07:53:38 +04:00
YouKnow
f5b4d6938f On Windows, fix CursorEntered/CursorLeft not sent during mouse grab
Fixes #3153.
2023-10-17 07:23:22 +04:00
Kirill Chibisov
c65e2247a1 On macOS, fix globe key triggering assertion
Sometimes FlagsChanged events don't carry any KeyCode information, thus
we can't create a synthetic presses events for them.

However in such cases, modifiers information is still accurate, thus
propagate it.

Fixes #2872.
2023-10-17 05:59:48 +04:00
Kirill Chibisov
801fddbfcf Make WindowBuilder Send + Sync
Window builder is always accessed by winit on the thread event loop
is on, thus it's safe to mark the data it gets as `Send + Sync`.
Each unsafe object is marked individually as `Send + Sync` instead
of just implementing `Send` and `Sync` for the whole builder.
2023-10-17 04:54:12 +04:00
Kirill Chibisov
3ad64fb811 Remove resolved deny.toml entries 2023-10-17 04:35:14 +04:00
Marijn Suijten
9bf4493a21 Upgrade to ndk 0.8, ndk-sys 0.5 + android-activity 0.5 releases
Fixes #2905.
Co-authored-by: Robert Bragg <robert@sixbynine.org>
2023-10-17 04:08:33 +04:00
daxpedda
48f6582eb4 Web Async Rework (#3082) 2023-10-16 15:50:22 +02:00
Kirill Chibisov
ef34692148 Add a note on Window::request_redraw on Windows
Fixing this could require a massive rework to how redraw is handled
on windows to the point of removing `WM_PAINT`, since it's not reliable
by any means for our use case.

For now at least document that the API is broken. It was broken like
that for a long while.
2023-10-15 23:48:37 +04:00
Kirill Chibisov
c48116a8fd Implement AsFd/AsRawFd for EventLoop<T>
This should help other crates to integrate winit's event loop into
their bigger event loop without adding an extra thread.
2023-10-15 20:31:29 +04:00
John Nunley
b938fe9df5 Fix potentially unaligned references in X11 device
Fixes #3125
Signed-off-by: John Nunley <dev@notgull.net>
2023-10-15 07:09:10 +04:00
Kirill Chibisov
b7e3649e8b Update SCTK to 0.18.0
The update is pretty minor, however we support now
`WindowEvent::Occluded` when xdg-shell v6 is available.

It also adds support for `Window::show_window_menu`.

Fixes #2927.
2023-10-15 06:49:57 +04:00
Kirill Chibisov
844269d017 Fix ndk deps versions 2023-10-15 06:39:18 +04:00
John Nunley
e41fac825c Update to new raw-window-handle strategy
Signed-off-by: John Nunley <dev@notgull.net>
Co-authored-by: TornaxO7 <tornax@proton.me>
2023-10-15 06:07:39 +04:00
Ryan Hileman
bbeacc46d5 feat: Implement set_cursor_hittest for X11 2023-10-13 20:42:07 -07:00
Kirill Chibisov
61581ebb4f Fix CHANGELOG entry for Event::MemoryWarning
While the changelog entries for beta releases doesn't really matter. The
change wasn't marked as breaking, while it is.

Fixes: 93f1000a0 (Add Occluded and MemoryWarning events for iOS/Android)
2023-10-13 02:02:00 +04:00
François
93f1000a05 Add Occluded and MemoryWarning events for iOS/Android
Hook `Occluded` event to foreground/background evens on iOS.

This commit also enabled the `MemoryWarning` event, since it's
emitted from the windowing system.

Co-authored-by: Dusty DeWeese <dustin.deweese@gmail.com>
Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
2023-10-13 00:42:09 +04:00
YouKnow
1ea41a2ee2 Add Window::show_window_menu
Add a method to request a system menu. The implementation
is provided only on Windows for now.

Co-authored-by: daxpedda <daxpedda@gmail.com>
Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
2023-10-11 01:46:16 +04:00
daxpedda
42c9b7e40e Fix reset to Poll after the event loop starts 2023-10-11 00:46:08 +04:00
baneyue
0960635895 On Wayland, fix MonitorHandle position 2023-10-11 00:44:52 +04:00
Kirill Chibisov
789a497980 Remove obsolete docs about wayland CSD env variable
The env variable was removed a while ago, yet it was still present in
the user docs.
2023-10-10 09:23:37 +04:00
daxpedda
fac6110cb6 Web: fix ControlFlow::WaitUntil to never wake up **before** the given time (#3133) 2023-10-09 12:31:02 +02:00
Dmitry Sharshakov
0363be4776 Add Window::set_blur
Allow clients to request blur behind their window, implemented on
Wayland for now.
2023-10-08 23:53:15 +04:00
daxpedda
f5dd1c008c Web: remove unnecessary usage of once_cell::unsync::Lazy (#3134) 2023-10-08 02:00:51 +02:00
daxpedda
48a1e84906 Update Clippy to v1.73 (#3135) 2023-10-08 01:21:46 +02:00
epimeletes
ee0db52ac4 Rename run_ondemand to run_on_demand 2023-10-04 01:24:42 +04:00
Fredrik Fornwall
c7cf0cfd83 Make DeviceId contain device id's on Android 2023-10-04 01:23:18 +04:00
Mads Marquart
8393d98940 Link to areweguiyet.com and arewegameyet.rs for extra deps 2023-10-04 01:22:14 +04:00
Mads Marquart
af247eac0f X11: Add #[deny(unsafe_op_in_unsafe_fn)] (#3121)
* X11: Add #[deny(unsafe_op_in_unsafe_fn)]

* Enable #![deny(unsafe_op_in_unsafe_fn)] everywhere
2023-09-30 21:43:41 +02:00
Mads Marquart
b2b4564a5f Windows: Add #[deny(unsafe_op_in_unsafe_fn)] (#3070) 2023-09-29 16:07:44 +02:00
Mads Marquart
cb58c49a90 Bump version on master (#3119)
This commit does not represent a release and only synchronizes CHANGELOG from the latest release.
2023-09-28 01:03:38 +02:00
Neil Macneale V
ffb46dd61f Fix transparent windows on X11 2023-09-26 01:05:15 +04:00
Kirill Chibisov
8c8fb39fcd Remove DeviceEvent::Text event
The event is never constructed inside the winit.
2023-09-23 18:40:23 +04:00
lucasmerlin
2422ea39d0 Pass force on touch events on android 2023-09-22 23:44:39 +04:00
daxpedda
878d832d24 Make ControlFlow::Wait the default (#3106) 2023-09-22 21:27:11 +02:00
Kirill Chibisov
e2e01e1fc6 Remove old docs about EventLoop::run 2023-09-22 13:46:52 +04:00
Pavel Strakhov
c8b685ddbc On X11, fix WaitUntil and Poll behavior
Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
2023-09-20 15:15:28 +04:00
StarStarJ
f10ae52385 Implement PartialOrd and Ord for MouseButton 2023-09-17 13:51:03 +04:00
Kirill Chibisov
e731041c15 Correct Wayland section in dpi docs
Fixes #3100.
2023-09-16 18:14:46 +04:00
daxpedda
9df7fc47a1 Install cargo-apk with the stable toolchain 2023-09-16 16:17:53 +04:00
daxpedda
992aeb0ca0 Ignore foreign-types* duplicate deps on macOS
The dependency is duplicated due to examples, yet we still need to
exclude checking it.

Fixes #3093.
2023-09-16 14:54:49 +04:00
daxpedda
0caba93b51 Rename PollType to PollStrategy (#3089) 2023-09-08 18:39:23 +02:00
John Nunley
c00c1e9eb7 Add an MSRV policy to the README (#3046) 2023-09-08 17:34:55 +02:00
daxpedda
83950acd5a Add Window.requestIdleCallback() support (#3084) 2023-09-07 12:12:35 +02:00
Fredrik Fornwall
b99403b1b9 Correct set_exit() -> exit() in the changelog (#3088) 2023-09-07 11:52:53 +02:00
John Nunley
4f0ce7201d Revert select_xkb_events to its previous impl
The new implementation of select_xkb_events apparently misconfigures
the server. This commit does a temporary fix by just reverting it to its
previous implementation.

This is temporary until I can figure out what Xlib is doing behind the
scenes or until I read xkbproto.pdf.

Fixes: #3079
Signed-off-by: John Nunley <dev@notgull.net>
2023-09-07 10:25:52 +04:00
daxpedda
e648169861 Move ControlFlow to EventLoopWindowTarget
Fixes #3042.
2023-09-07 10:25:04 +04:00
John Nunley
8fdd81ecef Allow the user to force X11 under Wayland
Use forced backend over the env variables. 

Signed-off-by: John Nunley <dev@notgull.net>
Fixes: #3057
2023-09-04 01:24:05 +04:00
daxpedda
7a2a2341c2 Remove T from EventLoopTargetWindow (#3081)
Co-authored-by: nerditation <12248559+nerditation@users.noreply.github.com>
2023-09-03 02:26:53 +02:00
Kirill Chibisov
d68d9eab38 Mark startup_notify unsafe functions as safe
They are safe, since they use the rust `std::env` stuff. Making them
safe lets downstream to determine that `std::env` is used and not the
`libc` env manipulation routines, which are unsafe.
2023-09-02 02:05:56 +04:00
Mads Marquart
a06ea45c0f Slightly reduce number of cfgs (#3071)
* Make Linux platforms less dependent on the root monitor handle

* Add various functions to the Wayland platform to reduce cfgs

* Don't use a cfg in listen_device_events

* Don't use a cfg in set_content_protected

* Fix instance of a target_os cfg
2023-09-01 23:14:16 +02:00
Kirill Chibisov
67b041e231 On Wayland, fix TouchPhase::Canceled sent for Move
Fixes #3035.
2023-09-01 02:14:34 +04:00
Mads Marquart
6dfc78fb50 Make EventLoopWindowTarget independent of the user type on Orbital (#3055) 2023-08-30 16:43:28 +02:00
Mads Marquart
477619c0a7 Ensure that winit initializes NSApplication (#3069) 2023-08-30 15:19:30 +02:00
Mads Marquart
5f1a4b65ad Fix missing quote (#3068) 2023-08-30 13:59:23 +02:00
John Nunley
bb9b629bc3 Implement X11 extensions using x11rb instead of Xlib
Removes Xlib code by replacing it with the x11rb equivalent,
the commit handles xrandr, xinput, xinput2, and xkb.

Signed-off-by: John Nunley <dev@notgull.net>
2023-08-30 01:01:25 +04:00
daxpedda
0c8cf94a70 Web: Fullscreen Overhaul (#3063) 2023-08-29 09:28:30 +02:00
daxpedda
1dfca5a395 Enable event propagation (#3062) 2023-08-28 19:18:10 +02:00
Mads Marquart
7541220a41 Fix macOS deminiaturize (#3054) 2023-08-27 17:35:45 +02:00
Kirill Chibisov
7e11912d22 Lock the cargo-apk deps on CI 2023-08-27 19:05:45 +04:00
Mads Marquart
86baa1c99a Make iOS fully thread safe (#3045)
* macOS & iOS: Refactor EventWrapper

* macOS & iOS: Make EventLoopWindowTarget independent of the user event

* iOS: Use MainThreadMarker instead of marking functions unsafe

* Make iOS thread safe
2023-08-27 17:04:39 +02:00
Mads Marquart
d9f04780cc Improve CI caching, and give each job names
This improves CI performance by around 20% (down from 10 to 8 minutes).
2023-08-27 18:25:32 +04:00
daxpedda
67d3fd28f7 Move Event::RedrawRequested to WindowEvent (#3049) 2023-08-27 16:15:09 +02:00
daxpedda
a3cba838ea On Web, never return a MonitorHandle (#3051) 2023-08-26 18:56:44 +02:00
daxpedda
48abf52aac Use setTimeout() trick instead of Window.requestIdleCallback() (#3044) 2023-08-25 21:40:21 +02:00
Mads Marquart
68ef9f707e Use frame instead of visibleRect (#3043) 2023-08-24 22:52:11 +02:00
Mads Marquart
9979441c82 Fix recent CI failures (#3041)
* Fix new clippy lints

* Fix nightly documentation warnings
2023-08-24 18:29:31 +02:00
Kirill Chibisov
309e6aa85a Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.

This is a follow up to beta yanking
2023-08-16 16:34:36 +04:00
Kirill Chibisov
8b8556798e Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2023-08-16 13:21:09 +04:00
Kirill Chibisov
2d96480a89 Use beta versions of android crates 2023-08-16 12:31:23 +04:00
Kirill Chibisov
6caff77abb Bump MSRV to 1.65 2023-08-16 12:10:38 +04:00
Mads Marquart
af6c343d0e Improve macOS/iOS/Web thread safety
Co-authored-by: daxpedda <daxpedda@gmail.com>
2023-08-14 23:19:57 +04:00
Kirill Chibisov
119462795a Pin android-activity git dependency 2023-08-14 23:10:32 +04:00
Kirill Chibisov
f801c4a00b Reexport raw-window-handle in window module
We use raw-window-handle extensive in the public API as well as we
force the users to use it to get some essential data for interop, thus
reexport it.

Fixes: #2913.
2023-08-14 11:24:45 +04:00
Kirill Chibisov
f9758528f6 Propagate error from EventLoop creation
Inner panics could make it hard to trouble shoot the issues and for some
users it's not desirable.

The inner panics were left only when they are used to `assert!` during
development.

This reverts commit 9f91bc413fe20618bd7090829832bb074aab15c3 which
reverted the original patch which was merged without a proper review.

Fixes: #500.
2023-08-13 23:20:09 +04:00
lucasmerlin
778d70c001 Fix touch force for Apple Pencil 2023-08-12 16:22:22 +04:00
John Nunley
dc973883c9 Add a way to embed the X11 window into another
Signed-off-by: John Nunley <dev@notgull.net>
Tested-by: Kirill Chibisov <contact@kchibisov.com>
2023-08-11 13:30:55 +04:00
Fredrik Fornwall
2233edb9a0 iOS: Use NSOperatingSystemVersion from icrate (#3019) 2023-08-09 15:57:20 +02:00
Robert Bragg
bd2f1e8312 Android: Support unicode character mapping + dead keys
Up until now the Android backend has been directly mapping key codes
which essentially just represent the "physical" cap of the key (quoted
since this also related to virtual keyboards).

Since we didn't account for any meta keys either it meant the backend
only supported a 1:1 mapping from key codes, which only covers a tiny
subset of characters. For example you couldn't type a colon since
there's no keycode for that and we didn't try and map Shift+Semicolon
into a colon character.

This has been tricky to support because the `NativeActivity` class doesn't
have direct access to the Java `KeyEvent` object which exposes a more
convenient `getUnicodeChar` API.

It is now possible to query a `KeyCharcterMap` for the device associated
with a `KeyEvent` via the `AndroidApp::device_key_character_map` API
which provides a binding to the SDK `KeyCharacterMap` API in Java:

 https://developer.android.com/reference/android/view/KeyCharacterMap

This is effectively what `getUnicodeChar` is implemented based on and is
a bit more general purpose.

`KeyCharacterMap` lets us map a key_code + meta_state from a `KeyEvent`
into either a unicode character or dead key accent that can be combined
with the following key. This mapping is done based on the user's chosen
layout for the keyboard.

To enable support for key character maps the
`AndroidApp::input_events()` API was replaced by
`AndroidApp::input_events_iter()` which returns a (lending) iterator for
events. This was changed because the previous design made it difficult
to allow other AndroidApp APIs to be used while iterating events (mainly
because AndroidApp held a lock over the backend during iteration)
2023-08-08 02:56:42 +04:00
Kirill Chibisov
e9ebf1e5f4 Fix event loop not waking up due to repeat source
Force the wake up from the repeat source as well.

Fixes: cad327755 (On Wayland, reduce amount of spurious wakeups)
2023-08-07 09:35:59 +04:00
Kirill Chibisov
5f7955cb2b On X11, set visual_id in raw-window-handle
Fixes #2681.
2023-08-06 06:07:19 +04:00
Kirill Chibisov
793c535b01 Revert "Propagate error from EventLoop creation" (#3010)
This reverts commit ed26dd58fd.
The patched was merged with a review by accident.
2023-08-06 06:07:01 +04:00
Kirill Chibisov
ed26dd58fd Propagate error from EventLoop creation
Inner panics could make it hard to trouble shoot the issues and for some
users ints not desirable.

The inner panics were left only when they are used to `assert!` during
development.
2023-08-06 06:03:54 +04:00
John Nunley
584aab4cd0 Make with_x11_visual take ID instead of a pointer
At the moment, the with_x11_visual function takes a pointer and
immediately dereferences it to get the visual info inside. As it is safe
to pass a null pointer to this function, it is unsound. This commit
replaces the pointer parameter with a visual ID, and then uses that ID
to look up the actual visual under
the X11 setup. As this is what was already practically happening before,
this change shouldn't cause any performance downgrades.

This is a breaking change, but it's done in the name of soundness so it
should be okay. It should be trivial for end users to accommodate it,
as it's just a matter of getting the visual ID from the pointer to the
visual before passing it in.

Signed-off-by: John Nunley <dev@notgull.net>
2023-08-06 01:58:23 +04:00
Kirill Chibisov
8100a6a584 Remove 'static requirement on run
There's no need to force the static on the users, given that internally
some backends were not using static in the first place.

Co-authored-by: daxpedda <daxpedda@gmail.com>
2023-08-06 01:56:56 +04:00
Kirill Chibisov
cad3277550 On Wayland, reduce amount of spurious wakeups
Mark it as breaking, since some clients relied on that behavior, simply
because dispatching clients queue always woke up a winit, meaning that
they won't be able to use user events for this sake.
2023-08-06 01:09:59 +04:00
Mads Marquart
3c3a863cc9 Remove functionality already exposed through raw-window-handle
Nothing changed from the user point of view, other than they should
use the `raw-window-handle`, which is objectively better, given that
it reduces the amount of `cfg` guards in downstream code.
2023-08-05 22:56:22 +04:00
John Nunley
8a7e18aaf0 Increase test coverage for generic modules 2023-08-05 19:58:38 +04:00
dAxpeDDa
57fad2ce15 On Web, use requestAnimationFrame for RedrawRequested 2023-08-04 14:23:44 +04:00
Kirill Chibisov
7a58fe58ce On Wayland, use frame callbacks to throttle RedrawRequested
Throttle RedrawRequested events by the frame callbacks, so the users
could render at the display refresh rate.
2023-08-04 14:23:44 +04:00
Kirill Chibisov
38f28d5836 Add Window::on_present_notify to ack about drawing
That's a way to communicate to winit that you'll present to the window.
While it's a no-op for now, it'll be used to throttle drawing.
2023-08-04 14:23:44 +04:00
Diggory Hardy
189a0080a6 Export smol_str and impl Ord for Key
Fixes #2996.
2023-08-03 20:12:48 +04:00
Mads Marquart
b5aa96bea4 Update icrate to v0.0.4 (#2992) 2023-08-02 16:30:41 +02:00
Marijn Suijten
19e3906369 On X11, remove the now-unrefrenced events.rs source file
#2662 renamed `VirtualKeyCode` to `Key` yet references to the former
type still exist in `src/platform_impl/linux/x11/events.rs`.  As it
turns out the `mod events;` in `x11/mod.rs` was removed in the same PR,
but the file accidentally stuck around without being referenced anywhere
else.
2023-07-31 22:15:43 +04:00
Kirill Chibisov
9ac3259a79 Remove lifetime from the Event
Lifetimes don't work nicely when dealing with multithreaded environments
in the current design of the existing winit's event handling model, so
remove it in favor of `InnerSizeWriter` fences passed to client, so they
could try to update the size.

Fixes #1387.
2023-07-31 00:39:01 +04:00
Tobias Hunger
2b2dd6b65d On Windows, keep window maximized when setting size bounds (#2899) 2023-07-29 16:22:28 +02:00
Géraud-Loup
75173118b0 On Windows, add option to customize window class name (#2978) 2023-07-29 15:39:23 +02:00
Mads Marquart
e33d2bee6c Update objc2 version (#2936)
* Upgrade to objc2 v0.4.0 and icrate v0.0.3

* Fix `touchBar` method

* Use ClassType::alloc

* Use #[method_id(...)] functionality in declare_class!
2023-07-29 00:33:03 +02:00
Robert Bragg
ae7497e18f Remove RedrawEventsCleared + MainEventsCleared, and added AboutToWait
The idea that redraw events are dispatched with a specific ordering
that makes it possible to specifically report when we have finished
dispatching redraw events isn't portable and the way in which we
dispatched RedrawEventsCleared was inconsistent across backends.

More generally speaking, there is no inherent relationship between
redrawing and event loop iterations. An event loop may wake up at any
frequency depending on what sources of input events are being listened
to but redrawing is generally throttled and in some way synchronized
with the display frequency.

Similarly there's no inherent relationship between a single event loop
iteration and the dispatching of any specific kind of "main" event.

An event loop wakes up when there are events to read (e.g. input
events or responses from a display server / compositor) and goes back
to waiting when there's nothing else to read.

There isn't really a special kind of "main" event that is dispatched
in order with respect to other events.

What we can do more portably is emit an event when the event loop
is about to block and wait for new events.

In practice this is very similar to how MainEventsCleared was
implemented except it wasn't the very last event previously since
redraw events could be dispatched afterwards.

The main backend where we don't strictly know when we're going to
wait for events is Web (since the real event loop is internal to
the browser). For now we emulate AboutToWait on Web similar to how
MainEventsCleared was dispatched.

In practice most applications almost certainly shouldn't care about
AboutToWait because the frequency of event loop iterations is
essentially arbitrary and usually irrelevant.
2023-07-28 20:37:56 +04:00
Robert Bragg
935146d299 Rename LoopDestroyed to LoopExiting
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.
2023-07-28 20:19:53 +04:00
François
755c533b08 iOS: Always set timer when polling to avoid slow waking (#2979)
* Always set timer when polling to avoid slow waking

* add comment and changelog

---------

Co-authored-by: Dusty DeWeese <dustin.deweese@gmail.com>
Co-authored-by: Mads Marquart <mads@marquart.dk>
2023-07-28 17:52:24 +02:00
Robert Bragg
ae9b02e097 Add timeout argument to pump_events
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.
2023-07-28 03:04:32 +04:00
Robert Bragg
e6c7cc297d Windows: implement pump_events_with_timeout internally 2023-07-28 03:04:32 +04:00
Robert Bragg
b74cee8df1 MacOS: implement pump_events_with_timeout internally
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.
2023-07-28 03:04:32 +04:00
Robert Bragg
e5eb253698 window_ondemand: wait for Destroyed event before exiting app
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.
2023-07-28 03:04:32 +04:00
Robert Bragg
ec11b4877f Linux: Sync with server/compositor before exiting run_ondemand
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.
2023-07-28 03:04:32 +04:00
Robert Bragg
9e46dffcc5 Update CHANGELOG.md 2023-07-28 03:04:32 +04:00
Robert Bragg
7501039d57 Add examples/window_ondemand
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.
2023-07-28 03:04:32 +04:00
Robert Bragg
289ce32d77 Add examples/window_pump_events
A minimal example of an application based on an external event loop that
calls `pump_events` for each iteration of the external loop.
2023-07-28 03:04:32 +04:00
Robert Bragg
0d366ffbda Re-work event loop run() API so it can return a Result
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
2023-07-28 03:04:32 +04:00
Robert Bragg
a6f414d732 Remove EventLoopExtRunReturn 2023-07-28 03:04:32 +04:00
Robert Bragg
c47d0846fa Linux: Implement EventLoopExtPumpEvents and EventLoopExtRunOnDemand
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.
2023-07-28 03:04:32 +04:00
Robert Bragg
461efaf99f MacOS: Implement EventLoopExtPumpEvents and EventLoopExtRunOnDemand
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).
2023-07-28 03:04:32 +04:00
Robert Bragg
420840278b Windows: Implement EventLoopExtPumpEvents and EventLoopExtRunOnDemand
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`.
2023-07-28 03:04:32 +04:00
Robert Bragg
f5e73b0af4 Android: Implement EventLoopExtPumpEvents and EventLoopExtRunOnDemand 2023-07-28 03:04:32 +04:00
Robert Bragg
f40b5f0dad Add EventLoopExtPumpEvents and EventLoopExtRunOnDemand
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.
2023-07-28 03:04:32 +04:00
daxpedda
c91402efb9 Correctly detect that we don't support Emscripten (#2971) 2023-07-22 18:31:40 +02:00
John Nunley
43acf7f42f Replace libc with rustix in some modules
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.
2023-07-22 09:32:27 +00:00
Venceslas Duet
c62e64060b On Windows, add drag_resize_window method support (#2966) 2023-07-21 20:01:56 +02:00
Kirill Chibisov
f7a84a5b50 Add platform::startup_notify for Wayland/X11
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>
2023-07-20 13:16:51 +00:00
Venceslas Duet
89aa7cc06e On Wayland, fix Window::is_decorated with CSD 2023-07-18 11:57:33 +00:00
Kirill Chibisov
b166e1ff13 On Wayland, make the CSD frame double click reliable
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
2023-07-15 08:09:28 +00:00
Kirill Chibisov
97434d8d80 On macOS, add a way to query amount of tabbed windows
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)
2023-07-14 08:01:40 +00:00
Sam
06fb089633 On macOS, set that we prefer tabbing
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.
2023-07-14 04:14:04 +00:00
Kirill Chibisov
4d6dbea74c On macOS, move automatic tabbing setting to ELWT
Those are global for the application, so it's better to keep them
on EventLoopWindowTarget.
2023-07-13 15:55:51 +00:00
Kirill Chibisov
c5941d105f On macOS, add tabbing APIs
This should let the users control macOS tabbing and allow to create
windows in tab.

Co-authored-by: Amr Bashir <amr.bashir2015@gmail.com>
2023-07-13 06:52:34 +00:00
daxpedda
b63164645b On Web, add WindowBuilderExtWebSys::with_append() (#2953) 2023-07-12 17:11:52 +02:00
daxpedda
5b5ebc25d8 Improve documentation of WindowBuilderExtWebSys methods (#2952) 2023-07-12 17:11:17 +02:00
John Nunley
d7ec899d69 Replace parts of the Xlib backend with x11-rb 2023-07-12 07:59:12 +00:00
daxpedda
5379d60e4d On Web, remove Window::is_dark_mode() (#2951) 2023-07-11 18:26:32 +02:00
daxpedda
44e2f95331 Fix mentions of Wasm (#2950) 2023-07-11 18:26:00 +02:00
daxpedda
3b2d1a7643 On Web, implement and fix missing methods on Window(Builder) (#2949) 2023-07-11 13:14:40 +02:00
daxpedda
50b17a3907 Add Fullscreen API compatibility for Safari (#2948) 2023-07-11 00:34:02 +02:00
daxpedda
af26f01b95 On Web, cache commonly used values (#2947) 2023-07-11 00:11:06 +02:00
daxpedda
c4d70d75c1 Increase accuracy of various Web APIs (#2946) 2023-07-10 23:55:43 +02:00
daxpedda
db8de03142 Improve Web specific documentation for various APIs (#2941)
Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
2023-07-10 12:50:28 +02:00
Kirill Chibisov
ff0ce9d065 Rename Window::set_inner_size to Window::request_inner_size
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.
2023-07-10 04:02:26 +00:00
daxpedda
42e492cde8 Fix touch location accuracy (#2944) 2023-07-10 02:17:36 +02:00
daxpedda
5e0e1e96bc On Web, implement WindowEvent::Occluded (#2940) 2023-07-10 02:02:38 +02:00
Imbris
bd890e69aa On X11, avoid false positive key repeats
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.
2023-07-09 17:05:49 +00:00
Mads Marquart
bca57ed0b4 Stop using &mut in Objective-C delegate methods (#2925)
* 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
2023-07-08 22:36:42 +03:00
daxpedda
4652d48105 Don't unnecessarily clone canvas on Web (#2934) 2023-07-08 17:05:05 +02:00
daxpedda
96c0b267e2 Fix typos on Web (#2933) 2023-07-08 16:47:31 +02:00
StarStarJ
81fd39485f Implement PartialOrd/Ord for KeyCode/NativeKeyCode 2023-07-01 19:07:35 +04:00
Kirill Chibisov
6178acede8 Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2023-07-01 00:10:02 +04:00
Kirill Chibisov
a320702a71 On X11, fix IME not working
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.
2023-06-30 19:59:24 +04:00
dAxpeDDa
b0106898f7 Don't allow event loops to run in parallel 2023-06-29 15:53:58 +02:00
Fredrik Fornwall
924f3323b5 On Web, map bfcache load/unload to suspend/resume 2023-06-28 15:38:49 +02:00
Kirill Chibisov
b97df599c5 On Linux, fix wrong layout for key_without_modifiers
The layout was hardcoded to zero, so the keys were sent for whatever
user configured first.
2023-06-28 14:48:35 +04:00
Kirill Chibisov
0defd747c8 Update xkbcommon-dl to 0.4.0
Most things were simply renamed due to migration to xkeysym.
2023-06-28 14:48:35 +04:00
Kirill Chibisov
e23186db8e Disallow cleanup for TLS in examples
Fixes issue on Wayland due to drop order, since TLS is being dropped
after the event loop, while it shouldn't. In particular it fixes the
crash in the window_run_return example.
2023-06-26 01:04:38 +04:00
Kirill Chibisov
059abb06fc On Wayland, handle none decorations
During the migration some logic wrt `none` decorations was lost along
the way, however we also now try to ask for client side decorations if
the user wants to disable server side decorations.

Fixes #2902.
2023-06-25 14:12:12 +04:00
Josh Groves
bc216b8f67 Allow recreating wasm event loop with spawn (#2897) 2023-06-23 19:31:42 +02:00
Josh Groves
864a1d5924 Fix some typos (#2901) 2023-06-23 10:10:36 +03:00
Kirill Chibisov
05444628e6 Provide a way to set cursor area for IME cursor
Rename `Window::set_ime_position` to `Window::set_ime_cursor_area`
adding a way to create cursor exclusive zone.

Fixes #2886.
2023-06-22 19:12:14 +00:00
Kirill Chibisov
66ff52b012 On Wayland, fix transparency hint not set in new
Fixes #2894.
2023-06-22 00:21:43 +00:00
Robert Bragg
7929999c1c Android: rework keycode handling (#2890)
The recent overhaul of the keyboard API broke keyboard input on Android.

The recent keyboard changes also broke building against the
game-activity backend of android-activity because it was assumed that
the backend is based on the NDK input API which isn't the case with
with game-activity since it doesn't use the InputQueue API from the NDK.

Any alphanumeric keycodes were being mapped to `Unidentified` Keys
which meant even crude keyboard input support was broken.

We do need to expose `getUnicodeChar` (or the ability to look
up characters based on the current character map and modifiers) but
for now we should at least map alphanumeric keycodes to `Key::Character`
for basic interim support of virtual keyboards.

This moves all the keycode mapping into a separate `keycodes.rs` file
to reduce clutter.

This adds back the mapping from Android key codes to Winit key codes
that we had before the keyboard API overhaul.

Android activity does expose scan codes but key codes currently seem
like the more appropriate mapping to Winit physical key codes.

This removes the gnarly, unsafe cfg() guarded digging into
'native-activity' and 'game-activity' specific implementation details. I
never intended to expose these details in the public API and really
hope to avoid there being a release of Winit that would depend on this.

I'm also hoping/considering if I can get away with sealing this without
necessarily requiring a semver breaking release of android_activity
since this absolutely should never have been possible, and can probably
safely assume this was the only code in the wild that has briefly done
this.

I'm also a bit unclear as to what led to doing this. There is a
`.key_code()` and `.scan_code()` getter and we even already accessed the
keycode in the Android backend so I'm not sure how those APIs were missed.
2023-06-21 19:49:44 +02:00
Kirill Chibisov
7094a223af Bring OptionAsAlt back for macOS
The correct handling of this setting requires to change the events
we're getting from the macOS on the fly and call `interpretKeyEvents`,
which could affect handling of the next events, meaning that we can't
provide them on `KeyEvent`.
2023-06-20 19:07:49 +00:00
John Nunley
b2a46d0439 Fill the windows in the examples with a solid color
Fixes #776.
2023-06-19 18:46:38 +00:00
bbb651
4748890935 Add MouseButton::{Back, Forward} to MouseInput
Add named variants for physical back and forward keys which could
be found on some mice. The macOS bits may not work on all the
hardware given that apple doesn't directly support such a thing.

Co-authored-by: daxpedda <daxpedda@gmail.com>
2023-06-16 08:51:09 +00:00
daxpedda
6300cf915e On Web, implement DeviceEvents (#2871) 2023-06-14 10:26:26 +02:00
daxpedda
9a9c9b15ba Implement ResizeObserver (#2859)
Co-authored-by: Liam Murphy <43807659+Liamolucko@users.noreply.github.com>
2023-06-14 09:43:53 +02:00
dAxpeDDa
7ce86c3d2a Use Window.requestIdleCallback() 2023-06-14 00:03:23 +02:00
daxpedda
a444637b18 Revert "Send modifiers first"
This reverts commit e17977d7c7.
2023-06-14 00:01:37 +02:00
daxpedda
f0d88c52a3 Fix pointer deltas on Firefox and send coalesced events together (#2878) 2023-06-13 15:49:27 +02:00
dAxpeDDa
e17977d7c7 Send modifiers first 2023-06-13 14:33:08 +02:00
dAxpeDDa
a7a8ff0bbb Drop pointerrawupdate support 2023-06-13 10:23:48 +02:00
dAxpeDDa
fc046add78 Resume propagation of events 2023-06-12 00:48:14 +02:00
dAxpeDDa
ab4a4a89e6 Remove unused EventListenerOptions 2023-06-11 19:44:52 +02:00
dAxpeDDa
f7a400ddf6 Improve media queries take 2 2023-06-09 20:38:54 +02:00
Xiaopeng Li
07d39abddd Fix panic when destroying window (#2773)
* Fix crash when destroying window

* Add a comment to draw_rect

---------

Co-authored-by: Xiaopeng Li <lixiaopeng.jetspark@bytedance.com>
2023-06-09 16:20:27 +03:00
Imbris
0c8bf25ae4 Fix compilation on aarch64-linux
aarch64 defines `c_char` as `u8` and not `i8`. Use `c_char`
alias directly.
2023-06-09 11:46:01 +00:00
dAxpeDDa
b5785ba785 Revert "Fix Window::set_inner_size()"
This reverts commit e220a75556.
2023-06-08 09:09:46 +02:00
dAxpeDDa
9797ed86f0 Fix unable to ignore scale factor resize suggestion 2023-06-07 22:46:14 +02:00
dAxpeDDa
e220a75556 Fix Window::set_inner_size() 2023-06-07 14:53:59 +02:00
dAxpeDDa
29d3729ac8 Disallow more methods 2023-06-07 12:53:47 +02:00
Robin Thunström
4a36741f9c On Android, change default implementation to ignore volume keys and let operating system handle them (#2748) 2023-06-06 23:04:51 +02:00
dAxpeDDa
ab46aa5b79 Replace beforeunload with pagehide 2023-06-05 16:40:53 +02:00
dAxpeDDa
12fb37d827 Make media queries more robust 2023-06-05 16:11:22 +02:00
dAxpeDDa
c88a4ab221 Use correct canvas size for scale factor change 2023-06-05 15:39:17 +02:00
daxpedda
8f7f3efc0d On Web, implement Send and Sync where appropriate (#2834) 2023-06-05 02:44:54 +02:00
dAxpeDDa
eb2d3894ef Document unpreventable events 2023-06-05 02:04:37 +02:00
dAxpeDDa
3f4f580181 Add pointerrawupdate support 2023-06-05 02:04:37 +02:00
dAxpeDDa
d3aeff8838 Remove unnecessary preventDefault() calls 2023-06-05 02:04:37 +02:00
dAxpeDDa
0786d534f4 Take IntoIterator in send_events() 2023-06-05 02:04:37 +02:00
dAxpeDDa
b4b2389d0a Split modifier handling in all pointer events 2023-06-05 02:04:37 +02:00
dAxpeDDa
964e342f69 Prevent text selection 2023-06-05 02:04:37 +02:00
dAxpeDDa
a134a59917 Remove MouseEvent fallback support 2023-06-05 02:04:37 +02:00
dAxpeDDa
fbba203c4a Focus window on touch press 2023-06-05 02:04:37 +02:00
dAxpeDDa
61bd8b8254 Send position on button release 2023-06-05 02:04:37 +02:00
dAxpeDDa
587fa67571 Split cursor move handlers 2023-06-05 02:04:37 +02:00
dAxpeDDa
7500a88230 Fix up changelog 2023-06-04 13:45:43 +02:00
dAxpeDDa
82d0380ea6 Ignore pen input on Web 2023-06-04 00:23:47 +02:00
John Nunley
642ce2bfa7 Port to windows-sys v0.48.0 (#2842) 2023-06-04 00:02:37 +02:00
dAxpeDDa
5bbe87960e Replace instant with web-time 2023-06-03 16:05:44 +02:00
Kirill Chibisov
cf77f82ae3 Update remaining actions to v3
This somehow was left unnoticed.
2023-06-03 17:00:55 +03:00
Kirill Chibisov
72cf4e577f Add missing Hash impls on bitflags
Some bitflags in public API lost their `Hash` implementations.

Fixes: 31ebc5caf (Update `bitflags` to `2.0`)
2023-06-03 16:44:52 +03:00
dAxpeDDa
4f3eacf01e On Web, handle coalesced events 2023-06-02 18:48:34 +02:00
George Burton
31ebc5caf4 Update bitflags to 2.0
Co-authored-by: dAxpeDDa <daxpedda@gmail.com>
2023-06-02 17:44:36 +03:00
dAxpeDDa
d273518ce9 Process pointer button events 2023-06-02 12:41:35 +02:00
dAxpeDDa
2ade772ab0 Bump console_log to v1 2023-06-01 17:19:30 +02:00
John Nunley
4ac2006cbc Replace mio with calloop in the X11 backend 2023-05-31 19:44:42 +03:00
dAxpeDDa
ba5ad3be13 On Web, fix no-op for Window::set_fullscreen 2023-05-31 15:25:15 +02:00
dAxpeDDa
8092fa2440 Fix changelog 2023-05-31 13:47:34 +02:00
Toniman575
8bb004a1d9 Rename DeviceEventFilter to DeviceEvents
The use of `Filter` was confusing so it was removed inverting the 
behavior of the enum and methods using it.

Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
2023-05-30 22:32:31 +03:00
Simon Hausmann
de5327477a web: Fix position of touch events to be relative to the canvas
Use the same logic as for mouse events when not captured.
2023-05-30 21:21:41 +02:00
Nicola Papale
8f959714cc Fix Window::set_theme doc string
Fix #2814.
2023-05-30 12:22:19 +03:00
Kirill Chibisov
035eebb19a Use linux scancode values for KeyCodeExtScancode
Old winit was using linux scancodes, so this should make it backward
compatible with itself.
2023-05-29 13:48:12 +03:00
Kirill Chibisov
b5af6bb266 Use xkbcommon-dl 0.3.0 2023-05-29 00:55:54 +03:00
dAxpeDDa
1805124c54 On Web, wake event loop on request_redraw() 2023-05-28 23:22:08 +02:00
dAxpeDDa
0f64589dba Don't change the internal canvas size 2023-05-28 23:10:33 +02:00
Kirill Chibisov
5438a2a524 Add @daxpedda as web maintainer
Fixes #1777.
2023-05-28 23:48:28 +03:00
Markus Røyset
918430979f Overhaul the Keyboard API
Overhaul the keyboard API in winit to mimic the W3C specification
to achieve better crossplatform parity. The `KeyboardInput` event
is now uses `KeyEvent` which consists of:

  - `physical_key` - a cross platform way to refer to scancodes;
  - `logical_key`  - keysym value, which shows your key respecting the
                     layout;
  - `text`         - the text produced by this keypress;
  - `location`     - the location of the key on the keyboard;
  - `repeat`       - whether the key was produced by the repeat.

And also a `platform_specific` field which encapsulates extra
information on desktop platforms, like key without modifiers
and text with all modifiers.

The `Modifiers` were also slightly reworked as in, the information
whether the left or right modifier is pressed is now also exposed
on platforms where it could be queried reliably. The support was
also added for the web and orbital platforms finishing the API
change.

This change made the `OptionAsAlt` API on macOS redundant thus it
was removed all together.

Co-authored-by: Artúr Kovács <kovacs.artur.barnabas@gmail.com>
Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
Co-authored-by: daxpedda <daxpedda@gmail.com>
Fixes: #2631.
Fixes: #2055.
Fixes: #2032.
Fixes: #1904.
Fixes: #1810.
Fixes: #1700.
Fixes: #1443.
Fixes: #1343.
Fixes: #1208.
Fixes: #1151.
Fixes: #812.
Fixes: #600.
Fixes: #361.
Fixes: #343.
2023-05-28 21:02:59 +03:00
Kirill Chibisov
f3f46cb3f6 On Wayland, fix Window::set_cursor_visible(true)
Making the cursor back visible was simply forgotten and it was
always hiding instead.

Fixes: 2496098890 (Update wayland-rs to 0.30.0)
Fixes: #2820.
2023-05-26 09:26:22 +03:00
John Nunley
3c3be71a77 Implement PartialOrd/Ord for dpi module types 2023-05-16 05:11:43 +03:00
Kirill Chibisov
a7986b077f Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2023-05-14 20:36:23 +03:00
Kirill Chibisov
8a0edde5c8 Bump github actions to v3 2023-05-14 20:35:58 +03:00
Kirill Chibisov
a9e168e10d On macOS, fix backspace emission on preedit clear
Fixes: d15feb5cfa (On macOS, fix empty marked text)
2023-05-13 03:02:05 +03:00
Kirill Chibisov
bd9cc2a9da Use cursor-icon crate for CursorIcon
This crate is aimed to simplify handling of cursor icon across
various crates and be used in the public API.
2023-05-09 20:19:35 +03:00
Kirill Chibisov
596c0edf0f Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2023-05-09 18:28:20 +03:00
Xiaopeng Li
92592ec605 Fix device description leak (#2758)
* Fix device description leak

* Update CHANGELOG.md

---------

Co-authored-by: Xiaopeng Li <lixiaopeng.jetspark@bytedance.com>
2023-05-08 17:58:34 +03:00
Kirill Chibisov
25c4e2e451 On macOS, fix key_up being ignored without IME
Fixes: d15feb5cfa (On macOS, fix empty marked text)
2023-05-06 14:05:28 +03:00
Kirill Chibisov
ad52c72e41 Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2023-05-05 13:27:22 +03:00
Kirill Chibisov
d15feb5cfa On macOS, fix empty marked text blocking input
Fixes #2775.
2023-05-04 00:24:02 +03:00
Kirill Chibisov
9938327066 On Wayland, fix nightly warnings
The new analysis suggests that we can remove mut.
2023-05-04 00:24:02 +03:00
Kirill Chibisov
f980ed7b83 On X11, fix nightly warnings
The new analysis suggests that we can remove mut.
2023-05-04 00:24:02 +03:00
Kirill Chibisov
2496098890 Update wayland-rs to 0.30.0
This update rewrites the winit's Wayland backend using new wayland-rs
0.30 API. This fixes long standing issue with the forward compatibility
of the wayland backend, meaning that future updates to the wayland
protocol won't break rust code anymore. like it was before when adding
new shm/enum variants into the protocol.

Fixes #2560.
Fixes #2164.
Fixes #2128.
Fixes #1760.
Fixes #725.
2023-04-19 00:56:29 +03:00
Amandus Søve Thorsrud
60e91b187a Run Window::set_ime_position on main thread on macOS
Fixes #2756.
2023-04-15 02:58:36 +03:00
Xiaopeng Li
2486f0f1a1 Fix potential panic (#2755)
* Fix potential panic

* Update CHANGELOG.md

* Use checked_div

---------

Co-authored-by: Xiaopeng Li <lixiaopeng.jetspark@bytedance.com>
2023-04-03 21:46:09 +03:00
Emil Ernerfeldt
fbea75d31f Add cargo-deny check to CI 2023-03-16 23:05:41 +03:00
Kirill Chibisov
d4c9535af9 Bump version on master
This commit does not represent a release and only synchronizes CHANGELOG
from the latest release.
2023-03-16 23:05:17 +03:00
daxpedda
f0fcb346b0 On Web, use target_family = "wasm" 2023-03-16 22:49:59 +03:00
Mads Marquart
77f8e511e9 Fix macos memory leaks (#2739)
* Use a weak reference from WinitView to WinitWindow

* Allow patched objc2 version

* Add changelog entry
2023-03-14 13:27:41 +03:00
Emil Ernerfeldt
3217eaa416 Fix 1.68 clippy warnings 2023-03-12 20:02:49 +03:00
Kirill Chibisov
b18295a1ce Bump MSRV to 1.64 2023-03-08 19:34:10 +03:00
esdevver
fb9695d56d Changed 'an' to 'a' in documentation (#2715) 2023-03-04 10:37:15 +01:00
Kirill Chibisov
08bdca19b1 Bump version on master
This commit does not represent a release and only
synchronizes CHANGELOG from the latest release.
2023-03-02 17:15:48 +03:00
Dylan Scott
79ac236721 On macOS, resize simple fullscreen on window move
Fixes #1118.
2023-03-02 01:47:45 +03:00
Nicolas Mazzon
b870a11a99 On Windows, check whether CoCreateInstance succeeds 2023-03-02 01:24:04 +03:00
Kirill Chibisov
2af1550bbb On macOS, fix initial focused state
The synthetic focused event was queued after the real event was send
leading to focused issues on startup.

Fixes #2695.
2023-02-27 20:46:00 +03:00
John Nunley
ed796dcd15 Update FEATURES.md 2023-02-26 09:53:45 +03:00
Kirill Chibisov
a006cd7dc8 On Wayland, fix rounding issue in resizes 2023-02-21 11:44:22 +03:00
Simon Hausmann
a31f71ee07 Add support for Window::theme on the web (#2687) 2023-02-20 08:51:21 +01:00
Kirill Chibisov
0f89aac9f6 On Wayland, fix rare crash on DPI change
While I don't understand the root cause for this issue, we can
dirty fix like that for now.
2023-02-19 17:39:39 +03:00
Kirill Chibisov
82df9531f4 On macOS, set resize increments only for live resize
Closes #2684 for macOS.
2023-02-15 03:32:55 +03:00
Sludge
265152355e Implement HasRawDisplayHandle for EventLoop (#2677)
* Implement `HasRawDisplayHandle` for `EventLoop`

* Add changelog entry
2023-02-10 16:25:22 +01:00
John Nunley
37c0f615cf On Windows, name the waiter thread (#2672) 2023-02-08 21:39:01 +01:00
John Nunley
5ba6bdef49 Replace lazy window message ids with a slimmer version (#2598) 2023-02-04 15:38:21 +01:00
Kirill Chibisov
69d6076310 Bump version on master
This commit does not represent a release and only
synchronizes CHANGELOG from the latest release.
2023-02-04 14:47:31 +03:00
Kirill Chibisov
7029ce6ecd Fix window drop on Wayland
In some scenarious of window dropping the callback for keyboard
may run after the window was dropped.
2023-02-02 14:42:34 +03:00
Kirill Chibisov
1eb1a13a77 Bump version on master
This commit does not represent a release and only
synchronizes CHANGELOG from the latest release.
2023-02-02 10:55:59 +03:00
488 changed files with 65052 additions and 46177 deletions

View File

@@ -1,2 +1,9 @@
[alias]
run-wasm = ["run", "--release", "--package", "run-wasm", "--"]
# Allow rust-analyzer and local `cargo doc` invocations to pick up unreleased changelog entries
#
# Note that these flags are (intentionally) not included when building from the downloaded crate.
[build]
rustdocflags = ["--cfg=unreleased_changelogs"]
rustflags = ["--cfg=unreleased_changelogs"]
[target.wasm32-unknown-unknown]
runner = "wasm-bindgen-test-runner"

8
.git-blame-ignore-revs Normal file
View File

@@ -0,0 +1,8 @@
# $ git config blame.ignoreRevsFile .git-blame-ignore-revs
# chore(rustfmt): use nightly
7b0c7b6cb2c62767ca0c73c857b299883f55a883
# Rustfmt: use `group_imports`
2665c120981af548433645c6383b3580dd8f8fc4
# Use Taplo for TOML formatting
3398ebe467c43ccfd91916c5b81ff3c68f598556

44
.github/CODEOWNERS vendored
View File

@@ -1,40 +1,26 @@
# Core maintainers:
# - @msiglreith
# - @kchibisov
# - @madsmtm
# - @maroider
# Android
/src/platform/android.rs @msiglreith
/src/platform_impl/android @msiglreith
/winit-android @MarijnS95
# iOS
/src/platform/ios.rs @madsmtm
/src/platform_impl/ios @madsmtm
# Apple (AppKit + UIKit)
/winit-appkit @madsmtm
/winit-uikit @madsmtm
/winit-common/src/core_foundation @madsmtm
/winit-common/src/event_handler.rs @madsmtm
# Unix
/src/platform_impl/linux/mod.rs @kchibisov
# XKB
/winit-common/src/xkb @kchibisov
# Wayland
/src/platform/wayland.rs @kchibisov
/src/platform_impl/linux/wayland @kchibisov
/winit-wayland @kchibisov
# X11
/src/platform/x11.rs @kchibisov
/src/platform_impl/linux/x11 @kchibisov
/winit-x11 @kchibisov
# macOS
/src/platform/macos.rs @madsmtm
/src/platform_impl/macos @madsmtm
# Web
/winit-web @daxpedda
# Web (no maintainer)
/src/platform/web.rs
/src/platform_impl/web
# Windows
/src/platform/windows.rs @msiglreith
/src/platform_impl/windows @msiglreith
# Windows (Win32) (UNOWNED)
#/winit-win32
# Orbital (Redox OS)
/src/platform/orbital.rs @jackpot51
/src/platform_impl/orbital @jackpot51
/winit-orbital @jackpot51

4
.github/ISSUE_TEMPLATE/blank_issue.md vendored Normal file
View File

@@ -0,0 +1,4 @@
---
name: Blank Issue
about: Create a blank issue.
---

36
.github/ISSUE_TEMPLATE/bug_android.yml vendored Normal file
View File

@@ -0,0 +1,36 @@
name: Android bug
description: Create an Android-specific bug report
labels:
- B - bug
- DS - android
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: textarea
id: description
attributes:
label: Description
description: Description of the problem you're having
validations:
required: true
- type: textarea
id: device
attributes:
label: Device and Android version
description: Which devices and Android versions are you seeing the problem on?
placeholder: |
Samsung Galaxy Z running Android Pie (API level 28),
Samsung Galaxy Z running Android 14 (API level 34),
Pixel 8 running Android 14 (API level 34)
validations:
required: true
- type: textarea
id: winit-version
attributes:
label: Winit version
description: What version of Winit are you using?
placeholder: 0.29.11
validations:
required: true

37
.github/ISSUE_TEMPLATE/bug_appkit.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: macOS bug
description: Create a macOS-specific bug report
labels:
- B - bug
- DS - appkit
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: textarea
id: description
attributes:
label: Description
description: Description of the problem you're having
validations:
required: true
- type: textarea
id: os-version
attributes:
label: macOS version
description: What version of macOS are you using? Please paste in the output of `sw_vers`.
placeholder: |
ProductName: macOS
ProductVersion: 14.2.1
BuildVersion: 23C71
render: shell
validations:
required: true
- type: textarea
id: winit-version
attributes:
label: Winit version
description: What version of Winit are you using?
placeholder: 0.29.11
validations:
required: true

37
.github/ISSUE_TEMPLATE/bug_uikit.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: iOS bug
description: Create an iOS/UIKit-specific bug report
labels:
- B - bug
- DS - uikit
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: textarea
id: description
attributes:
label: Description
description: Description of the problem you're having
validations:
required: true
- type: textarea
id: device
attributes:
label: Device and iOS version
description: Which devices and iOS versions are you seeing the problem on?
placeholder: |
iPhone 15 running iOS 14.0,
iPhone 15 running iOS 17.0,
MacBook Pro M2 Mac Catalyst running macOS 14.2,
iPhone simulator running iOS 17.0
validations:
required: true
- type: textarea
id: winit-version
attributes:
label: Winit version
description: What version of Winit are you using?
placeholder: 0.29.11
validations:
required: true

41
.github/ISSUE_TEMPLATE/bug_wayland.yml vendored Normal file
View File

@@ -0,0 +1,41 @@
name: Wayland bug
description: Create a Wayland-specific bug report
labels:
- B - bug
- DS - wayland
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: textarea
id: description
attributes:
label: Description
description: Description of the problem you're having
validations:
required: true
- type: textarea
id: debug
attributes:
label: Debugging output
description: Output of a binary run with `WAYLAND_DEBUG=1`
placeholder: |
[1234.5678] -> wl_display@1.get_registry(new id wl_registry@2)
[1234.5678] -> wl_display@1.sync(new id wl_callback@3)
...
render: shell
- type: checkboxes
attributes:
label: Window isn't shown unless you draw
options:
- label: I understand that windows aren't shown on Wayland unless I draw and present to them.
required: true
- type: textarea
id: winit-version
attributes:
label: Winit version
description: What version of Winit are you using?
placeholder: 0.29.11
validations:
required: true

51
.github/ISSUE_TEMPLATE/bug_web.yml vendored Normal file
View File

@@ -0,0 +1,51 @@
name: Web bug
description: Create a Web-specific bug report
labels:
- B - bug
- DS - web
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: textarea
id: description
attributes:
label: Description
description: Description of the problem you're having
validations:
required: true
- type: dropdown
id: browsers
attributes:
label: Tested browsers
description: What browsers are you seeing the problem on?
options:
- Firefox
- Chrome
- Microsoft Edge
- Safari 13
- Safari 14
- Safari 15
- Safari 16
- Safari 17
- Safari (newer than listed)
multiple: true
validations:
required: true
- type: textarea
id: device
attributes:
label: Tested devices
description: Which device(s) are you using?
placeholder: 'iPhone 15, Lenovo ThinkPad X1, MacBook Pro M2, Samsung Galaxy Z, ...'
validations:
required: true
- type: textarea
id: winit-version
attributes:
label: Winit version
description: What version of Winit are you using?
placeholder: 0.29.11
validations:
required: true

35
.github/ISSUE_TEMPLATE/bug_win32.yml vendored Normal file
View File

@@ -0,0 +1,35 @@
name: Windows bug
description: Create a Windows-specific bug report
labels:
- B - bug
- DS - win32
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: textarea
id: description
attributes:
label: Description
description: Description of the problem you're having
validations:
required: true
- type: textarea
id: os-version
attributes:
label: Windows version
description: What version of Windows are you using? Please paste in the output of the `ver` command.
placeholder: |
Microsoft Windows [Version 10.0.19042.2251]
render: shell
validations:
required: true
- type: textarea
id: winit-version
attributes:
label: Winit version
description: What version of Winit are you using?
placeholder: 0.29.11
validations:
required: true

32
.github/ISSUE_TEMPLATE/bug_x11.yml vendored Normal file
View File

@@ -0,0 +1,32 @@
name: X11 bug
description: Create a X11-specific bug report
labels:
- B - bug
- DS - x11
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: textarea
id: description
attributes:
label: Description
description: Description of the problem you're having
validations:
required: true
- type: textarea
id: os-info
attributes:
label: OS and window mananger
description: Which operating system and window manager are you using?
validations:
required: true
- type: textarea
id: winit-version
attributes:
label: Winit version
description: What version of Winit are you using?
placeholder: 0.29.11
validations:
required: true

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,5 @@
blank_issues_enabled: true
contact_links:
- name: Question
url: https://matrix.to/#/#rust-windowing:matrix.org
about: Please ask questions on the Matrix channel.

View File

@@ -0,0 +1,26 @@
name: Feature request
description: Propose a new feature
labels:
- S - enhancement
body:
- type: textarea
id: description
attributes:
label: Description
description: Description of the problem does this solve or what need does it fill? Please be mindful of the [scope](https://github.com/rust-windowing/winit/blob/master/FEATURES.md) of Winit.
validations:
required: true
- type: dropdown
id: platforms
attributes:
label: Relevant platforms
description: On which platforms is this feature relevant?
options:
- Windows
- macOS
- Wayland
- X11
- Web
- iOS
- Android
multiple: true

View File

@@ -1,5 +1,4 @@
- [ ] Tested on all platforms changed
- [ ] Added an entry to `CHANGELOG.md` if knowledge of this change could be valuable to users
- [ ] Added an entry to the `changelog` module if knowledge of this change could be valuable to users
- [ ] Updated documentation to reflect any user-facing changes, including notes of platform-specific behavior
- [ ] Created or updated an example program if it would help users understand this functionality
- [ ] Updated [feature matrix](https://github.com/rust-windowing/winit/blob/master/FEATURES.md), if new features were added or implemented

22
.github/dependabot.yaml vendored Normal file
View File

@@ -0,0 +1,22 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: daily
groups:
github-actions:
patterns:
- "*"
- package-ecosystem: npm
directory: src/platform_impl/web/script
schedule:
interval: daily
groups:
github-actions:
patterns:
- '*'
labels:
- "DS - web"

View File

@@ -6,116 +6,329 @@ on:
branches: [master]
jobs:
Check_Formatting:
fmt:
name: Check formatting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: hecrj/setup-rust-action@v1
- uses: taiki-e/checkout-action@v1
- uses: dtolnay/rust-toolchain@nightly
with:
rust-version: stable
components: rustfmt
- name: Check Formatting
run: cargo +stable fmt --all -- --check
run: cargo fmt -- --check
taplo:
name: Taplo
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: taiki-e/checkout-action@v1
- name: Install Taplo
uses: taiki-e/install-action@v2
with:
tool: taplo-cli
- name: Run Taplo
run: taplo fmt --check
typos:
name: Check for typos
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: taiki-e/checkout-action@v1
- uses: taiki-e/install-action@v2
with:
tool: typos-cli
- name: run typos
run: typos
- name: Typos info
if: failure()
run: |
echo 'To fix typos, please run `typos -w`'
echo 'To check for a diff, run `typos`'
echo 'You can find typos here: https://crates.io/crates/typos'
tests:
name: Tests
name: Test ${{ matrix.toolchain }} ${{ matrix.platform.name }}
runs-on: ${{ matrix.platform.os }}
strategy:
fail-fast: false
matrix:
rust_version: ['1.60.0', stable, nightly]
toolchain: [stable, nightly, '1.85']
platform:
# Note: Make sure that we test all the `docs.rs` targets defined in Cargo.toml!
- { target: x86_64-pc-windows-msvc, os: windows-latest, }
- { target: i686-pc-windows-msvc, os: windows-latest, }
- { target: x86_64-pc-windows-gnu, os: windows-latest, host: -x86_64-pc-windows-gnu }
- { target: i686-pc-windows-gnu, os: windows-latest, host: -i686-pc-windows-gnu }
- { target: i686-unknown-linux-gnu, os: ubuntu-latest, }
- { target: x86_64-unknown-linux-gnu, os: ubuntu-latest, }
- { target: x86_64-unknown-linux-gnu, os: ubuntu-latest, options: --no-default-features, features: x11 }
- { target: x86_64-unknown-linux-gnu, os: ubuntu-latest, options: --no-default-features, features: "wayland,wayland-dlopen" }
- { target: aarch64-linux-android, os: ubuntu-latest, options: -p winit, cmd: 'apk --', features: "android-native-activity" }
- { target: x86_64-unknown-redox, os: ubuntu-latest, }
- { target: x86_64-apple-darwin, os: macos-latest, }
- { target: x86_64-apple-ios, os: macos-latest, }
- { target: aarch64-apple-ios, os: macos-latest, }
# We're using Windows rather than Ubuntu to run the wasm tests because caching cargo-web
# doesn't currently work on Linux.
- { target: wasm32-unknown-unknown, os: windows-latest, }
- { name: 'Windows 64bit MSVC', target: x86_64-pc-windows-msvc, os: windows-latest, }
- { name: 'Windows 32bit MSVC', target: i686-pc-windows-msvc, os: windows-latest, }
- { name: 'Windows 64bit GNU', target: x86_64-pc-windows-gnu, os: windows-latest, host: -x86_64-pc-windows-gnu }
- { name: 'Windows 32bit GNU', target: i686-pc-windows-gnu, os: windows-latest, host: -i686-pc-windows-gnu }
- { name: 'Linux 32bit', target: i686-unknown-linux-gnu, os: ubuntu-latest, }
- { name: 'Linux 64bit', target: x86_64-unknown-linux-gnu, os: ubuntu-latest, }
- { name: 'X11', target: x86_64-unknown-linux-gnu, os: ubuntu-latest, options: '--no-default-features --features=x11' }
- { name: 'Wayland', target: x86_64-unknown-linux-gnu, os: ubuntu-latest, options: '--no-default-features --features=wayland,wayland-dlopen' }
- { name: 'Android', target: aarch64-linux-android, os: ubuntu-latest, options: '--package winit --features=android-native-activity', cmd: 'apk -- ' }
- { name: 'Redox OS', target: x86_64-unknown-redox, os: ubuntu-latest, }
- { name: 'macOS x86_64', target: x86_64-apple-darwin, os: macos-latest, }
- { name: 'macOS Aarch64', target: aarch64-apple-darwin, os: macos-latest, }
- { name: 'iOS x86_64', target: x86_64-apple-ios, os: macos-latest, }
- { name: 'iOS Aarch64', target: aarch64-apple-ios, os: macos-latest, }
- { name: 'Web', target: wasm32-unknown-unknown, os: ubuntu-latest, }
exclude:
# Web on nightly needs extra arguments
- toolchain: nightly
platform: { name: 'Web' }
# Rustup is broken.
- toolchain: nightly
platform: { name: 'Windows 32bit GNU' }
# Android is tested on stable-3
- toolchain: '1.85'
platform: { name: 'Android' }
# Redox OS doesn't follow MSRV
- toolchain: '1.85'
platform: { name: 'Redox OS' }
include:
- toolchain: '1.85'
platform: { name: 'Android', target: aarch64-linux-android, os: ubuntu-latest, options: '--package winit --features=android-native-activity', cmd: 'apk -- ' }
- toolchain: 'nightly'
platform: { name: 'Web', target: wasm32-unknown-unknown, os: ubuntu-latest, test-options: -Zdoctest-xcompile }
- toolchain: 'nightly'
platform: {
name: 'Web Atomic',
target: wasm32-unknown-unknown,
os: ubuntu-latest,
options: '-Zbuild-std=panic_abort,std',
test-options: -Zdoctest-xcompile,
rustflags: '-Ctarget-feature=+atomics,+bulk-memory',
components: rust-src,
}
env:
# Set more verbose terminal output
CARGO_TERM_VERBOSE: true
RUST_BACKTRACE: 1
CARGO_INCREMENTAL: 0
RUSTFLAGS: "-C debuginfo=0 --deny warnings"
OPTIONS: ${{ matrix.platform.options }}
FEATURES: ${{ format(',{0}', matrix.platform.features ) }}
# Faster compilation and error on warnings
RUSTFLAGS: '--codegen=debuginfo=0 --deny=warnings ${{ matrix.platform.rustflags }}'
RUSTDOCFLAGS: ${{ matrix.platform.rustflags }}
OPTIONS: --target=${{ matrix.platform.target }} ${{ matrix.platform.options }}
TEST_OPTIONS: ${{ matrix.platform.test-options }}
CMD: ${{ matrix.platform.cmd }}
RUSTDOCFLAGS: -Dwarnings
runs-on: ${{ matrix.platform.os }}
steps:
- uses: actions/checkout@v2
# Used to cache cargo-web
- name: Cache cargo folder
uses: actions/cache@v1
with:
path: ~/.cargo
key: ${{ matrix.platform.target }}-cargo-${{ matrix.rust_version }}
- uses: taiki-e/checkout-action@v1
- uses: hecrj/setup-rust-action@v1
- name: Restore cache of cargo folder
# We use `restore` and later `save`, so that we can create the key after
# the cache has been downloaded.
#
# This could be avoided if we added Cargo.lock to the repository.
uses: actions/cache/restore@v6
with:
rust-version: ${{ matrix.rust_version }}${{ matrix.platform.host }}
targets: ${{ matrix.platform.target }}
components: clippy
# https://doc.rust-lang.org/cargo/guide/cargo-home.html#caching-the-cargo-home-in-ci
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
key: cargo-${{ matrix.toolchain }}-${{ matrix.platform.name }}-never-intended-to-be-found
restore-keys: cargo-${{ matrix.toolchain }}-${{ matrix.platform.name }}
- name: Generate lockfile
# Also updates the crates.io index
run: cargo generate-lockfile && cargo update -p smol_str --precise 0.3.2 && cargo update -p unicode-segmentation --precise 1.12.0 && cargo update -p wayland-protocols --precise 0.32.12
- name: Install GCC Multilib
if: (matrix.platform.os == 'ubuntu-latest') && contains(matrix.platform.target, 'i686')
run: sudo apt-get update && sudo apt-get install gcc-multilib
- name: Install cargo-apk
- name: Cache cargo-apk
if: contains(matrix.platform.target, 'android')
run: cargo install cargo-apk
id: cargo-apk-cache
uses: actions/cache@v6
with:
path: ~/.cargo/bin/cargo-apk
# Change this key if we update the required cargo-apk version
key: cargo-apk-v0-9-7
- uses: dtolnay/rust-toolchain@master
if: contains(matrix.platform.target, 'android') && (steps.cargo-apk-cache.outputs.cache-hit != 'true')
with:
toolchain: stable
- name: Install cargo-apk
if: contains(matrix.platform.target, 'android') && (steps.cargo-apk-cache.outputs.cache-hit != 'true')
run: cargo install cargo-apk --version=^0.9.7 --locked
- uses: taiki-e/cache-cargo-install-action@v3
if: contains(matrix.platform.target, 'wasm32') && matrix.toolchain == 'nightly'
with:
tool: wasm-bindgen-cli
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.toolchain }}${{ matrix.platform.host }}
targets: ${{ matrix.platform.target }}
components: clippy, ${{ matrix.platform.components }}
- name: Check documentation
shell: bash
run: cargo doc --no-deps --target ${{ matrix.platform.target }} $OPTIONS --features $FEATURES --document-private-items
run: cargo doc --no-deps $OPTIONS --document-private-items
env:
RUSTDOCFLAGS: '--deny=warnings ${{ matrix.platform.rustflags }}'
- name: Build crate
shell: bash
run: cargo $CMD build --verbose --target ${{ matrix.platform.target }} $OPTIONS --features $FEATURES
run: cargo $CMD build $OPTIONS
- name: Test winit core
run: cargo test -p winit-core
- name: Test winit Android
if: contains(matrix.platform.target, 'android')
run: cargo $CMD test -p winit-android --features native-activity --no-run
- name: Test winit Common (EventHandler)
run: cargo $CMD test -p winit-common --features event-handler --no-run
- name: Test winit Common (CF)
if: contains(matrix.platform.target, 'apple')
run: cargo $CMD test -p winit-common --features core-foundation --no-run
- name: Test winit Common (XKB)
if: contains(matrix.platform.target, 'linux-gnu')
run: cargo $CMD test -p winit-common --features xkb,x11,wayland --no-run
- name: Test winit AppKit
if: contains(matrix.platform.target, 'macos')
run: cargo $CMD test -p winit-appkit $OPTIONS
- name: Test winit Orbital
if: contains(matrix.platform.target, 'redox')
run: cargo test -p winit-orbital
- name: Test winit UIKit
if: contains(matrix.platform.target, 'ios')
# TODO: Run on Simulator
run: cargo $CMD test -p winit-uikit $OPTIONS --no-run
- name: Test winit Web
if: contains(matrix.platform.target, 'wasm')
run: cargo $CMD test -p winit-web $OPTIONS --no-run
- name: Test winit Win32
if: contains(matrix.platform.target, 'windows')
run: cargo $CMD test -p winit-win32 $OPTIONS
- name: Test winit X11
if: contains(matrix.platform.target, 'linux-gnu')
run: cargo $CMD test -p winit-x11 --target=${{ matrix.platform.target }}
- name: Test winit Wayland
if: contains(matrix.platform.target, 'linux-gnu')
run: cargo $CMD test -p winit-wayland --target=${{ matrix.platform.target }}
# Test only on Linux x86_64, so we avoid spending unnecessary CI hours.
- name: Test dpi crate
if: >
contains(matrix.platform.name, 'Linux 64bit') &&
matrix.toolchain != '1.85'
run: cargo test -p dpi
- name: Check dpi crate (no_std)
if: >
contains(matrix.platform.name, 'Linux 64bit') &&
matrix.toolchain != '1.85'
run: cargo check -p dpi --no-default-features
- name: Build tests
shell: bash
if: >
!contains(matrix.platform.target, 'redox') &&
matrix.rust_version != '1.60.0'
run: cargo $CMD test --no-run --verbose --target ${{ matrix.platform.target }} $OPTIONS --features $FEATURES
matrix.toolchain != '1.85'
run: cargo $CMD test --no-run $OPTIONS
- name: Run tests
shell: bash
if: >
!contains(matrix.platform.target, 'android') &&
!contains(matrix.platform.target, 'ios') &&
!contains(matrix.platform.target, 'wasm32') &&
(!contains(matrix.platform.target, 'wasm32') || matrix.toolchain == 'nightly') &&
!contains(matrix.platform.target, 'redox') &&
matrix.rust_version != '1.60.0'
run: cargo $CMD test --verbose --target ${{ matrix.platform.target }} $OPTIONS --features $FEATURES
matrix.toolchain != '1.85'
run: cargo $CMD test $OPTIONS
- name: Lint with clippy
shell: bash
if: (matrix.rust_version == 'stable') && !contains(matrix.platform.options, '--no-default-features')
run: cargo clippy --all-targets --target ${{ matrix.platform.target }} $OPTIONS --features $FEATURES -- -Dwarnings
if: (matrix.toolchain == 'stable') && !contains(matrix.platform.options, '--no-default-features')
run: cargo clippy --all-targets $OPTIONS $TEST_OPTIONS -- -Dwarnings
- name: Build tests with serde enabled
shell: bash
if: >
!contains(matrix.platform.target, 'redox') &&
matrix.rust_version != '1.60.0'
run: cargo $CMD test --no-run --verbose --target ${{ matrix.platform.target }} $OPTIONS --features serde,$FEATURES
matrix.toolchain != '1.85'
run: cargo $CMD test --no-run $OPTIONS $TEST_OPTIONS --features serde
- name: Run tests with serde enabled
shell: bash
if: >
!contains(matrix.platform.target, 'android') &&
!contains(matrix.platform.target, 'ios') &&
!contains(matrix.platform.target, 'wasm32') &&
(!contains(matrix.platform.target, 'wasm32') || matrix.toolchain == 'nightly') &&
!contains(matrix.platform.target, 'redox') &&
matrix.rust_version != '1.60.0'
run: cargo $CMD test --verbose --target ${{ matrix.platform.target }} $OPTIONS --features serde,$FEATURES
matrix.toolchain != '1.85'
run: cargo $CMD test $OPTIONS $TEST_OPTIONS --features serde
- name: Check docs.rs documentation
if: matrix.toolchain == 'nightly'
run: cargo doc --no-deps $OPTIONS --features=serde,mint,android-native-activity
env:
RUSTDOCFLAGS: '--deny=warnings ${{ matrix.platform.rustflags }} --cfg=docsrs --cfg=unreleased_changelogs'
# See restore step above
- name: Save cache of cargo folder
uses: actions/cache/save@v6
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
key: cargo-${{ matrix.toolchain }}-${{ matrix.platform.name }}-${{ hashFiles('Cargo.lock') }}
cargo-deny:
name: Run cargo-deny
runs-on: ubuntu-latest
steps:
- uses: taiki-e/checkout-action@v1
- uses: EmbarkStudios/cargo-deny-action@v2
with:
log-level: error
eslint:
name: ESLint
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./winit-web/src/script
steps:
- uses: taiki-e/checkout-action@v1
- name: Setup NPM
run: npm install
- name: Run ESLint
run: npx eslint@9.38.0
swc:
name: Minimize JavaScript
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./winit-web/src/script
steps:
- uses: taiki-e/checkout-action@v1
- name: Install SWC
run: sudo npm i -g @swc/cli
- name: Run SWC
run: |
swc . --ignore node_modules,**/*.d.ts --only **/*.ts -d . --out-file-extension min.js
- name: Check for diff
run: |
[[ -z $(git status -s) ]]

50
.github/workflows/docs.yml vendored Normal file
View File

@@ -0,0 +1,50 @@
name: Docs
on:
push:
branches: [master]
jobs:
docs:
name: Documentation
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}winit
runs-on: ubuntu-latest
permissions:
contents: read
pages: write
id-token: write
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly
- name: Run Rustdoc
env:
RUSTDOCFLAGS: --crate-version master --cfg=docsrs --cfg=unreleased_changelogs
run: |
cargo doc --no-deps -Z rustdoc-map -Z rustdoc-scrape-examples --features=serde,mint,android-native-activity
- name: Setup Pages
uses: actions/configure-pages@v6
- name: Fix permissions
run: |
chmod -c -R +rX "target/doc" | while read line; do
echo "::warning title=Invalid file permissions automatically fixed::$line"
done
- name: Upload artifact
uses: actions/upload-pages-artifact@v5
with:
path: target/doc
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v5

6
.gitignore vendored
View File

@@ -3,8 +3,8 @@ target/
rls/
.vscode/
*~
*.wasm
*.ts
*.js
#*#
.DS_Store
# NPM package used to run ESLint.
/src/platform_impl/web/script/node_modules
/src/platform_impl/web/script/package-lock.json

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "deps/apk-builder"]
path = deps/apk-builder
url = https://github.com/rust-windowing/android-rs-glue

View File

@@ -1,951 +1,8 @@
# Changelog
Changelog entries should be put in the [`changelog::unreleased`].
All notable changes to this project will be documented in this file.
The changelog can also be viewed [on docs.rs][docs_rs] or [on the current
master docs][master_docs].
Please keep one empty line before and after all headers. (This is required for `git` to produce a conflict when a release is made while a PR is open and the PR's changelog entry would go into the wrong section).
And please only add new entries to the top of this list, right below the `# Unreleased` header.
# Unreleased
# 0.28.3
- Fix macOS memory leaks.
# 0.28.2
- Implement `HasRawDisplayHandle` for `EventLoop`.
- On macOS, set resize increments only for live resizes.
- On Wayland, fix rare crash on DPI change
- Web: Added support for `Window::theme`.
- On Wayland, fix rounding issues when doing resize.
- On macOS, fix wrong focused state on startup.
- On Windows, fix crash on setting taskbar when using Visual Studio debugger.
- On macOS, resize simple fullscreen windows on windowDidChangeScreen events.
# 0.28.1
- On Wayland, fix crash when dropping a window in multi-window setup.
# 0.28.0
- On macOS, fixed `Ime::Commit` persisting for all input after interacting with `Ime`.
- On macOS, added `WindowExtMacOS::option_as_alt` and `WindowExtMacOS::set_option_as_alt`.
- On Windows, fix window size for maximized, undecorated windows.
- On Windows and macOS, add `WindowBuilder::with_active`.
- Add `Window::is_minimized`.
- On X11, fix errors handled during `register_xlib_error_hook` invocation bleeding into winit.
- Add `Window::has_focus`.
- On Windows, fix `Window::set_minimized(false)` not working for windows minimized by `Win + D` hotkey.
- **Breaking:** On Web, touch input no longer fires `WindowEvent::Cursor*`, `WindowEvent::MouseInput`, or `DeviceEvent::MouseMotion` like other platforms, but instead it fires `WindowEvent::Touch`.
- **Breaking:** Removed platform specific `WindowBuilder::with_parent` API in favor of `WindowBuilder::with_parent_window`.
- On Windows, retain `WS_MAXIMIZE` window style when un-minimizing a maximized window.
- On Windows, fix left mouse button release event not being sent after `Window::drag_window`.
- On macOS, run most actions on the main thread, which is strictly more correct, but might make multithreaded applications block slightly more.
- On macOS, fix panic when getting current monitor without any monitor attached.
- On Windows and MacOS, add API to enable/disable window buttons (close, minimize, ...etc).
- On Windows, macOS, X11 and Wayland, add `Window::set_theme`.
- **Breaking:** Remove `WindowExtWayland::wayland_set_csd_theme` and `WindowBuilderExtX11::with_gtk_theme_variant`.
- On Windows, revert window background to an empty brush to avoid white flashes when changing scaling.
- **Breaking:** Removed `Window::set_always_on_top` and related APIs in favor of `Window::set_window_level`.
- On Windows, MacOS and X11, add always on bottom APIs.
- On Windows, fix the value in `MouseButton::Other`.
- On macOS, add `WindowExtMacOS::is_document_edited` and `WindowExtMacOS::set_document_edited` APIs.
- **Breaking:** Removed `WindowBuilderExtIOS::with_root_view_class`; instead, you should use `[[view layer] addSublayer: ...]` to add an instance of the desired layer class (e.g. `CAEAGLLayer` or `CAMetalLayer`). See `vulkano-win` or `wgpu` for examples of this.
- On MacOS and Windows, add `Window::set_content_protected`.
- On MacOS, add `EventLoopBuilderExtMacOS::with_activate_ignoring_other_apps`.
- On Windows, fix icons specified on `WindowBuilder` not taking effect for windows created after the first one.
- On Windows and macOS, add `Window::title` to query the current window title.
- On Windows, fix focusing menubar when pressing `Alt`.
- On MacOS, made `accepts_first_mouse` configurable.
- Migrated `WindowBuilderExtUnix::with_resize_increments` to `WindowBuilder`.
- Added `Window::resize_increments`/`Window::set_resize_increments` to update resize increments at runtime for X11/macOS.
- macOS/iOS: Use `objc2` instead of `objc` internally.
- **Breaking:** Bump MSRV from `1.57` to `1.60`.
- **Breaking:** Split the `platform::unix` module into `platform::x11` and `platform::wayland`. The extension types are similarly renamed.
- **Breaking:**: Removed deprecated method `platform::unix::WindowExtUnix::is_ready`.
- Removed `parking_lot` dependency.
- **Breaking:** On macOS, add support for two-finger touchpad magnification and rotation gestures with new events `WindowEvent::TouchpadMagnify` and `WindowEvent::TouchpadRotate`. Also add support for touchpad smart-magnification gesture with a new event `WindowEvent::SmartMagnify`.
- **Breaking:** On web, the `WindowBuilderExtWebSys::with_prevent_default` setting (enabled by default), now additionally prevents scrolling of the webpage in mobile browsers, previously it only disabled scrolling on desktop.
- On Wayland, `wayland-csd-adwaita` now uses `ab_glyph` instead of `crossfont` to render the title for decorations.
- On Wayland, a new `wayland-csd-adwaita-crossfont` feature was added to use `crossfont` instead of `ab_glyph` for decorations.
- On Wayland, if not otherwise specified use upstream automatic CSD theme selection.
- On X11, added `WindowExtX11::with_parent` to create child windows.
- Added support for `WindowBuilder::with_theme` and `Window::theme` to support per-window dark/light/system theme configuration on macos, windows and wayland.
- On macOS, added support for `WindowEvent::ThemeChanged`.
- **Breaking:** Removed `WindowBuilderExtWindows::with_theme` and `WindowBuilderExtWayland::with_wayland_csd_theme` in favour of `WindowBuilder::with_theme`.
- **Breaking:** Removed `WindowExtWindows::theme` in favour of `Window::theme`.
- Enabled `doc_auto_cfg` when generating docs on docs.rs for feature labels.
- **Breaking:** On Android, switched to using [`android-activity`](https://github.com/rib/android-activity) crate as a glue layer instead of [`ndk-glue`](https://github.com/rust-windowing/android-ndk-rs/tree/master/ndk-glue). See [README.md#Android](https://github.com/rust-windowing/winit#Android) for more details. ([#2444](https://github.com/rust-windowing/winit/pull/2444))
- **Breaking:** Removed support for `raw-window-handle` version `0.4`
- On Wayland, `RedrawRequested` not emitted during resize.
- Add a `set_wait_timeout` function to `ControlFlow` to allow waiting for a `Duration`.
- **Breaking:** Remove the unstable `xlib_xconnection()` function from the private interface.
- Added Orbital support for Redox OS
- On X11, added `drag_resize_window` method.
- Added `Window::set_transparent` to provide a hint about transparency of the window on Wayland and macOS.
- On macOS, fix the mouse buttons other than left/right/middle being reported as middle.
- On Wayland, support fractional scaling via the wp-fractional-scale protocol.
- On web, fix removal of mouse event listeners from the global object upon window distruction.
- Add WindowAttributes getter to WindowBuilder to allow introspection of default values.
- Added `Window::set_ime_purpose` for setting the IME purpose, currently implemented on Wayland only.
# 0.27.5
- On Wayland, fix byte offset in `Ime::Preedit` pointing to invalid bytes.
# 0.27.4
- On Windows, emit `ReceivedCharacter` events on system keybindings.
- On Windows, fixed focus event emission on minimize.
- On X11, fixed IME crashing during reload.
# 0.27.3
- On Windows, added `WindowExtWindows::set_undecorated_shadow` and `WindowBuilderExtWindows::with_undecorated_shadow` to draw the drop shadow behind a borderless window.
- On Windows, fixed default window features (ie snap, animations, shake, etc.) when decorations are disabled.
- On Windows, fixed ALT+Space shortcut to open window menu.
- On Wayland, fixed `Ime::Preedit` not being sent on IME reset.
- Fixed unbound version specified for `raw-window-handle` leading to compilation failures.
- Empty `Ime::Preedit` event will be sent before `Ime::Commit` to help clearing preedit.
- On X11, fixed IME context picking by querying for supported styles beforehand.
# 0.27.2 (2022-8-12)
- On macOS, fixed touch phase reporting when scrolling.
- On X11, fix min, max and resize increment hints not persisting for resizable windows (e.g. on DPI change).
- On Windows, respect min/max inner sizes when creating the window.
- For backwards compatibility, `Window` now (additionally) implements the old version (`0.4`) of the `HasRawWindowHandle` trait
- On Windows, added support for `EventLoopWindowTarget::set_device_event_filter`.
- On Wayland, fix user requested `WindowEvent::RedrawRequested` being delayed by a frame.
# 0.27.1 (2022-07-30)
- The minimum supported Rust version was lowered to `1.57.0` and now explicitly tested.
- On X11, fix crash on start due to inability to create an IME context without any preedit.
# 0.27.0 (2022-07-26)
- On Windows, fix hiding a maximized window.
- On Android, `ndk-glue`'s `NativeWindow` lock is now held between `Event::Resumed` and `Event::Suspended`.
- On Web, added `EventLoopExtWebSys` with a `spawn` method to start the event loop without throwing an exception.
- Added `WindowEvent::Occluded(bool)`, currently implemented on macOS and X11.
- On X11, fix events for caps lock key not being sent
- Build docs on `docs.rs` for iOS and Android as well.
- **Breaking:** Removed the `WindowAttributes` struct, since all its functionality is accessible from `WindowBuilder`.
- Added `WindowBuilder::transparent` getter to check if the user set `transparent` attribute.
- On macOS, Fix emitting `Event::LoopDestroyed` on CMD+Q.
- On macOS, fixed an issue where having multiple windows would prevent run_return from ever returning.
- On Wayland, fix bug where the cursor wouldn't hide in GNOME.
- On macOS, Windows, and Wayland, add `set_cursor_hittest` to let the window ignore mouse events.
- On Windows, added `WindowExtWindows::set_skip_taskbar` and `WindowBuilderExtWindows::with_skip_taskbar`.
- On Windows, added `EventLoopBuilderExtWindows::with_msg_hook`.
- On Windows, remove internally unique DC per window.
- On macOS, remove the need to call `set_ime_position` after moving the window.
- Added `Window::is_visible`.
- Added `Window::is_resizable`.
- Added `Window::is_decorated`.
- On X11, fix for repeated event loop iteration when `ControlFlow` was `Wait`
- On X11, fix scale factor calculation when the only monitor is reconnected
- On Wayland, report unaccelerated mouse deltas in `DeviceEvent::MouseMotion`.
- On Web, a focused event is manually generated when a click occurs to emulate behaviour of other backends.
- **Breaking:** Bump `ndk` version to 0.6, ndk-sys to `v0.3`, `ndk-glue` to `0.6`.
- Remove no longer needed `WINIT_LINK_COLORSYNC` environment variable.
- **Breaking:** Rename the `Exit` variant of `ControlFlow` to `ExitWithCode`, which holds a value to control the exit code after running. Add an `Exit` constant which aliases to `ExitWithCode(0)` instead to avoid major breakage. This shouldn't affect most existing programs.
- Add `EventLoopBuilder`, which allows you to create and tweak the settings of an event loop before creating it.
- Deprecated `EventLoop::with_user_event`; use `EventLoopBuilder::with_user_event` instead.
- **Breaking:** Replaced `EventLoopExtMacOS` with `EventLoopBuilderExtMacOS` (which also has renamed methods).
- **Breaking:** Replaced `EventLoopExtWindows` with `EventLoopBuilderExtWindows` (which also has renamed methods).
- **Breaking:** Replaced `EventLoopExtUnix` with `EventLoopBuilderExtUnix` (which also has renamed methods).
- **Breaking:** The platform specific extensions for Windows `winit::platform::windows` have changed. All `HANDLE`-like types e.g. `HWND` and `HMENU` were converted from winapi types or `*mut c_void` to `isize`. This was done to be consistent with the type definitions in windows-sys and to not expose internal dependencies.
- The internal bindings to the [Windows API](https://docs.microsoft.com/en-us/windows/) were changed from the unofficial [winapi](https://github.com/retep998/winapi-rs) bindings to the official Microsoft [windows-sys](https://github.com/microsoft/windows-rs) bindings.
- On Wayland, fix polling during consecutive `EventLoop::run_return` invocations.
- On Windows, fix race issue creating fullscreen windows with `WindowBuilder::with_fullscreen`
- On Android, `virtual_keycode` for `KeyboardInput` events is now filled in where a suitable match is found.
- Added helper methods on `ControlFlow` to set its value.
- On Wayland, fix `TouchPhase::Ended` always reporting the location of the first touch down, unless the compositor
sent a cancel or frame event.
- On iOS, send `RedrawEventsCleared` even if there are no redraw events, consistent with other platforms.
- **Breaking:** Replaced `Window::with_app_id` and `Window::with_class` with `Window::with_name` on `WindowBuilderExtUnix`.
- On Wayland, fallback CSD was replaced with proper one:
- `WindowBuilderExtUnix::with_wayland_csd_theme` to set color theme in builder.
- `WindowExtUnix::wayland_set_csd_theme` to set color theme when creating a window.
- `WINIT_WAYLAND_CSD_THEME` env variable was added, it can be used to set "dark"/"light" theme in apps that don't expose theme setting.
- `wayland-csd-adwaita` feature that enables proper CSD with title rendering using FreeType system library.
- `wayland-csd-adwaita-notitle` feature that enables CSD but without title rendering.
- On Wayland and X11, fix window not resizing with `Window::set_inner_size` after calling `Window:set_resizable(false)`.
- On Windows, fix wrong fullscreen monitors being recognized when handling WM_WINDOWPOSCHANGING messages
- **Breaking:** Added new `WindowEvent::Ime` supported on desktop platforms.
- Added `Window::set_ime_allowed` supported on desktop platforms.
- **Breaking:** IME input on desktop platforms won't be received unless it's explicitly allowed via `Window::set_ime_allowed` and new `WindowEvent::Ime` events are handled.
- On macOS, `WindowEvent::Resized` is now emitted in `frameDidChange` instead of `windowDidResize`.
- **Breaking:** On X11, device events are now ignored for unfocused windows by default, use `EventLoopWindowTarget::set_device_event_filter` to set the filter level.
- Implemented `Default` on `EventLoop<()>`.
- Implemented `Eq` for `Fullscreen`, `Theme`, and `UserAttentionType`.
- **Breaking:** `Window::set_cursor_grab` now accepts `CursorGrabMode` to control grabbing behavior.
- On Wayland, add support for `Window::set_cursor_position`.
- Fix on macOS `WindowBuilder::with_disallow_hidpi`, setting true or false by the user no matter the SO default value.
- `EventLoopBuilder::build` will now panic when the `EventLoop` is being created more than once.
- Added `From<u64>` for `WindowId` and `From<WindowId>` for `u64`.
- Added `MonitorHandle::refresh_rate_millihertz` to get monitor's refresh rate.
- **Breaking**, Replaced `VideoMode::refresh_rate` with `VideoMode::refresh_rate_millihertz` providing better precision.
- On Web, add `with_prevent_default` and `with_focusable` to `WindowBuilderExtWebSys` to control whether events should be propagated.
- On Windows, fix focus events being sent to inactive windows.
- **Breaking**, update `raw-window-handle` to `v0.5` and implement `HasRawDisplayHandle` for `Window` and `EventLoopWindowTarget`.
- On X11, add function `register_xlib_error_hook` into `winit::platform::unix` to subscribe for errors comming from Xlib.
- On Android, upgrade `ndk` and `ndk-glue` dependencies to the recently released `0.7.0`.
- All platforms can now be relied on to emit a `Resumed` event. Applications are recommended to lazily initialize graphics state and windows on first resume for portability.
- **Breaking:**: Reverse horizontal scrolling sign in `MouseScrollDelta` to match the direction of vertical scrolling. A positive X value now means moving the content to the right. The meaning of vertical scrolling stays the same: a positive Y value means moving the content down.
- On MacOS, fix deadlock when calling `set_maximized` from event loop.
# 0.26.1 (2022-01-05)
- Fix linking to the `ColorSync` framework on macOS 10.7, and in newer Rust versions.
- On Web, implement cursor grabbing through the pointer lock API.
- On X11, add mappings for numpad comma, numpad enter, numlock and pause.
- On macOS, fix Pinyin IME input by reverting a change that intended to improve IME.
- On Windows, fix a crash with transparent windows on Windows 11.
# 0.26.0 (2021-12-01)
- Update `raw-window-handle` to `v0.4`. This is _not_ a breaking change, we still implement `HasRawWindowHandle` from `v0.3`, see [rust-windowing/raw-window-handle#74](https://github.com/rust-windowing/raw-window-handle/pull/74). Note that you might have to run `cargo update -p raw-window-handle` after upgrading.
- On X11, bump `mio` to 0.8.
- On Android, fixed `WindowExtAndroid::config` initially returning an empty `Configuration`.
- On Android, fixed `Window::scale_factor` and `MonitorHandle::scale_factor` initially always returning 1.0.
- On X11, select an appropriate visual for transparency if is requested
- On Wayland and X11, fix diagonal window resize cursor orientation.
- On macOS, drop the event callback before exiting.
- On Android, implement `Window::request_redraw`
- **Breaking:** On Web, remove the `stdweb` backend.
- Added `Window::focus_window`to bring the window to the front and set input focus.
- On Wayland and X11, implement `is_maximized` method on `Window`.
- On Windows, prevent ghost window from showing up in the taskbar after either several hours of use or restarting `explorer.exe`.
- On macOS, fix issue where `ReceivedCharacter` was not being emitted during some key repeat events.
- On Wayland, load cursor icons `hand2` and `hand1` for `CursorIcon::Hand`.
- **Breaking:** On Wayland, Theme trait and its support types are dropped.
- On Wayland, bump `smithay-client-toolkit` to 0.15.1.
- On Wayland, implement `request_user_attention` with `xdg_activation_v1`.
- On X11, emit missing `WindowEvent::ScaleFactorChanged` when the only monitor gets reconnected.
- On X11, if RANDR based scale factor is higher than 20 reset it to 1
- On Wayland, add an enabled-by-default feature called `wayland-dlopen` so users can opt out of using `dlopen` to load system libraries.
- **Breaking:** On Android, bump `ndk` and `ndk-glue` to 0.5.
- On Windows, increase wait timer resolution for more accurate timing when using `WaitUntil`.
- On macOS, fix native file dialogs hanging the event loop.
- On Wayland, implement a workaround for wrong configure size when using `xdg_decoration` in `kwin_wayland`
- On macOS, fix an issue that prevented the menu bar from showing in borderless fullscreen mode.
- On X11, EINTR while polling for events no longer causes a panic. Instead it will be treated as a spurious wakeup.
# 0.25.0 (2021-05-15)
- **Breaking:** On macOS, replace `WindowBuilderExtMacOS::with_activation_policy` with `EventLoopExtMacOS::set_activation_policy`
- On macOS, wait with activating the application until the application has initialized.
- On macOS, fix creating new windows when the application has a main menu.
- On Windows, fix fractional deltas for mouse wheel device events.
- On macOS, fix segmentation fault after dropping the main window.
- On Android, `InputEvent::KeyEvent` is partially implemented providing the key scancode.
- Added `is_maximized` method to `Window`.
- On Windows, fix bug where clicking the decoration bar would make the cursor blink.
- On Windows, fix bug causing newly created windows to erroneously display the "wait" (spinning) cursor.
- On macOS, wake up the event loop immediately when a redraw is requested.
- On Windows, change the default window size (1024x768) to match the default on other desktop platforms (800x600).
- On Windows, fix bug causing mouse capture to not be released.
- On Windows, fix fullscreen not preserving minimized/maximized state.
- On Android, unimplemented events are marked as unhandled on the native event loop.
- On Windows, added `WindowBuilderExtWindows::with_menu` to set a custom menu at window creation time.
- On Android, bump `ndk` and `ndk-glue` to 0.3: use predefined constants for event `ident`.
- On macOS, fix objects captured by the event loop closure not being dropped on panic.
- On Windows, fixed `WindowEvent::ThemeChanged` not properly firing and fixed `Window::theme` returning the wrong theme.
- On Web, added support for `DeviceEvent::MouseMotion` to listen for relative mouse movements.
- Added `WindowBuilder::with_position` to allow setting the position of a `Window` on creation. Supported on Windows, macOS and X11.
- Added `Window::drag_window`. Implemented on Windows, macOS, X11 and Wayland.
- On X11, bump `mio` to 0.7.
- On Windows, added `WindowBuilderExtWindows::with_owner_window` to allow creating popup windows.
- On Windows, added `WindowExtWindows::set_enable` to allow creating modal popup windows.
- On macOS, emit `RedrawRequested` events immediately while the window is being resized.
- Implement `Default`, `Hash`, and `Eq` for `LogicalPosition`, `PhysicalPosition`, `LogicalSize`, and `PhysicalSize`.
- On macOS, initialize the Menu Bar with minimal defaults. (Can be prevented using `enable_default_menu_creation`)
- On macOS, change the default behavior for first click when the window was unfocused. Now the window becomes focused and then emits a `MouseInput` event on a "first mouse click".
- Implement mint (math interoperability standard types) conversions (under feature flag `mint`).
# 0.24.0 (2020-12-09)
- On Windows, fix applications not exiting gracefully due to thread_event_target_callback accessing corrupted memory.
- On Windows, implement `Window::set_ime_position`.
- **Breaking:** On Windows, Renamed `WindowBuilderExtWindows`'s `is_dark_mode` to `theme`.
- **Breaking:** On Windows, renamed `WindowBuilderExtWindows::is_dark_mode` to `theme`.
- On Windows, add `WindowBuilderExtWindows::with_theme` to set a preferred theme.
- On Windows, fix bug causing message boxes to appear delayed.
- On Android, calling `WindowEvent::Focused` now works properly instead of always returning false.
- On Windows, fix Alt-Tab behaviour by removing borderless fullscreen "always on top" flag.
- On Windows, fix bug preventing windows with transparency enabled from having fully-opaque regions.
- **Breaking:** On Windows, include prefix byte in scancodes.
- On Wayland, fix window not being resizeable when using `WindowBuilder::with_min_inner_size`.
- On Unix, fix cross-compiling to wasm32 without enabling X11 or Wayland.
- On Windows, fix use-after-free crash during window destruction.
- On Web, fix `WindowEvent::ReceivedCharacter` never being sent on key input.
- On macOS, fix compilation when targeting aarch64.
- On X11, fix `Window::request_redraw` not waking the event loop.
- On Wayland, the keypad arrow keys are now recognized.
- **Breaking** Rename `desktop::EventLoopExtDesktop` to `run_return::EventLoopExtRunReturn`.
- Added `request_user_attention` method to `Window`.
- **Breaking:** On macOS, removed `WindowExt::request_user_attention`, use `Window::request_user_attention`.
- **Breaking:** On X11, removed `WindowExt::set_urgent`, use `Window::request_user_attention`.
- On Wayland, default font size in CSD increased from 11 to 17.
- On Windows, fix bug causing message boxes to appear delayed.
- On Android, support multi-touch.
- On Wayland, extra mouse buttons are not dropped anymore.
- **Breaking**: `MouseButton::Other` now uses `u16`.
# 0.23.0 (2020-10-02)
- On iOS, fixed support for the "Debug View Heirarchy" feature in Xcode.
- On all platforms, `available_monitors` and `primary_monitor` are now on `EventLoopWindowTarget` rather than `EventLoop` to list monitors event in the event loop.
- On Unix, X11 and Wayland are now optional features (enabled by default)
- On X11, fix deadlock when calling `set_fullscreen_inner`.
- On Web, prevent the webpage from scrolling when the user is focused on a winit canvas
- On Web, calling `window.set_cursor_icon` no longer breaks HiDPI scaling
- On Windows, drag and drop is now optional (enabled by default) and can be disabled with `WindowBuilderExtWindows::with_drag_and_drop(false)`.
- On Wayland, fix deadlock when calling to `set_inner_size` from a callback.
- On macOS, add `hide__other_applications` to `EventLoopWindowTarget` via existing `EventLoopWindowTargetExtMacOS` trait. `hide_other_applications` will hide other applications by calling `-[NSApplication hideOtherApplications: nil]`.
- On android added support for `run_return`.
- On MacOS, Fixed fullscreen and dialog support for `run_return`.
- On Windows, fix bug where we'd try to emit `MainEventsCleared` events during nested win32 event loops.
- On Web, use mouse events if pointer events aren't supported. This affects Safari.
- On Windows, `set_ime_position` is now a no-op instead of a runtime crash.
- On Android, `set_fullscreen` is now a no-op instead of a runtime crash.
- On iOS and Android, `set_inner_size` is now a no-op instead of a runtime crash.
- On Android, fix `ControlFlow::Poll` not polling the Android event queue.
- On macOS, add `NSWindow.hasShadow` support.
- On Web, fix vertical mouse wheel scrolling being inverted.
- On Web, implement mouse capturing for click-dragging out of the canvas.
- On Web, fix `ControlFlow::Exit` not properly handled.
- On Web (web-sys only), send `WindowEvent::ScaleFactorChanged` event when `window.devicePixelRatio` is changed.
- **Breaking:** On Web, `set_cursor_position` and `set_cursor_grab` will now always return an error.
- **Breaking:** `PixelDelta` scroll events now return a `PhysicalPosition`.
- On NetBSD, fixed crash due to incorrect detection of the main thread.
- **Breaking:** On X11, `-` key is mapped to the `Minus` virtual key code, instead of `Subtract`.
- On macOS, fix inverted horizontal scroll.
- **Breaking:** `current_monitor` now returns `Option<MonitorHandle>`.
- **Breaking:** `primary_monitor` now returns `Option<MonitorHandle>`.
- On macOS, updated core-* dependencies and cocoa.
- Bump `parking_lot` to 0.11
- On Android, bump `ndk`, `ndk-sys` and `ndk-glue` to 0.2. Checkout the new ndk-glue main proc attribute.
- On iOS, fixed starting the app in landscape where the view still had portrait dimensions.
- Deprecate the stdweb backend, to be removed in a future release
- **Breaking:** Prefixed virtual key codes `Add`, `Multiply`, `Divide`, `Decimal`, and `Subtract` with `Numpad`.
- Added `Asterisk` and `Plus` virtual key codes.
- On Web (web-sys only), the `Event::LoopDestroyed` event is correctly emitted when leaving the page.
- On Web, the `WindowEvent::Destroyed` event now gets emitted when a `Window` is dropped.
- On Web (web-sys only), the event listeners are now removed when a `Window` is dropped or when the event loop is destroyed.
- On Web, the event handler closure passed to `EventLoop::run` now gets dropped after the event loop is destroyed.
- **Breaking:** On Web, the canvas element associated to a `Window` is no longer removed from the DOM when the `Window` is dropped.
- On Web, `WindowEvent::Resized` is now emitted when `Window::set_inner_size` is called.
- **Breaking:** `Fullscreen` enum now uses `Borderless(Option<MonitorHandle>)` instead of `Borderless(MonitorHandle)` to allow picking the current monitor.
- On MacOS, fix `WindowEvent::Moved` ignoring the scale factor.
- On Wayland, add missing virtual keycodes.
- On Wayland, implement proper `set_cursor_grab`.
- On Wayland, the cursor will use similar icons if the requested one isn't available.
- On Wayland, right clicking on client side decorations will request application menu.
- On Wayland, fix tracking of window size after state changes.
- On Wayland, fix client side decorations not being hidden properly in fullscreen.
- On Wayland, fix incorrect size event when entering fullscreen with client side decorations.
- On Wayland, fix `resizable` attribute not being applied properly on startup.
- On Wayland, fix disabled repeat rate not being handled.
- On Wayland, fix decoration buttons not working after tty switch.
- On Wayland, fix scaling not being applied on output re-enable.
- On Wayland, fix crash when `XCURSOR_SIZE` is `0`.
- On Wayland, fix pointer getting created in some cases without pointer capability.
- On Wayland, on kwin, fix space between window and decorations on startup.
- **Breaking:** On Wayland, `Theme` trait was reworked.
- On Wayland, disable maximize button for non-resizable window.
- On Wayland, added support for `set_ime_position`.
- On Wayland, fix crash on startup since GNOME 3.37.90.
- On X11, fix incorrect modifiers state on startup.
# 0.22.2 (2020-05-16)
- Added Clone implementation for 'static events.
- On Windows, fix window intermittently hanging when `ControlFlow` was set to `Poll`.
- On Windows, fix `WindowBuilder::with_maximized` being ignored.
- On Android, minimal platform support.
- On iOS, touch positions are now properly converted to physical pixels.
- On macOS, updated core-* dependencies and cocoa
# 0.22.1 (2020-04-16)
- On X11, fix `ResumeTimeReached` being fired too early.
- On Web, replaced zero timeout for `ControlFlow::Poll` with `requestAnimationFrame`
- On Web, fix a possible panic during event handling
- On macOS, fix `EventLoopProxy` leaking memory for every instance.
# 0.22.0 (2020-03-09)
- On Windows, fix minor timing issue in wait_until_time_or_msg
- On Windows, rework handling of request_redraw() to address panics.
- On macOS, fix `set_simple_screen` to remember frame excluding title bar.
- On Wayland, fix coordinates in touch events when scale factor isn't 1.
- On Wayland, fix color from `close_button_icon_color` not applying.
- Ignore locale if unsupported by X11 backend
- On Wayland, Add HiDPI cursor support
- On Web, add the ability to query "Light" or "Dark" system theme send `ThemeChanged` on change.
- Fix `Event::to_static` returning `None` for user events.
- On Wayland, Hide CSD for fullscreen windows.
- On Windows, ignore spurious mouse move messages.
- **Breaking:** Move `ModifiersChanged` variant from `DeviceEvent` to `WindowEvent`.
- On Windows, add `IconExtWindows` trait which exposes creating an `Icon` from an external file or embedded resource
- Add `BadIcon::OsError` variant for when OS icon functionality fails
- On Windows, fix crash at startup on systems that do not properly support Windows' Dark Mode
- Revert On macOS, fix not sending ReceivedCharacter event for specific keys combinations.
- on macOS, fix incorrect ReceivedCharacter events for some key combinations.
- **Breaking:** Use `i32` instead of `u32` for position type in `WindowEvent::Moved`.
- On macOS, a mouse motion event is now generated before every mouse click.
# 0.21.0 (2020-02-04)
- On Windows, fixed "error: linking with `link.exe` failed: exit code: 1120" error on older versions of windows.
- On macOS, fix set_minimized(true) works only with decorations.
- On macOS, add `hide_application` to `EventLoopWindowTarget` via a new `EventLoopWindowTargetExtMacOS` trait. `hide_application` will hide the entire application by calling `-[NSApplication hide: nil]`.
- On macOS, fix not sending ReceivedCharacter event for specific keys combinations.
- On macOS, fix `CursorMoved` event reporting the cursor position using logical coordinates.
- On macOS, fix issue where unbundled applications would sometimes open without being focused.
- On macOS, fix `run_return` does not return unless it receives a message.
- On Windows, fix bug where `RedrawRequested` would only get emitted every other iteration of the event loop.
- On X11, fix deadlock on window state when handling certain window events.
- `WindowBuilder` now implements `Default`.
- **Breaking:** `WindowEvent::CursorMoved` changed to `f64` units, preserving high-precision data supplied by most backends
- On Wayland, fix coordinates in mouse events when scale factor isn't 1
- On Web, add the ability to provide a custom canvas
- **Breaking:** On Wayland, the `WaylandTheme` struct has been replaced with a `Theme` trait, allowing for extra configuration
# 0.20.0 (2020-01-05)
- On X11, fix `ModifiersChanged` emitting incorrect modifier change events
- **Breaking**: Overhaul how Winit handles DPI:
- Window functions and events now return `PhysicalSize` instead of `LogicalSize`.
- Functions that take `Size` or `Position` types can now take either `Logical` or `Physical` types.
- `hidpi_factor` has been renamed to `scale_factor`.
- `HiDpiFactorChanged` has been renamed to `ScaleFactorChanged`, and lets you control how the OS
resizes the window in response to the change.
- On X11, deprecate `WINIT_HIDPI_FACTOR` environment variable in favor of `WINIT_X11_SCALE_FACTOR`.
- `Size` and `Position` types are now generic over their exact pixel type.
# 0.20.0 Alpha 6 (2020-01-03)
- On macOS, fix `set_cursor_visible` hides cursor outside of window.
- On macOS, fix `CursorEntered` and `CursorLeft` events fired at old window size.
- On macOS, fix error when `set_fullscreen` is called during fullscreen transition.
- On all platforms except mobile and WASM, implement `Window::set_minimized`.
- On X11, fix `CursorEntered` event being generated for non-winit windows.
- On macOS, fix crash when starting maximized without decorations.
- On macOS, fix application not terminating on `run_return`.
- On Wayland, fix cursor icon updates on window borders when using CSD.
- On Wayland, under mutter(GNOME Wayland), fix CSD being behind the status bar, when starting window in maximized mode.
- On Windows, theme the title bar according to whether the system theme is "Light" or "Dark".
- Added `WindowEvent::ThemeChanged` variant to handle changes to the system theme. Currently only implemented on Windows.
- **Breaking**: Changes to the `RedrawRequested` event (#1041):
- `RedrawRequested` has been moved from `WindowEvent` to `Event`.
- `EventsCleared` has been renamed to `MainEventsCleared`.
- `RedrawRequested` is now issued only after `MainEventsCleared`.
- `RedrawEventsCleared` is issued after each set of `RedrawRequested` events.
- Implement synthetic window focus key events on Windows.
- **Breaking**: Change `ModifiersState` to a `bitflags` struct.
- On Windows, implement `VirtualKeyCode` translation for `LWin` and `RWin`.
- On Windows, fix closing the last opened window causing `DeviceEvent`s to stop getting emitted.
- On Windows, fix `Window::set_visible` not setting internal flags correctly. This resulted in some weird behavior.
- Add `DeviceEvent::ModifiersChanged`.
- Deprecate `modifiers` fields in other events in favor of `ModifiersChanged`.
- On X11, `WINIT_HIDPI_FACTOR` now dominates `Xft.dpi` when picking DPI factor for output.
- On X11, add special value `randr` for `WINIT_HIDPI_FACTOR` to make winit use self computed DPI factor instead of the one from `Xft.dpi`.
# 0.20.0 Alpha 5 (2019-12-09)
- On macOS, fix application termination on `ControlFlow::Exit`
- On Windows, fix missing `ReceivedCharacter` events when Alt is held.
- On macOS, stop emitting private corporate characters in `ReceivedCharacter` events.
- On X11, fix misreporting DPI factor at startup.
- On X11, fix events not being reported when using `run_return`.
- On X11, fix key modifiers being incorrectly reported.
- On X11, fix window creation hanging when another window is fullscreen.
- On Windows, fix focusing unfocused windows when switching from fullscreen to windowed.
- On X11, fix reporting incorrect DPI factor when waking from suspend.
- Change `EventLoopClosed` to contain the original event.
- **Breaking**: Add `is_synthetic` field to `WindowEvent` variant `KeyboardInput`,
indicating that the event is generated by winit.
- On X11, generate synthetic key events for keys held when a window gains or loses focus.
- On X11, issue a `CursorMoved` event when a `Touch` event occurs,
as X11 implicitly moves the cursor for such events.
# 0.20.0 Alpha 4 (2019-10-18)
- Add web support via the 'stdweb' or 'web-sys' features
- On Windows, implemented function to get HINSTANCE
- On macOS, implement `run_return`.
- On iOS, fix inverted parameter in `set_prefers_home_indicator_hidden`.
- On X11, performance is improved when rapidly calling `Window::set_cursor_icon`.
- On iOS, fix improper `msg_send` usage that was UB and/or would break if `!` is stabilized.
- On Windows, unset `maximized` when manually changing the window's position or size.
- On Windows, add touch pressure information for touch events.
- On macOS, differentiate between `CursorIcon::Grab` and `CursorIcon::Grabbing`.
- On Wayland, fix event processing sometimes stalling when using OpenGL with vsync.
- Officially remove the Emscripten backend.
- On Windows, fix handling of surrogate pairs when dispatching `ReceivedCharacter`.
- On macOS 10.15, fix freeze upon exiting exclusive fullscreen mode.
- On iOS, fix panic upon closing the app.
- On X11, allow setting mulitple `XWindowType`s.
- On iOS, fix null window on initial `HiDpiFactorChanged` event.
- On Windows, fix fullscreen window shrinking upon getting restored to a normal window.
- On macOS, fix events not being emitted during modal loops, such as when windows are being resized
by the user.
- On Windows, fix hovering the mouse over the active window creating an endless stream of CursorMoved events.
- Always dispatch a `RedrawRequested` event after creating a new window.
- On X11, return dummy monitor data to avoid panicking when no monitors exist.
- On X11, prevent stealing input focus when creating a new window.
Only steal input focus when entering fullscreen mode.
- On Wayland, fixed DeviceEvents for relative mouse movement is not always produced
- On Wayland, add support for set_cursor_visible and set_cursor_grab.
- On Wayland, fixed DeviceEvents for relative mouse movement is not always produced.
- Removed `derivative` crate dependency.
- On Wayland, add support for set_cursor_icon.
- Use `impl Iterator<Item = MonitorHandle>` instead of `AvailableMonitorsIter` consistently.
- On macOS, fix fullscreen state being updated after entering fullscreen instead of before,
resulting in `Window::fullscreen` returning the old state in `Resized` events instead of
reflecting the new fullscreen state
- On X11, fix use-after-free during window creation
- On Windows, disable monitor change keyboard shortcut while in exclusive fullscreen.
- On Windows, ensure that changing a borderless fullscreen window's monitor via keyboard shortcuts keeps the window fullscreen on the new monitor.
- Prevent `EventLoop::new` and `EventLoop::with_user_event` from getting called outside the main thread.
- This is because some platforms cannot run the event loop outside the main thread. Preventing this
reduces the potential for cross-platform compatibility gotchyas.
- On Windows and Linux X11/Wayland, add platform-specific functions for creating an `EventLoop` outside the main thread.
- On Wayland, drop resize events identical to the current window size.
- On Windows, fix window rectangle not getting set correctly on high-DPI systems.
# 0.20.0 Alpha 3 (2019-08-14)
- On macOS, drop the run closure on exit.
- On Windows, location of `WindowEvent::Touch` are window client coordinates instead of screen coordinates.
- On X11, fix delayed events after window redraw.
- On macOS, add `WindowBuilderExt::with_disallow_hidpi` to have the option to turn off best resolution openGL surface.
- On Windows, screen saver won't start if the window is in fullscreen mode.
- Change all occurrences of the `new_user_event` method to `with_user_event`.
- On macOS, the dock and the menu bar are now hidden in fullscreen mode.
- `Window::set_fullscreen` now takes `Option<Fullscreen>` where `Fullscreen`
consists of `Fullscreen::Exclusive(VideoMode)` and
`Fullscreen::Borderless(MonitorHandle)` variants.
- Adds support for exclusive fullscreen mode.
- On iOS, add support for hiding the home indicator.
- On iOS, add support for deferring system gestures.
- On iOS, fix a crash that occurred while acquiring a monitor's name.
- On iOS, fix armv7-apple-ios compile target.
- Removed the `T: Clone` requirement from the `Clone` impl of `EventLoopProxy<T>`.
- On iOS, disable overscan compensation for external displays (removes black
bars surrounding the image).
- On Linux, the functions `is_wayland`, `is_x11`, `xlib_xconnection` and `wayland_display` have been moved to a new `EventLoopWindowTargetExtUnix` trait.
- On iOS, add `set_prefers_status_bar_hidden` extension function instead of
hijacking `set_decorations` for this purpose.
- On macOS and iOS, corrected the auto trait impls of `EventLoopProxy`.
- On iOS, add touch pressure information for touch events.
- Implement `raw_window_handle::HasRawWindowHandle` for `Window` type on all supported platforms.
- On macOS, fix the signature of `-[NSView drawRect:]`.
- On iOS, fix the behavior of `ControlFlow::Poll`. It wasn't polling if that was the only mode ever used by the application.
- On iOS, fix DPI sent out by views on creation was `0.0` - now it gives a reasonable number.
- On iOS, RedrawRequested now works for gl/metal backed views.
- On iOS, RedrawRequested is generally ordered after EventsCleared.
# 0.20.0 Alpha 2 (2019-07-09)
- On X11, non-resizable windows now have maximize explicitly disabled.
- On Windows, support paths longer than MAX_PATH (260 characters) in `WindowEvent::DroppedFile`
and `WindowEvent::HoveredFile`.
- On Mac, implement `DeviceEvent::Button`.
- Change `Event::Suspended(true / false)` to `Event::Suspended` and `Event::Resumed`.
- On X11, fix sanity check which checks that a monitor's reported width and height (in millimeters) are non-zero when calculating the DPI factor.
- Revert the use of invisible surfaces in Wayland, which introduced graphical glitches with OpenGL (#835)
- On X11, implement `_NET_WM_PING` to allow desktop environment to kill unresponsive programs.
- On Windows, when a window is initially invisible, it won't take focus from the existing visible windows.
- On Windows, fix multiple calls to `request_redraw` during `EventsCleared` sending multiple `RedrawRequested events.`
- On Windows, fix edge case where `RedrawRequested` could be dispatched before input events in event loop iteration.
- On Windows, fix timing issue that could cause events to be improperly dispatched after `RedrawRequested` but before `EventsCleared`.
- On macOS, drop unused Metal dependency.
- On Windows, fix the trail effect happening on transparent decorated windows. Borderless (or un-decorated) windows were not affected.
- On Windows, fix `with_maximized` not properly setting window size to entire window.
- On macOS, change `WindowExtMacOS::request_user_attention()` to take an `enum` instead of a `bool`.
# 0.20.0 Alpha 1 (2019-06-21)
- Changes below are considered **breaking**.
- Change all occurrences of `EventsLoop` to `EventLoop`.
- Previously flat API is now exposed through `event`, `event_loop`, `monitor`, and `window` modules.
- `os` module changes:
- Renamed to `platform`.
- All traits now have platform-specific suffixes.
- Exposes new `desktop` module on Windows, Mac, and Linux.
- Changes to event loop types:
- `EventLoopProxy::wakeup` has been removed in favor of `send_event`.
- **Major:** New `run` method drives winit event loop.
- Returns `!` to ensure API behaves identically across all supported platforms.
- This allows `emscripten` implementation to work without lying about the API.
- `ControlFlow`'s variants have been replaced with `Wait`, `WaitUntil(Instant)`, `Poll`, and `Exit`.
- Is read after `EventsCleared` is processed.
- `Wait` waits until new events are available.
- `WaitUntil` waits until either new events are available or the provided time has been reached.
- `Poll` instantly resumes the event loop.
- `Exit` aborts the event loop.
- Takes a closure that implements `'static + FnMut(Event<T>, &EventLoop<T>, &mut ControlFlow)`.
- `&EventLoop<T>` is provided to allow new `Window`s to be created.
- **Major:** `platform::desktop` module exposes `EventLoopExtDesktop` trait with `run_return` method.
- Behaves identically to `run`, but returns control flow to the calling context and can take non-`'static` closures.
- `EventLoop`'s `poll_events` and `run_forever` methods have been removed in favor of `run` and `run_return`.
- Changes to events:
- Remove `Event::Awakened` in favor of `Event::UserEvent(T)`.
- Can be sent with `EventLoopProxy::send_event`.
- Rename `WindowEvent::Refresh` to `WindowEvent::RedrawRequested`.
- `RedrawRequested` can be sent by the user with the `Window::request_redraw` method.
- `EventLoop`, `EventLoopProxy`, and `Event` are now generic over `T`, for use in `UserEvent`.
- **Major:** Add `NewEvents(StartCause)`, `EventsCleared`, and `LoopDestroyed` variants to `Event`.
- `NewEvents` is emitted when new events are ready to be processed by event loop.
- `StartCause` describes why new events are available, with `ResumeTimeReached`, `Poll`, `WaitCancelled`, and `Init` (sent once at start of loop).
- `EventsCleared` is emitted when all available events have been processed.
- Can be used to perform logic that depends on all events being processed (e.g. an iteration of a game loop).
- `LoopDestroyed` is emitted when the `run` or `run_return` method is about to exit.
- Rename `MonitorId` to `MonitorHandle`.
- Removed `serde` implementations from `ControlFlow`.
- Rename several functions to improve both internal consistency and compliance with Rust API guidelines.
- Remove `WindowBuilder::multitouch` field, since it was only implemented on a few platforms. Multitouch is always enabled now.
- **Breaking:** On macOS, change `ns` identifiers to use snake_case for consistency with iOS's `ui` identifiers.
- Add `MonitorHandle::video_modes` method for retrieving supported video modes for the given monitor.
- On Wayland, the window now exists even if nothing has been drawn.
- On Windows, fix initial dimensions of a fullscreen window.
- On Windows, Fix transparent borderless windows rendering wrong.
# Version 0.19.1 (2019-04-08)
- On Wayland, added a `get_wayland_display` function to `EventsLoopExt`.
- On Windows, fix `CursorMoved(0, 0)` getting dispatched on window focus.
- On macOS, fix command key event left and right reverse.
- On FreeBSD, NetBSD, and OpenBSD, fix build of X11 backend.
- On Linux, the numpad's add, subtract and divide keys are now mapped to the `Add`, `Subtract` and `Divide` virtual key codes
- On macOS, the numpad's subtract key has been added to the `Subtract` mapping
- On Wayland, the numpad's home, end, page up and page down keys are now mapped to the `Home`, `End`, `PageUp` and `PageDown` virtual key codes
- On Windows, fix icon not showing up in corner of window.
- On X11, change DPI scaling factor behavior. First, winit tries to read it from "Xft.dpi" XResource, and uses DPI calculation from xrandr dimensions as fallback behavior.
# Version 0.19.0 (2019-03-06)
- On X11, we will use the faster `XRRGetScreenResourcesCurrent` function instead of `XRRGetScreenResources` when available.
- On macOS, fix keycodes being incorrect when using a non-US keyboard layout.
- On Wayland, fix `with_title()` not setting the windows title
- On Wayland, add `set_wayland_theme()` to control client decoration color theme
- Added serde serialization to `os::unix::XWindowType`.
- **Breaking:** Remove the `icon_loading` feature and the associated `image` dependency.
- On X11, make event loop thread safe by replacing XNextEvent with select(2) and XCheckIfEvent
- On Windows, fix malformed function pointer typecast that could invoke undefined behavior.
- Refactored Windows state/flag-setting code.
- On Windows, hiding the cursor no longer hides the cursor for all Winit windows - just the one `hide_cursor` was called on.
- On Windows, cursor grabs used to get perpetually canceled when the grabbing window lost focus. Now, cursor grabs automatically get re-initialized when the window regains focus and the mouse moves over the client area.
- On Windows, only vertical mouse wheel events were handled. Now, horizontal mouse wheel events are also handled.
- On Windows, ignore the AltGr key when populating the `ModifersState` type.
# Version 0.18.1 (2018-12-30)
- On macOS, fix `Yen` (JIS) so applications receive the event.
- On X11 with a tiling WM, fixed high CPU usage when moving windows across monitors.
- On X11, fixed panic caused by dropping the window before running the event loop.
- on macOS, added `WindowExt::set_simple_fullscreen` which does not require a separate space
- Introduce `WindowBuilderExt::with_app_id` to allow setting the application ID on Wayland.
- On Windows, catch panics in event loop child thread and forward them to the parent thread. This prevents an invocation of undefined behavior due to unwinding into foreign code.
- On Windows, fix issue where resizing or moving window combined with grabbing the cursor would freeze program.
- On Windows, fix issue where resizing or moving window would eat `Awakened` events.
- On Windows, exiting fullscreen after entering fullscreen with disabled decorations no longer shrinks window.
- On X11, fixed a segfault when using virtual monitors with XRandR.
- Derive `Ord` and `PartialOrd` for `VirtualKeyCode` enum.
- On Windows, fix issue where hovering or dropping a non file item would create a panic.
- On Wayland, fix resizing and DPI calculation when a `wl_output` is removed without sending a `leave` event to the `wl_surface`, such as disconnecting a monitor from a laptop.
- On Wayland, DPI calculation is handled by smithay-client-toolkit.
- On X11, `WindowBuilder::with_min_dimensions` and `WindowBuilder::with_max_dimensions` now correctly account for DPI.
- Added support for generating dummy `DeviceId`s and `WindowId`s to better support unit testing.
- On macOS, fixed unsoundness in drag-and-drop that could result in drops being rejected.
- On macOS, implemented `WindowEvent::Refresh`.
- On macOS, all `MouseCursor` variants are now implemented and the cursor will no longer reset after unfocusing.
- Removed minimum supported Rust version guarantee.
# Version 0.18.0 (2018-11-07)
- **Breaking:** `image` crate upgraded to 0.20. This is exposed as part of the `icon_loading` API.
- On Wayland, pointer events will now provide the current modifiers state.
- On Wayland, titles will now be displayed in the window header decoration.
- On Wayland, key repetition is now ended when keyboard loses focus.
- On Wayland, windows will now use more stylish and modern client side decorations.
- On Wayland, windows will use server-side decorations when available.
- **Breaking:** Added support for F16-F24 keys (variants were added to the `VirtualKeyCode` enum).
- Fixed graphical glitches when resizing on Wayland.
- On Windows, fix freezes when performing certain actions after a window resize has been triggered. Reintroduces some visual artifacts when resizing.
- Updated window manager hints under X11 to v1.5 of [Extended Window Manager Hints](https://specifications.freedesktop.org/wm-spec/wm-spec-1.5.html#idm140200472629520).
- Added `WindowBuilderExt::with_gtk_theme_variant` to X11-specific `WindowBuilder` functions.
- Fixed UTF8 handling bug in X11 `set_title` function.
- On Windows, `Window::set_cursor` now applies immediately instead of requiring specific events to occur first.
- On Windows, the `HoveredFile` and `HoveredFileCancelled` events are now implemented.
- On Windows, fix `Window::set_maximized`.
- On Windows 10, fix transparency (#260).
- On macOS, fix modifiers during key repeat.
- Implemented the `Debug` trait for `Window`, `EventsLoop`, `EventsLoopProxy` and `WindowBuilder`.
- On X11, now a `Resized` event will always be generated after a DPI change to ensure the window's logical size is consistent with the new DPI.
- Added further clarifications to the DPI docs.
- On Linux, if neither X11 nor Wayland manage to initialize, the corresponding panic now consists of a single line only.
- Add optional `serde` feature with implementations of `Serialize`/`Deserialize` for DPI types and various event types.
- Add `PartialEq`, `Eq`, and `Hash` implementations on public types that could have them but were missing them.
- On X11, drag-and-drop receiving an unsupported drop type can no longer cause the WM to freeze.
- Fix issue whereby the OpenGL context would not appear at startup on macOS Mojave (#1069).
- **Breaking:** Removed `From<NSApplicationActivationPolicy>` impl from `ActivationPolicy` on macOS.
- On macOS, the application can request the user's attention with `WindowExt::request_user_attention`.
# Version 0.17.2 (2018-08-19)
- On macOS, fix `<C-Tab>` so applications receive the event.
- On macOS, fix `<Cmd-{key}>` so applications receive the event.
- On Wayland, key press events will now be repeated.
# Version 0.17.1 (2018-08-05)
- On X11, prevent a compilation failure in release mode for versions of Rust greater than or equal to 1.30.
- Fixed deadlock that broke fullscreen mode on Windows.
# Version 0.17.0 (2018-08-02)
- Cocoa and core-graphics updates.
- Fixed thread-safety issues in several `Window` functions on Windows.
- On MacOS, the key state for modifiers key events is now properly set.
- On iOS, the view is now set correctly. This makes it possible to render things (instead of being stuck on a black screen), and touch events work again.
- Added NetBSD support.
- **Breaking:** On iOS, `UIView` is now the default root view. `WindowBuilderExt::with_root_view_class` can be used to set the root view objective-c class to `GLKView` (OpenGLES) or `MTKView` (Metal/MoltenVK).
- On iOS, the `UIApplication` is not started until `Window::new` is called.
- Fixed thread unsafety with cursor hiding on macOS.
- On iOS, fixed the size of the `JmpBuf` type used for `setjmp`/`longjmp` calls. Previously this was a buffer overflow on most architectures.
- On Windows, use cached window DPI instead of repeatedly querying the system. This fixes sporadic crashes on Windows 7.
# Version 0.16.2 (2018-07-07)
- On Windows, non-resizable windows now have the maximization button disabled. This is consistent with behavior on macOS and popular X11 WMs.
- Corrected incorrect `unreachable!` usage when guessing the DPI factor with no detected monitors.
# Version 0.16.1 (2018-07-02)
- Added logging through `log`. Logging will become more extensive over time.
- On X11 and Windows, the window's DPI factor is guessed before creating the window. This _greatly_ cuts back on unsightly auto-resizing that would occur immediately after window creation.
- Fixed X11 backend compilation for environments where `c_char` is unsigned.
# Version 0.16.0 (2018-06-25)
- Windows additionally has `WindowBuilderExt::with_no_redirection_bitmap`.
- **Breaking:** Removed `VirtualKeyCode::LMenu` and `VirtualKeyCode::RMenu`; Windows now generates `VirtualKeyCode::LAlt` and `VirtualKeyCode::RAlt` instead.
- On X11, exiting fullscreen no longer leaves the window in the monitor's top left corner.
- **Breaking:** `Window::hidpi_factor` has been renamed to `Window::get_hidpi_factor` for better consistency. `WindowEvent::HiDPIFactorChanged` has been renamed to `WindowEvent::HiDpiFactorChanged`. DPI factors are always represented as `f64` instead of `f32` now.
- The Windows backend is now DPI aware. `WindowEvent::HiDpiFactorChanged` is implemented, and `MonitorId::get_hidpi_factor` and `Window::hidpi_factor` return accurate values.
- Implemented `WindowEvent::HiDpiFactorChanged` on X11.
- On macOS, `Window::set_cursor_position` is now relative to the client area.
- On macOS, setting the maximum and minimum dimensions now applies to the client area dimensions rather than to the window dimensions.
- On iOS, `MonitorId::get_dimensions` has been implemented and both `MonitorId::get_hidpi_factor` and `Window::get_hidpi_factor` return accurate values.
- On Emscripten, `MonitorId::get_hidpi_factor` now returns the same value as `Window::get_hidpi_factor` (it previously would always return 1.0).
- **Breaking:** The entire API for sizes, positions, etc. has changed. In the majority of cases, winit produces and consumes positions and sizes as `LogicalPosition` and `LogicalSize`, respectively. The notable exception is `MonitorId` methods, which deal in `PhysicalPosition` and `PhysicalSize`. See the documentation for specifics and explanations of the types. Additionally, winit automatically conserves logical size when the DPI factor changes.
- **Breaking:** All deprecated methods have been removed. For `Window::platform_display` and `Window::platform_window`, switch to the appropriate platform-specific `WindowExt` methods. For `Window::get_inner_size_points` and `Window::get_inner_size_pixels`, use the `LogicalSize` returned by `Window::get_inner_size` and convert as needed.
- HiDPI support for Wayland.
- `EventsLoop::get_available_monitors` and `EventsLoop::get_primary_monitor` now have identical counterparts on `Window`, so this information can be acquired without an `EventsLoop` borrow.
- `AvailableMonitorsIter` now implements `Debug`.
- Fixed quirk on macOS where certain keys would generate characters at twice the normal rate when held down.
- On X11, all event loops now share the same `XConnection`.
- **Breaking:** `Window::set_cursor_state` and `CursorState` enum removed in favor of the more composable `Window::grab_cursor` and `Window::hide_cursor`. As a result, grabbing the cursor no longer automatically hides it; you must call both methods to retain the old behavior on Windows and macOS. `Cursor::NoneCursor` has been removed, as it's no longer useful.
- **Breaking:** `Window::set_cursor_position` now returns `Result<(), String>`, thus allowing for `Box<Error>` conversion via `?`.
# Version 0.15.1 (2018-06-13)
- On X11, the `Moved` event is no longer sent when the window is resized without changing position.
- `MouseCursor` and `CursorState` now implement `Default`.
- `WindowBuilder::with_resizable` implemented for Windows, X11, Wayland, and macOS.
- `Window::set_resizable` implemented for Windows, X11, Wayland, and macOS.
- On X11, if the monitor's width or height in millimeters is reported as 0, the DPI is now 1.0 instead of +inf.
- On X11, the environment variable `WINIT_HIDPI_FACTOR` has been added for overriding DPI factor.
- On X11, enabling transparency no longer causes the window contents to flicker when resizing.
- On X11, `with_override_redirect` now actually enables override redirect.
- macOS now generates `VirtualKeyCode::LAlt` and `VirtualKeyCode::RAlt` instead of `None` for both.
- On macOS, `VirtualKeyCode::RWin` and `VirtualKeyCode::LWin` are no longer switched.
- On macOS, windows without decorations can once again be resized.
- Fixed race conditions when creating an `EventsLoop` on X11, most commonly manifesting as "[xcb] Unknown sequence number while processing queue".
- On macOS, `CursorMoved` and `MouseInput` events are only generated if they occurs within the window's client area.
- On macOS, resizing the window no longer generates a spurious `MouseInput` event.
# Version 0.15.0 (2018-05-22)
- `Icon::to_cardinals` is no longer public, since it was never supposed to be.
- Wayland: improve diagnostics if initialization fails
- Fix some system event key doesn't work when focused, do not block keyevent forward to system on macOS
- On X11, the scroll wheel position is now correctly reset on i3 and other WMs that have the same quirk.
- On X11, `Window::get_current_monitor` now reliably returns the correct monitor.
- On X11, `Window::hidpi_factor` returns values from XRandR rather than the inaccurate values previously queried from the core protocol.
- On X11, the primary monitor is detected correctly even when using versions of XRandR less than 1.5.
- `MonitorId` now implements `Debug`.
- Fixed bug on macOS where using `with_decorations(false)` would cause `set_decorations(true)` to produce a transparent titlebar with no title.
- Implemented `MonitorId::get_position` on macOS.
- On macOS, `Window::get_current_monitor` now returns accurate values.
- Added `WindowBuilderExt::with_resize_increments` to macOS.
- **Breaking:** On X11, `WindowBuilderExt::with_resize_increments` and `WindowBuilderExt::with_base_size` now take `u32` values rather than `i32`.
- macOS keyboard handling has been overhauled, allowing for the use of dead keys, IME, etc. Right modifier keys are also no longer reported as being left.
- Added the `Window::set_ime_spot(x: i32, y: i32)` method, which is implemented on X11 and macOS.
- **Breaking**: `os::unix::WindowExt::send_xim_spot(x: i16, y: i16)` no longer exists. Switch to the new `Window::set_ime_spot(x: i32, y: i32)`, which has equivalent functionality.
- Fixed detection of `Pause` and `Scroll` keys on Windows.
- On Windows, alt-tabbing while the cursor is grabbed no longer makes it impossible to re-grab the cursor.
- On Windows, using `CursorState::Hide` when the cursor is grabbed now ungrabs the cursor first.
- Implemented `MouseCursor::NoneCursor` on Windows.
- Added `WindowBuilder::with_always_on_top` and `Window::set_always_on_top`. Implemented on Windows, macOS, and X11.
- On X11, `WindowBuilderExt` now has `with_class`, `with_override_redirect`, and `with_x11_window_type` to allow for more control over window creation. `WindowExt` additionally has `set_urgent`.
- More hints are set by default on X11, including `_NET_WM_PID` and `WM_CLIENT_MACHINE`. Note that prior to this, the `WM_CLASS` hint was automatically set to whatever value was passed to `with_title`. It's now set to the executable name to better conform to expectations and the specification; if this is undesirable, you must explicitly use `WindowBuilderExt::with_class`.
# Version 0.14.0 (2018-05-09)
- Created the `Copy`, `Paste` and `Cut` `VirtualKeyCode`s and added support for them on X11 and Wayland
- Fix `.with_decorations(false)` in macOS
- On Mac, `NSWindow` and supporting objects might be alive long after they were `closed` which resulted in apps consuming more heap then needed. Mainly it was affecting multi window applications. Not expecting any user visible change of behaviour after the fix.
- Fix regression of Window platform extensions for macOS where `NSFullSizeContentViewWindowMask` was not being correctly applied to `.fullsize_content_view`.
- Corrected `get_position` on Windows to be relative to the screen rather than to the taskbar.
- Corrected `Moved` event on Windows to use position values equivalent to those returned by `get_position`. It previously supplied client area positions instead of window positions, and would additionally interpret negative values as being very large (around `u16::MAX`).
- Implemented `Moved` event on macOS.
- On X11, the `Moved` event correctly use window positions rather than client area positions. Additionally, a stray `Moved` that unconditionally accompanied `Resized` with the client area position relative to the parent has been eliminated; `Moved` is still received alongside `Resized`, but now only once and always correctly.
- On Windows, implemented all variants of `DeviceEvent` other than `Text`. Mouse `DeviceEvent`s are now received even if the window isn't in the foreground.
- `DeviceId` on Windows is no longer a unit struct, and now contains a `u32`. For `WindowEvent`s, this will always be 0, but on `DeviceEvent`s it will be the handle to that device. `DeviceIdExt::get_persistent_identifier` can be used to acquire a unique identifier for that device that persists across replugs/reboots/etc.
- Corrected `run_forever` on X11 to stop discarding `Awakened` events.
- Various safety and correctness improvements to the X11 backend internals.
- Fixed memory leak on X11 every time the mouse entered the window.
- On X11, drag and drop now works reliably in release mode.
- Added `WindowBuilderExt::with_resize_increments` and `WindowBuilderExt::with_base_size` to X11, allowing for more optional hints to be set.
- Rework of the wayland backend, migrating it to use [Smithay's Client Toolkit](https://github.com/Smithay/client-toolkit).
- Added `WindowBuilder::with_window_icon` and `Window::set_window_icon`, finally making it possible to set the window icon on Windows and X11. The `icon_loading` feature can be enabled to allow for icons to be easily loaded; see example program `window_icon.rs` for usage.
- Windows additionally has `WindowBuilderExt::with_taskbar_icon` and `WindowExt::set_taskbar_icon`.
- On Windows, fix panic when trying to call `set_fullscreen(None)` on a window that has not been fullscreened prior.
# Version 0.13.1 (2018-04-26)
- Ensure necessary `x11-dl` version is used.
# Version 0.13.0 (2018-04-25)
- Implement `WindowBuilder::with_maximized`, `Window::set_fullscreen`, `Window::set_maximized` and `Window::set_decorations` for MacOS.
- Implement `WindowBuilder::with_maximized`, `Window::set_fullscreen`, `Window::set_maximized` and `Window::set_decorations` for Windows.
- On Windows, `WindowBuilder::with_fullscreen` no longer changing monitor display resolution.
- Overhauled X11 window geometry calculations. `get_position` and `set_position` are more universally accurate across different window managers, and `get_outer_size` actually works now.
- Fixed SIGSEGV/SIGILL crashes on macOS caused by stabilization of the `!` (never) type.
- Implement `WindowEvent::HiDPIFactorChanged` for macOS
- On X11, input methods now work completely out of the box, no longer requiring application developers to manually call `setlocale`. Additionally, when input methods are started, stopped, or restarted on the server end, it's correctly handled.
- Implemented `Refresh` event on Windows.
- Properly calculate the minimum and maximum window size on Windows, including window decorations.
- Map more `MouseCursor` variants to cursor icons on Windows.
- Corrected `get_position` on macOS to return outer frame position, not content area position.
- Corrected `set_position` on macOS to set outer frame position, not content area position.
- Added `get_inner_position` method to `Window`, which gets the position of the window's client area. This is implemented on all applicable platforms (all desktop platforms other than Wayland, where this isn't possible).
- **Breaking:** the `Closed` event has been replaced by `CloseRequested` and `Destroyed`. To migrate, you typically just need to replace all usages of `Closed` with `CloseRequested`; see example programs for more info. The exception is iOS, where `Closed` must be replaced by `Destroyed`.
# Version 0.12.0 (2018-04-06)
- Added subclass to macos windows so they can be made resizable even with no decorations.
- Dead keys now work properly on X11, no longer resulting in a panic.
- On X11, input method creation first tries to use the value from the user's `XMODIFIERS` environment variable, so application developers should no longer need to manually call `XSetLocaleModifiers`. If that fails, fallbacks are tried, which should prevent input method initialization from ever outright failing.
- Fixed thread safety issues with input methods on X11.
- Add support for `Touch` for win32 backend.
- Fixed `Window::get_inner_size` and friends to return the size in pixels instead of points when using HIDPI displays on OSX.
# Version 0.11.3 (2018-03-28)
- Added `set_min_dimensions` and `set_max_dimensions` methods to `Window`, and implemented on Windows, X11, Wayland, and OSX.
- On X11, dropping a `Window` actually closes it now, and clicking the window's × button (or otherwise having the WM signal to close it) will result in the window closing.
- Added `WindowBuilderExt` methods for macos: `with_titlebar_transparent`,
`with_title_hidden`, `with_titlebar_buttons_hidden`,
`with_fullsize_content_view`.
- Mapped X11 numpad keycodes (arrows, Home, End, PageUp, PageDown, Insert and Delete) to corresponding virtual keycodes
# Version 0.11.2 (2018-03-06)
- Impl `Hash`, `PartialEq`, and `Eq` for `events::ModifiersState`.
- Implement `MonitorId::get_hidpi_factor` for MacOS.
- Added method `os::macos::MonitorIdExt::get_nsscreen() -> *mut c_void` that gets a `NSScreen` object matching the monitor ID.
- Send `Awakened` event on Android when event loop is woken up.
# Version 0.11.1 (2018-02-19)
- Fixed windows not receiving mouse events when click-dragging the mouse outside the client area of a window, on Windows platforms.
- Added method `os::android::EventsLoopExt:set_suspend_callback(Option<Box<Fn(bool) -> ()>>)` that allows glutin to register a callback when a suspend event happens
# Version 0.11.0 (2018-02-09)
- Implement `MonitorId::get_dimensions` for Android.
- Added method `os::macos::WindowBuilderExt::with_movable_by_window_background(bool)` that allows to move a window without a titlebar - `with_decorations(false)`
- Implement `Window::set_fullscreen`, `Window::set_maximized` and `Window::set_decorations` for Wayland.
- Added `Caret` as VirtualKeyCode and support OSX ^-Key with german input.
# Version 0.10.1 (2018-02-05)
_Yanked_
# Version 0.10.0 (2017-12-27)
- Add support for `Touch` for emscripten backend.
- Added support for `DroppedFile`, `HoveredFile`, and `HoveredFileCancelled` to X11 backend.
- **Breaking:** `unix::WindowExt` no longer returns pointers for things that aren't actually pointers; `get_xlib_window` now returns `Option<std::os::raw::c_ulong>` and `get_xlib_screen_id` returns `Option<std::os::raw::c_int>`. Additionally, methods that previously returned `libc::c_void` have been changed to return `std::os::raw::c_void`, which are not interchangeable types, so users wanting the former will need to explicitly cast.
- Added `set_decorations` method to `Window` to allow decorations to be toggled after the window is built. Presently only implemented on X11.
- Raised the minimum supported version of Rust to 1.20 on MacOS due to usage of associated constants in new versions of cocoa and core-graphics.
- Added `modifiers` field to `MouseInput`, `MouseWheel`, and `CursorMoved` events to track the modifiers state (`ModifiersState`).
- Fixed the emscripten backend to return the size of the canvas instead of the size of the window.
# Version 0.9.0 (2017-12-01)
- Added event `WindowEvent::HiDPIFactorChanged`.
- Added method `MonitorId::get_hidpi_factor`.
- Deprecated `get_inner_size_pixels` and `get_inner_size_points` methods of `Window` in favor of
`get_inner_size`.
- **Breaking:** `EventsLoop` is `!Send` and `!Sync` because of platform-dependant constraints,
but `Window`, `WindowId`, `DeviceId` and `MonitorId` guaranteed to be `Send`.
- `MonitorId::get_position` now returns `(i32, i32)` instead of `(u32, u32)`.
- Rewrite of the wayland backend to use wayland-client-0.11
- Support for dead keys on wayland for keyboard utf8 input
- Monitor enumeration on Windows is now implemented using `EnumDisplayMonitors` instead of
`EnumDisplayDevices`. This changes the value returned by `MonitorId::get_name()`.
- On Windows added `MonitorIdExt::hmonitor` method
- Impl `Clone` for `EventsLoopProxy`
- `EventsLoop::get_primary_monitor()` on X11 will fallback to any available monitor if no primary is found
- Support for touch event on wayland
- `WindowEvent`s `MouseMoved`, `MouseEntered`, and `MouseLeft` have been renamed to
`CursorMoved`, `CursorEntered`, and `CursorLeft`.
- New `DeviceEvent`s added, `MouseMotion` and `MouseWheel`.
- Send `CursorMoved` event after `CursorEntered` and `Focused` events.
- Add support for `ModifiersState`, `MouseMove`, `MouseInput`, `MouseMotion` for emscripten backend.
# Version 0.8.3 (2017-10-11)
- Fixed issue of calls to `set_inner_size` blocking on Windows.
- Mapped `ISO_Left_Tab` to `VirtualKeyCode::Tab` to make the key work with modifiers
- Fixed the X11 backed on 32bit targets
# Version 0.8.2 (2017-09-28)
- Uniformize keyboard scancode values accross Wayland and X11 (#297).
- Internal rework of the wayland event loop
- Added method `os::linux::WindowExt::is_ready`
# Version 0.8.1 (2017-09-22)
- Added various methods to `os::linux::EventsLoopExt`, plus some hidden items necessary to make
glutin work.
# Version 0.8.0 (2017-09-21)
- Added `Window::set_maximized`, `WindowAttributes::maximized` and `WindowBuilder::with_maximized`.
- Added `Window::set_fullscreen`.
- Changed `with_fullscreen` to take a `Option<MonitorId>` instead of a `MonitorId`.
- Removed `MonitorId::get_native_identifer()` in favor of platform-specific traits in the `os`
module.
- Changed `get_available_monitors()` and `get_primary_monitor()` to be methods of `EventsLoop`
instead of stand-alone methods.
- Changed `EventsLoop` to be tied to a specific X11 or Wayland connection.
- Added a `os::linux::EventsLoopExt` trait that makes it possible to configure the connection.
- Fixed the emscripten code, which now compiles.
- Changed the X11 fullscreen code to use `xrandr` instead of `xxf86vm`.
- Fixed the Wayland backend to produce `Refresh` event after window creation.
- Changed the `Suspended` event to be outside of `WindowEvent`.
- Fixed the X11 backend sometimes reporting the wrong virtual key (#273).
[`changelog::unreleased`]: winit/src/changelog/unreleased.md
[docs_rs]: https://docs.rs/winit/latest/winit/changelog/index.html
[master_docs]: https://rust-windowing.github.io/winit/winit/changelog/index.html

6
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,6 @@
# Code of Conduct
The `rust-windowing` project adheres to the [Rust Code of Conduct]. This
describes the minimum behavior expected from all contributors.
[Rust Code of Conduct]: https://www.rust-lang.org/policies/code-of-conduct

View File

@@ -1,72 +1,162 @@
# Winit Contributing Guidelines
# Contribution Guidelines
## Scope
[See `FEATURES.md`](./FEATURES.md). When requesting or implementing a new Winit feature, you should
consider whether or not it's directly related to window creation or input handling. If it isn't, it
may be worth creating a separate crate that extends Winit's API to add that functionality.
This document contains guidelines for contributing code to winit. It has to be
followed in order for your patch to be approved and applied.
## Contributing
## Reporting an issue
Anyone can contribute to winit, however given that it's a cross platform
windowing toolkit getting certain changes incorporated could be challenging.
When reporting an issue, in order to help the maintainers understand what the problem is, please make
your description of the issue as detailed as possible:
To save your time it's wise to check already opened [pull requests][prs] and
[issues][issues]. In general, bug fixes and missing implementations are always
accepted, however larger new API proposals should go into the issue first. When
in doubt contact us on [Matrix][matrix] or via opening an issue.
- if it is a bug, please provide clear explanation of what happens, what should happen, and how to
reproduce the issue, ideally by providing a minimal program exhibiting the problem
- if it is a feature request, please provide a clear argumentation about why you believe this feature
should be supported by winit
### Windows
## Making a pull request
To run the examples on Windows, you must have symlinks enabled, see
[this][git-windows-symlinks].
When making a code contribution to winit, before opening your pull request, please make sure that:
[git-windows-symlinks]: https://gitforwindows.org/symbolic-links.html
- your patch builds with Winit's minimal supported rust version - Rust 1.60.
- you tested your modifications on all the platforms impacted, or if not possible detail which platforms
were not tested, and what should be tested, so that a maintainer or another contributor can test them
- you updated any relevant documentation in winit
- you left comments in your code explaining any part that is not straightforward, so that the
maintainers and future contributors don't have to try to guess what your code is supposed to do
- your PR adds an entry to the changelog file if the introduced change is relevant to winit users.
### Submitting your work and handling review
You needn't worry about the added entry causing conflicts, the maintainer that merges the PR will
handle those for you when merging (see below).
- if your PR affects the platform compatibility of one or more features or adds another feature, the
relevant sections in [`FEATURES.md`](https://github.com/rust-windowing/winit/blob/master/FEATURES.md#features)
should be updated.
All patches have to be sent on Github as [pull requests][prs]. To simplify your
life during review it's recommended to check the "give contributors write access
to the branch" checkbox.
Once your PR is open, you can ask for review by a maintainer of your platform. Winit's merging policy
is that a PR must be approved by at least two maintainers of winit before being merged, including
at least a maintainer of the platform (a maintainer making a PR themselves counts as approving it).
We use unstable Rustfmt options across the project, so please run
`cargo +nightly fmt` before submitting your work. If you are unable to do so,
the maintainers can do it for you before merging, just state so in your pull
request description. For details on how to use nightly, consult [the
documentation][toolchains].
Once your PR is deemed ready, the merging maintainer will take care of resolving conflicts in
`CHANGELOG.md` (but you must resolve other conflicts yourself). Doing this requires that you check the
"give contributors write access to the branch" checkbox when creating the PR.
When editing markdown files (`.md`) they must be wrapped at 80 characters.
## Maintainers & Testers
[toolchains]: https://rust-lang.github.io/rustup/concepts/toolchains.html
The current maintainers are listed in the [CODEOWNERS](.github/CODEOWNERS) file.
#### Handling review
If you are interested in being pinged when testing is needed for a certain platform, please add yourself to the [Testers and Contributors](https://github.com/rust-windowing/winit/wiki/Testers-and-Contributors) table!
During the review process certain events could require an action from your side,
common patterns and reactions are described below.
## Release process
_Event:_ The CI fails to build, but it looks like it is not your fault. Not
communicating so could result in maintainers not looking into your patch,
since they may assume that you're still working on it.\
_Desired behaviour:_ Write a message saying roughly the following "The CI
failure is unrelated", so that the maintainers will fix it for you.
Given that winit is a widely used library we should be able to make a patch
_Event:_ Maintainer requested changes to your PR.\
_Desired behavior:_ Once you address the request, you should re-request a review
with GitHub's UI. If you don't agree with what maintainer suggested, you
should state your objections and re-request the review. That will indicate that
the ball is on maintainer's side.
_Event:_ You've opened a PR, but maintainer shortly after commented that they
want to work on that themselves.\
_Desired behavior:_ Discuss with the maintainer regarding their plans if they
were not outlined in the initial response, because such response means that they
are not interested in reviewing your code. Such thing could happen when
underestimating complexity of the task you're solving or when your patch
mandate certain downstream designs. In general, the maintainer will likely
close your PR in order to prevent work being done on it.
[prs]: https://github.com/rust-windowing/winit/pulls
[issues]: https://github.com/rust-windowing/winit/issues
[matrix]: https://matrix.to/#/#rust-windowing:matrix.org
## Maintainers
Winit has plenty of maintainers with different backgrounds, different time
available to work on Winit, and reasons to be winit maintainer in the first
place. To ensure that Winit's code quality does not decrease over time and to
make it easier to teach new maintainers the "winit way of doing things" the
common policies and routines are defined in this section.
The current maintainers for each platform are listed in [this file][CODEOWNERS].
### Contributions handling
The maintainers must ensure that the external contributions meet Winit's
quality standards. If it's not, it **is the maintainer's responsibility** to
bring it on par, which includes:
- Ensure that formatting is consistent and `CHANGELOG` messages are clear
for the end users.
- Improve the commit message, so it'll be easier for other maintainers to
understand the motivation without going through all the discussions on the
particular patch/PR.
- Ensure that the proposed patch doesn't break platform parity. If the
breakage is desired by contributor, an issue should be opened to discuss
with other maintainers before merging.
- Always fix CI issues before merging if they don't originate from the
submitted work.
However, maintainers should give some leeway for external contributors, so they
don't feel discouraged contributing, for example:
- Suggest a patch to resolve style issues, if it's the only issue with the
submitted work. Keep in mind that pushing the resolution yourself is not
desired, because the contributor might not agree with what you did.
- Be more explicit on how things should be done if you don't like the
approach.
- Suggest to finish the PR for them if they're absent for a while and you need
the proposed changes to move forward with something. In such cases the
maintainer must preserve attribution with `Co-authored-by`, `Suggested-by`,
or keep the original committer.
- Rebase their work for them when massive changes to the Winit codebase were
introduced.
When reviewing code of other maintainers all of the above is on the maintainer
who submitted the patch. Interested maintainers could help push the work over
the finish line, but teaching other maintainers should be preferred.
For a _regular_ contributor to winit, the maintainer should slowly start
requiring contributor to match *maintainer* quality standards when writing
patches and commit messages.
### Contributing
When submitting a patch, the maintainer should follow the general contributing
guidelines, however greater attention to detail is expected in this case.
To make life simpler for other maintainers it's suggested to create your branch
under the project repository instead of your own fork. The naming scheme is
`github_user_name/branch_name`. Doing so will make your work easier to rebase
for other maintainers when you're absent.
### Administrative Actions
Some things (such as changing required CI steps, adding contributors, ...)
require administrative permissions. If you don't have those, ask about the
change in an issue. If you have the permissions, discuss it with at least one
other admin before making the change.
### Release process
Given that winit is a widely used library, we should be able to make a patch
releases at any time we want without blocking the development of new features.
To achieve these goals, a new branch is created for every new release. Releases
and later patch releases are committed and tagged in this branch.
The exact steps for an exemplary `0.2.0` release might look like this:
1. Initially the version on the latest master is `0.1.0`
1. Initially, the version on the latest master is `0.1.0`
2. A new `v0.2.x` branch is created for the release
3. In the branch, the version is bumped to `v0.2.0`
4. The new commit in the branch is tagged `v0.2.0`
5. The version is pushed to crates.io
6. A GitHub release is created for the `v0.2.0` tag
7. On master, the version is bumped to `0.2.0` and the CHANGELOG is updated
When doing a patch release the process is similar:
1. Initially the version of the latest release is `0.2.0`
3. Update released `cfg_attr` in `src/changelog/mod.rs` to `v0.2.md`
4. Move entries from `src/changelog/unreleased.md` into
`src/changelog/v0.2.md`
5. In the branch, the version is bumped to `v0.2.0`
6. The new commit in the branch is tagged `v0.2.0`
7. The version is pushed to crates.io
8. A GitHub release is created for the `v0.2.0` tag
9. On master, the version is bumped to `0.2.0`, and the changelog is updated
When doing a patch release, the process is similar:
1. Initially, the version of the latest release is `0.2.0`
2. Checkout the `v0.2.x` branch
3. Cherry-pick the required non-breaking changes into the `v0.2.x`
4. Follow steps 3-7 of the regular release example
4. Follow steps 4-9 of the regular release example
[CODEOWNERS]: .github/CODEOWNERS

View File

@@ -1,161 +1,97 @@
[package]
name = "winit"
version = "0.28.3"
authors = ["The winit contributors", "Pierre Krieger <pierre.krieger1708@gmail.com>"]
description = "Cross-platform window creation library."
edition = "2021"
keywords = ["windowing"]
license = "Apache-2.0"
readme = "README.md"
repository = "https://github.com/rust-windowing/winit"
documentation = "https://docs.rs/winit"
categories = ["gui"]
rust-version = "1.60.0"
[package.metadata.docs.rs]
features = ["serde"]
default-target = "x86_64-unknown-linux-gnu"
# These are all tested in CI
targets = [
# Windows
"i686-pc-windows-msvc",
"x86_64-pc-windows-msvc",
# macOS
"x86_64-apple-darwin",
# Unix (X11 & Wayland)
"i686-unknown-linux-gnu",
"x86_64-unknown-linux-gnu",
# iOS
"x86_64-apple-ios",
# Android
"aarch64-linux-android",
# WebAssembly
"wasm32-unknown-unknown",
]
rustdoc-args = ["--cfg", "docsrs"]
[features]
default = ["x11", "wayland", "wayland-dlopen", "wayland-csd-adwaita"]
x11 = ["x11-dl", "mio", "percent-encoding"]
wayland = ["wayland-client", "wayland-protocols", "sctk", "wayland-commons"]
wayland-dlopen = ["sctk/dlopen", "wayland-client/dlopen"]
wayland-csd-adwaita = ["sctk-adwaita", "sctk-adwaita/ab_glyph"]
wayland-csd-adwaita-crossfont = ["sctk-adwaita", "sctk-adwaita/crossfont"]
wayland-csd-adwaita-notitle = ["sctk-adwaita"]
android-native-activity = [ "android-activity/native-activity" ]
android-game-activity = [ "android-activity/game-activity" ]
[build-dependencies]
cfg_aliases = "0.1.1"
[dependencies]
bitflags = "1"
instant = { version = "0.1", features = ["wasm-bindgen"] }
log = "0.4"
mint = { version = "0.5.6", optional = true }
once_cell = "1.12"
raw_window_handle = { package = "raw-window-handle", version = "0.5" }
serde = { version = "1", optional = true, features = ["serde_derive"] }
[dev-dependencies]
image = { version = "0.24.0", default-features = false, features = ["png"] }
simple_logger = { version = "2.1.0", default_features = false }
[target.'cfg(target_os = "android")'.dependencies]
# Coordinate the next winit release with android-ndk-rs: https://github.com/rust-windowing/winit/issues/1995
android-activity = "0.4.0"
ndk = "0.7.0"
[target.'cfg(any(target_os = "ios", target_os = "macos"))'.dependencies]
core-foundation = "0.9.3"
objc2 = ">=0.3.0-beta.3, <0.3.0-beta.4" # Allow `0.3.0-beta.3.patch-leaks`
[target.'cfg(target_os = "macos")'.dependencies]
core-graphics = "0.22.3"
dispatch = "0.2.0"
[target.'cfg(target_os = "windows")'.dependencies.windows-sys]
version = "0.45"
features = [
"Win32_Devices_HumanInterfaceDevice",
"Win32_Foundation",
"Win32_Globalization",
"Win32_Graphics_Dwm",
"Win32_Graphics_Gdi",
"Win32_Media",
"Win32_System_Com_StructuredStorage",
"Win32_System_Com",
"Win32_System_LibraryLoader",
"Win32_System_Ole",
"Win32_System_SystemInformation",
"Win32_System_SystemServices",
"Win32_System_Threading",
"Win32_System_WindowsProgramming",
"Win32_UI_Accessibility",
"Win32_UI_Controls",
"Win32_UI_HiDpi",
"Win32_UI_Input_Ime",
"Win32_UI_Input_KeyboardAndMouse",
"Win32_UI_Input_Pointer",
"Win32_UI_Input_Touch",
"Win32_UI_Shell",
"Win32_UI_TextServices",
"Win32_UI_WindowsAndMessaging",
]
[target.'cfg(all(unix, not(any(target_os = "redox", target_arch = "wasm32", target_os = "android", target_os = "ios", target_os = "macos"))))'.dependencies]
libc = "0.2.64"
mio = { version = "0.8", features = ["os-ext"], optional = true }
percent-encoding = { version = "2.0", optional = true }
sctk = { package = "smithay-client-toolkit", version = "0.16.0", default_features = false, features = ["calloop"], optional = true }
sctk-adwaita = { version = "0.5.1", default_features = false, optional = true }
wayland-client = { version = "0.29.5", default_features = false, features = ["use_system_lib"], optional = true }
wayland-protocols = { version = "0.29.5", features = [ "staging_protocols"], optional = true }
wayland-commons = { version = "0.29.5", optional = true }
x11-dl = { version = "2.18.5", optional = true }
[target.'cfg(target_os = "redox")'.dependencies]
orbclient = { version = "0.3.42", default-features = false }
redox_syscall = "0.3"
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.build-dependencies]
wayland-scanner = "0.29.5"
[target.'cfg(target_arch = "wasm32")'.dependencies.web_sys]
package = "web-sys"
version = "0.3.22"
features = [
'console',
"AddEventListenerOptions",
'CssStyleDeclaration',
'BeforeUnloadEvent',
'Document',
'DomRect',
'Element',
'Event',
"EventListenerOptions",
'EventTarget',
'FocusEvent',
'HtmlCanvasElement',
'HtmlElement',
'KeyboardEvent',
'MediaQueryList',
'MediaQueryListEvent',
'MouseEvent',
'Node',
'PointerEvent',
'Window',
'WheelEvent'
]
[target.'cfg(target_arch = "wasm32")'.dependencies.wasm-bindgen]
version = "0.2.45"
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
console_log = "0.2"
web-sys = { version = "0.3.22", features = ['CanvasRenderingContext2d'] }
[workspace]
members = [
"run-wasm",
]
default-members = ["winit"]
members = ["dpi", "winit*"]
resolver = "2"
[workspace.package]
edition = "2024"
license = "Apache-2.0"
repository = "https://github.com/rust-windowing/winit"
rust-version = "1.85"
version = "0.31.0-beta.2"
[workspace.dependencies]
# Workspace dependencies.
# `winit` has no version here to allow using it in dev deps for docs.
winit = { path = "winit" }
winit-android = { version = "=0.31.0-beta.2", path = "winit-android" }
winit-appkit = { version = "=0.31.0-beta.2", path = "winit-appkit" }
winit-common = { version = "=0.31.0-beta.2", path = "winit-common" }
winit-core = { version = "=0.31.0-beta.2", path = "winit-core" }
winit-orbital = { version = "=0.31.0-beta.2", path = "winit-orbital" }
winit-uikit = { version = "=0.31.0-beta.2", path = "winit-uikit" }
winit-wayland = { version = "=0.31.0-beta.2", path = "winit-wayland", default-features = false }
winit-web = { version = "=0.31.0-beta.2", path = "winit-web" }
winit-win32 = { version = "=0.31.0-beta.2", path = "winit-win32" }
winit-x11 = { version = "=0.31.0-beta.2", path = "winit-x11" }
# Core dependencies.
bitflags = "2"
cfg_aliases = "0.2.1"
cursor-icon = "1.1.0"
dpi = { version = "0.1.2", path = "dpi" }
keyboard-types = "0.8.0"
mint = "0.5.6"
rwh_06 = { package = "raw-window-handle", version = "0.6", features = ["std"] }
serde = { version = "1", features = ["serde_derive"] }
smol_str = "0.3"
tracing = { version = "0.1.40", default-features = false }
# Dev dependencies.
image = { version = "0.25.0", default-features = false }
softbuffer = { version = "0.4.8", default-features = false, features = [
"x11",
"x11-dlopen",
"wayland",
"wayland-dlopen",
] }
tracing-subscriber = "0.3.18"
# Android dependencies.
android-activity = "0.6.0"
ndk = { version = "0.9.0", features = ["rwh_06"], default-features = false }
# Apple dependencies.
block2 = "0.6.1"
dispatch2 = { version = "0.3.0", default-features = false, features = ["std", "objc2"] }
objc2 = { version = "0.6.1", features = ["relax-sign-encoding"] }
objc2-app-kit = { version = "0.3.2", default-features = false }
objc2-core-foundation = { version = "0.3.2", default-features = false }
objc2-core-graphics = { version = "0.3.2", default-features = false }
objc2-core-video = { version = "0.3.2", default-features = false }
objc2-foundation = { version = "0.3.2", default-features = false }
objc2-ui-kit = { version = "0.3.2", default-features = false }
# Windows dependencies.
unicode-segmentation = "1.7.1"
windows-sys = "0.61"
# Linux dependencies.
bytemuck = { version = "1.13.1", default-features = false }
calloop = "0.14.3"
foldhash = { version = "0.2.0", default-features = false, features = ["std"] }
libc = "0.2.64"
memmap2 = "0.9.0"
percent-encoding = "2.0"
rustix = { version = "1.0.7", default-features = false }
x11-dl = "2.19.1"
x11rb = { version = "0.13.0", default-features = false }
xkbcommon-dl = "0.4.2"
# Orbital dependencies.
libredox = "0.1.12"
orbclient = { version = "0.3.47", default-features = false }
redox_event = { package = "redox_event", version = "0.4.5" }
# Web dependencies.
atomic-waker = "1"
concurrent-queue = { version = "2", default-features = false }
console_error_panic_hook = "0.1"
js-sys = "0.3.70"
pin-project = "1"
tracing-web = "0.1"
wasm-bindgen = "0.2.93"
wasm-bindgen-futures = "0.4.43"
wasm-bindgen-test = "0.3"
web-time = "1"
web_sys = { package = "web-sys", version = "0.3.70" }

View File

@@ -1,10 +1,10 @@
# Winit Scope
Winit aims to expose an interface that abstracts over window creation and input handling, and can
Winit aims to expose an interface that abstracts over window creation and input handling and can
be used to create both games and applications. It supports the following main graphical platforms:
- Desktop
- Windows 7+ (10+ is tested regularly)
- macOS 10.7+ (10.14+ is tested regularly)
- Windows
- macOS
- Unix
- via X11
- via Wayland
@@ -13,7 +13,6 @@ be used to create both games and applications. It supports the following main gr
- iOS
- Android
- Web
- via WASM
Most platforms expose capabilities that cannot be meaningfully transposed onto others. Winit does not
aim to support every single feature of every platform, but rather to abstract over the common features
@@ -43,205 +42,8 @@ be released and the library will enter maintenance mode. For the most part, new
be added past this point. New platform features may be accepted and exposed through point releases.
### Tier upgrades
Some platform features could in theory be exposed across multiple platforms, but have not gone
Some platform features could, in theory, be exposed across multiple platforms, but have not gone
through the implementation work necessary to function on all platforms. When one of these features
gets implemented across all platforms, a PR can be opened to upgrade the feature to a core feature.
If that gets accepted, the platform-specific functions gets deprecated and become permanently
If that gets accepted, the platform-specific functions get deprecated and become permanently
exposed through the core, cross-platform API.
# Features
## Extending this section
If your PR makes notable changes to Winit's features, please update this section as follows:
- If your PR adds a new feature, add a brief description to the relevant section. If the feature is a core
feature, add a row to the feature matrix and describe what platforms the feature has been implemented on.
- If your PR begins a new API rework, add a row to the `Pending API Reworks` table. If the PR implements the
API rework on all relevant platforms, please move it to the `Completed API Reworks` table.
- If your PR implements an already-existing feature on a new platform, either mark the feature as *completed*,
or mark it as *mostly completed* and link to an issue describing the problems with the implementation.
## Core
### Windowing
- **Window initialization**: Winit allows the creation of a window
- **Providing pointer to init OpenGL**: Winit provides the necessary pointers to initialize a working opengl context
- **Providing pointer to init Vulkan**: Same as OpenGL but for Vulkan
- **Window decorations**: The windows created by winit are properly decorated, and the decorations can
be deactivated
- **Window decorations toggle**: Decorations can be turned on or off after window creation
- **Window resizing**: The windows created by winit can be resized and generate the appropriate events
when they are. The application can precisely control its window size if desired.
- **Window resize increments**: When the window gets resized, the application can choose to snap the window's
size to specific values.
- **Window transparency**: Winit allows the creation of windows with a transparent background.
- **Window maximization**: The windows created by winit can be maximized upon creation.
- **Window maximization toggle**: The windows created by winit can be maximized and unmaximized after
creation.
- **Window minimization**: The windows created by winit can be minimized after creation.
- **Fullscreen**: The windows created by winit can be put into fullscreen mode.
- **Fullscreen toggle**: The windows created by winit can be switched to and from fullscreen after
creation.
- **Exclusive fullscreen**: Winit allows changing the video mode of the monitor
for fullscreen windows, and if applicable, captures the monitor for exclusive
use by this application.
- **HiDPI support**: Winit assists developers in appropriately scaling HiDPI content.
- **Popup / modal windows**: Windows can be created relative to the client area of other windows, and parent
windows can be disabled in favor of popup windows. This feature also guarantees that popup windows
get drawn above their owner.
### System Information
- **Monitor list**: Retrieve the list of monitors and their metadata, including which one is primary.
- **Video mode query**: Monitors can be queried for their supported fullscreen video modes (consisting of resolution, refresh rate, and bit depth).
### Input Handling
- **Mouse events**: Generating mouse events associated with pointer motion, click, and scrolling events.
- **Mouse set location**: Forcibly changing the location of the pointer.
- **Cursor locking**: Locking the cursor inside the window so it cannot move.
- **Cursor confining**: Confining the cursor to the window bounds so it cannot leave them.
- **Cursor icon**: Changing the cursor icon, or hiding the cursor.
- **Cursor hittest**: Handle or ignore mouse events for a window.
- **Touch events**: Single-touch events.
- **Touch pressure**: Touch events contain information about the amount of force being applied.
- **Multitouch**: Multi-touch events, including cancellation of a gesture.
- **Keyboard events**: Properly processing keyboard events using the user-specified keymap and
translating keypresses into UTF-8 characters, handling dead keys and IMEs.
- **Drag & Drop**: Dragging content into winit, detecting when content enters, drops, or if the drop is cancelled.
- **Raw Device Events**: Capturing input from input devices without any OS filtering.
- **Gamepad/Joystick events**: Capturing input from gamepads and joysticks.
- **Device movement events**: Capturing input from the device gyroscope and accelerometer.
## Platform
### Windows
* Setting the taskbar icon
* Setting the parent window
* Setting a menu bar
* `WS_EX_NOREDIRECTIONBITMAP` support
* Theme the title bar according to Windows 10 Dark Mode setting or set a preferred theme
### macOS
* Window activation policy
* Window movable by background
* Transparent titlebar
* Hidden titlebar
* Hidden titlebar buttons
* Full-size content view
* Accepts first mouse
* Set a preferred theme and get current theme.
### Unix
* Window urgency
* X11 Window Class
* X11 Override Redirect Flag
* GTK Theme Variant
* Base window size
* Setting the X11 parent window
### iOS
* `winit` has a minimum OS requirement of iOS 8
* Get the `UIWindow` object pointer
* Get the `UIViewController` object pointer
* Get the `UIView` object pointer
* Get the `UIScreen` object pointer
* Setting the `UIView` hidpi factor
* Valid orientations
* Home indicator visibility
* Status bar visibility
* Deferrring system gestures
* Getting the device idiom
* Getting the preferred video mode
### Web
* Get if systems preferred color scheme is "dark"
## Usability
* `serde`: Enables serialization/deserialization of certain types with Serde. (Maintainer: @Osspial)
## Compatibility Matrix
Legend:
- ✔️: Works as intended
- ▢: Mostly works but some bugs are known
- ❌: Missing feature or large bugs making it unusable
- **N/A**: Not applicable for this platform
- ❓: Unknown status
### Windowing
|Feature |Windows|MacOS |Linux x11 |Linux Wayland |Android|iOS |WASM |Redox OS|
|-------------------------------- | ----- | ---- | ------- | ----------- | ----- | ----- | -------- | ------ |
|Window initialization |✔️ |✔️ |▢[#5] |✔️ |▢[#33]|▢[#33] |✔️ |✔️ |
|Providing pointer to init OpenGL |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |**N/A**|✔️ |
|Providing pointer to init Vulkan |✔️ |✔️ |✔️ |✔️ |✔️ |❓ |**N/A**|**N/A** |
|Window decorations |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|✔️ |
|Window decorations toggle |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|**N/A** |
|Window resizing |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|✔️ |✔️ |
|Window resize increments |❌ |✔️ |✔️ |❌ |**N/A**|**N/A**|**N/A**|**N/A** |
|Window transparency |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|N/A |✔️ |
|Window maximization |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|**N/A** |
|Window maximization toggle |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|**N/A** |
|Window minimization |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|**N/A** |
|Fullscreen |✔️ |✔️ |✔️ |✔️ |**N/A**|✔️ |✔️ |**N/A** |
|Fullscreen toggle |✔️ |✔️ |✔️ |✔️ |**N/A**|✔️ |✔️ |**N/A** |
|Exclusive fullscreen |✔️ |✔️ |✔️ |**N/A** |❌ |✔️ |**N/A**|**N/A** |
|HiDPI support |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |❌ |
|Popup windows |❌ |❌ |❌ |❌ |❌ |❌ |**N/A**|**N/A** |
### System information
|Feature |Windows|MacOS |Linux x11|Linux Wayland|Android|iOS |WASM |Redox OS|
|---------------- | ----- | ---- | ------- | ----------- | ----- | ------- | -------- | ------ |
|Monitor list |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |**N/A**|❌ |
|Video mode query |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |**N/A**|❌ |
### Input handling
|Feature |Windows |MacOS |Linux x11|Linux Wayland|Android|iOS |WASM |Redox OS|
|----------------------- | ----- | ---- | ------- | ----------- | ----- | ----- | -------- | ------ |
|Mouse events |✔️ |▢[#63] |✔️ |✔️ |**N/A**|**N/A**|✔️ |✔️ |
|Mouse set location |✔️ |✔️ |✔️ |✔️(when locked) |**N/A**|**N/A**|**N/A**|**N/A** |
|Cursor locking |❌ |✔️ |❌ |✔️ |**N/A**|**N/A**|✔️ |❌ |
|Cursor confining |✔️ |❌ |✔️ |✔️ |**N/A**|**N/A**|❌ |❌ |
|Cursor icon |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|✔️ |**N/A** |
|Cursor hittest |✔️ |✔️ |❌ |✔️ |**N/A**|**N/A**|❌ |❌ |
|Touch events |✔️ |❌ |✔️ |✔️ |✔️ |✔️ |✔️ |**N/A** |
|Touch pressure |✔️ |❌ |❌ |❌ |❌ |✔️ |✔️ |**N/A** |
|Multitouch |✔️ |❌ |✔️ |✔️ |✔️ |✔️ |❌ |**N/A** |
|Keyboard events |✔️ |✔️ |✔️ |✔️ |✔️ |❌ |✔️ |✔️ |
|Drag & Drop |▢[#720] |▢[#720] |▢[#720] |▢[#720] |**N/A**|**N/A**|❓ |**N/A** |
|Raw Device Events |▢[#750] |▢[#750] |▢[#750] |❌ |❌ |❌ |❓ |**N/A** |
|Gamepad/Joystick events |❌[#804] |❌ |❌ |❌ |❌ |❌ |❓ |**N/A** |
|Device movement events |❓ |❓ |❓ |❓ |❌ |❌ |❓ |**N/A** |
|Drag window with cursor |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A** |**N/A** |
|Resize with cursor |❌ |❌ |✔️ |❌ |**N/A**|**N/A**|**N/A** |**N/A** |
### Pending API Reworks
Changes in the API that have been agreed upon but aren't implemented across all platforms.
|Feature |Windows|MacOS |Linux x11|Linux Wayland|Android|iOS |WASM |Redox OS|
|------------------------------ | ----- | ---- | ------- | ----------- | ----- | ----- | -------- | ------ |
|New API for HiDPI ([#315] [#319]) |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |❓ |❓ |
|Event Loop 2.0 ([#459]) |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |❓ |❓ |
|Keyboard Input ([#812]) |❌ |❌ |❌ |❌ |❌ |❌ |❓ |❓ |
### Completed API Reworks
|Feature |Windows|MacOS |Linux x11|Linux Wayland|Android|iOS |WASM |Redox OS|
|------------------------------ | ----- | ---- | ------- | ----------- | ----- | ----- | -------- | ------ |
[#165]: https://github.com/rust-windowing/winit/issues/165
[#219]: https://github.com/rust-windowing/winit/issues/219
[#242]: https://github.com/rust-windowing/winit/issues/242
[#306]: https://github.com/rust-windowing/winit/issues/306
[#315]: https://github.com/rust-windowing/winit/issues/315
[#319]: https://github.com/rust-windowing/winit/issues/319
[#33]: https://github.com/rust-windowing/winit/issues/33
[#459]: https://github.com/rust-windowing/winit/issues/459
[#5]: https://github.com/rust-windowing/winit/issues/5
[#63]: https://github.com/rust-windowing/winit/issues/63
[#720]: https://github.com/rust-windowing/winit/issues/720
[#721]: https://github.com/rust-windowing/winit/issues/721
[#750]: https://github.com/rust-windowing/winit/issues/750
[#804]: https://github.com/rust-windowing/winit/issues/804
[#812]: https://github.com/rust-windowing/winit/issues/812

View File

@@ -2,21 +2,20 @@
The winit maintainers would like to recognize the following former winit
contributors, without whom winit would not exist in its current form. We thank
them deeply for their time and efforts, and wish them best of luck in their
them deeply for their time and efforts and wish them the best of luck in their
future endeavors:
* [@tomaka]: For creating the winit project and guiding it through its early
years of existence.
* [@vberger]: For diligently creating the Wayland backend, and being its
* [@vberger]: For diligently creating the Wayland backend and being its
extremely helpful and benevolent maintainer for years.
* [@francesca64]: For taking over the responsibility of maintaining almost every
winit backend, and standardizing HiDPI support across all of them.
* [@Osspial]: For heroically landing EventLoop 2.0, and valiantly ushering in a
winit backend and standardizing HiDPI support across all of them.
* [@Osspial]: For heroically landing EventLoop 2.0 and valiantly ushering in a
vastly more sustainable era of winit.
* [@goddessfreya]: For selflessly taking over maintainership of glutin, and her
* [@goddessfreya]: For selflessly taking over maintainership of glutin and her
stellar dedication to improving both winit and glutin.
* [@ArturKovacs]: For consistently maintaining the macOS backend, and his
immense involvement in designing and implementing the new keyboard API.
* [@ArturKovacs]: For consistently maintaining the macOS backend and for his immense involvement in designing and implementing the new keyboard API.
[@tomaka]: https://github.com/tomaka
[@vberger]: https://github.com/vberger

215
README.md
View File

@@ -2,215 +2,78 @@
[![Crates.io](https://img.shields.io/crates/v/winit.svg)](https://crates.io/crates/winit)
[![Docs.rs](https://docs.rs/winit/badge.svg)](https://docs.rs/winit)
[![UNSTABLE docs](https://img.shields.io/github/actions/workflow/status/rust-windowing/winit/docs.yml?branch=master&label=UNSTABLE%20docs
)](https://rust-windowing.github.io/winit/winit/index.html)
[![CI Status](https://github.com/rust-windowing/winit/workflows/CI/badge.svg)](https://github.com/rust-windowing/winit/actions)
```toml
[dependencies]
winit = "0.28.3"
winit = "0.31.0-beta.2"
```
## [Documentation](https://docs.rs/winit)
For features _within_ the scope of winit, see [FEATURES.md](FEATURES.md).
For features _outside_ the scope of winit, see [Missing features provided by other crates](https://github.com/rust-windowing/winit/wiki/Missing-features-provided-by-other-crates) in the wiki.
For features _outside_ the scope of winit, see [Are we GUI Yet?](https://areweguiyet.com/) and [Are we game yet?](https://arewegameyet.rs/), depending on what kind of project you're looking to do.
## Contact Us
Join us in any of these:
Join us in our [![Matrix](https://img.shields.io/badge/Matrix-%23rust--windowing%3Amatrix.org-blueviolet.svg)](https://matrix.to/#/#rust-windowing:matrix.org) room.
[![Matrix](https://img.shields.io/badge/Matrix-%23rust--windowing%3Amatrix.org-blueviolet.svg)](https://matrix.to/#/#rust-windowing:matrix.org)
[![Libera.Chat](https://img.shields.io/badge/libera.chat-%23winit-red.svg)](https://web.libera.chat/#winit)
The maintainers have a meeting every friday at UTC 15. The meeting notes can be found [here](https://hackmd.io/@winit-meetings).
## Usage
Winit is a window creation and management library. It can create windows and lets you handle
events (for example: the window being resized, a key being pressed, a mouse movement, etc.)
produced by window.
produced by the window.
Winit is designed to be a low-level brick in a hierarchy of libraries. Consequently, in order to
show something on the window you need to use the platform-specific getters provided by winit, or
another library.
```rust
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
## CONTRIBUTING
fn main() {
let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();
For contributing guidelines see [CONTRIBUTING.md](./CONTRIBUTING.md).
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
## MSRV Policy
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => *control_flow = ControlFlow::Exit,
_ => (),
}
});
}
This crate's Minimum Supported Rust Version (MSRV) is **1.85**. Changes to
the MSRV will be accompanied by a minor version bump.
As a **tentative** policy, the upper bound of the MSRV is given by the following
formula:
```
min(sid, stable - 3)
```
Winit is only officially supported on the latest stable version of the Rust compiler.
Where `sid` is the current version of `rustc` provided by [Debian Sid], and
`stable` is the latest stable version of Rust. This bound may be broken in case of a major ecosystem shift or a security vulnerability.
### Cargo Features
[Debian Sid]: https://packages.debian.org/sid/rustc
Winit provides the following features, which can be enabled in your `Cargo.toml` file:
* `serde`: Enables serialization/deserialization of certain types with [Serde](https://crates.io/crates/serde).
* `x11` (enabled by default): On Unix platform, compiles with the X11 backend
* `wayland` (enabled by default): On Unix platform, compiles with the Wayland backend
* `mint`: Enables mint (math interoperability standard types) conversions.
An exception is made for the Android platform, where a higher Rust version
must be used for certain Android features. In this case, the MSRV will be
capped at the latest stable version of Rust minus three. This inconsistency is
not reflected in Cargo metadata, as it is not powerful enough to expose this
restriction.
Redox OS is also not covered by this MSRV policy, as it requires a Rust nightly
toolchain to compile.
All crates in the [`rust-windowing`] organizations have the
same MSRV policy.
[`rust-windowing`]: https://github.com/rust-windowing
### Platform-specific usage
#### Wayland
Check out the [`winit::platform`](https://docs.rs/winit/latest/winit/platform/index.html) module for platform-specific usage.
Note that windows don't appear on Wayland until you draw/present to them.
### Repository License
`winit` doesn't do drawing, try the examples in [`glutin`] instead.
[`glutin`]: https://github.com/rust-windowing/glutin
#### WebAssembly
To run the web example: `cargo run-wasm --example web`
Winit supports compiling to the `wasm32-unknown-unknown` target with `web-sys`.
On the web platform, a Winit window is backed by a `<canvas>` element. You can
either [provide Winit with a `<canvas>` element][web with_canvas], or [let Winit
create a `<canvas>` element which you can then retrieve][web canvas getter] and
insert it into the DOM yourself.
For example code using Winit with WebAssembly, check out the [web example]. For
information on using Rust on WebAssembly, check out the [Rust and WebAssembly
book].
[web with_canvas]: https://docs.rs/winit/latest/wasm32-unknown-unknown/winit/platform/web/trait.WindowBuilderExtWebSys.html#tymethod.with_canvas
[web canvas getter]: https://docs.rs/winit/latest/wasm32-unknown-unknown/winit/platform/web/trait.WindowExtWebSys.html#tymethod.canvas
[web example]: ./examples/web.rs
[Rust and WebAssembly book]: https://rustwasm.github.io/book/
#### Android
The Android backend builds on (and exposes types from) the [`ndk`](https://docs.rs/ndk/0.7.0/ndk/) crate.
Native Android applications need some form of "glue" crate that is responsible
for defining the main entry point for your Rust application as well as tracking
various life-cycle events and synchronizing with the main JVM thread.
Winit uses the [android-activity](https://github.com/rib/android-activity) as a
glue crate (prior to `0.28` it used
[ndk-glue](https://github.com/rust-windowing/android-ndk-rs/tree/master/ndk-glue)).
The version of the glue crate that your application depends on _must_ match the
version that Winit depends on because the glue crate is responsible for your
application's main entrypoint. If Cargo resolves multiple versions they will
clash.
`winit` glue compatibility table:
| winit | ndk-glue |
| :---: | :--------------------------: |
| 0.28 | `android-activity = "0.4"` |
| 0.27 | `ndk-glue = "0.7"` |
| 0.26 | `ndk-glue = "0.5"` |
| 0.25 | `ndk-glue = "0.3"` |
| 0.24 | `ndk-glue = "0.2"` |
The recommended way to avoid a conflict with the glue version is to avoid explicitly
depending on the `android-activity` crate, and instead consume the API that
is re-exported by Winit under `winit::platform::android::activity::*`
Running on an Android device needs a dynamic system library, add this to Cargo.toml:
```toml
[lib]
name = "main"
crate-type = ["cdylib"]
```
All Android applications are based on an `Activity` subclass and the
`android-activity` crate is designed to support different choices for this base
class. Your application _must_ specify the base class it needs via a feature flag:
| Base Class | Feature Flag | Notes |
| :--------------: | :---------------: | :-----: |
| `NativeActivity` | `android-native-activity` | Built-in to Android - it is possible to use without compiling any Java or Kotlin code. Java or Kotlin code may be needed to subclass `NativeActivity` to access some platform features. It does not derive from the [`AndroidAppCompat`] base class.|
| [`GameActivity`] | `android-game-activity` | Derives from [`AndroidAppCompat`] which is a defacto standard `Activity` base class that helps support a wider range of Android versions. Requires a build system that can compile Java or Kotlin and fetch Android dependencies from a [Maven repository][agdk_jetpack] (or link with an embedded [release][agdk_releases] of [`GameActivity`]) |
[`GameActivity`]: https://developer.android.com/games/agdk/game-activity
[`GameTextInput`]: https://developer.android.com/games/agdk/add-support-for-text-input
[`AndroidAppCompat`]: https://developer.android.com/reference/androidx/appcompat/app/AppCompatActivity
[agdk_jetpack]: https://developer.android.com/jetpack/androidx/releases/games
[agdk_releases]: https://developer.android.com/games/agdk/download#agdk-libraries
[Gradle]: https://developer.android.com/studio/build
For example, add this to Cargo.toml:
```toml
winit = { version = "0.28", features = [ "android-native-activity" ] }
[target.'cfg(target_os = "android")'.dependencies]
android_logger = "0.11.0"
```
And, for example, define an entry point for your library like this:
```rust
#[cfg(target_os = "android")]
use winit::platform::android::activity::AndroidApp;
#[cfg(target_os = "android")]
#[no_mangle]
fn android_main(app: AndroidApp) {
use winit::platform::android::EventLoopBuilderExtAndroid;
android_logger::init_once(android_logger::Config::default().with_min_level(log::Level::Trace));
let event_loop = EventLoopBuilder::with_user_event()
.with_android_app(app)
.build();
_main(event_loop);
}
```
For more details, refer to these `android-activity` [example applications](https://github.com/rib/android-activity/tree/main/examples).
##### Converting from `ndk-glue` to `android-activity`
If your application is currently based on `NativeActivity` via the `ndk-glue` crate and building with `cargo apk` then the minimal changes would be:
1. Remove `ndk-glue` from your `Cargo.toml`
2. Enable the `"android-native-activity"` feature for Winit: `winit = { version = "0.28", features = [ "android-native-activity" ] }`
3. Add an `android_main` entrypoint (as above), instead of using the '`[ndk_glue::main]` proc macro from `ndk-macros` (optionally add a dependency on `android_logger` and initialize logging as above).
4. Pass a clone of the `AndroidApp` that your application receives to Winit when building your event loop (as shown above).
#### MacOS
A lot of functionality expects the application to be ready before you start
doing anything; this includes creating windows, fetching monitors, drawing,
and so on, see issues [#2238], [#2051] and [#2087].
If you encounter problems, you should try doing your initialization inside
`Event::NewEvents(StartCause::Init)`.
#### iOS
Similar to macOS, iOS's main `UIApplicationMain` does some init work that's required
by all UI related code, see issue [#1705]. You should consider creating your windows
inside `Event::NewEvents(StartCause::Init)`.
[#2238]: https://github.com/rust-windowing/winit/issues/2238
[#2051]: https://github.com/rust-windowing/winit/issues/2051
[#2087]: https://github.com/rust-windowing/winit/issues/2087
[#1705]: https://github.com/rust-windowing/winit/issues/1705
#### Redox OS
Redox OS has some functionality not present yet, that will be implemented when
its orbital display server provides it.
Note that the license in `LICENSE` doesn't apply in full to the DPI package [./dpi](./dpi).
Full details can be found in that folder's README.
<!-- This doesn't apply to users of the Winit crate, but this is also the repository level README -->

View File

@@ -1,64 +0,0 @@
use cfg_aliases::cfg_aliases;
#[cfg(all(
any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
),
feature = "wayland",
))]
mod wayland {
use std::env;
use std::path::PathBuf;
use wayland_scanner::Side;
pub fn main() {
let mut path = PathBuf::from(env::var("OUT_DIR").unwrap());
path.push("fractional_scale_v1.rs");
wayland_scanner::generate_code(
"wayland_protocols/fractional-scale-v1.xml",
&path,
Side::Client,
);
}
}
fn main() {
// The script doesn't depend on our code
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=wayland_protocols");
// Setup cfg aliases
cfg_aliases! {
// Systems.
android_platform: { target_os = "android" },
wasm_platform: { target_arch = "wasm32" },
macos_platform: { target_os = "macos" },
ios_platform: { target_os = "ios" },
windows_platform: { target_os = "windows" },
apple: { any(target_os = "ios", target_os = "macos") },
free_unix: { all(unix, not(apple), not(android_platform)) },
redox: { target_os = "redox" },
// Native displays.
x11_platform: { all(feature = "x11", free_unix, not(wasm), not(redox)) },
wayland_platform: { all(feature = "wayland", free_unix, not(wasm), not(redox)) },
orbital_platform: { redox },
}
// XXX aliases are not available for the build script itself.
#[cfg(all(
any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
),
feature = "wayland",
))]
wayland::main();
}

27
clippy.toml Normal file
View File

@@ -0,0 +1,27 @@
# Using allow-invalid because this is platform-specific code
disallowed-macros = [
{ path = "std::print", reason = "works badly on web", replacement = "tracing::info" },
{ path = "std::println", reason = "works badly on web", replacement = "tracing::info" },
{ path = "std::eprint", reason = "works badly on web", replacement = "tracing::error" },
{ path = "std::eprintln", reason = "works badly on web", replacement = "tracing::error" },
{ path = "std::dbg", reason = "leftover debugging aid, remove it or use tracing" },
]
disallowed-methods = [
{ allow-invalid = true, path = "objc2_app_kit::NSView::visibleRect", reason = "We expose a render target to the user, and visibility is not really relevant to that (and can break if you don't use the rectangle position as well). Use `frame` instead." },
{ allow-invalid = true, path = "objc2_app_kit::NSWindow::setFrameTopLeftPoint", reason = "Not sufficient when working with Winit's coordinate system, use `flip_window_screen_coordinates` instead" },
{ allow-invalid = true, path = "web_sys::Document::exit_fullscreen", reason = "Doesn't account for compatibility with Safari" },
{ allow-invalid = true, path = "web_sys::Document::fullscreen_element", reason = "Doesn't account for compatibility with Safari" },
{ allow-invalid = true, path = "web_sys::Element::request_fullscreen", reason = "Doesn't account for compatibility with Safari" },
{ allow-invalid = true, path = "web_sys::HtmlCanvasElement::height", reason = "Winit shouldn't touch the internal canvas size" },
{ allow-invalid = true, path = "web_sys::HtmlCanvasElement::set_height", reason = "Winit shouldn't touch the internal canvas size" },
{ allow-invalid = true, path = "web_sys::HtmlCanvasElement::set_width", reason = "Winit shouldn't touch the internal canvas size" },
{ allow-invalid = true, path = "web_sys::HtmlCanvasElement::width", reason = "Winit shouldn't touch the internal canvas size" },
{ allow-invalid = true, path = "web_sys::HtmlElement::style", reason = "cache this to reduce calls to JS" },
{ allow-invalid = true, path = "web_sys::MouseEvent::buttons", reason = "Use `backend::event::cursor_buttons()` to avoid wrong conversions" },
{ allow-invalid = true, path = "web_sys::MouseEvent::button", reason = "Use `backend::event::cursor_button()` to avoid wrong conversions" },
{ allow-invalid = true, path = "web_sys::PointerEvent::pointer_type", reason = "Use `WebPointerType` to emit warnings" },
{ allow-invalid = true, path = "web_sys::Window::document", reason = "cache this to reduce calls to JS" },
{ allow-invalid = true, path = "web_sys::Window::get_computed_style", reason = "cache this to reduce calls to JS" },
{ allow-invalid = true, path = "web_sys::Window::navigator", reason = "cache this to reduce calls to JS" },
{ allow-invalid = true, path = "web_sys::window", reason = "is not available in every context" },
]

61
deny.toml Normal file
View File

@@ -0,0 +1,61 @@
# https://embarkstudios.github.io/cargo-deny
# cargo install cargo-deny
# cargo update && cargo deny check
[graph]
all-features = true
exclude-dev = true
targets = [
"aarch64-apple-darwin",
"aarch64-apple-ios",
"aarch64-linux-android",
"i686-pc-windows-gnu",
"i686-pc-windows-msvc",
"i686-unknown-linux-gnu",
{ triple = "wasm32-unknown-unknown", features = [
"atomics",
] },
"x86_64-apple-darwin",
"x86_64-apple-ios",
"x86_64-pc-windows-gnu",
"x86_64-pc-windows-msvc",
"x86_64-unknown-linux-gnu",
"x86_64-unknown-redox",
]
[licenses]
allow = [
"Apache-2.0", # https://tldrlegal.com/license/apache-license-2.0-(apache-2.0)
"BSD-2-Clause", # https://tldrlegal.com/license/bsd-2-clause-license-(freebsd)
"BSD-3-Clause", # https://tldrlegal.com/license/bsd-3-clause-license-(revised)
"ISC", # https://tldrlegal.com/license/isc-license
"MIT", # https://tldrlegal.com/license/mit-license
"Unicode-3.0", # https://spdx.org/licenses/Unicode-3.0.html
"Zlib", # https://spdx.org/licenses/Zlib.html
"MPL-2.0", # https://www.mozilla.org/en-US/MPL/2.0/
]
confidence-threshold = 1.0
private = { ignore = true }
[bans]
multiple-versions = "deny"
skip = [
{ crate = "jni-sys@0.3", reason = "uses the semver trick to depend on v0.4, but `ndk` hasn't been updated to v0.4 yet" },
{ crate = "thiserror@1.0", reason = "dep of `ndk` crate, yet to be updated" },
{ crate = "thiserror-impl@1.0", reason = "dep of `thiserror`" },
{ crate = "objc2@0.5", reason = "used by crossfont" },
{ crate = "objc2-foundation@0.2", reason = "used by crossfont" },
]
skip-tree = [
{ crate = "windows-sys", reason = "foundational but bumps fairly often, nothing we can do about it not having a shared version" },
]
[bans.build]
bypass = [
{ crate = "android-activity", allow-globs = ["android-games-sdk/import-games-sdk.sh"] },
{ crate = "freetype-sys", allow-globs = ["freetype2/*"] },
# `crossfont` still depends (partially transitively) on `winapi`.
{ crate = "winapi-i686-pc-windows-gnu", allow-globs = ["lib/lib*.a"] },
{ crate = "winapi-x86_64-pc-windows-gnu", allow-globs = ["lib/lib*.a"] },
]
include-archives = true
interpreted = "deny"

25
dpi/CHANGELOG.md Normal file
View File

@@ -0,0 +1,25 @@
# Changelog
All notable changes to this project will be documented in this file.
Please keep one empty line before and after all headers. (This is required for
`git` to produce a conflict when a release is made while a PR is open and the
PR's changelog entry would go into the wrong section).
And please only add new entries to the top of this list, right below the `#
Unreleased` header.
## Unreleased
## 0.1.2
- Added `Insets`, `LogicalInsets` and `PhysicalInsets` types.
- Make `no_std` compatible. If you use this functionality, DPI's license has changed.
## 0.1.1
- Derive `Debug`, `Copy`, `Clone`, `PartialEq`, `Serialize`, `Deserialize` traits for `PixelUnit`.
## 0.1.0
- Add `LogicalUnit`, `PhysicalUnit` and `PixelUnit` types and related functions.

46
dpi/Cargo.toml Normal file
View File

@@ -0,0 +1,46 @@
[package]
categories = ["gui"]
description = "Types for handling UI scaling"
edition.workspace = true
keywords = ["DPI", "HiDPI", "scale-factor"]
# N.B. This is "AND", because of the imported libm code.
license = "Apache-2.0 AND MIT"
name = "dpi"
repository.workspace = true
rust-version.workspace = true
version = "0.1.2"
[features]
default = ["std"]
mint = ["dep:mint"]
serde = ["dep:serde"]
# Access mathematical functions using the standard library implementations
std = []
[dependencies]
mint = { workspace = true, optional = true }
serde = { workspace = true, optional = true }
[package.metadata.docs.rs]
features = ["mint", "serde"]
# These are all tested in CI
rustdoc-args = ["--cfg", "docsrs"]
targets = [
# Windows
"i686-pc-windows-msvc",
"x86_64-pc-windows-msvc",
# macOS
"aarch64-apple-darwin",
"x86_64-apple-darwin",
# Unix (X11 & Wayland)
"i686-unknown-linux-gnu",
"x86_64-unknown-linux-gnu",
# iOS
"aarch64-apple-ios",
# Android
"aarch64-linux-android",
# Web
"wasm32-unknown-unknown",
]

1
dpi/LICENSE Symbolic link
View File

@@ -0,0 +1 @@
../LICENSE

51
dpi/LICENSE-LIBM-MIT Normal file
View File

@@ -0,0 +1,51 @@
rust-lang/libm as a whole is available for use under the MIT license:
------------------------------------------------------------------------------
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
This Rust library contains the following copyrights:
Copyright (c) 2018 Jorge Aparicio
Portions of this software are derived from third-party works licensed under
terms compatible with the above MIT license:
* musl libc https://www.musl-libc.org/. This library contains the following
copyright:
Copyright © 2005-2020 Rich Felker, et al.
* The CORE-MATH project https://core-math.gitlabpages.inria.fr/. CORE-MATH
routines are available under the MIT license on a per-file basis.
The musl libc COPYRIGHT file also includes the following notice relevant to
math portions of the library:
------------------------------------------------------------------------------
Much of the math library code (src/math/* and src/complex/*) is
Copyright © 1993,2004 Sun Microsystems or
Copyright © 2003-2011 David Schultz or
Copyright © 2003-2009 Steven G. Kargl or
Copyright © 2003-2009 Bruce D. Evans or
Copyright © 2008 Stephen L. Moshier or
Copyright © 2017-2018 Arm Limited
and labelled as such in comments in the individual source files. All
have been licensed under extremely permissive terms.
------------------------------------------------------------------------------

18
dpi/README.md Normal file
View File

@@ -0,0 +1,18 @@
# DPI
Full docs can be found on docs.rs.
## License
Most of DPI is licensed under the Apache License, Version 2.0 ([LICENSE](LICENSE)).
All files except for `src/libm.rs` (and `LICENSE-LIBM-MIT`) are available solely under that license.
For its `no_std` support, DPI uses code from the [libm](https://crates.io/crates/libm) crate.
This is in the `libm.rs` file, and is licensed solely under the MIT Licence ([LICENSE-LIBM-MIT](LICENSE-LIBM-MIT)).
That file contains details of all potentially applicable copyright notices.
This is feature gated to only be included if you disable the `std` feature, otherwise it will not be compiled into your final binary
(and so these license terms will not apply).
Overall, this means that the license for this crate depends on what features you have enabled.
If you enable the `std` feature, then DPI uses only code available under the Apache-2.0 license, and so can be used under the terms of that license.
However, if you disable the `std` feature, then both these licenses must be followed to use the crate as a whole.

1223
dpi/src/lib.rs Normal file

File diff suppressed because it is too large Load Diff

56
dpi/src/libm.rs Normal file
View File

@@ -0,0 +1,56 @@
// Copyright (c) 2018 Jorge Aparicio
// Copyright © 2005-2020 Rich Felker, et al.
// Copyright © 1993,2004 Sun Microsystems or
// Copyright © 2003-2011 David Schultz or
// Copyright © 2003-2009 Steven G. Kargl or
// Copyright © 2003-2009 Bruce D. Evans or
// Copyright © 2008 Stephen L. Moshier or
// Copyright © 2017-2018 Arm Limited
// SPDX-License-Identifier: MIT
// This file is licensed solely under the terms discussed in LICENSE-LIBM-MIT at the crate root.
// See the package-level README for full details.
// Taken from https://github.com/rust-lang/libm/blob/master/src/math/mod.rs#L1
macro_rules! force_eval {
($e:expr) => {
unsafe { ::core::ptr::read_volatile(&$e) }
};
}
// Taken from https://github.com/rust-lang/libm/blob/libm-v0.2.11/src/math/round.rs
pub(crate) fn round(x: f64) -> f64 {
trunc(x + copysign(0.5 - 0.25 * f64::EPSILON, x))
}
// Adapted from: https://github.com/rust-lang/libm/blob/libm-v0.2.11/src/math/trunc.rs#L8-L12
#[allow(clippy::needless_late_init /*, reason = "The original libm code uses this style" */)]
fn trunc(x: f64) -> f64 {
let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120
let mut i: u64 = x.to_bits();
let mut e: i64 = ((i >> 52) & 0x7ff) as i64 - 0x3ff + 12;
let m: u64;
if e >= 52 + 12 {
return x;
}
if e < 12 {
e = 1;
}
m = -1i64 as u64 >> e;
if (i & m) == 0 {
return x;
}
force_eval!(x + x1p120);
i &= !m;
f64::from_bits(i)
}
// Taken from https://github.com/rust-lang/libm/blob/libm-v0.2.11/src/math/copysign.rs
fn copysign(x: f64, y: f64) -> f64 {
let mut ux = x.to_bits();
let uy = y.to_bits();
ux &= (!0) >> 1;
ux |= uy & (1 << 63);
f64::from_bits(ux)
}

1
examples Symbolic link
View File

@@ -0,0 +1 @@
winit/examples

View File

@@ -1,80 +0,0 @@
#[cfg(any(x11_platform, macos_platform, windows_platform))]
fn main() {
use std::collections::HashMap;
use raw_window_handle::HasRawWindowHandle;
use winit::{
dpi::{LogicalPosition, LogicalSize, Position},
event::{ElementState, Event, KeyboardInput, WindowEvent},
event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget},
window::{Window, WindowBuilder, WindowId},
};
fn spawn_child_window(
parent: &Window,
event_loop: &EventLoopWindowTarget<()>,
windows: &mut HashMap<WindowId, Window>,
) {
let parent = parent.raw_window_handle();
let mut builder = WindowBuilder::new()
.with_title("child window")
.with_inner_size(LogicalSize::new(200.0f32, 200.0f32))
.with_position(Position::Logical(LogicalPosition::new(0.0, 0.0)))
.with_visible(true);
// `with_parent_window` is unsafe. Parent window must be a valid window.
builder = unsafe { builder.with_parent_window(Some(parent)) };
let child_window = builder.build(event_loop).unwrap();
let id = child_window.id();
windows.insert(id, child_window);
println!("child window created with id: {id:?}");
}
let mut windows = HashMap::new();
let event_loop: EventLoop<()> = EventLoop::new();
let parent_window = WindowBuilder::new()
.with_title("parent window")
.with_position(Position::Logical(LogicalPosition::new(0.0, 0.0)))
.with_inner_size(LogicalSize::new(640.0f32, 480.0f32))
.build(&event_loop)
.unwrap();
println!("parent window: {parent_window:?})");
event_loop.run(move |event: Event<'_, ()>, event_loop, control_flow| {
*control_flow = ControlFlow::Wait;
if let Event::WindowEvent { event, window_id } = event {
match event {
WindowEvent::CloseRequested => {
windows.clear();
*control_flow = ControlFlow::Exit;
}
WindowEvent::CursorEntered { device_id: _ } => {
// On x11, println when the cursor entered in a window even if the child window is created
// by some key inputs.
// the child windows are always placed at (0, 0) with size (200, 200) in the parent window,
// so we also can see this log when we move the cursor arround (200, 200) in parent window.
println!("cursor entered in the window {window_id:?}");
}
WindowEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Pressed,
..
},
..
} => {
spawn_child_window(&parent_window, event_loop, &mut windows);
}
_ => (),
}
}
})
}
#[cfg(not(any(x11_platform, macos_platform, windows_platform)))]
fn main() {
panic!("This example is supported only on x11, macOS, and Windows.");
}

View File

@@ -1,114 +0,0 @@
#![allow(clippy::single_match)]
use std::{thread, time};
use simple_logger::SimpleLogger;
use winit::{
event::{Event, KeyboardInput, WindowEvent},
event_loop::EventLoop,
window::WindowBuilder,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Mode {
Wait,
WaitUntil,
Poll,
}
const WAIT_TIME: time::Duration = time::Duration::from_millis(100);
const POLL_SLEEP_TIME: time::Duration = time::Duration::from_millis(100);
fn main() {
SimpleLogger::new().init().unwrap();
println!("Press '1' to switch to Wait mode.");
println!("Press '2' to switch to WaitUntil mode.");
println!("Press '3' to switch to Poll mode.");
println!("Press 'R' to toggle request_redraw() calls.");
println!("Press 'Esc' to close the window.");
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_title("Press 1, 2, 3 to change control flow mode. Press R to toggle redraw requests.")
.build(&event_loop)
.unwrap();
let mut mode = Mode::Wait;
let mut request_redraw = false;
let mut wait_cancelled = false;
let mut close_requested = false;
event_loop.run(move |event, _, control_flow| {
use winit::event::{ElementState, StartCause, VirtualKeyCode};
println!("{event:?}");
match event {
Event::NewEvents(start_cause) => {
wait_cancelled = match start_cause {
StartCause::WaitCancelled { .. } => mode == Mode::WaitUntil,
_ => false,
}
}
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => {
close_requested = true;
}
WindowEvent::KeyboardInput {
input:
KeyboardInput {
virtual_keycode: Some(virtual_code),
state: ElementState::Pressed,
..
},
..
} => match virtual_code {
VirtualKeyCode::Key1 => {
mode = Mode::Wait;
println!("\nmode: {mode:?}\n");
}
VirtualKeyCode::Key2 => {
mode = Mode::WaitUntil;
println!("\nmode: {mode:?}\n");
}
VirtualKeyCode::Key3 => {
mode = Mode::Poll;
println!("\nmode: {mode:?}\n");
}
VirtualKeyCode::R => {
request_redraw = !request_redraw;
println!("\nrequest_redraw: {request_redraw}\n");
}
VirtualKeyCode::Escape => {
close_requested = true;
}
_ => (),
},
_ => (),
},
Event::MainEventsCleared => {
if request_redraw && !wait_cancelled && !close_requested {
window.request_redraw();
}
if close_requested {
control_flow.set_exit();
}
}
Event::RedrawRequested(_window_id) => {}
Event::RedrawEventsCleared => {
match mode {
Mode::Wait => control_flow.set_wait(),
Mode::WaitUntil => {
if !wait_cancelled {
control_flow.set_wait_until(instant::Instant::now() + WAIT_TIME);
}
}
Mode::Poll => {
thread::sleep(POLL_SLEEP_TIME);
control_flow.set_poll();
}
};
}
_ => (),
}
});
}

View File

@@ -1,90 +0,0 @@
#![allow(clippy::single_match)]
use simple_logger::SimpleLogger;
use winit::{
event::{ElementState, Event, KeyboardInput, WindowEvent},
event_loop::EventLoop,
window::{CursorIcon, WindowBuilder},
};
fn main() {
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();
window.set_title("A fantastic window!");
let mut cursor_idx = 0;
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
match event {
Event::WindowEvent {
event:
WindowEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Pressed,
..
},
..
},
..
} => {
println!("Setting cursor to \"{:?}\"", CURSORS[cursor_idx]);
window.set_cursor_icon(CURSORS[cursor_idx]);
if cursor_idx < CURSORS.len() - 1 {
cursor_idx += 1;
} else {
cursor_idx = 0;
}
}
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => {
control_flow.set_exit();
}
_ => (),
}
});
}
const CURSORS: &[CursorIcon] = &[
CursorIcon::Default,
CursorIcon::Crosshair,
CursorIcon::Hand,
CursorIcon::Arrow,
CursorIcon::Move,
CursorIcon::Text,
CursorIcon::Wait,
CursorIcon::Help,
CursorIcon::Progress,
CursorIcon::NotAllowed,
CursorIcon::ContextMenu,
CursorIcon::Cell,
CursorIcon::VerticalText,
CursorIcon::Alias,
CursorIcon::Copy,
CursorIcon::NoDrop,
CursorIcon::Grab,
CursorIcon::Grabbing,
CursorIcon::AllScroll,
CursorIcon::ZoomIn,
CursorIcon::ZoomOut,
CursorIcon::EResize,
CursorIcon::NResize,
CursorIcon::NeResize,
CursorIcon::NwResize,
CursorIcon::SResize,
CursorIcon::SeResize,
CursorIcon::SwResize,
CursorIcon::WResize,
CursorIcon::EwResize,
CursorIcon::NsResize,
CursorIcon::NeswResize,
CursorIcon::NwseResize,
CursorIcon::ColResize,
CursorIcon::RowResize,
];

View File

@@ -1,70 +0,0 @@
#![allow(clippy::single_match)]
use simple_logger::SimpleLogger;
use winit::{
event::{DeviceEvent, ElementState, Event, KeyboardInput, ModifiersState, WindowEvent},
event_loop::EventLoop,
window::{CursorGrabMode, WindowBuilder},
};
fn main() {
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_title("Super Cursor Grab'n'Hide Simulator 9000")
.build(&event_loop)
.unwrap();
let mut modifiers = ModifiersState::default();
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
match event {
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => control_flow.set_exit(),
WindowEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Released,
virtual_keycode: Some(key),
..
},
..
} => {
use winit::event::VirtualKeyCode::*;
let result = match key {
Escape => {
control_flow.set_exit();
Ok(())
}
G => window.set_cursor_grab(CursorGrabMode::Confined),
L => window.set_cursor_grab(CursorGrabMode::Locked),
A => window.set_cursor_grab(CursorGrabMode::None),
H => {
window.set_cursor_visible(modifiers.shift());
Ok(())
}
_ => Ok(()),
};
if let Err(err) = result {
println!("error: {err}");
}
}
WindowEvent::ModifiersChanged(m) => modifiers = m,
_ => (),
},
Event::DeviceEvent { event, .. } => match event {
DeviceEvent::MouseMotion { delta } => println!("mouse moved: {delta:?}"),
DeviceEvent::Button { button, state } => match state {
ElementState::Pressed => println!("mouse button {button} pressed"),
ElementState::Released => println!("mouse button {button} released"),
},
_ => (),
},
_ => (),
}
});
}

View File

@@ -1,55 +0,0 @@
#![allow(clippy::single_match)]
#[cfg(not(wasm_platform))]
fn main() {
use simple_logger::SimpleLogger;
use winit::{
event::{Event, WindowEvent},
event_loop::EventLoopBuilder,
window::WindowBuilder,
};
#[derive(Debug, Clone, Copy)]
enum CustomEvent {
Timer,
}
SimpleLogger::new().init().unwrap();
let event_loop = EventLoopBuilder::<CustomEvent>::with_user_event().build();
let _window = WindowBuilder::new()
.with_title("A fantastic window!")
.build(&event_loop)
.unwrap();
// `EventLoopProxy` allows you to dispatch custom events to the main Winit event
// loop from any thread.
let event_loop_proxy = event_loop.create_proxy();
std::thread::spawn(move || {
// Wake up the `event_loop` once every second and dispatch a custom event
// from a different thread.
loop {
std::thread::sleep(std::time::Duration::from_secs(1));
event_loop_proxy.send_event(CustomEvent::Timer).ok();
}
});
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
match event {
Event::UserEvent(event) => println!("user event: {event:?}"),
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => control_flow.set_exit(),
_ => (),
}
});
}
#[cfg(wasm_platform)]
fn main() {
panic!("This example is not supported on web.");
}

View File

@@ -1,75 +0,0 @@
#![allow(clippy::single_match)]
use simple_logger::SimpleLogger;
use winit::{
event::{
ElementState, Event, KeyboardInput, MouseButton, StartCause, VirtualKeyCode, WindowEvent,
},
event_loop::EventLoop,
window::{Window, WindowBuilder, WindowId},
};
fn main() {
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let window_1 = WindowBuilder::new().build(&event_loop).unwrap();
let window_2 = WindowBuilder::new().build(&event_loop).unwrap();
let mut switched = false;
let mut entered_id = window_2.id();
event_loop.run(move |event, _, control_flow| match event {
Event::NewEvents(StartCause::Init) => {
eprintln!("Switch which window is to be dragged by pressing \"x\".")
}
Event::WindowEvent { event, window_id } => match event {
WindowEvent::CloseRequested => control_flow.set_exit(),
WindowEvent::MouseInput {
state: ElementState::Pressed,
button: MouseButton::Left,
..
} => {
let window = if (window_id == window_1.id() && switched)
|| (window_id == window_2.id() && !switched)
{
&window_2
} else {
&window_1
};
window.drag_window().unwrap()
}
WindowEvent::CursorEntered { .. } => {
entered_id = window_id;
name_windows(entered_id, switched, &window_1, &window_2)
}
WindowEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Released,
virtual_keycode: Some(VirtualKeyCode::X),
..
},
..
} => {
switched = !switched;
name_windows(entered_id, switched, &window_1, &window_2);
println!("Switched!")
}
_ => (),
},
_ => (),
});
}
fn name_windows(window_id: WindowId, switched: bool, window_1: &Window, window_2: &Window) {
let (drag_target, other) =
if (window_id == window_1.id() && switched) || (window_id == window_2.id() && !switched) {
(&window_2, &window_1)
} else {
(&window_1, &window_2)
};
drag_target.set_title("drag target");
other.set_title("winit window");
}

View File

@@ -1,122 +0,0 @@
#![allow(clippy::single_match)]
use simple_logger::SimpleLogger;
use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent};
use winit::event_loop::EventLoop;
use winit::window::{Fullscreen, WindowBuilder};
#[cfg(target_os = "macos")]
use winit::platform::macos::WindowExtMacOS;
fn main() {
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let mut decorations = true;
let mut minimized = false;
let window = WindowBuilder::new()
.with_title("Hello world!")
.build(&event_loop)
.unwrap();
let mut monitor_index = 0;
let mut monitor = event_loop
.available_monitors()
.next()
.expect("no monitor found!");
println!("Monitor: {:?}", monitor.name());
let mut mode_index = 0;
let mut mode = monitor.video_modes().next().expect("no mode found");
println!("Mode: {mode}");
println!("Keys:");
println!("- Esc\tExit");
println!("- F\tToggle exclusive fullscreen mode");
println!("- B\tToggle borderless mode");
#[cfg(target_os = "macos")]
println!("- C\tToggle simple fullscreen mode");
println!("- S\tNext screen");
println!("- M\tNext mode for this screen");
println!("- D\tToggle window decorations");
println!("- X\tMaximize window");
println!("- Z\tMinimize window");
event_loop.run(move |event, elwt, control_flow| {
control_flow.set_wait();
match event {
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => control_flow.set_exit(),
WindowEvent::KeyboardInput {
input:
KeyboardInput {
virtual_keycode: Some(virtual_code),
state: ElementState::Pressed,
..
},
..
} => match virtual_code {
VirtualKeyCode::Escape => control_flow.set_exit(),
VirtualKeyCode::F | VirtualKeyCode::B if window.fullscreen().is_some() => {
window.set_fullscreen(None);
}
VirtualKeyCode::F => {
let fullscreen = Some(Fullscreen::Exclusive(mode.clone()));
println!("Setting mode: {fullscreen:?}");
window.set_fullscreen(fullscreen);
}
VirtualKeyCode::B => {
let fullscreen = Some(Fullscreen::Borderless(Some(monitor.clone())));
println!("Setting mode: {fullscreen:?}");
window.set_fullscreen(fullscreen);
}
#[cfg(target_os = "macos")]
VirtualKeyCode::C => {
window.set_simple_fullscreen(!window.simple_fullscreen());
}
VirtualKeyCode::S => {
monitor_index += 1;
if let Some(mon) = elwt.available_monitors().nth(monitor_index) {
monitor = mon;
} else {
monitor_index = 0;
monitor = elwt.available_monitors().next().expect("no monitor found!");
}
println!("Monitor: {:?}", monitor.name());
mode_index = 0;
mode = monitor.video_modes().next().expect("no mode found");
println!("Mode: {mode}");
}
VirtualKeyCode::M => {
mode_index += 1;
if let Some(m) = monitor.video_modes().nth(mode_index) {
mode = m;
} else {
mode_index = 0;
mode = monitor.video_modes().next().expect("no mode found");
}
println!("Mode: {mode}");
}
VirtualKeyCode::D => {
decorations = !decorations;
window.set_decorations(decorations);
}
VirtualKeyCode::X => {
let is_maximized = window.is_maximized();
window.set_maximized(!is_maximized);
}
VirtualKeyCode::Z => {
minimized = !minimized;
window.set_minimized(minimized);
}
_ => (),
},
_ => (),
},
_ => {}
}
});
}

View File

@@ -1,86 +0,0 @@
#![allow(clippy::single_match)]
use simple_logger::SimpleLogger;
use winit::{
event::{Event, KeyboardInput, WindowEvent},
event_loop::EventLoop,
window::WindowBuilder,
};
fn main() {
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let _window = WindowBuilder::new()
.with_title("Your faithful window")
.build(&event_loop)
.unwrap();
let mut close_requested = false;
event_loop.run(move |event, _, control_flow| {
use winit::event::{
ElementState::Released,
VirtualKeyCode::{N, Y},
};
control_flow.set_wait();
match event {
Event::WindowEvent { event, .. } => {
match event {
WindowEvent::CloseRequested => {
// `CloseRequested` is sent when the close button on the window is pressed (or
// through whatever other mechanisms the window manager provides for closing a
// window). If you don't handle this event, the close button won't actually do
// anything.
// A common thing to do here is prompt the user if they have unsaved work.
// Creating a proper dialog box for that is far beyond the scope of this
// example, so here we'll just respond to the Y and N keys.
println!("Are you ready to bid your window farewell? [Y/N]");
close_requested = true;
// In applications where you can safely close the window without further
// action from the user, this is generally where you'd handle cleanup before
// closing the window. How to close the window is detailed in the handler for
// the Y key.
}
WindowEvent::KeyboardInput {
input:
KeyboardInput {
virtual_keycode: Some(virtual_code),
state: Released,
..
},
..
} => {
match virtual_code {
Y => {
if close_requested {
// This is where you'll want to do any cleanup you need.
println!("Buh-bye!");
// For a single-window application like this, you'd normally just
// break out of the event loop here. If you wanted to keep running the
// event loop (i.e. if it's a multi-window application), you need to
// drop the window. That closes it, and results in `Destroyed` being
// sent.
control_flow.set_exit();
}
}
N => {
if close_requested {
println!("Your window will continue to stay by your side.");
close_requested = false;
}
}
_ => (),
}
}
_ => (),
}
}
_ => (),
}
});
}

View File

@@ -1,112 +0,0 @@
#![allow(clippy::single_match)]
use log::LevelFilter;
use simple_logger::SimpleLogger;
use winit::{
dpi::PhysicalPosition,
event::{ElementState, Event, Ime, VirtualKeyCode, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{ImePurpose, WindowBuilder},
};
fn main() {
SimpleLogger::new()
.with_level(LevelFilter::Trace)
.init()
.unwrap();
println!("IME position will system default");
println!("Click to set IME position to cursor's");
println!("Press F2 to toggle IME. See the documentation of `set_ime_allowed` for more info");
println!("Press F3 to cycle through IME purposes.");
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_inner_size(winit::dpi::LogicalSize::new(256f64, 128f64))
.build(&event_loop)
.unwrap();
let mut ime_purpose = ImePurpose::Normal;
let mut ime_allowed = true;
window.set_ime_allowed(ime_allowed);
let mut may_show_ime = false;
let mut cursor_position = PhysicalPosition::new(0.0, 0.0);
let mut ime_pos = PhysicalPosition::new(0.0, 0.0);
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => *control_flow = ControlFlow::Exit,
Event::WindowEvent {
event: WindowEvent::CursorMoved { position, .. },
..
} => {
cursor_position = position;
}
Event::WindowEvent {
event:
WindowEvent::MouseInput {
state: ElementState::Released,
..
},
..
} => {
println!(
"Setting ime position to {}, {}",
cursor_position.x, cursor_position.y
);
ime_pos = cursor_position;
if may_show_ime {
window.set_ime_position(ime_pos);
}
}
Event::WindowEvent {
event: WindowEvent::Ime(event),
..
} => {
println!("{event:?}");
may_show_ime = event != Ime::Disabled;
if may_show_ime {
window.set_ime_position(ime_pos);
}
}
Event::WindowEvent {
event: WindowEvent::ReceivedCharacter(ch),
..
} => {
println!("ch: {ch:?}");
}
Event::WindowEvent {
event: WindowEvent::KeyboardInput { input, .. },
..
} => {
println!("key: {input:?}");
if input.state == ElementState::Pressed
&& input.virtual_keycode == Some(VirtualKeyCode::F2)
{
ime_allowed = !ime_allowed;
window.set_ime_allowed(ime_allowed);
println!("\nIME allowed: {ime_allowed}\n");
}
if input.state == ElementState::Pressed
&& input.virtual_keycode == Some(VirtualKeyCode::F3)
{
ime_purpose = match ime_purpose {
ImePurpose::Normal => ImePurpose::Password,
ImePurpose::Password => ImePurpose::Terminal,
_ => ImePurpose::Normal,
};
window.set_ime_purpose(ime_purpose);
println!("\nIME purpose: {ime_purpose:?}\n");
}
}
_ => (),
}
});
}

View File

@@ -1,58 +0,0 @@
#![allow(clippy::single_match)]
use simple_logger::SimpleLogger;
use winit::dpi::{PhysicalPosition, PhysicalSize};
use winit::monitor::MonitorHandle;
use winit::{event_loop::EventLoop, window::WindowBuilder};
fn main() {
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();
if let Some(mon) = window.primary_monitor() {
print_info("Primary output", mon);
}
for mon in window.available_monitors() {
if Some(&mon) == window.primary_monitor().as_ref() {
continue;
}
println!();
print_info("Output", mon);
}
}
fn print_info(intro: &str, monitor: MonitorHandle) {
if let Some(name) = monitor.name() {
println!("{intro}: {name}");
} else {
println!("{intro}: [no name]");
}
let PhysicalSize { width, height } = monitor.size();
print!(" Current mode: {width}x{height}");
if let Some(m_hz) = monitor.refresh_rate_millihertz() {
println!(" @ {}.{} Hz", m_hz / 1000, m_hz % 1000);
} else {
println!();
}
let PhysicalPosition { x, y } = monitor.position();
println!(" Position: {x},{y}");
println!(" Scale factor: {}", monitor.scale_factor());
println!(" Available modes (width x height x bit-depth):");
for mode in monitor.video_modes() {
let PhysicalSize { width, height } = mode.size();
let bits = mode.bit_depth();
let m_hz = mode.refresh_rate_millihertz();
println!(
" {width}x{height}x{bits} @ {}.{} Hz",
m_hz / 1000,
m_hz % 1000
);
}
}

View File

@@ -1,62 +0,0 @@
#![allow(clippy::single_match)]
use simple_logger::SimpleLogger;
use winit::{
event::{Event, WindowEvent},
event_loop::EventLoop,
window::WindowBuilder,
};
fn main() {
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_title("Mouse Wheel events")
.build(&event_loop)
.unwrap();
println!(
r"
When using so called 'natural scrolling' (scrolling that acts like on a touch screen), this is what to expect:
Moving your finger downwards on a scroll wheel should make the window move down, and you should see a positive Y scroll value.
When moving fingers on a trackpad down and to the right, you should see positive X and Y deltas, and the window should move down and to the right.
With reverse scrolling, you should see the inverse behavior.
In both cases the example window should move like the content of a scroll area in any other application.
In other words, the deltas indicate the direction in which to move the content (in this case the window)."
);
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
match event {
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => control_flow.set_exit(),
WindowEvent::MouseWheel { delta, .. } => match delta {
winit::event::MouseScrollDelta::LineDelta(x, y) => {
println!("mouse wheel Line Delta: ({x},{y})");
let pixels_per_line = 120.0;
let mut pos = window.outer_position().unwrap();
pos.x += (x * pixels_per_line) as i32;
pos.y += (y * pixels_per_line) as i32;
window.set_outer_position(pos)
}
winit::event::MouseScrollDelta::PixelDelta(p) => {
println!("mouse wheel Pixel Delta: ({},{})", p.x, p.y);
let mut pos = window.outer_position().unwrap();
pos.x += p.x as i32;
pos.y += p.y as i32;
window.set_outer_position(pos)
}
},
_ => (),
},
_ => (),
}
});
}

View File

@@ -1,199 +0,0 @@
#![allow(clippy::single_match)]
#[cfg(not(wasm_platform))]
fn main() {
use std::{collections::HashMap, sync::mpsc, thread, time::Duration};
use simple_logger::SimpleLogger;
use winit::{
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
event_loop::EventLoop,
window::{CursorGrabMode, CursorIcon, Fullscreen, WindowBuilder, WindowLevel},
};
const WINDOW_COUNT: usize = 3;
const WINDOW_SIZE: PhysicalSize<u32> = PhysicalSize::new(600, 400);
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let mut window_senders = HashMap::with_capacity(WINDOW_COUNT);
for _ in 0..WINDOW_COUNT {
let window = WindowBuilder::new()
.with_inner_size(WINDOW_SIZE)
.build(&event_loop)
.unwrap();
let mut video_modes: Vec<_> = window.current_monitor().unwrap().video_modes().collect();
let mut video_mode_id = 0usize;
let (tx, rx) = mpsc::channel();
window_senders.insert(window.id(), tx);
thread::spawn(move || {
while let Ok(event) = rx.recv() {
match event {
WindowEvent::Moved { .. } => {
// We need to update our chosen video mode if the window
// was moved to an another monitor, so that the window
// appears on this monitor instead when we go fullscreen
let previous_video_mode = video_modes.get(video_mode_id).cloned();
video_modes = window.current_monitor().unwrap().video_modes().collect();
video_mode_id = video_mode_id.min(video_modes.len());
let video_mode = video_modes.get(video_mode_id);
// Different monitors may support different video modes,
// and the index we chose previously may now point to a
// completely different video mode, so notify the user
if video_mode != previous_video_mode.as_ref() {
println!(
"Window moved to another monitor, picked video mode: {}",
video_modes.get(video_mode_id).unwrap()
);
}
}
#[allow(deprecated)]
WindowEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Released,
virtual_keycode: Some(key),
modifiers,
..
},
..
} => {
window.set_title(&format!("{key:?}"));
let state = !modifiers.shift();
use VirtualKeyCode::*;
match key {
Key1 => window.set_window_level(WindowLevel::AlwaysOnTop),
Key2 => window.set_window_level(WindowLevel::AlwaysOnBottom),
Key3 => window.set_window_level(WindowLevel::Normal),
C => window.set_cursor_icon(match state {
true => CursorIcon::Progress,
false => CursorIcon::Default,
}),
D => window.set_decorations(!state),
// Cycle through video modes
Right | Left => {
video_mode_id = match key {
Left => video_mode_id.saturating_sub(1),
Right => (video_modes.len() - 1).min(video_mode_id + 1),
_ => unreachable!(),
};
println!("Picking video mode: {}", video_modes[video_mode_id]);
}
F => window.set_fullscreen(match (state, modifiers.alt()) {
(true, false) => Some(Fullscreen::Borderless(None)),
(true, true) => {
Some(Fullscreen::Exclusive(video_modes[video_mode_id].clone()))
}
(false, _) => None,
}),
L if state => {
if let Err(err) = window.set_cursor_grab(CursorGrabMode::Locked) {
println!("error: {err}");
}
}
G if state => {
if let Err(err) = window.set_cursor_grab(CursorGrabMode::Confined) {
println!("error: {err}");
}
}
G | L if !state => {
if let Err(err) = window.set_cursor_grab(CursorGrabMode::None) {
println!("error: {err}");
}
}
H => window.set_cursor_visible(!state),
I => {
println!("Info:");
println!("-> outer_position : {:?}", window.outer_position());
println!("-> inner_position : {:?}", window.inner_position());
println!("-> outer_size : {:?}", window.outer_size());
println!("-> inner_size : {:?}", window.inner_size());
println!("-> fullscreen : {:?}", window.fullscreen());
}
L => window.set_min_inner_size(match state {
true => Some(WINDOW_SIZE),
false => None,
}),
M => window.set_maximized(state),
P => window.set_outer_position({
let mut position = window.outer_position().unwrap();
let sign = if state { 1 } else { -1 };
position.x += 10 * sign;
position.y += 10 * sign;
position
}),
Q => window.request_redraw(),
R => window.set_resizable(state),
S => window.set_inner_size(match state {
true => PhysicalSize::new(
WINDOW_SIZE.width + 100,
WINDOW_SIZE.height + 100,
),
false => WINDOW_SIZE,
}),
W => {
if let Size::Physical(size) = WINDOW_SIZE.into() {
window
.set_cursor_position(Position::Physical(
PhysicalPosition::new(
size.width as i32 / 2,
size.height as i32 / 2,
),
))
.unwrap()
}
}
Z => {
window.set_visible(false);
thread::sleep(Duration::from_secs(1));
window.set_visible(true);
}
_ => (),
}
}
_ => (),
}
}
});
}
event_loop.run(move |event, _event_loop, control_flow| {
match !window_senders.is_empty() {
true => control_flow.set_wait(),
false => control_flow.set_exit(),
};
match event {
Event::WindowEvent { event, window_id } => match event {
WindowEvent::CloseRequested
| WindowEvent::Destroyed
| WindowEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Released,
virtual_keycode: Some(VirtualKeyCode::Escape),
..
},
..
} => {
window_senders.remove(&window_id);
}
_ => {
if let Some(tx) = window_senders.get(&window_id) {
if let Some(event) = event.to_static() {
tx.send(event).unwrap();
}
}
}
},
_ => {}
}
})
}
#[cfg(wasm_platform)]
fn main() {
panic!("Example not supported on Wasm");
}

View File

@@ -1,61 +0,0 @@
#![allow(clippy::single_match)]
use std::collections::HashMap;
use simple_logger::SimpleLogger;
use winit::{
event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
event_loop::EventLoop,
window::Window,
};
fn main() {
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let mut windows = HashMap::new();
for _ in 0..3 {
let window = Window::new(&event_loop).unwrap();
println!("Opened a new window: {:?}", window.id());
windows.insert(window.id(), window);
}
println!("Press N to open a new window.");
event_loop.run(move |event, event_loop, control_flow| {
control_flow.set_wait();
match event {
Event::WindowEvent { event, window_id } => {
match event {
WindowEvent::CloseRequested => {
println!("Window {window_id:?} has received the signal to close");
// This drops the window, causing it to close.
windows.remove(&window_id);
if windows.is_empty() {
control_flow.set_exit();
}
}
WindowEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::N),
..
},
is_synthetic: false,
..
} => {
let window = Window::new(event_loop).unwrap();
println!("Opened a new window: {:?}", window.id());
windows.insert(window.id(), window);
}
_ => (),
}
}
_ => (),
}
})
}

View File

@@ -1,41 +0,0 @@
#![allow(clippy::single_match)]
use simple_logger::SimpleLogger;
use winit::{
event::{ElementState, Event, WindowEvent},
event_loop::EventLoop,
window::WindowBuilder,
};
fn main() {
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_title("A fantastic window!")
.build(&event_loop)
.unwrap();
event_loop.run(move |event, _, control_flow| {
println!("{event:?}");
control_flow.set_wait();
match event {
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => control_flow.set_exit(),
WindowEvent::MouseInput {
state: ElementState::Released,
..
} => {
window.request_redraw();
}
_ => (),
},
Event::RedrawRequested(_) => {
println!("\nredrawing!\n");
}
_ => (),
}
});
}

View File

@@ -1,48 +0,0 @@
#![allow(clippy::single_match)]
#[cfg(not(wasm_platform))]
fn main() {
use std::{thread, time};
use simple_logger::SimpleLogger;
use winit::{
event::{Event, WindowEvent},
event_loop::EventLoop,
window::WindowBuilder,
};
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_title("A fantastic window!")
.build(&event_loop)
.unwrap();
thread::spawn(move || loop {
thread::sleep(time::Duration::from_secs(1));
window.request_redraw();
});
event_loop.run(move |event, _, control_flow| {
println!("{event:?}");
control_flow.set_wait();
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => control_flow.set_exit(),
Event::RedrawRequested(_) => {
println!("\nredrawing!\n");
}
_ => (),
}
});
}
#[cfg(wasm_platform)]
fn main() {
unimplemented!() // `Window` can't be sent between threads
}

View File

@@ -1,50 +0,0 @@
#![allow(clippy::single_match)]
use simple_logger::SimpleLogger;
use winit::{
dpi::LogicalSize,
event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
event_loop::EventLoop,
window::WindowBuilder,
};
fn main() {
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let mut resizable = false;
let window = WindowBuilder::new()
.with_title("Hit space to toggle resizability.")
.with_inner_size(LogicalSize::new(600.0, 300.0))
.with_min_inner_size(LogicalSize::new(400.0, 200.0))
.with_max_inner_size(LogicalSize::new(800.0, 400.0))
.with_resizable(resizable)
.build(&event_loop)
.unwrap();
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
match event {
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => control_flow.set_exit(),
WindowEvent::KeyboardInput {
input:
KeyboardInput {
virtual_keycode: Some(VirtualKeyCode::Space),
state: ElementState::Released,
..
},
..
} => {
resizable = !resizable;
println!("Resizable: {resizable}");
window.set_resizable(resizable);
}
_ => (),
},
_ => (),
};
});
}

View File

@@ -1,71 +0,0 @@
#![allow(clippy::single_match)]
use simple_logger::SimpleLogger;
use winit::{
event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{Theme, WindowBuilder},
};
fn main() {
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_title("A fantastic window!")
.with_theme(Some(Theme::Dark))
.build(&event_loop)
.unwrap();
println!("Initial theme: {:?}", window.theme());
println!("debugging keys:");
println!(" (A) Automatic theme");
println!(" (L) Light theme");
println!(" (D) Dark theme");
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => *control_flow = ControlFlow::Exit,
Event::WindowEvent {
event: WindowEvent::ThemeChanged(theme),
window_id,
..
} if window_id == window.id() => {
println!("Theme is changed: {theme:?}")
}
Event::WindowEvent {
event:
WindowEvent::KeyboardInput {
input:
KeyboardInput {
virtual_keycode: Some(key),
state: ElementState::Pressed,
..
},
..
},
..
} => match key {
VirtualKeyCode::A => {
println!("Theme was: {:?}", window.theme());
window.set_theme(None);
}
VirtualKeyCode::L => {
println!("Theme was: {:?}", window.theme());
window.set_theme(Some(Theme::Light));
}
VirtualKeyCode::D => {
println!("Theme was: {:?}", window.theme());
window.set_theme(Some(Theme::Dark));
}
_ => (),
},
_ => (),
}
});
}

View File

@@ -1,42 +0,0 @@
#![allow(clippy::single_match)]
use instant::Instant;
use std::time::Duration;
use simple_logger::SimpleLogger;
use winit::{
event::{Event, StartCause, WindowEvent},
event_loop::EventLoop,
window::WindowBuilder,
};
fn main() {
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let _window = WindowBuilder::new()
.with_title("A fantastic window!")
.build(&event_loop)
.unwrap();
let timer_length = Duration::new(1, 0);
event_loop.run(move |event, _, control_flow| {
println!("{event:?}");
match event {
Event::NewEvents(StartCause::Init) => {
control_flow.set_wait_until(Instant::now() + timer_length);
}
Event::NewEvents(StartCause::ResumeTimeReached { .. }) => {
control_flow.set_wait_until(Instant::now() + timer_length);
println!("\nTimer\n");
}
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => control_flow.set_exit(),
_ => (),
}
});
}

View File

@@ -1,46 +0,0 @@
use simple_logger::SimpleLogger;
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
fn main() {
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let _window = WindowBuilder::new()
.with_title("Touchpad gestures")
.build(&event_loop)
.unwrap();
println!("Only supported on macOS at the moment.");
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
if let Event::WindowEvent { event, .. } = event {
match event {
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
WindowEvent::TouchpadMagnify { delta, .. } => {
if delta > 0.0 {
println!("Zoomed in {delta}");
} else {
println!("Zoomed out {delta}");
}
}
WindowEvent::SmartMagnify { .. } => {
println!("Smart zoom");
}
WindowEvent::TouchpadRotate { delta, .. } => {
if delta > 0.0 {
println!("Rotated counterclockwise {delta}");
} else {
println!("Rotated clockwise {delta}");
}
}
_ => (),
}
}
});
}

View File

@@ -1,34 +0,0 @@
#![allow(clippy::single_match)]
use simple_logger::SimpleLogger;
use winit::{
event::{Event, WindowEvent},
event_loop::EventLoop,
window::WindowBuilder,
};
fn main() {
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_decorations(false)
.with_transparent(true)
.build(&event_loop)
.unwrap();
window.set_title("A fantastic window!");
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
println!("{event:?}");
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => control_flow.set_exit(),
_ => (),
}
});
}

View File

@@ -1,22 +0,0 @@
#![allow(clippy::single_match)]
use simple_logger::SimpleLogger;
use winit::event_loop::EventLoop;
fn main() {
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let monitor = match event_loop.primary_monitor() {
Some(monitor) => monitor,
None => {
println!("No primary monitor detected.");
return;
}
};
println!("Listing available video modes:");
for mode in monitor.video_modes() {
println!("{mode}");
}
}

View File

@@ -1,90 +0,0 @@
#![allow(clippy::single_match)]
use winit::{
event::{Event, WindowEvent},
event_loop::EventLoop,
window::WindowBuilder,
};
pub fn main() {
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_title("A fantastic window!")
.build(&event_loop)
.unwrap();
#[cfg(wasm_platform)]
let log_list = wasm::insert_canvas_and_create_log_list(&window);
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
#[cfg(wasm_platform)]
wasm::log_event(&log_list, &event);
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => control_flow.set_exit(),
Event::MainEventsCleared => {
window.request_redraw();
}
_ => (),
}
});
}
#[cfg(wasm_platform)]
mod wasm {
use wasm_bindgen::prelude::*;
use winit::{event::Event, window::Window};
#[wasm_bindgen(start)]
pub fn run() {
console_log::init_with_level(log::Level::Debug).expect("error initializing logger");
#[allow(clippy::main_recursion)]
super::main();
}
pub fn insert_canvas_and_create_log_list(window: &Window) -> web_sys::Element {
use winit::platform::web::WindowExtWebSys;
let canvas = window.canvas();
let window = web_sys::window().unwrap();
let document = window.document().unwrap();
let body = document.body().unwrap();
// Set a background color for the canvas to make it easier to tell where the canvas is for debugging purposes.
canvas.style().set_css_text("background-color: crimson;");
body.append_child(&canvas).unwrap();
let log_header = document.create_element("h2").unwrap();
log_header.set_text_content(Some("Event Log"));
body.append_child(&log_header).unwrap();
let log_list = document.create_element("ul").unwrap();
body.append_child(&log_list).unwrap();
log_list
}
pub fn log_event(log_list: &web_sys::Element, event: &Event<()>) {
log::debug!("{:?}", event);
// Getting access to browser logs requires a lot of setup on mobile devices.
// So we implement this basic logging system into the page to give developers an easy alternative.
// As a bonus its also kind of handy on desktop.
if let Event::WindowEvent { event, .. } = &event {
let window = web_sys::window().unwrap();
let document = window.document().unwrap();
let log = document.create_element("li").unwrap();
log.set_text_content(Some(&format!("{event:?}")));
log_list
.insert_before(&log, log_list.first_child().as_ref())
.unwrap();
}
}
}

View File

@@ -1,103 +0,0 @@
pub fn main() {
println!("This example must be run with cargo run-wasm --example web_aspect_ratio")
}
#[cfg(wasm_platform)]
mod wasm {
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use web_sys::HtmlCanvasElement;
use winit::{
dpi::PhysicalSize,
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{Window, WindowBuilder},
};
const EXPLANATION: &str = "
This example draws a circle in the middle of a 4/1 aspect ratio canvas which acts as a useful demonstration of winit's resize handling on web.
Even when the browser window is resized or aspect-ratio of the canvas changed the circle should always:
* Fill the entire width or height of the canvas (whichever is smaller) without exceeding it.
* Be perfectly round
* Not be blurry or pixelated (there is no antialiasing so you may still see jagged edges depending on the DPI of your monitor)
Currently winit does not handle resizes on web so the circle is rendered incorrectly.
This example demonstrates the desired future functionality which will possibly be provided by https://github.com/rust-windowing/winit/pull/2074
";
#[wasm_bindgen(start)]
pub fn run() {
console_log::init_with_level(log::Level::Debug).expect("error initializing logger");
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_title("A fantastic window!")
// When running in a non-wasm environment this would set the window size to 100x100.
// However in this example it just sets a default initial size of 100x100 that is immediately overwritten due to the layout + styling of the page.
.with_inner_size(PhysicalSize::new(100, 100))
.build(&event_loop)
.unwrap();
let canvas = create_canvas(&window);
// Render once with the size info we currently have
render_circle(&canvas, window.inner_size());
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
match event {
Event::WindowEvent {
event: WindowEvent::Resized(resize),
window_id,
} if window_id == window.id() => {
render_circle(&canvas, resize);
}
_ => (),
}
});
}
pub fn create_canvas(window: &Window) -> HtmlCanvasElement {
use winit::platform::web::WindowExtWebSys;
let web_window = web_sys::window().unwrap();
let document = web_window.document().unwrap();
let body = document.body().unwrap();
// Set a background color for the canvas to make it easier to tell the where the canvas is for debugging purposes.
let canvas = window.canvas();
canvas
.style()
.set_css_text("display: block; background-color: crimson; margin: auto; width: 50%; aspect-ratio: 4 / 1;");
body.append_child(&canvas).unwrap();
let explanation = document.create_element("pre").unwrap();
explanation.set_text_content(Some(EXPLANATION));
body.append_child(&explanation).unwrap();
canvas
}
pub fn render_circle(canvas: &HtmlCanvasElement, size: PhysicalSize<u32>) {
log::info!("rendering circle with canvas size: {:?}", size);
let context = canvas
.get_context("2d")
.unwrap()
.unwrap()
.dyn_into::<web_sys::CanvasRenderingContext2d>()
.unwrap();
context.begin_path();
context
.arc(
size.width as f64 / 2.0,
size.height as f64 / 2.0,
size.width.min(size.height) as f64 / 2.0,
0.0,
std::f64::consts::PI * 2.0,
)
.unwrap();
context.fill();
}
}

View File

@@ -1,35 +0,0 @@
#![allow(clippy::single_match)]
use simple_logger::SimpleLogger;
use winit::{
event::{Event, WindowEvent},
event_loop::EventLoop,
window::WindowBuilder,
};
fn main() {
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_title("A fantastic window!")
.with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0))
.build(&event_loop)
.unwrap();
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
println!("{event:?}");
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => control_flow.set_exit(),
Event::MainEventsCleared => {
window.request_redraw();
}
_ => (),
}
});
}

View File

@@ -1,68 +0,0 @@
#![allow(clippy::single_match)]
// This example is used by developers to test various window functions.
use simple_logger::SimpleLogger;
use winit::{
dpi::LogicalSize,
event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
event_loop::{DeviceEventFilter, EventLoop},
window::{WindowBuilder, WindowButtons},
};
fn main() {
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_title("A fantastic window!")
.with_inner_size(LogicalSize::new(300.0, 300.0))
.build(&event_loop)
.unwrap();
eprintln!("Window Button keys:");
eprintln!(" (F) Toggle close button");
eprintln!(" (G) Toggle maximize button");
eprintln!(" (H) Toggle minimize button");
event_loop.set_device_event_filter(DeviceEventFilter::Never);
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
match event {
Event::WindowEvent {
event:
WindowEvent::KeyboardInput {
input:
KeyboardInput {
virtual_keycode: Some(key),
state: ElementState::Pressed,
..
},
..
},
..
} => match key {
VirtualKeyCode::F => {
let buttons = window.enabled_buttons();
window.set_enabled_buttons(buttons ^ WindowButtons::CLOSE);
}
VirtualKeyCode::G => {
let buttons = window.enabled_buttons();
window.set_enabled_buttons(buttons ^ WindowButtons::MAXIMIZE);
}
VirtualKeyCode::H => {
let buttons = window.enabled_buttons();
window.set_enabled_buttons(buttons ^ WindowButtons::MINIMIZE);
}
_ => (),
},
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => control_flow.set_exit(),
_ => (),
}
});
}

View File

@@ -1,132 +0,0 @@
#![allow(clippy::single_match)]
// This example is used by developers to test various window functions.
use simple_logger::SimpleLogger;
use winit::{
dpi::{LogicalSize, PhysicalSize},
event::{DeviceEvent, ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
event_loop::{DeviceEventFilter, EventLoop},
window::{Fullscreen, WindowBuilder},
};
fn main() {
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_title("A fantastic window!")
.with_inner_size(LogicalSize::new(100.0, 100.0))
.build(&event_loop)
.unwrap();
eprintln!("debugging keys:");
eprintln!(" (E) Enter exclusive fullscreen");
eprintln!(" (F) Toggle borderless fullscreen");
eprintln!(" (P) Toggle borderless fullscreen on system's preffered monitor");
eprintln!(" (M) Toggle minimized");
eprintln!(" (Q) Quit event loop");
eprintln!(" (V) Toggle visibility");
eprintln!(" (X) Toggle maximized");
let mut minimized = false;
let mut visible = true;
event_loop.set_device_event_filter(DeviceEventFilter::Never);
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
match event {
Event::DeviceEvent {
event:
DeviceEvent::Key(KeyboardInput {
virtual_keycode: Some(key),
state: ElementState::Pressed,
..
}),
..
} => match key {
VirtualKeyCode::M => {
if minimized {
minimized = !minimized;
window.set_minimized(minimized);
window.focus_window();
}
}
VirtualKeyCode::V => {
if !visible {
visible = !visible;
window.set_visible(visible);
}
}
_ => (),
},
Event::WindowEvent {
event:
WindowEvent::KeyboardInput {
input:
KeyboardInput {
virtual_keycode: Some(key),
state: ElementState::Pressed,
..
},
..
},
..
} => match key {
VirtualKeyCode::E => {
fn area(size: PhysicalSize<u32>) -> u32 {
size.width * size.height
}
let monitor = window.current_monitor().unwrap();
if let Some(mode) = monitor
.video_modes()
.max_by(|a, b| area(a.size()).cmp(&area(b.size())))
{
window.set_fullscreen(Some(Fullscreen::Exclusive(mode)));
} else {
eprintln!("no video modes available");
}
}
VirtualKeyCode::F => {
if window.fullscreen().is_some() {
window.set_fullscreen(None);
} else {
let monitor = window.current_monitor();
window.set_fullscreen(Some(Fullscreen::Borderless(monitor)));
}
}
VirtualKeyCode::P => {
if window.fullscreen().is_some() {
window.set_fullscreen(None);
} else {
window.set_fullscreen(Some(Fullscreen::Borderless(None)));
}
}
VirtualKeyCode::M => {
minimized = !minimized;
window.set_minimized(minimized);
}
VirtualKeyCode::Q => {
control_flow.set_exit();
}
VirtualKeyCode::V => {
visible = !visible;
window.set_visible(visible);
}
VirtualKeyCode::X => {
let is_maximized = window.is_maximized();
window.set_maximized(!is_maximized);
}
_ => (),
},
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => control_flow.set_exit(),
_ => (),
}
});
}

View File

@@ -1,141 +0,0 @@
//! Demonstrates capability to create in-app draggable regions for client-side decoration support.
use simple_logger::SimpleLogger;
use winit::{
event::{
ElementState, Event, KeyboardInput, MouseButton, StartCause, VirtualKeyCode, WindowEvent,
},
event_loop::{ControlFlow, EventLoop},
window::{CursorIcon, ResizeDirection, WindowBuilder},
};
const BORDER: f64 = 8.0;
fn main() {
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_inner_size(winit::dpi::LogicalSize::new(600.0, 400.0))
.with_min_inner_size(winit::dpi::LogicalSize::new(400.0, 200.0))
.with_decorations(false)
.build(&event_loop)
.unwrap();
let mut border = false;
let mut cursor_location = None;
event_loop.run(move |event, _, control_flow| match event {
Event::NewEvents(StartCause::Init) => {
eprintln!("Press 'B' to toggle borderless")
}
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
WindowEvent::CursorMoved { position, .. } => {
if !window.is_decorated() {
let new_location =
cursor_resize_direction(window.inner_size(), position, BORDER);
if new_location != cursor_location {
cursor_location = new_location;
window.set_cursor_icon(cursor_direction_icon(cursor_location))
}
}
}
WindowEvent::MouseInput {
state: ElementState::Pressed,
button: MouseButton::Left,
..
} => {
if let Some(dir) = cursor_location {
let _res = window.drag_resize_window(dir);
}
}
WindowEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Released,
virtual_keycode: Some(VirtualKeyCode::B),
..
},
..
} => {
border = !border;
window.set_decorations(border);
}
_ => (),
},
_ => (),
});
}
fn cursor_direction_icon(resize_direction: Option<ResizeDirection>) -> CursorIcon {
match resize_direction {
Some(resize_direction) => match resize_direction {
ResizeDirection::East => CursorIcon::EResize,
ResizeDirection::North => CursorIcon::NResize,
ResizeDirection::NorthEast => CursorIcon::NeResize,
ResizeDirection::NorthWest => CursorIcon::NwResize,
ResizeDirection::South => CursorIcon::SResize,
ResizeDirection::SouthEast => CursorIcon::SeResize,
ResizeDirection::SouthWest => CursorIcon::SwResize,
ResizeDirection::West => CursorIcon::WResize,
},
None => CursorIcon::Default,
}
}
fn cursor_resize_direction(
win_size: winit::dpi::PhysicalSize<u32>,
position: winit::dpi::PhysicalPosition<f64>,
border_size: f64,
) -> Option<ResizeDirection> {
enum XDirection {
West,
East,
Default,
}
enum YDirection {
North,
South,
Default,
}
let xdir = if position.x < border_size {
XDirection::West
} else if position.x > (win_size.width as f64 - border_size) {
XDirection::East
} else {
XDirection::Default
};
let ydir = if position.y < border_size {
YDirection::North
} else if position.y > (win_size.height as f64 - border_size) {
YDirection::South
} else {
YDirection::Default
};
Some(match xdir {
XDirection::West => match ydir {
YDirection::North => ResizeDirection::NorthWest,
YDirection::South => ResizeDirection::SouthWest,
YDirection::Default => ResizeDirection::West,
},
XDirection::East => match ydir {
YDirection::North => ResizeDirection::NorthEast,
YDirection::South => ResizeDirection::SouthEast,
YDirection::Default => ResizeDirection::East,
},
XDirection::Default => match ydir {
YDirection::North => ResizeDirection::North,
YDirection::South => ResizeDirection::South,
YDirection::Default => return None,
},
})
}

View File

@@ -1,59 +0,0 @@
#![allow(clippy::single_match)]
use std::path::Path;
use simple_logger::SimpleLogger;
use winit::{
event::Event,
event_loop::EventLoop,
window::{Icon, WindowBuilder},
};
fn main() {
SimpleLogger::new().init().unwrap();
// You'll have to choose an icon size at your own discretion. On X11, the desired size varies
// by WM, and on Windows, you still have to account for screen scaling. Here we use 32px,
// since it seems to work well enough in most cases. Be careful about going too high, or
// you'll be bitten by the low-quality downscaling built into the WM.
let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/icon.png");
let icon = load_icon(Path::new(path));
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_title("An iconic window!")
// At present, this only does anything on Windows and X11, so if you want to save load
// time, you can put icon loading behind a function that returns `None` on other platforms.
.with_window_icon(Some(icon))
.build(&event_loop)
.unwrap();
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
if let Event::WindowEvent { event, .. } = event {
use winit::event::WindowEvent::*;
match event {
CloseRequested => control_flow.set_exit(),
DroppedFile(path) => {
window.set_window_icon(Some(load_icon(&path)));
}
_ => (),
}
}
});
}
fn load_icon(path: &Path) -> Icon {
let (icon_rgba, icon_width, icon_height) = {
let image = image::open(path)
.expect("Failed to open icon path")
.into_rgba8();
let (width, height) = image.dimensions();
let rgba = image.into_raw();
(rgba, width, height)
};
Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon")
}

View File

@@ -1,67 +0,0 @@
#![allow(clippy::single_match)]
#[cfg(target_os = "macos")]
use winit::platform::macos::{OptionAsAlt, WindowExtMacOS};
#[cfg(target_os = "macos")]
use winit::{
event::ElementState,
event::{Event, MouseButton, WindowEvent},
event_loop::EventLoop,
window::WindowBuilder,
};
/// Prints the keyboard events characters received when option_is_alt is true versus false.
/// A left mouse click will toggle option_is_alt.
#[cfg(target_os = "macos")]
fn main() {
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_title("A fantastic window!")
.with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0))
.build(&event_loop)
.unwrap();
let mut option_as_alt = window.option_as_alt();
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => control_flow.set_exit(),
Event::WindowEvent { event, .. } => match event {
WindowEvent::MouseInput {
state: ElementState::Pressed,
button: MouseButton::Left,
..
} => {
option_as_alt = match option_as_alt {
OptionAsAlt::None => OptionAsAlt::OnlyLeft,
OptionAsAlt::OnlyLeft => OptionAsAlt::OnlyRight,
OptionAsAlt::OnlyRight => OptionAsAlt::Both,
OptionAsAlt::Both => OptionAsAlt::None,
};
println!("Received Mouse click, toggling option_as_alt to: {option_as_alt:?}");
window.set_option_as_alt(option_as_alt);
}
WindowEvent::ReceivedCharacter(c) => println!("ReceivedCharacter: {c:?}"),
WindowEvent::KeyboardInput { .. } => println!("KeyboardInput: {event:?}"),
_ => (),
},
Event::MainEventsCleared => {
window.request_redraw();
}
_ => (),
}
});
}
#[cfg(not(target_os = "macos"))]
fn main() {
println!("This example is only supported on MacOS");
}

View File

@@ -1,57 +0,0 @@
use log::debug;
use simple_logger::SimpleLogger;
use winit::{
dpi::LogicalSize,
event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
event_loop::EventLoop,
window::WindowBuilder,
};
fn main() {
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_title("A fantastic window!")
.with_inner_size(LogicalSize::new(128.0, 128.0))
.with_resize_increments(LogicalSize::new(25.0, 25.0))
.build(&event_loop)
.unwrap();
let mut has_increments = true;
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => control_flow.set_exit(),
Event::WindowEvent {
event:
WindowEvent::KeyboardInput {
input:
KeyboardInput {
virtual_keycode: Some(VirtualKeyCode::Space),
state: ElementState::Released,
..
},
..
},
window_id,
} if window_id == window.id() => {
has_increments = !has_increments;
let new_increments = match window.resize_increments() {
Some(_) => None,
None => Some(LogicalSize::new(25.0, 25.0)),
};
debug!("Had increments: {}", new_increments.is_none());
window.set_resize_increments(new_increments);
}
Event::MainEventsCleared => window.request_redraw(),
_ => (),
}
});
}

View File

@@ -1,64 +0,0 @@
#![allow(clippy::single_match)]
// Limit this example to only compatible platforms.
#[cfg(any(
windows_platform,
macos_platform,
x11_platform,
wayland_platform,
android_platform,
orbital_platform,
))]
fn main() {
use std::{thread::sleep, time::Duration};
use simple_logger::SimpleLogger;
use winit::{
event::{Event, WindowEvent},
event_loop::EventLoop,
platform::run_return::EventLoopExtRunReturn,
window::WindowBuilder,
};
let mut event_loop = EventLoop::new();
SimpleLogger::new().init().unwrap();
let _window = WindowBuilder::new()
.with_title("A fantastic window!")
.build(&event_loop)
.unwrap();
let mut quit = false;
while !quit {
event_loop.run_return(|event, _, control_flow| {
control_flow.set_wait();
if let Event::WindowEvent { event, .. } = &event {
// Print only Window events to reduce noise
println!("{event:?}");
}
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => {
quit = true;
}
Event::MainEventsCleared => {
control_flow.set_exit();
}
_ => (),
}
});
// Sleep for 1/60 second to simulate rendering
println!("rendering");
sleep(Duration::from_millis(16));
}
}
#[cfg(any(ios_platform, wasm_platform))]
fn main() {
println!("This platform doesn't support run_return.");
}

View File

@@ -1,9 +0,0 @@
[package]
name = "run-wasm"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
cargo-run-wasm = "0.2.0"

View File

@@ -1,3 +0,0 @@
fn main() {
cargo_run_wasm::run_wasm_with_css("body { margin: 0px; }");
}

View File

@@ -1,3 +1,20 @@
force_explicit_abi=true
use_field_init_shorthand=true
# merge_imports=true
comment_width = 100
condense_wildcard_suffixes = true
error_on_unformatted = true
format_code_in_doc_comments = true
format_macro_bodies = true
format_macro_matchers = true
format_strings = true
group_imports = "StdExternalCrate"
hex_literal_case = "Lower"
imports_granularity = "Module"
match_block_trailing_comma = true
newline_style = "Unix"
normalize_comments = true
normalize_doc_attributes = true
overflow_delimited_expr = true
# Some macros break with this.
reorder_impl_items = false
use_field_init_shorthand = true
use_small_heuristics = "Max"
wrap_comments = true

View File

@@ -1,583 +0,0 @@
//! UI scaling is important, so read the docs for this module if you don't want to be confused.
//!
//! ## Why should I care about UI scaling?
//!
//! Modern computer screens don't have a consistent relationship between resolution and size.
//! 1920x1080 is a common resolution for both desktop and mobile screens, despite mobile screens
//! normally being less than a quarter the size of their desktop counterparts. What's more, neither
//! desktop nor mobile screens are consistent resolutions within their own size classes - common
//! mobile screens range from below 720p to above 1440p, and desktop screens range from 720p to 5K
//! and beyond.
//!
//! Given that, it's a mistake to assume that 2D content will only be displayed on screens with
//! a consistent pixel density. If you were to render a 96-pixel-square image on a 1080p screen,
//! then render the same image on a similarly-sized 4K screen, the 4K rendition would only take up
//! about a quarter of the physical space as it did on the 1080p screen. That issue is especially
//! problematic with text rendering, where quarter-sized text becomes a significant legibility
//! problem.
//!
//! Failure to account for the scale factor can create a significantly degraded user experience.
//! Most notably, it can make users feel like they have bad eyesight, which will potentially cause
//! them to think about growing elderly, resulting in them having an existential crisis. Once users
//! enter that state, they will no longer be focused on your application.
//!
//! ## How should I handle it?
//!
//! The solution to this problem is to account for the device's *scale factor*. The scale factor is
//! the factor UI elements should be scaled by to be consistent with the rest of the user's system -
//! for example, a button that's normally 50 pixels across would be 100 pixels across on a device
//! with a scale factor of `2.0`, or 75 pixels across with a scale factor of `1.5`.
//!
//! Many UI systems, such as CSS, expose DPI-dependent units like [points] or [picas]. That's
//! usually a mistake, since there's no consistent mapping between the scale factor and the screen's
//! actual DPI. Unless you're printing to a physical medium, you should work in scaled pixels rather
//! than any DPI-dependent units.
//!
//! ### Position and Size types
//!
//! Winit's [`PhysicalPosition`] / [`PhysicalSize`] types correspond with the actual pixels on the
//! device, and the [`LogicalPosition`] / [`LogicalSize`] types correspond to the physical pixels
//! divided by the scale factor.
//! All of Winit's functions return physical types, but can take either logical or physical
//! coordinates as input, allowing you to use the most convenient coordinate system for your
//! particular application.
//!
//! Winit's position and size types types are generic over their exact pixel type, `P`, to allow the
//! API to have integer precision where appropriate (e.g. most window manipulation functions) and
//! floating precision when necessary (e.g. logical sizes for fractional scale factors and touch
//! input). If `P` is a floating-point type, please do not cast the values with `as {int}`. Doing so
//! will truncate the fractional part of the float, rather than properly round to the nearest
//! integer. Use the provided `cast` function or [`From`]/[`Into`] conversions, which handle the
//! rounding properly. Note that precision loss will still occur when rounding from a float to an
//! int, although rounding lessens the problem.
//!
//! ### Events
//!
//! Winit will dispatch a [`ScaleFactorChanged`] event whenever a window's scale factor has changed.
//! This can happen if the user drags their window from a standard-resolution monitor to a high-DPI
//! monitor, or if the user changes their DPI settings. This gives you a chance to rescale your
//! application's UI elements and adjust how the platform changes the window's size to reflect the new
//! scale factor. If a window hasn't received a [`ScaleFactorChanged`] event, then its scale factor
//! can be found by calling [`window.scale_factor()`].
//!
//! ## How is the scale factor calculated?
//!
//! Scale factor is calculated differently on different platforms:
//!
//! - **Windows:** On Windows 8 and 10, per-monitor scaling is readily configured by users from the
//! display settings. While users are free to select any option they want, they're only given a
//! selection of "nice" scale factors, i.e. 1.0, 1.25, 1.5... on Windows 7, the scale factor is
//! global and changing it requires logging out. See [this article][windows_1] for technical
//! details.
//! - **macOS:** Recent versions of macOS allow the user to change the scaling factor for certain
//! displays. When this is available, the user may pick a per-monitor scaling factor from a set
//! of pre-defined settings. All "retina displays" have a scaling factor above 1.0 by default but
//! the specific value varies across devices.
//! - **X11:** Many man-hours have been spent trying to figure out how to handle DPI in X11. Winit
//! currently uses a three-pronged approach:
//! + Use the value in the `WINIT_X11_SCALE_FACTOR` environment variable, if present.
//! + If not present, use the value set in `Xft.dpi` in Xresources.
//! + Otherwise, calculate the scale factor based on the millimeter monitor dimensions provided by XRandR.
//!
//! If `WINIT_X11_SCALE_FACTOR` is set to `randr`, it'll ignore the `Xft.dpi` field and use the
//! XRandR scaling method. Generally speaking, you should try to configure the standard system
//! variables to do what you want before resorting to `WINIT_X11_SCALE_FACTOR`.
//! - **Wayland:** On Wayland, scale factors are set per-screen by the server, and are always
//! integers (most often 1 or 2).
//! - **iOS:** Scale factors are set by Apple to the value that best suits the device, and range
//! from `1.0` to `3.0`. See [this article][apple_1] and [this article][apple_2] for more
//! information.
//! - **Android:** Scale factors are set by the manufacturer to the value that best suits the
//! device, and range from `1.0` to `4.0`. See [this article][android_1] for more information.
//! - **Web:** The scale factor is the ratio between CSS pixels and the physical device pixels.
//! In other words, it is the value of [`window.devicePixelRatio`][web_1]. It is affected by
//! both the screen scaling and the browser zoom level and can go below `1.0`.
//!
//!
//! [points]: https://en.wikipedia.org/wiki/Point_(typography)
//! [picas]: https://en.wikipedia.org/wiki/Pica_(typography)
//! [`ScaleFactorChanged`]: crate::event::WindowEvent::ScaleFactorChanged
//! [`window.scale_factor()`]: crate::window::Window::scale_factor
//! [windows_1]: https://docs.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows
//! [apple_1]: https://developer.apple.com/library/archive/documentation/DeviceInformation/Reference/iOSDeviceCompatibility/Displays/Displays.html
//! [apple_2]: https://developer.apple.com/design/human-interface-guidelines/macos/icons-and-images/image-size-and-resolution/
//! [android_1]: https://developer.android.com/training/multiscreen/screendensities
//! [web_1]: https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio
pub trait Pixel: Copy + Into<f64> {
fn from_f64(f: f64) -> Self;
fn cast<P: Pixel>(self) -> P {
P::from_f64(self.into())
}
}
impl Pixel for u8 {
fn from_f64(f: f64) -> Self {
f.round() as u8
}
}
impl Pixel for u16 {
fn from_f64(f: f64) -> Self {
f.round() as u16
}
}
impl Pixel for u32 {
fn from_f64(f: f64) -> Self {
f.round() as u32
}
}
impl Pixel for i8 {
fn from_f64(f: f64) -> Self {
f.round() as i8
}
}
impl Pixel for i16 {
fn from_f64(f: f64) -> Self {
f.round() as i16
}
}
impl Pixel for i32 {
fn from_f64(f: f64) -> Self {
f.round() as i32
}
}
impl Pixel for f32 {
fn from_f64(f: f64) -> Self {
f as f32
}
}
impl Pixel for f64 {
fn from_f64(f: f64) -> Self {
f
}
}
/// Checks that the scale factor is a normal positive `f64`.
///
/// All functions that take a scale factor assert that this will return `true`. If you're sourcing scale factors from
/// anywhere other than winit, it's recommended to validate them using this function before passing them to winit;
/// otherwise, you risk panics.
#[inline]
pub fn validate_scale_factor(scale_factor: f64) -> bool {
scale_factor.is_sign_positive() && scale_factor.is_normal()
}
/// A position represented in logical pixels.
///
/// The position is stored as floats, so please be careful. Casting floats to integers truncates the
/// fractional part, which can cause noticable issues. To help with that, an `Into<(i32, i32)>`
/// implementation is provided which does the rounding for you.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct LogicalPosition<P> {
pub x: P,
pub y: P,
}
impl<P> LogicalPosition<P> {
#[inline]
pub const fn new(x: P, y: P) -> Self {
LogicalPosition { x, y }
}
}
impl<P: Pixel> LogicalPosition<P> {
#[inline]
pub fn from_physical<T: Into<PhysicalPosition<X>>, X: Pixel>(
physical: T,
scale_factor: f64,
) -> Self {
physical.into().to_logical(scale_factor)
}
#[inline]
pub fn to_physical<X: Pixel>(&self, scale_factor: f64) -> PhysicalPosition<X> {
assert!(validate_scale_factor(scale_factor));
let x = self.x.into() * scale_factor;
let y = self.y.into() * scale_factor;
PhysicalPosition::new(x, y).cast()
}
#[inline]
pub fn cast<X: Pixel>(&self) -> LogicalPosition<X> {
LogicalPosition {
x: self.x.cast(),
y: self.y.cast(),
}
}
}
impl<P: Pixel, X: Pixel> From<(X, X)> for LogicalPosition<P> {
fn from((x, y): (X, X)) -> LogicalPosition<P> {
LogicalPosition::new(x.cast(), y.cast())
}
}
impl<P: Pixel, X: Pixel> From<LogicalPosition<P>> for (X, X) {
fn from(p: LogicalPosition<P>) -> (X, X) {
(p.x.cast(), p.y.cast())
}
}
impl<P: Pixel, X: Pixel> From<[X; 2]> for LogicalPosition<P> {
fn from([x, y]: [X; 2]) -> LogicalPosition<P> {
LogicalPosition::new(x.cast(), y.cast())
}
}
impl<P: Pixel, X: Pixel> From<LogicalPosition<P>> for [X; 2] {
fn from(p: LogicalPosition<P>) -> [X; 2] {
[p.x.cast(), p.y.cast()]
}
}
#[cfg(feature = "mint")]
impl<P: Pixel> From<mint::Point2<P>> for LogicalPosition<P> {
fn from(p: mint::Point2<P>) -> Self {
Self::new(p.x, p.y)
}
}
#[cfg(feature = "mint")]
impl<P: Pixel> From<LogicalPosition<P>> for mint::Point2<P> {
fn from(p: LogicalPosition<P>) -> Self {
mint::Point2 { x: p.x, y: p.y }
}
}
/// A position represented in physical pixels.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct PhysicalPosition<P> {
pub x: P,
pub y: P,
}
impl<P> PhysicalPosition<P> {
#[inline]
pub const fn new(x: P, y: P) -> Self {
PhysicalPosition { x, y }
}
}
impl<P: Pixel> PhysicalPosition<P> {
#[inline]
pub fn from_logical<T: Into<LogicalPosition<X>>, X: Pixel>(
logical: T,
scale_factor: f64,
) -> Self {
logical.into().to_physical(scale_factor)
}
#[inline]
pub fn to_logical<X: Pixel>(&self, scale_factor: f64) -> LogicalPosition<X> {
assert!(validate_scale_factor(scale_factor));
let x = self.x.into() / scale_factor;
let y = self.y.into() / scale_factor;
LogicalPosition::new(x, y).cast()
}
#[inline]
pub fn cast<X: Pixel>(&self) -> PhysicalPosition<X> {
PhysicalPosition {
x: self.x.cast(),
y: self.y.cast(),
}
}
}
impl<P: Pixel, X: Pixel> From<(X, X)> for PhysicalPosition<P> {
fn from((x, y): (X, X)) -> PhysicalPosition<P> {
PhysicalPosition::new(x.cast(), y.cast())
}
}
impl<P: Pixel, X: Pixel> From<PhysicalPosition<P>> for (X, X) {
fn from(p: PhysicalPosition<P>) -> (X, X) {
(p.x.cast(), p.y.cast())
}
}
impl<P: Pixel, X: Pixel> From<[X; 2]> for PhysicalPosition<P> {
fn from([x, y]: [X; 2]) -> PhysicalPosition<P> {
PhysicalPosition::new(x.cast(), y.cast())
}
}
impl<P: Pixel, X: Pixel> From<PhysicalPosition<P>> for [X; 2] {
fn from(p: PhysicalPosition<P>) -> [X; 2] {
[p.x.cast(), p.y.cast()]
}
}
#[cfg(feature = "mint")]
impl<P: Pixel> From<mint::Point2<P>> for PhysicalPosition<P> {
fn from(p: mint::Point2<P>) -> Self {
Self::new(p.x, p.y)
}
}
#[cfg(feature = "mint")]
impl<P: Pixel> From<PhysicalPosition<P>> for mint::Point2<P> {
fn from(p: PhysicalPosition<P>) -> Self {
mint::Point2 { x: p.x, y: p.y }
}
}
/// A size represented in logical pixels.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct LogicalSize<P> {
pub width: P,
pub height: P,
}
impl<P> LogicalSize<P> {
#[inline]
pub const fn new(width: P, height: P) -> Self {
LogicalSize { width, height }
}
}
impl<P: Pixel> LogicalSize<P> {
#[inline]
pub fn from_physical<T: Into<PhysicalSize<X>>, X: Pixel>(
physical: T,
scale_factor: f64,
) -> Self {
physical.into().to_logical(scale_factor)
}
#[inline]
pub fn to_physical<X: Pixel>(&self, scale_factor: f64) -> PhysicalSize<X> {
assert!(validate_scale_factor(scale_factor));
let width = self.width.into() * scale_factor;
let height = self.height.into() * scale_factor;
PhysicalSize::new(width, height).cast()
}
#[inline]
pub fn cast<X: Pixel>(&self) -> LogicalSize<X> {
LogicalSize {
width: self.width.cast(),
height: self.height.cast(),
}
}
}
impl<P: Pixel, X: Pixel> From<(X, X)> for LogicalSize<P> {
fn from((x, y): (X, X)) -> LogicalSize<P> {
LogicalSize::new(x.cast(), y.cast())
}
}
impl<P: Pixel, X: Pixel> From<LogicalSize<P>> for (X, X) {
fn from(s: LogicalSize<P>) -> (X, X) {
(s.width.cast(), s.height.cast())
}
}
impl<P: Pixel, X: Pixel> From<[X; 2]> for LogicalSize<P> {
fn from([x, y]: [X; 2]) -> LogicalSize<P> {
LogicalSize::new(x.cast(), y.cast())
}
}
impl<P: Pixel, X: Pixel> From<LogicalSize<P>> for [X; 2] {
fn from(s: LogicalSize<P>) -> [X; 2] {
[s.width.cast(), s.height.cast()]
}
}
#[cfg(feature = "mint")]
impl<P: Pixel> From<mint::Vector2<P>> for LogicalSize<P> {
fn from(v: mint::Vector2<P>) -> Self {
Self::new(v.x, v.y)
}
}
#[cfg(feature = "mint")]
impl<P: Pixel> From<LogicalSize<P>> for mint::Vector2<P> {
fn from(s: LogicalSize<P>) -> Self {
mint::Vector2 {
x: s.width,
y: s.height,
}
}
}
/// A size represented in physical pixels.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct PhysicalSize<P> {
pub width: P,
pub height: P,
}
impl<P> PhysicalSize<P> {
#[inline]
pub const fn new(width: P, height: P) -> Self {
PhysicalSize { width, height }
}
}
impl<P: Pixel> PhysicalSize<P> {
#[inline]
pub fn from_logical<T: Into<LogicalSize<X>>, X: Pixel>(logical: T, scale_factor: f64) -> Self {
logical.into().to_physical(scale_factor)
}
#[inline]
pub fn to_logical<X: Pixel>(&self, scale_factor: f64) -> LogicalSize<X> {
assert!(validate_scale_factor(scale_factor));
let width = self.width.into() / scale_factor;
let height = self.height.into() / scale_factor;
LogicalSize::new(width, height).cast()
}
#[inline]
pub fn cast<X: Pixel>(&self) -> PhysicalSize<X> {
PhysicalSize {
width: self.width.cast(),
height: self.height.cast(),
}
}
}
impl<P: Pixel, X: Pixel> From<(X, X)> for PhysicalSize<P> {
fn from((x, y): (X, X)) -> PhysicalSize<P> {
PhysicalSize::new(x.cast(), y.cast())
}
}
impl<P: Pixel, X: Pixel> From<PhysicalSize<P>> for (X, X) {
fn from(s: PhysicalSize<P>) -> (X, X) {
(s.width.cast(), s.height.cast())
}
}
impl<P: Pixel, X: Pixel> From<[X; 2]> for PhysicalSize<P> {
fn from([x, y]: [X; 2]) -> PhysicalSize<P> {
PhysicalSize::new(x.cast(), y.cast())
}
}
impl<P: Pixel, X: Pixel> From<PhysicalSize<P>> for [X; 2] {
fn from(s: PhysicalSize<P>) -> [X; 2] {
[s.width.cast(), s.height.cast()]
}
}
#[cfg(feature = "mint")]
impl<P: Pixel> From<mint::Vector2<P>> for PhysicalSize<P> {
fn from(v: mint::Vector2<P>) -> Self {
Self::new(v.x, v.y)
}
}
#[cfg(feature = "mint")]
impl<P: Pixel> From<PhysicalSize<P>> for mint::Vector2<P> {
fn from(s: PhysicalSize<P>) -> Self {
mint::Vector2 {
x: s.width,
y: s.height,
}
}
}
/// A size that's either physical or logical.
#[derive(Debug, Copy, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Size {
Physical(PhysicalSize<u32>),
Logical(LogicalSize<f64>),
}
impl Size {
pub fn new<S: Into<Size>>(size: S) -> Size {
size.into()
}
pub fn to_logical<P: Pixel>(&self, scale_factor: f64) -> LogicalSize<P> {
match *self {
Size::Physical(size) => size.to_logical(scale_factor),
Size::Logical(size) => size.cast(),
}
}
pub fn to_physical<P: Pixel>(&self, scale_factor: f64) -> PhysicalSize<P> {
match *self {
Size::Physical(size) => size.cast(),
Size::Logical(size) => size.to_physical(scale_factor),
}
}
pub fn clamp<S: Into<Size>>(input: S, min: S, max: S, scale_factor: f64) -> Size {
let (input, min, max) = (
input.into().to_physical::<f64>(scale_factor),
min.into().to_physical::<f64>(scale_factor),
max.into().to_physical::<f64>(scale_factor),
);
let width = input.width.clamp(min.width, max.width);
let height = input.height.clamp(min.height, max.height);
PhysicalSize::new(width, height).into()
}
}
impl<P: Pixel> From<PhysicalSize<P>> for Size {
#[inline]
fn from(size: PhysicalSize<P>) -> Size {
Size::Physical(size.cast())
}
}
impl<P: Pixel> From<LogicalSize<P>> for Size {
#[inline]
fn from(size: LogicalSize<P>) -> Size {
Size::Logical(size.cast())
}
}
/// A position that's either physical or logical.
#[derive(Debug, Copy, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Position {
Physical(PhysicalPosition<i32>),
Logical(LogicalPosition<f64>),
}
impl Position {
pub fn new<S: Into<Position>>(position: S) -> Position {
position.into()
}
pub fn to_logical<P: Pixel>(&self, scale_factor: f64) -> LogicalPosition<P> {
match *self {
Position::Physical(position) => position.to_logical(scale_factor),
Position::Logical(position) => position.cast(),
}
}
pub fn to_physical<P: Pixel>(&self, scale_factor: f64) -> PhysicalPosition<P> {
match *self {
Position::Physical(position) => position.cast(),
Position::Logical(position) => position.to_physical(scale_factor),
}
}
}
impl<P: Pixel> From<PhysicalPosition<P>> for Position {
#[inline]
fn from(position: PhysicalPosition<P>) -> Position {
Position::Physical(position.cast())
}
}
impl<P: Pixel> From<LogicalPosition<P>> for Position {
#[inline]
fn from(position: LogicalPosition<P>) -> Position {
Position::Logical(position.cast())
}
}

View File

@@ -1,82 +0,0 @@
use std::{error, fmt};
use crate::platform_impl;
/// An error whose cause it outside Winit's control.
#[derive(Debug)]
pub enum ExternalError {
/// The operation is not supported by the backend.
NotSupported(NotSupportedError),
/// The OS cannot perform the operation.
Os(OsError),
}
/// The error type for when the requested operation is not supported by the backend.
#[derive(Clone)]
pub struct NotSupportedError {
_marker: (),
}
/// The error type for when the OS cannot perform the requested operation.
#[derive(Debug)]
pub struct OsError {
line: u32,
file: &'static str,
error: platform_impl::OsError,
}
impl NotSupportedError {
#[inline]
#[allow(dead_code)]
pub(crate) fn new() -> NotSupportedError {
NotSupportedError { _marker: () }
}
}
impl OsError {
#[allow(dead_code)]
pub(crate) fn new(line: u32, file: &'static str, error: platform_impl::OsError) -> OsError {
OsError { line, file, error }
}
}
#[allow(unused_macros)]
macro_rules! os_error {
($error:expr) => {{
crate::error::OsError::new(line!(), file!(), $error)
}};
}
impl fmt::Display for OsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.pad(&format!(
"os error at {}:{}: {}",
self.file, self.line, self.error
))
}
}
impl fmt::Display for ExternalError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
ExternalError::NotSupported(e) => e.fmt(f),
ExternalError::Os(e) => e.fmt(f),
}
}
}
impl fmt::Debug for NotSupportedError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.debug_struct("NotSupportedError").finish()
}
}
impl fmt::Display for NotSupportedError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.pad("the requested operation is not supported by Winit")
}
}
impl error::Error for OsError {}
impl error::Error for ExternalError {}
impl error::Error for NotSupportedError {}

File diff suppressed because it is too large Load Diff

View File

@@ -1,440 +0,0 @@
//! The [`EventLoop`] struct and assorted supporting types, including
//! [`ControlFlow`].
//!
//! If you want to send custom events to the event loop, use
//! [`EventLoop::create_proxy`] to acquire an [`EventLoopProxy`] and call its
//! [`send_event`](`EventLoopProxy::send_event`) method.
//!
//! See the root-level documentation for information on how to create and use an event loop to
//! handle events.
use std::marker::PhantomData;
use std::ops::Deref;
use std::{error, fmt};
use instant::{Duration, Instant};
use once_cell::sync::OnceCell;
use raw_window_handle::{HasRawDisplayHandle, RawDisplayHandle};
use crate::{event::Event, monitor::MonitorHandle, platform_impl};
/// Provides a way to retrieve events from the system and from the windows that were registered to
/// the events loop.
///
/// An `EventLoop` can be seen more or less as a "context". Calling [`EventLoop::new`]
/// initializes everything that will be required to create windows. For example on Linux creating
/// an event loop opens a connection to the X or Wayland server.
///
/// To wake up an `EventLoop` from a another thread, see the [`EventLoopProxy`] docs.
///
/// Note that this cannot be shared across threads (due to platform-dependant logic
/// forbidding it), as such it is neither [`Send`] nor [`Sync`]. If you need cross-thread access, the
/// [`Window`] created from this _can_ be sent to an other thread, and the
/// [`EventLoopProxy`] allows you to wake up an `EventLoop` from another thread.
///
/// [`Window`]: crate::window::Window
pub struct EventLoop<T: 'static> {
pub(crate) event_loop: platform_impl::EventLoop<T>,
pub(crate) _marker: PhantomData<*mut ()>, // Not Send nor Sync
}
/// Target that associates windows with an [`EventLoop`].
///
/// This type exists to allow you to create new windows while Winit executes
/// your callback. [`EventLoop`] will coerce into this type (`impl<T> Deref for
/// EventLoop<T>`), so functions that take this as a parameter can also take
/// `&EventLoop`.
pub struct EventLoopWindowTarget<T: 'static> {
pub(crate) p: platform_impl::EventLoopWindowTarget<T>,
pub(crate) _marker: PhantomData<*mut ()>, // Not Send nor Sync
}
/// Object that allows building the event loop.
///
/// This is used to make specifying options that affect the whole application
/// easier. But note that constructing multiple event loops is not supported.
#[derive(Default)]
pub struct EventLoopBuilder<T: 'static> {
pub(crate) platform_specific: platform_impl::PlatformSpecificEventLoopAttributes,
_p: PhantomData<T>,
}
impl EventLoopBuilder<()> {
/// Start building a new event loop.
#[inline]
pub fn new() -> Self {
Self::with_user_event()
}
}
impl<T> EventLoopBuilder<T> {
/// Start building a new event loop, with the given type as the user event
/// type.
#[inline]
pub fn with_user_event() -> Self {
Self {
platform_specific: Default::default(),
_p: PhantomData,
}
}
/// Builds a new event loop.
///
/// ***For cross-platform compatibility, the [`EventLoop`] must be created on the main thread,
/// and only once per application.***
///
/// Attempting to create the event loop on a different thread, or multiple event loops in
/// the same application, will panic. This restriction isn't
/// strictly necessary on all platforms, but is imposed to eliminate any nasty surprises when
/// porting to platforms that require it. `EventLoopBuilderExt::any_thread` functions are exposed
/// in the relevant [`platform`] module if the target platform supports creating an event loop on
/// any thread.
///
/// Calling this function will result in display backend initialisation.
///
/// ## Platform-specific
///
/// - **Linux:** Backend type can be controlled using an environment variable
/// `WINIT_UNIX_BACKEND`. Legal values are `x11` and `wayland`.
/// If it is not set, winit will try to connect to a Wayland connection, and if that fails,
/// will fall back on X11. If this variable is set with any other value, winit will panic.
/// - **Android:** Must be configured with an `AndroidApp` from `android_main()` by calling
/// [`.with_android_app(app)`] before calling `.build()`.
///
/// [`platform`]: crate::platform
#[cfg_attr(
android,
doc = "[`.with_android_app(app)`]: crate::platform::android::EventLoopBuilderExtAndroid::with_android_app"
)]
#[cfg_attr(
not(android),
doc = "[`.with_android_app(app)`]: #only-available-on-android"
)]
#[inline]
pub fn build(&mut self) -> EventLoop<T> {
static EVENT_LOOP_CREATED: OnceCell<()> = OnceCell::new();
if EVENT_LOOP_CREATED.set(()).is_err() {
panic!("Creating EventLoop multiple times is not supported.");
}
// Certain platforms accept a mutable reference in their API.
#[allow(clippy::unnecessary_mut_passed)]
EventLoop {
event_loop: platform_impl::EventLoop::new(&mut self.platform_specific),
_marker: PhantomData,
}
}
}
impl<T> fmt::Debug for EventLoop<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad("EventLoop { .. }")
}
}
impl<T> fmt::Debug for EventLoopWindowTarget<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad("EventLoopWindowTarget { .. }")
}
}
/// Set by the user callback given to the [`EventLoop::run`] method.
///
/// Indicates the desired behavior of the event loop after [`Event::RedrawEventsCleared`] is emitted.
///
/// Defaults to [`Poll`].
///
/// ## Persistency
///
/// Almost every change is persistent between multiple calls to the event loop closure within a
/// given run loop. The only exception to this is [`ExitWithCode`] which, once set, cannot be unset.
/// Changes are **not** persistent between multiple calls to `run_return` - issuing a new call will
/// reset the control flow to [`Poll`].
///
/// [`ExitWithCode`]: Self::ExitWithCode
/// [`Poll`]: Self::Poll
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ControlFlow {
/// When the current loop iteration finishes, immediately begin a new iteration regardless of
/// whether or not new events are available to process.
///
/// ## Platform-specific
///
/// - **Web:** Events are queued and usually sent when `requestAnimationFrame` fires but sometimes
/// the events in the queue may be sent before the next `requestAnimationFrame` callback, for
/// example when the scaling of the page has changed. This should be treated as an implementation
/// detail which should not be relied on.
Poll,
/// When the current loop iteration finishes, suspend the thread until another event arrives.
Wait,
/// When the current loop iteration finishes, suspend the thread until either another event
/// arrives or the given time is reached.
///
/// Useful for implementing efficient timers. Applications which want to render at the display's
/// native refresh rate should instead use [`Poll`] and the VSync functionality of a graphics API
/// to reduce odds of missed frames.
///
/// [`Poll`]: Self::Poll
WaitUntil(Instant),
/// Send a [`LoopDestroyed`] event and stop the event loop. This variant is *sticky* - once set,
/// `control_flow` cannot be changed from `ExitWithCode`, and any future attempts to do so will
/// result in the `control_flow` parameter being reset to `ExitWithCode`.
///
/// The contained number will be used as exit code. The [`Exit`] constant is a shortcut for this
/// with exit code 0.
///
/// ## Platform-specific
///
/// - **Android / iOS / WASM:** The supplied exit code is unused.
/// - **Unix:** On most Unix-like platforms, only the 8 least significant bits will be used,
/// which can cause surprises with negative exit values (`-42` would end up as `214`). See
/// [`std::process::exit`].
///
/// [`LoopDestroyed`]: Event::LoopDestroyed
/// [`Exit`]: ControlFlow::Exit
ExitWithCode(i32),
}
impl ControlFlow {
/// Alias for [`ExitWithCode`]`(0)`.
///
/// [`ExitWithCode`]: Self::ExitWithCode
#[allow(non_upper_case_globals)]
pub const Exit: Self = Self::ExitWithCode(0);
/// Sets this to [`Poll`].
///
/// [`Poll`]: Self::Poll
pub fn set_poll(&mut self) {
*self = Self::Poll;
}
/// Sets this to [`Wait`].
///
/// [`Wait`]: Self::Wait
pub fn set_wait(&mut self) {
*self = Self::Wait;
}
/// Sets this to [`WaitUntil`]`(instant)`.
///
/// [`WaitUntil`]: Self::WaitUntil
pub fn set_wait_until(&mut self, instant: Instant) {
*self = Self::WaitUntil(instant);
}
/// Sets this to wait until a timeout has expired.
///
/// In most cases, this is set to [`WaitUntil`]. However, if the timeout overflows, it is
/// instead set to [`Wait`].
///
/// [`WaitUntil`]: Self::WaitUntil
/// [`Wait`]: Self::Wait
pub fn set_wait_timeout(&mut self, timeout: Duration) {
match Instant::now().checked_add(timeout) {
Some(instant) => self.set_wait_until(instant),
None => self.set_wait(),
}
}
/// Sets this to [`ExitWithCode`]`(code)`.
///
/// [`ExitWithCode`]: Self::ExitWithCode
pub fn set_exit_with_code(&mut self, code: i32) {
*self = Self::ExitWithCode(code);
}
/// Sets this to [`Exit`].
///
/// [`Exit`]: Self::Exit
pub fn set_exit(&mut self) {
*self = Self::Exit;
}
}
impl Default for ControlFlow {
#[inline(always)]
fn default() -> Self {
Self::Poll
}
}
impl EventLoop<()> {
/// Alias for [`EventLoopBuilder::new().build()`].
///
/// [`EventLoopBuilder::new().build()`]: EventLoopBuilder::build
#[inline]
pub fn new() -> EventLoop<()> {
EventLoopBuilder::new().build()
}
}
impl Default for EventLoop<()> {
fn default() -> Self {
Self::new()
}
}
impl<T> EventLoop<T> {
#[deprecated = "Use `EventLoopBuilder::<T>::with_user_event().build()` instead."]
pub fn with_user_event() -> EventLoop<T> {
EventLoopBuilder::<T>::with_user_event().build()
}
/// Hijacks the calling thread and initializes the winit event loop with the provided
/// closure. Since the closure is `'static`, it must be a `move` closure if it needs to
/// access any data from the calling context.
///
/// See the [`ControlFlow`] docs for information on how changes to `&mut ControlFlow` impact the
/// event loop's behavior.
///
/// Any values not passed to this function will *not* be dropped.
///
/// ## Platform-specific
///
/// - **X11 / Wayland:** The program terminates with exit code 1 if the display server
/// disconnects.
///
/// [`ControlFlow`]: crate::event_loop::ControlFlow
#[inline]
pub fn run<F>(self, event_handler: F) -> !
where
F: 'static + FnMut(Event<'_, T>, &EventLoopWindowTarget<T>, &mut ControlFlow),
{
self.event_loop.run(event_handler)
}
/// Creates an [`EventLoopProxy`] that can be used to dispatch user events to the main event loop.
pub fn create_proxy(&self) -> EventLoopProxy<T> {
EventLoopProxy {
event_loop_proxy: self.event_loop.create_proxy(),
}
}
}
unsafe impl<T> HasRawDisplayHandle for EventLoop<T> {
/// Returns a [`raw_window_handle::RawDisplayHandle`] for the event loop.
fn raw_display_handle(&self) -> RawDisplayHandle {
self.event_loop.window_target().p.raw_display_handle()
}
}
impl<T> Deref for EventLoop<T> {
type Target = EventLoopWindowTarget<T>;
fn deref(&self) -> &EventLoopWindowTarget<T> {
self.event_loop.window_target()
}
}
impl<T> EventLoopWindowTarget<T> {
/// Returns the list of all the monitors available on the system.
#[inline]
pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
self.p
.available_monitors()
.into_iter()
.map(|inner| MonitorHandle { inner })
}
/// Returns the primary monitor of the system.
///
/// Returns `None` if it can't identify any monitor as a primary one.
///
/// ## Platform-specific
///
/// **Wayland:** Always returns `None`.
#[inline]
pub fn primary_monitor(&self) -> Option<MonitorHandle> {
self.p
.primary_monitor()
.map(|inner| MonitorHandle { inner })
}
/// Change [`DeviceEvent`] filter mode.
///
/// Since the [`DeviceEvent`] capture can lead to high CPU usage for unfocused windows, winit
/// will ignore them by default for unfocused windows on Linux/BSD. This method allows changing
/// this filter at runtime to explicitly capture them again.
///
/// ## Platform-specific
///
/// - **Wayland / macOS / iOS / Android / Web / Orbital:** Unsupported.
///
/// [`DeviceEvent`]: crate::event::DeviceEvent
pub fn set_device_event_filter(&self, _filter: DeviceEventFilter) {
#[cfg(any(x11_platform, wayland_platform, windows))]
self.p.set_device_event_filter(_filter);
}
}
unsafe impl<T> HasRawDisplayHandle for EventLoopWindowTarget<T> {
/// Returns a [`raw_window_handle::RawDisplayHandle`] for the event loop.
fn raw_display_handle(&self) -> RawDisplayHandle {
self.p.raw_display_handle()
}
}
/// Used to send custom events to [`EventLoop`].
pub struct EventLoopProxy<T: 'static> {
event_loop_proxy: platform_impl::EventLoopProxy<T>,
}
impl<T: 'static> Clone for EventLoopProxy<T> {
fn clone(&self) -> Self {
Self {
event_loop_proxy: self.event_loop_proxy.clone(),
}
}
}
impl<T: 'static> EventLoopProxy<T> {
/// Send an event to the [`EventLoop`] from which this proxy was created. This emits a
/// `UserEvent(event)` event in the event loop, where `event` is the value passed to this
/// function.
///
/// Returns an `Err` if the associated [`EventLoop`] no longer exists.
///
/// [`UserEvent(event)`]: Event::UserEvent
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
self.event_loop_proxy.send_event(event)
}
}
impl<T: 'static> fmt::Debug for EventLoopProxy<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad("EventLoopProxy { .. }")
}
}
/// The error that is returned when an [`EventLoopProxy`] attempts to wake up an [`EventLoop`] that
/// no longer exists.
///
/// Contains the original event given to [`EventLoopProxy::send_event`].
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct EventLoopClosed<T>(pub T);
impl<T> fmt::Display for EventLoopClosed<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Tried to wake up a closed `EventLoop`")
}
}
impl<T: fmt::Debug> error::Error for EventLoopClosed<T> {}
/// Filter controlling the propagation of device events.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum DeviceEventFilter {
/// Always filter out device events.
Always,
/// Filter out device events while the window is not focused.
Unfocused,
/// Report all device events regardless of window focus.
Never,
}
impl Default for DeviceEventFilter {
fn default() -> Self {
Self::Unfocused
}
}

View File

@@ -1,129 +0,0 @@
use crate::platform_impl::PlatformIcon;
use std::{error::Error, fmt, io, mem};
#[repr(C)]
#[derive(Debug)]
pub(crate) struct Pixel {
pub(crate) r: u8,
pub(crate) g: u8,
pub(crate) b: u8,
pub(crate) a: u8,
}
pub(crate) const PIXEL_SIZE: usize = mem::size_of::<Pixel>();
#[derive(Debug)]
/// An error produced when using [`Icon::from_rgba`] with invalid arguments.
pub enum BadIcon {
/// Produced when the length of the `rgba` argument isn't divisible by 4, thus `rgba` can't be
/// safely interpreted as 32bpp RGBA pixels.
ByteCountNotDivisibleBy4 { byte_count: usize },
/// Produced when the number of pixels (`rgba.len() / 4`) isn't equal to `width * height`.
/// At least one of your arguments is incorrect.
DimensionsVsPixelCount {
width: u32,
height: u32,
width_x_height: usize,
pixel_count: usize,
},
/// Produced when underlying OS functionality failed to create the icon
OsError(io::Error),
}
impl fmt::Display for BadIcon {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BadIcon::ByteCountNotDivisibleBy4 { byte_count } => write!(f,
"The length of the `rgba` argument ({byte_count:?}) isn't divisible by 4, making it impossible to interpret as 32bpp RGBA pixels.",
),
BadIcon::DimensionsVsPixelCount {
width,
height,
width_x_height,
pixel_count,
} => write!(f,
"The specified dimensions ({width:?}x{height:?}) don't match the number of pixels supplied by the `rgba` argument ({pixel_count:?}). For those dimensions, the expected pixel count is {width_x_height:?}.",
),
BadIcon::OsError(e) => write!(f, "OS error when instantiating the icon: {e:?}"),
}
}
}
impl Error for BadIcon {
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(self)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct RgbaIcon {
pub(crate) rgba: Vec<u8>,
pub(crate) width: u32,
pub(crate) height: u32,
}
/// For platforms which don't have window icons (e.g. web)
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct NoIcon;
#[allow(dead_code)] // These are not used on every platform
mod constructors {
use super::*;
impl RgbaIcon {
pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> {
if rgba.len() % PIXEL_SIZE != 0 {
return Err(BadIcon::ByteCountNotDivisibleBy4 {
byte_count: rgba.len(),
});
}
let pixel_count = rgba.len() / PIXEL_SIZE;
if pixel_count != (width * height) as usize {
Err(BadIcon::DimensionsVsPixelCount {
width,
height,
width_x_height: (width * height) as usize,
pixel_count,
})
} else {
Ok(RgbaIcon {
rgba,
width,
height,
})
}
}
}
impl NoIcon {
pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> {
// Create the rgba icon anyway to validate the input
let _ = RgbaIcon::from_rgba(rgba, width, height)?;
Ok(NoIcon)
}
}
}
/// An icon used for the window titlebar, taskbar, etc.
#[derive(Clone)]
pub struct Icon {
pub(crate) inner: PlatformIcon,
}
impl fmt::Debug for Icon {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
fmt::Debug::fmt(&self.inner, formatter)
}
}
impl Icon {
/// Creates an icon from 32bpp RGBA data.
///
/// The length of `rgba` must be divisible by 4, and `width * height` must equal
/// `rgba.len() / 4`. Otherwise, this will return a `BadIcon` error.
pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Self, BadIcon> {
Ok(Icon {
inner: PlatformIcon::from_rgba(rgba, width, height)?,
})
}
}

View File

@@ -1,161 +0,0 @@
//! Winit is a cross-platform window creation and event loop management library.
//!
//! # Building windows
//!
//! Before you can build a [`Window`], you first need to build an [`EventLoop`]. This is done with the
//! [`EventLoop::new()`] function.
//!
//! ```no_run
//! use winit::event_loop::EventLoop;
//! let event_loop = EventLoop::new();
//! ```
//!
//! Once this is done there are two ways to create a [`Window`]:
//!
//! - Calling [`Window::new(&event_loop)`][window_new].
//! - Calling [`let builder = WindowBuilder::new()`][window_builder_new] then [`builder.build(&event_loop)`][window_builder_build].
//!
//! The first method is the simplest, and will give you default values for everything. The second
//! method allows you to customize the way your [`Window`] will look and behave by modifying the
//! fields of the [`WindowBuilder`] object before you create the [`Window`].
//!
//! # Event handling
//!
//! Once a [`Window`] has been created, it will generate different *events*. A [`Window`] object can
//! generate [`WindowEvent`]s when certain input events occur, such as a cursor moving over the
//! window or a key getting pressed while the window is focused. Devices can generate
//! [`DeviceEvent`]s, which contain unfiltered event data that isn't specific to a certain window.
//! Some user activity, like mouse movement, can generate both a [`WindowEvent`] *and* a
//! [`DeviceEvent`]. You can also create and handle your own custom [`UserEvent`]s, if desired.
//!
//! You can retrieve events by calling [`EventLoop::run`][event_loop_run]. This function will
//! dispatch events for every [`Window`] that was created with that particular [`EventLoop`], and
//! will run until the `control_flow` argument given to the closure is set to
//! [`ControlFlow`]`::`[`ExitWithCode`] (which [`ControlFlow`]`::`[`Exit`] aliases to), at which
//! point [`Event`]`::`[`LoopDestroyed`] is emitted and the entire program terminates.
//!
//! Winit no longer uses a `EventLoop::poll_events() -> impl Iterator<Event>`-based event loop
//! model, since that can't be implemented properly on some platforms (e.g web, iOS) and works poorly on
//! most other platforms. However, this model can be re-implemented to an extent with
//! [`EventLoopExtRunReturn::run_return`]. See that method's documentation for more reasons about why
//! it's discouraged, beyond compatibility reasons.
//!
//!
//! ```no_run
//! use winit::{
//! event::{Event, WindowEvent},
//! event_loop::EventLoop,
//! window::WindowBuilder,
//! };
//!
//! let event_loop = EventLoop::new();
//! let window = WindowBuilder::new().build(&event_loop).unwrap();
//!
//! event_loop.run(move |event, _, control_flow| {
//! // ControlFlow::Poll continuously runs the event loop, even if the OS hasn't
//! // dispatched any events. This is ideal for games and similar applications.
//! control_flow.set_poll();
//!
//! // ControlFlow::Wait pauses the event loop if no events are available to process.
//! // This is ideal for non-game applications that only update in response to user
//! // input, and uses significantly less power/CPU time than ControlFlow::Poll.
//! control_flow.set_wait();
//!
//! match event {
//! Event::WindowEvent {
//! event: WindowEvent::CloseRequested,
//! ..
//! } => {
//! println!("The close button was pressed; stopping");
//! control_flow.set_exit();
//! },
//! Event::MainEventsCleared => {
//! // Application update code.
//!
//! // Queue a RedrawRequested event.
//! //
//! // You only need to call this if you've determined that you need to redraw, in
//! // applications which do not always need to. Applications that redraw continuously
//! // can just render here instead.
//! window.request_redraw();
//! },
//! Event::RedrawRequested(_) => {
//! // Redraw the application.
//! //
//! // It's preferable for applications that do not render continuously to render in
//! // this event rather than in MainEventsCleared, since rendering in here allows
//! // the program to gracefully handle redraws requested by the OS.
//! },
//! _ => ()
//! }
//! });
//! ```
//!
//! [`Event`]`::`[`WindowEvent`] has a [`WindowId`] member. In multi-window environments, it should be
//! compared to the value returned by [`Window::id()`][window_id_fn] to determine which [`Window`]
//! dispatched the event.
//!
//! # Drawing on the window
//!
//! Winit doesn't directly provide any methods for drawing on a [`Window`]. However it allows you to
//! retrieve the raw handle of the window and display (see the [`platform`] module and/or the
//! [`raw_window_handle`] and [`raw_display_handle`] methods), which in turn allows
//! you to create an OpenGL/Vulkan/DirectX/Metal/etc. context that can be used to render graphics.
//!
//! Note that many platforms will display garbage data in the window's client area if the
//! application doesn't render anything to the window by the time the desktop compositor is ready to
//! display the window to the user. If you notice this happening, you should create the window with
//! [`visible` set to `false`](crate::window::WindowBuilder::with_visible) and explicitly make the
//! window visible only once you're ready to render into it.
//!
//! [`EventLoop`]: event_loop::EventLoop
//! [`EventLoopExtRunReturn::run_return`]: ./platform/run_return/trait.EventLoopExtRunReturn.html#tymethod.run_return
//! [`EventLoop::new()`]: event_loop::EventLoop::new
//! [event_loop_run]: event_loop::EventLoop::run
//! [`ControlFlow`]: event_loop::ControlFlow
//! [`Exit`]: event_loop::ControlFlow::Exit
//! [`ExitWithCode`]: event_loop::ControlFlow::ExitWithCode
//! [`Window`]: window::Window
//! [`WindowId`]: window::WindowId
//! [`WindowBuilder`]: window::WindowBuilder
//! [window_new]: window::Window::new
//! [window_builder_new]: window::WindowBuilder::new
//! [window_builder_build]: window::WindowBuilder::build
//! [window_id_fn]: window::Window::id
//! [`Event`]: event::Event
//! [`WindowEvent`]: event::WindowEvent
//! [`DeviceEvent`]: event::DeviceEvent
//! [`UserEvent`]: event::Event::UserEvent
//! [`LoopDestroyed`]: event::Event::LoopDestroyed
//! [`platform`]: platform
//! [`raw_window_handle`]: ./window/struct.Window.html#method.raw_window_handle
//! [`raw_display_handle`]: ./window/struct.Window.html#method.raw_display_handle
#![deny(rust_2018_idioms)]
#![deny(rustdoc::broken_intra_doc_links)]
#![deny(clippy::all)]
#![cfg_attr(feature = "cargo-clippy", deny(warnings))]
// Doc feature labels can be tested locally by running RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![allow(clippy::missing_safety_doc)]
#[allow(unused_imports)]
#[macro_use]
extern crate log;
#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;
#[macro_use]
extern crate bitflags;
pub mod dpi;
#[macro_use]
pub mod error;
pub mod event;
pub mod event_loop;
mod icon;
pub mod monitor;
mod platform_impl;
pub mod window;
pub mod platform;

View File

@@ -1,181 +0,0 @@
//! Types useful for interacting with a user's monitors.
//!
//! If you want to get basic information about a monitor, you can use the
//! [`MonitorHandle`] type. This is retrieved from one of the following
//! methods, which return an iterator of [`MonitorHandle`]:
//! - [`EventLoopWindowTarget::available_monitors`](crate::event_loop::EventLoopWindowTarget::available_monitors).
//! - [`Window::available_monitors`](crate::window::Window::available_monitors).
use crate::{
dpi::{PhysicalPosition, PhysicalSize},
platform_impl,
};
/// Describes a fullscreen video mode of a monitor.
///
/// Can be acquired with [`MonitorHandle::video_modes`].
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct VideoMode {
pub(crate) video_mode: platform_impl::VideoMode,
}
impl std::fmt::Debug for VideoMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.video_mode.fmt(f)
}
}
impl PartialOrd for VideoMode {
fn partial_cmp(&self, other: &VideoMode) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for VideoMode {
fn cmp(&self, other: &VideoMode) -> std::cmp::Ordering {
// TODO: we can impl `Ord` for `PhysicalSize` once we switch from `f32`
// to `u32` there
let size: (u32, u32) = self.size().into();
let other_size: (u32, u32) = other.size().into();
self.monitor().cmp(&other.monitor()).then(
size.cmp(&other_size)
.then(
self.refresh_rate_millihertz()
.cmp(&other.refresh_rate_millihertz())
.then(self.bit_depth().cmp(&other.bit_depth())),
)
.reverse(),
)
}
}
impl VideoMode {
/// Returns the resolution of this video mode.
#[inline]
pub fn size(&self) -> PhysicalSize<u32> {
self.video_mode.size()
}
/// Returns the bit depth of this video mode, as in how many bits you have
/// available per color. This is generally 24 bits or 32 bits on modern
/// systems, depending on whether the alpha channel is counted or not.
///
/// ## Platform-specific
///
/// - **Wayland / Orbital:** Always returns 32.
/// - **iOS:** Always returns 32.
#[inline]
pub fn bit_depth(&self) -> u16 {
self.video_mode.bit_depth()
}
/// Returns the refresh rate of this video mode in mHz.
#[inline]
pub fn refresh_rate_millihertz(&self) -> u32 {
self.video_mode.refresh_rate_millihertz()
}
/// Returns the monitor that this video mode is valid for. Each monitor has
/// a separate set of valid video modes.
#[inline]
pub fn monitor(&self) -> MonitorHandle {
MonitorHandle {
inner: self.video_mode.monitor(),
}
}
}
impl std::fmt::Display for VideoMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}x{} @ {} mHz ({} bpp)",
self.size().width,
self.size().height,
self.refresh_rate_millihertz(),
self.bit_depth()
)
}
}
/// Handle to a monitor.
///
/// Allows you to retrieve information about a given monitor and can be used in [`Window`] creation.
///
/// [`Window`]: crate::window::Window
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct MonitorHandle {
pub(crate) inner: platform_impl::MonitorHandle,
}
impl MonitorHandle {
/// Returns a human-readable name of the monitor.
///
/// Returns `None` if the monitor doesn't exist anymore.
///
/// ## Platform-specific
///
/// - **Web:** Always returns None
#[inline]
pub fn name(&self) -> Option<String> {
self.inner.name()
}
/// Returns the monitor's resolution.
///
/// ## Platform-specific
///
/// - **Web:** Always returns (0,0)
#[inline]
pub fn size(&self) -> PhysicalSize<u32> {
self.inner.size()
}
/// Returns the top-left corner position of the monitor relative to the larger full
/// screen area.
///
/// ## Platform-specific
///
/// - **Web:** Always returns (0,0)
#[inline]
pub fn position(&self) -> PhysicalPosition<i32> {
self.inner.position()
}
/// The monitor refresh rate used by the system.
///
/// Return `Some` if succeed, or `None` if failed, which usually happens when the monitor
/// the window is on is removed.
///
/// When using exclusive fullscreen, the refresh rate of the [`VideoMode`] that was used to
/// enter fullscreen should be used instead.
#[inline]
pub fn refresh_rate_millihertz(&self) -> Option<u32> {
self.inner.refresh_rate_millihertz()
}
/// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
///
/// See the [`dpi`](crate::dpi) module for more information.
///
/// ## Platform-specific
///
/// - **X11:** Can be overridden using the `WINIT_X11_SCALE_FACTOR` environment variable.
/// - **Android:** Always returns 1.0.
/// - **Web:** Always returns 1.0
#[inline]
pub fn scale_factor(&self) -> f64 {
self.inner.scale_factor()
}
/// Returns all fullscreen video modes supported by this monitor.
///
/// ## Platform-specific
///
/// - **Web:** Always returns an empty iterator
#[inline]
pub fn video_modes(&self) -> impl Iterator<Item = VideoMode> {
self.inner
.video_modes()
.map(|video_mode| VideoMode { video_mode })
}
}

View File

@@ -1,78 +0,0 @@
use crate::{
event_loop::{EventLoop, EventLoopBuilder, EventLoopWindowTarget},
window::{Window, WindowBuilder},
};
use android_activity::{AndroidApp, ConfigurationRef, Rect};
/// Additional methods on [`EventLoop`] that are specific to Android.
pub trait EventLoopExtAndroid {}
impl<T> EventLoopExtAndroid for EventLoop<T> {}
/// Additional methods on [`EventLoopWindowTarget`] that are specific to Android.
pub trait EventLoopWindowTargetExtAndroid {}
/// Additional methods on [`Window`] that are specific to Android.
pub trait WindowExtAndroid {
fn content_rect(&self) -> Rect;
fn config(&self) -> ConfigurationRef;
}
impl WindowExtAndroid for Window {
fn content_rect(&self) -> Rect {
self.window.content_rect()
}
fn config(&self) -> ConfigurationRef {
self.window.config()
}
}
impl<T> EventLoopWindowTargetExtAndroid for EventLoopWindowTarget<T> {}
/// Additional methods on [`WindowBuilder`] that are specific to Android.
pub trait WindowBuilderExtAndroid {}
impl WindowBuilderExtAndroid for WindowBuilder {}
pub trait EventLoopBuilderExtAndroid {
/// Associates the `AndroidApp` that was passed to `android_main()` with the event loop
///
/// This must be called on Android since the `AndroidApp` is not global state.
fn with_android_app(&mut self, app: AndroidApp) -> &mut Self;
}
impl<T> EventLoopBuilderExtAndroid for EventLoopBuilder<T> {
fn with_android_app(&mut self, app: AndroidApp) -> &mut Self {
self.platform_specific.android_app = Some(app);
self
}
}
/// Re-export of the `android_activity` API
///
/// Winit re-exports the `android_activity` API for convenience so that most
/// applications can rely on the Winit crate to resolve the required version of
/// `android_activity` and avoid any chance of a conflict between Winit and the
/// application crate.
///
/// Unlike most libraries there can only be a single implementation
/// of the `android_activity` glue crate linked with an application because
/// it is responsible for the application's `android_main()` entry point.
///
/// Since Winit depends on a specific version of `android_activity` the simplest
/// way to avoid creating a conflict is for applications to avoid explicitly
/// depending on the `android_activity` crate, and instead consume the API that
/// is re-exported by Winit.
///
/// For compatibility applications should then import the `AndroidApp` type for
/// their `android_main(app: AndroidApp)` function like:
/// ```rust
/// #[cfg(target_os="android")]
/// use winit::platform::android::activity::AndroidApp;
/// ```
pub mod activity {
pub use android_activity::*;
}

View File

@@ -1,306 +0,0 @@
use std::os::raw::c_void;
use objc2::rc::Id;
use crate::{
event_loop::EventLoop,
monitor::{MonitorHandle, VideoMode},
window::{Window, WindowBuilder},
};
/// Additional methods on [`EventLoop`] that are specific to iOS.
pub trait EventLoopExtIOS {
/// Returns the [`Idiom`] (phone/tablet/tv/etc) for the current device.
fn idiom(&self) -> Idiom;
}
impl<T: 'static> EventLoopExtIOS for EventLoop<T> {
fn idiom(&self) -> Idiom {
self.event_loop.idiom()
}
}
/// Additional methods on [`Window`] that are specific to iOS.
pub trait WindowExtIOS {
/// Returns a pointer to the [`UIWindow`] that is used by this window.
///
/// The pointer will become invalid when the [`Window`] is destroyed.
///
/// [`UIWindow`]: https://developer.apple.com/documentation/uikit/uiwindow?language=objc
fn ui_window(&self) -> *mut c_void;
/// Returns a pointer to the [`UIViewController`] that is used by this window.
///
/// The pointer will become invalid when the [`Window`] is destroyed.
///
/// [`UIViewController`]: https://developer.apple.com/documentation/uikit/uiviewcontroller?language=objc
fn ui_view_controller(&self) -> *mut c_void;
/// Returns a pointer to the [`UIView`] that is used by this window.
///
/// The pointer will become invalid when the [`Window`] is destroyed.
///
/// [`UIView`]: https://developer.apple.com/documentation/uikit/uiview?language=objc
fn ui_view(&self) -> *mut c_void;
/// Sets the [`contentScaleFactor`] of the underlying [`UIWindow`] to `scale_factor`.
///
/// The default value is device dependent, and it's recommended GLES or Metal applications set
/// this to [`MonitorHandle::scale_factor()`].
///
/// [`UIWindow`]: https://developer.apple.com/documentation/uikit/uiwindow?language=objc
/// [`contentScaleFactor`]: https://developer.apple.com/documentation/uikit/uiview/1622657-contentscalefactor?language=objc
fn set_scale_factor(&self, scale_factor: f64);
/// Sets the valid orientations for the [`Window`].
///
/// The default value is [`ValidOrientations::LandscapeAndPortrait`].
///
/// This changes the value returned by
/// [`-[UIViewController supportedInterfaceOrientations]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621435-supportedinterfaceorientations?language=objc),
/// and then calls
/// [`-[UIViewController attemptRotationToDeviceOrientation]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621400-attemptrotationtodeviceorientati?language=objc).
fn set_valid_orientations(&self, valid_orientations: ValidOrientations);
/// Sets whether the [`Window`] prefers the home indicator hidden.
///
/// The default is to prefer showing the home indicator.
///
/// This changes the value returned by
/// [`-[UIViewController prefersHomeIndicatorAutoHidden]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/2887510-prefershomeindicatorautohidden?language=objc),
/// and then calls
/// [`-[UIViewController setNeedsUpdateOfHomeIndicatorAutoHidden]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/2887509-setneedsupdateofhomeindicatoraut?language=objc).
///
/// This only has an effect on iOS 11.0+.
fn set_prefers_home_indicator_hidden(&self, hidden: bool);
/// Sets the screen edges for which the system gestures will take a lower priority than the
/// application's touch handling.
///
/// This changes the value returned by
/// [`-[UIViewController preferredScreenEdgesDeferringSystemGestures]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/2887512-preferredscreenedgesdeferringsys?language=objc),
/// and then calls
/// [`-[UIViewController setNeedsUpdateOfScreenEdgesDeferringSystemGestures]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/2887507-setneedsupdateofscreenedgesdefer?language=objc).
///
/// This only has an effect on iOS 11.0+.
fn set_preferred_screen_edges_deferring_system_gestures(&self, edges: ScreenEdge);
/// Sets whether the [`Window`] prefers the status bar hidden.
///
/// The default is to prefer showing the status bar.
///
/// This changes the value returned by
/// [`-[UIViewController prefersStatusBarHidden]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621440-prefersstatusbarhidden?language=objc),
/// and then calls
/// [`-[UIViewController setNeedsStatusBarAppearanceUpdate]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621354-setneedsstatusbarappearanceupdat?language=objc).
fn set_prefers_status_bar_hidden(&self, hidden: bool);
}
impl WindowExtIOS for Window {
#[inline]
fn ui_window(&self) -> *mut c_void {
self.window.ui_window()
}
#[inline]
fn ui_view_controller(&self) -> *mut c_void {
self.window.ui_view_controller()
}
#[inline]
fn ui_view(&self) -> *mut c_void {
self.window.ui_view()
}
#[inline]
fn set_scale_factor(&self, scale_factor: f64) {
self.window.set_scale_factor(scale_factor)
}
#[inline]
fn set_valid_orientations(&self, valid_orientations: ValidOrientations) {
self.window.set_valid_orientations(valid_orientations)
}
#[inline]
fn set_prefers_home_indicator_hidden(&self, hidden: bool) {
self.window.set_prefers_home_indicator_hidden(hidden)
}
#[inline]
fn set_preferred_screen_edges_deferring_system_gestures(&self, edges: ScreenEdge) {
self.window
.set_preferred_screen_edges_deferring_system_gestures(edges)
}
#[inline]
fn set_prefers_status_bar_hidden(&self, hidden: bool) {
self.window.set_prefers_status_bar_hidden(hidden)
}
}
/// Additional methods on [`WindowBuilder`] that are specific to iOS.
pub trait WindowBuilderExtIOS {
/// Sets the [`contentScaleFactor`] of the underlying [`UIWindow`] to `scale_factor`.
///
/// The default value is device dependent, and it's recommended GLES or Metal applications set
/// this to [`MonitorHandle::scale_factor()`].
///
/// [`UIWindow`]: https://developer.apple.com/documentation/uikit/uiwindow?language=objc
/// [`contentScaleFactor`]: https://developer.apple.com/documentation/uikit/uiview/1622657-contentscalefactor?language=objc
fn with_scale_factor(self, scale_factor: f64) -> WindowBuilder;
/// Sets the valid orientations for the [`Window`].
///
/// The default value is [`ValidOrientations::LandscapeAndPortrait`].
///
/// This sets the initial value returned by
/// [`-[UIViewController supportedInterfaceOrientations]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621435-supportedinterfaceorientations?language=objc).
fn with_valid_orientations(self, valid_orientations: ValidOrientations) -> WindowBuilder;
/// Sets whether the [`Window`] prefers the home indicator hidden.
///
/// The default is to prefer showing the home indicator.
///
/// This sets the initial value returned by
/// [`-[UIViewController prefersHomeIndicatorAutoHidden]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/2887510-prefershomeindicatorautohidden?language=objc).
///
/// This only has an effect on iOS 11.0+.
fn with_prefers_home_indicator_hidden(self, hidden: bool) -> WindowBuilder;
/// Sets the screen edges for which the system gestures will take a lower priority than the
/// application's touch handling.
///
/// This sets the initial value returned by
/// [`-[UIViewController preferredScreenEdgesDeferringSystemGestures]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/2887512-preferredscreenedgesdeferringsys?language=objc).
///
/// This only has an effect on iOS 11.0+.
fn with_preferred_screen_edges_deferring_system_gestures(
self,
edges: ScreenEdge,
) -> WindowBuilder;
/// Sets whether the [`Window`] prefers the status bar hidden.
///
/// The default is to prefer showing the status bar.
///
/// This sets the initial value returned by
/// [`-[UIViewController prefersStatusBarHidden]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621440-prefersstatusbarhidden?language=objc).
fn with_prefers_status_bar_hidden(self, hidden: bool) -> WindowBuilder;
}
impl WindowBuilderExtIOS for WindowBuilder {
#[inline]
fn with_scale_factor(mut self, scale_factor: f64) -> WindowBuilder {
self.platform_specific.scale_factor = Some(scale_factor);
self
}
#[inline]
fn with_valid_orientations(mut self, valid_orientations: ValidOrientations) -> WindowBuilder {
self.platform_specific.valid_orientations = valid_orientations;
self
}
#[inline]
fn with_prefers_home_indicator_hidden(mut self, hidden: bool) -> WindowBuilder {
self.platform_specific.prefers_home_indicator_hidden = hidden;
self
}
#[inline]
fn with_preferred_screen_edges_deferring_system_gestures(
mut self,
edges: ScreenEdge,
) -> WindowBuilder {
self.platform_specific
.preferred_screen_edges_deferring_system_gestures = edges;
self
}
#[inline]
fn with_prefers_status_bar_hidden(mut self, hidden: bool) -> WindowBuilder {
self.platform_specific.prefers_status_bar_hidden = hidden;
self
}
}
/// Additional methods on [`MonitorHandle`] that are specific to iOS.
pub trait MonitorHandleExtIOS {
/// Returns a pointer to the [`UIScreen`] that is used by this monitor.
///
/// [`UIScreen`]: https://developer.apple.com/documentation/uikit/uiscreen?language=objc
fn ui_screen(&self) -> *mut c_void;
/// Returns the preferred [`VideoMode`] for this monitor.
///
/// This translates to a call to [`-[UIScreen preferredMode]`](https://developer.apple.com/documentation/uikit/uiscreen/1617823-preferredmode?language=objc).
fn preferred_video_mode(&self) -> VideoMode;
}
impl MonitorHandleExtIOS for MonitorHandle {
#[inline]
fn ui_screen(&self) -> *mut c_void {
Id::as_ptr(self.inner.ui_screen()) as *mut c_void
}
#[inline]
fn preferred_video_mode(&self) -> VideoMode {
VideoMode {
video_mode: self.inner.preferred_video_mode(),
}
}
}
/// Valid orientations for a particular [`Window`].
#[derive(Clone, Copy, Debug)]
pub enum ValidOrientations {
/// Excludes `PortraitUpsideDown` on iphone
LandscapeAndPortrait,
Landscape,
/// Excludes `PortraitUpsideDown` on iphone
Portrait,
}
impl Default for ValidOrientations {
#[inline]
fn default() -> ValidOrientations {
ValidOrientations::LandscapeAndPortrait
}
}
/// The device [idiom].
///
/// [idiom]: https://developer.apple.com/documentation/uikit/uidevice/1620037-userinterfaceidiom?language=objc
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Idiom {
Unspecified,
/// iPhone and iPod touch.
Phone,
/// iPad.
Pad,
/// tvOS and Apple TV.
TV,
CarPlay,
}
bitflags! {
/// The [edges] of a screen.
///
/// [edges]: https://developer.apple.com/documentation/uikit/uirectedge?language=objc
#[derive(Default)]
pub struct ScreenEdge: u8 {
const NONE = 0;
const TOP = 1 << 0;
const LEFT = 1 << 1;
const BOTTOM = 1 << 2;
const RIGHT = 1 << 3;
const ALL = ScreenEdge::TOP.bits | ScreenEdge::LEFT.bits
| ScreenEdge::BOTTOM.bits | ScreenEdge::RIGHT.bits;
}
}

View File

@@ -1,371 +0,0 @@
use std::os::raw::c_void;
use objc2::rc::Id;
use crate::{
event_loop::{EventLoopBuilder, EventLoopWindowTarget},
monitor::MonitorHandle,
window::{Window, WindowBuilder},
};
/// Additional methods on [`Window`] that are specific to MacOS.
pub trait WindowExtMacOS {
/// Returns a pointer to the cocoa `NSWindow` that is used by this window.
///
/// The pointer will become invalid when the [`Window`] is destroyed.
fn ns_window(&self) -> *mut c_void;
/// Returns a pointer to the cocoa `NSView` that is used by this window.
///
/// The pointer will become invalid when the [`Window`] is destroyed.
fn ns_view(&self) -> *mut c_void;
/// Returns whether or not the window is in simple fullscreen mode.
fn simple_fullscreen(&self) -> bool;
/// Toggles a fullscreen mode that doesn't require a new macOS space.
/// Returns a boolean indicating whether the transition was successful (this
/// won't work if the window was already in the native fullscreen).
///
/// This is how fullscreen used to work on macOS in versions before Lion.
/// And allows the user to have a fullscreen window without using another
/// space or taking control over the entire monitor.
fn set_simple_fullscreen(&self, fullscreen: bool) -> bool;
/// Returns whether or not the window has shadow.
fn has_shadow(&self) -> bool;
/// Sets whether or not the window has shadow.
fn set_has_shadow(&self, has_shadow: bool);
/// Get the window's edit state.
///
/// # Examples
///
/// ```ignore
/// WindowEvent::CloseRequested => {
/// if window.is_document_edited() {
/// // Show the user a save pop-up or similar
/// } else {
/// // Close the window
/// drop(window);
/// }
/// }
/// ```
fn is_document_edited(&self) -> bool;
/// Put the window in a state which indicates a file save is required.
fn set_document_edited(&self, edited: bool);
/// Set option as alt behavior as described in [`OptionAsAlt`].
///
/// This will ignore diacritical marks and accent characters from
/// being processed as received characters. Instead, the input
/// device's raw character will be placed in event queues with the
/// Alt modifier set.
fn set_option_as_alt(&self, option_as_alt: OptionAsAlt);
/// Getter for the [`WindowExtMacOS::set_option_as_alt`].
fn option_as_alt(&self) -> OptionAsAlt;
}
impl WindowExtMacOS for Window {
#[inline]
fn ns_window(&self) -> *mut c_void {
self.window.ns_window()
}
#[inline]
fn ns_view(&self) -> *mut c_void {
self.window.ns_view()
}
#[inline]
fn simple_fullscreen(&self) -> bool {
self.window.simple_fullscreen()
}
#[inline]
fn set_simple_fullscreen(&self, fullscreen: bool) -> bool {
self.window.set_simple_fullscreen(fullscreen)
}
#[inline]
fn has_shadow(&self) -> bool {
self.window.has_shadow()
}
#[inline]
fn set_has_shadow(&self, has_shadow: bool) {
self.window.set_has_shadow(has_shadow)
}
#[inline]
fn is_document_edited(&self) -> bool {
self.window.is_document_edited()
}
#[inline]
fn set_document_edited(&self, edited: bool) {
self.window.set_document_edited(edited)
}
#[inline]
fn set_option_as_alt(&self, option_as_alt: OptionAsAlt) {
self.window.set_option_as_alt(option_as_alt)
}
#[inline]
fn option_as_alt(&self) -> OptionAsAlt {
self.window.option_as_alt()
}
}
/// Corresponds to `NSApplicationActivationPolicy`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ActivationPolicy {
/// Corresponds to `NSApplicationActivationPolicyRegular`.
Regular,
/// Corresponds to `NSApplicationActivationPolicyAccessory`.
Accessory,
/// Corresponds to `NSApplicationActivationPolicyProhibited`.
Prohibited,
}
impl Default for ActivationPolicy {
fn default() -> Self {
ActivationPolicy::Regular
}
}
/// Additional methods on [`WindowBuilder`] that are specific to MacOS.
///
/// **Note:** Properties dealing with the titlebar will be overwritten by the [`WindowBuilder::with_decorations`] method:
/// - `with_titlebar_transparent`
/// - `with_title_hidden`
/// - `with_titlebar_hidden`
/// - `with_titlebar_buttons_hidden`
/// - `with_fullsize_content_view`
pub trait WindowBuilderExtMacOS {
/// Enables click-and-drag behavior for the entire window, not just the titlebar.
fn with_movable_by_window_background(self, movable_by_window_background: bool)
-> WindowBuilder;
/// Makes the titlebar transparent and allows the content to appear behind it.
fn with_titlebar_transparent(self, titlebar_transparent: bool) -> WindowBuilder;
/// Hides the window title.
fn with_title_hidden(self, title_hidden: bool) -> WindowBuilder;
/// Hides the window titlebar.
fn with_titlebar_hidden(self, titlebar_hidden: bool) -> WindowBuilder;
/// Hides the window titlebar buttons.
fn with_titlebar_buttons_hidden(self, titlebar_buttons_hidden: bool) -> WindowBuilder;
/// Makes the window content appear behind the titlebar.
fn with_fullsize_content_view(self, fullsize_content_view: bool) -> WindowBuilder;
fn with_disallow_hidpi(self, disallow_hidpi: bool) -> WindowBuilder;
fn with_has_shadow(self, has_shadow: bool) -> WindowBuilder;
/// Window accepts click-through mouse events.
fn with_accepts_first_mouse(self, accepts_first_mouse: bool) -> WindowBuilder;
/// Set whether the `OptionAsAlt` key is interpreted as the `Alt` modifier.
///
/// See [`WindowExtMacOS::set_option_as_alt`] for details on what this means if set.
fn with_option_as_alt(self, option_as_alt: OptionAsAlt) -> WindowBuilder;
}
impl WindowBuilderExtMacOS for WindowBuilder {
#[inline]
fn with_movable_by_window_background(
mut self,
movable_by_window_background: bool,
) -> WindowBuilder {
self.platform_specific.movable_by_window_background = movable_by_window_background;
self
}
#[inline]
fn with_titlebar_transparent(mut self, titlebar_transparent: bool) -> WindowBuilder {
self.platform_specific.titlebar_transparent = titlebar_transparent;
self
}
#[inline]
fn with_titlebar_hidden(mut self, titlebar_hidden: bool) -> WindowBuilder {
self.platform_specific.titlebar_hidden = titlebar_hidden;
self
}
#[inline]
fn with_titlebar_buttons_hidden(mut self, titlebar_buttons_hidden: bool) -> WindowBuilder {
self.platform_specific.titlebar_buttons_hidden = titlebar_buttons_hidden;
self
}
#[inline]
fn with_title_hidden(mut self, title_hidden: bool) -> WindowBuilder {
self.platform_specific.title_hidden = title_hidden;
self
}
#[inline]
fn with_fullsize_content_view(mut self, fullsize_content_view: bool) -> WindowBuilder {
self.platform_specific.fullsize_content_view = fullsize_content_view;
self
}
#[inline]
fn with_disallow_hidpi(mut self, disallow_hidpi: bool) -> WindowBuilder {
self.platform_specific.disallow_hidpi = disallow_hidpi;
self
}
#[inline]
fn with_has_shadow(mut self, has_shadow: bool) -> WindowBuilder {
self.platform_specific.has_shadow = has_shadow;
self
}
#[inline]
fn with_accepts_first_mouse(mut self, accepts_first_mouse: bool) -> WindowBuilder {
self.platform_specific.accepts_first_mouse = accepts_first_mouse;
self
}
#[inline]
fn with_option_as_alt(mut self, option_as_alt: OptionAsAlt) -> WindowBuilder {
self.platform_specific.option_as_alt = option_as_alt;
self
}
}
pub trait EventLoopBuilderExtMacOS {
/// Sets the activation policy for the application.
///
/// It is set to [`ActivationPolicy::Regular`] by default.
///
/// # Example
///
/// Set the activation policy to "accessory".
///
/// ```
/// use winit::event_loop::EventLoopBuilder;
/// #[cfg(target_os = "macos")]
/// use winit::platform::macos::{EventLoopBuilderExtMacOS, ActivationPolicy};
///
/// let mut builder = EventLoopBuilder::new();
/// #[cfg(target_os = "macos")]
/// builder.with_activation_policy(ActivationPolicy::Accessory);
/// # if false { // We can't test this part
/// let event_loop = builder.build();
/// # }
/// ```
fn with_activation_policy(&mut self, activation_policy: ActivationPolicy) -> &mut Self;
/// Used to control whether a default menubar menu is created.
///
/// Menu creation is enabled by default.
///
/// # Example
///
/// Disable creating a default menubar.
///
/// ```
/// use winit::event_loop::EventLoopBuilder;
/// #[cfg(target_os = "macos")]
/// use winit::platform::macos::EventLoopBuilderExtMacOS;
///
/// let mut builder = EventLoopBuilder::new();
/// #[cfg(target_os = "macos")]
/// builder.with_default_menu(false);
/// # if false { // We can't test this part
/// let event_loop = builder.build();
/// # }
/// ```
fn with_default_menu(&mut self, enable: bool) -> &mut Self;
/// Used to prevent the application from automatically activating when launched if
/// another application is already active.
///
/// The default behavior is to ignore other applications and activate when launched.
fn with_activate_ignoring_other_apps(&mut self, ignore: bool) -> &mut Self;
}
impl<T> EventLoopBuilderExtMacOS for EventLoopBuilder<T> {
#[inline]
fn with_activation_policy(&mut self, activation_policy: ActivationPolicy) -> &mut Self {
self.platform_specific.activation_policy = activation_policy;
self
}
#[inline]
fn with_default_menu(&mut self, enable: bool) -> &mut Self {
self.platform_specific.default_menu = enable;
self
}
#[inline]
fn with_activate_ignoring_other_apps(&mut self, ignore: bool) -> &mut Self {
self.platform_specific.activate_ignoring_other_apps = ignore;
self
}
}
/// Additional methods on [`MonitorHandle`] that are specific to MacOS.
pub trait MonitorHandleExtMacOS {
/// Returns the identifier of the monitor for Cocoa.
fn native_id(&self) -> u32;
/// Returns a pointer to the NSScreen representing this monitor.
fn ns_screen(&self) -> Option<*mut c_void>;
}
impl MonitorHandleExtMacOS for MonitorHandle {
#[inline]
fn native_id(&self) -> u32 {
self.inner.native_identifier()
}
fn ns_screen(&self) -> Option<*mut c_void> {
self.inner.ns_screen().map(|s| Id::as_ptr(&s) as _)
}
}
/// Additional methods on [`EventLoopWindowTarget`] that are specific to macOS.
pub trait EventLoopWindowTargetExtMacOS {
/// Hide the entire application. In most applications this is typically triggered with Command-H.
fn hide_application(&self);
/// Hide the other applications. In most applications this is typically triggered with Command+Option-H.
fn hide_other_applications(&self);
}
impl<T> EventLoopWindowTargetExtMacOS for EventLoopWindowTarget<T> {
fn hide_application(&self) {
self.p.hide_application()
}
fn hide_other_applications(&self) {
self.p.hide_other_applications()
}
}
/// Option as alt behavior.
///
/// The default is `None`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum OptionAsAlt {
/// The left `Option` key is treated as `Alt`.
OnlyLeft,
/// The right `Option` key is treated as `Alt`.
OnlyRight,
/// Both `Option` keys are treated as `Alt`.
Both,
/// No special handling is applied for `Option` key.
None,
}
impl Default for OptionAsAlt {
fn default() -> Self {
OptionAsAlt::None
}
}

View File

@@ -1,43 +0,0 @@
//! Contains traits with platform-specific methods in them.
//!
//! Contains the follow OS-specific modules:
//!
//! - `android`
//! - `ios`
//! - `macos`
//! - `unix`
//! - `windows`
//! - `web`
//!
//! And the following platform-specific module:
//!
//! - `run_return` (available on `windows`, `unix`, `macos`, and `android`)
//!
//! However only the module corresponding to the platform you're compiling to will be available.
#[cfg(android_platform)]
pub mod android;
#[cfg(ios_platform)]
pub mod ios;
#[cfg(macos_platform)]
pub mod macos;
#[cfg(orbital_platform)]
pub mod orbital;
#[cfg(wayland_platform)]
pub mod wayland;
#[cfg(wasm_platform)]
pub mod web;
#[cfg(windows_platform)]
pub mod windows;
#[cfg(x11_platform)]
pub mod x11;
#[cfg(any(
windows_platform,
macos_platform,
android_platform,
x11_platform,
wayland_platform,
orbital_platform
))]
pub mod run_return;

View File

@@ -1 +0,0 @@
// There are no Orbital specific traits yet.

View File

@@ -1,53 +0,0 @@
use crate::{
event::Event,
event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget},
};
/// Additional methods on [`EventLoop`] to return control flow to the caller.
pub trait EventLoopExtRunReturn {
/// A type provided by the user that can be passed through [`Event::UserEvent`].
type UserEvent;
/// Initializes the `winit` event loop.
///
/// Unlike [`EventLoop::run`], this function accepts non-`'static` (i.e. non-`move`) closures
/// and returns control flow to the caller when `control_flow` is set to [`ControlFlow::Exit`].
///
/// # Caveats
///
/// Despite its appearance at first glance, this is *not* a perfect replacement for
/// `poll_events`. For example, this function will not return on Windows or macOS while a
/// window is getting resized, resulting in all application logic outside of the
/// `event_handler` closure not running until the resize operation ends. Other OS operations
/// may also result in such freezes. This behavior is caused by fundamental limitations in the
/// underlying OS APIs, which cannot be hidden by `winit` without severe stability repercussions.
///
/// You are strongly encouraged to use `run`, unless the use of this is absolutely necessary.
///
/// ## Platform-specific
///
/// - **X11 / Wayland:** This function returns `1` upon disconnection from
/// the display server.
fn run_return<F>(&mut self, event_handler: F) -> i32
where
F: FnMut(
Event<'_, Self::UserEvent>,
&EventLoopWindowTarget<Self::UserEvent>,
&mut ControlFlow,
);
}
impl<T> EventLoopExtRunReturn for EventLoop<T> {
type UserEvent = T;
fn run_return<F>(&mut self, event_handler: F) -> i32
where
F: FnMut(
Event<'_, Self::UserEvent>,
&EventLoopWindowTarget<Self::UserEvent>,
&mut ControlFlow,
),
{
self.event_loop.run_return(event_handler)
}
}

View File

@@ -1,144 +0,0 @@
use std::os::raw;
use crate::{
event_loop::{EventLoopBuilder, EventLoopWindowTarget},
monitor::MonitorHandle,
window::{Window, WindowBuilder},
};
use crate::platform_impl::{
ApplicationName, Backend, EventLoopWindowTarget as LinuxEventLoopWindowTarget,
Window as LinuxWindow,
};
pub use crate::window::Theme;
/// Additional methods on [`EventLoopWindowTarget`] that are specific to Wayland.
pub trait EventLoopWindowTargetExtWayland {
/// True if the [`EventLoopWindowTarget`] uses Wayland.
fn is_wayland(&self) -> bool;
/// Returns a pointer to the `wl_display` object of wayland that is used by this
/// [`EventLoopWindowTarget`].
///
/// Returns `None` if the [`EventLoop`] doesn't use wayland (if it uses xlib for example).
///
/// The pointer will become invalid when the winit [`EventLoop`] is destroyed.
///
/// [`EventLoop`]: crate::event_loop::EventLoop
fn wayland_display(&self) -> Option<*mut raw::c_void>;
}
impl<T> EventLoopWindowTargetExtWayland for EventLoopWindowTarget<T> {
#[inline]
fn is_wayland(&self) -> bool {
self.p.is_wayland()
}
#[inline]
fn wayland_display(&self) -> Option<*mut raw::c_void> {
match self.p {
LinuxEventLoopWindowTarget::Wayland(ref p) => {
Some(p.display().get_display_ptr() as *mut _)
}
#[cfg(x11_platform)]
_ => None,
}
}
}
/// Additional methods on [`EventLoopBuilder`] that are specific to Wayland.
pub trait EventLoopBuilderExtWayland {
/// Force using Wayland.
fn with_wayland(&mut self) -> &mut Self;
/// Whether to allow the event loop to be created off of the main thread.
///
/// By default, the window is only allowed to be created on the main
/// thread, to make platform compatibility easier.
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self;
}
impl<T> EventLoopBuilderExtWayland for EventLoopBuilder<T> {
#[inline]
fn with_wayland(&mut self) -> &mut Self {
self.platform_specific.forced_backend = Some(Backend::Wayland);
self
}
#[inline]
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self {
self.platform_specific.any_thread = any_thread;
self
}
}
/// Additional methods on [`Window`] that are specific to Wayland.
pub trait WindowExtWayland {
/// Returns a pointer to the `wl_surface` object of wayland that is used by this window.
///
/// Returns `None` if the window doesn't use wayland (if it uses xlib for example).
///
/// The pointer will become invalid when the [`Window`] is destroyed.
fn wayland_surface(&self) -> Option<*mut raw::c_void>;
/// Returns a pointer to the `wl_display` object of wayland that is used by this window.
///
/// Returns `None` if the window doesn't use wayland (if it uses xlib for example).
///
/// The pointer will become invalid when the [`Window`] is destroyed.
fn wayland_display(&self) -> Option<*mut raw::c_void>;
}
impl WindowExtWayland for Window {
#[inline]
fn wayland_surface(&self) -> Option<*mut raw::c_void> {
match self.window {
LinuxWindow::Wayland(ref w) => Some(w.surface().as_ref().c_ptr() as *mut _),
#[cfg(x11_platform)]
_ => None,
}
}
#[inline]
fn wayland_display(&self) -> Option<*mut raw::c_void> {
match self.window {
LinuxWindow::Wayland(ref w) => Some(w.display().get_display_ptr() as *mut _),
#[cfg(x11_platform)]
_ => None,
}
}
}
/// Additional methods on [`WindowBuilder`] that are specific to Wayland.
pub trait WindowBuilderExtWayland {
/// Build window with the given name.
///
/// The `general` name sets an application ID, which should match the `.desktop`
/// file destributed with your program. The `instance` is a `no-op`.
///
/// For details about application ID conventions, see the
/// [Desktop Entry Spec](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id)
fn with_name(self, general: impl Into<String>, instance: impl Into<String>) -> Self;
}
impl WindowBuilderExtWayland for WindowBuilder {
#[inline]
fn with_name(mut self, general: impl Into<String>, instance: impl Into<String>) -> Self {
self.platform_specific.name = Some(ApplicationName::new(general.into(), instance.into()));
self
}
}
/// Additional methods on `MonitorHandle` that are specific to Wayland.
pub trait MonitorHandleExtWayland {
/// Returns the inner identifier of the monitor.
fn native_id(&self) -> u32;
}
impl MonitorHandleExtWayland for MonitorHandle {
#[inline]
fn native_id(&self) -> u32 {
self.inner.native_identifier()
}
}

View File

@@ -1,89 +0,0 @@
//! The web target does not automatically insert the canvas element object into the web page, to
//! allow end users to determine how the page should be laid out. Use the [`WindowExtWebSys`] trait
//! to retrieve the canvas from the Window. Alternatively, use the [`WindowBuilderExtWebSys`] trait
//! to provide your own canvas.
use crate::event::Event;
use crate::event_loop::ControlFlow;
use crate::event_loop::EventLoop;
use crate::event_loop::EventLoopWindowTarget;
use crate::window::WindowBuilder;
use web_sys::HtmlCanvasElement;
pub trait WindowExtWebSys {
fn canvas(&self) -> HtmlCanvasElement;
/// Whether the browser reports the preferred color scheme to be "dark".
fn is_dark_mode(&self) -> bool;
}
pub trait WindowBuilderExtWebSys {
fn with_canvas(self, canvas: Option<HtmlCanvasElement>) -> Self;
/// Whether `event.preventDefault` should be automatically called to prevent event propagation
/// when appropriate.
///
/// For example, mouse wheel events are only handled by the canvas by default. This avoids
/// the default behavior of scrolling the page.
fn with_prevent_default(self, prevent_default: bool) -> Self;
/// Whether the canvas should be focusable using the tab key. This is necessary to capture
/// canvas keyboard events.
fn with_focusable(self, focusable: bool) -> Self;
}
impl WindowBuilderExtWebSys for WindowBuilder {
fn with_canvas(mut self, canvas: Option<HtmlCanvasElement>) -> Self {
self.platform_specific.canvas = canvas;
self
}
fn with_prevent_default(mut self, prevent_default: bool) -> Self {
self.platform_specific.prevent_default = prevent_default;
self
}
fn with_focusable(mut self, focusable: bool) -> Self {
self.platform_specific.focusable = focusable;
self
}
}
/// Additional methods on `EventLoop` that are specific to the web.
pub trait EventLoopExtWebSys {
/// A type provided by the user that can be passed through `Event::UserEvent`.
type UserEvent;
/// Initializes the winit event loop.
///
/// Unlike `run`, this returns immediately, and doesn't throw an exception in order to
/// satisfy its `!` return type.
fn spawn<F>(self, event_handler: F)
where
F: 'static
+ FnMut(
Event<'_, Self::UserEvent>,
&EventLoopWindowTarget<Self::UserEvent>,
&mut ControlFlow,
);
}
impl<T> EventLoopExtWebSys for EventLoop<T> {
type UserEvent = T;
fn spawn<F>(self, event_handler: F)
where
F: 'static
+ FnMut(
Event<'_, Self::UserEvent>,
&EventLoopWindowTarget<Self::UserEvent>,
&mut ControlFlow,
),
{
self.event_loop.spawn(event_handler)
}
}

View File

@@ -1,346 +0,0 @@
use std::{ffi::c_void, path::Path};
use crate::{
dpi::PhysicalSize,
event::DeviceId,
event_loop::EventLoopBuilder,
monitor::MonitorHandle,
platform_impl::WinIcon,
window::{BadIcon, Icon, Window, WindowBuilder},
};
/// Window Handle type used by Win32 API
pub type HWND = isize;
/// Menu Handle type used by Win32 API
pub type HMENU = isize;
/// Monitor Handle type used by Win32 API
pub type HMONITOR = isize;
/// Instance Handle type used by Win32 API
pub type HINSTANCE = isize;
/// Additional methods on `EventLoop` that are specific to Windows.
pub trait EventLoopBuilderExtWindows {
/// Whether to allow the event loop to be created off of the main thread.
///
/// By default, the window is only allowed to be created on the main
/// thread, to make platform compatibility easier.
///
/// # `Window` caveats
///
/// Note that any `Window` created on the new thread will be destroyed when the thread
/// terminates. Attempting to use a `Window` after its parent thread terminates has
/// unspecified, although explicitly not undefined, behavior.
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self;
/// Whether to enable process-wide DPI awareness.
///
/// By default, `winit` will attempt to enable process-wide DPI awareness. If
/// that's undesirable, you can disable it with this function.
///
/// # Example
///
/// Disable process-wide DPI awareness.
///
/// ```
/// use winit::event_loop::EventLoopBuilder;
/// #[cfg(target_os = "windows")]
/// use winit::platform::windows::EventLoopBuilderExtWindows;
///
/// let mut builder = EventLoopBuilder::new();
/// #[cfg(target_os = "windows")]
/// builder.with_dpi_aware(false);
/// # if false { // We can't test this part
/// let event_loop = builder.build();
/// # }
/// ```
fn with_dpi_aware(&mut self, dpi_aware: bool) -> &mut Self;
/// A callback to be executed before dispatching a win32 message to the window procedure.
/// Return true to disable winit's internal message dispatching.
///
/// # Example
///
/// ```
/// # use windows_sys::Win32::UI::WindowsAndMessaging::{ACCEL, CreateAcceleratorTableW, TranslateAcceleratorW, DispatchMessageW, TranslateMessage, MSG};
/// use winit::event_loop::EventLoopBuilder;
/// #[cfg(target_os = "windows")]
/// use winit::platform::windows::EventLoopBuilderExtWindows;
///
/// let mut builder = EventLoopBuilder::new();
/// #[cfg(target_os = "windows")]
/// builder.with_msg_hook(|msg|{
/// let msg = msg as *const MSG;
/// # let accels: Vec<ACCEL> = Vec::new();
/// let translated = unsafe {
/// TranslateAcceleratorW(
/// (*msg).hwnd,
/// CreateAcceleratorTableW(accels.as_ptr() as _, 1),
/// msg,
/// ) == 1
/// };
/// translated
/// });
/// ```
fn with_msg_hook<F>(&mut self, callback: F) -> &mut Self
where
F: FnMut(*const c_void) -> bool + 'static;
}
impl<T> EventLoopBuilderExtWindows for EventLoopBuilder<T> {
#[inline]
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self {
self.platform_specific.any_thread = any_thread;
self
}
#[inline]
fn with_dpi_aware(&mut self, dpi_aware: bool) -> &mut Self {
self.platform_specific.dpi_aware = dpi_aware;
self
}
#[inline]
fn with_msg_hook<F>(&mut self, callback: F) -> &mut Self
where
F: FnMut(*const c_void) -> bool + 'static,
{
self.platform_specific.msg_hook = Some(Box::new(callback));
self
}
}
/// Additional methods on `Window` that are specific to Windows.
pub trait WindowExtWindows {
/// Returns the HINSTANCE of the window
fn hinstance(&self) -> HINSTANCE;
/// Returns the native handle that is used by this window.
///
/// The pointer will become invalid when the native window was destroyed.
fn hwnd(&self) -> HWND;
/// Enables or disables mouse and keyboard input to the specified window.
///
/// A window must be enabled before it can be activated.
/// If an application has create a modal dialog box by disabling its owner window
/// (as described in [`WindowBuilderExtWindows::with_owner_window`]), the application must enable
/// the owner window before destroying the dialog box.
/// Otherwise, another window will receive the keyboard focus and be activated.
///
/// If a child window is disabled, it is ignored when the system tries to determine which
/// window should receive mouse messages.
///
/// For more information, see <https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enablewindow#remarks>
/// and <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#disabled-windows>
fn set_enable(&self, enabled: bool);
/// This sets `ICON_BIG`. A good ceiling here is 256x256.
fn set_taskbar_icon(&self, taskbar_icon: Option<Icon>);
/// Whether to show or hide the window icon in the taskbar.
fn set_skip_taskbar(&self, skip: bool);
/// Shows or hides the background drop shadow for undecorated windows.
///
/// Enabling the shadow causes a thin 1px line to appear on the top of the window.
fn set_undecorated_shadow(&self, shadow: bool);
}
impl WindowExtWindows for Window {
#[inline]
fn hinstance(&self) -> HINSTANCE {
self.window.hinstance()
}
#[inline]
fn hwnd(&self) -> HWND {
self.window.hwnd()
}
#[inline]
fn set_enable(&self, enabled: bool) {
self.window.set_enable(enabled)
}
#[inline]
fn set_taskbar_icon(&self, taskbar_icon: Option<Icon>) {
self.window.set_taskbar_icon(taskbar_icon)
}
#[inline]
fn set_skip_taskbar(&self, skip: bool) {
self.window.set_skip_taskbar(skip)
}
#[inline]
fn set_undecorated_shadow(&self, shadow: bool) {
self.window.set_undecorated_shadow(shadow)
}
}
/// Additional methods on `WindowBuilder` that are specific to Windows.
pub trait WindowBuilderExtWindows {
/// Set an owner to the window to be created. Can be used to create a dialog box, for example.
/// This only works when [`WindowBuilder::with_parent_window`] isn't called or set to `None`.
/// Can be used in combination with [`WindowExtWindows::set_enable(false)`](WindowExtWindows::set_enable)
/// on the owner window to create a modal dialog box.
///
/// From MSDN:
/// - An owned window is always above its owner in the z-order.
/// - The system automatically destroys an owned window when its owner is destroyed.
/// - An owned window is hidden when its owner is minimized.
///
/// For more information, see <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#owned-windows>
fn with_owner_window(self, parent: HWND) -> WindowBuilder;
/// Sets a menu on the window to be created.
///
/// Parent and menu are mutually exclusive; a child window cannot have a menu!
///
/// The menu must have been manually created beforehand with [`CreateMenu`] or similar.
///
/// Note: Dark mode cannot be supported for win32 menus, it's simply not possible to change how the menus look.
/// If you use this, it is recommended that you combine it with `with_theme(Some(Theme::Light))` to avoid a jarring effect.
///
/// [`CreateMenu`]: windows_sys::Win32::UI::WindowsAndMessaging::CreateMenu
fn with_menu(self, menu: HMENU) -> WindowBuilder;
/// This sets `ICON_BIG`. A good ceiling here is 256x256.
fn with_taskbar_icon(self, taskbar_icon: Option<Icon>) -> WindowBuilder;
/// This sets `WS_EX_NOREDIRECTIONBITMAP`.
fn with_no_redirection_bitmap(self, flag: bool) -> WindowBuilder;
/// Enables or disables drag and drop support (enabled by default). Will interfere with other crates
/// that use multi-threaded COM API (`CoInitializeEx` with `COINIT_MULTITHREADED` instead of
/// `COINIT_APARTMENTTHREADED`) on the same thread. Note that winit may still attempt to initialize
/// COM API regardless of this option. Currently only fullscreen mode does that, but there may be more in the future.
/// If you need COM API with `COINIT_MULTITHREADED` you must initialize it before calling any winit functions.
/// See <https://docs.microsoft.com/en-us/windows/win32/api/objbase/nf-objbase-coinitialize#remarks> for more information.
fn with_drag_and_drop(self, flag: bool) -> WindowBuilder;
/// Whether show or hide the window icon in the taskbar.
fn with_skip_taskbar(self, skip: bool) -> WindowBuilder;
/// Shows or hides the background drop shadow for undecorated windows.
///
/// The shadow is hidden by default.
/// Enabling the shadow causes a thin 1px line to appear on the top of the window.
fn with_undecorated_shadow(self, shadow: bool) -> WindowBuilder;
}
impl WindowBuilderExtWindows for WindowBuilder {
#[inline]
fn with_owner_window(mut self, parent: HWND) -> WindowBuilder {
self.platform_specific.owner = Some(parent);
self
}
#[inline]
fn with_menu(mut self, menu: HMENU) -> WindowBuilder {
self.platform_specific.menu = Some(menu);
self
}
#[inline]
fn with_taskbar_icon(mut self, taskbar_icon: Option<Icon>) -> WindowBuilder {
self.platform_specific.taskbar_icon = taskbar_icon;
self
}
#[inline]
fn with_no_redirection_bitmap(mut self, flag: bool) -> WindowBuilder {
self.platform_specific.no_redirection_bitmap = flag;
self
}
#[inline]
fn with_drag_and_drop(mut self, flag: bool) -> WindowBuilder {
self.platform_specific.drag_and_drop = flag;
self
}
#[inline]
fn with_skip_taskbar(mut self, skip: bool) -> WindowBuilder {
self.platform_specific.skip_taskbar = skip;
self
}
#[inline]
fn with_undecorated_shadow(mut self, shadow: bool) -> WindowBuilder {
self.platform_specific.decoration_shadow = shadow;
self
}
}
/// Additional methods on `MonitorHandle` that are specific to Windows.
pub trait MonitorHandleExtWindows {
/// Returns the name of the monitor adapter specific to the Win32 API.
fn native_id(&self) -> String;
/// Returns the handle of the monitor - `HMONITOR`.
fn hmonitor(&self) -> HMONITOR;
}
impl MonitorHandleExtWindows for MonitorHandle {
#[inline]
fn native_id(&self) -> String {
self.inner.native_identifier()
}
#[inline]
fn hmonitor(&self) -> HMONITOR {
self.inner.hmonitor()
}
}
/// Additional methods on `DeviceId` that are specific to Windows.
pub trait DeviceIdExtWindows {
/// Returns an identifier that persistently refers to this specific device.
///
/// Will return `None` if the device is no longer available.
fn persistent_identifier(&self) -> Option<String>;
}
impl DeviceIdExtWindows for DeviceId {
#[inline]
fn persistent_identifier(&self) -> Option<String> {
self.0.persistent_identifier()
}
}
/// Additional methods on `Icon` that are specific to Windows.
pub trait IconExtWindows: Sized {
/// Create an icon from a file path.
///
/// Specify `size` to load a specific icon size from the file, or `None` to load the default
/// icon size from the file.
///
/// In cases where the specified size does not exist in the file, Windows may perform scaling
/// to get an icon of the desired size.
fn from_path<P: AsRef<Path>>(path: P, size: Option<PhysicalSize<u32>>)
-> Result<Self, BadIcon>;
/// Create an icon from a resource embedded in this executable or library.
///
/// Specify `size` to load a specific icon size from the file, or `None` to load the default
/// icon size from the file.
///
/// In cases where the specified size does not exist in the file, Windows may perform scaling
/// to get an icon of the desired size.
fn from_resource(ordinal: u16, size: Option<PhysicalSize<u32>>) -> Result<Self, BadIcon>;
}
impl IconExtWindows for Icon {
fn from_path<P: AsRef<Path>>(
path: P,
size: Option<PhysicalSize<u32>>,
) -> Result<Self, BadIcon> {
let win_icon = WinIcon::from_path(path, size)?;
Ok(Icon { inner: win_icon })
}
fn from_resource(ordinal: u16, size: Option<PhysicalSize<u32>>) -> Result<Self, BadIcon> {
let win_icon = WinIcon::from_resource(ordinal, size)?;
Ok(Icon { inner: win_icon })
}
}

View File

@@ -1,233 +0,0 @@
use std::os::raw;
use std::ptr;
use crate::{
event_loop::{EventLoopBuilder, EventLoopWindowTarget},
monitor::MonitorHandle,
window::{Window, WindowBuilder},
};
use crate::dpi::Size;
use crate::platform_impl::{
x11::ffi::XVisualInfo, ApplicationName, Backend, Window as LinuxWindow, XLIB_ERROR_HOOKS,
};
pub use crate::platform_impl::{x11::util::WindowType as XWindowType, XNotSupported};
/// The first argument in the provided hook will be the pointer to `XDisplay`
/// and the second one the pointer to [`XErrorEvent`]. The returned `bool` is an
/// indicator whether the error was handled by the callback.
///
/// [`XErrorEvent`]: https://linux.die.net/man/3/xerrorevent
pub type XlibErrorHook =
Box<dyn Fn(*mut std::ffi::c_void, *mut std::ffi::c_void) -> bool + Send + Sync>;
/// Hook to winit's xlib error handling callback.
///
/// This method is provided as a safe way to handle the errors comming from X11
/// when using xlib in external crates, like glutin for GLX access. Trying to
/// handle errors by speculating with `XSetErrorHandler` is [`unsafe`].
///
/// **Be aware that your hook is always invoked and returning `true` from it will
/// prevent `winit` from getting the error itself. It's wise to always return
/// `false` if you're not initiated the `Sync`.**
///
/// [`unsafe`]: https://www.remlab.net/op/xlib.shtml
#[inline]
pub fn register_xlib_error_hook(hook: XlibErrorHook) {
// Append new hook.
unsafe {
XLIB_ERROR_HOOKS.lock().unwrap().push(hook);
}
}
/// Additional methods on [`EventLoopWindowTarget`] that are specific to X11.
pub trait EventLoopWindowTargetExtX11 {
/// True if the [`EventLoopWindowTarget`] uses X11.
fn is_x11(&self) -> bool;
}
impl<T> EventLoopWindowTargetExtX11 for EventLoopWindowTarget<T> {
#[inline]
fn is_x11(&self) -> bool {
!self.p.is_wayland()
}
}
/// Additional methods on [`EventLoopBuilder`] that are specific to X11.
pub trait EventLoopBuilderExtX11 {
/// Force using X11.
fn with_x11(&mut self) -> &mut Self;
/// Whether to allow the event loop to be created off of the main thread.
///
/// By default, the window is only allowed to be created on the main
/// thread, to make platform compatibility easier.
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self;
}
impl<T> EventLoopBuilderExtX11 for EventLoopBuilder<T> {
#[inline]
fn with_x11(&mut self) -> &mut Self {
self.platform_specific.forced_backend = Some(Backend::X);
self
}
#[inline]
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self {
self.platform_specific.any_thread = any_thread;
self
}
}
/// Additional methods on [`Window`] that are specific to X11.
pub trait WindowExtX11 {
/// Returns the ID of the [`Window`] xlib object that is used by this window.
///
/// Returns `None` if the window doesn't use xlib (if it uses wayland for example).
fn xlib_window(&self) -> Option<raw::c_ulong>;
/// Returns a pointer to the `Display` object of xlib that is used by this window.
///
/// Returns `None` if the window doesn't use xlib (if it uses wayland for example).
///
/// The pointer will become invalid when the [`Window`] is destroyed.
fn xlib_display(&self) -> Option<*mut raw::c_void>;
fn xlib_screen_id(&self) -> Option<raw::c_int>;
/// This function returns the underlying `xcb_connection_t` of an xlib `Display`.
///
/// Returns `None` if the window doesn't use xlib (if it uses wayland for example).
///
/// The pointer will become invalid when the [`Window`] is destroyed.
fn xcb_connection(&self) -> Option<*mut raw::c_void>;
}
impl WindowExtX11 for Window {
#[inline]
fn xlib_window(&self) -> Option<raw::c_ulong> {
match self.window {
LinuxWindow::X(ref w) => Some(w.xlib_window()),
#[cfg(wayland_platform)]
_ => None,
}
}
#[inline]
fn xlib_display(&self) -> Option<*mut raw::c_void> {
match self.window {
LinuxWindow::X(ref w) => Some(w.xlib_display()),
#[cfg(wayland_platform)]
_ => None,
}
}
#[inline]
fn xlib_screen_id(&self) -> Option<raw::c_int> {
match self.window {
LinuxWindow::X(ref w) => Some(w.xlib_screen_id()),
#[cfg(wayland_platform)]
_ => None,
}
}
#[inline]
fn xcb_connection(&self) -> Option<*mut raw::c_void> {
match self.window {
LinuxWindow::X(ref w) => Some(w.xcb_connection()),
#[cfg(wayland_platform)]
_ => None,
}
}
}
/// Additional methods on [`WindowBuilder`] that are specific to X11.
pub trait WindowBuilderExtX11 {
fn with_x11_visual<T>(self, visual_infos: *const T) -> Self;
fn with_x11_screen(self, screen_id: i32) -> Self;
/// Build window with the given `general` and `instance` names.
///
/// The `general` sets general class of `WM_CLASS(STRING)`, while `instance` set the
/// instance part of it. The resulted property looks like `WM_CLASS(STRING) = "general", "instance"`.
///
/// For details about application ID conventions, see the
/// [Desktop Entry Spec](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id)
fn with_name(self, general: impl Into<String>, instance: impl Into<String>) -> Self;
/// Build window with override-redirect flag; defaults to false. Only relevant on X11.
fn with_override_redirect(self, override_redirect: bool) -> Self;
/// Build window with `_NET_WM_WINDOW_TYPE` hints; defaults to `Normal`. Only relevant on X11.
fn with_x11_window_type(self, x11_window_type: Vec<XWindowType>) -> Self;
/// Build window with base size hint. Only implemented on X11.
///
/// ```
/// # use winit::dpi::{LogicalSize, PhysicalSize};
/// # use winit::window::WindowBuilder;
/// # use winit::platform::x11::WindowBuilderExtX11;
/// // Specify the size in logical dimensions like this:
/// WindowBuilder::new().with_base_size(LogicalSize::new(400.0, 200.0));
///
/// // Or specify the size in physical dimensions like this:
/// WindowBuilder::new().with_base_size(PhysicalSize::new(400, 200));
/// ```
fn with_base_size<S: Into<Size>>(self, base_size: S) -> Self;
}
impl WindowBuilderExtX11 for WindowBuilder {
#[inline]
fn with_x11_visual<T>(mut self, visual_infos: *const T) -> Self {
{
self.platform_specific.visual_infos =
Some(unsafe { ptr::read(visual_infos as *const XVisualInfo) });
}
self
}
#[inline]
fn with_x11_screen(mut self, screen_id: i32) -> Self {
self.platform_specific.screen_id = Some(screen_id);
self
}
#[inline]
fn with_name(mut self, general: impl Into<String>, instance: impl Into<String>) -> Self {
self.platform_specific.name = Some(ApplicationName::new(general.into(), instance.into()));
self
}
#[inline]
fn with_override_redirect(mut self, override_redirect: bool) -> Self {
self.platform_specific.override_redirect = override_redirect;
self
}
#[inline]
fn with_x11_window_type(mut self, x11_window_types: Vec<XWindowType>) -> Self {
self.platform_specific.x11_window_types = x11_window_types;
self
}
#[inline]
fn with_base_size<S: Into<Size>>(mut self, base_size: S) -> Self {
self.platform_specific.base_size = Some(base_size.into());
self
}
}
/// Additional methods on `MonitorHandle` that are specific to X11.
pub trait MonitorHandleExtX11 {
/// Returns the inner identifier of the monitor.
fn native_id(&self) -> u32;
}
impl MonitorHandleExtX11 for MonitorHandle {
#[inline]
fn native_id(&self) -> u32 {
self.inner.native_identifier()
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,992 +0,0 @@
#![deny(unused_results)]
use std::{
cell::{RefCell, RefMut},
collections::HashSet,
mem,
os::raw::c_void,
ptr,
time::Instant,
};
use core_foundation::base::CFRelease;
use core_foundation::date::CFAbsoluteTimeGetCurrent;
use core_foundation::runloop::{
kCFRunLoopCommonModes, CFRunLoopAddTimer, CFRunLoopGetMain, CFRunLoopRef, CFRunLoopTimerCreate,
CFRunLoopTimerInvalidate, CFRunLoopTimerRef, CFRunLoopTimerSetNextFireDate,
};
use objc2::foundation::{CGRect, CGSize, NSInteger, NSProcessInfo};
use objc2::rc::{Id, Shared};
use objc2::runtime::Object;
use objc2::{msg_send, sel};
use once_cell::sync::Lazy;
use super::uikit::UIView;
use super::view::WinitUIWindow;
use crate::{
dpi::LogicalSize,
event::{Event, StartCause, WindowEvent},
event_loop::ControlFlow,
platform_impl::platform::{
event_loop::{EventHandler, EventProxy, EventWrapper, Never},
ffi::NSOperatingSystemVersion,
},
window::WindowId as RootWindowId,
};
macro_rules! bug {
($($msg:tt)*) => {
panic!("winit iOS bug, file an issue: {}", format!($($msg)*))
};
}
macro_rules! bug_assert {
($test:expr, $($msg:tt)*) => {
assert!($test, "winit iOS bug, file an issue: {}", format!($($msg)*))
};
}
enum UserCallbackTransitionResult<'a> {
Success {
event_handler: Box<dyn EventHandler>,
active_control_flow: ControlFlow,
processing_redraws: bool,
},
ReentrancyPrevented {
queued_events: &'a mut Vec<EventWrapper>,
},
}
impl Event<'static, Never> {
fn is_redraw(&self) -> bool {
matches!(self, Event::RedrawRequested(_))
}
}
// this is the state machine for the app lifecycle
#[derive(Debug)]
#[must_use = "dropping `AppStateImpl` without inspecting it is probably a bug"]
enum AppStateImpl {
NotLaunched {
queued_windows: Vec<Id<WinitUIWindow, Shared>>,
queued_events: Vec<EventWrapper>,
queued_gpu_redraws: HashSet<Id<WinitUIWindow, Shared>>,
},
Launching {
queued_windows: Vec<Id<WinitUIWindow, Shared>>,
queued_events: Vec<EventWrapper>,
queued_event_handler: Box<dyn EventHandler>,
queued_gpu_redraws: HashSet<Id<WinitUIWindow, Shared>>,
},
ProcessingEvents {
event_handler: Box<dyn EventHandler>,
queued_gpu_redraws: HashSet<Id<WinitUIWindow, Shared>>,
active_control_flow: ControlFlow,
},
// special state to deal with reentrancy and prevent mutable aliasing.
InUserCallback {
queued_events: Vec<EventWrapper>,
queued_gpu_redraws: HashSet<Id<WinitUIWindow, Shared>>,
},
ProcessingRedraws {
event_handler: Box<dyn EventHandler>,
active_control_flow: ControlFlow,
},
Waiting {
waiting_event_handler: Box<dyn EventHandler>,
start: Instant,
},
PollFinished {
waiting_event_handler: Box<dyn EventHandler>,
},
Terminated,
}
struct AppState {
// This should never be `None`, except for briefly during a state transition.
app_state: Option<AppStateImpl>,
control_flow: ControlFlow,
waker: EventLoopWaker,
}
impl AppState {
// requires main thread
unsafe fn get_mut() -> RefMut<'static, AppState> {
// basically everything in UIKit requires the main thread, so it's pointless to use the
// std::sync APIs.
// must be mut because plain `static` requires `Sync`
static mut APP_STATE: RefCell<Option<AppState>> = RefCell::new(None);
if cfg!(debug_assertions) {
assert_main_thread!(
"bug in winit: `AppState::get_mut()` can only be called on the main thread"
);
}
let mut guard = APP_STATE.borrow_mut();
if guard.is_none() {
#[inline(never)]
#[cold]
unsafe fn init_guard(guard: &mut RefMut<'static, Option<AppState>>) {
let waker = EventLoopWaker::new(CFRunLoopGetMain());
**guard = Some(AppState {
app_state: Some(AppStateImpl::NotLaunched {
queued_windows: Vec::new(),
queued_events: Vec::new(),
queued_gpu_redraws: HashSet::new(),
}),
control_flow: ControlFlow::default(),
waker,
});
}
init_guard(&mut guard)
}
RefMut::map(guard, |state| state.as_mut().unwrap())
}
fn state(&self) -> &AppStateImpl {
match &self.app_state {
Some(ref state) => state,
None => bug!("`AppState` previously failed a state transition"),
}
}
fn state_mut(&mut self) -> &mut AppStateImpl {
match &mut self.app_state {
Some(ref mut state) => state,
None => bug!("`AppState` previously failed a state transition"),
}
}
fn take_state(&mut self) -> AppStateImpl {
match self.app_state.take() {
Some(state) => state,
None => bug!("`AppState` previously failed a state transition"),
}
}
fn set_state(&mut self, new_state: AppStateImpl) {
bug_assert!(
self.app_state.is_none(),
"attempted to set an `AppState` without calling `take_state` first {:?}",
self.app_state
);
self.app_state = Some(new_state)
}
fn replace_state(&mut self, new_state: AppStateImpl) -> AppStateImpl {
match &mut self.app_state {
Some(ref mut state) => mem::replace(state, new_state),
None => bug!("`AppState` previously failed a state transition"),
}
}
fn has_launched(&self) -> bool {
!matches!(
self.state(),
AppStateImpl::NotLaunched { .. } | AppStateImpl::Launching { .. }
)
}
fn will_launch_transition(&mut self, queued_event_handler: Box<dyn EventHandler>) {
let (queued_windows, queued_events, queued_gpu_redraws) = match self.take_state() {
AppStateImpl::NotLaunched {
queued_windows,
queued_events,
queued_gpu_redraws,
} => (queued_windows, queued_events, queued_gpu_redraws),
s => bug!("unexpected state {:?}", s),
};
self.set_state(AppStateImpl::Launching {
queued_windows,
queued_events,
queued_event_handler,
queued_gpu_redraws,
});
}
fn did_finish_launching_transition(
&mut self,
) -> (Vec<Id<WinitUIWindow, Shared>>, Vec<EventWrapper>) {
let (windows, events, event_handler, queued_gpu_redraws) = match self.take_state() {
AppStateImpl::Launching {
queued_windows,
queued_events,
queued_event_handler,
queued_gpu_redraws,
} => (
queued_windows,
queued_events,
queued_event_handler,
queued_gpu_redraws,
),
s => bug!("unexpected state {:?}", s),
};
self.set_state(AppStateImpl::ProcessingEvents {
event_handler,
active_control_flow: ControlFlow::Poll,
queued_gpu_redraws,
});
(windows, events)
}
fn wakeup_transition(&mut self) -> Option<EventWrapper> {
// before `AppState::did_finish_launching` is called, pretend there is no running
// event loop.
if !self.has_launched() {
return None;
}
let (event_handler, event) = match (self.control_flow, self.take_state()) {
(
ControlFlow::Poll,
AppStateImpl::PollFinished {
waiting_event_handler,
},
) => (
waiting_event_handler,
EventWrapper::StaticEvent(Event::NewEvents(StartCause::Poll)),
),
(
ControlFlow::Wait,
AppStateImpl::Waiting {
waiting_event_handler,
start,
},
) => (
waiting_event_handler,
EventWrapper::StaticEvent(Event::NewEvents(StartCause::WaitCancelled {
start,
requested_resume: None,
})),
),
(
ControlFlow::WaitUntil(requested_resume),
AppStateImpl::Waiting {
waiting_event_handler,
start,
},
) => {
let event = if Instant::now() >= requested_resume {
EventWrapper::StaticEvent(Event::NewEvents(StartCause::ResumeTimeReached {
start,
requested_resume,
}))
} else {
EventWrapper::StaticEvent(Event::NewEvents(StartCause::WaitCancelled {
start,
requested_resume: Some(requested_resume),
}))
};
(waiting_event_handler, event)
}
(ControlFlow::ExitWithCode(_), _) => bug!("unexpected `ControlFlow` `Exit`"),
s => bug!("`EventHandler` unexpectedly woke up {:?}", s),
};
self.set_state(AppStateImpl::ProcessingEvents {
event_handler,
queued_gpu_redraws: Default::default(),
active_control_flow: self.control_flow,
});
Some(event)
}
fn try_user_callback_transition(&mut self) -> UserCallbackTransitionResult<'_> {
// If we're not able to process an event due to recursion or `Init` not having been sent out
// yet, then queue the events up.
match self.state_mut() {
&mut AppStateImpl::Launching {
ref mut queued_events,
..
}
| &mut AppStateImpl::NotLaunched {
ref mut queued_events,
..
}
| &mut AppStateImpl::InUserCallback {
ref mut queued_events,
..
} => {
// A lifetime cast: early returns are not currently handled well with NLL, but
// polonius handles them well. This transmute is a safe workaround.
return unsafe {
mem::transmute::<
UserCallbackTransitionResult<'_>,
UserCallbackTransitionResult<'_>,
>(UserCallbackTransitionResult::ReentrancyPrevented {
queued_events,
})
};
}
&mut AppStateImpl::ProcessingEvents { .. }
| &mut AppStateImpl::ProcessingRedraws { .. } => {}
s @ &mut AppStateImpl::PollFinished { .. }
| s @ &mut AppStateImpl::Waiting { .. }
| s @ &mut AppStateImpl::Terminated => {
bug!("unexpected attempted to process an event {:?}", s)
}
}
let (event_handler, queued_gpu_redraws, active_control_flow, processing_redraws) =
match self.take_state() {
AppStateImpl::Launching { .. }
| AppStateImpl::NotLaunched { .. }
| AppStateImpl::InUserCallback { .. } => unreachable!(),
AppStateImpl::ProcessingEvents {
event_handler,
queued_gpu_redraws,
active_control_flow,
} => (
event_handler,
queued_gpu_redraws,
active_control_flow,
false,
),
AppStateImpl::ProcessingRedraws {
event_handler,
active_control_flow,
} => (event_handler, Default::default(), active_control_flow, true),
AppStateImpl::PollFinished { .. }
| AppStateImpl::Waiting { .. }
| AppStateImpl::Terminated => unreachable!(),
};
self.set_state(AppStateImpl::InUserCallback {
queued_events: Vec::new(),
queued_gpu_redraws,
});
UserCallbackTransitionResult::Success {
event_handler,
active_control_flow,
processing_redraws,
}
}
fn main_events_cleared_transition(&mut self) -> HashSet<Id<WinitUIWindow, Shared>> {
let (event_handler, queued_gpu_redraws, active_control_flow) = match self.take_state() {
AppStateImpl::ProcessingEvents {
event_handler,
queued_gpu_redraws,
active_control_flow,
} => (event_handler, queued_gpu_redraws, active_control_flow),
s => bug!("unexpected state {:?}", s),
};
self.set_state(AppStateImpl::ProcessingRedraws {
event_handler,
active_control_flow,
});
queued_gpu_redraws
}
fn events_cleared_transition(&mut self) {
if !self.has_launched() {
return;
}
let (waiting_event_handler, old) = match self.take_state() {
AppStateImpl::ProcessingRedraws {
event_handler,
active_control_flow,
} => (event_handler, active_control_flow),
s => bug!("unexpected state {:?}", s),
};
let new = self.control_flow;
match (old, new) {
(ControlFlow::Poll, ControlFlow::Poll) => self.set_state(AppStateImpl::PollFinished {
waiting_event_handler,
}),
(ControlFlow::Wait, ControlFlow::Wait) => {
let start = Instant::now();
self.set_state(AppStateImpl::Waiting {
waiting_event_handler,
start,
});
}
(ControlFlow::WaitUntil(old_instant), ControlFlow::WaitUntil(new_instant))
if old_instant == new_instant =>
{
let start = Instant::now();
self.set_state(AppStateImpl::Waiting {
waiting_event_handler,
start,
});
}
(_, ControlFlow::Wait) => {
let start = Instant::now();
self.set_state(AppStateImpl::Waiting {
waiting_event_handler,
start,
});
self.waker.stop()
}
(_, ControlFlow::WaitUntil(new_instant)) => {
let start = Instant::now();
self.set_state(AppStateImpl::Waiting {
waiting_event_handler,
start,
});
self.waker.start_at(new_instant)
}
(_, ControlFlow::Poll) => {
self.set_state(AppStateImpl::PollFinished {
waiting_event_handler,
});
self.waker.start()
}
(_, ControlFlow::ExitWithCode(_)) => {
// https://developer.apple.com/library/archive/qa/qa1561/_index.html
// it is not possible to quit an iOS app gracefully and programatically
warn!("`ControlFlow::Exit` ignored on iOS");
self.control_flow = old
}
}
}
fn terminated_transition(&mut self) -> Box<dyn EventHandler> {
match self.replace_state(AppStateImpl::Terminated) {
AppStateImpl::ProcessingEvents { event_handler, .. } => event_handler,
s => bug!(
"`LoopDestroyed` happened while not processing events {:?}",
s
),
}
}
}
// requires main thread and window is a UIWindow
// retains window
pub(crate) unsafe fn set_key_window(window: &Id<WinitUIWindow, Shared>) {
let mut this = AppState::get_mut();
match this.state_mut() {
&mut AppStateImpl::NotLaunched {
ref mut queued_windows,
..
} => return queued_windows.push(window.clone()),
&mut AppStateImpl::ProcessingEvents { .. }
| &mut AppStateImpl::InUserCallback { .. }
| &mut AppStateImpl::ProcessingRedraws { .. } => {}
s @ &mut AppStateImpl::Launching { .. }
| s @ &mut AppStateImpl::Waiting { .. }
| s @ &mut AppStateImpl::PollFinished { .. } => bug!("unexpected state {:?}", s),
&mut AppStateImpl::Terminated => {
panic!("Attempt to create a `Window` after the app has terminated")
}
}
drop(this);
window.makeKeyAndVisible();
}
// requires main thread and window is a UIWindow
// retains window
pub(crate) unsafe fn queue_gl_or_metal_redraw(window: Id<WinitUIWindow, Shared>) {
let mut this = AppState::get_mut();
match this.state_mut() {
&mut AppStateImpl::NotLaunched {
ref mut queued_gpu_redraws,
..
}
| &mut AppStateImpl::Launching {
ref mut queued_gpu_redraws,
..
}
| &mut AppStateImpl::ProcessingEvents {
ref mut queued_gpu_redraws,
..
}
| &mut AppStateImpl::InUserCallback {
ref mut queued_gpu_redraws,
..
} => {
let _ = queued_gpu_redraws.insert(window);
}
s @ &mut AppStateImpl::ProcessingRedraws { .. }
| s @ &mut AppStateImpl::Waiting { .. }
| s @ &mut AppStateImpl::PollFinished { .. } => bug!("unexpected state {:?}", s),
&mut AppStateImpl::Terminated => {
panic!("Attempt to create a `Window` after the app has terminated")
}
}
}
// requires main thread
pub unsafe fn will_launch(queued_event_handler: Box<dyn EventHandler>) {
AppState::get_mut().will_launch_transition(queued_event_handler)
}
// requires main thread
pub unsafe fn did_finish_launching() {
let mut this = AppState::get_mut();
let windows = match this.state_mut() {
AppStateImpl::Launching { queued_windows, .. } => mem::take(queued_windows),
s => bug!("unexpected state {:?}", s),
};
// start waking up the event loop now!
bug_assert!(
this.control_flow == ControlFlow::Poll,
"unexpectedly not setup to `Poll` on launch!"
);
this.waker.start();
// have to drop RefMut because the window setup code below can trigger new events
drop(this);
for window in windows {
// Do a little screen dance here to account for windows being created before
// `UIApplicationMain` is called. This fixes visual issues such as being
// offcenter and sized incorrectly. Additionally, to fix orientation issues, we
// gotta reset the `rootViewController`.
//
// relevant iOS log:
// ```
// [ApplicationLifecycle] Windows were created before application initialzation
// completed. This may result in incorrect visual appearance.
// ```
let screen = window.screen();
let _: () = msg_send![&window, setScreen: ptr::null::<Object>()];
window.setScreen(&screen);
let controller = window.rootViewController();
window.setRootViewController(None);
window.setRootViewController(controller.as_deref());
window.makeKeyAndVisible();
}
let (windows, events) = AppState::get_mut().did_finish_launching_transition();
let events = std::iter::once(EventWrapper::StaticEvent(Event::NewEvents(
StartCause::Init,
)))
.chain(events);
handle_nonuser_events(events);
// the above window dance hack, could possibly trigger new windows to be created.
// we can just set those windows up normally, as they were created after didFinishLaunching
for window in windows {
window.makeKeyAndVisible();
}
}
// requires main thread
// AppState::did_finish_launching handles the special transition `Init`
pub unsafe fn handle_wakeup_transition() {
let mut this = AppState::get_mut();
let wakeup_event = match this.wakeup_transition() {
None => return,
Some(wakeup_event) => wakeup_event,
};
drop(this);
handle_nonuser_event(wakeup_event)
}
// requires main thread
pub(crate) unsafe fn handle_nonuser_event(event: EventWrapper) {
handle_nonuser_events(std::iter::once(event))
}
// requires main thread
pub(crate) unsafe fn handle_nonuser_events<I: IntoIterator<Item = EventWrapper>>(events: I) {
let mut this = AppState::get_mut();
let (mut event_handler, active_control_flow, processing_redraws) =
match this.try_user_callback_transition() {
UserCallbackTransitionResult::ReentrancyPrevented { queued_events } => {
queued_events.extend(events);
return;
}
UserCallbackTransitionResult::Success {
event_handler,
active_control_flow,
processing_redraws,
} => (event_handler, active_control_flow, processing_redraws),
};
let mut control_flow = this.control_flow;
drop(this);
for wrapper in events {
match wrapper {
EventWrapper::StaticEvent(event) => {
if !processing_redraws && event.is_redraw() {
log::info!("processing `RedrawRequested` during the main event loop");
} else if processing_redraws && !event.is_redraw() {
log::warn!(
"processing non `RedrawRequested` event after the main event loop: {:#?}",
event
);
}
event_handler.handle_nonuser_event(event, &mut control_flow)
}
EventWrapper::EventProxy(proxy) => {
handle_event_proxy(&mut event_handler, control_flow, proxy)
}
}
}
loop {
let mut this = AppState::get_mut();
let queued_events = match this.state_mut() {
&mut AppStateImpl::InUserCallback {
ref mut queued_events,
queued_gpu_redraws: _,
} => mem::take(queued_events),
s => bug!("unexpected state {:?}", s),
};
if queued_events.is_empty() {
let queued_gpu_redraws = match this.take_state() {
AppStateImpl::InUserCallback {
queued_events: _,
queued_gpu_redraws,
} => queued_gpu_redraws,
_ => unreachable!(),
};
this.app_state = Some(if processing_redraws {
bug_assert!(
queued_gpu_redraws.is_empty(),
"redraw queued while processing redraws"
);
AppStateImpl::ProcessingRedraws {
event_handler,
active_control_flow,
}
} else {
AppStateImpl::ProcessingEvents {
event_handler,
queued_gpu_redraws,
active_control_flow,
}
});
this.control_flow = control_flow;
break;
}
drop(this);
for wrapper in queued_events {
match wrapper {
EventWrapper::StaticEvent(event) => {
if !processing_redraws && event.is_redraw() {
log::info!("processing `RedrawRequested` during the main event loop");
} else if processing_redraws && !event.is_redraw() {
log::warn!(
"processing non-`RedrawRequested` event after the main event loop: {:#?}",
event
);
}
event_handler.handle_nonuser_event(event, &mut control_flow)
}
EventWrapper::EventProxy(proxy) => {
handle_event_proxy(&mut event_handler, control_flow, proxy)
}
}
}
}
}
// requires main thread
unsafe fn handle_user_events() {
let mut this = AppState::get_mut();
let mut control_flow = this.control_flow;
let (mut event_handler, active_control_flow, processing_redraws) =
match this.try_user_callback_transition() {
UserCallbackTransitionResult::ReentrancyPrevented { .. } => {
bug!("unexpected attempted to process an event")
}
UserCallbackTransitionResult::Success {
event_handler,
active_control_flow,
processing_redraws,
} => (event_handler, active_control_flow, processing_redraws),
};
if processing_redraws {
bug!("user events attempted to be sent out while `ProcessingRedraws`");
}
drop(this);
event_handler.handle_user_events(&mut control_flow);
loop {
let mut this = AppState::get_mut();
let queued_events = match this.state_mut() {
&mut AppStateImpl::InUserCallback {
ref mut queued_events,
queued_gpu_redraws: _,
} => mem::take(queued_events),
s => bug!("unexpected state {:?}", s),
};
if queued_events.is_empty() {
let queued_gpu_redraws = match this.take_state() {
AppStateImpl::InUserCallback {
queued_events: _,
queued_gpu_redraws,
} => queued_gpu_redraws,
_ => unreachable!(),
};
this.app_state = Some(AppStateImpl::ProcessingEvents {
event_handler,
queued_gpu_redraws,
active_control_flow,
});
this.control_flow = control_flow;
break;
}
drop(this);
for wrapper in queued_events {
match wrapper {
EventWrapper::StaticEvent(event) => {
event_handler.handle_nonuser_event(event, &mut control_flow)
}
EventWrapper::EventProxy(proxy) => {
handle_event_proxy(&mut event_handler, control_flow, proxy)
}
}
}
event_handler.handle_user_events(&mut control_flow);
}
}
// requires main thread
pub unsafe fn handle_main_events_cleared() {
let mut this = AppState::get_mut();
if !this.has_launched() {
return;
}
match this.state_mut() {
AppStateImpl::ProcessingEvents { .. } => {}
_ => bug!("`ProcessingRedraws` happened unexpectedly"),
};
drop(this);
// User events are always sent out at the end of the "MainEventLoop"
handle_user_events();
handle_nonuser_event(EventWrapper::StaticEvent(Event::MainEventsCleared));
let mut this = AppState::get_mut();
let mut redraw_events: Vec<EventWrapper> = this
.main_events_cleared_transition()
.into_iter()
.map(|window| EventWrapper::StaticEvent(Event::RedrawRequested(RootWindowId(window.id()))))
.collect();
redraw_events.push(EventWrapper::StaticEvent(Event::RedrawEventsCleared));
drop(this);
handle_nonuser_events(redraw_events);
}
// requires main thread
pub unsafe fn handle_events_cleared() {
AppState::get_mut().events_cleared_transition();
}
// requires main thread
pub unsafe fn terminated() {
let mut this = AppState::get_mut();
let mut event_handler = this.terminated_transition();
let mut control_flow = this.control_flow;
drop(this);
event_handler.handle_nonuser_event(Event::LoopDestroyed, &mut control_flow)
}
fn handle_event_proxy(
event_handler: &mut Box<dyn EventHandler>,
control_flow: ControlFlow,
proxy: EventProxy,
) {
match proxy {
EventProxy::DpiChangedProxy {
suggested_size,
scale_factor,
window,
} => handle_hidpi_proxy(
event_handler,
control_flow,
suggested_size,
scale_factor,
window,
),
}
}
fn handle_hidpi_proxy(
event_handler: &mut Box<dyn EventHandler>,
mut control_flow: ControlFlow,
suggested_size: LogicalSize<f64>,
scale_factor: f64,
window: Id<WinitUIWindow, Shared>,
) {
let mut size = suggested_size.to_physical(scale_factor);
let new_inner_size = &mut size;
let event = Event::WindowEvent {
window_id: RootWindowId(window.id()),
event: WindowEvent::ScaleFactorChanged {
scale_factor,
new_inner_size,
},
};
event_handler.handle_nonuser_event(event, &mut control_flow);
let (view, screen_frame) = get_view_and_screen_frame(&window);
let physical_size = *new_inner_size;
let logical_size = physical_size.to_logical(scale_factor);
let size = CGSize::new(logical_size.width, logical_size.height);
let new_frame: CGRect = CGRect::new(screen_frame.origin, size);
view.setFrame(new_frame);
}
fn get_view_and_screen_frame(window: &WinitUIWindow) -> (Id<UIView, Shared>, CGRect) {
let view_controller = window.rootViewController().unwrap();
let view = view_controller.view().unwrap();
let bounds = window.bounds();
let screen = window.screen();
let screen_space = screen.coordinateSpace();
let screen_frame = window.convertRect_toCoordinateSpace(bounds, &screen_space);
(view, screen_frame)
}
struct EventLoopWaker {
timer: CFRunLoopTimerRef,
}
impl Drop for EventLoopWaker {
fn drop(&mut self) {
unsafe {
CFRunLoopTimerInvalidate(self.timer);
CFRelease(self.timer as _);
}
}
}
impl EventLoopWaker {
fn new(rl: CFRunLoopRef) -> EventLoopWaker {
extern "C" fn wakeup_main_loop(_timer: CFRunLoopTimerRef, _info: *mut c_void) {}
unsafe {
// Create a timer with a 0.1µs interval (1ns does not work) to mimic polling.
// It is initially setup with a first fire time really far into the
// future, but that gets changed to fire immediately in did_finish_launching
let timer = CFRunLoopTimerCreate(
ptr::null_mut(),
std::f64::MAX,
0.000_000_1,
0,
0,
wakeup_main_loop,
ptr::null_mut(),
);
CFRunLoopAddTimer(rl, timer, kCFRunLoopCommonModes);
EventLoopWaker { timer }
}
}
fn stop(&mut self) {
unsafe { CFRunLoopTimerSetNextFireDate(self.timer, std::f64::MAX) }
}
fn start(&mut self) {
unsafe { CFRunLoopTimerSetNextFireDate(self.timer, std::f64::MIN) }
}
fn start_at(&mut self, instant: Instant) {
let now = Instant::now();
if now >= instant {
self.start();
} else {
unsafe {
let current = CFAbsoluteTimeGetCurrent();
let duration = instant - now;
let fsecs =
duration.subsec_nanos() as f64 / 1_000_000_000.0 + duration.as_secs() as f64;
CFRunLoopTimerSetNextFireDate(self.timer, current + fsecs)
}
}
}
}
macro_rules! os_capabilities {
(
$(
$(#[$attr:meta])*
$error_name:ident: $objc_call:literal,
$name:ident: $major:literal-$minor:literal
),*
$(,)*
) => {
#[derive(Clone, Debug)]
pub struct OSCapabilities {
$(
pub $name: bool,
)*
os_version: NSOperatingSystemVersion,
}
impl From<NSOperatingSystemVersion> for OSCapabilities {
fn from(os_version: NSOperatingSystemVersion) -> OSCapabilities {
$(let $name = os_version.meets_requirements($major, $minor);)*
OSCapabilities { $($name,)* os_version, }
}
}
impl OSCapabilities {$(
$(#[$attr])*
pub fn $error_name(&self, extra_msg: &str) {
log::warn!(
concat!("`", $objc_call, "` requires iOS {}.{}+. This device is running iOS {}.{}.{}. {}"),
$major, $minor, self.os_version.major, self.os_version.minor, self.os_version.patch,
extra_msg
)
}
)*}
};
}
os_capabilities! {
/// <https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc>
#[allow(unused)] // error message unused
safe_area_err_msg: "-[UIView safeAreaInsets]",
safe_area: 11-0,
/// <https://developer.apple.com/documentation/uikit/uiviewcontroller/2887509-setneedsupdateofhomeindicatoraut?language=objc>
home_indicator_hidden_err_msg: "-[UIViewController setNeedsUpdateOfHomeIndicatorAutoHidden]",
home_indicator_hidden: 11-0,
/// <https://developer.apple.com/documentation/uikit/uiviewcontroller/2887507-setneedsupdateofscreenedgesdefer?language=objc>
defer_system_gestures_err_msg: "-[UIViewController setNeedsUpdateOfScreenEdgesDeferringSystem]",
defer_system_gestures: 11-0,
/// <https://developer.apple.com/documentation/uikit/uiscreen/2806814-maximumframespersecond?language=objc>
maximum_frames_per_second_err_msg: "-[UIScreen maximumFramesPerSecond]",
maximum_frames_per_second: 10-3,
/// <https://developer.apple.com/documentation/uikit/uitouch/1618110-force?language=objc>
#[allow(unused)] // error message unused
force_touch_err_msg: "-[UITouch force]",
force_touch: 9-0,
}
impl NSOperatingSystemVersion {
fn meets_requirements(&self, required_major: NSInteger, required_minor: NSInteger) -> bool {
(self.major, self.minor) >= (required_major, required_minor)
}
}
pub fn os_capabilities() -> OSCapabilities {
static OS_CAPABILITIES: Lazy<OSCapabilities> = Lazy::new(|| {
let version: NSOperatingSystemVersion = unsafe {
let process_info = NSProcessInfo::process_info();
let atleast_ios_8: bool = msg_send![
&process_info,
respondsToSelector: sel!(operatingSystemVersion)
];
// winit requires atleast iOS 8 because no one has put the time into supporting earlier os versions.
// Older iOS versions are increasingly difficult to test. For example, Xcode 11 does not support
// debugging on devices with an iOS version of less than 8. Another example, in order to use an iOS
// simulator older than iOS 8, you must download an older version of Xcode (<9), and at least Xcode 7
// has been tested to not even run on macOS 10.15 - Xcode 8 might?
//
// The minimum required iOS version is likely to grow in the future.
assert!(atleast_ios_8, "`winit` requires iOS version 8 or greater");
msg_send![&process_info, operatingSystemVersion]
};
version.into()
});
OS_CAPABILITIES.clone()
}

View File

@@ -1,353 +0,0 @@
use std::{
collections::VecDeque,
ffi::c_void,
fmt::{self, Debug},
marker::PhantomData,
ptr,
sync::mpsc::{self, Receiver, Sender},
};
use core_foundation::base::{CFIndex, CFRelease};
use core_foundation::runloop::{
kCFRunLoopAfterWaiting, kCFRunLoopBeforeWaiting, kCFRunLoopCommonModes, kCFRunLoopDefaultMode,
kCFRunLoopExit, CFRunLoopActivity, CFRunLoopAddObserver, CFRunLoopAddSource, CFRunLoopGetMain,
CFRunLoopObserverCreate, CFRunLoopObserverRef, CFRunLoopSourceContext, CFRunLoopSourceCreate,
CFRunLoopSourceInvalidate, CFRunLoopSourceRef, CFRunLoopSourceSignal, CFRunLoopWakeUp,
};
use objc2::foundation::{MainThreadMarker, NSString};
use objc2::rc::{Id, Shared};
use objc2::ClassType;
use raw_window_handle::{RawDisplayHandle, UiKitDisplayHandle};
use super::uikit::{UIApplication, UIApplicationMain, UIDevice, UIScreen};
use super::view::WinitUIWindow;
use super::{app_state, monitor, view, MonitorHandle};
use crate::{
dpi::LogicalSize,
event::Event,
event_loop::{
ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootEventLoopWindowTarget,
},
platform::ios::Idiom,
};
#[derive(Debug)]
pub(crate) enum EventWrapper {
StaticEvent(Event<'static, Never>),
EventProxy(EventProxy),
}
#[derive(Debug, PartialEq)]
pub(crate) enum EventProxy {
DpiChangedProxy {
window: Id<WinitUIWindow, Shared>,
suggested_size: LogicalSize<f64>,
scale_factor: f64,
},
}
pub struct EventLoopWindowTarget<T: 'static> {
receiver: Receiver<T>,
sender_to_clone: Sender<T>,
}
impl<T: 'static> EventLoopWindowTarget<T> {
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
monitor::uiscreens(MainThreadMarker::new().unwrap())
}
pub fn primary_monitor(&self) -> Option<MonitorHandle> {
Some(MonitorHandle::new(UIScreen::main(
MainThreadMarker::new().unwrap(),
)))
}
pub fn raw_display_handle(&self) -> RawDisplayHandle {
RawDisplayHandle::UiKit(UiKitDisplayHandle::empty())
}
}
pub struct EventLoop<T: 'static> {
window_target: RootEventLoopWindowTarget<T>,
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub(crate) struct PlatformSpecificEventLoopAttributes {}
impl<T: 'static> EventLoop<T> {
pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> EventLoop<T> {
assert_main_thread!("`EventLoop` can only be created on the main thread on iOS");
static mut SINGLETON_INIT: bool = false;
unsafe {
assert!(
!SINGLETON_INIT,
"Only one `EventLoop` is supported on iOS. \
`EventLoopProxy` might be helpful"
);
SINGLETON_INIT = true;
}
let (sender_to_clone, receiver) = mpsc::channel();
// this line sets up the main run loop before `UIApplicationMain`
setup_control_flow_observers();
EventLoop {
window_target: RootEventLoopWindowTarget {
p: EventLoopWindowTarget {
receiver,
sender_to_clone,
},
_marker: PhantomData,
},
}
}
pub fn run<F>(self, event_handler: F) -> !
where
F: 'static + FnMut(Event<'_, T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
{
unsafe {
let application = UIApplication::shared(MainThreadMarker::new().unwrap());
assert!(
application.is_none(),
"\
`EventLoop` cannot be `run` after a call to `UIApplicationMain` on iOS\n\
Note: `EventLoop::run` calls `UIApplicationMain` on iOS",
);
app_state::will_launch(Box::new(EventLoopHandler {
f: event_handler,
event_loop: self.window_target,
}));
// Ensure application delegate is initialized
view::WinitApplicationDelegate::class();
UIApplicationMain(
0,
ptr::null(),
None,
Some(&NSString::from_str("WinitApplicationDelegate")),
);
unreachable!()
}
}
pub fn create_proxy(&self) -> EventLoopProxy<T> {
EventLoopProxy::new(self.window_target.p.sender_to_clone.clone())
}
pub fn window_target(&self) -> &RootEventLoopWindowTarget<T> {
&self.window_target
}
}
// EventLoopExtIOS
impl<T: 'static> EventLoop<T> {
pub fn idiom(&self) -> Idiom {
UIDevice::current(MainThreadMarker::new().unwrap())
.userInterfaceIdiom()
.into()
}
}
pub struct EventLoopProxy<T> {
sender: Sender<T>,
source: CFRunLoopSourceRef,
}
unsafe impl<T: Send> Send for EventLoopProxy<T> {}
impl<T> Clone for EventLoopProxy<T> {
fn clone(&self) -> EventLoopProxy<T> {
EventLoopProxy::new(self.sender.clone())
}
}
impl<T> Drop for EventLoopProxy<T> {
fn drop(&mut self) {
unsafe {
CFRunLoopSourceInvalidate(self.source);
CFRelease(self.source as _);
}
}
}
impl<T> EventLoopProxy<T> {
fn new(sender: Sender<T>) -> EventLoopProxy<T> {
unsafe {
// just wake up the eventloop
extern "C" fn event_loop_proxy_handler(_: *const c_void) {}
// adding a Source to the main CFRunLoop lets us wake it up and
// process user events through the normal OS EventLoop mechanisms.
let rl = CFRunLoopGetMain();
let mut context = CFRunLoopSourceContext {
version: 0,
info: ptr::null_mut(),
retain: None,
release: None,
copyDescription: None,
equal: None,
hash: None,
schedule: None,
cancel: None,
perform: event_loop_proxy_handler,
};
let source =
CFRunLoopSourceCreate(ptr::null_mut(), CFIndex::max_value() - 1, &mut context);
CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes);
CFRunLoopWakeUp(rl);
EventLoopProxy { sender, source }
}
}
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
self.sender
.send(event)
.map_err(|::std::sync::mpsc::SendError(x)| EventLoopClosed(x))?;
unsafe {
// let the main thread know there's a new event
CFRunLoopSourceSignal(self.source);
let rl = CFRunLoopGetMain();
CFRunLoopWakeUp(rl);
}
Ok(())
}
}
fn setup_control_flow_observers() {
unsafe {
// begin is queued with the highest priority to ensure it is processed before other observers
extern "C" fn control_flow_begin_handler(
_: CFRunLoopObserverRef,
activity: CFRunLoopActivity,
_: *mut c_void,
) {
unsafe {
#[allow(non_upper_case_globals)]
match activity {
kCFRunLoopAfterWaiting => app_state::handle_wakeup_transition(),
_ => unreachable!(),
}
}
}
// Core Animation registers its `CFRunLoopObserver` that performs drawing operations in
// `CA::Transaction::ensure_implicit` with a priority of `0x1e8480`. We set the main_end
// priority to be 0, in order to send MainEventsCleared before RedrawRequested. This value was
// chosen conservatively to guard against apple using different priorities for their redraw
// observers in different OS's or on different devices. If it so happens that it's too
// conservative, the main symptom would be non-redraw events coming in after `MainEventsCleared`.
//
// The value of `0x1e8480` was determined by inspecting stack traces and the associated
// registers for every `CFRunLoopAddObserver` call on an iPad Air 2 running iOS 11.4.
//
// Also tested to be `0x1e8480` on iPhone 8, iOS 13 beta 4.
extern "C" fn control_flow_main_end_handler(
_: CFRunLoopObserverRef,
activity: CFRunLoopActivity,
_: *mut c_void,
) {
unsafe {
#[allow(non_upper_case_globals)]
match activity {
kCFRunLoopBeforeWaiting => app_state::handle_main_events_cleared(),
kCFRunLoopExit => unimplemented!(), // not expected to ever happen
_ => unreachable!(),
}
}
}
// end is queued with the lowest priority to ensure it is processed after other observers
extern "C" fn control_flow_end_handler(
_: CFRunLoopObserverRef,
activity: CFRunLoopActivity,
_: *mut c_void,
) {
unsafe {
#[allow(non_upper_case_globals)]
match activity {
kCFRunLoopBeforeWaiting => app_state::handle_events_cleared(),
kCFRunLoopExit => unimplemented!(), // not expected to ever happen
_ => unreachable!(),
}
}
}
let main_loop = CFRunLoopGetMain();
let begin_observer = CFRunLoopObserverCreate(
ptr::null_mut(),
kCFRunLoopAfterWaiting,
1, // repeat = true
CFIndex::min_value(),
control_flow_begin_handler,
ptr::null_mut(),
);
CFRunLoopAddObserver(main_loop, begin_observer, kCFRunLoopDefaultMode);
let main_end_observer = CFRunLoopObserverCreate(
ptr::null_mut(),
kCFRunLoopExit | kCFRunLoopBeforeWaiting,
1, // repeat = true
0, // see comment on `control_flow_main_end_handler`
control_flow_main_end_handler,
ptr::null_mut(),
);
CFRunLoopAddObserver(main_loop, main_end_observer, kCFRunLoopDefaultMode);
let end_observer = CFRunLoopObserverCreate(
ptr::null_mut(),
kCFRunLoopExit | kCFRunLoopBeforeWaiting,
1, // repeat = true
CFIndex::max_value(),
control_flow_end_handler,
ptr::null_mut(),
);
CFRunLoopAddObserver(main_loop, end_observer, kCFRunLoopDefaultMode);
}
}
#[derive(Debug)]
pub enum Never {}
pub trait EventHandler: Debug {
fn handle_nonuser_event(&mut self, event: Event<'_, Never>, control_flow: &mut ControlFlow);
fn handle_user_events(&mut self, control_flow: &mut ControlFlow);
}
struct EventLoopHandler<F, T: 'static> {
f: F,
event_loop: RootEventLoopWindowTarget<T>,
}
impl<F, T: 'static> Debug for EventLoopHandler<F, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EventLoopHandler")
.field("event_loop", &self.event_loop)
.finish()
}
}
impl<F, T> EventHandler for EventLoopHandler<F, T>
where
F: 'static + FnMut(Event<'_, T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
T: 'static,
{
fn handle_nonuser_event(&mut self, event: Event<'_, Never>, control_flow: &mut ControlFlow) {
(self.f)(
event.map_nonuser_event().unwrap(),
&self.event_loop,
control_flow,
);
}
fn handle_user_events(&mut self, control_flow: &mut ControlFlow) {
for event in self.event_loop.p.receiver.try_iter() {
(self.f)(Event::UserEvent(event), &self.event_loop, control_flow);
}
}
}

View File

@@ -1,93 +0,0 @@
#![allow(non_camel_case_types, non_snake_case, non_upper_case_globals)]
use std::convert::TryInto;
use objc2::encode::{Encode, Encoding};
use objc2::foundation::{NSInteger, NSUInteger};
use crate::platform::ios::{Idiom, ScreenEdge};
#[repr(C)]
#[derive(Clone, Debug)]
pub struct NSOperatingSystemVersion {
pub major: NSInteger,
pub minor: NSInteger,
pub patch: NSInteger,
}
unsafe impl Encode for NSOperatingSystemVersion {
const ENCODING: Encoding = Encoding::Struct(
"NSOperatingSystemVersion",
&[
NSInteger::ENCODING,
NSInteger::ENCODING,
NSInteger::ENCODING,
],
);
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct UIUserInterfaceIdiom(NSInteger);
unsafe impl Encode for UIUserInterfaceIdiom {
const ENCODING: Encoding = NSInteger::ENCODING;
}
impl UIUserInterfaceIdiom {
pub const Unspecified: UIUserInterfaceIdiom = UIUserInterfaceIdiom(-1);
pub const Phone: UIUserInterfaceIdiom = UIUserInterfaceIdiom(0);
pub const Pad: UIUserInterfaceIdiom = UIUserInterfaceIdiom(1);
pub const TV: UIUserInterfaceIdiom = UIUserInterfaceIdiom(2);
pub const CarPlay: UIUserInterfaceIdiom = UIUserInterfaceIdiom(3);
}
impl From<Idiom> for UIUserInterfaceIdiom {
fn from(idiom: Idiom) -> UIUserInterfaceIdiom {
match idiom {
Idiom::Unspecified => UIUserInterfaceIdiom::Unspecified,
Idiom::Phone => UIUserInterfaceIdiom::Phone,
Idiom::Pad => UIUserInterfaceIdiom::Pad,
Idiom::TV => UIUserInterfaceIdiom::TV,
Idiom::CarPlay => UIUserInterfaceIdiom::CarPlay,
}
}
}
impl From<UIUserInterfaceIdiom> for Idiom {
fn from(ui_idiom: UIUserInterfaceIdiom) -> Idiom {
match ui_idiom {
UIUserInterfaceIdiom::Unspecified => Idiom::Unspecified,
UIUserInterfaceIdiom::Phone => Idiom::Phone,
UIUserInterfaceIdiom::Pad => Idiom::Pad,
UIUserInterfaceIdiom::TV => Idiom::TV,
UIUserInterfaceIdiom::CarPlay => Idiom::CarPlay,
_ => unreachable!(),
}
}
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct UIRectEdge(NSUInteger);
unsafe impl Encode for UIRectEdge {
const ENCODING: Encoding = NSUInteger::ENCODING;
}
impl From<ScreenEdge> for UIRectEdge {
fn from(screen_edge: ScreenEdge) -> UIRectEdge {
assert_eq!(
screen_edge.bits() & !ScreenEdge::ALL.bits(),
0,
"invalid `ScreenEdge`"
);
UIRectEdge(screen_edge.bits().into())
}
}
impl From<UIRectEdge> for ScreenEdge {
fn from(ui_rect_edge: UIRectEdge) -> ScreenEdge {
let bits: u8 = ui_rect_edge.0.try_into().expect("invalid `UIRectEdge`");
ScreenEdge::from_bits(bits).expect("invalid `ScreenEdge`")
}
}

View File

@@ -1,117 +0,0 @@
//! iOS support
//!
//! # Building app
//! To build ios app you will need rustc built for this targets:
//!
//! - armv7-apple-ios
//! - armv7s-apple-ios
//! - i386-apple-ios
//! - aarch64-apple-ios
//! - x86_64-apple-ios
//!
//! Then
//!
//! ```
//! cargo build --target=...
//! ```
//! The simplest way to integrate your app into xcode environment is to build it
//! as a static library. Wrap your main function and export it.
//!
//! ```rust, ignore
//! #[no_mangle]
//! pub extern fn start_winit_app() {
//! start_inner()
//! }
//!
//! fn start_inner() {
//! ...
//! }
//! ```
//!
//! Compile project and then drag resulting .a into Xcode project. Add winit.h to xcode.
//!
//! ```ignore
//! void start_winit_app();
//! ```
//!
//! Use start_winit_app inside your xcode's main function.
//!
//!
//! # App lifecycle and events
//!
//! iOS environment is very different from other platforms and you must be very
//! careful with it's events. Familiarize yourself with
//! [app lifecycle](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/).
//!
//!
//! This is how those event are represented in winit:
//!
//! - applicationDidBecomeActive is Resumed
//! - applicationWillResignActive is Suspended
//! - applicationWillTerminate is LoopDestroyed
//!
//! Keep in mind that after LoopDestroyed event is received every attempt to draw with
//! opengl will result in segfault.
//!
//! Also note that app may not receive the LoopDestroyed event if suspended; it might be SIGKILL'ed.
#![cfg(ios_platform)]
#![allow(clippy::let_unit_value)]
// TODO: (mtak-) UIKit requires main thread for virtually all function/method calls. This could be
// worked around in the future by using GCD (grand central dispatch) and/or caching of values like
// window size/position.
macro_rules! assert_main_thread {
($($t:tt)*) => {
if !::objc2::foundation::is_main_thread() {
panic!($($t)*);
}
};
}
mod app_state;
mod event_loop;
mod ffi;
mod monitor;
mod uikit;
mod view;
mod window;
use std::fmt;
pub(crate) use self::{
event_loop::{
EventLoop, EventLoopProxy, EventLoopWindowTarget, PlatformSpecificEventLoopAttributes,
},
monitor::{MonitorHandle, VideoMode},
window::{PlatformSpecificWindowBuilderAttributes, Window, WindowId},
};
use self::uikit::UIScreen;
pub(crate) use crate::icon::NoIcon as PlatformIcon;
pub(self) use crate::platform_impl::Fullscreen;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeviceId {
uiscreen: *const UIScreen,
}
impl DeviceId {
pub const unsafe fn dummy() -> Self {
DeviceId {
uiscreen: std::ptr::null(),
}
}
}
unsafe impl Send for DeviceId {}
unsafe impl Sync for DeviceId {}
#[derive(Debug)]
pub enum OsError {}
impl fmt::Display for OsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "os error")
}
}

View File

@@ -1,246 +0,0 @@
#![allow(clippy::unnecessary_cast)]
use std::{
collections::{BTreeSet, VecDeque},
fmt,
ops::{Deref, DerefMut},
};
use objc2::foundation::{MainThreadMarker, NSInteger};
use objc2::rc::{Id, Shared};
use super::uikit::{UIScreen, UIScreenMode};
use crate::{
dpi::{PhysicalPosition, PhysicalSize},
monitor::VideoMode as RootVideoMode,
platform_impl::platform::app_state,
};
// TODO(madsmtm): Remove or refactor this
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub(crate) struct ScreenModeSendSync(pub(crate) Id<UIScreenMode, Shared>);
unsafe impl Send for ScreenModeSendSync {}
unsafe impl Sync for ScreenModeSendSync {}
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct VideoMode {
pub(crate) size: (u32, u32),
pub(crate) bit_depth: u16,
pub(crate) refresh_rate_millihertz: u32,
pub(crate) screen_mode: ScreenModeSendSync,
pub(crate) monitor: MonitorHandle,
}
impl VideoMode {
fn new(uiscreen: Id<UIScreen, Shared>, screen_mode: Id<UIScreenMode, Shared>) -> VideoMode {
assert_main_thread!("`VideoMode` can only be created on the main thread on iOS");
let refresh_rate_millihertz = refresh_rate_millihertz(&uiscreen);
let size = screen_mode.size();
VideoMode {
size: (size.width as u32, size.height as u32),
bit_depth: 32,
refresh_rate_millihertz,
screen_mode: ScreenModeSendSync(screen_mode),
monitor: MonitorHandle::new(uiscreen),
}
}
pub fn size(&self) -> PhysicalSize<u32> {
self.size.into()
}
pub fn bit_depth(&self) -> u16 {
self.bit_depth
}
pub fn refresh_rate_millihertz(&self) -> u32 {
self.refresh_rate_millihertz
}
pub fn monitor(&self) -> MonitorHandle {
self.monitor.clone()
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Inner {
uiscreen: Id<UIScreen, Shared>,
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct MonitorHandle {
inner: Inner,
}
impl PartialOrd for MonitorHandle {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for MonitorHandle {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
// TODO: Make a better ordering
(self as *const Self).cmp(&(other as *const Self))
}
}
impl Deref for MonitorHandle {
type Target = Inner;
fn deref(&self) -> &Inner {
assert_main_thread!("`MonitorHandle` methods can only be run on the main thread on iOS");
&self.inner
}
}
impl DerefMut for MonitorHandle {
fn deref_mut(&mut self) -> &mut Inner {
assert_main_thread!("`MonitorHandle` methods can only be run on the main thread on iOS");
&mut self.inner
}
}
unsafe impl Send for MonitorHandle {}
unsafe impl Sync for MonitorHandle {}
impl Drop for MonitorHandle {
fn drop(&mut self) {
assert_main_thread!("`MonitorHandle` can only be dropped on the main thread on iOS");
}
}
impl fmt::Debug for MonitorHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// TODO: Do this using the proper fmt API
#[derive(Debug)]
#[allow(dead_code)]
struct MonitorHandle {
name: Option<String>,
size: PhysicalSize<u32>,
position: PhysicalPosition<i32>,
scale_factor: f64,
}
let monitor_id_proxy = MonitorHandle {
name: self.name(),
size: self.size(),
position: self.position(),
scale_factor: self.scale_factor(),
};
monitor_id_proxy.fmt(f)
}
}
impl MonitorHandle {
pub(crate) fn new(uiscreen: Id<UIScreen, Shared>) -> Self {
assert_main_thread!("`MonitorHandle` can only be created on the main thread on iOS");
Self {
inner: Inner { uiscreen },
}
}
}
impl Inner {
pub fn name(&self) -> Option<String> {
let main = UIScreen::main(MainThreadMarker::new().unwrap());
if self.uiscreen == main {
Some("Primary".to_string())
} else if self.uiscreen == main.mirroredScreen() {
Some("Mirrored".to_string())
} else {
UIScreen::screens(MainThreadMarker::new().unwrap())
.iter()
.position(|rhs| rhs == &*self.uiscreen)
.map(|idx| idx.to_string())
}
}
pub fn size(&self) -> PhysicalSize<u32> {
let bounds = self.uiscreen.nativeBounds();
PhysicalSize::new(bounds.size.width as u32, bounds.size.height as u32)
}
pub fn position(&self) -> PhysicalPosition<i32> {
let bounds = self.uiscreen.nativeBounds();
(bounds.origin.x as f64, bounds.origin.y as f64).into()
}
pub fn scale_factor(&self) -> f64 {
self.uiscreen.nativeScale() as f64
}
pub fn refresh_rate_millihertz(&self) -> Option<u32> {
Some(refresh_rate_millihertz(&self.uiscreen))
}
pub fn video_modes(&self) -> impl Iterator<Item = VideoMode> {
// Use Ord impl of RootVideoMode
let modes: BTreeSet<_> = self
.uiscreen
.availableModes()
.into_iter()
.map(|mode| {
let mode: *const UIScreenMode = mode;
let mode = unsafe { Id::retain(mode as *mut UIScreenMode).unwrap() };
RootVideoMode {
video_mode: VideoMode::new(self.uiscreen.clone(), mode),
}
})
.collect();
modes.into_iter().map(|mode| mode.video_mode)
}
}
fn refresh_rate_millihertz(uiscreen: &UIScreen) -> u32 {
let refresh_rate_millihertz: NSInteger = {
let os_capabilities = app_state::os_capabilities();
if os_capabilities.maximum_frames_per_second {
uiscreen.maximumFramesPerSecond()
} else {
// https://developer.apple.com/library/archive/technotes/tn2460/_index.html
// https://en.wikipedia.org/wiki/IPad_Pro#Model_comparison
//
// All iOS devices support 60 fps, and on devices where `maximumFramesPerSecond` is not
// supported, they are all guaranteed to have 60hz refresh rates. This does not
// correctly handle external displays. ProMotion displays support 120fps, but they were
// introduced at the same time as the `maximumFramesPerSecond` API.
//
// FIXME: earlier OSs could calculate the refresh rate using
// `-[CADisplayLink duration]`.
os_capabilities.maximum_frames_per_second_err_msg("defaulting to 60 fps");
60
}
};
refresh_rate_millihertz as u32 * 1000
}
// MonitorHandleExtIOS
impl Inner {
pub(crate) fn ui_screen(&self) -> &Id<UIScreen, Shared> {
&self.uiscreen
}
pub fn preferred_video_mode(&self) -> VideoMode {
VideoMode::new(
self.uiscreen.clone(),
self.uiscreen.preferredMode().unwrap(),
)
}
}
pub fn uiscreens(mtm: MainThreadMarker) -> VecDeque<MonitorHandle> {
UIScreen::screens(mtm)
.into_iter()
.map(|screen| {
let screen: *const UIScreen = screen;
let screen = unsafe { Id::retain(screen as *mut UIScreen).unwrap() };
MonitorHandle::new(screen)
})
.collect()
}

View File

@@ -1,30 +0,0 @@
use objc2::foundation::{CGRect, MainThreadMarker, NSArray, NSObject};
use objc2::rc::{Id, Shared};
use objc2::{extern_class, extern_methods, msg_send_id, ClassType};
use super::{UIResponder, UIWindow};
extern_class!(
#[derive(Debug, PartialEq, Eq, Hash)]
pub(crate) struct UIApplication;
unsafe impl ClassType for UIApplication {
#[inherits(NSObject)]
type Super = UIResponder;
}
);
extern_methods!(
unsafe impl UIApplication {
pub fn shared(_mtm: MainThreadMarker) -> Option<Id<Self, Shared>> {
unsafe { msg_send_id![Self::class(), sharedApplication] }
}
pub fn windows(&self) -> Id<NSArray<UIWindow, Shared>, Shared> {
unsafe { msg_send_id![self, windows] }
}
#[sel(statusBarFrame)]
pub fn statusBarFrame(&self) -> CGRect;
}
);

View File

@@ -1,11 +0,0 @@
use objc2::foundation::NSObject;
use objc2::{extern_class, ClassType};
extern_class!(
#[derive(Debug, PartialEq, Eq, Hash)]
pub(crate) struct UICoordinateSpace;
unsafe impl ClassType for UICoordinateSpace {
type Super = NSObject;
}
);

View File

@@ -1,25 +0,0 @@
use objc2::foundation::{MainThreadMarker, NSObject};
use objc2::rc::{Id, Shared};
use objc2::{extern_class, extern_methods, msg_send_id, ClassType};
use super::super::ffi::UIUserInterfaceIdiom;
extern_class!(
#[derive(Debug, PartialEq, Eq, Hash)]
pub(crate) struct UIDevice;
unsafe impl ClassType for UIDevice {
type Super = NSObject;
}
);
extern_methods!(
unsafe impl UIDevice {
pub fn current(_mtm: MainThreadMarker) -> Id<Self, Shared> {
unsafe { msg_send_id![Self::class(), currentDevice] }
}
#[sel(userInterfaceIdiom)]
pub fn userInterfaceIdiom(&self) -> UIUserInterfaceIdiom;
}
);

View File

@@ -1,11 +0,0 @@
use objc2::foundation::NSObject;
use objc2::{extern_class, ClassType};
extern_class!(
#[derive(Debug, PartialEq, Eq, Hash)]
pub(crate) struct UIEvent;
unsafe impl ClassType for UIEvent {
type Super = NSObject;
}
);

View File

@@ -1,44 +0,0 @@
#![deny(unsafe_op_in_unsafe_fn)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
use std::os::raw::{c_char, c_int};
use objc2::foundation::NSString;
mod application;
mod coordinate_space;
mod device;
mod event;
mod responder;
mod screen;
mod screen_mode;
mod touch;
mod trait_collection;
mod view;
mod view_controller;
mod window;
pub(crate) use self::application::UIApplication;
pub(crate) use self::coordinate_space::UICoordinateSpace;
pub(crate) use self::device::UIDevice;
pub(crate) use self::event::UIEvent;
pub(crate) use self::responder::UIResponder;
pub(crate) use self::screen::{UIScreen, UIScreenOverscanCompensation};
pub(crate) use self::screen_mode::UIScreenMode;
pub(crate) use self::touch::{UITouch, UITouchPhase, UITouchType};
pub(crate) use self::trait_collection::{UIForceTouchCapability, UITraitCollection};
#[allow(unused_imports)]
pub(crate) use self::view::{UIEdgeInsets, UIView};
pub(crate) use self::view_controller::{UIInterfaceOrientationMask, UIViewController};
pub(crate) use self::window::UIWindow;
#[link(name = "UIKit", kind = "framework")]
extern "C" {
pub fn UIApplicationMain(
argc: c_int,
argv: *const c_char,
principalClassName: Option<&NSString>,
delegateClassName: Option<&NSString>,
) -> c_int;
}

View File

@@ -1,11 +0,0 @@
use objc2::foundation::NSObject;
use objc2::{extern_class, ClassType};
extern_class!(
#[derive(Debug, PartialEq, Eq, Hash)]
pub(crate) struct UIResponder;
unsafe impl ClassType for UIResponder {
type Super = NSObject;
}
);

Some files were not shown because too many files have changed in this diff Show More