Compare commits

...

864 Commits

Author SHA1 Message Date
Kirill Chibisov
c53a574bff Release 0.27.1 version 2022-07-30 19:33:23 +03:00
Kirill Chibisov
95246d81c1 On X11, fix crash when can't disable IME
Fixes #2402.
2022-07-30 17:15:57 +03:00
Kirill Chibisov
bf537009d9 Explicitly specify minimum supported rust version
This should help with distributing apps using winit.

Fixes #1075.
2022-07-29 14:39:41 +03:00
Kirill Chibisov
50035643f7 Release 0.27.0 version 2022-07-26 23:54:12 +03:00
Mads Marquart
64c22f9075 Fix changelog entry wrt scrolling
The breaking change was put into the wrong release section.
2022-07-26 22:25:00 +03:00
Marijn Suijten
4895a29e92 ci: manually point ANDROID_NDK_ROOT to latest supplied version
It seems the symlink to `ndk-bundle` and this environment variable
pointing to it have been removed to prevent the sdkmanager from failing,
when finding the SDK setup to be in an "indeterminate" state.  It is now
up to the users themselves to install an NDK through that tool or point
the right variables to a preinstalled "latest" NDK.

https://github.com/actions/virtual-environments/issues/2689
https://github.com/actions/virtual-environments/pull/5926
2022-07-26 19:55:06 +03:00
Robert Bragg
6cdb3179c8 Consistently deliver a Resumed event on all platforms
To be more consistent with mobile platforms this updates the Windows,
macOS, Wayland, X11 and Web backends to all emit a Resumed event
immediately after the initial `NewEvents(StartCause::Init)` event.

The documentation for Suspended and Resumed has also been updated
to provide general recommendations for how to handle Suspended and
Resumed events in portable applications as well as providing
Android and iOS specific details.

This consistency makes it possible to write applications that lazily
initialize their graphics state when the application resumes without
any platform-specific knowledge. Previously, applications that wanted
to run on Android and other systems would have to maintain two,
mutually-exclusive, initialization paths.

Note: This patch does nothing to guarantee that Suspended events will
be delivered. It's still reasonable to say that most OSs without a
formal lifecycle for applications will simply never "suspend" your
application. There are currently no known portability issues caused
by not delivering `Suspended` events consistently and technically
it's not possible to guarantee the delivery of `Suspended` events if
the OS doesn't define an application lifecycle. (app can always be
terminated without any kind of clean up notification on most
non-mobile OSs)

Fixes #2185.

Co-authored-by: Marijn Suijten <marijns95@gmail.com>
Co-authored-by: Markus Røyset <maroider@protonmail.com>
2022-07-26 16:03:12 +03:00
Kirill Chibisov
4fd52af682 Fix type hint reference for xlib hook 2022-07-26 16:02:09 +03:00
Marijn Suijten
5a0bad130d Bump ndk and ndk-glue dependencies to stable 0.7.0 release (#2392) 2022-07-25 15:20:31 +02:00
Amr Bashir
08d025968e Fix hiding a maximized window On Windows (#2336) 2022-07-23 14:23:58 +02:00
Amr Bashir
1cd0e94c26 Windows: apply skip taskbar state when taskbar is restarted (#2380) 2022-07-22 19:33:22 +02:00
Kirill Chibisov
1ec976f95e Add method to hook xlib error handler
This should help glutin to handle errors coming from GLX
and offer multithreading support in a safe way.

Fixes #2378.
2022-07-22 20:21:28 +03:00
Kirill Chibisov
f10ef5f331 On macOS, fix confirmed character inserted
When confirming input in e.g. Korean IME or using characters like
`+` winit was sending those twice, once via `Ime::Commit` and the
other one via `ReceivedCharacter`, since those events weren't generating
any `Ime::Preedit` and were forwarded due to `do_command_by_selector`.
2022-07-21 22:23:22 +03:00
Kirill Chibisov
653bc59813 Update raw-window-handle to v0.5.0
This updates raw-window-handle to v0.5.0.
2022-07-21 22:22:36 +03:00
Rodrigo Batista de Moraes
3e991e13dc Android: avoid deadlocks while handling UserEvent (#2343)
Replace `Arc<Mutex<VecDeque<T>>` by `mpsc`
2022-07-20 19:52:36 +02:00
Markus Røyset
5397b53e04 Tidy up "platform-specifc" doc sections (#2356)
* Tidy up "platform-specific" doc sections

* Unrelated grammatical fix

* Subjective improvements
2022-07-20 13:45:12 +02:00
Kirill Chibisov
f09259f6de Bump sctk-adwaita to 0.4.1
This should force the use of system libraries for Fontconfig
and freetype instead of building them with cmake if missing.

This also fixes compilation failures on nightly.

Fixes #2373.
2022-07-20 11:50:49 +03:00
Josh Groves
430a49ebc2 Fix typos (#2375) 2022-07-15 18:32:12 +02:00
Steve Wooster
1091a8ba1a Make winit focus take activity into account on Windows (#2159)
winit's notion of "focus" is very simple; you're either focused or not.
However, Windows has both notions of focused window and active window
and paying attention only to WM_SETFOCUS/WM_KILLFOCUS can cause a window
to believe the user is interacting with it when they're not. (this
manifests when a user switches to another application between when a
winit application starts and it creates its first window)
2022-07-15 10:27:27 +02:00
Josh Groves
9116b6c8cd windows: Use correct value for mouse wheel delta (#2374) 2022-07-14 22:00:22 +02:00
Josh Groves
990e34a129 web: add with_prevent_default, with_focusable (#2365)
* web: add `with_prevent_default`, `with_focusable`

`with_prevent_default` controls whether `event.preventDefault` is called

`with_focusable` controls whether `tabindex` is added

Fixes #1768

* Remove extra space from CHANGELOG
2022-07-14 17:52:31 +02:00
Marijn Suijten
472d7b9376 android: Hold NativeWindow lock until after notifying the user with Event::Suspended (#2307)
This applies https://github.com/rust-windowing/android-ndk-rs/issues/117
on the `winit` side: Android destroys its window/surface as soon as the
user returns from [`onNativeWindowDestroyed`], and we "fixed" this on
the `ndk-glue` side by sending the `WindowDestroyed` event before
locking the window and removing it: this lock has to wait for any user
of `ndk-glue` - ie. `winit` - to give up its readlock on the window,
which is what we utilize here to give users of `winit` "time" to destroy
any resource created on top of a `RawWindowHandle`.

since we can't pass the user a `RawWindowHandle` through the
`HasRawWindowHandle` trait we have to document this case explicitly and
keep the lock alive on the `winit` side instead.

[`onNativeWindowDestroyed`]: https://developer.android.com/ndk/reference/struct/a-native-activity-callbacks#onnativewindowdestroyed
2022-07-14 12:35:49 +02:00
Markus Røyset
50dd7881b1 Fix changelog entry for EventLoopExtWebSys (#2372) 2022-07-13 17:54:06 +02:00
Liam Murphy
aa8f8db305 web: Add EventLoop::spawn (#2208)
* web: Add `EventLoop::spawn`

This is the same as `EventLoop::run`, but doesn't throw an exception in order to return `!`.

I decided to name it `spawn` rather than `run_web` because I think that's more descriptive, but I'm happy to change it to `run_web`.

Resolves #1714

* Update src/platform/web.rs

Co-authored-by: Markus Røyset <maroider@protonmail.com>

* Fix outdated names

Co-authored-by: Markus Røyset <maroider@protonmail.com>
2022-07-13 17:17:18 +02:00
Lucas Kent
cdd9b1e1eb web: Manually emit focused event on mouse click (#2202)
* Manually emit focused event on mouse click

* Update CHANGELOG.md

Co-authored-by: Markus Røyset <maroider@protonmail.com>

Co-authored-by: Markus Røyset <maroider@protonmail.com>
2022-07-13 00:46:15 +02:00
Kirill Chibisov
2d2ce70edc On Wayland, drop wl_surface on window close 2022-07-09 21:41:18 +03:00
Kirill Chibisov
78f1d1df38 On Wayland send Focused(false) for new window
On Wayland winit will always get an explicit focused event from the
system and will transfer it downstream. So send focused false to enforce
it.
2022-07-09 18:17:41 +03:00
Kirill Chibisov
a06bb3f992 Add refresh_rate_millihertz for MonitorHandle
This also alters `VideoMode::refresh_rate` to
`VideoMode::refresh_rate_millihertz` which now returns monitor refresh rate in
mHz.
2022-07-08 13:25:56 +03:00
trimental
e289f30e5d Add 'WindowEvent::Occluded(bool)'
This commits and an event to track window occlusion state,
which could help optimize rendering downstream.
2022-07-06 21:46:25 +03:00
Shinichi Tanaka
4b10993970 Fix infinite recursion in WindowId conversion methods 2022-07-05 20:09:40 +03:00
Diggory Hardy
d78a870e66 examples/multiwindow.rs: ignore synthetic key press events 2022-07-03 22:25:08 +03:00
Kirill Chibisov
cb41c58f21 Implement From<u64> for WindowId and vise-versa
This should help downstream applications to expose WindowId to the end
users via e.g. IPC to control particular windows in multi window
systems.
2022-07-02 14:27:19 +03:00
Diggory Hardy
c55d97183d Less redundancy and improve fullscreen in examples
Remove examples/minimize which is redundant
2022-07-01 14:07:10 +03:00
Aaron Hill
8646cbc9f5 Map XK_Caps_Lock to VirtualKeyCode::Capital (#1864)
This allows applications to handle events for the caps lock key under X11
2022-06-23 17:59:04 +02:00
Amr Bashir
64c1d4c5bb Fix conflict in WindowFlags on Windows 2022-06-22 20:44:00 +03:00
MarcusGrass
76b949c196 Disallow multiple EventLoop creation 2022-06-22 20:43:25 +03:00
Kirill Chibisov
c93ef47b9b Bump smithay-client-toolkit to v0.16.0 2022-06-20 10:19:49 +03:00
Marijn Suijten
2b414cd825 ci: Disallow warnings in rustdoc and test private items (#2341)
Make sure `cargo doc` runs cleanly without any warnings in the CI - some
recently introduced but still allowing a PR to get merged.

In case someone wishes to add docs on private items, make sure those
adhere to the same standards.
2022-06-17 14:19:09 +02:00
Nazarí González
ac42447459 macOS: disallow_highdpi will set explicity the value to avoid the SO value by default (#2339)
Co-authored-by: Mads Marquart <mads@marquart.dk>
2022-06-17 01:12:05 +02:00
Markus Røyset
401d20fa1f Fix doubled device events on X11
Fixes #2332
2022-06-13 19:24:56 +03:00
Marijn Suijten
6b5b570b45 examples/window_run_return: Enable on Android (#2321)
Android also supports `EventLoopExtRunReturn`.  The user will still have
to follow the README to turn this example into a `cdylib` and add the
`ndk_glue::main()` initialization attribute, though.
2022-06-13 16:40:21 +02:00
Kirill Chibisov
9e6f666616 Refine Window::set_cursor_grab API
This commit renames `Window::set_cursor_grab` to
`Window::set_cursor_grab_mode`. The new API now accepts enumeration
to control the way cursor grab is performed. The value could be: `lock`,
`confine`, or `none`.

This commit also implements `Window::set_cursor_position` for Wayland,
since it's tied to locked cursor.

Implements API from #1677.
2022-06-13 09:43:14 +03:00
Kirill Chibisov
8ef9fe44c7 Add WindowBuilder::transparent
This is required to help hardware accelerated libraries like glutin
that accept WindowBuilder instead of RawWindowHandle, since the api
to access builder properties directly was removed.

Follow up to 44288f6.
2022-06-12 09:53:28 +03:00
Mads Marquart
3e0a544eb8 Documentation cleanup (#2328)
* Remove redundant documentation links

* Add note to README about windows not showing up on Wayland

* Fix documentation links

* Small documentation fixes

* Add note about doing stuff after StartCause::Init on macOS
2022-06-11 18:57:19 +02:00
Mads Marquart
6474891f1e Fix macOS 32bit (#2327) 2022-06-11 03:43:51 +02:00
Mads Marquart
40abb526cc Remove core-video-sys dependency (#2326)
Hasn't been updated in over 2 years - many open PRs, seems abandoned. Is the cause of several duplicate dependencies in our dependency tree!
2022-06-11 02:37:46 +02:00
Mads Marquart
c532d910c0 Build docs on docs.rs for iOS and Android as well (#2324) 2022-06-11 00:45:24 +02:00
Mads Marquart
44288f6280 Make WindowAttributes private (#2134)
* Make `WindowAttributes` private, and move its documentation

* Reorder WindowAttributes title and fullscreen to match method order
2022-06-10 19:05:28 +02:00
Kirill Chibisov
eec84ade86 Make set_device_event_filter non-mut
Commit f10a984 added `EventLoopWindowTarget::set_device_event_filter`
with for a mutable reference, however most winit APIs work with
immutable references, so altering API to play nicely with existing APIs.

This also disables device event filtering on debug example.
2022-06-10 15:39:02 +03:00
Kirill Chibisov
10419ff441 Run clippy on CI
Fixes #1402.
2022-06-10 13:43:33 +03:00
Marijn Suijten
57981b533d On Android, use HasRawWindowHandle directly from the ndk crate (#2318)
The `ndk` crate now implements [`HasRawWindowHandle` directly on
`NativeWindow`], relieving the burden to reimplement it on `winit`.

[`HasRawWindowHandle` directly on `NativeWindow`]: https://github.com/rust-windowing/android-ndk-rs/pull/274
2022-06-10 11:37:06 +02:00
tinaun
c5eaa0ab69 macOS: Emit LoopDestroyed on CMD+Q (#2073)
override applicationWillTerminate:

Co-authored-by: Mads Marquart <mads@marquart.dk>
2022-06-09 16:08:52 +02:00
James Liu
2c01e9e747 Migrate from lazy_static to once_cell 2022-06-08 21:50:26 +03:00
Kevin King
4c39b3188c Remove old dialog fix that is superseded by #2027 (#2292)
This fixes the run_return loop never returning on macos when using multiple windows
2022-06-08 17:22:54 +02:00
Kirill Chibisov
224872ce03 Prevent null dereference on X11 with bad locale 2022-06-08 01:04:33 +03:00
Christian Duerr
f10a984ba3 Add X11 opt-in function for device events
Previously on X11, by default all global events were broadcasted to
every winit application. This unnecessarily drains battery due to
excessive CPU usage when moving the mouse.

To resolve this, device events are now ignored by default and users must
manually opt into it using
`EventLoopWindowTarget::set_filter_device_events`.

Fixes (#1634) on Linux.
2022-06-08 00:17:45 +03:00
Lucas Kent
c7f7181388 Set WindowBuilder to must_use 2022-06-07 23:55:57 +03:00
Kirill Chibisov
92530299eb Revert "On Wayland, fix resize not propagating properly"
This reverts commit 78e5a395da.

It was discovered that in some cases mesa will lock the back
buffer, e.g. when making context current, leading to resize
missing. Given that applications can restructure their rendering
to account for that, and that winit isn't limited to playing
nice with mesa reverting the original commit.
2022-06-05 22:19:27 +03:00
Markus Siglreithmaier
58cd23d1ac On Windows, fix reported cursor position. (#2311)
When clicking and moving the cursor out of the window negative coordinates were not handled correctly.
2022-06-02 19:08:54 +02:00
Aron Parker
5d85c10a2c [Windows] Avoid GetModuleHandle(NULL) (#2301)
Use get_instance_handle() over GetModuleHandle(NULL)
2022-05-29 17:12:46 +02:00
Kevin Reid
f11270dac0 Reorganize EventLoopBuilder::build() platform documentation
Since there's a "Platform-specific" header, it makes sense to put the
Linux-specific part under it. On the other hand, "Can only be called on
the main thread." is true for all platforms, not just iOS, so there is
no reason to call it out for iOS specifically.
2022-05-29 14:51:27 +03:00
Phillip Hellewell
bcd76d4718 On macOS, emit resize event on frame_did_change
When the window switches mode from normal to tabbed one, it doesn't
get resized, however the frame gets resized. This commit makes
winit to track resizes when frame changes instead of window.

Fixes #2191.
2022-05-23 22:53:07 +03:00
Liam Murphy
4dd2b66aaa Fix warnings on nightly rust (#2295)
This was causing CI to fail: https://github.com/rust-windowing/winit/runs/6506026326
2022-05-20 17:03:35 +02:00
Bartłomiej Maryńczak
829a140d9b On Wayland, provide option for better CSD
While most compositors provide server side decorations, the GNOME
does not, and won't provide them. Also Wayland clients must render
client side decorations.

Winit was already drawing some decorations, however they were bad
looking and provided no text rendering, so the title was missing.
However this commit makes use of the SCTK external frame similar to
GTK's Adwaita theme supporting text rendering and looking similar to
other GTK applications.

Fixes #1967.
2022-05-20 03:09:23 +03:00
Kirill Chibisov
f04fa5d54f Add new Ime event for desktop platforms
This commit brings new Ime event to account for preedit state of input
method, also adding `Window::set_ime_allowed` to toggle IME input on
the particular window.

This commit implements API as designed in #1497 for desktop platforms.

Co-authored-by: Artur Kovacs <kovacs.artur.barnabas@gmail.com>
Co-authored-by: Markus Siglreithmaier <m.siglreith@gmail.com>
Co-authored-by: Murarth <murarth@gmail.com>
Co-authored-by: Yusuke Kominami <yukke.konan@gmail.com>
Co-authored-by: moko256 <koutaro.mo@gmail.com>
2022-05-07 05:29:25 +03:00
Markus Siglreithmaier
b4175c1454 Bump windows-sys version to 0.36 (#2277) 2022-05-03 12:39:29 +02:00
Tobias Menzi
0728105b2b On Wayland, fix hiding cursors on GNOME
`wl_pointer::set_cursor` expects a serial number of the last
`wl_pointer::enter` event. However other calls expect latest
observed pointer serial, so this commit tracks both and
use them as required by specification.

Fixes #2273.
2022-05-01 16:21:34 +03:00
Kas
ea09d1d10e Fix embedded NULs in C wide strings returned from Windows API (#2264) 2022-04-30 13:58:51 +02:00
Kas
e7f88588bf Fix assigning the wrong monitor when receiving Windows move events (#2266)
Co-authored-by: kas <exactly-one-kas@users.noreply.github.com>
2022-04-30 13:21:08 +02:00
Kirill Chibisov
ce890c3455 Unify behavior of resizable across platforms
This makes X11 and Wayland follow Windows and macOS, so the size of the
window could be set even though it has resizable attribute set to false.

Fixes #2242.
2022-04-24 23:35:18 +03:00
Kirill Chibisov
cbba00d360 Unify with_app_id and with_class methods
Both APIs are used to set application name. This commit unifies the API
between Wayland and X11, so downstream applications can remove platform
specific code when using `WindowBuilderExtUnix`.

Fixes #1739.
2022-04-20 01:56:56 +03:00
Markus Siglreithmaier
bf366cb99d Add cursor hittest window functionality (#2232)
Co-authored-by: z4122 <412213484@qq.com>
Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
2022-04-12 19:10:46 +02:00
Dusty DeWeese
142d55ff24 Always send RedrawEventsCleared on iOS
This makes it consistent with the rest of the platforms in winit.
2022-04-11 20:51:21 +03:00
Simon Hausmann
a58400a82c Fix TouchPhase::Ended reporting on Wayland
When all the receive from the compositor is `TouchEvent::Down` and
`TouchEvent::Up` for the same id, we would record the touch position in
the touch_points vector the first time. On `TouchEvent::Up` we'd find it
and report `TouchPhase::Ended` with that location. The next time we
receive `TouchEvent::Down` for the same id, we'd however unconditionally
append a new `TouchPoint` to `inner.touch_points`, with the new
position. On release however we'd find the earlier point and report its
location, which basically means that `TouchPhase::Ended` always and
forever reported the location of the very first touch down event.

Instead, this patch updates an existing touch point location with the
same id on `TouchDown`.

Fixes #1996
2022-04-11 20:13:28 +03:00
Kirill Chibisov
aac28d24ac Force SCTK version to prevent pointer leaking
SCTK versions before 15.4 were leaking pointers when window got closed.
So the more windows you've got the pointers you'll keep around.

Fixes #2248.
2022-04-10 13:42:05 +03:00
Steve Wooster
d624a3e648 Add methods to set ControlFlow operation
This allows downstream users to avoid importing `ControlFlow` from winit.
2022-04-10 04:32:02 +03:00
Kirill Chibisov
c57294b41a On Wayland commit after setting all startup props
The commit without buffer attached should be done after setting all
top level size/application related properties. While c4df7ad7a added
commit after setting decorations, it accounted just for decorations,
however we should account for the min/max size and other attributes.
2022-04-10 03:56:01 +03:00
Kirill Chibisov
485e82dcb1 Add getters for visible, resizeable, etc on X11
This commit adds `Window::is_visible`, `Window::is_decorated`, and
`Window::is_resizable` APIs on X11.
2022-04-10 01:51:54 +03:00
Kirill Chibisov
e8d910ffd3 Add is_resizable and is_decorated on Wayland
This commit brings `is_resizable` and `is_decorated`. Since the client
is responsible for both of them, they could be tracked without deep
syncing with server.
2022-04-07 03:05:11 +03:00
Amr Bashir
ab1f636960 feat(Windows): add skip taskbar methods (#2177) 2022-04-01 20:21:09 +02:00
TÖRÖK Attila
52c4670237 android: Add mapping from NDK Keycode to VirtualKeyCode (#2226) 2022-04-01 18:16:59 +02:00
Benjamin Saunders
2ae12fb0a0 Discourage use of WaitUntil to implement VSync (#2230) 2022-03-31 22:38:02 +02:00
Daniel Müller
6c1d3c4fd8 Fix scale factor calculation when the only monitor is reconnected
The scale factor being sent when the only monitor is disconnected and
reconnected is hard coded to 1.0. That may work by chance, if that's the
scale factor in use currently, but it does not work in the general case.
As a result, clients may end up with wrongly scaled or laid out window
contents after reconnect, as was reported over in
https://github.com/alacritty/alacritty/issues/5703, for example.

The problem was introduced by change 125ee0b, which caused an additional
ScaleFactorChanged event to be sent on monitor reconnect, but got the
scale factor wrong when the only monitor is disconnected and
reconnected.
This change fixes the problem by using the current monitor's scale
factor in this case. The event is still being sent as intended by
125ee0b.

Fixes #2123.
2022-03-31 17:43:48 +03:00
Amr Bashir
08de2b3fc4 feat(Windows): add with_msg_hook (#2213) 2022-03-30 10:30:45 +02:00
Markus Siglreithmaier
945a9e3122 Windows: Remove owned DC context per window (#1910)
The flag is not required for OpenGL and comes with several limitations when used with other style flags
2022-03-26 22:59:13 +01:00
Johan Andersson
6e28ba8927 Fix fullscreen window messaging race on Windows (#2225) 2022-03-26 16:43:13 +01:00
Lucas Kent
7369551c02 Clippy fixes for windows platform (#2131) 2022-03-23 19:08:04 +01:00
Mads Marquart
e22c76b3ac macOS set_ime_position fixes (#2180)
* Use NSView's inputContext instead of creating our own

This means that `set_ime_position` now properly invalidates the character coordinates.

* Make `set_ime_position` robust against moving windows
2022-03-18 14:50:24 +01:00
Mads Marquart
a438091266 Rename internal structs for consistency (#2149)
Proxy -> EventLoopProxy
Id -> WindowId or DeviceId
WindowTarget -> EventLoopWindowTarget
Handle -> MonitorHandle
Mode -> VideoMode
PlatformSpecificBuilderAttributes -> PlatformSpecificWindowBuilderAttributes
SuperWindowId -> RootWindowId
2022-03-18 14:09:39 +01:00
Emil Ernerfeldt
85baf79d17 Reverse horizontal scroll direction (#2105) 2022-03-13 14:22:02 +01:00
Kirill Chibisov
1c68be0631 On Wayland, fix consecutive run_return not polling
If you try to use `EventLoop::run_return` API in a way that you do on
demand polling of events it won't actually poll, since in such strategy
the `ControlFlow::Exit` is sent right before Wayland backend starts to
poll.

This was observed with smithay compositor Anvil which was doing this
particular thing leading to GNOME thinking that app isn't responding,
due to connection not being polled.
2022-03-11 18:15:33 +03:00
Clemens Wasser
b222dde835 Adopt windows-sys (#2057) 2022-03-07 22:58:12 +01:00
Kirill Chibisov
78e5a395da On Wayland, fix resize not propagating properly
On Wayland window size and scaling are double buffered, so winit should
send redraw requested for a client on the next frame as well.
2022-02-28 11:47:38 +03:00
Chris Copeland
7846e6a31e Update Window::is_maximized doc about X11/Wayland
The support for `Window::is_maximized` on X11/Wayland was added in c916eb6,
however the doc comment on the method was stating that it's not supported.
2022-02-28 11:19:16 +03:00
Lucas Kent
b7e7755edd Improve web example (#2115)
* Improve web example

* Implement basic logger into the example webpage

* Repace bash script with xtask

* replace wasm-bindgen-cli with wasm-bindgen-cli-support

* refactor

* Move logic into external crate.

* Remove CI changes

* Review feedback
2022-02-25 12:57:46 +01:00
Markus Røyset
40f48cbeb4 Fix unsafe_op_in_unsafe_fn warning on nightly (#2207) 2022-02-25 12:27:52 +01:00
Nikolai Kuklin
fb8313aa97 Fix typo in deprecation message (#2199) 2022-02-19 16:21:37 +01:00
Amr Bashir
f9643917d3 feat: add Window::is_visible (#2169)
* feat: add `Window::is_visible`

* use `Option<bool>`

* update doc

* move it right after `set_visible`
2022-02-17 19:44:14 +01:00
Mads Marquart
ac1c9b1218 Fix Android CI (#2197)
Fixes https://github.com/rust-windowing/winit/issues/2196 until a better solution using `ndk-context` is possible
2022-02-17 18:50:18 +01:00
Amr Bashir
daf0d6b9a7 feat: add Window::is_resizable (#2171)
* feat: add `Window::is_resizable`

* move it right after `set_resizable`
2022-02-17 16:03:17 +01:00
Amr Bashir
fa14863284 feat: add Window::is_decorated (#2172)
* feat: add `Window::is_decorated`

* move it right after `set_decorations`
2022-02-17 14:31:13 +01:00
Mads Marquart
cd9ec0afc7 Bump dev-dependencies (#2181)
* Update image 0.23 -> 0.24 and simple_logger 1.9 -> 2.1

* Reduce feature set in `image` dev-dependency
2022-02-17 14:13:32 +01:00
Mads Marquart
f3f6f1008a Add EventLoopBuilder
This commit adds an `EventLoopBuilder` struct to simplify event loop
customization and providing options to it upon creation. It also
deprecates the use of `EventLoop::with_user_event` in favor of the same
method on new builder, and replaces old platforms specific extension
traits with the new ones on the `EventLoopBuilder`.
2022-02-17 00:09:03 +03:00
Artúr Kovács
0e52672f4a On X11, Fix for repeated event loop iteration when ControlFlow was Wait (#2155)
* On X11, Fix for repeated event loop iteration
when `ControlFlow` was `Wait`

* ControlFlow::Poll now runs continously as should
2022-02-04 12:13:04 +01:00
Lassi Pulkkinen
bc1dc1fd63 On Wayland, report unaccelerated mouse deltas in DeviceEvent::MouseMotion 2022-02-03 13:46:29 +03:00
David Ackerman
f93f2c158b Bump versions of ndk to 0.6, ndk-sys to 0.3, ndk-glue to 0.6 (#2163) 2022-02-01 00:14:36 +01:00
Mads Marquart
9229e2d88b macOS RAII trace guards (#2150)
* Add TraceGuard to make tracing simpler

* Add SharedStateMutexGuard to make tracing simpler

* Add trace_scope macro

* Add missing let binding in trace_scope!
2022-01-23 21:35:26 +01:00
Mads Marquart
51bb6b751e Remove WINIT_LINK_COLORSYNC (no longer needed) (#2136)
Since https://github.com/rust-windowing/winit/pull/2078 we link to `ApplicationServices`, which contains the `CGDisplayCreateUUIDFromDisplayID` symbol in all versions.
2022-01-23 20:38:08 +01:00
Mads Marquart
2cc87cab65 Update changelog guidelines to prevent conflicts from blocking PRs (#2145)
* Update changelog guidelines to prevent conflicts from blocking PRs

As per consensus in https://github.com/rust-windowing/winit/issues/2135

* Add note about whitespace in changelog

* Add note about maintainer creating new tag
2022-01-23 13:55:33 +01:00
Benjamin Brittain
7cd273ae58 Make WindowBuilder's with_app_id method more ergonomic 2022-01-22 03:42:46 +03:00
Lucas Kent
001fb7ef60 Clippy fixes macos platform (#2133) 2022-01-16 01:14:59 +01:00
Lucas Kent
cf4660841a Update to Rust 2021 Edition (#2114) 2022-01-13 06:59:57 +01:00
multisn8
a52f755ce8 Add exit code to ControlFlow::Exit (#2100)
* Add exit code to control flow and impl on linux

* Fix examples to have an exit code

* Fix doc examples to use an exit code

* Improve documentation wording on the exit code

* Add exit code example

* Add exit code on windows

* Change i32 as exit code to u8

This avoids nasty surprises with negative numbers on some unix-alikes
due to two's complement.

* Fix android usages of ControlFlow::Exit

* Fix ios usages of ControlFlow::Exit

* Fix web usages of ControlFlow::Exit

* Add macos exit code

* Add changelog note

* Document exit code on display server disconnection

* Revert "Change i32 as exit code to u8"

This reverts commit f88fba0253.

* Change Exit to ExitWithCode and make an Exit const

* Revert "Add exit code example"

This reverts commit fbd3d03de9.

* Revert "Fix doc examples to use an exit code"

This reverts commit daabcdf9ef.

* Revert "Fix examples to have an exit code"

This reverts commit 0df486896b.

* Fix unix-alike to use ExitWithCode instead of Exit

* Fix windows to use ExitWithCode rather than Exit

* Silence warning about non-uppercase Exit const

* Refactor exit code handling

* Fix macos Exit usage and recover original semantic

* Fix ios to use ExitWithCode instead of Exit

* Update documentation to reflect ExitWithCode

* Fix web to use ExitWithCode when needed, not Exit

* Fix android to use ExitWithCode, not Exit

* Apply documenation nits

* Apply even more documentation nits

* Move change in CHANGELOG.md under "Unreleased"

* Try to use OS error code as exit code on wayland
2022-01-11 01:23:20 +01:00
Mads Marquart
2a2abc4843 Fix some invalid msg_send! usage (#2138)
* Fix some invalid msg_send! usage

* Make the implementation of superclass clearer
2022-01-10 21:39:17 +01:00
Lucas Kent
8af222c1e3 Remove entries from PULL_REQUEST_TEMPLATE.md that are now covered by CI. (#2126) 2022-01-05 16:23:56 +01:00
Artúr Kovács
d3e6949007 Release 0.26.1 (#2125) 2022-01-05 15:38:59 +01:00
Mads Marquart
a033b25ecb Make CI run on changes to non-code files as well (#2130)
The repository is configured such that specific checks are required to pass before merging; since CI doesn't run on PRs that don't change code, they can't be merged without administrator intervention.

Also, while this definition is currently correct, we might in the future change something so that changes to other files (like markdown files) really should be run through CI.

And example of that could be:
```rust
#[cfg(doctest)]
#[doc = include_str!("../README.md")]
extern "C" {}
```
2022-01-05 15:01:17 +01:00
Mads Marquart
39dd30c239 Fix CGDisplayCreateUUIDFromDisplayID linking (again) (#2078)
See also https://github.com/rust-windowing/winit/pull/1626.

The `cocoa` crate links to AppKit, which made the symbol `CGDisplayCreateUUIDFromDisplayID` from ApplicationServices/ColorSync (which AppKit uses internally) available to us on macOS 10.8 to 10.13.

However, this does not work on macOS 10.7 (where AppKit does not link to ColorSync internally). Instead of relying on this, we should just link to ApplicationServices directly.
2022-01-05 14:38:24 +01:00
TotalKrill
c5c99d2357 Add cursor grab for web target (#2025)
* Add cursor grab

* Update feature matrix, changelog and platform information

* Add proper error propagation

* Remove "expect" from fallible code

    code would crash if handling pointer capture outside of winit on
    every mouse click

    we swallow the error since we could not think of a case where this
    would fail in a way that would want to handle that it fails

* Remove unnecessary implementation comment

Co-authored-by: Will Crichton <wcrichto@cs.stanford.edu>
2022-01-05 11:13:46 +01:00
Shuoliu Yang
25ff30ee8c Fix transparent window crash on Windows 11 (#2121)
Maybe the transparent setting in WM_NCCREATE on Windows 11 will cause a block when calling DwmEnableBlureBehindWindow and will crash. Puts them into WM_CREATE and it works.
2022-01-03 13:54:31 +01:00
Artúr Kovács
6b250a74f8 Revert "Add composition event on macOS (#1979)" (#2119)
This reverts commit 8afeb910bd.

Reverting because this change made Pinyin input unusable
(only latin characters showed even after selecting the
desired Chinese character)
2022-01-02 22:01:51 +01:00
Lucas Kent
5331397c6c Provide examples for all window position/size setters (#2107) 2022-01-02 04:56:13 +01:00
Lucas Kent
0b39024133 Fix clippy warnings (#2108)
* Fix clippy warnings

* review feedback.
2022-01-01 03:00:11 +01:00
Mika
438d286fd5 Add new mappings for numlock, numpadenter and numpadcomma on X11 (#1937)
* Add X11 mappings

* Update CHANGELOG.md

Co-authored-by: Markus Røyset <maroider@protonmail.com>

Co-authored-by: Markus Røyset <maroider@protonmail.com>
2021-12-11 03:14:31 +01:00
Philippe Renon
18a61f1058 Fix warnings (#2076)
* examples: Fix unused `Result` that must be used when initializing console_log

* examples: Fix unused imports

* Fix unread name field warning in linux x11 ime InputMethod struct

* Fix unread name field warning in linux x11 Device struct

* Ignore unread field warning in macos/ios MonitorHandle struct

* ci: Add `--deny warnings` to `RUSTFLAGS`
2021-12-11 03:02:48 +01:00
Markus Røyset
20d012ae3f Update contact links (#2079) 2021-12-07 11:27:30 -08:00
Mads Marquart
efc54ab8ba Add note about cargo update to the raw-window-handle changelog update (#2086) 2021-12-06 12:53:56 -08:00
Kirill Chibisov
ea1c031b54 Release 0.26.0 version 2021-12-01 14:43:38 +03:00
Mads Marquart
11a44081df macOS move impl details of platform into platform_impl 2021-12-01 14:20:56 +03:00
Mads Marquart
5eb9c9504b Update raw-window-handle to 0.4.1 (#1957)
* Update raw-window-handle to `0.4.2`

See:
- https://github.com/rust-windowing/raw-window-handle/issues/72
- https://github.com/rust-windowing/raw-window-handle/pull/73
- https://github.com/rust-windowing/raw-window-handle/pull/74

* Clean up raw_window_handle functions a bit
2021-11-30 17:50:23 +01:00
Adrien Bennadji
29a078f65c bump ndk dependencies to 0.5 (#2071) 2021-11-24 16:56:57 +01:00
Alphyr
be61ca13fe On X11, update 'mio' to 0.8 2021-11-20 03:42:23 +03:00
mahkoh
e9d5b2007a On X11, don't panic when getting EINTR
Fixes #1972.
2021-11-20 03:24:45 +03:00
Ian Hobson
f2de8475fc Show the menu bar in borderless fullscreen on macOS (#2053)
* In MacOS, only disable menu bar in exclusive fullscreen

* Save and restore fullscreen options in set_fullscreen

* Don't always cache presentation options when entering exclusive fullscreen

This commit caches presentation options when entering exclusive fullscreen
only if we're coming from borderless fullscreen.

Then, when transitioning from exclusive -> borderless, if no cached presentation
options are present, then the default borderless options are applied.

This fixes the menu bar being unavailable when taking the following path:
[not fullscreen] -> [exclusive fullscreen] -> [borderless fullscreen].

Without this commit, the presentation options from [not fullscreen] were being
cached and then applied to [borderless fullscreen].

* Restore the window level when switching to exclusive fullscreen

The hack of using `CGShieldingWindowLevel() + 1` in borderless fullscreen needs
to be undone when switching from [borderless] -> [exclusive] fullscreen,
otherwise there are menu bar glitches when following a path through
[borderless] -> [exclusive] -> [borderless] modes.

Now, this might appear to conflict with the 'always on top' feature which uses
the 'floating window' level, but this feature appears to be broken anyway when
entering and exiting fullscreen with an always-on-top window. So, rather than
introducing logic to attempt to restore to the 'floating' level here, I think
it's better to do the simple thing for now and then introduce logic for
always-on-top windows when fixing the overall fullscreen behaviour.

* Update the changelog

Co-authored-by: Ehden Sinai <ehdens@gmail.com>
Co-authored-by: Francesca Lovebloom <francesca@brainiumstudios.com>
2021-11-19 13:05:36 -08:00
Markus Siglreithmaier
3ecbea3c39 Windows: Split window initialization across NCCREATE and CREATE (#2062)
* Refactor window initialization by splitting NCCREATE and CREATE related tasks.

Fixes issue with invisible owner windows.

* address review comments

* Update src/platform_impl/windows/event_loop.rs

Co-authored-by: Markus Røyset <maroider@protonmail.com>

Co-authored-by: Markus Røyset <maroider@protonmail.com>
2021-11-17 18:33:44 +01:00
cmeissl
c4df7ad7a5 On Wayland, commit the window surface after setting the decoration mode
Fixes #2064.
2021-11-15 01:23:54 +03:00
Emil Ernerfeldt
387567a917 macOS: Fix native file dialogs freezing the event loop (#2027)
* macOS: Ignore all events while in the callback

Previously all native dialogs, such as [rfd](https://github.com/PolyMeilex/rfd), would cause the event loop (event_loop.run) to freeze.

* Update changelog

* spelling

* Fix merge mistake

* Add link to issue in the code

Co-authored-by: Poly <marynczak.bartlomiej@gmail.com>
2021-11-04 11:37:02 -07:00
Markus Siglreithmaier
cfbe8462cc Windows: Increase wait timer resolution (#2007)
Windows: Increase wait timer resolution for more accurate timing when using `WaitUntil`.
2021-11-02 21:51:39 +01:00
Markus Siglreithmaier
5f4df54895 Android: Bump ndk/ndk-glue version (#2047) 2021-11-02 18:54:59 +01:00
Kirill Chibisov
ed698f2462 On Wayland, add wayland-dlopen feature to use dlopen
While winit was always using dlopen for opening system libs, it
provides a way now to disable dlopen feature helping with linking
on some targets.

Fixes #2037.
2021-10-31 17:06:00 +03:00
Kirill Chibisov
b4774861db On X11, if RANDR based scale factor is higher than 20 reset it to 1
Some video drivers could set display metrics to odd values, which can result in
extra large scale factors (e.g. winit is sending 720 for 5k screen on nvidia
binary drivers), so let's just drop them to prevent clients from using them.
The value 20 was picked, because the DPR for 8k @ 5 inch is ~18.36.

Fixes #1983.
2021-10-30 23:47:31 +03:00
Alexis Hildebrandt
9768f73bb7 Update smithay-client-toolkit
Fixes libxcbcommon linking on OpenBSD by using pkg-config when
building without dlopen feature. For details see [1].

[1] - https://github.com/Smithay/client-toolkit/pull/198
2021-10-30 22:35:36 +03:00
Arthur Kaukal Valladares
805249e27e Android: Window::config now initially returns accurate data. (#2021)
Initialize Android's static 'CONFIG' from NativeActivity's Asset Manager
2021-10-26 23:28:28 +02:00
Markus Siglreithmaier
5f24c40d05 Fix wasm CI failure (#2024)
* Fix wasm ci

* remove cargo-web step
2021-10-26 11:05:01 -07:00
Philippe Renon
1b3b82a3c1 Clippy fixes (#2011)
* windows: bump winapi version

* windows: address dark_mode FIXMEs

use now available winapi structures

* clippy: fix clippy::upper_case_acronyms warnings

* clippy: fix needless_arbitrary_self_type warnings

* clippy: fix clone_on_copy warnings

* clippy: fix unnecessary_mut_passed warnings

* clippy: fix identity_op warnings

* clippy: fix misc warnings

* prefix rustdoc lints with rustdoc::

the prefix was introduced in Rust 1.52

* windows: silence file_drop_handler is never read warning

* clippy: fix from_over_into warnings

and a bit of naming simplification

* clippy: fix missing_safety_doc warnings

* make dummy() functions const
2021-08-30 19:40:02 +02:00
Davester47
9e72396709 Fix X11 memory leak and remove mio-misc (#1987)
* Fix X11 memory leak and remove mio-misc

I also fixed a couple of clippy lints.
Fixes #1984

* Send the redraw event before waking up the main event

* Use .map instead of a match, and remove comments saved by git

* Remove unnecessary pub keywords on `WakeSender` in x11/mod.rs
2021-08-24 12:38:56 +02:00
oxalica
125ee0b446 Emit ScaleFactorChanged event on monitor reconnect (#1963)
When disconnect the only monitor, scale factor is reset to 1.0. We need
to set it back when the monitor is reconnected.

We previously assume current window must be on an existing monitor, but
that's not true in case of reconnecting the only one monitor.
2021-08-24 12:36:13 +02:00
sandmor
3bfb580d7a Fix potential bug (#2009)
* polish and failed to find visual warning

* improvement
2021-08-24 12:35:11 +02:00
sandmor
b54d47796d Fix transparency on X11 (#2006)
* find transparent in x11

* remove debug hooks

* update changelog

* polish and failed to find visual warning
2021-08-22 20:45:24 +02:00
Kirill Chibisov
b5d0d6ff3e On Wayland, implement 'request_user_attention'
This commit implements 'request_user_attention' on Wayland with
new 'xdg_activation_v1' protocol.
2021-08-17 07:59:57 +03:00
Kirill Chibisov
c9520deef8 Update smithay-client-toolkit to 'v0.15.0'
This commit also drops 'Theme' trait with its support types
in favor of 'FallbackFrame' meaning that winit will use some
predefined frame for the time being, since porting 'ConceptFrame'
will require adding font rendering librarires right into winit,
which is not desired.

Fixes #1889.
2021-08-15 22:31:59 +03:00
Steven Bosnick
ceab0f8c40 On Wayland, log error for failure to set cursor
The inability to set the cursor using any of the named cursor files
likely indicates an error in the system on which we are running.
'WinitPointer::set_cursor' also does not have any way of returning an
error so just log the error to assist users in diagnosing the problem.

Fixes: #1988.
2021-08-15 22:05:14 +03:00
Markus Siglreithmaier
b87757c552 Fix Window visibility regression (#1994)
On Windows, set windows visible on init before position update

Ensure that the style change is correctly applied, triggering the necessary events.
2021-08-12 18:57:07 +02:00
Nuno Ribeiro
1972eb952d Adds Android winit<->ndk_glue version match table (#1993)
* Adds Android winit<->ndk_glue version match table

* Fixes justification

* Adds crosses

* Address review and instead of a m:n table it shows a 1:1 version compatibility

* Addresses review
2021-08-11 14:28:49 -07:00
Osspial
f92803d80e Prevent ghost window from showing up on taskbar (#1977)
Add WS_EX_TOOLWINDOW to event target window
2021-08-11 20:02:40 +02:00
Yusuke Kominami
8afeb910bd Add composition event on macOS (#1979)
* Enable to show text when IME is active

* Remove unnecessary variable

* Enable to use IME

* fmt

* Remove println! for debug

* Fix handling of utf-8 string

* clear_marked_text should be rust function, not member function

* Store state information in ViewState

* Remove unnecessary function

* format

* Remove mut

* format

* Remove duplicate marked text

* Remove unused `is_preediting` field

Co-authored-by: Artúr Kovács <kovacs.artur.barnabas@gmail.com>
2021-08-09 11:14:13 +02:00
Sven Niederberger
f16ed98af4 On X11 and Wayland, fx window resize cursor orientation
Fixes #1912.
2021-08-01 11:19:00 +03:00
Aidan Dang
2a9916103b On Wayland, load "hand2" and "hand1" cursor icons for CursorIcon::Hand 2021-08-01 11:16:02 +03:00
Markus Røyset
63ad47a7bf Remove window subclassing (#1933)
* Remove window subclassing

* Always call `DefWindowProcW` when we don't process a message

* Improve window initialization

Note that the error path in `init` is kind of cursed at the moment.

* Rename `ThreadMsgTargetCallbackData` to `ThreadMsgTargetData`

* Simplify window initialization

* Fix compilation on 32-bit targets

* Simplify the creation of the event target window

* Use `.clone()` rather than `Rc::clone()`

* Use concrete types for args to `SetWindowLongPtrW`

On 32-bit targets, `SetWindowLongPtrW` is an alias to `SetWindowLongW`,
which returns `LONG` (`i32`) rather than `LONG_PTR` (`isisze`).

* Minor comment adjustments
2021-07-16 12:40:48 +02:00
jim jammer
27e6548343 macOS: Remove is_key_down from ViewState (#1489)
Fixes #1488.

`is_key_down` was only set to true when `insertText` was called.
Therefore `is_key_down` was actually meant to store whether the most
recently pressed key generated an `insertText` event, at which, winit
produces a `ReceivedCharacter`. The issue is that `insertText` is *not*
called for "key repeat", but winit wants to send `ReceivedCharacter`
events for "key repeat" too. To solve this, the `is_key_down` variable
was then checked in the `key_down` function to determine whether it was
valid to produce repeated `ReceivedCharacter` events during "key
repeat". However this check is not needed since `ReceivedCharacter` must
always be called if the key event has a non-empty `characters` property.

Furthermore `is_key_down` didn't actually store whether the previously
pressed character had an `insertText` event, because it was incorrectly
set to false on every "key up". This meant that if two keys were pressed
consecutively and then the first was released, then `is_key_down` was
set to false even if the most recent keypress did actually produce an
`insertText`.

Update changelog.
2021-07-13 17:38:01 +02:00
Markus Røyset
8c91986dd3 Remove libc dependency on non-linux platforms (#1976) 2021-07-13 17:27:47 +02:00
Aden Haussmann
5a65347c4e Changed description of window scale factor in Events (#1834)
* changed description of window scale factor in Events

* Update src/dpi.rs

Co-authored-by: Markus Røyset <maroider@protonmail.com>

* Fix intra-doc link

Co-authored-by: Markus Røyset <maroider@protonmail.com>
2021-06-16 09:24:49 +02:00
Francesca Lovebloom
635180c8be Update Hall of Champions (#1959)
* Lionize Aubrey

* Lionize Victor

* Lionize Freya

* Stylization consistency
2021-06-14 13:55:13 -07:00
Onirik79
019ce9862f Fix typo in events documentation (#1960) 2021-06-13 14:26:20 +02:00
Artúr Kovács
c7f46876a7 Drop the event callback before exiting on macOS (#1954)
* Drop the event callback before exiting

* Update the changelog

* Apply suggestion from review

Co-authored-by: Markus Røyset <maroider@protonmail.com>

* Apply review suggestions

Co-authored-by: Markus Røyset <maroider@protonmail.com>
2021-06-13 14:25:06 +02:00
garasubo
c916eb6137 On X11 and Wayland, add is_maximized support
Fixes #1845.

Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
2021-06-10 10:43:27 +03:00
Tilmann Meyer
67cca71524 Implement Window::request_redraw on Android (#1953) 2021-06-05 12:47:08 +02:00
i509VCB
1eff7ae004 Document how main_thread_id for Windows works (#1951) 2021-06-05 12:46:44 +02:00
Mads Marquart
982ad46c83 Use objc's autoreleasepool instead of manually with NSAutoreleasePool (#1936)
Ensures the pools are released even if we panic
2021-05-27 17:38:41 +02:00
Markus Røyset
657b4fd59e Remove support for stdweb (#1941)
* Remove support for `stdweb`

* Expunge `stdweb`; make `web-sys` the default

* Mark this change as a breaking change

* Re-insert accidental removal of space

* Use the correct cargo feature syntax

* Re-add some `cfg` attributes

* Remove `web-sys` feature from CI
2021-05-24 10:06:21 -07:00
Max de Danschutter
b371b406d5 Implemented focus_window (#1944) 2021-05-19 18:39:53 +02:00
Artúr Kovács
91591c4e94 Release 0.25.0 (#1939) 2021-05-15 19:17:08 +02:00
Luis Wirth
078b9719cc implement mint conversions (#1930)
Implement conversions for [mint](https://docs.rs/mint) (math interoperability standard types).

- `impl From<mint::Point2> for {Physical, Logical}Position`
- `impl From<{Physical, Logical}Position> for mint::Point2`

- `impl From<mint::Vector2> for {Physical, Logical}Size`
- `impl From<{Physical, Logical}Size> for mint::Vector2`
2021-05-09 00:56:52 +02:00
Markus Røyset
41d9826ee9 Fix incorrect changelog entry for #1524 (#1916)
* Fix incorrect changelog entry for #1524

* Fix incorrect changelog entry for #1524
2021-05-04 11:00:11 -07:00
Artúr Kovács
0152508a39 Allow preventing the creation of the default menu (#1923)
* Allow preventing the creation of the default menu

* Use more grammar friendly naming

* Update the changelog
2021-04-30 13:34:50 +02:00
Artúr Kovács
cdeb1c3828 Require setting the activation policy on the event loop (#1922)
* Require setting the activation policy on the event loop

* Run cargo fmt

* Update changelog

* Fixes and tweaks from review

* Correct comment in app_state.rs

Co-authored-by: Mads Marquart <mads@marquart.dk>
2021-04-30 11:31:28 +02:00
z4122
0986fae066 Add accept_first_mouse for macOS (#1882)
* feat: add accept_first_mouse for macOS

* Update the changelog

Co-authored-by: Artur Kovacs <kovacs.artur.barnabas@gmail.com>
2021-04-30 11:30:09 +02:00
Mads Marquart
277515636d MacOS: Only activate after the application has finished launching (#1903)
* MacOS: Only activate after the application has finished launching

This fixes the main menu not responding until you refocus, at least from what I can tell - though we might have to do something similar to https://github.com/linebender/druid/pull/994 to fix it fully?

* MacOS: Remove activation hack

* Stop unnecessarily calling `makeKeyWindow` on initially hidden windows

You can't make hidden windows the key window

* Add new, simpler activation hack

For activating multiple windows created before the application finished launching
2021-04-29 19:49:17 +02:00
Mads Marquart
45aacd8407 Use initialFirstResponder instead of makeFirstResponder (#1920)
As recommended by the documentation: https://developer.apple.com/documentation/appkit/nswindow/1419366-makefirstresponder?language=objc
2021-04-29 12:52:41 +02:00
Casper Rogild Storm
e8cdf8b092 Add MacOS menu (#1583)
* feat: added MacOS menu

* fix: ran fmt

* extracted function into variable

* idiomatic formatting

* Set the default menu only during app startup

* Don't set the activation policy in the menu init

Co-authored-by: Artur Kovacs <kovacs.artur.barnabas@gmail.com>
2021-04-24 16:56:46 +02:00
Artúr Kovács
1c4d6e7613 Correct the false documentation about macOS dpi (#1905) 2021-04-13 21:31:41 +02:00
LoganDark
04b4e48265 Derive Default, Hash, and Eq for some dpi types (#1833)
* Derive more things

* Changelog entry
2021-04-12 23:12:39 +02:00
Rodrigodd
dabcb1834d On Windows, allow the creation of popup window (#1895)
Add with_owner_window to WindowBuilderExtWindows.
Add set_enable to WindowExtWindows.
2021-04-10 15:47:19 +02:00
Mads Marquart
629cd86c7c Stop calling NSApplication.finishLaunching on window creation (#1902)
This is called internally by NSApplication.run, and is not something we should call - I couldn't find the reasoning behind this being there in the first place, git blame reveals c38110cac from 2014, so probably a piece of legacy code.

Removing this fixes creating new windows when you have assigned a main menu to the application.
2021-04-07 22:24:49 +02:00
Xiaopeng Li
ba704c4eb4 Mac: Redraw immediately to prevent shaking on window resize (#1901)
* Mac: Redraw immediately to prevent shaking on window resize

* Update CHANGELOG.md

* Update CHANGELOG.md

Co-authored-by: 李小鹏 <lixiaopeng.jetspark@bytedance.com>
Co-authored-by: Markus Røyset <maroider@protonmail.com>
2021-04-06 09:22:38 +02:00
Aleksandr Ovchinnikov
0487876826 On macOS, wake up the event loop immediately when a redraw is requested. (#1812)
We allow to have RunLoop running only on the main thread. Which means if
we call Window::request_redraw() from other the thread then we have to
wait until some other event arrives on the main thread. That situation
is even worse when we have ControlFlow set to the `Wait` mode then user
will not ever render anything.
2021-04-06 09:19:25 +02:00
Markus Røyset
ca9c05368e Fix CI warnings (#1898)
* Fix CI warnings

* Use the panic! macro rather than format! + panic_any
2021-03-30 21:27:32 +02:00
Michal Srb
0d634a0061 Add WindowBuilder::with_outer_position (#1866) 2021-03-25 19:18:51 +01:00
Norbert Nemec
86748fbc68 Fix communication of fractional RI_MOUSE_WHEEL events (Windows) (#1877) 2021-03-11 22:08:29 +01:00
Artúr Kovács
599477d754 Only try publishing when a version tag is pushed (#1876) 2021-03-10 14:10:35 -08:00
daxpedda
889258f538 Upgrade mio to 0.7 (#1875)
* Upgrade `mio` to 0.7
Replaced `mio-extras` with `mio-misc`.

* Possible improvement

* Remove leftover

* Wrong rebase

* Fix typo
2021-03-09 09:50:15 -07:00
Artúr Kovács
ffe2143d14 Fix for closure-captured values not being dropped on panic (#1853)
* Fix for #1850

* Update changelog

* Fix for compilation warnings

* Apply suggestions from code review

Co-authored-by: Markus Røyset <maroider@protonmail.com>

* Improve code quality

* Change Arc<Mutex> to Rc<RefCell>

* Panicking in the user callback is now well defined

* Address feedback

* Fix nightly warning

* The panic info is now not a global.

* Apply suggestions from code review

Co-authored-by: Francesca Lovebloom <francesca@brainiumstudios.com>

* Address feedback

Co-authored-by: Markus Røyset <maroider@protonmail.com>
Co-authored-by: Francesca Lovebloom <francesca@brainiumstudios.com>
2021-03-08 19:56:39 +01:00
daxpedda
98470393d1 Add dragging window with cursor feature (#1840)
* X11 implementation.

* Introduce example.

* Wayland implementation.

* Windows implementation.

* Improve Wayland seat passing.

* MacOS implementation.

* Correct windows implementation per specification.

* Update dependency smithay-client-toolkit from branch to master.

* Fixed blocking thread in windows implementation.

* Add multi-window example.

* Move Wayland to a different PR.

* Fix CHANGELOG.

* Improve example.

Co-authored-by: Markus Røyset <maroider@protonmail.com>

* Rename `set_drag_window` to `begin_drag`.

* Improve example.

* Fix CHANGELOG.

* Fix CHANGELOG.

Co-authored-by: Markus Røyset <maroider@protonmail.com>

* Rename to `drag_window`.

* Fix typo.

* Re-introduce Wayland implementation.

* Fixing Wayland build.

* Fixing Wayland build.

* Move SCTK to 0.12.3.

Co-authored-by: Markus Røyset <maroider@protonmail.com>
2021-03-07 10:43:23 +01:00
Artúr Kovács
4192d04a53 Fix seg-fault when using without a window (#1874)
* Fix seg-fault when using without a window #1869

* Update changelog
2021-03-06 11:17:23 +01:00
leafjolt
3571dcd68c Update window.rs (#1871) 2021-02-27 21:25:26 +01:00
mmacedo
952edcb804 Android: Add KeyEvent handling (#1839) 2021-02-23 22:35:38 +01:00
Axel Cocat
10a94c0794 Fix Windows' try_theme returning Theme::Dark when new theme is light (#1861) 2021-02-20 00:06:12 +01:00
Björn Steinbrink
dd32ace9ab Restore the ability to have fully transparent windows on Windows (#1815)
* Restore the ability to have fully transparent windows on Windows

Besides its original purpose, commit 6343059b "Fix Windows transparency
behavior to support fully-opaque regions (#1621)" also included some
changes considered cleanups, one of them was:

* Remove the `CreateRectRgn` call, since we want the entire window's region to
  have blur behind it, and `DwnEnableBlurBehindWindow` does that by default.

But the original code actually disabled the blur effect for the whole
window by creating an empty region for it, because that allows for the
window to be truely fully transparent. With the blur effect in place,
the areas meant to be transparent either blur the things behind it
(until Windows 8) or are darkened (since Windows 8). This also means
that on Windows 8 and newer, the resulting colors are darker than
intended in translucent areas when the blur effect is enabled.

This restores the behaviour from winit <0.24 and fixes #1814.

Arguably, one might want to expose the ability to control the blur
region, but that is outside the scope of this commit.

* Remove useless WS_EX_LAYERED from transparent windows on Windows

`WS_EX_LAYERED` is not supposed to be used in combination with
`CS_OWNDC`. In winit, as it is currently used, `WS_EX_LAYERED` actually
has no effect at all. The only relevant call is to
`SetLayeredWindowAttributes`, which is required to make the window
visible at all with `WS_EX_LAYERED` set, but is called with full
opacity, i.e. there's no transparency involved at all.

The actual transparency is already achieved by using
`DwmEnableBlurBehindWindow`, so `WS_EX_LAYERED` and the call to
`SetLayeredWindowAttributes` can both be removed.
2021-02-17 13:50:24 +01:00
Will Crichton
7e0c6ee097 Add DeviceEvent::MouseMove on web platform to support pointer lock (#1827)
* Add DeviceEvent::MouseMove on web platform to support pointer lock

* Update changelog

* Add support for stdweb too

* Add mouse_delta to stdweb

* Remove reference to pointer lock
2021-02-16 17:50:46 -05:00
Ssaely
b1be34c6a0 fix cursor blinking when clicking decorations bar on Windows (#1852) 2021-02-06 21:10:36 +01:00
Imberflur
b9307a9967 Change linking of CGDisplayCreateUUIDFromDisplayID on macos (#1626)
* Link CGDisplayCreateUUIDFromDisplayID through ColorSync instead of CoreGraphics

* Conditionally link through ColorSync only if WINIT_LINK_COLORSYNC is set
to true

* Document new macos env var in README
2021-02-05 08:58:55 +01:00
Mads Marquart
b1d353180b Add ability to assign a menu when creating a window on Windows (#1842) 2021-02-04 22:26:33 +01:00
Marijn Suijten
bd99eb1347 Android: Bump ndk/ndk-glue to 0.3 and use constants for event ident (#1847)
Following the changes in [1] this bumps ndk and ndk-glue to 0.3 and uses
the new constants. The minor version has been bumped to prevent
applications from running an older winit (without #1826) with a newer
ndk/ndk-glue that does not pass this `ident` through the `data` pointer
anymore.

[1]: https://github.com/rust-windowing/android-ndk-rs/pull/112
2021-01-30 19:43:26 +01:00
Mads Marquart
f79c01b0cf Fix HINSTANCE returned by raw_window_handle on 64 bit Windows (#1841) 2021-01-28 18:51:49 +01:00
Simas Toleikis
3f1e09ec0e Add Window::is_maximized method (#1804) 2021-01-27 19:01:17 +01:00
Markus Røyset
05125029c6 On Windows, fix deadlock caused by mouse capture (#1830)
The issue was caused by calling SetCapture on a window which already
had the capture. The WM_CAPTURECHANGED handler assumed that it would
only run if the capture was lost, but that wasn't the case. This made
the handler to try to lock the window state mutex while it was already
locked.

The issue was introduced in #1797 (932cbe4).
2021-01-19 17:41:02 +01:00
Marijn Suijten
05fe983757 android: Use event identifier instead of userdata pointer (#1826)
ndk-glue currently sets both the `ident` field and user-data pointer to
`0` or `1` for the event pipe and input queue respectively, to tell
these sources apart. While it works to reinterpret this `data` pointer
as integer identifier it shouldn't be abused for that, in particular
when one may wish to provide extra information with an event in the
future; then the `data` field is used as pointer (or abused as abstract
value) for that.
2021-01-13 23:02:55 +01:00
alula
d1a7749df5 Android: Do not mark unhandled events as handled. (#1820) 2021-01-12 08:25:56 +01:00
Markus Røyset
9d63fc7ca0 On Windows, set the cursor icon when the cursor first enters a window (#1807) 2021-01-05 17:39:13 +01:00
Markus Røyset
38fccebe1f On Windows, change the default window size (#1805) 2020-12-20 17:59:46 +01:00
Markus Røyset
c05952b813 On Windows, improve handling of window destruction (#1798) 2020-12-20 12:54:42 +01:00
Samuel
932cbe40bf On Windows, fix bug causing mouse capture to not be released. (#1797) 2020-12-15 07:31:13 +01:00
relrelb
39573d65d0 Windows: Preserve minimized/maximized state in fullscreen (#1784) 2020-12-13 19:06:53 +01:00
Kirill Chibisov
6db308f1e9 Release 0.24.0 2020-12-10 19:12:46 +03:00
Viktor Zoutman
6f70fd90b9 Windows: Changed thread_event_target_callback's WM_DESTROY to WM_NCDESTROY (#1780) 2020-12-10 12:09:08 +01:00
moko256
db038d943c On Windows, implement 'Window::set_ime_position' with IMM API 2020-12-09 23:16:59 +03:00
Kirill Chibisov
c5620efc9c On Wayland, don't drop extra mouse buttons
This commit forwards "unknown" Wayland mouse buttons downstream via
'MouseButton::Other'. Possible values for those could be found in
<linux/input-event-codes.h>.

Also, since Wayland just forwards buttons from the kernel, which are
'u16', we must adjust 'MouseButton::Other' to take 'u16' instead of
'u8'.
2020-12-09 23:11:25 +03:00
Marnix Kuijs
8fb7aa5cef Android: Improved multi-touch (#1783)
* Improved multi-touch

* Update feature matrix

* Generate cancelled events for all pointers

* Changed back features matrix layout

* Reduced code duplication

* Updated changelog

* Revert changelog update
2020-12-02 12:13:42 -08:00
Viktor Zoutman
6ddee9a8ac Ability to force a theme on Windows (#1666) 2020-11-30 19:04:26 +01:00
Max de Danschutter
5700359a61 Android: support multi-touch (#1776) 2020-11-28 17:41:11 +01:00
Max de Danschutter
0861a353d6 Add 'request_user_attention' to Window
This commit introduces a cross platform way to request a user attention
to the window via a 'request_user_attention' method on a Window struct.
This method is inspired by macOS's 'request_user_attention' method and
thus reuses its signature and semantics to some extent.
2020-11-27 05:03:08 +03:00
Philippe Renon
f79efec7ef Fix deprecation warning in the window icon example 2020-11-26 00:20:35 +00:00
Viktor Zoutman
77d5d20391 Windows: Delayed Message Boxes Fix. (#1769) 2020-11-24 23:05:29 +01:00
Kirill Chibisov
165e51d850 On Wayland, increase default font size in CSD
This commit increased default font size from 11 to 17 making it
identical to the one SCTK is using under the hood, since it's more
readable.
2020-11-22 01:53:56 +03:00
Max de Danschutter
1c38f113b3 Remove println call from Android's eventloop 2020-11-19 17:56:24 +00:00
msiglreith
66859607a3 Rename desktop eventloop extensions to run_return extension (#1738) 2020-11-12 20:49:44 +01:00
Wladimir J. van der Laan
edf396b1a4 On Wayland, add missing mappings for numpad arrows
The mappings for 'keysyms::XKB_KEY_KP_{Up,Down,Left,Rigt}' were missing making the arrow keys on the numpad not sending proper 'VirtualKeyCode's.
2020-11-11 00:55:29 +03:00
Murarth
cbeb51b436 X11: Fix multiple RedrawRequested events per event loop iteration (#1758)
* X11: Fix multiple RedrawRequested per event loop iteration

* Prevent infinite loop
2020-11-07 11:46:37 -07:00
Murarth
45e4fd6ec1 X11: Fix request_redraw not waking the event loop (#1756) 2020-11-05 16:42:03 -07:00
Mikko Lehtonen
3a077ff211 macos: Fix compile on aarch64 2020-11-02 21:06:00 +00:00
Brad
be850e483a Document Android raw_window_handle requirements (#1749)
* Add docs describing raw_winow_handle on android

* Run cargo fmt

* Change raw_window_handle panic to give more info
2020-10-29 14:23:46 -07:00
Simon Hausmann
33fb62bb25 Fix WindowEvent::ReceivedCharacter on web (#1747)
* Fix WindowEvent::ReceivedCharacter on web

The event was never sent to the application because of the unconditional
preventDefault() call on keydown.

Fixes #1741

* Don't scroll when pressing space on a focused canvas

After reaching keypress, we should prevent further propagation.

Relates to #1741
2020-10-29 17:13:21 -04:00
qthree
66c117e599 [Windows] Fix use after free during window destruction (#1746) 2020-10-23 19:04:18 +02:00
Waridley
8aa1be8336 On Unix, fix cross-compiling to wasm32
Aborting compilation by using 'compile_error!' macro in build.rs was resulting in failing cross
compilation, thus this commit removes build.rs. The compilation will now be aborted on existing 'compile_error!' macros in corresponding platform sources.
2020-10-22 07:14:33 +03:00
Kirill Chibisov
037d4121a1 On Wayland, fix 'with_min_inner_size' disabling resize
Building window with 'set_min_inner_size' was setting 'max_inner_size'
under the hood, thus completely disabling window resize, since
the window isn't resizeable on Wayland when its minimum size
is equal to its maximum size.
2020-10-20 03:30:19 +03:00
Vickles
fbd3918d3a Add prefix byte for extended scancodes on Windows (#1679) 2020-10-19 16:35:01 +02:00
Alex Butler
7c543a43a9 Windows: Fix alt tab bordless fullscreen (#1740) 2020-10-19 16:15:23 +02:00
Kirill Chibisov
ee3996cac6 Feature gate more dependencies
Wayland backend is self contained and only requires
smithay-client-toolkit to work, thus feature gate the
rest of the deps that are only for X11.
2020-10-18 02:05:08 +03:00
Murarth
96809ac659 Fix warnings (#1742) 2020-10-15 11:33:06 -07:00
Jim Porter
6343059bc0 Fix Windows transparency behavior to support fully-opaque regions (#1621)
This patch removes an unneeded workaround for transparent windows on the
Windows platform. In addition, it simplifies a couple of related API calls:

* Remove the `CreateRectRgn` call, since we want the entire window's region to
  have blur behind it, and `DwnEnableBlurBehindWindow` does that by default.
* Remove the `color_key` for `SetLayeredWindowAttributes`, since it's not used
  (we're not passing `winuser::LWA_COLORKEY` to the flags).
2020-10-14 12:23:34 +02:00
Simon Hausmann
5a78fe33e8 Fix failing assertion on start-up with Safari (#1736)
The initial media query that's used to watch for device pixel ratio
changes should match. Unfortunately it doesn't with Safari and the
corresponding assertion fails. This is because resolution is not a
supported support property for queries. As a workaround, this patch
extends the query to optionally match for the webkit specific DPR
property directly.

This fixes #1734
2020-10-10 00:31:51 -04:00
Max de Danschutter
676fb947f2 Added WindowHasFocus and WindowLostFocus events to Android (#1733)
* Added WindowHasFocus and WindowLostFocus events to Android

* Update changelog
2020-10-08 19:44:41 +02:00
Kirill Chibisov
d18afb4a50 Release 0.23.0 2020-10-02 18:05:07 +03:00
Nathan Lilienthal
fc336a76bf Fix incorrect modifiers state on startup
Fixes #1563.
2020-10-02 05:07:09 +03:00
Kirill Chibisov
b9f3d333e4 Update SCTK to 0.12
SCTK was a bit behind on Wayland protocol version, and so this release
brings it up to date. It also cleans up 'Environment'.
2020-10-01 01:19:15 +03:00
Kirill Chibisov
3d85af04be Update SCTK to 0.11.0
* Update SCTK to 0.11.0

Updates smithay-client-toolkit to 0.11.0. The major highlight
of that updated, is update of wayland-rs to 0.27.0. Switching
to wayland-cursor, instead of using libwayland-cursor. It
also fixes the following bugs:

  - Disabled repeat rate not being handled.
  - Decoration buttons not working after tty switch.
  - Scaling not being applied on output reenable.
  - Crash when `XCURSOR_SIZE` is `0`.
  - Pointer getting created in some cases without pointer capability.
  - On kwin, fix space between window and decorations on startup.
  - Incorrect size event when entering fullscreen when using
    client side decorations.
  - Client side decorations not being hided properly in fullscreen.
  - Size tracking between fullscreen/tiled state changes.
  - Repeat rate triggering multiple times from slow callback handler.
  - Resizable attribute not being applied properly on startup.
  - Not working IME

Besides those fixes it also adds a bunch of missing virtual key codes,
implements proper cursor grabbing, adds right click on decorations
to open application menu, disabled maximize button for non-resizeable
window, and fall back for cursor icon to similar ones, if the requested
is missing.

It also adds new methods to a `Theme` trait, such as:
  - `title_font(&self) -> Option<(String, f32)>` - The font for a title.
  - `title_color(&self, window_active: bool) -> [u8; 4]` - The color of
  the text in the title.

Fixes #1680.
Fixes #1678.
Fixes #1676.
Fixes #1646.
Fixes #1614.
Fixes #1601.
Fixes #1533.
Fixes #1509.
Fixes #952.
Fixes #947.
2020-09-29 00:11:43 +03:00
Logan Magee
471b1e003a Bump console_log from 0.1 to 0.2 2020-09-27 17:47:47 +03:00
alvinhochun
be2e17d605 Update readme info regarding WebAssembly and web target (#1726) 2020-09-24 10:52:11 -07:00
alvinhochun
9d6b9797c0 Clarify ControlFlow::Poll doc for web (#1725)
Make it clear that ControlFlow::Poll causing events to be sent on
`requestAnimationFrame` is an implementation detail which should not be
relied on.
2020-09-24 10:30:26 -04:00
Wang Kai
3cd6a18048 Fix WindowEvent::Moved ignoring DPI on macOS 2020-09-23 10:54:53 +00:00
Michael Hills
c9558c5f0e Fix view frame in portrait when starting iOS app in landscape (#1703)
Co-authored-by: Francesca Lovebloom <francesca@brainiumstudios.com>
2020-09-22 11:21:07 -07:00
Kirill Chibisov
71e3d25422 Rework 'Fullscreen::Borderless' enum variant
This changes 'Fullscreen::Borderless' enum variant from
'Fullscreen::Borderless(MonitorHandle)' to
'Fullscreen::Borderless(Option<MonitorHandle>)'. Providing
'None' to it will result in picking the current monitor.
2020-09-22 04:54:47 +03:00
alvinhochun
644dc13e00 web: Emit WindowEvent::Resized on Window::set_inner_size (#1717)
* web: Allow event to be queued from inside the EventLoop handler

The Runner is behind a RefCell, which is mutably borrowed when the event
handler is being called. To queue events, `send_events` needs to check
`is_closed()` and the `is_busy` flag, but it cannot be done since the
RefCell is already locked. This commit changes the conditions to work
without needing a successful borrow.

* web: Emit WindowEvent::Resized on Window::set_inner_size

* Update changelog
2020-09-21 18:19:00 -04:00
alvinhochun
47e7aa4209 Add cleanup code to web backend, mostly web-sys (#1715)
* web-sys: Impl. event listeners removal for canvas

* web-sys: Impl. media query listeners cleanup

* web: Emit WindowEvent::Destroyed after Window is dropped

* web-sys: Fix unload event closure being dropped early

* web: Impl. cleanup on ControlFlow::Exit

- Drops the Runner, which causes the event handler closure to be
  dropped.
- (web-sys only:) Remove event listeners from DOM.

* web: Do not remove canvas from DOM when dropping Window

The canvas was inserted by the user, so it should be up to the user
whether the canvas should be removed.

* Update changelog
2020-09-20 18:42:07 -04:00
Ryan G
1c97a310b1 Deprecate the stdweb backend (#1712)
* Deprecate the stdweb backend

* Add a changelog entry

* Fmt

* Move the deprecation notice
2020-09-20 18:41:44 -04:00
Kirill Chibisov
d612a1b5a1 Prefix numpad virtual key codes with Numpad
This commit is a follow up to a2db4c0a32
to make it clear which virtual key codes are located on numeric pad.

It also adds Asterisk and Plus virtual key codes.
2020-09-20 12:58:24 +03:00
msiglreith
386ead15a3 Android: bump ndk versions (#1708)
* Bump ndk versions

* Update README for new ndk proc attribute

* android: add CHANGELOG entry to ndk vesion bump
2020-09-18 11:14:56 -07:00
alvinhochun
83c95e774d Explicitly require simple_logger 1.9 for examples 2020-09-17 16:58:53 +03:00
Logan Magee
e4754999b7 Replace deprecated simple_logger initialization 2020-09-10 01:58:30 +00:00
Logan Magee
c66489dbb1 Bump parking_lot to 0.11
Fixes #1657.
2020-09-09 23:56:48 +03:00
Josh Groves
21f9aefc7e Update macOS dependencies
Fixes #1658.
2020-09-07 23:43:51 +03:00
Kirill Chibisov
d103dc2631 Make 'primary_monitor' return 'Option<MonitorHandle>'
Certain platforms like Wayland don't have a concept of
primary Monitor in particular. To indicate that
'primary_monitor' will return 'None' as well as in cases
where the primary monitor can't be detected.

Fixes #1683.
2020-09-07 20:20:47 +03:00
Kirill Chibisov
cac627ed05 Make 'current_monitor' return 'Option<MonitorHandle>'
On certain platforms window couldn't be on any monitor
resulting in failures of 'current_monitor' function.

Such issue was happening on Wayland, since the window
isn't on any monitor, unless the user has drawn something into it.

Returning 'Option<MonitorHandle>' will give an ability to
handle such situations gracefully by properly indicating that
there's no current monitor.

Fixes #793.
2020-09-07 20:09:24 +03:00
Michael Kirk
e2cf2a5754 Fix inverted horizontal scroll on macOS
In winit the swipe from left to right on touchpad should
generate positive horizontal delta change, however on
macOS it was the other way around without
natural scrolling.

This commit inverses the horizontal scrolling delta
in 'MouseScrollDelta' events to match other platforms.

Fixes #1695.
2020-09-06 17:41:19 +03:00
alvinhochun
658a9a4ea8 Handle scale factor change on web-sys backend (#1690)
* Change web backend `event_handler` to without  'static lifetime

* Refactor web runner and fix ControlFlow::Exit not being sticky

* Impl. scaling change event for web-sys backend

* Improve `dpi` docs regarding the web backend

* Add changes to changelog

* Update features.md
2020-08-30 09:15:44 -04:00
Christian Duerr
a2db4c0a32 Unify Minus/Subtract virtual keycodes
On all platforms other than Linux/X11, the Subtract key was uniformly
used only for the Numpad. To make this cross-platform compatible, the
`-` key will now map to `Minus` on X11 instead of `Subtract`.

Since people have been confused about the difference between `Minus` and
`Subtract` in the past, the `Subtract` key has also been renamed to
`NumpadSubtract`. This is a breaking change that might be annoying to
downstream since there's no direct improvement, but it should help new
users in the future. Alternatively this could just be documented, rather
than explicitly mentioning the Numpad in the name.
2020-08-29 16:38:41 +03:00
alvinhochun
02a34a167a Impl. mouse capturing on web target (#1672)
* Impl. mouse capturing for web-sys with PointerEvent

* Impl. mouse capturing for web-sys with MouseEvent by manual tracking

* Reorganize web-sys backend mouse and pointer handling code

* Impl. mouse capturing for stdweb with PointerEvent

* Add mouse capturing for web target to changelog
2020-08-29 09:34:33 -04:00
alvinhochun
bea60930b6 Use send_events instead of send_event in web backend (#1681) 2020-08-26 12:11:27 -04:00
alvinhochun
0f7c82d38f Send CursorMove before mouse press event and note that touch is unimplemented on web target (#1668)
* Change to send CursorMove before mouse press event on web target

* Fix feature matrix to indicate touch being unimplemented on web
2020-08-21 20:23:08 -04:00
alvinhochun
6ba583d198 Fix vertical scroll being inverted on web targets (#1665) 2020-08-20 21:09:04 -04:00
Christian Duerr
89d4c06dec Fix crash on NetBSD
The `_lwp_self` function cannot be used to reliably determine the main
thread, see
https://github.com/alacritty/alacritty/issues/2631#issuecomment-676723289.

It might always be equal to the PID, but it's certainly not always 1
when the thread is the main thread.

However, Rust's built in `Thread::id` and `Thread::name` function will
always return `ThreadId(1)` and `Some("main")`. Since converting the
thread's ID to a number is not supported on stable Rust, checking that
the thread is labeled `Some("main")` seems like the most reliable
option. It should also be a good fallback in general.
2020-08-20 21:12:01 +03:00
Michael Kirk
9c72cc2a98 Fix HiDPI vs. set_cursor_icon for web (#1652)
PhysicalSize is recorded as canvas.size, whereas LogicalSize is stored
as canvas.style.size.

The previous cursor behavior on stdweb clobbered all style - thus losing
the LogicalSize.
2020-08-17 19:48:29 -04:00
simlay
412bd94ea4 Renamed NSString to NSStringRust to support Debug View Heirarchy in Xcode (#1631)
* Renamed NSString to NSStringRust to support Debug View Heirarchy

* Updated from comments

* Update CHANGELOG.md
2020-08-14 12:26:16 -07:00
TakWolf
514ab043f2 [macos] add NSWindow.hasShadow support (#1637)
* [macos] add NSWindow.hasShadow

* change log

* cargo fmt

* Update CHANGELOG.md

* Update src/platform_impl/macos/window.rs

* Update src/platform/macos.rs

* set_has_shadow() with cuter format

* adjust code

* cargo fmt

* changelog
2020-08-13 11:10:34 -07:00
msiglreith
68100102be android: fix event loop polling (#1638)
* android: poll looper for ControlFlow::Poll and don't exit when no new event received

* Add Android ControlFlow:Poll fix to CHANGELOG
2020-08-12 11:56:28 -07:00
josh65536
05fdcb5b27 Web: Use mouse events instead of pointer events if the latter isn't supported (#1630)
* Fixed Safari not getting mouse events

* Edited changelog

* Addressed compiler warnings

Co-authored-by: Ryan G <ryanisaacg@users.noreply.github.com>
2020-08-04 21:39:09 -04:00
Christian Duerr
7a49c88200 Fix with_fullscreen signature 2020-08-02 02:10:33 +03:00
Christian Duerr
40232d48ba Use PhysicalPosition in PixelDelta event
This removes the `LogicalPosition` from the `PixelDelta`, since all
other APIs have been switched to use `PhysicalPosition` instead.

Fixes #1406.
2020-07-27 01:16:21 +03:00
Christian Duerr
55dff53a98 Fix Window platform support documentation
This resolves various problems with the documentation about platform
support on the Window struct.

It also completely removes pointless runtime errors in favor of
consistent no-ops on all platforms that do not support a certain
features.
2020-07-27 00:13:17 +03:00
Matt Kraai
6919c2fb2d Fix misspellings in comments (#1618) 2020-07-09 08:08:26 -07:00
Xavier L'Heureux
3d5d05eac7 Move available_monitors and primary_monitor to EventLoopWindowTarget (#1616) 2020-07-04 15:46:41 -04:00
Osspial
dd866a74a6 On Windows, fix bug where we'd try to emit MainEventsCleared events during nested win32 event loops (#1615) 2020-07-02 16:53:47 -04:00
Jurgis
b1e22aa559 Make drag and drop optional (fixes OleInitialize failure #1255) (#1524)
Co-authored-by: Osspial <osspial@gmail.com>
2020-06-28 18:17:27 -04:00
Andrey Lesnikov
2191e9ecd5 macOS: Support click-dragging out of a window (#1607)
* macos: Support click-dragging out of a window

* macos: Use NSEvent::pressedMouseButtons for click-dragging

* macos: Click-dragging: Move pressedMouseButtons inside
2020-06-19 17:42:19 -07:00
Viktor Zoutman
bf62103417 Android run return (#1604)
* Initial Draft

* Minor clean up

* cargo fmt

* Removed accidental change

* Update CHANGELOG.md

Co-authored-by: VZout <=>
2020-06-17 15:55:52 +02:00
Murarth
4b1b314ce2 Test x11 and wayland features on CI 2020-06-15 22:49:09 +03:00
Olivier Goffart
c1ea0dde92 On Unix, add option to pick backends
Add features 'x11'  and 'wayland' to pick backends on Linux/BSD, with
both enabled by default.

Fixes #774.
2020-06-15 10:15:27 +03:00
Viktor Zoutman
5a6cfc314e Macos fullscreen & dialog support with run_return (#1581)
* Fix for fullscreen with run_return on mac

* Cleanup

* Removed a comment

* fmt

* This doesn't break exiting run_return anymore

* Now you can also transition from code

* Fmt & cleanup

* Now using a atomic instead of a static bool

* reinserted a line

* Fmt

* Added support for dialogs and child windows

* Cargo fmt

* Dialogs are now being shutdown properly

* Cargo fmt

* Update CHANGELOG.md
2020-06-09 14:46:33 -07:00
Boqin Qin
a4121a2c2e platform_impl/linux/x11: fix deadlock in fn set_fullscreen_inner (#1579)
Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
2020-05-27 09:24:08 -07:00
Andrew Slater
03335cef85 macOS: add function to hide other applications 2020-05-24 19:26:29 +03:00
Kirill Chibisov
ff66bdda7c On Wayland, fix deadlock when calling set_inner_size from event loop
Fixes #1571.
2020-05-22 13:33:04 +03:00
Ryan G
6cfddfea21 Prevent the default browser behavior of events (#1576)
This stops things like page scrolling on spacebar / arrow keys
2020-05-21 13:13:33 -04:00
Osspial
49bcec1d27 Release 0.22.2 (#1570) 2020-05-16 12:27:16 -04:00
Michal Hornický
878c179761 Implement Clone for 'static events (#1478) 2020-05-15 14:58:12 -04:00
j4qfrost
bc19c04339 Fixed changelog line for core-* dependencies (#1561) 2020-05-15 14:32:04 -04:00
curldivergence
c7a33f926b Fixed a couple of typos in repo description (#1568) 2020-05-15 14:31:32 -04:00
j4qfrost
3c38afdb47 Update macOS dependencies (#1554)
* update macos libs

* modify dependency

* changelog

* update core-video-sys version
2020-05-07 22:32:09 -04:00
Jasper De Sutter
b8828105cf add android NDK event loop (#1556)
* add android NDK event loop

* add Android build documentation & cargo-apk to CI

Co-authored-by: David Craven <david@craven.ch>
2020-05-06 15:27:49 +02:00
Francesca Lovebloom
007b195a5e iOS: convert touch positions to physical (#1551) 2020-05-04 15:55:58 -07:00
Osspial
b4c6cdf9a3 Fix several crashes on Windows by heavily simplifying the event loop code (#1496) 2020-05-04 15:14:13 -04:00
Christian Duerr
26775fa0b6 Report mouse motion before click (#1490)
* Report mouse motion before click

This fixes an issue on macOS where a mouse click would be generated,
without ever getting a mouse motion to the position before the click.
This leads to the application thinking the mouse click occurred at a
position other than the actual mouse location.

This happens due to mouse motion above the window not automatically
giving focus to the window, unless it is actually clicked, making it
possible to move the window without motion events.

Fixes #942.

* Add additional mouse motion events

Co-authored-by: Ryan Goldstein <ryan@ryanisaacg.com>
2020-04-26 16:42:45 -04:00
Matthias Fauconneau
114fe9d502 wayland: rework scale factor handling (#1538)
- Always send Resized events in case of scale factor change
- Properly take into account the resize the user can do using the resize event.
2020-04-22 18:00:41 +02:00
Héctor Ramón
54bc41f68b Implement Drop for Proxy on macOS platform (#1526) 2020-04-20 17:48:42 -04:00
Osspial
47ff8d61d1 Document that platforms will display garbage data in the window by default (#1541) 2020-04-20 00:04:30 -04:00
Benjamin Saunders
849b8f5dce Clarify when RedrawRequested is useful (#1529)
Co-Authored-By: Osspial <osspial@gmail.com>
2020-04-19 17:09:08 -04:00
Yanchi Toth
aabe42d252 Preserve with_maximized on windows (#1515) 2020-04-19 15:52:48 -04:00
simlay
78a62ec547 Added more docs.rs targets (#1521) 2020-04-19 15:37:13 -04:00
Benjamin Saunders
6dae994bb4 Mention raw-window-handle in library docs (#1528) 2020-04-19 14:58:58 -04:00
Philippe Renon
4c4d0916fd control_flow example: fix wait_cancelled logic again (#1511) 2020-04-19 13:55:10 -04:00
Ryan G
d5609729cc Bump version to 0.22.1 (#1537)
There are a few relatively important bugfixes with no API impact in the
master branch. We might as well release this as a non-breaking change.
2020-04-17 13:36:42 -04:00
Jurgis
1f24a09570 Implement requestAnimationFrame for web (#1519)
* Use requestAnimationFrame for polling wasm

* Implement `requestAnimationFrame` for stdweb

Co-authored-by: Ryan G <ryanisaacg@users.noreply.github.com>
2020-04-11 15:49:07 -04:00
Ryan G
a8e777a5df Fix a possible double-borrow during event handling (#1512) 2020-04-11 15:20:38 -04:00
Murarth
0bc58f695b Fix warnings (#1530) 2020-04-10 11:29:33 -07:00
Matthew Russo
28023d9f5b upgrades x11-dl to 2.18.5 to fix #376 (#1517)
x11-dl was using std::mem::uninitialized incorrectly and when
rustlang added MaybeUninit and intrinsic panics on UB caused
by improper use of uninitialized (see rust-lang/rust/pull/69922)
it caused issues with X11 initialization. x11-dl pr
erlepereira/x11-rs/pull/101 updated x11-dl to use MaybeUninit
correctly
2020-03-25 22:38:25 -07:00
Murarth
c2aed1979d X11: Fix ResumeTimeReached being fired early (#1505)
* X11: Fix `ResumeTimeReached` being fired early

* Update CHANGELOG.md

Co-authored-by: Osspial <osspial@gmail.com>
2020-03-11 21:54:23 -07:00
Osspial
7e04273719 Replace Travis and Appveyor CI badges with GitHub Actions CI badge 2020-03-09 18:23:03 -04:00
Osspial
0683bdcd42 Add Unreleased category back to changelog 2020-03-09 17:01:34 -04:00
Osspial
29ab0bb629 Correct 0.22.0 date 2020-03-09 16:59:39 -04:00
Christian Duerr
7a9c17a520 Bump version to 0.22.0 (#1500)
There are two PRs I'm aware of that should be relatively trivial to get
merged, which would fix some issues. Other than those, I don't think it
makes sense to wait on anything.

 - Fix Windows crash: https://github.com/rust-windowing/winit/pull/1459
 - Fix macOS mouse reports: https://github.com/rust-windowing/winit/pull/1490

While #1459 seems pretty essential to actually make winit run, #1490 is
much less important and can probably be ignored if there aren't any
resources to merge it.
2020-03-09 16:58:54 -04:00
Kirill Chibisov
b208daa271 Revert "on MacOS, Fix not sending ReceivedCharacter event for s… (#1501)
This reverts commit 9daa0738a9.

This commit introduced other bug #1453 with likely much more common bindings,
so reverting it for now.

Fixes #1453.

Co-authored-by: Osspial <osspial@gmail.com>
2020-03-09 16:57:04 -04:00
Imberflur
e85a80dd65 Fix freeze when pressing modifier keys on Windows (#1503) 2020-03-08 01:22:53 -05:00
Osspial
b1d8ce24e9 Use i32 instead of u32 for position type in WindowEvent::Moved (#1502)
* Use i32 instead of u32 for position type in WindowEvent::Moved

* Mark change as breaking
2020-03-08 00:21:04 -05:00
David Hewitt
098fd5d602 Add ability to create Icons from embedded resources on Windows (#1410)
* Add IconExtWindows trait

* Move changelog entries to unreleased category

Co-authored-by: Osspial <osspial@gmail.com>
2020-03-07 14:42:21 -05:00
Philippe Renon
2f27f64cdb On Windows, fix request_redraw() related panics (#1461)
* On Windows, fix request_redraw() related panics

These panics were introduced by 6a330a2894

Fixes https://github.com/rust-windowing/winit/issues/1391
Fixes https://github.com/rust-windowing/winit/issues/1400
Fixes https://github.com/rust-windowing/winit/issues/1466
Probably fixes other related issues

See https://github.com/rust-windowing/winit/issues/1429

* On Windows, replace all calls to UpdateWindow by calls to InvalidateRgn

This avoids directly sending a WM_PAINT message,
which might cause buffering of RedrawRequested events.

We don't want to buffer RedrawRequested events because:
- we wan't to handle RedrawRequested during processing of WM_PAINT messages
- state transitionning is broken when handling buffered RedrawRequested events

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

* On Windows, panic if we are trying to buffer a RedrawRequested event

* On Windows, move modal loop jumpstart to set_modal_loop() method

This fixes a panic.
Note that the WM_PAINT event is now sent to the modal_redraw_method
which is more correct and avoids an unecessary redraw of the window.

Relates to but does does not fix https://github.com/rust-windowing/winit/issues/1484

* On Window, filter by paint messages when draining paint messages

This seems to prevent PeekMessage from dispatching unrelated sent messages

* Change recently added panic/assert calls with warn calls

This makes the code less panicky...

And actually, winit's Windoww callbacks should not panic
because the panic will unwind into Windows code.

It is currently undefined behavior to unwind from Rust code into foreign code.
See https://doc.rust-lang.org/std/panic/fn.catch_unwind.html

* add comments to clarify WM_PAINT handling in non modal loop

* made redraw_events_cleared more explicit and more comments
2020-03-07 14:04:24 -05:00
Christian Duerr
cbb60d29a2 Remove assertions from Windows dark mode code (#1459)
* Remove assertions from Windows dark mode code

In general, winit should never assert on anything unless it means that
it is impossible to continue the execution of the program. There are
several assertions in the Windows dark mode code where this is not the
case.

Based on surface level inspection, all existing assertions could be
easily replaced with just simple conditional checks, allowing the
execution of the program to proceed with sane default values.

Fixes #1458.

* Add changelog entry

* Format code

* Pass dark mode by mutable reference

* Format code

* Return bool instead of mutable reference

* Fix dark mode success reply

Co-Authored-By: daxpedda <daxpedda@gmail.com>

* Fix dark mode success reply

* Replace magic integers with constants

Co-authored-by: daxpedda <daxpedda@gmail.com>
2020-03-07 13:56:33 -05:00
Murarth
e707052f66 Move ModifiersChanged variant to WindowEvent (#1381)
* Move `ModifiersChanged` variant to `WindowEvent`

* macos: Fix flags_changed for ModifiersChanged variant move

I haven't look too deep at what this does internally, but at least
cargo-check is fully happy now. :)

Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>

* macos: Fire a ModifiersChanged event on window_did_resign_key

From debugging, I determined that macOS' emission of a flagsChanged
around window switching is inconsistent.  It is fair to assume, I think,
that when the user switches windows, they do not expect their former
modifiers state to remain effective; so I think it's best to clear that
state by sending a ModifiersChanged(ModifiersState::empty()).

Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>

* windows: Fix build

I don't know enough about the code to implement the fix as it is done on
this branch, but this commit at least fixes the build.

Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>

* windows: Send ModifiersChanged(ModifiersState::empty) on KILLFOCUS

Very similar to the changes made in [1], as focus is lost, send an event
to the window indicating that the modifiers have been released.

It's unclear to me (without a Windows device to test this on) whether
this is necessary, but it certainly ensures that unfocused windows will
have at least received this event, which is an improvement.

[1]: f79f21641a

Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>

* macos: Add a hook to update stale modifiers

Sometimes, `ViewState` and `event` might have different values for their
stored `modifiers` flags.  These are internally stored as a bitmask in
the latter and an enum in the former.

We can check to see if they differ, and if they do, automatically
dispatch an event to update consumers of modifier state as well as the
stored `state.modifiers`.  That's what the hook does.

This hook is then called in the key_down, mouse_entered, mouse_exited,
mouse_click, scroll_wheel, and pressure_change_with_event callbacks,
which each will contain updated modifiers.

Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>

* Only call event_mods once when determining whether to update state

Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>

* flags_changed: Memoize window_id collection

Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>

* window_did_resign_key: Remove synthetic ModifiersChanged event

We no longer need to emit this event, since we are checking the state of
our modifiers before emitting most other events.

Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>

* mouse_motion: Add a call to update_potentially_stale_modifiers

Now, cover all events (that I can think of, at least) where stale
modifiers might affect how user programs behave.  Effectively, every
human-interface event (keypress, mouse click, keydown, etc.) will cause
a ModifiersChanged event to be fired if something has changed.

Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>

* key_up: Add a call to update_potentially_stale_modifiers

We also want to make sure modifiers state is synchronized here, too.

Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>

* mouse_motion: Remove update_potentially_stale_modifiers invocation

Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>

* Retry CI

* ViewState: Promote visibility of modifiers to the macos impl

This is so that we can interact with the ViewState directly from the
WindowDelegate.

Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>

* window_delegate: Synthetically set modifiers state to empty on resignKey

This logic is implemented similarly on other platforms, so we wish to
regain parity here.  Originally this behavior was implemented to always
fire an event with ModifiersState::empty(), but that was not the best as
it was not necessarily correct and could be a duplicate event.

This solution is perhaps the most elegant possible to implement the
desired behavior of sending a synthetic empty modifiers event when a
window loses focus, trading some safety for interoperation between the
NSWindowDelegate and the NSView (as the objc runtime must now be
consulted in order to acquire access to the ViewState which is "owned"
by the NSView).

Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>

* Check for modifiers change in window events

* Fix modifier changed on macOS

Since the `mouse_entered` function was generating a mouse motion, which
updates the modifier state, a modifiers changed event was incorrectly
generated.

The updating of the modifier state has also been changed to make sure it
consistently happens before events that have a modifier state attached
to it, without happening on any other event.

This of course means that no `CursorMoved` event is generated anymore
when the user enters the window without it being focused, however I'd
say that is consistent with how winit should behave.

* Fix unused variable warning

* Move changelog entry into `Unreleased` section

Co-authored-by: Freya Gentz <zegentzy@protonmail.com>
Co-authored-by: Kristofer Rye <kristofer.rye@gmail.com>
Co-authored-by: Christian Duerr <contact@christianduerr.com>
2020-03-06 15:43:55 -07:00
Philippe Renon
71bd6e73ca windows: ignore spurious mouse move messages (#1435)
Fixes https://github.com/rust-windowing/winit/issues/1428
2020-03-06 16:15:49 -05:00
Philippe Renon
b8326f6452 In control_flow example, don't schedule a new WaitUntil if wait was cancelled (#1482) 2020-03-06 10:48:54 -07:00
HeroicKatora
ece2e70a53 Update image to 0.23 (#1485)
Also makes use of a few ergonomics improvements that were introduced or
optimized in the more recent version.
2020-03-03 16:13:53 -07:00
Murarth
2b14ec23d5 Fix GitHub Actions (#1479)
* Replaces `actions/checkout@v1` with `actions/checkout@v2` to get a bug fix
2020-02-25 09:10:31 -07:00
Murarth
9999f53329 X11: Fix deadlock when an error occurs during startup (#1475) 2020-02-19 10:38:59 -07:00
Philippe Renon
522a6e3298 fix issues in wait_until_time_or_msg function (#1423)
also removed unused return value
2020-02-18 19:27:47 -05:00
Kirill Chibisov
76d0dd7ec3 On Wayland, Hide CSD for fullscreen windows (#1473) 2020-02-18 16:58:48 -07:00
daxpedda
d1073dcecb Implement ThemeChanged for web target. (#1462)
* Implement ThemeChanged for web target.

* Add TODO upstream to stdweb.

Co-authored-by: Ryan G <ryanisaacg@users.noreply.github.com>
2020-02-17 14:25:27 -05:00
Héctor Ramón
e88e8bc194 Map UserEvent properly in Event::to_static (#1468) 2020-02-16 10:53:02 -07:00
Philippe Renon
bc29931434 Add an example that calls request_redraw() from a thread (#1467)
reproduces https://github.com/rust-windowing/winit/issues/1466
2020-02-15 11:38:29 -07:00
Philippe Renon
505f312d5f Add new example that demonstrates the different control flow schemes (#1460)
User can switch between Wait, WaitUntil and Poll modes with key '1', '2' and '3' respectivly.
User can toggle request_redraw calls with the 'R' key.

Helpful for testing all control flow modes and use of request_redraw.
2020-02-13 15:20:32 -07:00
Philippe Renon
f0093d3c54 rename dpi_factor to scale_factor where appropriate (#1463)
fixes https://github.com/rust-windowing/winit/issues/1457
2020-02-13 12:41:41 -07:00
Kirill Chibisov
83b60beba6 on Wayland, Add HiDPI cursor support (#1454)
Fixes #727.
2020-02-12 19:48:58 -07:00
hatoo
5f52d7c9d0 On macOS, Fix set_simple_screen to remember frame excluding title bar (#1430)
* On macOS, Fix `set_simple_screen` to remember frame excluding title bar

* Add CHANGELOG
2020-02-12 11:27:11 +03:00
Julien Sanchez
a1b65f7080 Ignore locale if unsupported by X11 backend (#1445)
This restores default portable 'C' locale when target locale is unsupported
by X11 backend (Xlib).

When target locale is unsupported by X11, some locale-dependent Xlib
functions like `XSetLocaleModifiers` fail or have no effect triggering
later failures and panics.

When target locale is not valid, `setLocale` should normally leave the
locale unchanged (`setLocale` returns 'C'). However, in some situations,
locale is accepted by `setLocale` (`setLocale` returns the new locale)
but the accepted locale is unsupported by Xlib (`XSupportsLocale` returns
`false`).

Fix #636
2020-02-09 22:37:06 -07:00
Kirill Chibisov
96df858961 On Wayland, fix color from close_button_icon_color not applying (#1444) 2020-02-08 19:36:44 -07:00
Kirill Chibisov
4eddd1e5bc On Wayland, fix coordinates in touch events when scale factor isn't 1 (#1439)
* On Wayland, fix coordinates in touch events when scale factor isn't 1

* Explicitly state that Wayland is using LogicalPosition internally

* Fix CHANGELOG
2020-02-08 01:25:08 -07:00
Freya Gentz
28f0eb598d Release 0.21.0 (#1440)
* Update CHANGELOG.md

* Update README.md

* Update Cargo.toml

* Update Cargo.toml

* Update README.md

* Update CHANGELOG.md
2020-02-04 19:07:31 -07:00
David Craven
c1eb7f9629 Fix deadlock wayland. (#1438) 2020-02-04 16:46:19 -07:00
Murarth
2f8aa5c52a Remove armv7-apple-ios target from CI (#1433) 2020-02-03 17:42:52 -07:00
hatoo
22dcc19898 Fix set_minimized(true) works only with decorations on macOS (#1411)
* On macOS, Fix set_minimized(true) works only with decorations

* Add CHANGELOG
2020-01-31 18:07:36 +03:00
Christian Duerr
e295104199 Remove Wayland theme intermediates (#1209)
* Remove Wayland theme intermediates

This removes the intermediate struct for passing a Wayland theme to
allow the user direct implementation of the trait.

By passing the trait directly, it is possible for downstream users to
have more freedom with customization without relying on winit to offer
these options as fields.

It should also make maintenance easier, since winit already doesn't
implement all the functions which are offered by the smithay client
toolkit.

* Reimplement SCTK's Theme and ButtonState

* Fix style issues

* Remove public signature

* Format code

* Add change log entry

Co-authored-by: Murarth <murarth@gmail.com>
2020-01-26 19:56:54 -07:00
Murarth
66fe69edd9 Fix warnings on macos (#1419) 2020-01-26 13:55:27 -07:00
Ryan G
fd946feac4 Web backend refactor and documentation (#1415)
The current implementation of the event loop runner has some significant
problems. It can't handle multiple events being emitted at once (for
example, when a keyboard event causes a key input, a text input, and a
modifier change.) It's also relatively easy to introduce bugs for the
different possible control flow states.

The new model separates intentionally emitting a NewEvents (poll
completed, wait completed, init) and emitting a normal event, as well as
providing a method for emitting multiple events in a single call.
2020-01-25 19:04:03 -05:00
Freya Gentz
8856b6ecb7 Remove unused code in X11 backend. (#1416)
Signed-off-by: Freya Gentz <zegentzy@protonmail.com>
2020-01-23 12:42:15 -07:00
Osspial
0ae78db6cb Fix building on Windows 7 and 8 (#1398)
* Fix building on Windows 7 and 8

* Format
2020-01-21 12:43:36 -07:00
David Yamnitsky
3e3bb8a8f1 add hide_application on macos (#1364)
Co-authored-by: Osspial <osspial@gmail.com>
Co-authored-by: Bogaevsky <vbogaevsky@gmail.com>
2020-01-19 16:38:52 -07:00
Steven Sheldon
e48262a797 Simplify code by switching to higher-level dispatch APIs (#1409)
* Switch to higher-level dispatch APIs

* Inline all the functions

* Switch to autoreleasepool from objc
2020-01-19 11:47:55 -07:00
Diggory Hardy
d934f94704 Fix: deadlock when requesting redraw on X11 (#1408) 2020-01-18 10:49:02 -07:00
Ryan G
1fe4a7a4ea Add the ability to pass a prebuilt canvas (#1394)
This allows Winit to take control of existing canvas elements in the
DOM, which is useful for web applications with other content in the
page.
2020-01-15 21:20:14 -05:00
hatoo
9daa0738a9 on MacOS, Fix not sending ReceivedCharacter event for some key combination (#1347)
* MacOS FIX #1267

* Add CHANGELOG

* Remove unnecessary trace!
2020-01-15 00:52:18 +03:00
Philippe Renon
ad7d4939a8 doc: change remaining EventsCleared references to MainEventsCleared (#1390) 2020-01-13 12:15:44 -07:00
Ryan G
c4d07952cb Remove TODOs from the web backen (#1395) 2020-01-13 12:14:25 -07:00
Héctor Ramón
dc302b0db4 Return physical position in CursorMoved on macOS (#1378) 2020-01-12 20:50:34 +03:00
Kirill Chibisov
a6d180cefb On Wayland, fix coordinates in mouse events when scale factor isn't 1 (#1385)
* On Wayland, fix coordinates in mouse events when scale factor isn't 1

* Refactor mouse_focus to be a surface instead of WindowId
2020-01-11 01:45:52 -07:00
Francesca Plebani
1ddceeb063 macOS: Unbundled window activation hack (#1318)
* `ns_string_id_ref` convenience fn

* Unbundled app activation hack

* Greatly improved solution

* Shortened names

* Remove cruft I left here a year ago

* Doc improvements

* Use `AtomicBool` for `activationHackFlag`

* Add CHANGELOG entry

* Doc improvements

* Fix `did_finish_launching` return type + delay more

* More reliable activation checking

* Fix merge goof

* ...fix other merge goof

Co-authored-by: Freya Gentz <zegentzy@protonmail.com>
Co-authored-by: Bogaevsky <vbogaevsky@gmail.com>
2020-01-10 16:02:42 -08:00
hatoo
633d0deeae Fix run_return does not return on macOS unless it receives a message (#1380)
* On MacOS, fix `run_return` not exit immediately

* Add CHANGELOG
2020-01-10 18:25:55 +03:00
Murarth
9e3844ddd9 Fix warnings on all platforms (#1383)
* Fix warnings on all platforms

* Also fixed a trait impl bound that I noticed along the way
2020-01-09 22:29:31 -07:00
Benjamin Saunders
4b618bd6a6 Don't discard high-precision cursor position data (#1375)
* Don't discard high-precision cursor position data

Most platforms (X11, wayland, macos, stdweb, ...) provide physical
positions in f64 units, which can contain meaningful fractional
data. For example, this can be empirically observed on modern X11
using a typical laptop touchpad. This is useful for e.g. content
creation tools, where cursor motion might map to brush strokes on a
canvas with higher-than-screen resolution, or positioning of an object
in a vector space.

* Update CHANGELOG.md

Co-Authored-By: Murarth <murarth@gmail.com>

Co-authored-by: Murarth <murarth@gmail.com>
2020-01-09 21:19:50 -07:00
Osspial
09c4ed0694 Remove util from gitignore 2020-01-09 12:24:57 -05:00
Murarth
d15eb04f9e Make docs set control_flow in a more realistic way (#1376) 2020-01-07 22:55:18 -05:00
Bastian Kauschke
02ac7456e4 impl Default for WindowBuilder (#1373) 2020-01-07 14:33:56 -05:00
Murarth
6b0875728c X11: Fix deadlock on window state with certain window events (#1369) 2020-01-06 20:54:22 -07:00
Osspial
6a330a2894 On Windows, fix bug where RedrawRequested would only get emitted every other iteration of the event loop (#1366)
* Fix bug causing RedrawRequested events to only get emitted every other iteration of the event loop.

* Initialize simple_logger in examples.

This PR's primary bug was discovered because a friend of mine reported
that winit was emitting concerning log messages, which I'd never seen
since none of the examples print out the log messages. This addresses
that, to hopefully reduce the chance of bugs going unnoticed in the
future.

* Add changelog entry

* Format
2020-01-06 15:28:58 -05:00
Osspial
627a127f1b we did it bois (#1352) 2020-01-05 17:11:25 -05:00
Murarth
ec1ae68cfc X11: Properly update window size constraints on DPI change (#1356)
* In `WindowBuilderExtUnix` methods, use `Size` instead of `LogicalSize`
2020-01-05 17:04:31 -05:00
Osspial
3aa3880e69 Add changelog entry 2020-01-05 16:57:32 -05:00
Osspial
a1b8d265d0 Refine DPI docs 2020-01-05 16:34:37 -05:00
Osspial
9b122c3804 Update the DPI module docs (#1349)
* Update the DPI module docs

* Fix HiDpiFactorChanged doc link

* Incorporate lokathor and icefox feedback

* Adjust documented desktop resolution range

* X11 is one of the reasons I use Windows

* Address DPI generics and float->int rounding

* Revise DPI value statement to better reflect best practices

* Address some of freya's feedback

* phrasing

* Rephrase X11 DPI stuff
2020-01-05 14:15:12 -05:00
Osspial
28b82fb9aa Try to fix iOS build 2020-01-05 14:15:12 -05:00
Murarth
7753bbba94 Fix examples 2020-01-05 14:15:12 -05:00
Murarth
ac69a9c0dc Silence warnings about use of deprecated fields 2020-01-05 14:15:12 -05:00
Osspial
d29f7f34aa Rename hidpi_factor to scale_factor (#1334)
* Rename hidpi_factor to scale_factor

* Deprecate WINIT_HIDPI_FACTOR environment variable in favor of WINIT_X11_SCALE_FACTOR

* Rename HiDpiFactorChanged to DpiChanged and update docs

I'm renaming it to DpiChanged instead of ScaleFactorChanged, since I'd
like Winit to expose the raw DPI value at some point in the near future,
and DpiChanged is a more apt name for that purpose.

* Format

* Fix macos and ios again

* Fix bad macos rebase
2020-01-05 14:15:12 -05:00
Osspial
85ea3f1d5d Use i32 in Position::Physical (#1350)
* Use i32 in Position::Physical

* Fix multithreaded example

* format
2020-01-05 14:15:12 -05:00
Osspial
55166da437 Remove Option from HiDpiFactorChanged in favor of a bare PhysicalSize (#1346)
* Remove Option from HiDpiFactorChanged in favor of a bare PhysicalSize

* Fix macos and ios builds
2020-01-05 14:15:12 -05:00
Michael Tang
777d9edeaa Implement hidpi for web platform (#1233)
* fix: use a 'static lifetime for the web backend's `Event` types

* implement hidpi for stdweb (web-sys wip?)

* fix: make all canvas resizes go through backend::set_canvas_size

* update Window docs for web, make `inner/outer_position` return the position in the viewport
2020-01-05 14:15:11 -05:00
Antonino Siena
28a20aec10 Dpi Type conversions into/from arrays (#1283)
* Added array conversion methods

* Cargo fmt

* Undo wrong fmt
2020-01-05 14:15:11 -05:00
Osspial
3a1e694c2f Make size/position types generic over pixel type (#1277)
* Begin implementing DPI generics

* Fix multithreaded example

* Format

* Fix serde test

* hopefully fix most of the errors

* Fix dpi module errors

* More error fixings

* Format

* fix macos errors

* Another error pass

* Replace bad type signatures

* more fixins
2020-01-05 14:15:11 -05:00
Bogaevsky
b16042a047 iOS: Dpi overhaul (#1223)
* WIP - Make EL2 DPI changes and implement on Windows (#895)

* Modify DPI API publicly and on Windows

* Add generic Position and make dpi creation functions const

* Make examples work

* Fix fullscreen windows not appearing

* Replace Logical coordinates in window events with Physical coordinates

* Update HiDpiFactorChanged

* Document to_static

* On Windows, make AdjustRect calls DPI-aware when possible (#1015)

* Use AdjustWidowRectExForDPI when available

* Prioritize presevering logical size when handling WM_DPICHANGED

* Format

* Add changelog entry

* macOS: Dpi overhaul (#997)

* WIP - Make EL2 DPI changes and implement on Windows (#895)

* Modify DPI API publicly and on Windows

* Add generic Position and make dpi creation functions const

* Make examples work

* Fix fullscreen windows not appearing

* Replace Logical coordinates in window events with Physical coordinates

* Update HiDpiFactorChanged

* Document to_static

* fix app_state errors

* fixes hidpi related errors in window_delegate

* fix bad merge

* dpi_factor edits in window_delegate

* fixes type and lifetime errors in window and window_delegate

* applies fmt

* complies with @aleksijuvani requested changes

* modifies Handler lifetimes

* fixes lifetime isues, adds propper handling for HiDpiChanged

* applies fmt

* restore original lifetimes

* solution is somewhere out there

* applies fmt

* pass as references

* resolves issue with HANDLER

* crate visible type error

* fixes visibility issues

* applies fmt

* deals with warnings

* simplifies new_inner_size setting algorthm

* moves proxy instead of referencing it and removes double deref from proxy.ns_window

* makes @Osspial tests (https://github.com/rust-windowing/winit/pull/997\#discussion_r301852354) pass

* complies with @aleksijuvani suggested changes

* makes max window size std::f32::MAX

* On Windows, fix new DPI API not setting window size properly (#1130)

* First attempt

* Second attempt

* Maintain cursor horizontal ratio

* Fix DPI change handling when maximized

* Revert window example

* Make new DPI code more understandable

* Format

* Implement DPI Usability Upgrades for X11 and Wayland (#1098)

* Fix compile errors

* Use `mio` for the X11 event loop

* Removes `calloop` from the X11 event loop, as the method of draining a
  source using a closure provided to the `calloop::EventLoop` instance
  conflicts with the need to deliver events directly to the callback
  provided to `EventLoop::run`, in order to respond to the value provided by
  `WindowEvent::HiDpiFactorChanged`.

* Implement interactive `HiDpiFactorChanged` event for X11

* Implement interactive `HiDpiFactorChanged` event for Wayland

* Run cargo fmt

* Fix Wayland not processing events from EventQueue

* Backport #981

* some lifetime tinkering

* finishes lifetime tinkering

* fixes all type errors

* adds support ffi functions

* adds wrappers for nonstatic events

* replaces events with event wrappers

* reimplementing hidpichanged event in app_state

* implements HiDpiFactorChanged for iOS

* applies formatter

* complies with @aleksijuvani requested changes

* resolves conflicts

* applies fmt

* removes merge blurp

* corrects state of CHANGELOG

* fix fmt check error

* fixes hidpi_factor for armv7-apple-ios
2020-01-05 14:15:11 -05:00
Osspial
cbf61e5cb9 Fix window rectangle change being in wrong changelog entry 2020-01-05 14:15:11 -05:00
Vladimir Bogaevsky
077ee4d851 macOS: Dpi overhaul (#997) (and rebase changes)
* WIP - Make EL2 DPI changes and implement on Windows (#895)

* Modify DPI API publicly and on Windows

* Add generic Position and make dpi creation functions const

* Make examples work

* Fix fullscreen windows not appearing

* Replace Logical coordinates in window events with Physical coordinates

* Update HiDpiFactorChanged

* Document to_static

* fix app_state errors

* fixes hidpi related errors in window_delegate

* fix bad merge

* dpi_factor edits in window_delegate

* fixes type and lifetime errors in window and window_delegate

* applies fmt

* complies with @aleksijuvani requested changes

* modifies Handler lifetimes

* fixes lifetime isues, adds propper handling for HiDpiChanged

* applies fmt

* restore original lifetimes

* solution is somewhere out there

* applies fmt

* pass as references

* resolves issue with HANDLER

* crate visible type error

* fixes visibility issues

* applies fmt

* deals with warnings

* simplifies new_inner_size setting algorthm

* moves proxy instead of referencing it and removes double deref from proxy.ns_window

* makes @Osspial tests (https://github.com/rust-windowing/winit/pull/997\#discussion_r301852354) pass

* complies with @aleksijuvani suggested changes

* makes max window size std::f32::MAX

Changes from rebasing:

* fixes compile errors

* applies fmt

* reimplements HiDpiFactorChanged after #1173 merge

* uses EventWrappers
2020-01-05 14:15:11 -05:00
Murarth
7b43b0bc94 Implement DPI Usability Upgrades for X11 and Wayland (#1098)
* Fix compile errors

* Use `mio` for the X11 event loop

* Removes `calloop` from the X11 event loop, as the method of draining a
  source using a closure provided to the `calloop::EventLoop` instance
  conflicts with the need to deliver events directly to the callback
  provided to `EventLoop::run`, in order to respond to the value provided by
  `WindowEvent::HiDpiFactorChanged`.

* Implement interactive `HiDpiFactorChanged` event for X11

* Implement interactive `HiDpiFactorChanged` event for Wayland

* Run cargo fmt

* Fix Wayland not processing events from EventQueue

* Backport #981
2020-01-05 14:15:11 -05:00
Osspial
6bb7db7c11 On Windows, fix new DPI API not setting window size properly (#1130)
* First attempt

* Second attempt

* Maintain cursor horizontal ratio

* Fix DPI change handling when maximized

* Revert window example

* Make new DPI code more understandable

* Format
2020-01-05 14:15:11 -05:00
Osspial
6ffd78767f On Windows, make AdjustRect calls DPI-aware when possible (#1015)
* Use AdjustWidowRectExForDPI when available

* Prioritize presevering logical size when handling WM_DPICHANGED

* Format

* Add changelog entry
2020-01-05 14:15:11 -05:00
Osspial
f379d069b9 WIP - Make EL2 DPI changes and implement on Windows (#895)
* Modify DPI API publicly and on Windows

* Add generic Position and make dpi creation functions const

* Make examples work

* Fix fullscreen windows not appearing

* Replace Logical coordinates in window events with Physical coordinates

* Update HiDpiFactorChanged

* Document to_static
2020-01-05 14:15:11 -05:00
Osspial
2da24089de Replace Appveyor and Travis with Github Actions (#1309)
* Experiment with github actions

* Only use stable for testing simplicity

* Disable fail-fast

* Never fail when rustup target add fails

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Update rust.yml

* Split formatting check into separate job

* Update and rename rust.yml to ci.yml

* Attempt to add web support

* Fix things

* Fixings

* The "I'm not familiar with YAML" update

* The empty string update

* Fix target interpolation

* Add gcc-multilib on linux x86

* Update ci.yml

* Update ci.yml

* Update ci.yml

* Update ci.yml

* Update ci.yml

* Update ci.yml

* Use correct host on Windows GNU

* Update ci.yml

* Update ci.yml

* in my defense it was like 2 AM when I wrote this

* Update ci.yml

* Update ci.yml

* Update ci.yml

* Update ci.yml

* try caching

* Update ci.yml

* Update ci.yml

* Update on

* Update ci.yml

* Update ci.yml

* Remove travis and appveyor testing

* Cache entire cargo folder

* Make cargo cache key more appropriately named

* Reduce key collisions

* Make key work

* Add publish workflow and path qualifiers

* Remove -f in cargo install cargo-web

* continue-on-error for cargo web

* ping

* Try to shorten matrix

* attempt two

* attempt three

* attempt four

* Use bash

* web feature formatting

* ping
2020-01-05 14:13:05 -05:00
icefoxen
57f29aa6d7 Added some "how" and "why" docs to event handling. (#1032)
* Added some "how" and "why" docs to event handling.

Basically I had these questions when I started exploring the new
event API's, and as I figured out the answers I put down more info
about how everything works.  This is not final, and suggestions
are welcome -- the code example in the `event` module docs is
particularly dubious, but it's how I'm used to thinking abou things
so it only made sense to me once I wrote that.

Note that my bias is towards using winit for writing games, so that's
the sort of things I was interested in.  This may not be valid for
more general use cases.

* cargo fmt

* Fix minor typos

* Revise event documentation

* Update lib.rs docs

* Update root docs

Co-authored-by: Osspial <osspial@gmail.com>
2020-01-05 11:02:41 -05:00
Osspial
028d3ec16d Make examples set control_flow in a more realistic way (#1363)
* Make examples set control_flow in a more realistic way

* Format
2020-01-05 02:12:03 -05:00
Christian Duerr
d1c6506865 Fix ModifiersChanged event on X11 (#1358) 2020-01-03 22:11:00 -07:00
Osspial
c0b46a03b5 Relase alpha 6 (#1338)
* Relase alpha 6

* Update CHANGELOG.md

Co-authored-by: Freya Gentz <zegentzy@protonmail.com>
2020-01-03 18:17:05 -05:00
Kirill Chibisov
114c18e70d On X11, make WINIT_HIDPI_FACTOR dominate Xft.dpi in some cases (#1354)
* On X11, make `WINIT_HIDPI_FACTOR` dominate `Xft.dpi` in some cases

This commit makes `WINIT_HIDPI_FACTOR` dominate `Xft.dpi` in general and
adds a special value `0` for `WINIT_HIDPI_FACTOR` to use winit computed
DPI factor with randr over Xft.dpi.

* Use `randr` instead of `0` for auto dpi scaling

* Update CHANGELOG

* blow up on wrong env var

* Allow empty string for env var
2020-01-03 18:15:47 -05:00
hatoo
7367b8be6c On Macos, Hide cursor only inside window (#1348)
* On MacOS, hide cursor by invisible cursor

* Add CHANGELOG

* Fix variable name

* Add comments for `CURSOR_BYTES`
2020-01-03 03:34:14 +03:00
hatoo
dd768fe655 MacOS fix CursorEntered and CursorLeft events fired at old window size. (#1335)
* On macOS, Fix `CursorEntered` and `CursorLeft`

* Add CHANGELOG

Co-authored-by: Freya Gentz <zegentzy@protonmail.com>
2019-12-30 13:32:37 -07:00
Osspial
d9bda3e985 Implement ModifiersChanged on Windows, and fix bugs discovered in implementation process (#1344)
* Move DeviceEvent handling to the message target window.

Previously, device events seem to have only been sent to one particular
window, and when that window was closed Winit would stop receiving
device events. This also allows users to create windowless event loops
that process device events - an intriguing idea, to say the least.

* Emit LWin and RWin VirtualKeyCodes on Windows

* Implement ModifiersChanged on Windows

* Make ModifiersChanged a tuple variant instead of a struct variant

* Add changelog entries

* Format

* Update changelog entry

* Fix AltGr handling

* Reformat

* Publicly expose ModifiersChanged and deprecate misc. modifiers fields
2019-12-30 14:11:11 -05:00
hatoo
fa7a3025ec [MacOS] Fix memory management (#1342)
* macOS, Reduce memory usage

* macOS, Fix memory leak
2019-12-29 15:16:12 -07:00
Osspial
e4451d6786 Fix Window::set_visible not setting internal flags correctly (#1345) 2019-12-29 10:39:15 -05:00
Michael Tang
468b6b83ec fix: remove deprecated usage of mem::uninitialized. (#1341) 2019-12-28 18:53:41 -05:00
Osspial
8a3a32f286 Properly mark a few changes as breaking 2019-12-28 16:22:51 -05:00
Osspial
20e81695ca Change ModifiersState to a bitflags struct (#1306)
* Change ModifiersState to a bitflags struct

* Make examples work

* Add modifier state methods

* all things considered, only erroring out in one file throughout all of these changes is kinda impressive

* Make expansion plans more clear

* Move changelog entry

* Try to fix macos build

* Revert modifiers println in cursor_grab

* Make serde serialization less bug-prone
2019-12-28 15:36:06 -05:00
Osspial
027c52171d Fix changelog 2019-12-27 16:28:06 -05:00
Osspial
cc206d31b7 Implement windows focus key press/release on Windows (#1307)
* X11: Sync key press/release with window focus

* When a window loses focus, key release events are issued for all pressed keys
* When a window gains focus, key press events are issued for all pressed keys
* Adds `is_synthetic` field to `WindowEvent` variant `KeyboardInput`
  to indicate that these events are synthetic.
* Adds `is_synthetic: false` to `WindowEvent::KeyboardInput` events issued
  on all other platforms

* Implement windows focus key press/release on Windows

* Docs

Co-authored-by: Murarth <murarth@gmail.com>
2019-12-27 16:26:23 -05:00
hatoo
5d99316c96 macOS: Don't change fullscreen state during fullscreen transition (#1331)
* Register windowWillExitFullScreen

* On macOS: Do not toggle fullscreen during fullscreen transition

* Add CHANGELOG

Co-authored-by: Freya Gentz <zegentzy@protonmail.com>
2019-12-24 11:56:56 -07:00
David Hewitt
d59eec4633 Add support for Windows Dark Mode (#1217)
* Add support for Windows Dark Mode

* Add is_dark_mode() getter to WindowExtWindows

* Add WindowEvent::DarkModeChanged

* Add support for dark mode in Windows 10 builds > 18362

* Change strategy for querying windows 10 build version

* Drop window state before sending event

Co-Authored-By: daxpedda <daxpedda@gmail.com>

* Change implementation of windows dark mode support

* Expand supported range of windows 10 versions with dark mode

* Use get_function! macro where possible

* Minor style fixes

* Improve documentation for ThemeChanged

* Use `as` conversion for `BOOL`

* Correct CHANGELOG entry for dark mode

Co-authored-by: daxpedda <daxpedda@gmail.com>
Co-authored-by: Osspial <osspial@gmail.com>
2019-12-22 12:04:09 -07:00
Osspial
25e018d1ce Fix extraneous # in 0.20.0 Alpha 5 2019-12-22 11:24:49 -05:00
Osspial
25123bed23 Rebasing moved the RedrawRequested changelog entry to the wrong position
:/
2019-12-22 11:23:27 -05:00
Osspial
a8d6db0fc1 Update alpha version in readme.md 2019-12-22 11:19:17 -05:00
Osspial
8a9a9cd92d Move changelog entry into proper position
Fix window_run_return

Make docs build
2019-12-22 11:17:24 -05:00
simlay
530ff5420b Implement revamped RedrawRequested on iOS. (#1299)
* Implement revamped `RedrawRequested` on iOS

* Added RedrawEventsCleared to events_cleared logic

* Fixed from comments

* Added RedrawEventsCleared to draw_rect handler.

* Fixed out of order `RedrawEventsCleared` events.

* cargo fmt
2019-12-22 11:17:23 -05:00
Héctor Ramón
133b11fa6d Implement revamped RedrawRequested on Web (#1301)
* Implement revamped `RedrawRequested` on Web

* Add `web` example
2019-12-22 11:17:23 -05:00
Héctor Ramón
5b489284e4 Implement revamped RedrawRequested on macOS (#1235) 2019-12-22 11:17:23 -05:00
Heghedus Razvan
cdc32eb817 Implemented revamped RedrawRequested for linux wayland (#1237)
Signed-off-by: Heghedus Razvan <heghedus.razvan@gmail.com>
2019-12-22 11:17:23 -05:00
Osspial
eb38ff453a Run rustfmt 2019-12-22 11:17:23 -05:00
Osspial
8eb7853a1a Implement revamped RedrawRequested on Windows (#1050)
* Move event loop runner to runner module

* Implement new redraw API
2019-12-22 11:17:23 -05:00
Murarth
0c151f9fb3 Implement changes to RedrawRequested event (#1062)
* Implement changes to `RedrawRequested` event

Implements the changes described in #1041 for the X11 platform and for
platform-independent public-facing code.

* Fix `request_redraw` example

* Fix examples in lib docs

* Only issue `RedrawRequested` on final `Expose` event
2019-12-22 11:17:23 -05:00
simlay
c10c820311 Reimplement NativeDisplayMode on iOS for #1310 (#1330)
* Reimplement NativeDisplayMode on iOS for #1310

* Type annotations from code review.

Co-Authored-By: Aleksi Juvani <3168386+aleksijuvani@users.noreply.github.com>

Co-authored-by: Aleksi Juvani <3168386+aleksijuvani@users.noreply.github.com>
2019-12-22 01:39:22 -07:00
Justin Miller
82889e2367 Window::set_minimized (#985) (#990)
* Expose set_minimized. Implement for macOS (#985)

* Implement set_minimized for Wayland (#985)

Co-Authored-By: Victor Berger <vberger@users.noreply.github.com>

* Implement set_minimized for Windows (#985)

* Remove debug logs (#985)

* Implement Window::set_minimized for X11

* Remove extra param from set_window_flags call

* Cargo fmt

* Add example of usage

* Update changelog

* Update feature matrix

* Cargo fmt

* Update example to remove unnecessary event var

* Stop setting window styles when minimizing (#985)

* Add stub for WASM (#985)

Co-authored-by: Victor Berger <vberger@users.noreply.github.com>
Co-authored-by: Murarth <murarth@gmail.com>
Co-authored-by: Freya Gentz <zegentzy@protonmail.com>
Co-authored-by: Osspial <osspial@gmail.com>
2019-12-22 01:04:11 -05:00
Osspial
92741aa4ec Fix array_into_iter warning on Windows (#1329) 2019-12-21 17:49:44 -07:00
Murarth
2f352ca5cf X11: Fix CursorEntered event for non-winit window (#1320)
* X11: Fix CursorEntered event for non-winit window

* Retry CI

Co-authored-by: Osspial <osspial@gmail.com>
2019-12-21 17:47:29 -07:00
hatoo
38c8cb9f4a FIX Crash on macOS when starting maximized without decorations (#1323)
* FIX #1288

* Fix CHANGELOG.md

Co-authored-by: Freya Gentz <zegentzy@protonmail.com>
2019-12-19 18:03:41 -07:00
Kirill Chibisov
73248bdced On Wayland, under mutter(GNOME Wayland), fix CSD being behind the status bar, when starting window in maximized mode (#1324)
Mutter can reposition window on resize, if it is behind mutter's "bounding box".
So, when you start winit window in maximized mode with CSD, mutter places its CSD
behind the GNOME's status bar initially, and then sends configure with the
exact same size as your current window. If winit decides to optimize calling
frame.resize(..) in this case, we won't call set_geometry(we're calling
it through resize) and GNOME won't reposition your window to be inside the
"bounding box", which is not a desired behavior for the end user.
2019-12-19 17:08:28 -07:00
hatoo
01203b247b Fix run_return in MacOS (#1321)
* Fix run_return in MacOS

* MacOS: Fix the way of getting a window in run_return

* Fix CHANGELOG.md
2019-12-19 12:10:47 +03:00
Kirill Chibisov
3e1d169160 On Wayland, fix cursor icon updates on window borders when using CSD (#1322)
* On Wayland, fix cursor icon updates on window borders when using CSD

* Move changelog entry to a right place
2019-12-18 06:41:44 -07:00
Christian Duerr
c1b93fc3d0 Add ModifiersChanged event for macOS (#1268)
* Add ModifiersChanged event for macOS

This implements the macOS portion of #1124.

* Fix ModifiersChanged event import

* Fix event passing window instead of device id
2019-12-13 00:48:32 +03:00
Murarth
1f81e5c872 X11: Report CursorMoved when touch event occurs (#1297)
* X11: Report `CursorMoved` when touch event occurs

* Only trigger CursorMoved events for the first touch ID

* Fix testing for current touch events

* Fix first touch logic
2019-12-11 17:23:55 -07:00
Manish Goregaokar
e5291c9e28 Release 0.20.0-alpha5 (#1315) 2019-12-09 17:29:50 -07:00
Murarth
35505a3114 X11: Sync key press/release with window focus (#1296)
* X11: Sync key press/release with window focus

* When a window loses focus, key release events are issued for all pressed keys
* When a window gains focus, key press events are issued for all pressed keys
* Adds `is_synthetic` field to `WindowEvent` variant `KeyboardInput`
  to indicate that these events are synthetic.
* Adds `is_synthetic: false` to `WindowEvent::KeyboardInput` events issued
  on all other platforms

* Clarify code with comments
2019-12-07 15:51:37 -07:00
zserik
830d47a5f7 Have EventLoopClosed contain the original event (#1294)
* Fix issue #1292

* Remove "optionally" from changelog entry
2019-12-07 10:22:03 -07:00
Murarth
1a514dff38 X11: Fix incorrect DPI factor when waking from suspend (#1303) 2019-12-04 10:18:20 -07:00
Osspial
2888d5c6cf Fix array_into_iter warning on Windows (#1308) 2019-12-04 12:02:33 -05:00
Osspial
400f75a2b3 Make WindowStore::for_each less terrifying to rebase (#1304) 2019-12-04 03:55:49 -05:00
Charles Helmich
07bdd3e218 Fix ReceivedCharacter not working with Alt held on Windows (#1282)
* Fix ReceivedCharacter with Alt held on Windows

* Update CHANGELOG.md
2019-11-29 15:49:43 -05:00
Héctor Ramón
35a11ae24f Stop emitting corporate characters in macOS (#1254) 2019-11-27 12:14:36 +03:00
Ryan G
3d28283a81 Only use 'extern crate stdweb' on web targets (#1291)
The 'extern crate' declaration shouldn't be there even if the stdweb feature is on, unless the crate is being compiled for web.
2019-11-27 00:38:18 -05:00
daxpedda
aec5a9fa09 Stop refocusing window when switching from fullscreen to windowed (#1285)
* Stop refocusing window when switching from fullscreen to windowed

* Update Changelog.
2019-11-26 22:49:14 -05:00
Manish Goregaokar
0f94f62025 Bump parking_lot to 0.10 (#1287) 2019-11-25 18:05:44 -07:00
Murarth
a95ebc5ee6 X11: Fix incorrect modifiers when events are missed (#1279)
* X11: Fix incorrect modifiers when events are missed

* Syncs modifier state with state data in X key/button/motion events.
* Fixes modifier state in XWayland, as xinput2 raw input events will
  not be received when a window does not have focus.
* Removes `impl From<_> for ModifiersState` on X11/Wayland API types,
  replacing them with `pub(crate)` methods.

* Cleanup modifier state update using a macro

* Remove keys from modifier state when updating
2019-11-22 17:11:30 -07:00
Murarth
a70ac1531e X11: Fix window creation hangs when another application is fullscreen (#1248)
* X11: Fix window creation hangs when another application is fullscreen

Previously, the X11 backend would block until a `VisibilityNotify` event
is received when creating a Window that is visible or when calling
`set_visible(true)` on a Window that is not currently visible. This
could cause winit to hang in situations where the WM does not quickly
send this event to the application, such as another window being
fullscreen at the time.

This behavior existed to prevent an X protocol error caused by setting
fullscreen state on an invisible window. This fix instead stores desired
fullscreen state when `set_fullscreen` is called (iff the window is not
visible or not yet visible) and issues X commands to set fullscreen
state when a `VisibilityNotify` event is received through the normal
processing of events in the event loop.

* Add window_debug example to facilitate testing

* Add a CHANGELOG entry

* Call `XUnmapWindow` if `VisibilityNotify` is received on an invisible window
2019-11-22 17:11:04 -07:00
ariesfluctus
b6e8dd0d8a Fixed typo (#1273) 2019-11-14 00:10:31 -05:00
Murarth
af80ce842d Fix cargo doc on nightly builds (#1274) 2019-11-12 16:51:46 -07:00
Osspial
08bae037f0 Use paths for intra-doc links, and verify that links are valid in CI (#1244)
* Use paths to generate intra-doc links

* Add entry to PR checklist
2019-11-11 16:05:59 -07:00
Thom Chiovoloni
cd39327ea2 Fix invalid_value lint triggering on mem::zeroed of CFRunLoopSourceContext (#1271) 2019-11-11 15:50:31 -07:00
Murarth
9828f368d6 X11: Fix misreporting DPI factor at startup (#1252)
* X11: Fix misreporting DPI factor at startup

* Add a CHANGELOG entry
2019-11-10 13:55:29 -07:00
Murarth
1ed15c7ec7 X11: Fix events not being reported when using run_return (#1245)
* X11: Fix events not being reported using `run_return`

* Adapt examples to be more practical

* Add CHANGELOG entry
2019-11-10 11:24:43 -07:00
Murarth
c66784995d X11: Fix modifiers being reported after release (#1262)
* X11: Fix modifiers being reported after release

* Moves `ModifiersChanged` variant from `WindowEvent` to `DeviceEvent`

* Add CHANGELOG entry
2019-11-10 00:16:44 -07:00
Murarth
dba21c06ed Run cargo fmt on Rust stable 1.39.0 (#1264) 2019-11-07 13:48:34 -07:00
Kirill Chibisov
72fc6a74ec on Wayland, drop resize events equal to the current window size (#1249)
* on Wayland, drop resize events equal to the current window size

* Add changelog entry
2019-10-31 20:45:45 -04:00
Michael Tang
f916311744 Add error message when building for web without selecting a feature. (#1253) 2019-10-31 12:45:12 -04:00
David Sinclair
05a1f4280c Miscellaneous small changes (#1238)
* Use a slice instead of a new object

* Remove unnecessary 'into_iter'

* Use 'and_then' instead of 'map_or'
2019-10-23 19:45:25 -04:00
Bogaevsky
6608a0241d macOS: fixes app termination (#1234)
* fixes app termination

* applies fmt

* fmt all

* updates changelog

* keeps formating consistent

* fixes misstype
2019-10-23 17:24:50 +03:00
Osspial
429bbfade0 Release Alpha 4 (#1187)
* Release Alpha 4. TODO CHANGELOG RELEASE DATE

* Add changelog date
2019-10-18 13:25:12 -04:00
Osspial
28e3c35547 Prevent EventLoop from getting initialized outside the main thread in cross-platform functions (#1186)
* Prevent EventLoop from getting initialized outside the main thread

This only applies to the cross-platform functions. We expose functions
to do this in a platform-specific manner, when available.

* Add CHANGELOG entry

* Formatting has changed since the latest stable update...

* Fix error spacing

* Unix: Prevent initializing EventLoop outside main thread

* Updates libc dependency to 0.2.64, as required by BSD platforms

* Update CHANGELOG.md for Linux implementation

* Finish sentence

* Consolidate documentation
2019-10-18 11:51:06 -04:00
Steven Sheldon
af3ef52252 Fix so the compiler can infer msg_send! return types (#1227)
* Fix so the compiler can infer msg_send! return type

Currently, due to a quirk in Rust's type inference interacting with the
structure of the msg_send! macro, a () return type will be inferred when
the compiler cannot otherwise determine the return type. This behavior
is expected to change, and in the future could resolve to a ! return
type, which results in undefined behavior.

Linting has previously been added for this in rust-lang/rust#39216, but
it did not catch these cases due to SSheldon/rust-objc#62. An upcoming
version of objc will be fixed to stop hiding these errors, at which
point they will become compile errors.

This change fixes these errors and allows winit to compile with the
fixed version of objc.

* Bump cocoa to 0.19.1
2019-10-18 11:33:40 -04:00
Osspial
2b5f9c52a6 Always dispatch a RedrawRequested event after creating a new window (#1175) 2019-10-17 10:59:07 -04:00
Ryan G
5631cc2528 Remove test files that stuck around on accident (#1226) 2019-10-16 22:46:16 -04:00
Aleksi Juvani
de33a92a1b Fix panic upon closing the app on iOS (#1168) 2019-10-16 18:52:10 -04:00
Ryan Goldstein
1c6353aa3a Merge branch 'web' 2019-10-16 16:09:39 -04:00
Marcus Willock
08cb950226 Link WindowBuilder documentation to corresponding Window methods (fixes #1070) (#1216)
* fixes #1070

* Continuing adding documentation links for #1070
2019-10-16 12:18:02 -04:00
Kirill Chibisov
765225d918 Wayland: Fix panic when calling set_cursor_grab from a different thread than evlp's one. (#1206)
This commit also start following X11 behavior on cursor icon update when
cursor is invisible.

Fixes regression introdced in 5ced36e319
2019-10-16 12:16:23 -04:00
Ryan Goldstein
35bc65f6fa Remove usage of derivative 2019-10-13 14:36:54 -04:00
Ryan Goldstein
676268d461 Merge remote-tracking branch 'upstream/master' into web 2019-10-13 14:09:52 -04:00
Osspial
34dce8069f Test all windows targets and allow nightly Appveyor failures (#1222)
* Test all windows targets

* Allow nightly failures
2019-10-13 13:19:46 -04:00
Ryan G
f62bb33317 Merge branch 'master' into web 2019-10-12 23:51:34 -04:00
Ryan G
a557b3cfb6 Add web targets to travis (#1220)
* Add web targets to travis

* Fix some bash syntax

* Avoid crash on providing no features

* Fix syntax error

* Syntax?

* Fix pleas

* Fix features check

* Add a comment

* Add nightly builds
2019-10-12 23:44:30 -04:00
Ryan G
3ff4834bd5 Add web fullscreen support (#1142)
Adds fullscreen using native web APIs to the stdweb and web-sys backends.

Due to limitations of browser APIs, requests for fullscreen can only be fulfilled during a short-lived user-triggered event. This commit does automatically handle that under the hood, but it does introduce unavoidable latency in full-screening the canvas.
2019-10-11 11:45:07 -04:00
Ryan G
bedb889693 Fix the event key code variable name (#1219) 2019-10-11 11:41:49 -04:00
Ryan G
157ca9cd17 Update the feature matrix for wasm (#1218) 2019-10-09 19:49:12 -04:00
Osspial
6f5e7e170c Update raw-window-handle to 0.3 (#1215) 2019-10-05 21:34:27 -04:00
Osspial
df7571b369 Improve interaction between fullscreen windows and monitor-switching keyboard shortcuts (#1171)
* Update to 1.38.0 formatting

* Improve fullscreen window monitor switching on Windows

* Format
2019-10-05 16:23:30 -04:00
Aleksi Juvani
d69e41eba8 Update fullscreen state on macOS before entering fullscreen (#1196) 2019-10-05 16:23:06 -04:00
Benjamin Saunders
2d41a7d1b0 Fix use-after-free in XConnection::get_output_info (#1211) 2019-10-05 15:00:54 -04:00
Antonino Siena
42e0ccfa1c Implemented a HINSTANCE getter function for Windows (#1213)
* Expose HINSTANCE now using a getter function

* Missing changes

* remove unused import

* Required changes for the PR

* Rust fmt

* Use GetWindowLong

* Use GetWindowLong
2019-10-05 14:52:40 -04:00
Lúcás Meier
55640a91ae Use consistent return types for available_monitors() (#1207)
* [#1111] Use consistent return types for available_monitors()

Always use `impl Iterator<Item = MonitorHandle>` instead of
`AvailableMonitorsIter`. Fix an example that used the Debug
implementation of `AvailableMonitorsIter`.

* [#1111] Update changelog

* [#1111] Remove AvailableMonitorsIter type completely

* [#1111] Remove doc references to AvailableMonitorsIter
2019-10-05 10:49:24 -04:00
Alex Butler
4f6ca8792c Remove derivative dependency (#1201)
* Remove derivative dependency

* Update CHANGELOG.md
2019-10-03 16:19:10 -04:00
Kirill Chibisov
5ced36e319 Wayland support for set_cursor_icon (#1204) 2019-10-03 06:02:59 -07:00
andersrein
237e7ee2e6 Wayland support for set_cursor_grab and set_cursor_visible (#1180)
* Fixed relative_pointer not being set up when the "zwp_relative_pointer_manager_v1" callback comes after the "wl_seat" callback

* Ran cargo fmt

* Updated changelog

* Added wayland support for set_grab_cursor and set_cursor_visible

* Updated changelog

* Ran cargo fmt

* Fixed set_cursor_visible and set_cursor_grab so they can be called from any thread.

* Ran cargo_fmt

* Improved CHANGELOG

* Added workaround so that when cursor is hidden it takes effect before the cursor enters the surface. Making the cursor visible again still only happens once the cursor re-enters the surface

* Switched to using Rc<RefCell> instead of Arc<Mutex> since all accesses to the relative_pointer_manager_proxy will happen on the same thread.

* Forgot to run cargo fmt

* Switched to using Rc and RefCell instead of Arc and Mutex where applicable.

* Improved comments and documentation relating to changing a hidden cursor back to visible on wayland.

* Wayland: Fixed cursor not appearing immendiately when setting the cursor to visible.

* Forgot to run cargo fmt

* Switched to only storing the pointers in CursorManager as AutoPointer.

* Fixed typo and removed println

* Update CHANGELOG.md

Co-Authored-By: Kirill Chibisov <wchibisovkirill@gmail.com>
2019-10-01 18:25:59 -07:00
Ryan Goldstein
02f281569d Update cargo fmt 2019-09-30 16:33:41 -04:00
Ryan Goldstein
ab4d971c5e Fix imports in the multithreaded example 2019-09-30 15:55:27 -04:00
Ryan Goldstein
e21df5831e Merge branch 'master' into merge-master-to-web 2019-09-30 11:19:12 -04:00
msiglreith
18a0119b06 Update raw-window-handle to 0.2 (#1191) 2019-09-30 11:17:01 -04:00
Osspial
34348435fd Update to 1.38.0 formatting (#1188) 2019-09-27 17:35:16 -04:00
Ryan Goldstein
cf3b0f3b70 Attach the raw handle data attribute 2019-09-27 17:06:14 -04:00
Ryan Goldstein
a336e9e959 Fix the formatting in the changelog 2019-09-27 16:57:25 -04:00
Ryan Goldstein
ea93a0130d Switch to the released version 2019-09-27 16:17:40 -04:00
Ryan Goldstein
dcd9ddde50 Fix the examples 2019-09-24 19:44:43 -04:00
Ryan Goldstein
86bafdc104 Merge branch 'web' into merge-master-to-web 2019-09-24 19:41:59 -04:00
Ryan Goldstein
6732fa731d Fix compilation errors 2019-09-24 19:39:13 -04:00
Ryan G
8cea3e262b Update the documentation to reflect web support (#1183)
* Update the documentation to reflect web support

Indicate which methods have platform-specific web behavior

* cargo fmt
2019-09-24 19:33:32 -04:00
Ryan Goldstein
3e8669ea7f Merge branch 'master' into merge-master-to-web 2019-09-24 14:21:18 -04:00
andersrein
7df040f451 Wayland: Switched to using a reference to relative_pointer_manager_proxy when creating SeatData (#1179)
* Fixed relative_pointer not being set up when the "zwp_relative_pointer_manager_v1" callback comes after the "wl_seat" callback

* Ran cargo fmt

* Updated changelog

* Improved CHANGELOG

* Switched to using Rc<RefCell> instead of Arc<Mutex> since all accesses to the relative_pointer_manager_proxy will happen on the same thread.

* Forgot to run cargo fmt
2019-09-23 14:50:06 -04:00
Murarth
472eddcc1b X11: Fix panic when no monitors are available (#1158)
* X11: Fix panic when no monitors are available

* Set dummy monitor's dimensions to `(1, 1)`

* X11: Avoid panicking when there are no monitors in Window::new
2019-09-23 14:45:29 -04:00
Michael Palmos
c0a7900341 Allow using multiple XWindowTypes on X11 (#1140) (#1147)
* Allow using multiple `XWindowType`s on X11 (#1140)

* Update documentation to make combining window types clearer

* Update build flags because X11 runs on more than just Linux

* Revert "Update build flags because X11 runs on more than just Linux"

This reverts commit 882b910046.

* Revert "Update documentation to make combining window types clearer"

This reverts commit da00ad391a.

* Revert "Allow using multiple `XWindowType`s on X11 (#1140)"

This reverts commit a230333456.

* Allow using multiple `XWindowType`s on X11 (slice variant) (#1140)

* Multiple `XWindowType`s, with non-static lifetime.

* Multiple `XWindowType`s (#1140) (`Vec` variant)

* Append change to changelog.

* Fix formatting.
2019-09-23 07:10:33 -07:00
Ryan G
28a50817af Fix web redraw requested (#1181)
* Keep track of what windows have requested redraw

Instead of using request_animation_frame and sending redraw request
events, just keep track of all windows that have asked for a redraw.
This doesn't handle dispatching the events

* Issue redraw events to windows that request it

* Cargo fmt
2019-09-23 09:14:26 -04:00
Ryan G
2c47c43f47 Implement WindowID on the web platform (#1177)
* Use actual numeric IDs to differentiate Windows

This is generally important to identifying which window should
recieve which event, but is also specifically crucial for fixing
RedrawRequested on web.

* Cargo fmt
2019-09-19 18:40:18 -04:00
Osspial
2ef39651eb Fix fullscreen window shrinking upon getting restored to a normal window (#1172) 2019-09-19 11:48:20 -04:00
Murarth
eb20612d77 Prevent stealing focus on new windows (#1176) 2019-09-19 11:47:51 -04:00
Aleksi Juvani
695547f4ca Fix events not being emitted during modal loops on macOS (#1173) 2019-09-17 22:49:29 -04:00
Osspial
d35ee0d580 Fix hovering the mouse over the active window creating an endless stream of CursorMoved events (#1170)
* Fix hovering the mouse over the active window creating an endless stream of CursorMoved events

* Format
2019-09-17 11:34:48 -04:00
Aleksi Juvani
95581ab92f Fix null window on initial HiDpiFactorChanged event on iOS (#1167) 2019-09-16 14:27:46 -04:00
Osspial
3716f13d8e Flush high surrogate if not followed by low surrogate (#1166)
* Flush high surrogate if not followed by low surrogate

* Remove transmute from WM_CHAR handler

* Fix window_state being locked while dispatching ReceivedCharacter for surrogate codepoints.

* Format
2019-09-16 14:26:56 -04:00
Osspial
c03ef852a4 Fix surrogate pair handling on Windows (#1165)
* Fix surrogate pair handling on Windows

* Change high_surrogate to Option<u16>

* Format
2019-09-15 22:09:08 -04:00
Aleksi Juvani
28a5feef28 Fix freeze upon exiting exclusive fullscreen on macOS 10.15 (#1127) 2019-09-15 19:59:37 -04:00
Osspial
57a53bda74 Officially remove the Emscripten backend (#1159) 2019-09-13 19:09:45 -04:00
hafiz
36f4eccb5c fix: distinguish grab and grabbing cursors (#1154)
On macOS, there is a difference between a "grab" cursor and a "grabbing"
cursor, where "grab" is an open-hand cursor used during a hover, and
"grabbing" is a closed-hand cursor used on a click. These, and other
native MacOS cursors, can be seen at the [NSCursor documentation](https://developer.apple.com/documentation/appkit/nscursor?language=objc).

See https://github.com/hecrj/iced/issues/9 for the motivation for this
PR.
2019-09-12 16:38:44 -07:00
Victor Berger
b6de19e92e Changelog entry for #1153 (#1157) 2019-09-11 15:22:41 -07:00
Ryan G
e87bc3db20 Send a LoopDestroyed event when the browser is closed (#1155)
* Add the plumbing for handling browser closes

* Implement the business logic for handling closes
2019-09-11 11:47:03 -04:00
Victor Berger
a3739d6bad wayland: instantly wake up if events are pending (#1153)
Just before starting to poll/wait on calloop(mio), check if there
are already events pending in the internal buffer of our wayland
event queue. If so, dispatch them and force an instant wakeup from
the polling, in order to behave as if we were instantly woken up by
incoming wayland events.

When using OpenGL, mesa shares our wayland socket, and also reads
from it, especially if vsync is enabled as it'll do blocking reads.
When doing so, it may enqueue events in the internal buffer of our
event queue.

As the socket has been read, mio will thus not notify it to calloop
as read, and thus calloop will not know it needs to dispatch. In some
cases this can lead to some events being delivered much later than
they should. Combined with key repetition this can actually cause some
flooding of the event queue making this effect event worse.

Fixes #1148
2019-09-11 08:28:21 +02:00
dam4rus
068d114740 Add touch pressure information for touch events on Windows (#1134)
* Add touch pressure information for touch events on Windows

* Modified CHANGELOG.md and FEATURES.md to reflect changes

* Updated documentation of struct Touch to reflect changes

* Replaced mem::uninitalized() with mem::MaybeUninit
Fixed warnings in platform_impl/windows/dpi.rs
2019-09-09 14:15:49 -04:00
Hal Gentz
3273c14dea Hide ModifiersChanged from the docs. (#1152)
We wouldn't want users stumbling on it until all platforms implement it.
2019-09-08 12:57:43 -07:00
Murarth
206c3c246c Implement WindowEvent ModifiersChanged for X11 and Wayland (#1132)
* Implement WindowEvent ModifiersChanged for X11 and Wayland

* Fix modifier key state desync on X11

* Run cargo fmt
2019-09-08 11:43:28 -07:00
mtak-
bfcd85ab15 [ios] Groundwork for new Redraw API, refactoring AppState, and bugfixes (#1133)
* fix #1087. the CFRunLoopTimer was never started if the user never changed the controlflow.

* RedrawRequested ordering matches the new redraw api
consistent asserts
lots of appstate refactoring to rely less on unsafe, and hopefully make it easier to maintain

* ios: dpi bugfix. inputs to setContentScaleFactor are not to be trusted as iOS uses 0.0 as a sentinel value for "default device dpi".

the fix is to always go through the getter.

* move touch handling onto uiview

* update changelog

* rustfmt weirdness

* fix use option around nullable function pointers in ffi

* Document why gl and metal views don't use setNeedsDisplay

* change main events cleared observer priority to 0 instead of magic number
log when processing non-redraw events when we expect to only be processing redraw events
2019-09-04 14:23:11 -07:00
Murarth
c99bba1655 Remove unused unix dlopen module (#1138) 2019-08-31 01:58:45 -07:00
Osspial
1e7376847b Move changelog entries into proper position (#1131) 2019-08-27 19:20:24 -04:00
Osspial
b03e589987 On Windows, Unset maximized when transforming window (#1014)
* Unset maximized when functionally transforming window

* Add docs

* Fix compile issues
2019-08-26 22:07:15 -04:00
Murarth
0b497b62d8 X11: Improve performance of Window::set_cursor_icon (#1116)
* X11: Fix performance issue with rapidly resetting cursor icon

* When setting cursor icon, if the new icon value is the same as the
  current value, no messages are sent the X server.

* X11: Cache cursor objects in XConnection

* Add changelog entry
2019-08-26 22:06:59 -04:00
Osspial
f085b7349c Remove outdated noop comment (#1126) 2019-08-26 22:06:40 -04:00
Aleksi Juvani
dd99b3bd73 Fix inverted parameter in set_prefers_home_indicator_hidden on iOS (#1123) 2019-08-26 19:56:10 -04:00
mtak-
f53683f01f iOS os version checking around certain APIs (#1094)
* iOS os version checking

* iOS, fix some incorrect msg_send return types

* address nits, and fix OS version check for unsupported os versions

* source for 60fps guarantee
2019-08-26 18:47:23 -04:00
Kirill Chibisov
7b707e7d75 macos: Implement run_return (#1108)
* macos: Implement run_return

* Update comments

* Fix CHANGELOG.md
2019-08-23 02:30:53 -07:00
Osspial
31110be396 Release alpha 3 (#1106) 2019-08-14 11:09:47 -04:00
Osspial
604016d69d Implement raw_window_handle::HasRawWindowHandle for Window type (#1105)
* Implement raw_window_handle::HasRawWindowHandle for Window type

* Format

* Address compilation issues

* Fix Linux build hopefully

* Fix iOS build
2019-08-14 07:57:16 -04:00
Zakarum
7ee9d5639b Disable web module on other targets than wasm32 (#1102) 2019-08-14 01:20:05 -07:00
mtak-
1aab328e2a macos: fix an incorrect type signature on NSView drawRect (#1104) 2019-08-14 00:01:22 -04:00
Aleksi Juvani
1366dc326a Add touch pressure information for touch events on iOS (#1090)
* Add touch pressure information for touch events on iOS

* Add a variant for calibrated touch pressure
2019-08-13 18:12:13 -04:00
satrix321
8e73287646 Change 'proxy.rs' into 'custom_events.rs" (#1101)
* changed i32 to CustomEvent enum
* added a match case for custom event
* minor cleanup
* fixes #953
2019-08-13 18:09:34 -04:00
Emmanouil Katefidis
7eed52a97a Update parking_lot to 0.9 (#1097) (#1099) 2019-08-11 13:31:30 -07:00
YVT
31ada5a052 macOS/iOS: Fix auto trait impls of EventLoopProxy (#1084)
* macOS/iOS: Fix auto trait impls of `EventLoopProxy`

`EventLoopProxy<T>` allows sending `T` from an arbitrary thread that
owns the proxy object. Thus, if `T` is `!Send`, `EventLoopProxy<T>` must
not be allowed to leave the main thread.

`EventLoopProxy<T>` uses `std::sync::mpsc::Sender` under the hood,
meaning the `!Sync` restriction of it also applies to
`EventLoopProxy<T>`. That is, even if `T` is thread-safe, a single
`EventLoopProxy` object cannot be shared between threads.

* Update `CHANGELOG.md`
2019-08-08 17:13:13 -07:00
Aleksi Juvani
30b4f8dc9f Replace set_decorations with set_prefers_status_bar_hidden on iOS (#1092) 2019-08-08 16:10:54 -07:00
Héctor Ramón
dbdde3d781 Stop appending canvas to document in web platform (#1089)
* Stop appending canvas to document in web platform

* Remove `tabindex` TODO in web backend

* Return `OsError` instead of panicking on web canvas creation
2019-08-08 14:51:41 -07:00
Hal Gentz
cf0b8babbd Add new EventLoopWindowTargetExtUnix trait. (#1026)
* Add new `EventLoopWindowTargetExtUnix` trait.

Signed-off-by: Hal Gentz <zegentzy@protonmail.com>

* Slide.

Signed-off-by: Hal Gentz <zegentzy@protonmail.com>

* Travis, damn you.

Signed-off-by: Hal Gentz <zegentzy@protonmail.com>

* Update CHANGELOG.md
2019-08-08 14:50:22 -07:00
Aleksi Juvani
c0c22c8ff1 Disable overscan compensation for external displays on iOS (#1088) 2019-08-06 16:47:00 -04:00
YVT
73cf10e4f3 Do not require T: Clone for EventLoopProxy<T>: Clone (#1086)
* Do not require `T: Clone` for `EventLoopProxy<T>: Clone`

* Update `CHANGELOG.md`

* Remove the conflicting `Clone` impl

* Fix match statement
2019-08-05 16:51:42 -04:00
mtak-
8a1c5277eb iOS: update feature table (#1085) 2019-08-01 15:07:22 -06:00
Aleksi Juvani
1e4c176506 Fix armv7-apple-ios compile target (#1083) 2019-08-01 01:30:05 -06:00
mtak-
3c27e7d88f iOS: add support for controlling the home indicator, and Exclusive video mode (#1078)
* iOS: platform specific edge home indicator control

* iOS: exclusive video mode support

* address nits, and linkify all the ios documentation
2019-07-31 00:57:31 -06:00
Aleksi Juvani
5bc3cf18d9 Add exclusive fullscreen mode (#925)
* Add exclusive fullscreen mode

* Add `WindowExtMacOS::set_fullscreen_presentation_options`

* Capture display for exclusive fullscreen on macOS

* Fix applying video mode on macOS after a fullscreen cycle

* Fix compilation on iOS

* Set monitor appropriately for fullscreen on macOS

* Fix exclusive to borderless fullscreen transitions on macOS

* Fix borderless to exclusive fullscreen transition on macOS

* Sort video modes on Windows

* Fix fullscreen issues on Windows

* Fix video mode changes during exclusive fullscreen on Windows

* Add video mode sorting for macOS and iOS

* Fix monitor `ns_screen` returning `None` after video mode change

* Fix "multithreaded" example on macOS

* Restore video mode upon closing an exclusive fullscreen window

* Fix "multithreaded" example closing multiple windows at once

* Fix compilation on Linux

* Update FEATURES.md

* Don't care about logical monitor groups on X11

* Add exclusive fullscreen for X11

* Update FEATURES.md

* Fix transitions between exclusive and borderless fullscreen on X11

* Update CHANGELOG.md

* Document that Wayland doesn't support exclusive fullscreen

* Replace core-graphics display mode bindings on macOS

* Use `panic!()` instead of `unreachable!()` in "fullscreen" example

* Fix fullscreen "always on top" flag on Windows

* Track current monitor for fullscreen in "multithreaded" example

* Fix exclusive fullscreen sometimes not positioning window properly

* Format

* More formatting and fix CI issues

* Fix formatting

* Fix changelog formatting
2019-07-29 14:16:14 -04:00
Brian Kabiro
131e67ddc1 Rename new_user_event method to with_user_event (#1057) (#1068)
Finishes #1057
2019-07-29 08:58:16 -06:00
dam4rus
e5ba79db04 Process WM_SYSCOMMAND to forbid screen savers in fullscreen mode (#1065)
* Process WM_SYSCOMMAND to forbid screen savers in fullscreen mode

Fixes #1047

* Update CHANGELOG.md and documentation to reflect changes from issue #1065

* Updated documentation of window.Window.set_fullscreen to match the documentation of window.WindowBuilder.with_fullscreen.
2019-07-29 03:18:23 -06:00
t嘎
f4e9bf51db add macos with_disallow_hidpi (#1073)
* add macos with_disallow_hidpi

add CHANGELOG

* Always use stable rustfmt for CI. (#1074)

Signed-off-by: Hal Gentz <zegentzy@protonmail.com>

* add macos with_disallow_hidpi

add CHANGELOG
2019-07-29 02:07:36 -06:00
Hal Gentz
03f9e8fce0 Always use stable rustfmt for CI. (#1074)
Signed-off-by: Hal Gentz <zegentzy@protonmail.com>
2019-07-28 03:09:31 -06:00
Felix Rabe
4ae9900363 PULL_REQUEST_TEMPLATE.md: Add entry on warnings (#1017) 2019-07-26 01:14:48 -06:00
dam4rus
454d4190b7 Use himetric values in WM_POINTER events (#1053)
* Use himetric location for WM_POINTER events

* Ran rustfmt
2019-07-26 01:12:06 -06:00
Austin Lasher
a28b60578d Fix run_return example build error on non-desktop platforms (#1067) 2019-07-25 14:56:24 -04:00
Tilman Schmidt
5a206de620 macOS: Drop the closure on exit. (Fixes #1058) (#1063) 2019-07-23 14:44:06 -06:00
Simon Sapin
b547531499 Update the percent-encoding crate to 2.0 (#1066) 2019-07-23 13:38:45 -04:00
Murarth
39e668ffb0 Fix CHANGELOG.md (#1061) 2019-07-22 19:26:52 -06:00
Murarth
bd1ac6cb1e X11: Fix events not being reported promptly (#1048)
* X11: Fix events not being reported promptly

* Add an entry to the changelog
2019-07-17 14:09:02 -04:00
dam4rus
8567758156 Touch events emit screen coordinates instead of client coordinates on Windows (#1042)
* Touch events emit screen coordinates instead of client coordinates on Windows

Fixes #1002

* Don't lose precision of WM_TOUCH events when converting from screen space to client space

* Updated CHANGELOG.md to reflect changes from issue: #1042
2019-07-17 12:25:35 -04:00
Ryan G
e897d70733 Bump the stdweb version to 0.4.18 (#1049)
This removes the need to patch to a git version
2019-07-16 21:56:58 -06:00
Ryan Goldstein
fe12996382 Update the web backend todo list 2019-07-16 20:00:03 -07:00
Murarth
e8e4d4ce66 X11: Fix request_redraw deadlock while handling RedrawRequested (#1046) 2019-07-16 16:53:41 -06:00
Felix Rabe
44af4f4f52 Minor doc changes (#1024)
* Minor doc changes

* More typos
2019-07-12 19:05:07 -04:00
Murarth
7daf146801 Replace std::mem::uninitialized with MaybeUninit (#1027)
* Replace `std::mem::uninitialized` with `MaybeUninit`

* Avoid undefined behavior when using `MaybeUninit`

* Restore unused `PointerState` fields as internally public

* Zero-initialize some struct values in Xlib FFI calls

* Reform usage of `MaybeUninit` in Xlib FFI

* Prefer safe zero-initialization using `Default`, when possible
* Zero-initialize integers and floats using `0` or `0.0`
* Use `MaybeUninit::uninit` for large byte buffers and union types
* Use `MaybeUninit::uninit` when the resulting value is ignored
2019-07-11 10:34:32 -06:00
Héctor Ramón
7b23d190b1 Fix web errors (#1040)
* Fix old `use` declarations

* Fix hidden lifetime parameter

* Fix missing methods in `web::Monitor`.

Originally fixed by @ryanisaacg in 94387c4bf5.

* Disable some tests and examples on `wasm32`
2019-07-10 18:54:54 -04:00
Osspial
17b8310517 Update Windows Multitouch in FEATURES.md (#1039)
It seems we were already implementing multitouch on Windows, and the question mark was inaccurate.
2019-07-10 18:54:34 -04:00
Osspial
5ca828d445 Merge pull request #1031 from rikusalminen/event_loop_test
Add NewEvents(Init) callback to x11
2019-07-10 11:29:21 -04:00
Riku Salminen
1ea29b4de0 x11: NewEvents(StartCause::Init) callback at start
Before starting the event loop, invoke callback with
NewEvents(StartCause::Init).
2019-07-10 15:27:57 +03:00
Osspial
b00cdadb5b Merge pull request #991 from dam4rus/master
Handle WM_POINTER* events in favor of WM_TOUCH
2019-07-10 02:30:09 -04:00
Osspial
53e646dabc Merge pull request #1038 from ZeGentzy/web
Webmerge4
2019-07-10 02:17:21 -04:00
Hal Gentz
613fafdfdf Merge branch 'web' into webmerge2 2019-07-09 22:50:51 -06:00
Osspial
5d0bc5f607 Correct 0.20.0 Alpha 2 release date 2019-07-09 19:19:00 -04:00
Osspial
ce5cf97e17 Release Alpha 2 (#996) 2019-07-09 18:25:32 -04:00
Felix Rabe
3ee59696e5 Always use f as the argument name for &mut std::fmt::Formatter (#1023) 2019-07-09 17:49:07 -04:00
aloucks
f5c624bcd6 Handle RedrawRequested event in request_redraw example (#1030) 2019-07-08 22:22:10 -06:00
Kalmár Róbert
026b331ba5 Handle WM_POINTER* events in favor of WM_TOUCH
Fixes #975
2019-07-08 10:13:02 +02:00
Kalmar Robert
93c36ccf78 Handle WM_POINTER* events in favor of WM_TOUCH
Fixes #975.
2019-07-08 10:12:47 +02:00
Felix Rabe
c1f314ccdc MacOS: request_user_attention(bool -> enum) (#1021) 2019-07-07 14:14:00 -06:00
Felix Rabe
53a89f28a0 Remove dead code (unused as of d5391686a) (#1022) 2019-07-07 14:13:17 -06:00
Felix Rabe
f874d76289 Fix warnings (#1020)
* Windows: Fix warning

* iOS: Fix warning
2019-07-07 14:12:39 -06:00
Héctor Ramón Jiménez
76645f3b5a Bump version 2019-07-07 05:51:06 +02:00
Bradley Smith
28775be115 Fix transparent window with decorations (#1011)
* Fix transparent window with decorations

* To changelog, added fix for transparent decorated windows.
2019-07-06 13:29:15 -04:00
Felix Rabe
7d3ff3d2d9 Fix warning (#1016) 2019-07-06 13:28:50 -04:00
Osspial
4a5d639d74 On Windows, fix with_maximized not properly setting window size to entire window. (#1013) 2019-07-05 17:28:11 -04:00
Osspial
74a7cf55ea Fix issues with redraw_requested when called during EventsCleared (#994)
* Fix issues with redraw_requested when called during EventsCleared

* Format

* Fix event dispatch after RedrawRequested but before EventsCleared

This could happen if the event queue was cleared, we processed WM_PAINT,
but the event queue got re-filled before we checked to see it was empty.

* Fix paint ordering issues when resizing window

* Format
2019-07-04 16:14:15 -04:00
Murarth
9393b14b01 X11: Disable maximize on non-resizable windows (#1000)
* X11: Disable maximize on non-resizable windows

* Add a note for the source for Motif WM constants
2019-07-04 04:43:44 -06:00
Aleksi Juvani
f8bd671073 Remove Metal dependency on macOS (#1003) 2019-07-03 14:19:07 -04:00
Murarth
2af753f307 Fix warnings on Linux (#1004) 2019-07-03 14:18:42 -04:00
Héctor Ramón Jiménez
5cc84f32db Improve feature names to enable web backends 2019-07-01 20:43:54 +02:00
Héctor Ramón Jiménez
e89674d337 Add dyn keyword where necessary 2019-07-01 20:23:42 +02:00
Héctor Ramón Jiménez
de120280e3 Fix mouse release/press events 2019-06-29 17:48:22 +02:00
Héctor Ramón Jiménez
7f2ba0ee3e Fix set_cursor_icon 2019-06-29 17:48:01 +02:00
Michael Streif
5bf303fd26 Improve handling of file paths in the windows DnD handler (#980)
* Make FileDropHandler::iterate_filenames more robust

by replacing the call to mem::uninitialized with mem::zeroed and change
file name retrieval to use buffers of exact length as reported
by DragQueryFileW instead of relying on MAX_PATH.

* Change remaining calls of uninitialized to zeroed

* Run rustfmt

* Add CHANGELOG entry and comment
2019-06-28 18:07:36 -04:00
Felix Rabe
e37e46b155 Remove comment that contradicts code (#992) 2019-06-28 15:32:27 -04:00
Victor Berger
b8192ef6f6 Revert "wayland: use an invisible surface as shell surface (#835)" (#981)
This reverts commit 65587ef43a.

It introduced sublte bugs in its interaction with OpenGL and glutin,
so we should better revert it for now.
2019-06-28 15:31:54 -04:00
Ho-Yon Mak
23354cf1a5 Implement _NET_WM_PING for X11 (#977) 2019-06-27 18:40:27 -06:00
Felix Rabe
dd38fab2f3 examples/window_icon.rs: De-duplicate code (#988) 2019-06-27 11:59:13 -04:00
Tristam MacDonald
ac08601b40 Implement DeviceEvent::Button on Mac (#967)
* Add deviceevent logging to cursor_grab example

* Implement DeviceEvent::Button on Mac
2019-06-27 02:58:21 -04:00
Héctor Ramón Jiménez
ea73dac753 Fix feature names 2019-06-27 01:18:46 +02:00
Héctor Ramón Jiménez
2a35646520 Use latest stdweb revision 2019-06-27 00:23:58 +02:00
Héctor Ramón Jiménez
bb285984da Implement stdweb backend for web platform 2019-06-27 00:02:46 +02:00
Austin Lasher
34db2d7d4c Fix broken links to mod DPI on various documentation pages (#984) 2019-06-26 15:35:54 +02:00
chichid
0e20973bdb Fix 968: Invisible windows steal focus from visible windows Win32 (#968) 2019-06-26 00:04:49 -04:00
Murarth
29e2481597 Remove XFlush call in event loop (#982)
Internally, `XFlush` calls `_XSend` to write data. It then calls
`XEventsQueued(display, QueuedAfterReading)`, which reads data from the
X server connection. This prevents the event loop source callback from
being run, as there is no longer data waiting on the socket.

Ideally, we would want to call `_XSend` directly to ensure that no
output is buffered by Xlib. However, this function is not exported as
part of Xlib's public API.

Testing with the `XFlush` call removed does not appear to adversely
affect the performance of an application. If any bugs should eventually
arise from this change, perhaps another function may be used in place of
`XFlush`, such as `XPending`, which writes buffered output but does not
so aggressively read from the X server connection.

Closes #865
2019-06-25 15:29:52 -06:00
Héctor Ramón Jiménez
1596cc5d9e Avoid leaking implementation details in Canvas API 2019-06-25 21:36:24 +02:00
Héctor Ramón Jiménez
8f66d96915 Support ReceivedCharacter event 2019-06-25 21:18:11 +02:00
Héctor Ramón Jiménez
8ad078b964 Implement keyboard and blur/focus events 2019-06-25 21:01:13 +02:00
Héctor Ramón Jiménez
d5368d7979 Implement Canvas::request_redraw 2019-06-25 18:39:41 +02:00
Héctor Ramón Jiménez
9c5657b86c Remove Canvas when dropped 2019-06-25 18:19:22 +02:00
Héctor Ramón Jiménez
b79089ea57 Implement web_sys::Canvas event listeners 2019-06-25 18:07:47 +02:00
Cherser-s
3555de114a Wayland: Add relative pointer movement (#973)
* Add relative pointer movement for Wayland

* Format changed code with rustfmt

* Wayland: merge window and device event queues into one

* Replace map_or_else call for simplification
2019-06-25 03:00:41 -06:00
Héctor Ramón Jiménez
c5703eb00a Draft web platform structure 2019-06-25 03:15:34 +02:00
Austin Lasher
dbe6a1bcdf Update docs to differentiate DeviceEvents and WindowEvents (#976) 2019-06-24 17:30:06 -04:00
Héctor Ramón Jiménez
eea9530f38 Merge remote-tracking branch 'blm/web-sys' into stdweb-eventloop-2 2019-06-24 18:31:56 +02:00
Osspial
a195ce8146 Re-format on stable rustfmt (#974) 2019-06-24 12:14:55 -04:00
Ryan Goldstein
a0f280e71f Update how timeouts are cleared to avoid possible double-clearing 2019-06-23 14:38:35 -07:00
Ryan Goldstein
cf28751ae3 Remove unnecessary set-to-wait in example 2019-06-23 14:38:16 -07:00
Felix Rabe
9dd15d00d8 Update PULL_REQUEST_TEMPLATE.md (#969) 2019-06-23 14:05:37 -04:00
Felix Rabe
2442305bb7 Forward porting (#966)
* README: Use shields.io instead of Herokuapp (#859)

* README: Link to FEATURES.md and missing features wiki page (#860)

Closes #854

* Update URLs (#863)

* CHANGELOG.md: Add line from #861 (legacy) that is missing from equivalent #964 (EL 2)
2019-06-23 02:39:26 -04:00
Felix Rabe
063648368d CHANGELOG.md: Move entries for #805 to 0.19.1 (#965) 2019-06-22 13:57:56 -04:00
Osspial
918b2efce7 Improve the example in lib.rs (#957) 2019-06-22 13:26:06 -04:00
Abendstolz
2467a997f4 [#963] Change XRandR display size check to also take height into account (#964) 2019-06-22 18:48:51 +02:00
Felix Rabe
f457c6a0b8 Change Suspended(true/false) => Suspended/Resumed (#959) 2019-06-21 20:59:31 -06:00
Felix Rabe
1193cada46 Minor spelling changes (#960) 2019-06-21 18:34:55 -06:00
Felix Rabe
b0e09b8ffe Rephrase (#958) 2019-06-21 17:35:08 -06:00
Osspial
8d6e8bb8d1 Release 0.20.0 Alpha 1 (#913) 2019-06-21 11:33:44 -04:00
Osspial
e2c84725de Format everything and add rustfmt to travis (#951)
* Format everything and add rustfmt to travis

* Remove extern crate winit from examples and add force_multiline_blocks

* Format the code properly

* Fix inconsistent period in PULL_REQUEST_TEMPLATE.md

* Only run rustfmt on nightly

* Travis fixings
2019-06-21 11:33:15 -04:00
Ryan Goldstein
b571362bf1 Fix a panic due to double-borrow 2019-06-20 21:46:01 -07:00
Osspial
b1b5aefc4b Implement fix described in #851 (#945)
* Implement fix described in #851

* Add changelog entry
2019-06-20 23:59:27 -04:00
Osspial
06244dd492 Remove window resize call in timer example (#938)
* Remove window resize call in timer example

* Move timer_length to separate variable

* Re-add _window
2019-06-19 22:06:09 -04:00
Osspial
de2f0740f7 Move contributors table to wiki (#934)
* Add stub wiki link instead of inline table

* Replace with real link

* Update CONTRIBUTING.md

* Update CONTRIBUTING.md
2019-06-19 15:12:27 -04:00
Felix Rabe
c56a66cb90 Fix warnings (#929)
* Fix warnings

* Bring back derivatives crate for Windows
2019-06-19 15:12:01 -04:00
Felix Rabe
c1329ff156 Linkify HALL_OF_CHAMPIONS.md (#935) 2019-06-18 16:30:37 -06:00
Osspial
72509b5b42 Update example in README.md and add move prefix to window.rs example closure (#921)
* Update example in README.md and add move prefix to window.rs example

* Make Window and README example trivially capture window

* Update README.md
2019-06-18 11:15:55 -04:00
Aleksi Juvani
c35fdc8d61 Fix thread-safety of set_maximized and set_title on macOS (#922) 2019-06-18 00:34:27 -06:00
Ben Merritt
5d31f73302 Clean up Cargo.toml after incorrect rebase 2019-06-17 22:56:37 -07:00
Ben Merritt
7de1261555 Fix some warnings 2019-06-17 22:54:07 -07:00
Ben Merritt
91a511ba8c Replace JS snippet with throw_str 2019-06-17 22:54:07 -07:00
Ben Merritt
94f6294c0a Prevent callbacks from being destroyed too early 2019-06-17 22:54:07 -07:00
Ben Merritt
77cd3adb01 TEMPORARY: add testing example 2019-06-17 22:54:07 -07:00
Ben Merritt
7dabad4d71 Fix throwToEscapeEventLoop function 2019-06-17 22:51:23 -07:00
Ben Merritt
54b4074369 Port remaining modules to web_sys 2019-06-17 22:51:23 -07:00
Ben Merritt
e4d8e22846 Start implementing web-sys backend 2019-06-17 22:51:23 -07:00
Felix Rabe
403dcc02f4 CONTRIBUTING.md: Linkify project members (#933) 2019-06-17 16:52:30 -06:00
Felix Rabe
64be6e5c5e Typo (#932) 2019-06-17 16:22:01 -06:00
Felix Rabe
c661006683 Use dbg!() macro in monitor list example (#931) 2019-06-17 16:13:35 -06:00
CrLF0710
f879bca21c Migrate to 2018 edition. (#924)
* Migrate to 2018 edition.

* Use impl Iterator at one site.

* Fix more rust 2018 idioms.
2019-06-17 14:27:00 -04:00
Ryan Goldstein
182beb4f8b Indicate that I will be maintaing the stdweb backend 2019-06-16 21:34:54 -07:00
Ryan Goldstein
2690306f4a Implement Poll and WaitUntil in the stdweb backend 2019-06-16 21:30:05 -07:00
Ryan Goldstein
b59e3c670b WIP 2019-06-14 21:15:43 -07:00
Osspial
2e0bbc091f Set CHANGELOG.md merge style to union (#919) 2019-06-13 16:11:44 -04:00
Aleksi Juvani
91f05e940f Fix initial dimensions of a fullscreen window on Windows (#909) 2019-06-13 15:17:56 -04:00
Aleksi Juvani
db794b976c Disable caching on Travis (#918) 2019-06-13 14:24:44 -04:00
Victor Berger
9a11f90a02 x11/wayland: Don't reset control flow between loop ticks (#916) 2019-06-13 12:52:10 -04:00
Osspial
412516159f Document the caveats of run_return (#914) 2019-06-13 12:51:44 -04:00
Victor Berger
65587ef43a wayland: use an invisible surface as shell surface (#835)
This decorelates the window management from the actual user content,
meaning:

- the created window no longer needs the user to draw something to
  start existing
- it reduces our need to do roundtrips during initialization to
  avoid protocol errors
2019-06-13 12:50:02 -04:00
Osspial
cf713bef31 Remove CircleCI (#915)
None of the platforms that use it are supported right now, so it seems
silly to fail builds for other platforms when these ones can't possibly
succeed.

This should be reverted in stages as the platforms regain support.
2019-06-13 00:34:21 -06:00
Osspial
ea5c21950c Change Monitor dimensions functions to size functions (#911) 2019-06-13 00:33:44 -06:00
Aleksi Juvani
47b5dfa034 Support listing available video modes for a monitor (#896)
* Support listing available video modes for a monitor

* Use derivative for Windows `MonitorHandle`

* Update FEATURES.md

* Fix multiline if statement

* Add documentation for `VideoMode` type
2019-06-12 14:07:25 -04:00
Osspial
2b89ddec15 Fix WindowBuilder function names that missed first pass (#910) 2019-06-12 13:34:09 -04:00
Nikolai Vazquez
f256ff7d58 Make ns identifiers use snake_case on macOS (#904)
This makes the macOS API style consistent with that of iOS.
2019-06-10 19:09:38 -04:00
Christian Duerr
07356b9634 Update cursor visibility docs (#893)
The cursor visibility docs were still outdated from the rename and
talking about setting the invisibility, rather than visibility.

The platform-specific docs are unchanged since those should be fine and
the rest has been adapted using similar docs.
2019-06-01 18:06:41 -06:00
Ryan Goldstein
f2b6ef2edd Merge master into stdweb-eventloop-2
Update the internal APIs to match the new API changes
2019-06-01 13:21:50 -07:00
Ryan Goldstein
1409f83fb9 Add support for mouse wheel 2019-05-31 21:50:34 -07:00
Ryan Goldstein
37dadab745 Add access to the canvas in the Window 2019-05-31 21:50:25 -07:00
Osspial
0eefa3ba42 Fix compiler warning of potential undefined behavior (#892) 2019-05-30 20:42:53 -04:00
aloucks
08f8f89702 Fix control flow issues with Window::request_redraw (eventloop-2.0) (#890)
* Fix request_redraw with Poll and WaitUntil(time_in_the_past) on Windows

`Window::request_redraw` now fires a `RedrawRequested` event when
called from an `Event::EventsCleared` callback while the control
flow is set to `Poll`. A control flow of `WaitUntil(resume_time)`,
will now also fire the `RedrawRequested` event when `resume_time`
is in the past.

* Prevent panic on x11 when WaitUntil(resume_time) is in the past

* Prevent panic on wayland when WaitUntil(resume_time) is in the past
2019-05-29 22:33:52 -06:00
Osspial
0df436901a Refine function names and type signatures (#886)
* First name consistency pass. More to come!

* Remove multitouch variable (hopefully this compiles!)

* Remove CreationError::NotSupported

* Add new error handling types

* Remove `get_` prefix from getters.

This is as per the Rust naming conventions recommended in
https://rust-lang-nursery.github.io/api-guidelines/naming.html#getter-names-follow-rust-convention-c-getter

* Make changes to Window position and size function signatures

* Remove CreationError in favor of OsError

* Begin updating iOS backend

* Change MonitorHandle::outer_position to just position

* Fix build on Windows and Linux

* Add Display and Error implementations to Error types

* Attempt to fix iOS build.

I can't actually check that this works since I can't cross-compile to
iOS on a Windows machine (thanks apple :/) but this should be one of
several commits to get it working.

* Attempt to fix iOS errors, and muck up Travis to make debugging easier

* More iOS fixins

* Add Debug and Display impls to OsError

* Fix Display impl

* Fix unused code warnings and travis

* Rename set_ime_spot to set_ime_position

* Add CHANGELOG entry

* Rename set_cursor to set_cursor_icon and MouseCursor to CursorIcon

* Organize Window functions into multiple, categorized impls

* Improve clarity of function ordering and docs in EventLoop
2019-05-29 21:29:54 -04:00
Osspial
ae63fbdbbb Merge branch 'eventloop-2.0' of https://github.com/tomaka/winit into eventloop-2.0 2019-05-29 21:28:39 -04:00
Osspial
4f29618c73 I forgot to remove the backtrace dependency in the EL2 rework 2019-05-29 21:22:35 -04:00
Osspial
76660f3621 Fix Windows backend invoking unreachable! with Exit and run_return (#887) 2019-05-27 13:45:26 -04:00
mtak-
3a7350cbb9 El2.0 ios (#871)
* port ios winit el2.0 implementation to the new rust-windowing repo

* unimplemented! => unreachable
trailing comma in CFRunLoopTimerCallback

* implement get_fullscreen

* add iOS specific platform documentation. Add a TODO about how to possibly extend the iOS backend to work have methods callable from more than just the main thread

* assert that window is only dropped from the main thread

* assert_main_thread called from fewer places
2019-05-25 21:10:41 -04:00
aloucks
e5aa906b01 Fix macos compile error in fullscreen example (#885) 2019-05-25 15:23:54 -06:00
aloucks
4b0162a013 Update parking_lot to 0.8 (for windows, too) (#884)
The previous attempt to update parking_lot missed the windows platform.

The parking_lot dependency is now no longer specified twice to help
prevent that mistake from happening again.
2019-05-25 15:23:09 -06:00
Bastien Orivel
5be88e79b0 Update parking_lot to 0.8 (#882) 2019-05-25 10:12:07 -06:00
Lucas Kent
93502e0cda Fix warning (#880) 2019-05-24 05:10:31 -06:00
Osspial
8d6a857ba5 Merge branch 'evl2' into eventloop-2.0 2019-05-16 00:26:59 -04:00
Osspial
6ff1370035 Fix crash caused by WM_PAINT getting invoked at inopportune times. (#866) 2019-05-16 00:00:30 -04:00
Hal Gentz
d5391686ae Squashed commit of the following: (#853)
commit fa95f204d3c10ceca70e794870657a0f33349761
Author: Hal Gentz <zegentzy@protonmail.com>
Date:   Sun Apr 28 00:14:01 2019 -0600

    xrender

    Signed-off-by: Hal Gentz <zegentzy@protonmail.com>

commit b62cee51c7b22f6f150bfe04f9b28f024e641323
Merge: 3f021ea7 a6551f46
Author: Hal Gentz <zegentzy@protonmail.com>
Date:   Thu Apr 25 18:13:43 2019 -0600

    Merge branch 'macos-gentz' of github.com:ZeGentzy/winit into macos-gentz

commit 3f021ea7f7ac6bc2a697a5b6e4e6424e838a2139
Author: Hal Gentz <zegentzy@protonmail.com>
Date:   Thu Apr 25 18:04:02 2019 -0600

    Get rid of warnings.

    Signed-off-by: Hal Gentz <zegentzy@protonmail.com>

commit a6551f4607ea0bc26df8716dee8115371ef367db
Author: Hal Gentz <zegentzy@protonmail.com>
Date:   Thu Apr 25 07:40:56 2019 -0600

    Fix example

    Signed-off-by: Hal Gentz <zegentzy@protonmail.com>

commit cbfda6c57e9740b49d2b496bda43197f611cb48c
Author: Hal Gentz <zegentzy@protonmail.com>
Date:   Wed Apr 24 23:47:46 2019 -0600

    Fixes

    Signed-off-by: Hal Gentz <zegentzy@protonmail.com>

commit 86bc86f3d3add4a6125aa9b2eca79061c0dfcd91
Author: Hal Gentz <zegentzy@protonmail.com>
Date:   Wed Apr 24 23:39:19 2019 -0600

    Backport 9a23ec3c37 (diff-1d95fe39cdbaa708c975380a16c314cb)

    Signed-off-by: Hal Gentz <zegentzy@protonmail.com>

commit 742a688efe2f0eeacc2ffbf49b1157c4aaffccbd
Author: Hal Gentz <zegentzy@protonmail.com>
Date:   Wed Apr 24 23:09:14 2019 -0600

    Backports 45a4281413 (diff-1d95fe39cdbaa708c975380a16c314cb)

    Signed-off-by: Hal Gentz <zegentzy@protonmail.com>

commit 6c81f2a517d4e2d5ba2ff3eddca030bce972cb2a
Author: Hal Gentz <zegentzy@protonmail.com>
Date:   Wed Apr 24 23:05:57 2019 -0600

    Francesca's macos changes

    Also backports bfbcab3a01 (diff-1d95fe39cdbaa708c975380a16c314cb)

commit 7c2e1300c26a0634ad505ce72b90eb6dc2fdcac7
Author: Francesca Plebani <franplebani@gmail.com>
Date:   Wed Apr 24 20:58:26 2019 -0600

    Squashed commit of the following:

    commit 5f4aa9f01a719eef98c6d894801c20ee8f96d30f
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Fri Dec 21 17:14:14 2018 -0500

        Protect against reentrancy (messily)

    commit b75073a5b2a8d65ab8806a00ffee390752255c8c
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Fri Dec 21 15:15:27 2018 -0500

        Send resize events immediately

    commit 8e9fc01bd6b404f59488b130413f48e4e5f89b0d
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Fri Dec 21 16:07:43 2018 -0500

        Don't use struct for window delegate

    commit c6853b0c4a8fe357f463604bb879dc1be424860e
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Wed Dec 19 21:17:48 2018 -0500

        Split up util

    commit 262c46b148413130fa239099f1151c1f1bd5c13c
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Wed Dec 19 20:55:00 2018 -0500

        Use dispatch crate

    commit 63152c2f475794d1a36a5b3687c777664d7d5613
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Wed Dec 19 20:29:13 2018 -0500

        RedrawRequested

    commit 27e475c7c78b059fd9b5e8350cd26756eecdfc94
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Wed Dec 19 19:24:44 2018 -0500

        User events

    commit 157418d7dedace9c571e977d98ea92464c3188b2
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Tue Dec 18 22:38:05 2018 -0500

        Moved out cursor loading

    commit b4925641c973979a38743202b4269efe09ac43b4
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Tue Dec 18 21:32:12 2018 -0500

        Fixed a bunch of threading issues

    commit 4aef63dfb78dfaf38c83cb0e88d4ea9d8d0578a6
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Mon Dec 17 13:54:59 2018 -0500

        Wait works

    commit 72ed426c695df5dc410902263bd74188059b8ddd
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Fri Dec 14 20:49:10 2018 -0500

        Fixed drag and dropg

    commit 658209f4a20acd536218f41a01fb8cbbebc705e0
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Fri Dec 14 20:42:42 2018 -0500

        Made mutexes finer for less deadlock risk

    commit 8e6b9866084690da900c4d058e412cab8ebb30c4
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Fri Dec 14 16:45:06 2018 -0500

        Dump (encapsulate) everything into AppState

    commit d2dc83df15939d89301e2cff0ffa2d98c48b406f
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Thu Dec 13 17:36:47 2018 -0500

        All window events work!

    commit 7c7fcc98872b3c35bd7767b5c6235a74bc105e06
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Wed Dec 12 17:11:09 2018 -0500

        Very rough usage of CFRunLoop

    commit 3c7a52ff4df683b5b7e1751e4051ec445a818774
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Tue Dec 11 15:45:23 2018 -0500

        Fixed deadlocks

    commit b74c7fe1bcd173e9b0c0e004956c257e805bc2a2
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Mon Dec 10 18:59:46 2018 -0500

        Fix keyDown deadlock

    commit 3798f9c1a4bef2a3d1552f846b26efc31b1bbb6c
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Mon Dec 10 18:44:40 2018 -0500

        It builds!

    commit 8c8620214357714c5cd0b3beefda6704512e3f64
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Fri Dec 7 21:09:55 2018 -0500

        Horribly broken so far

    commit 8269ed2a92
    Author: Osspial <osspial@gmail.com>
    Date:   Mon Nov 19 23:51:20 2018 -0500

        Fix crash with runner refcell not getting dropped

    commit 54ce6a21a0
    Author: Osspial <osspial@gmail.com>
    Date:   Sun Nov 18 19:12:45 2018 -0500

        Fix buffered events not getting dispatched

    commit 2c18b804df
    Author: Osspial <osspial@gmail.com>
    Date:   Sun Nov 18 18:51:24 2018 -0500

        Fix thread executor not executing closure when called from non-loop thread

    commit 5a3a5e2293
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Nov 15 22:43:59 2018 -0500

        Fix some deadlocks that could occur when changing window state

    commit 2a3cefd8c5
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Nov 15 16:45:17 2018 -0500

        Document and implement Debug for EventLoopWindowTarget

    commit fa46825a28
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Nov 15 16:40:48 2018 -0500

        Replace &EventLoop in callback with &EventLoopWindowTarget

    commit 9f36a7a68e
    Author: Osspial <osspial@gmail.com>
    Date:   Wed Nov 14 21:28:38 2018 -0500

        Fix freeze when setting decorations

    commit d9c3daca9b
    Author: Osspial <osspial@gmail.com>
    Date:   Fri Nov 9 20:41:15 2018 -0500

        Fix 1.24.1 build

    commit 5289d22372
    Author: Osspial <osspial@gmail.com>
    Date:   Fri Nov 9 00:00:27 2018 -0500

        Remove serde implementations from ControlFlow

    commit 92ac3d6ac7
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Nov 8 23:46:41 2018 -0500

        Remove crossbeam dependency and make drop events work again

    commit 8299eb2f03
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Sep 13 22:39:40 2018 -0400

        Fix crash when running in release mode

    commit bb6ab1bb6e
    Author: Osspial <osspial@gmail.com>
    Date:   Sun Sep 9 14:28:16 2018 -0400

        Fix unreachable panic after setting ControlFlow to Poll during some RedrawRequested events.

    commit 5068ff4ee1
    Author: Osspial <osspial@gmail.com>
    Date:   Sun Sep 9 14:14:28 2018 -0400

        Improve clarity/fix typos in docs

    commit 8ed575ff4a
    Author: Osspial <osspial@gmail.com>
    Date:   Sun Sep 9 00:19:53 2018 -0400

        Update send test and errors that broke some examples/APIs

    commit bf7bfa82eb
    Author: Osspial <osspial@gmail.com>
    Date:   Wed Sep 5 22:36:05 2018 -0400

        Fix resize lag when waiting in some situations

    commit 70722cc4c3
    Author: Osspial <osspial@gmail.com>
    Date:   Wed Sep 5 19:58:52 2018 -1100

        When SendEvent is called during event closure, buffer events

    commit 53370924b2
    Author: Osspial <osspial@gmail.com>
    Date:   Sun Aug 26 21:55:51 2018 -0400

        Improve WaitUntil timer precision

    commit a654400e73
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Aug 23 21:06:19 2018 -0400

        Add CHANGELOG entry

    commit deb7d379b7
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Aug 23 20:19:56 2018 -0400

        Rename MonitorId to MonitorHandle

    commit 8d8d9b7cd1
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Aug 23 20:16:52 2018 -0400

        Change instances of "events_loop" to "event_loop"

    commit 0f34408763
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Aug 23 20:13:53 2018 -0400

        Improve docs for run and run_return

    commit fba41f7a7e
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Aug 23 19:09:53 2018 -0400

        Small changes to examples

    commit 42e8a0d2cf
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Aug 23 19:09:19 2018 -0400

        Improve documentation

    commit 4377680a44
    Author: Osspial <osspial@gmail.com>
    Date:   Wed Aug 22 23:01:36 2018 -0400

        Re-organize into module structure

    commit f20fac99f6
    Author: Osspial <osspial@gmail.com>
    Date:   Wed Aug 22 22:07:39 2018 -0400

        Add platform::desktop module with EventLoopExt::run_return

    commit dad24d086a
    Author: Osspial <osspial@gmail.com>
    Date:   Wed Aug 22 18:03:41 2018 -0400

        Rename os to platform, add Ext trait postfixes

    commit 7df59c60a0
    Author: Osspial <osspial@gmail.com>
    Date:   Wed Aug 22 17:59:36 2018 -0400

        Rename platform to platform_impl

    commit 99c0f84a9f
    Author: Osspial <osspial@gmail.com>
    Date:   Wed Aug 22 17:55:27 2018 -0400

        Add request_redraw

    commit a0fef1a5fa
    Author: Osspial <osspial@gmail.com>
    Date:   Mon Aug 20 01:47:11 2018 -0400

        Fully invert windows control flow so win32 calls into winit's callback

    commit 2c607ff87f
    Author: Osspial <osspial@gmail.com>
    Date:   Sun Aug 19 13:44:22 2018 -0400

        Add ability to send custom user events

    commit a0b2bb3695
    Author: Osspial <osspial@gmail.com>
    Date:   Fri Aug 17 17:49:46 2018 -0400

        Add StartCause::Init support, timer example

    commit 02f922f003
    Author: Osspial <osspial@gmail.com>
    Date:   Fri Aug 17 17:31:04 2018 -0400

        Implement new ControlFlow and associated events

    commit 8b8a7675ec
    Author: Osspial <osspial@gmail.com>
    Date:   Fri Jul 13 01:48:26 2018 -0400

        Replace windows Mutex with parking_lot Mutex

    commit 9feada206f
    Author: Osspial <osspial@gmail.com>
    Date:   Fri Jul 13 01:39:53 2018 -0400

        Update run_forever to hijack thread

    commit 2e83bac99c
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Jul 12 23:43:58 2018 -0400

        Remove second thread from win32 backend

    commit 64b8a9c6a5
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Jul 12 22:13:07 2018 -0400

        Rename WindowEvent::Refresh to WindowEvent::Redraw

    commit 529c08555f
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Jul 12 22:04:38 2018 -0400

        Rename EventsLoop and associated types to EventLoop

    Signed-off-by: Hal Gentz <zegentzy@protonmail.com>

    Co-authored-by: Hal Gentz <zegentzy@protonmail.com>

commit cfb929ba0a9e787f8bb1a6dae4e05e4c7776bc97
Author: Hal Gentz <zegentzy@protonmail.com>
Date:   Thu Apr 25 07:40:56 2019 -0600

    Fix example

    Signed-off-by: Hal Gentz <zegentzy@protonmail.com>

commit 68d3317ff58381d55f5f9bd3db0860d66544fe12
Author: Hal Gentz <zegentzy@protonmail.com>
Date:   Wed Apr 24 23:47:46 2019 -0600

    Fixes

    Signed-off-by: Hal Gentz <zegentzy@protonmail.com>

commit 02d1aae4db27df054b703aa935ca118f31e17123
Author: Hal Gentz <zegentzy@protonmail.com>
Date:   Wed Apr 24 23:39:19 2019 -0600

    Backport 9a23ec3c37 (diff-1d95fe39cdbaa708c975380a16c314cb)

    Signed-off-by: Hal Gentz <zegentzy@protonmail.com>

commit dd9de5a6d444a9ab17afe470f4cf2a57e3ed76ae
Author: Hal Gentz <zegentzy@protonmail.com>
Date:   Wed Apr 24 23:09:14 2019 -0600

    Backports 45a4281413 (diff-1d95fe39cdbaa708c975380a16c314cb)

    Signed-off-by: Hal Gentz <zegentzy@protonmail.com>

commit 533e2adc1d1e417742475786635848b1620e476c
Author: Hal Gentz <zegentzy@protonmail.com>
Date:   Wed Apr 24 23:05:57 2019 -0600

    Francesca's macos changes

    Also backports bfbcab3a01 (diff-1d95fe39cdbaa708c975380a16c314cb)

commit 73b52221080bd3a881ae3a58c2dbb19bc8d954c6
Author: Hal Gentz <zegentzy@protonmail.com>
Date:   Wed Apr 24 20:58:26 2019 -0600

    Squashed commit of the following:

    commit 5f4aa9f01a719eef98c6d894801c20ee8f96d30f
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Fri Dec 21 17:14:14 2018 -0500

        Protect against reentrancy (messily)

    commit b75073a5b2a8d65ab8806a00ffee390752255c8c
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Fri Dec 21 15:15:27 2018 -0500

        Send resize events immediately

    commit 8e9fc01bd6b404f59488b130413f48e4e5f89b0d
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Fri Dec 21 16:07:43 2018 -0500

        Don't use struct for window delegate

    commit c6853b0c4a8fe357f463604bb879dc1be424860e
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Wed Dec 19 21:17:48 2018 -0500

        Split up util

    commit 262c46b148413130fa239099f1151c1f1bd5c13c
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Wed Dec 19 20:55:00 2018 -0500

        Use dispatch crate

    commit 63152c2f475794d1a36a5b3687c777664d7d5613
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Wed Dec 19 20:29:13 2018 -0500

        RedrawRequested

    commit 27e475c7c78b059fd9b5e8350cd26756eecdfc94
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Wed Dec 19 19:24:44 2018 -0500

        User events

    commit 157418d7dedace9c571e977d98ea92464c3188b2
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Tue Dec 18 22:38:05 2018 -0500

        Moved out cursor loading

    commit b4925641c973979a38743202b4269efe09ac43b4
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Tue Dec 18 21:32:12 2018 -0500

        Fixed a bunch of threading issues

    commit 4aef63dfb78dfaf38c83cb0e88d4ea9d8d0578a6
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Mon Dec 17 13:54:59 2018 -0500

        Wait works

    commit 72ed426c695df5dc410902263bd74188059b8ddd
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Fri Dec 14 20:49:10 2018 -0500

        Fixed drag and dropg

    commit 658209f4a20acd536218f41a01fb8cbbebc705e0
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Fri Dec 14 20:42:42 2018 -0500

        Made mutexes finer for less deadlock risk

    commit 8e6b9866084690da900c4d058e412cab8ebb30c4
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Fri Dec 14 16:45:06 2018 -0500

        Dump (encapsulate) everything into AppState

    commit d2dc83df15939d89301e2cff0ffa2d98c48b406f
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Thu Dec 13 17:36:47 2018 -0500

        All window events work!

    commit 7c7fcc98872b3c35bd7767b5c6235a74bc105e06
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Wed Dec 12 17:11:09 2018 -0500

        Very rough usage of CFRunLoop

    commit 3c7a52ff4df683b5b7e1751e4051ec445a818774
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Tue Dec 11 15:45:23 2018 -0500

        Fixed deadlocks

    commit b74c7fe1bcd173e9b0c0e004956c257e805bc2a2
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Mon Dec 10 18:59:46 2018 -0500

        Fix keyDown deadlock

    commit 3798f9c1a4bef2a3d1552f846b26efc31b1bbb6c
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Mon Dec 10 18:44:40 2018 -0500

        It builds!

    commit 8c8620214357714c5cd0b3beefda6704512e3f64
    Author: Francesca Plebani <franplebani@gmail.com>
    Date:   Fri Dec 7 21:09:55 2018 -0500

        Horribly broken so far

    commit 8269ed2a92
    Author: Osspial <osspial@gmail.com>
    Date:   Mon Nov 19 23:51:20 2018 -0500

        Fix crash with runner refcell not getting dropped

    commit 54ce6a21a0
    Author: Osspial <osspial@gmail.com>
    Date:   Sun Nov 18 19:12:45 2018 -0500

        Fix buffered events not getting dispatched

    commit 2c18b804df
    Author: Osspial <osspial@gmail.com>
    Date:   Sun Nov 18 18:51:24 2018 -0500

        Fix thread executor not executing closure when called from non-loop thread

    commit 5a3a5e2293
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Nov 15 22:43:59 2018 -0500

        Fix some deadlocks that could occur when changing window state

    commit 2a3cefd8c5
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Nov 15 16:45:17 2018 -0500

        Document and implement Debug for EventLoopWindowTarget

    commit fa46825a28
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Nov 15 16:40:48 2018 -0500

        Replace &EventLoop in callback with &EventLoopWindowTarget

    commit 9f36a7a68e
    Author: Osspial <osspial@gmail.com>
    Date:   Wed Nov 14 21:28:38 2018 -0500

        Fix freeze when setting decorations

    commit d9c3daca9b
    Author: Osspial <osspial@gmail.com>
    Date:   Fri Nov 9 20:41:15 2018 -0500

        Fix 1.24.1 build

    commit 5289d22372
    Author: Osspial <osspial@gmail.com>
    Date:   Fri Nov 9 00:00:27 2018 -0500

        Remove serde implementations from ControlFlow

    commit 92ac3d6ac7
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Nov 8 23:46:41 2018 -0500

        Remove crossbeam dependency and make drop events work again

    commit 8299eb2f03
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Sep 13 22:39:40 2018 -0400

        Fix crash when running in release mode

    commit bb6ab1bb6e
    Author: Osspial <osspial@gmail.com>
    Date:   Sun Sep 9 14:28:16 2018 -0400

        Fix unreachable panic after setting ControlFlow to Poll during some RedrawRequested events.

    commit 5068ff4ee1
    Author: Osspial <osspial@gmail.com>
    Date:   Sun Sep 9 14:14:28 2018 -0400

        Improve clarity/fix typos in docs

    commit 8ed575ff4a
    Author: Osspial <osspial@gmail.com>
    Date:   Sun Sep 9 00:19:53 2018 -0400

        Update send test and errors that broke some examples/APIs

    commit bf7bfa82eb
    Author: Osspial <osspial@gmail.com>
    Date:   Wed Sep 5 22:36:05 2018 -0400

        Fix resize lag when waiting in some situations

    commit 70722cc4c3
    Author: Osspial <osspial@gmail.com>
    Date:   Wed Sep 5 19:58:52 2018 -1100

        When SendEvent is called during event closure, buffer events

    commit 53370924b2
    Author: Osspial <osspial@gmail.com>
    Date:   Sun Aug 26 21:55:51 2018 -0400

        Improve WaitUntil timer precision

    commit a654400e73
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Aug 23 21:06:19 2018 -0400

        Add CHANGELOG entry

    commit deb7d379b7
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Aug 23 20:19:56 2018 -0400

        Rename MonitorId to MonitorHandle

    commit 8d8d9b7cd1
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Aug 23 20:16:52 2018 -0400

        Change instances of "events_loop" to "event_loop"

    commit 0f34408763
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Aug 23 20:13:53 2018 -0400

        Improve docs for run and run_return

    commit fba41f7a7e
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Aug 23 19:09:53 2018 -0400

        Small changes to examples

    commit 42e8a0d2cf
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Aug 23 19:09:19 2018 -0400

        Improve documentation

    commit 4377680a44
    Author: Osspial <osspial@gmail.com>
    Date:   Wed Aug 22 23:01:36 2018 -0400

        Re-organize into module structure

    commit f20fac99f6
    Author: Osspial <osspial@gmail.com>
    Date:   Wed Aug 22 22:07:39 2018 -0400

        Add platform::desktop module with EventLoopExt::run_return

    commit dad24d086a
    Author: Osspial <osspial@gmail.com>
    Date:   Wed Aug 22 18:03:41 2018 -0400

        Rename os to platform, add Ext trait postfixes

    commit 7df59c60a0
    Author: Osspial <osspial@gmail.com>
    Date:   Wed Aug 22 17:59:36 2018 -0400

        Rename platform to platform_impl

    commit 99c0f84a9f
    Author: Osspial <osspial@gmail.com>
    Date:   Wed Aug 22 17:55:27 2018 -0400

        Add request_redraw

    commit a0fef1a5fa
    Author: Osspial <osspial@gmail.com>
    Date:   Mon Aug 20 01:47:11 2018 -0400

        Fully invert windows control flow so win32 calls into winit's callback

    commit 2c607ff87f
    Author: Osspial <osspial@gmail.com>
    Date:   Sun Aug 19 13:44:22 2018 -0400

        Add ability to send custom user events

    commit a0b2bb3695
    Author: Osspial <osspial@gmail.com>
    Date:   Fri Aug 17 17:49:46 2018 -0400

        Add StartCause::Init support, timer example

    commit 02f922f003
    Author: Osspial <osspial@gmail.com>
    Date:   Fri Aug 17 17:31:04 2018 -0400

        Implement new ControlFlow and associated events

    commit 8b8a7675ec
    Author: Osspial <osspial@gmail.com>
    Date:   Fri Jul 13 01:48:26 2018 -0400

        Replace windows Mutex with parking_lot Mutex

    commit 9feada206f
    Author: Osspial <osspial@gmail.com>
    Date:   Fri Jul 13 01:39:53 2018 -0400

        Update run_forever to hijack thread

    commit 2e83bac99c
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Jul 12 23:43:58 2018 -0400

        Remove second thread from win32 backend

    commit 64b8a9c6a5
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Jul 12 22:13:07 2018 -0400

        Rename WindowEvent::Refresh to WindowEvent::Redraw

    commit 529c08555f
    Author: Osspial <osspial@gmail.com>
    Date:   Thu Jul 12 22:04:38 2018 -0400

        Rename EventsLoop and associated types to EventLoop

    Signed-off-by: Hal Gentz <zegentzy@protonmail.com>

commit ab1dfaaaa53a3acd206bf494ac90e3fe130dc609
Author: Hal Gentz <zegentzy@protonmail.com>
Date:   Tue Apr 23 21:52:17 2019 -0600

    Minor

    Signed-off-by: Hal Gentz <zegentzy@protonmail.com>

commit 7933209d60
Author: Victor Berger <victor.berger@m4x.org>
Date:   Thu Apr 18 09:10:41 2019 +0200

    wayland/x11: Make ControlFlow::Exit sticky

commit 8355a7513e
Author: Victor Berger <victor.berger@m4x.org>
Date:   Tue Apr 16 12:21:33 2019 +0200

    x11: Implement run_return using calloop

commit f64edb60cc
Author: Victor Berger <victor.berger@m4x.org>
Date:   Tue Apr 16 10:42:04 2019 +0200

    x11: port to evl2 with stubs

commit be372898dd
Author: Victor Berger <victor.berger@m4x.org>
Date:   Mon Apr 15 17:35:59 2019 +0200

    Fix compilation on Linux.

Signed-off-by: Hal Gentz <zegentzy@protonmail.com>

Co-authored-by: Francesca Plebani <franplebani@gmail.com>
2019-05-13 22:20:51 -04:00
Ryan Goldstein
70c7382a09 Fix the request_animation_frame lifetimes 2019-05-01 21:20:54 -04:00
Ryan Goldstein
9f801cf79e Only send the request-redraw on the next animation frame 2019-04-29 15:39:43 -04:00
acheronfail
062e0e52ee Feat/fullscreen getters (#838)
* feat: [macos] add get_fullscreen and get_simple_fullscreen

* feat: [windows] add get_fullscreen

* feat: [ios] add get_fullscreen

* feat: [android] add get_fullscreen

* feat: [emscripten] add get_fullscreen

* feat: [linux] add get_fullscreen

* feedback: `get_fullscreen() -> bool` -> `get_fullscreen() -> Option<Id>`
2019-04-27 20:29:55 +02:00
Osspial
fa99b9ff5a Fix CI links in README.md (#852) 2019-04-27 18:29:02 +02:00
Felix Rabe
8f6e80917f Popup windows are also known as modal windows (#848) 2019-04-27 18:28:51 +02:00
Osspial
e087ebd1c7 Makes changes to CONTRIBUTING.md's table as discussed in #830 (#841)
This includes de-listing @francesca64 from the table, as I suggested. I
realize that this is a controversial decision, and it's not a decision I
make lightly, but I believe I have justification for doing so:

I contacted @francesca64 last month asking her about her inactivity as a
maintainer on this project. She replied on March 26th as follows. For the
sake of her privacy, I've removed removed certain sections of her response,
as it contains some personal details that I'm not comfortable sharing with
the world at large without her explicit permission.

> Hello! Thanks for reaching out!❤

> In short, I've moved on. <removed> ...in November, I was hired by a
> company that recently started using Rust. I'm very happily building
> infrastructure there!

> I'm simply not interested in spending more than 8 hours a day
> programming. You couldn't even pay me to do it! My time is best spent
> going on adventures with my beloved.

> I'll still be active in the Rust ecosystem, but only insofar as the
> company I work for is. We use winit on iOS, Android, and (to a limited
> extent) macOS, so I'll work on those backends as needed.

> Thank you for taking care of winit. I hope you're taking care of
> yourself too; <removed>.

I don't begrudge her for her decision, and others shouldn't either - I
firmly believe that, as this is unpaid, volunteer work, everybody should
have the right to move on when they decide they no longer have the time
or will to contribute.

The exact impliciation of this in regards to her status as maintainer
is open to interpretation. I would argue that this means, should she in
her work stumble upon an issue in any of her listed backends, she would be
willing to submit PRs addressing those issues. However, it also means
that she is not able to put in the time to be active as a maintainer on
those platforms, or review PRs and issues for those platforms.

On March 28th I responded to her email as follows:

> Hey, thanks for responding.

> <removed, personal details>

> In the meanwhile, there are still a few loose ends from your time as
> maintainer that I'd like to get cleaned up. It's okay if you aren't
> going to be spending much time on Winit, but there's still a broad
> assumption that you're able to review PRs for them and that doesn't seem
> to be the case. Would you be able to do a couple things to ease the
> transition to whoever next takes over the macOS, X11, and Android
> backends?

> 1) Submit a PR downgrading yourself from maintainer for macOS, X11, and
>    Android, so somebody else can more actively take them over.
> 2) Post your WIP macOS backend for EL2.0 as well as the issues it
>    currently has, so whoever next maintains macOS can finish it.

> Going forward, I'd like to reach out to the broader Rust community and
> find more active maintainers so Winit can get to 1.0 and I can mostly
> move on from it.

I recieved no response to that email. On April 4th, I followed up on
that email:

> If you aren't able to act as a maintainer for Winit, and aren't able to
> submit a PR updating your official status as maintainer to reflect
> reality, would you mind if I submitted a PR removing you as maintainer?
> That's not something I want to do since it's a bad image for me, a bad
> image for Winit, and sets an extremely uncomfortable precedent, but I'd
> like to start more aggressive outreach to ensure each backend is less
> dependent on one specific person and I don't want to see new
> contributors pinging you for help when you're unable to provide it.

> If you don't reply by the 11th that's the path I'm going to take, but I
> consider it the nuclear option and I want to avoid invoking it if at all
> possible.

Up to this date (April 13th), I have recieved no response. Given the
amount of time I've given her to respond, as well as her lack of
response, I believe we have the justification to remove her from the
table. Should she show back up again, any clarifications on her status
would be welcome, and she is welcome to submit a PR re-listing herself
on the table with a more accurate description of her current contributor
status. However, once we begin the contributor marketing push discussed
in #830, I don't want new contributors to attempt to ask her questions
on the macOS, X11, or Android backends when she isn't able to give a
response.

-----------------------------------------------------------------------

This PR also introduces HALL_OF_CHAMPIONS.md, which commends the efforts
of former maintainers that have contributed greatly to the Winit project.
This wasn't discussed previously, but I think it's important to recognize
the people that brought us to where we are today. It currently lists
@tomaka and @francesca64, as they are the two individuals I'm aware of
that both deserve such recognition and no longer actively contribute to
Winit, but if there's anybody I missed feel free to suggest them and a
blurb describing their work.
2019-04-27 18:28:40 +02:00
Osspial
0d3e75d6b0 Fix TODO in CONTRIBUTING.md 2019-04-27 18:28:32 +02:00
Osspial
873f7bcec7 Fix link in PULL_REQUEST_TEMPLATE.md 2019-04-27 18:28:20 +02:00
Osspial
e579a03035 Winit Features and Scope (#695)
* Add initial draft of SCOPE document

* Rephrase/rename feature tiers

* Rename to FEATURES and add a few annotations

* Fix API Reworks table

* Add more annotations

* Some phrasing

* Split compat matrix into seperate section, to be moved into wiki

* Mention compatibility in CONTRIBUTING

* Remove some discuss annotations

* Apply review changes and rename child windows feature to popup windows

* Update based on discussion

* Add issue for Android HiDPI

* Update FEATURES.md

* Update FEATURES.md

* Update PULL_REQUEST_TEMPLATE.md

* Update PULL_REQUEST_TEMPLATE.md

* Reformat FEATURES.MD

* Remove comments

* Improve formatting and add guide for extending #Features
2019-04-27 18:28:10 +02:00
Victor Berger
94f998af0a Port X11 backend to the EVL2.0 API (#842)
* Fix compilation on Linux.

* x11: port to evl2 with stubs

* x11: Implement run_return using calloop

* wayland/x11: Make ControlFlow::Exit sticky

* x11: Send LoopDestroyed on exit

* x11: Fix RedrawRequested semandics

* wayland: Fix RedrawRequested semandics

* x11/wayland: reduce code duplication for sticky callback
2019-04-27 18:06:51 +02:00
Ryan Goldstein
fe5e300062 Clean up and document the core of stdweb event handling 2019-04-25 00:02:13 -04:00
aloucks
2253565db5 Prevent the event loop from pausing when entering modal loop (eventloop-2.0) (#839)
* Prevent the event loop from pausing after entering modal loop

After clicking the window title bar or border (for a drag or resize),
the event loop pauses until the mouse is moved. This change relays
the WM_NCLBUTTONDOWN message to the dummy window where it queues
a redraw and consumes the message. This effectively jumpstarts
the modal loop and it continues to fire draw requests.

* Handle WM_NCLBUTTONDOWN in public_window_callback instead of relaying.

Relaying the WM_NCLBUTTONDOWN message to the modal window turned out
to be unnecessary.
2019-04-14 11:48:31 -04:00
Osspial
2ead1c1c59 Update for 0.19.1 (#823) 2019-04-08 08:35:36 +02:00
Hal Gentz
746e99c958 Add ability to get wayland display from events loop. (#829)
Signed-off-by: Hal Gentz <zegentzy@protonmail.com>
2019-04-08 08:34:49 +02:00
Osspial
47194b5f3c Fix window icon (#831)
* Fix window icon

* Add CHANGELOG entry
2019-04-08 08:30:37 +02:00
mitchmindtree
4515b77aa5 [Rebased] [x11-backend] Retrieve DPI from Xft.dpi XResource (#824)
* [x11-backend] Retrieve DPI from Xft.dpi XResource

* Update CHANGELOG.md

* Update window.rs

* Update CHANGELOG.md
2019-04-08 08:30:09 +02:00
Christian Duerr
20b09c4514 Add additional numpad key mappings (#805)
* Add additional numpad key mappings

Since some platforms have already used the existing `Add`, `Subtract`
and `Divide` codes to map numpad keys, the X11 and Wayland platform has
been updated to achieve parity between platforms. On macOS only the
`Subtract` numpad key had to be added.

Since the numpad key is different from the normal keys, an alternative
option would be to add new `NumpadAdd`, `NumpadSubtract` and
`NumpadDivide` actions, however I think in this case it should be fine
to map them to the same virtual key code.

* Add Numpad PageUp/Down, Home and End on Wayland
2019-04-07 16:41:52 +02:00
TakWolf
9874181ccd fix command key event left and right reverse on macOS (#810)
* fix command key event left and right reverse on macOS

https://github.com/tomaka/winit/issues/808

* update changelog
2019-04-07 16:41:52 +02:00
Tobias Kortkamp
cb93554938 Fix build on FreeBSD (#815)
* Fix build on FreeBSD

error[E0432]: unresolved import `libc::__errno_location`
  --> src/platform/linux/x11/mod.rs:22:85
   |
22 | use libc::{select, fd_set, FD_SET, FD_ZERO, FD_ISSET, EINTR, EINVAL, ENOMEM, EBADF, __errno_location};
   |                                                                                     ^^^^^^^^^^^^^^^^ no `__errno_location` in the root

__errno_location is called __error on FreeBSD and __errno on Open- and NetBSD.

Signed-off-by: Tobias Kortkamp <t@tobik.me>

* Import __error / __errno on *BSD as __errno_location

Signed-off-by: Tobias Kortkamp <t@tobik.me>

* Add changelog entry

Signed-off-by: Tobias Kortkamp <t@tobik.me>
2019-04-07 16:41:52 +02:00
Hal Gentz
6b7bd32c8e Add contact info. (#818)
Signed-off-by: Hal Gentz <zegentzy@protonmail.com>
2019-04-07 16:41:52 +02:00
Osspial
17a240cd43 On Windows, fix CursorMoved(0, 0) getting sent on focus (#819)
* On Windows, fix CursorMoved(0, 0) getting sent on focus

* Add changelog entry
2019-04-07 16:41:52 +02:00
Osspial
fc481b6d6d Update winit to 0.19.0 (#798)
* Update winit to 0.19.0

* Update date for 0.19
2019-04-07 16:41:52 +02:00
Hal Gentz
09182dc093 Use XRRGetScreenResourcesCurrent when avail. (#801)
* Use `XRRGetScreenResourcesCurrent` when avail.

Signed-off-by: Hal Gentz <zegentzy@protonmail.com>

* Changelog

Signed-off-by: Hal Gentz <zegentzy@protonmail.com>
2019-04-07 16:41:52 +02:00
Osspial
b682c3dfb5 Ignore the AltGr key when populating ModifersState (#763)
* When building ModifiersState, ignore AltGr on Windows

* Add CHANGELOG entry

* Also filter out Control when pressing AltGr
2019-04-07 16:41:52 +02:00
Riku Salminen
ab0a34012f x11: thread safe replacement for XNextEvent (#782)
XNextEvent will block for input while holding the global Xlib mutex.

This will cause a deadlock in even the most trivial multi-threaded
application because OpenGL functions will need to hold the Xlib mutex
too.

Add EventsLoop::poll_one_event and EventsLoop::wait_for_input to provide
thread-safe functions to poll and wait events from the X11 event queue
using unix select(2) and XCheckIfEvent.

This is a somewhat ugly workaround to an ugly problem.

Fixes #779
2019-04-07 16:41:52 +02:00
Michael Palmos
f000b82d74 Fix incorrect keycodes when using a non-US keyboard layout. (#755)
* Fix incorrect keycodes when using a non-US keyboard layout.

This commit fixes the issue described in #752, and uses the advised
method to fix it.

* Style fixes

Co-Authored-By: Toqozz <toqoz@hotmail.com>

* Refactoring of macOS `virtualkeycode` fix (#752)

* Applies requested changes as per pull request discussion (#755).
2019-04-07 16:41:52 +02:00
Torkel Danielsson
dad8de82fa Handle horizontal wheel input (Windows) (#792)
* add handler for horizontal wheel input

* add changlelog message re now handling horiz scroll on windows
2019-04-07 16:41:51 +02:00
trimental
3fea477bfd On wayland, fix with_title() not setting the windows title (#770) 2019-04-07 16:39:55 +02:00
Victor Berger
f7d7acb3c5 Cleanup some previous merge errors 2019-04-07 15:58:47 +02:00
Ryan Goldstein
9e25561edf Fix compile failures and add canvas positioning 2019-04-02 22:31:30 -04:00
Ryan Goldstein
7c6bdcc459 Handle ControlFlow::Exit and dealing with events-in-events 2019-03-22 22:15:49 -04:00
Ryan Goldstein
b09629f1d4 Handle ControlFlow::Exit 2019-03-18 22:13:30 -04:00
Ryan Goldstein
85446d81f3 Fix warnings 2019-03-16 18:51:11 -04:00
Ryan Goldstein
96786bbb87 Implement focus event 2019-03-16 18:44:13 -04:00
Ryan Goldstein
a5166baba2 Implement request_redraw 2019-03-16 18:40:35 -04:00
Ryan Goldstein
d1deba8620 Rename modules 2019-03-11 22:22:21 -04:00
Ryan Goldstein
aaee72422a Rearchitect to allow API compliance 2019-03-11 22:18:58 -04:00
Ryan Goldstein
3dd0e31cc4 Merge eventloop-2.0 into stdweb-eventloop-2 2019-03-11 15:52:04 -04:00
Ryan Goldstein
283a8dec37 Refactor out the stdweb functionality into different modules 2019-03-09 22:23:39 -05:00
Ryan Goldstein
37d354cf7f Get to a state where a canvas is spawned 2019-03-09 21:54:29 -05:00
Ryan Goldstein
f698d451df Add key and mouse event support that typechecks 2019-03-02 12:31:16 -05:00
Ryan Goldstein
c088f8bd03 Create the outline of event input and handler calls 2019-02-26 13:36:48 -05:00
Osspial
3cd40ef655 Remove icon loading feature (#799) 2019-02-23 20:59:00 -05:00
Victor Berger
6513351e0c Wayland's eventloop 2.0 (#790)
* match unix common API to evl 2.0

* wayland: eventloop2.0

* make EventLoopProxy require T: 'static

* Fix linux build and tests

* wayland: update sctk & small fixes
2019-02-21 10:51:43 +01:00
Ryan Goldstein
f44e98ddc9 Implemented a few easy methods 2019-02-19 20:08:18 -05:00
Ryan Goldstein
fd4db4000c Create the type layout
Everything typechecks, but nothing is implemented
2019-02-12 20:47:31 -05:00
Osspial
9602716ed2 Event Loop 2.0 API and Windows implementation (#638)
* Rename EventsLoop and associated types to EventLoop

* Rename WindowEvent::Refresh to WindowEvent::Redraw

* Remove second thread from win32 backend

* Update run_forever to hijack thread

* Replace windows Mutex with parking_lot Mutex

* Implement new ControlFlow and associated events

* Add StartCause::Init support, timer example

* Add ability to send custom user events

* Fully invert windows control flow so win32 calls into winit's callback

* Add request_redraw

* Rename platform to platform_impl

* Rename os to platform, add Ext trait postfixes

* Add platform::desktop module with EventLoopExt::run_return

* Re-organize into module structure

* Improve documentation

* Small changes to examples

* Improve docs for run and run_return

* Change instances of "events_loop" to "event_loop"

* Rename MonitorId to MonitorHandle

* Add CHANGELOG entry

* Improve WaitUntil timer precision

* When SendEvent is called during event closure, buffer events

* Fix resize lag when waiting in some situations

* Update send test and errors that broke some examples/APIs

* Improve clarity/fix typos in docs

* Fix unreachable panic after setting ControlFlow to Poll during some RedrawRequested events.

* Fix crash when running in release mode

* Remove crossbeam dependency and make drop events work again

* Remove serde implementations from ControlFlow

* Fix 1.24.1 build

* Fix freeze when setting decorations

* Replace &EventLoop in callback with &EventLoopWindowTarget

* Document and implement Debug for EventLoopWindowTarget

* Fix some deadlocks that could occur when changing window state

* Fix thread executor not executing closure when called from non-loop thread

* Fix buffered events not getting dispatched

* Fix crash with runner refcell not getting dropped

* Address review feedback

* Fix CHANGELOG typo

* Catch panics in user callback
2019-02-05 10:30:33 -05:00
Osspial
7be1d16263 Refactor win32 window state code (#730)
* Overhaul win32 window state

* Fix warnings

* Add CHANGELOG entry

* Rephrase CHANGELOG entries

* Fix 1.28.0 build

* Remove WS_POPUP styling

* Slight style correction

* Make set_maximized work

* Fix rect restore not working after winit set_maximized call

* Add a few comments
2019-02-04 11:52:00 -05:00
trimental
c91dfdd6fe Wayland: add set_wayland_theme() to control client decoration color… (#775)
* Wayland: add `set_wayland_theme()` to control client decoration color theme

* Change &mut self to &self

* Remove endianness comment
2019-01-29 11:04:15 +01:00
Anthony Ramine
8e733543cd Update image to 0.21 (#758) 2019-01-16 14:36:46 -05:00
Sascha Grunert
26e37590e8 Allow serialization for WindowType (#762)
* Allow serialization for WindowType

* Update CHANGELOG.md

* Update CHANGELOG.md

Co-Authored-By: saschagrunert <sgrunert@suse.com>
2019-01-15 09:30:02 -08:00
Osspial
ddf133dd66 Version 0.18.1 (#749)
* Version 0.18.1

* Change to 0.18.1
2019-01-09 03:16:41 -11:00
Osspial
4584e7629a Remove MSRV guarantee (#746)
* Remove MSRV guarantee

* Update CHANGELOG
2018-12-29 15:02:02 -11:00
Francesca Plebani
139686ddce macOS: Improve set_cursor (#740)
* Improve set_cursor on macOS

* Check for nil
2018-12-28 15:29:29 -05:00
Francesca Plebani
5a0b4dba47 macOS: Implement Refresh (#742)
* macOS: Implement Refresh

* drawRect should take NSRect
2018-12-27 15:16:58 -05:00
Francesca Plebani
33c8aa660f macOS: Correct prepareForDragOperation: signature (#741) 2018-12-27 14:22:00 -05:00
Francesca Plebani
cb76dcae2a Change francesca64 to maintainer for macOS and Android (#744) 2018-12-24 13:08:33 -05:00
Bastien Orivel
d622de4797 Update parking_lot to 0.7 (#747) 2018-12-23 06:12:11 -11:00
Jacob Kiesel
9ae75c0c03 Add support for generating dummy DeviceIDs and WindowIDs (#738)
* Add support for generating dummy DeviceIDs and WindowIDs

* Fix linux

* Improve docs and move dummy to unsafe

* Strengthen guarantees a bit

* Add backticks to CHANGELOG.md

Co-Authored-By: Xaeroxe <xaeroxe@amethyst-engine.org>
2018-12-21 05:51:48 -11:00
Alisue
45a4281413 Support Yen in macOS (#739)
* Support Yen in macOS

* Add entry to CHANGELOG
2018-12-19 13:32:14 -05:00
acheronfail
bfbcab3a01 feat: add macos simple fullscreen (#692)
* feat: add macos simple fullscreen

* move impl to WindowExt

* feedback: remove warning, unused file and rename param

* feedback: combine fullscreen examples into one example

* fix: ensure decorations and maximize do not toggle while in fullscreen

* fix: prevent warning on non-macos platforms

* feedback: make changelog more explicit

* fix: prevent unconditional construction of NSRect

* fix: don't try to set_simple_fullscreen if already using native fullscreen

* fix: ensure set_simple_fullscreen plays nicely with set_fullscreen

* fix: do not enter native fullscreen if simple fullscreen is active
2018-12-18 23:07:33 -05:00
Jasper Mattsson
4b4c73cee4 Fix high CPU usage on tiling WMs when moving windows across monitors (#737)
This commit restricts an Xfwm4-specific DPI-preserving hack to Xfwm4
only. The hack saves and restores the DPI-adjusted size until the actual
size matches. On tiling WMs like i3 this fails, since the size is
constrained by the layout. This in turn causes a never-ending
XResizeWindow vs. XConfigureWindow fight between the WM and the client,
making the WM, winit client, and Xorg consume all CPU cycles available.
2018-12-18 22:20:31 -05:00
David Craven
fd349f1822 Use smithay-client-toolkit's dpi handling. (#724)
* Use smithay-client-toolkit's dpi handling.

* Add CHANGELOG entry.
2018-12-10 14:55:40 -05:00
Francesca Plebani
cb0a085968 X11: WindowBuilder min/max size accounts for DPI (#729) 2018-11-30 16:19:50 -05:00
Osspial
aabf0e13b7 On Windows, fix window shrinking when leaving fullscreen in some situations (#718)
* Fix resize border appearing in some cases after leaving fullscreen.

* On fullscreen, save client rect instead of window rect

* Add CHANGELOG entry

* Revert test changes to fullscreen example

* Update panic message when unable to get client area
2018-11-20 15:57:06 -05:00
Andreas Johansson
92873b06ed Handle removed wl_outputs (#719)
* Move the event managent to the closure

In preparation of more events not relating to the SeatManager being
captured.

* Handle wl_output remove events

In some cases, wl_outputs can be removed without the compositor
notifying the surfaces using leave/enter events. This breaks the DPI and
resize stuff since the windows' list of monitors were not updated.

Now, wl_output removals are handled and windows are updated accordingly.

* Add changelog entry for disappearing wl_outputs

* Clearer changelog message for wl_output removal changes
2018-11-20 15:21:58 -05:00
Artúr Kovács
04ca2cf9f4 Fix panic when dragging text onto a window on Windws (#697) (#711)
* Fix panic when dragging text onto a window on Windws (#697)

* Changed `panic` to `debug` (log) when unknow error occurs in `GetData` while processing a drag-drop / hover event. Plus added appropriate cursor effect if hovered item can not be processed.

* Improved code clarity.

* Add documentation to clarify behaviour of `DroppedFile`, `HoveredFile`, and `HoveredFileCancelled`

* Add period at the end of sentences in documentation.
2018-11-20 03:28:26 -05:00
Oskar Gustafsson
b049a4dc66 Add ordering traits to VirtualKeyCode (#713)
Motivation:
This allows VirtualKeyCode variants to be stored in a BTreeSet.
Unlike HashSets, BTreeSets implement Ord and Hash, allowing them to be
keys in a {Hash|BTree}Maps. This is nice, e.g. when implementing
keyboard shortcuts functionality, which maps a set of pressed keys to
some action.
2018-11-19 16:59:04 -05:00
Francesca Plebani
5be52c9753 Increase MSRV to 1.28.0 (#716) 2018-11-19 16:56:11 -05:00
Francesca Plebani
3c59283b3f X11: Check if XRRGetOutputInfo returned NULL (#709)
* X11: Check if XRRGetOutputInfo returned NULL

Fixes #693

* Change X11 error logging to actually use log
2018-11-17 15:51:39 -05:00
Osspial
3ba808e3c6 On Windows, catch window callback panics and forward them to the calling thread (#703)
* Catch windows callback panics

* Unwind through calling thread

* Add CHANGELOG entry

* Fix 1.24.1 builds

* Reformat CHANGELOG entry

* Make changes from review

* Wrap thread event target in panic catcher, reformat panic resume message

* Fix me being bad at git
2018-11-17 14:20:04 -05:00
Osspial
df5d66b5e8 Replace thread messages with messages to dummy window (#710)
* Replace thread messages with messages to dummy window

* Add CHANGELOG entry

* Style changes

* Make review changes
2018-11-16 22:17:32 -05:00
Victor Berger
7fe90e6c80 Introduce WindowBuilderExt::with_app_id for wayland (#700) 2018-11-15 16:59:56 -05:00
mtak-
8dcd514393 add mtak- to CONTRIBUTING.md as iOS maintainer, change francesca64 to a reviewer (#702) 2018-11-12 21:49:15 -05:00
Victor Berger
2c3e420f82 travis: freeze dependencies that silently broke 1.24.1 compat (#701) 2018-11-12 20:37:51 -05:00
Francesca Plebani
917db35a84 X11: Fix panic when dropping window before running event loop (#694)
Fixes #691

Dropping a window before running the `EventsLoop` results in events
still being queued when `XDestroyWindow` is called, so events like
`XI_Enter` (the culprit in this case) will still be processed.
Simply checking that the window still exists before calling
`query_pointer` was enough to solve the problem.
2018-11-10 13:54:50 -05:00
Victor Berger
dd52364d33 [META] Add a CONTRIBUTING.md (#674) 2018-11-10 11:56:40 +01:00
Joe Moon
30aa5a5057 version 0.18.0 (#680)
* version 0.18.0

* Changelog: F16-F24 support was a breaking change

* fix version in README

* bump image dep

* Updated release date
2018-11-07 00:43:15 -05:00
Barret Rennie
a46fcaee31 Support requesting user attention on macOS (#664)
* Support requesting user attention on macOS

* Documentation improvements
2018-11-06 23:50:40 -05:00
Osspial
52e2748869 Remove From<NSApplicationActivationPolicy> impl from ActivationPolicy (#690)
* Remove From<NSApplicationActivationPolicy> impl from ActivationPolicy

* Update CHANGELOG
2018-11-05 18:54:22 -05:00
Patrick Walton
d2d127a4c4 Make views explicitly layer-backed on macOS Mojave. (#685)
On Mojave, views automatically become layer-backed shortly after being added to
a window. Changing the layer-backedness of a view breaks the association
between the view and its associated OpenGL context. To work around this, on
Mojave we explicitly make the view layer-backed up front so that AppKit doesn't
do it itself and break the association with its context.

This was breaking the `window` example in `glutin`.
2018-11-05 14:34:54 -05:00
Francesca Plebani
0fca8e8cb5 X11: Fix DND freezing the WM (#688)
Fixes #687

`XdndFinished` isn't supposed to be sent when rejecting a `XdndPosition`; it should only be
sent in response to `XdndDrop`.

https://freedesktop.org/wiki/Specifications/XDND/
2018-11-02 17:41:51 -04:00
Osspial
6bec912961 Add optional Serde implementations and missing derivable traits (#652)
* Add optional serde feature

* Document features in README

* Add changelog entry

* Implement some missing derivable traits

* Add changelog entry for std derives

* Remove extraneous space on serde doc comments

* Add period to end of serde line in readme

* Remove serde impls from WindowAttributes

* Add serde impls for TouchPhase

* Add serde test file

* Add feature lines to testing CIs

* Remove WindowAttributes from changelog
2018-11-01 04:24:56 -04:00
Artúr Kovács
214e157e5d Implement HoveredFile and HoveredFileCancelled on Windows (#662)
* Implement HoveredFile and HoveredFileCancelled on Windows (#448)

* Update CHANGELOG.

* Applied code organizational corrections and fixed IDropHandler leak on window destroy.

* Moved FileDropHandle to a separate file.
2018-10-24 14:40:12 -04:00
Lucas Kent
da1d479e55 update to image 0.20 (#683) 2018-10-23 20:29:11 -04:00
Eleanore Young
062bb0cef2 On linux without X11 or Wayland, reduced the panic message to a single line (#681) 2018-10-21 18:12:51 -04:00
Victor Berger
c744b016ce x11: compute resize logical size with new dpi (#668)
* x11: compute resize logical size with new dpi

Whenever a dpi change occurs, trigger a Resized event as well with the
new logical size. Given X11 primarily deals in physical pixels, a change
in DPI also changes the logical size (as the physical size remains
fixed).

* Doc tweaks
2018-10-19 16:32:57 -04:00
George Burton
f486845f7f Implement Debug trait on exported opaque types (#677)
* Implement `Debug` trait on exported opaque types

* Make formatting consistent
2018-10-17 23:20:12 -04:00
trimental
7baa96c5c7 Provide current modifiers state with pointer events on wayland (#676) 2018-10-17 22:34:02 -04:00
Joe Moon
ea07ec1fda macOS: fix modifiers during key repeat (#666)
* macOS: fix modifiers during key repeat

* fix compile warnings
2018-10-17 22:03:26 -04:00
Alex Taylor
26b70e457b Windows: Fix transparency (#675)
* Windows: Fix transparency (#260)

* Windows: Only enable WS_EX_LAYERED for transparent windows

* Update winapi to 0.3.6

* Windows: Amend transparency code

* Add transparency fix to CHANGELOG.md
2018-10-17 20:23:59 -04:00
Rob Horswell
5d5fcb3911 Windows: Fix window.set_maximized() (#672)
* Windows: Fix window.set_maximized()

* Add window.set_maximized fix to CHANGELOG.

* Windows: use same style for set_maximized as other set_x(bool) methods
2018-10-14 19:47:08 -04:00
trimental
50008dff3d Upgrade to smithay-client-toolkit 0.4 (#671)
* Upgrade to smithay-client-toolkit 0.4

* Fix PR points
2018-10-14 19:15:43 -04:00
Francesca Plebani
808638fee3 Windows: Fix set_cursor delay (#660) 2018-09-22 21:03:38 -04:00
Tobias Umbach
b0e3865562 Don't include NUL byte in _NET_WM_NAME (#658)
> The contents of the property are not required to be null-terminated;
> any terminating null should not be included in text_prop.nitems.

https://tronche.com/gui/x/xlib/ICC/client-to-window-manager/XmbTextPropertyToTextList.html
2018-09-20 17:59:37 -04:00
Tobias Umbach
bc03ffb317 Add X11-specific with_gtk_theme_variant option (#659) 2018-09-20 17:00:04 -04:00
trimental
1edbca1775 Wayland: use init_from_env() to create windows and allow server-sid… (#655)
* Wayland: use `init_from_env()` to create windows and allow server-side decorations

* Change the CHANGELOG.md entrys wording
2018-09-20 13:48:36 -04:00
Kirill Chibisov
5a0bc016e7 Add support for F16-F24 (#641)
* Added support for F16-F19 keys.

* Documented support for F16-F19 keys

* Added support for F20 key

* Added support for F21-F24 on platforms except macOs

* Added support for F21-F24 on macOs

* Documented addition of F16-F24 keys

* Added missing ref qualifier

* Fixed compilation error on 1.24.1

* Refactored methods in macOs events_loop and view files
2018-09-12 13:04:16 -04:00
Sven-Hendrik Haase
bb66b7f28e Update wm spec hints (#646)
* Update wm-spec hints to v1.5

* Update changelog

* Fix CHANGELOG entry

* Remove trailing quote
2018-09-11 15:03:42 -04:00
Sven-Hendrik Haase
0331491b2b Put badges next to each other instead of below eachother (#649) 2018-09-11 14:59:04 -04:00
Kornel
54a782c8ae Syntax fix in Cargo.toml (#644) 2018-09-11 00:23:48 -04:00
Osspial
a70bc20829 Remove resize block on Windows (#634)
* Remove Windows block on resize

* Add CHANGELOG entry

* Move CHANGELOG entry to Unreleased

* Further edits to CHANGELOG entry
2018-08-24 13:48:57 -04:00
trimental
102ed3b800 Wayland: commit frame surface on resize (#635) 2018-08-23 13:20:02 -04:00
Joe Moon
c8e339fe6d version 0.17.2 (#630)
* version 0.17.2

* Update release date
2018-08-19 18:27:57 -04:00
trimental
e4e53fe315 Add key repetition for the wayland backend (#628)
* Add key repetition for the wayland backend

* Upgrade smithay-client-toolkit to 0.3.0
2018-08-19 17:17:40 -04:00
Joe Moon
1c795c3f1c 625 macos modifiers (#629)
* fix <C-Tab>

* fix <CMD-{key}>

* move the NSKeyUp special handling into the match statement

* add special handling for `<Cmd-.>`

* formatting

* add return type to msg_send!
2018-08-15 19:42:57 -04:00
Francesca Frangipane
b2b740fed7 Windows: Fix fullscreen deadlock + release 0.17.1 (#622)
* Windows: Fix fullscreen deadlock

* Release winit 0.17.1
2018-08-07 14:24:43 -04:00
Azriel Hoh
09550397d7 Maintenance/620/fix x11 release mode compilation (#621)
* Raised minimum version of `x11-dl`.

This fixes a compilation error in release mode on X11.

Issue #620

* Updated `CHANGELOG.md` about X11 release mode compilation issue.
2018-08-05 02:24:49 -04:00
Paul Rouget
a32f7f2ec5 Update cocoa and core-graphics (#608)
* Update cocoa and core-graphics

* Release winit 0.17.0

* Updated date / README version
2018-08-02 16:26:30 -04:00
Dennis Möhlmann
e8e9fa2418 fix assertion failed: validate_hidpi_factor(dpi_factor) (#607) (#618)
* fix assertion failed: validate_hidpi_factor(dpi_factor) (#607)

* added changelog entry
2018-08-02 13:03:15 -04:00
Felix Rabe
1a119bdfe9 Use consistent order inside #[cfg(any(...))] (#619) 2018-08-01 15:22:14 -04:00
Andrew Hickman
21ff2e0ffc Fix unsoundness on Windows (#601)
* Fix unsoundness in windows backend

* Synchronize window state properly

* update changelog and add a comment to execute_in_thread

* Formatting fixes and improve changelog message
2018-07-27 18:34:08 -04:00
Felix Rabe
df9b23c96a Typo: retreiv... -> retriev... (#614) 2018-07-27 14:59:53 -04:00
mtak-
4c117aa282 iOS: Fix the longjmp/setjmp ffi (#613)
* iOS: Fix the `longjmp`/`setjmp` ffi. `jmp_buf` was the wrong size (too small) causing crashes on application launch, make longjmp return Never

* remove extra parentheses around JBLEN, and add a changelog entry about the JmpBuf fix
2018-07-26 19:27:26 -04:00
Francesca Frangipane
88427262a6 macOS: Fix cursor hiding thread unsafety (#611) 2018-07-26 17:14:16 -04:00
mtak-
72b24a9348 iOS Abstract Out the UIView type from winit (#609)
* remove opengl code from winit

* iOS: restrict EventsLoop to be created on the main thread
iOS: Window can only be made once, make Drop on Window thread safe
iOS: make DelegateState owned by Window, cleanup
iOS: fixes from merge (class! macro)

* update the changelog

* Fixed nitpicks
2018-07-25 14:49:46 -04:00
Paul Rouget
01cb8e59e3 Fix key state on MacOS (#610) 2018-07-25 13:36:33 -04:00
trimental
3910326709 Update wayland-client and client-toolkit (#602) 2018-07-20 12:08:55 -04:00
Josh Groves
7ee46d80e6 Use class macro (#605) 2018-07-19 12:02:33 -04:00
Victor Berger
0cb5450999 Clarify DPI docs to highlight WindowEvent::HiDpiFactorChanged (#598)
* Clarify DPI docs to highlight WindowEvent::HiDpiFactorChanged

* Address review of #598

* dpi docs: grammar corrections

* The final nitpick
2018-07-16 10:44:29 -04:00
Iku Iwasa
8c78013257 Support NetBSD platform (#603)
* Support NetBSD platform

* CHANGELOG tweak + target ordering
2018-07-16 10:25:26 -04:00
mtak-
bd944898f0 set the UIViewController's view to the one that was just created (#595)
* set the UIViewController's view to the one that was just created

* capture the return value in a Unit to avoid SIGILL/SIGSEGV's.
change whitespace to be more idiomatic of Obj-C

* CHANGELOG entry
2018-07-13 15:10:12 -04:00
Bastien Orivel
c1ef1acfc0 Update parking_lot and bump version (#593) 2018-07-07 17:21:53 -04:00
Francesca Frangipane
040d3f5d8b Remove incorrect unreachable usage when guessing DPI factor (#592) 2018-07-05 11:52:25 -04:00
Joshua Minter
ec393e4a90 Disable maximize button on non-resizable windows (#588)
* Disabled maximize button

When creating a non resizable window in win32.
Also added example code to test.

* Added to changelog

* Added to documentation

* Removed non_resizable test

* Other suggested PR changes

* Documentation changes

* CHANGELOG nits
2018-07-03 20:15:19 -04:00
Francesca Frangipane
1703d0417a Release winit 0.16.1 (#587) 2018-07-02 20:14:38 -04:00
Francesca Frangipane
fad72c0441 X11: Fix compilation when c_char==c_uchar (#586) 2018-07-02 11:05:25 -04:00
Francesca Frangipane
2f7321a076 X11+Windows: Guess initial DPI factor (#583)
* X11: Guess initial DPI factor

* Windows: Guess initial DPI factor
2018-07-01 11:01:46 -04:00
icefoxen
85ee422acd Define "DPI" in docs. (#580)
It makes my pedant reflexes tingle.
2018-06-28 14:05:56 -04:00
Francesca Frangipane
089816d9ba Release winit 0.16.0 (#578) 2018-06-25 16:47:10 -04:00
Francesca Frangipane
c873c2db15 Wayland: Fix window creation dimensions (#577)
* Wayland: Fix window creation dimensions

* Wayland: Fix window creation min/max
2018-06-24 08:28:57 -04:00
えちょ
047c67baf3 windows feature WS_EX_NOREDIRECTIONBITMAP (#575)
* set WS_EX_NOREDIRECTIONBITMAP

* add CHANGELOG.md

* more flexibility.

* Skip DwmEnableBlurBehindWindow if no_redirection_bitmap is enabled.
2018-06-21 21:33:29 -04:00
aloucks
8f394f117b Change set_cursor_position to return Result<(), String> (#562)
* Change set_cursor_position to return Result<(), String>

This is now consistent with `grab_cursor`, and
enables `window.set_cursor_position(x, y)?` in functions
that return `Result<_, Box<Error>>`.

* Adjust error handling of unimplemented cusor opertions in wayland

* The final nitpick

* Actually one more
2018-06-19 10:30:15 -04:00
Francesca Frangipane
fb7528c239 grab_cursor and hide_cursor (#571)
* Windows: Use new cursor state API

* X11: Use new cursor state API

* macOS: Use new cursor state API

* Android+iOS: Stubbed new cursor state API

* Emscripten: Use new cursor state API

* Prevent multiple inc/dec of display count on Windows

* Fixed missing imports (no idea where those went)

* Remove NoneCursor

* Improved documentation

* Fix Emscripten build

* Windows: Re-grab before and after fullscreen
2018-06-18 12:32:18 -04:00
Hal Gentz
042f5fe4b3 Shares the XConnection between all event loops instead of just all event (#572)
loops on the same thread.

This is needed for adding shared context support to glutin, as contexts
must be made with the same native display (and therefore the same
connection.)

Signed-off-by: Hal Gentz <zegentzy@protonmail.com>
2018-06-17 20:44:38 -04:00
Francesca Frangipane
289fb47a34 macOS: Fix doubled key repeats (#570) 2018-06-17 15:08:26 -04:00
Nikolai Vazquez
38bc6babb7 Change Travis badge to SVG (#573)
PNG on GitHub does not render well on HiDPI screens.
2018-06-17 15:08:01 -04:00
Francesca Frangipane
e7a8efcfa0 Mirror monitor list methods on Window (#567)
* macOS: Monitor list methods on Window

* X11+Wayland: Monitor list methods on Window

* Windows: Monitor list methods on Window

* iOS: Monitor list methods on Window

* Android: Monitor list methods on Window

* Emscripten: Monitor list methods on Window

* Fixed Wayland implementation
2018-06-16 10:14:12 -04:00
Francesca Frangipane
1b74822cfc DPI for everyone (#548) 2018-06-14 19:42:18 -04:00
Lucas Kent
f083dae328 Windows creates Alt event instead of Menu event. (to match other platforms) (#551)
* Removed VirtualKeyCode::LMenu + VirtualKeyCode::RMenu, Windows now generates VirtualKeyCode::LAlt + VirtualKeyCode::RAlt instead.

* CHANGELOG nits
2018-06-13 13:24:33 -04:00
Francesca Frangipane
23c384bd30 Release winit 0.15.1 (#564) 2018-06-13 12:06:22 -04:00
Victor Berger
ced1616e51 wayland: implement set_resizable (#565) 2018-06-13 11:18:44 -04:00
Peter Atashian
233ac4aed2 Update to winapi 0.3.5 (#563) 2018-06-12 11:58:18 -04:00
Danny Fritz
be5a2b0e87 Windows & X11: Window::set_resizable (#558)
* Windows: Window::set_resizable

* X11: Window::set_resizable

* Code style regarding resizable

* X11: set_resizable remember max/min window size

* Stub out set_resizable on Android, iOS, and emscripten

* remove comment block from docs

* Windows: set_resizable in fullscreen

* Special case Xfwm

* Added fun provisos to docs
2018-06-11 18:47:50 -04:00
Francesca Frangipane
2b4b64f499 macOS: Only detect clicks+motion within client area (#561)
* macOS: Only detect clicks within client area

* macOS: Only track mouse motion within client area

* Add CHANGELOG entry about #463 fix
2018-06-11 11:16:39 -04:00
Francesca Frangipane
262490d074 X11: Fix super fun race conditions (#554)
* X11: Fix super fun race conditions

* Fix build on rustc<1.26
2018-06-07 14:08:19 -04:00
Francesca Frangipane
8891cfd85e macOS: Resizable without decorations (#553)
* macOS: Resizable without decorations

* Fix style mask regressions
2018-06-07 13:29:23 -04:00
Danny Fritz
2cc8fa1eac X11: implement with_resizable (#540) (#556) 2018-06-07 12:46:15 -04:00
Francesca Frangipane
79aebf06dc macOS: Fix alt and win keycodes (#552)
* macOS: Generate LAlt/RAlt VirtualKeyCode

* macOS: Correct RWin/LWin
2018-06-06 11:30:26 -04:00
Francesca Frangipane
19dd961752 X11: Fix flickering when resizing with transparency enabled (#546)
* X11: Fix flickering when resizing with transparency enabled

* X11: Fix with_override_redirect
2018-06-03 13:11:54 -04:00
Christian Duerr
bf413ecb83 Fix DPI with 0 width/hight reported by xorg (#544)
* Fix DPI with 0 width/hight reported by xorg

* Add `WINIT_HIDPI_FACTOR` env variable

It is now possible to override the DPI factor using the
`WINIT_HIDPI_FACTOR` environment variable on X11.

The changelog also has been updated to introduce all current changes
made.

* Add documentation for the environment variable

* Fix nitpicks

* Learning the alphabet

* Panic with error message if DPI env var is <= 0
2018-06-03 12:41:47 -04:00
Francesca Frangipane
fd1a3eda1c Test against rustc 1.24.1 on Travis (#547) 2018-06-02 22:59:59 -04:00
Danny Fritz
0e2488db32 Added a GitHub PULL_REQUEST_TEMPLATE (#542)
* Added a GitHub PULL_REQUEST_TEMPLATE

* Updated to better reflect my dictatorial demands
2018-06-02 11:04:08 -04:00
Danny Fritz
58a00bffbb Windows: implement with_resizable (#540) (#541)
* Windows: implement with_resizable (#540)

* Fixed typo
2018-06-02 10:51:24 -04:00
Johannes Hofmann
bbfe57400d appveyor.yml: Test additional Rust channels (#539)
* In addition to nightly, also test the current stable version and Rust
  1.24.1
* Use rustup-init.exe to install the different versions
2018-05-30 07:57:40 -04:00
Francesca Frangipane
4372f6fdac X11: Flatten window model (#536) 2018-05-29 07:48:47 -04:00
Francesca Frangipane
30f798b246 X11: util design improvements (#534) 2018-05-27 08:49:35 -04:00
Francesca Frangipane
282770f11a Release winit 0.15.0 (#530) 2018-05-22 14:17:41 -04:00
Francesca Frangipane
17373a4e91 X11: Fix primary monitor fallback regression (#532) 2018-05-22 09:07:46 -04:00
Francesca Frangipane
a34147b602 macOS: Fix keyboard regressions (#533)
* Emit `ReceivedCharacter` for key repeats
* Enter emits `\r` instead of `\n`
2018-05-22 09:05:33 -04:00
Francesca Frangipane
cebd15bfd1 X11: Improve hint support (#529)
Fixes #257
2018-05-20 10:47:22 -04:00
Francesca Frangipane
f51f7c0ca8 Add option to make window "always on top" (#528)
* macOS: always_on_top

* Windows: always_on_top

* X11: always_on_top

* Stub set_always_on_top on other platforms
2018-05-20 10:24:05 -04:00
Francesca Frangipane
f6d26df64d Windows: CursorState improvements (#526)
* Windows: CursorState improvements

Fixes #523

Prior to changing the cursor state, we now check the current grab
state, since it can be invalidated by alt-tabbing and other things.

`CursorState::Hide` is also implemented now.

The cursor name is now wrapped in a `Cursor` struct to allow
multithreaded access.

`Window::set_cursor_state` has been reworked to use
`execute_in_thread`. Two unneeded `transmute` calls were also
removed.

The `WM_SETCURSOR` handler is much more readable now.

`MonitorId::get_adapter_name` has been removed, since it's dead
code and appears to be a relic from 4 years ago.

* Windows: CursorState::Grab no longer hides cursor

`MouseCursor::NoneCursor` has been implemented to allow for
equivalent behavior to the older implementation.

Windows and X11 now have consistent cursor grabbing behavior.
macOS still needs to be updated.

* Windows: Grabbing auto-hides again (for now)

This API needs more work, so let's stick to a bug fix and some
refactoring. However, it now hides using a different technique
than it did originally, which applies instantly instead of after
mouse movement.
2018-05-19 12:02:57 -04:00
Francesca Frangipane
fddfb2e2d6 Windows: Fix detection of Pause and Scroll keys (#525)
Fixes #524
2018-05-18 18:48:19 -04:00
Francesca Frangipane
dec728cfa2 macOS: Implement NSTextInputClient (#518)
Fixes #263
2018-05-17 21:28:30 -04:00
Francesca Frangipane
8440091a4e macOS: Implement with_resize_increments (#519)
Fixes #135
2018-05-16 10:16:36 -04:00
Francesca Frangipane
2464a135b3 macOS: Fix Window::get_current_monitor (#521)
* macOS: Implement MonitorId::get_position

* macOS: Fix Window::get_current_monitor
2018-05-16 09:41:45 -04:00
Francesca Frangipane
87fa120ebb macOS: Fix re-enabling decorations after the window is built without them (#520)
Fixes #517
2018-05-16 08:51:56 -04:00
Francesca Frangipane
d86f53a02c X11: Fix get_current_monitor (#515)
* X11: Fix get_current_monitor

Fixes #64

* impl Debug for MonitorId on all platforms
2018-05-14 08:14:57 -04:00
Francesca Frangipane
15a4fec3d9 X11: Fix scroll wheel delta on i3/etc. (#514)
Fixes #447
2018-05-13 08:44:23 -04:00
OJ Kwon
1819be1173 fix(mac_platform): forward keyevent to system (#511)
* fix(mac_platform): forward keyevent to system

* doc(changelog): update changelog
2018-05-12 22:10:57 -04:00
Victor Berger
ffa9b51d27 wayland: improve diagnostic of failed init (#512) 2018-05-12 07:58:11 -04:00
tinaun
b4a8c08f43 compile with icon_loading feature on docs.rs (#509)
* compile with icon_loading feature on docs.rs

these functions should be more visible now.

* Explicitly document which functions require icon_loading
2018-05-11 10:33:06 -04:00
Francesca Frangipane
741bcc4672 Correct privacy for Icon::to_cardinals (#510) 2018-05-10 18:42:41 -04:00
Francesca Frangipane
e48f1fc5f1 Release winit 0.14.0 (#503) 2018-05-09 10:58:06 -04:00
Johannes Hofmann
374f131f1e Update wayland-client to version 0.20.4 (#505)
Fixes #504
2018-05-08 19:00:54 -04:00
Jack Magnus
363261077f Windows: Fix panic when calling set_fullscreen(None) (#502)
* Windows: Fix panic for set_fullscreen(None) (#501)

* Add condition to prevent panic

Trying to call set_fullscreen(None) on a window that has never been in
fullscreen mode caused a panic before this change.
The responsible method now simply checks if this precondition is met and
returns (does nothing) otherwise.

* Add entry to CHANGELOG

* Add platform specification to CHANGELOG entry

Forgot to add that the to_fullscreen(None) bugfix is Windows only in
CHANGELOG.
2018-05-08 08:16:49 -04:00
Francesca Frangipane
102dd07456 Window icons (#497) 2018-05-07 17:36:21 -04:00
Victor Berger
1e97103094 wayland: migrate to smithay-client-toolkit (#490)
* wayland: migrate to smithay-client-toolkit

* Update smithay-client-toolkit

* Add changelog entry for wayland rework
2018-05-05 13:36:34 -04:00
Francesca Frangipane
cc8907b956 X11: Implement resize increments and base size (#494) 2018-05-03 09:41:11 -04:00
Francesca Frangipane
c4b92ebd45 X11: General cleanup (#491)
* X11: General cleanup

This is almost entirely internal changes, and as usual, doesn't actually
fix any problems people have complained about.

- `XSetInputFocus` can't be called before the window is visible. This
was previously handled by looping (with a sleep) and querying for the
window's state until it was visible. Now we use `XIfEvent`, which blocks
until we receive `VisibilityNotify`. Note that this can't be replaced
with an `XSync` (I tried).
- We now call `XSync` at the end of window creation and check for
errors, assuring that broken windows are never returned. When creating
invisible windows, this is the only time the output buffer is flushed
during the entire window creation process (AFAIK). For visible windows,
`XIfEvent` will generally flush, but window creation has overall been
reduced to the minimum number of flushes.
- `check_errors().expect()` has been a common pattern throughout the
backend, but it seems that people (myself included) didn't make a
distinction between using it after synchronous requests and asynchronous
requests. Now we only use it after async requests if we flush first,
though this still isn't correct (since the request likely hasn't been
processed yet). The only real solution (besides forcing a sync *every
time*) is to handle asynchronous errors *asynchronously*. For future
work, I plan on adding logging, though I don't plan on actually
*handling* those errors; that's more of something to hope for in the
hypothetical async/await XCB paradise.
- We now flush whenever it makes sense to. `util::Flusher` was added to
force contributors to be aware of the output buffer.
- `Window::get_position`, `Window::get_inner_position`,
`Window::get_inner_size`, and `Window::get_outer_size` previously all
required *several* round-trips. On my machine, it took an average of
around 80µs. They've now been reduced to one round-trip each, which
reduces my measurement to 16µs. This was accomplished simply by caching
the frame extents, which are expensive to calculate (due to various
queries and heuristics), but change infrequently and predictably. I
still recommend that application developers use these methods sparingly
and generally prefer storing the values from `Resized`/`Moved`, as
that's zero overhead.
- The above change enabled me to change the `Moved` event to supply
window positions, rather than client area positions. Additionally, we no
longer generate `Moved` for real (as in, not synthetic)
`ConfigureNotify` events. Real `ConfigureNotify` events contain
positions relative to the parent window, which are typically constant
and useless. Since that position would be completely different from the
root-relative positions supplied by synthetic `ConfigureNotify` events
(which are the vast majority of them), that meant real `ConfigureNotify`
events would *always* be detected as the position having changed, so the
resultant `Moved` was multiple levels of misleading. In practice, this
meant a garbage `Moved` would be sent every time the window was resized;
now a resize has to actually change the window's position to be
accompanied by `Moved`.
- Every time we processed an `XI_Enter` event, we would leak 4 bytes via
`util::query_pointer` (`XIQueryPointer`). `XIButtonState` contains a
dynamically-allocated mask field which we weren't freeing. As this event
occurs with fairly high frequency, long-running applications could
easily accumulate substantial leaks. `util::PointerState::drop` now
takes care of this.
- The `util` module has been split up into several sub-modules, as it
was getting rather lengthy. This accounts for a significant part of this
diff, unfortunately.
- Atoms are now cached. Xlib caches them too, so `XInternAtom` wouldn't
typically be a round-trip anyway, but the added complexity is
negligible.
- Switched from `std::sync::Mutex` to `parking_lot::Mutex` (within this
backend). There appears to be no downside to this, but if anyone finds
one, this would be easy to revert.
- The WM name and supported hints are now global to the application, and
are updated upon `ReparentNotify`, which should detect when the WM was
replaced (assuming a reparenting WM was involved, that is). Previously,
these values were per-window and would never update, meaning replacing
the WM could potentially lead to (admittedly very minor) problems.
- The result of `Window2::create_empty_cursor` will now only be used if
it actually succeeds.
- `Window2::load_cursor` no longer re-allocates the cursor name.
- `util::lookup_utf8` previously allocated a 16-byte buffer on the heap.
Now it allocates a 1024-byte buffer on the stack, and falls back to
dynamic allocation if the buffer is too small. This base buffer size is
admittedly gratuitous, but less so if you're using IME.
- `with_c_str` was finally removed.
- Added `util::Format` enum to help prevent goofs when dealing with
format arguments.
- `util::get_property`, something I added way back in my first winit PR,
only calculated offsets correctly for `util::Format::Char`. This was
concealed by the accomodating buffer size, as it would be very rare for
the offset to be needed; however, testing with a buffer size of 1,
`util::Format::Long` would read from the same offset multiple times, and
`util::Format::Short` would miss data. This function now works correctly
for all formats, relying on the simple fact that the offset increases by
the buffer size on each iteration. We also account for the extra byte
that `XGetWindowProperty` allocates at the end of the buffer, and copy
data from the buffer instead of moving it and taking ownership of the
pointer.
- Drag and drop now reliably works in release mode. This is presumably
related to the `util::get_property` changes.
- `util::change_property` now exists, which should make it easier to add
features in the future.
- The `EventsLoop` device map is no longer in a mutex.
- `XConnection` now implements `Debug`.
- Valgrind no longer complains about anything related to winit (with
either the system allocator or jemalloc, though "not having valgrind
complain about jemalloc" isn't something to strive for).

* X11: Add better diagnostics when initialization fails

* X11: Handle XIQueryDevice failure

* X11: Use correct types in error handler
2018-05-03 09:15:49 -04:00
Christian Duerr
fee874b5b7 Add Copy/Paste keys (#495)
* Add Copy/Paste keys

This is only a tiny update which introduces the `Copy` and `Paste` keys
which are present on X11/Wayland/Windows. I'm not sure if this exists on
MacOS too, but I'm not able to test that and it doesn't have names but
just matches on the hex key values.

The "Copy" element is a reserved keyword in Rust but shouldn't cause any
conflicts in this scenario, this behavior falls in line with
https://docs.rs/winit/0.13.1/winit/enum.MouseCursor.html#variant.Copy,
but it would be possible to rename it. However `Copy` seems like the
most intuitive choice.

* Add Cut key, fix windows and update CHANGELOG

This introduces a bunch of minor fixes:
 * The changes introduced by this branch have been added to the changelog
 * Since related, the `Cut` key has also been added
 * An attempt has been made to fix Windows

* Fix position of fallback comment

The new keys have been inserted at the wrong position, so the fallback
comment has been moved to the `_ => ...` section again.

* Fix windows build

Apparently there are no keys for Cut/Paste on Windows, so for now those
have been removed on Windows and only the `Copy` key has been added on
Windows, the changelog has been updated to reflect that.

Linux still implements Copy/Clone/Paste, but `Copy` is now working
properly on Wayland.

MacOS still does not have any of these keys.

* Remove Windows changes

Because the Windows design wasn't completely clear the VirtualKeyCode
variants are now only used on Linux with X11 and Wayland and ignored on
both MacOS and Windows.

The CHANGELOG has also been updated. Windows has been removed from it
and the Linux section has been clarified a bit.
2018-05-02 19:18:52 -04:00
Joe Moon
eba888207e macos platform attributes regression (#488)
* macOS: fix regression in 03c3e79409

fixed !decorations case and refactored logic to be a little easier to
read

* fix default case to inlude closable mask

* add comment to default case of macos platform attrs
2018-04-29 18:51:57 -04:00
Johannes Hofmann
ea28791da6 x11: Always receive Awakened event in run_forever (#489)
* x11: Always receive Awakened event in run_forever

Do not reset the pending_wakeup boolean at the start of run_forever so
that each call to EventsLoopProxy::wakeup results in an Awakened event.

Fixes #462

* Update CHANGELOG.md
2018-04-28 19:03:06 -04:00
Francesca Frangipane
fe2d37fcdc Windows: Implement DeviceEvents (#482)
Fixes #467

All variants other than Text have been implemented. While Text can
be implemented using ToUnicode, that doesn't play nice with dead
keys, IME, etc.

Most of the mouse DeviceEvents were already implemented, but due
to the flags that were used when registering for raw input events,
they only worked when the window was in the foreground.

This is also a step forward for #338, as DeviceIds are no longer
useless on Windows. On DeviceEvents, the DeviceId contains that
device's handle. While that handle could ostensibly be used by
developers to query device information, my actual reason for
choosing it is because it's simply a very easy way to handle this.
As a fun bonus, this enabled me to create this method:
  DevideIdExt::get_persistent_identifier() -> Option<String>
Using this gives you a unique identifier for the device that
persists across replugs/reboots/etc., so it's ideal for something
like device-specific configuration.

There's a notable caveat to the new DeviceIds, which is that the
value will always be 0 for a WindowEvent. There doesn't seem to be
any straightforward way around this limitation.

I was concerned that multi-window applications would receive n
copies of every DeviceEvent, but Windows only sends them to one
window per application.

Lastly, there's a chance that these additions will cause
antivirus/etc. software to detect winit applications as keyloggers.
I don't know how likely that is to actually happen to people, but
if it does become an issue, the raw input code is neatly
sequestered and would be easy to make optional during compilation.
2018-04-28 12:42:33 -04:00
Vladimir
3407a8dd78 Macos multi windows leak (#481)
* adding a multiwindow example

* Added NSAutoReleasepool for WindowDelegate::Drop
as setDelegate:nil autoreleases WindowDelegate during work.

Added NSAutoReleasepool for Window2::Create,
as it uses autorelease on objects while doing work.

Added NSAutoreleasepool for Window2::Drop
as nswindow::close uses autorelease on objects.

Added NSAutoreleasepool for IdRef.

Moved Window2 WinitWindow objc class to a static var, as we are creating
multiple windows.

* specifying return type for msg_send!

* removing example/recreate_window_leak.rs

* EventLoop, Shared, no need to retain dead weak ptr

* Change log entry added

* added comment about Shared.find_and_remove_window

* fixed code style errors
2018-04-28 12:10:06 -04:00
Joe Moon
5761fb6b30 macOS: fix subtle regression introduced in 0474dc986 (#487)
* macOS: fix subtle regression introduced in 0474dc986

* update changelog
2018-04-28 00:12:50 -04:00
Francesca Frangipane
7aeb2c083b macOS: Implement Moved (#478)
* macOS: Implement Moved

Fixes #67

* Also emit Moved after resizes that change position
2018-04-27 20:46:20 -04:00
Francesca Frangipane
8f47fdbe67 Windows: Position fixes (#479)
* Remove executable flag from os/macos.rs

This was causing me some grief while working on Windows, and it
doesn't belong here to begin with.

* Windows: get_position returns screen coordinates instead of workspace coordinates

Previously, get_position used GetWindowPlacement. As per the
documentation of WINDOWSTRUCT, the returned coordinates are in
workspace space, meaning they're relative to the taskbar. It's
also explicitly remarked that these coordinates should only be
used in conjunction with SetWindowPlacement, as mixing them with
functions expecting screen coordinates can cause unpleasantness.
Since our set_position (correctly) uses SetWindowPos, this meant
that passing the return of get_position to set_position would
cause the window to move.

We now use GetWindowRect, which returns screen coordinates. This
gives us both better consistency within the Windows backend and
across platforms.

Note that this only makes a difference if the taskbar is visible.
With the taskbar hidden, the values are exactly the same as before.

* Windows: Moved event position values are consistent with get_position

The old Moved values had two problems:

* They were obtained by casting a WORD (u16) straight to an i32.
This meant wrap-around would never be interpreted as negative,
thus negative positions (which are ubiquitous when using multiple
monitors) would result in positions around u16::MAX.

* WM_MOVE supplies client area positions, not window positions.

Switching to handling WM_WINDOWPOSCHANGED solves both of these
problems.

* Better documentation for Moved and Resized
2018-04-26 20:09:33 -04:00
Francesca Frangipane
2ea42b3947 Release winit 0.13.1 (#486) 2018-04-26 18:53:16 -04:00
Branan Riley
7510b95d8c Set minimum x11-dl version to include Z (#484)
Without this pin, an existing cargo.lock for an older winit will not
update the x11-dl dependency, and thus will select a version that is
missing required new XIM features.
2018-04-26 11:53:11 -04:00
208 changed files with 41823 additions and 15370 deletions

2
.cargo/config.toml Normal file
View File

@@ -0,0 +1,2 @@
[alias]
run-wasm = ["run", "--release", "--package", "run-wasm", "--"]

View File

@@ -1,56 +0,0 @@
version: 2
jobs:
android-test:
working_directory: ~/winit
docker:
- image: tomaka/cargo-apk
steps:
- run: apt-get -qq update && apt-get install -y git
- checkout
- restore_cache:
key: android-test-cache-{{ checksum "Cargo.toml" }}
- run: cargo apk build --example window
- save_cache:
key: android-test-cache-{{ checksum "Cargo.toml" }}
paths:
- target
asmjs-test:
working_directory: ~/winit
docker:
- image: tomaka/rustc-emscripten
steps:
- run: apt-get -qq update && apt-get install -y git
- checkout
- restore_cache:
key: asmjs-test-cache-{{ checksum "Cargo.toml" }}
- run: cargo build --example window --target asmjs-unknown-emscripten
- save_cache:
key: asmjs-test-cache-{{ checksum "Cargo.toml" }}
paths:
- target
wasm-test:
working_directory: ~/winit
docker:
- image: tomaka/rustc-emscripten
steps:
- run: apt-get -qq update && apt-get install -y git
- checkout
- restore_cache:
key: wasm-test-cache-{{ checksum "Cargo.toml" }}
- run: cargo build --example window --target wasm32-unknown-emscripten
- save_cache:
key: wasm-test-cache-{{ checksum "Cargo.toml" }}
paths:
- target
workflows:
version: 2
build-test-and-deploy:
jobs:
- android-test
- asmjs-test
- wasm-test

5
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,5 @@
- [ ] Tested on all platforms changed
- [ ] Added an entry to `CHANGELOG.md` 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

122
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,122 @@
name: CI
on:
pull_request:
push:
branches: [master]
jobs:
Check_Formatting:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: hecrj/setup-rust-action@v1
with:
rust-version: stable
components: rustfmt
- name: Check Formatting
run: cargo +stable fmt --all -- --check
tests:
name: Tests
strategy:
fail-fast: false
matrix:
rust_version: [1.57.0, stable, nightly]
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, cmd: 'apk --' }
- { 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, }
env:
RUST_BACKTRACE: 1
CARGO_INCREMENTAL: 0
PKG_CONFIG_ALLOW_CROSS: 1
RUSTFLAGS: "-C debuginfo=0 --deny warnings"
OPTIONS: ${{ matrix.platform.options }}
FEATURES: ${{ format(',{0}', matrix.platform.features ) }}
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: hecrj/setup-rust-action@v1
with:
rust-version: ${{ matrix.rust_version }}${{ matrix.platform.host }}
targets: ${{ matrix.platform.target }}
components: clippy
- name: Setup NDK path
shell: bash
# "Temporary" workaround until https://github.com/actions/virtual-environments/issues/5879#issuecomment-1195156618
# gets looked into.
run: echo "ANDROID_NDK_ROOT=$ANDROID_NDK_LATEST_HOME" >> $GITHUB_ENV
- name: Install Linux dependencies
if: (matrix.platform.os == 'ubuntu-latest')
run: sudo apt-get update && sudo apt-get install pkg-config cmake libfreetype6-dev libfontconfig1-dev
- name: Install GCC Multilib
if: (matrix.platform.os == 'ubuntu-latest') && contains(matrix.platform.target, 'i686')
run: sudo dpkg --add-architecture i386 && sudo apt-get update && sudo apt-get install g++-multilib gcc-multilib libfreetype6-dev:i386 libfontconfig1-dev:i386
- name: Install cargo-apk
if: contains(matrix.platform.target, 'android')
run: cargo install cargo-apk
- name: Check documentation
shell: bash
run: cargo $CMD doc --no-deps --target ${{ matrix.platform.target }} $OPTIONS --features $FEATURES --document-private-items
- name: Build
shell: bash
run: cargo $CMD build --verbose --target ${{ matrix.platform.target }} $OPTIONS --features $FEATURES
- name: Build tests
shell: bash
run: cargo $CMD test --no-run --verbose --target ${{ matrix.platform.target }} $OPTIONS --features $FEATURES
- name: Run tests
shell: bash
if: (
!contains(matrix.platform.target, 'android') &&
!contains(matrix.platform.target, 'ios') &&
!contains(matrix.platform.target, 'wasm32'))
run: cargo $CMD test --verbose --target ${{ matrix.platform.target }} $OPTIONS --features $FEATURES
- name: Lint with clippy
shell: bash
if: (matrix.rust_version == '1.57.0') && !contains(matrix.platform.options, '--no-default-features')
run: cargo clippy --all-targets --target ${{ matrix.platform.target }} $OPTIONS --features $FEATURES -- -Dwarnings
- name: Build with serde enabled
shell: bash
run: cargo $CMD build --verbose --target ${{ matrix.platform.target }} $OPTIONS --features serde,$FEATURES
- name: Build tests with serde enabled
shell: bash
run: cargo $CMD test --no-run --verbose --target ${{ matrix.platform.target }} $OPTIONS --features serde,$FEATURES
- name: Run tests with serde enabled
shell: bash
if: (
!contains(matrix.platform.target, 'android') &&
!contains(matrix.platform.target, 'ios') &&
!contains(matrix.platform.target, 'wasm32'))
run: cargo $CMD test --verbose --target ${{ matrix.platform.target }} $OPTIONS --features serde,$FEATURES

18
.github/workflows/publish.yml vendored Normal file
View File

@@ -0,0 +1,18 @@
name: Publish
on:
push:
tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
jobs:
Publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: hecrj/setup-rust-action@v1
with:
rust-version: stable
components: rustfmt
- name: Publish to crates.io
run: cargo publish --token ${{ secrets.cratesio_token }}

6
.gitignore vendored
View File

@@ -1,4 +1,10 @@
Cargo.lock
target/
rls/
.vscode/
*~
*.wasm
*.ts
*.js
#*#
.DS_Store

2
.gitmodules vendored
View File

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

View File

@@ -1,60 +0,0 @@
language: rust
cache: cargo
matrix:
include:
# Linux 32bit
- env: TARGET=i686-unknown-linux-gnu
os: linux
rust: nightly
addons:
apt:
# Cross compiler and cross compiled C libraries
packages: &i686_packages
- gcc-multilib
- env: TARGET=i686-unknown-linux-gnu
os: linux
rust: stable
addons:
apt:
packages: *i686_packages
# Linux 64bit
- env: TARGET=x86_64-unknown-linux-gnu
os: linux
rust: nightly
- env: TARGET=x86_64-unknown-linux-gnu
os: linux
rust: stable
# macOS
- env: TARGET=x86_64-apple-darwin
os: osx
rust: nightly
- env: TARGET=x86_64-apple-darwin
os: osx
rust: stable
# iOS
- env: TARGET=x86_64-apple-ios
os: osx
rust: nightly
- env: TARGET=x86_64-apple-ios
os: osx
rust: stable
install:
- rustup self update
- rustup target add $TARGET; true
script:
- cargo build --target $TARGET --verbose
# Running iOS apps on OSX requires the simulator so we skip that for now
- if [ "$TARGET" != "x86_64-apple-ios" ]; then cargo test --target $TARGET --verbose; fi
after_success:
- |
[ $TRAVIS_BRANCH = master ] &&
[ $TRAVIS_PULL_REQUEST = false ] &&
cargo publish --token ${CRATESIO_TOKEN}

View File

@@ -1,5 +1,718 @@
# 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.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.
# 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.
@@ -56,7 +769,7 @@
# Version 0.10.1 (2018-02-05)
*Yanked*
_Yanked_
# Version 0.10.0 (2017-12-27)

63
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,63 @@
# Winit Contributing 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.
## Reporting an issue
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:
- 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
## Making a pull request
When making a code contribution to winit, before opening your pull request, please make sure that:
- your patch builds with Winit's minimal supported rust version - Rust 1.57.0.
- 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.
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.
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).
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.
## Maintainers & Testers
The current [list of testers and contributors](https://github.com/rust-windowing/winit/wiki/Testers-and-Contributors)
can be found on the Wiki.
If you are interested in contributing or testing on a platform, please add yourself to that table!
## Making a new release
If you believe a new release is warranted, you can make a pull-request with:
- An updated version number (remember to change the version everywhere it is used).
- A new section in the changelog (below the `# Unreleased` section).
This gives contributors an opportunity to squeeze in an extra PR or two that they feel is valuable
enough to warrant blocking the release a little.
Once the PR is merged, a maintainer will create a new tag matching the version name (e.g. `v0.26.1`),
and a CI job will automatically release the new version. Remember that the release date in the
changelog must be kept in check with the actual release date.

View File

@@ -1,52 +1,149 @@
[package]
name = "winit"
version = "0.13.0"
authors = ["The winit contributors, Pierre Krieger <pierre.krieger1708@gmail.com>"]
version = "0.27.1"
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/tomaka/winit"
repository = "https://github.com/rust-windowing/winit"
documentation = "https://docs.rs/winit"
categories = ["gui"]
rust-version = "1.57.0"
[dependencies]
lazy_static = "1"
libc = "0.2"
[target.'cfg(target_os = "android")'.dependencies.android_glue]
version = "0.2"
[target.'cfg(target_os = "ios")'.dependencies]
objc = "0.2"
[target.'cfg(target_os = "macos")'.dependencies]
objc = "0.2"
cocoa = "0.14"
core-foundation = "0.5"
core-graphics = "0.13"
[target.'cfg(target_os = "windows")'.dependencies.winapi]
version = "0.3"
features = [
"winnt",
"winuser",
"wingdi",
"shellapi",
"dwmapi",
"processthreadsapi",
"libloaderapi",
"windowsx",
"hidusage",
"combaseapi",
"objbase",
"unknwnbase",
[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",
]
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))'.dependencies]
wayland-client = { version = "0.12.0", features = ["dlopen"] }
wayland-protocols = { version = "0.12.0", features = ["unstable_protocols"] }
wayland-kbd = "0.13.0"
wayland-window = "0.13.0"
x11-dl = "2.17"
percent-encoding = "1.0"
[features]
default = ["x11", "wayland", "wayland-dlopen", "wayland-csd-adwaita"]
x11 = ["x11-dl", "mio", "percent-encoding", "parking_lot"]
wayland = ["wayland-client", "wayland-protocols", "sctk"]
wayland-dlopen = ["sctk/dlopen", "wayland-client/dlopen"]
wayland-csd-adwaita = ["sctk-adwaita", "sctk-adwaita/title"]
wayland-csd-adwaita-notitle = ["sctk-adwaita"]
[dependencies]
instant = { version = "0.1", features = ["wasm-bindgen"] }
once_cell = "1.12"
log = "0.4"
serde = { version = "1", optional = true, features = ["serde_derive"] }
raw-window-handle = "0.5.0"
bitflags = "1"
mint = { version = "0.5.6", optional = true }
[dev-dependencies]
image = { version = "0.24.0", default-features = false, features = ["png"] }
simple_logger = "2.1.0"
[target.'cfg(target_os = "android")'.dependencies]
# Coordinate the next winit release with android-ndk-rs: https://github.com/rust-windowing/winit/issues/1995
ndk = "0.7.0"
ndk-glue = "0.7.0"
[target.'cfg(any(target_os = "ios", target_os = "macos"))'.dependencies]
objc = "0.2.7"
[target.'cfg(target_os = "macos")'.dependencies]
cocoa = "0.24"
core-foundation = "0.9"
core-graphics = "0.22"
dispatch = "0.2.0"
[target.'cfg(target_os = "windows")'.dependencies]
parking_lot = "0.12"
[target.'cfg(target_os = "windows")'.dependencies.windows-sys]
version = "0.36"
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(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies]
wayland-client = { version = "0.29.4", default_features = false, features = ["use_system_lib"], optional = true }
wayland-protocols = { version = "0.29.4", features = [ "staging_protocols"], optional = true }
sctk = { package = "smithay-client-toolkit", version = "0.16.0", default_features = false, features = ["calloop"], optional = true }
sctk-adwaita = { version = "0.4.1", optional = true }
mio = { version = "0.8", features = ["os-ext"], optional = true }
x11-dl = { version = "2.18.5", optional = true }
percent-encoding = { version = "2.0", optional = true }
parking_lot = { version = "0.12.0", optional = true }
libc = "0.2.64"
[target.'cfg(target_arch = "wasm32")'.dependencies.web_sys]
package = "web-sys"
version = "0.3.22"
features = [
'console',
"AddEventListenerOptions",
'CssStyleDeclaration',
'BeforeUnloadEvent',
'Document',
'DomRect',
'Element',
'Event',
'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"
[workspace]
members = [
"run-wasm",
]

243
FEATURES.md Normal file
View File

@@ -0,0 +1,243 @@
# Winit Scope
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 main graphical platforms:
- Desktop
- Windows
- macOS
- Unix
- via X11
- via Wayland
- Mobile
- 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
available everywhere. In this context, APIs exposed in winit can be split into different "support tiers":
- **Core:** Features that are essential to providing a well-formed abstraction over each platform's
windowing and input APIs.
- **Platform:** Platform-specific features that can't be meaningfully exposed through a common API and
cannot be implemented outside of Winit without exposing a significant amount of Winit's internals
or interfering with Winit's abstractions.
- **Usability:** Features that are not strictly essential to Winit's functionality, but provide meaningful
usability improvements and cannot be reasonably implemented in an external crate. These are
generally optional and exposed through Cargo features.
Core features are taken care of by the core Winit maintainers. Platform features are not.
When a platform feature is submitted, the submitter is considered the expert in the
feature and may be asked to support the feature should it break in the future.
Winit ***does not*** directly expose functionality for drawing inside windows or creating native
menus, but ***does*** commit to providing APIs that higher-level crates can use to implement that
functionality.
## `1.0` and stability
When all core features are implemented to the satisfaction of the Winit maintainers, Winit 1.0 will
be released and the library will enter maintenance mode. For the most part, new core features will not
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
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
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
### Unix
* Window urgency
* X11 Window Class
* X11 Override Redirect Flag
* GTK Theme Variant
* Base window size
### 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
* Support for custom `UIView` derived class
* 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 |
|-------------------------------- | ----- | ---- | ------- | ----------- | ----- | ----- | -------- |
|Window initialization |✔️ |✔️ |▢[#5] |✔️ |▢[#33]|▢[#33] |✔️ |
|Providing pointer to init OpenGL |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |**N/A**|
|Providing pointer to init Vulkan |✔️ |✔️ |✔️ |✔️ |✔️ |❓ |**N/A**|
|Window decorations |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|
|Window decorations toggle |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|
|Window resizing |✔️ |▢[#219]|✔️ |▢[#306] |**N/A**|**N/A**|✔️ |
|Window resize increments |❌ |❌ |❌ |❌ |❌ |❌ |**N/A**|
|Window transparency |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|N/A |
|Window maximization |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|
|Window maximization toggle |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|
|Window minimization |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|
|Fullscreen |✔️ |✔️ |✔️ |✔️ |**N/A**|✔️ |✔️ |
|Fullscreen toggle |✔️ |✔️ |✔️ |✔️ |**N/A**|✔️ |✔️ |
|Exclusive fullscreen |✔️ |✔️ |✔️ |**N/A** |❌ |✔️ |**N/A**|
|HiDPI support |✔️ |✔️ |✔️ |✔️ |▢[#721]|✔️ |✔️ |
|Popup windows |❌ |❌ |❌ |❌ |❌ |❌ |**N/A**|
### System information
|Feature |Windows|MacOS |Linux x11|Linux Wayland|Android|iOS |WASM |
|---------------- | ----- | ---- | ------- | ----------- | ----- | ------- | -------- |
|Monitor list |✔️ |✔️ |✔️ |✔️ |**N/A**|✔️ |**N/A**|
|Video mode query |✔️ |✔️ |✔️ |✔️ |❌ |✔️ |**N/A**|
### Input handling
|Feature |Windows |MacOS |Linux x11|Linux Wayland|Android|iOS |WASM |
|----------------------- | ----- | ---- | ------- | ----------- | ----- | ----- | -------- |
|Mouse events |✔️ |▢[#63] |✔️ |✔️ |**N/A**|**N/A**|✔️ |
|Mouse set location |✔️ |✔️ |✔️ |✔️(when locked) |**N/A**|**N/A**|**N/A**|
|Cursor locking |❌ |✔️ |❌ |✔️ |**N/A**|**N/A**|✔️ |
|Cursor confining |✔️ |❌ |✔️ |✔️ |**N/A**|**N/A**|❌ |
|Cursor icon |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|✔️ |
|Cursor hittest |✔️ |✔️ |❌ |✔️ |**N/A**|**N/A**|❌ |
|Touch events |✔️ |❌ |✔️ |✔️ |✔️ |✔️ |❌ |
|Touch pressure |✔️ |❌ |❌ |❌ |❌ |✔️ |❌ |
|Multitouch |✔️ |❌ |✔️ |✔️ |✔️ |✔️ |❌ |
|Keyboard events |✔️ |✔️ |✔️ |✔️ |❓ |❌ |✔️ |
|Drag & Drop |▢[#720] |▢[#720] |▢[#720] |❌[#306] |**N/A**|**N/A**|❓ |
|Raw Device Events |▢[#750] |▢[#750] |▢[#750] |❌ |❌ |❌ |❓ |
|Gamepad/Joystick events |❌[#804] |❌ |❌ |❌ |❌ |❌ |❓ |
|Device movement events |❓ |❓ |❓ |❓ |❌ |❌ |❓ |
|Drag window with cursor |✔️ |✔️ |✔️ |✔️ |**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 |
|------------------------------ | ----- | ---- | ------- | ----------- | ----- | ----- | -------- |
|New API for HiDPI ([#315] [#319]) |✔️ |✔️ |✔️ |✔️ |▢[#721]|✔️ |❓ |
|Event Loop 2.0 ([#459]) |✔️ |✔️ |❌ |✔️ |❌ |✔️ |❓ |
|Keyboard Input ([#812]) |❌ |❌ |❌ |❌ |❌ |❌ |❓ |
### Completed API Reworks
|Feature |Windows|MacOS |Linux x11|Linux Wayland|Android|iOS |WASM |
|------------------------------ | ----- | ---- | ------- | ----------- | ----- | ----- | -------- |
[#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

23
HALL_OF_CHAMPIONS.md Normal file
View File

@@ -0,0 +1,23 @@
# Hall of Champions
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
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
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
vastly more sustainable era of winit.
* [@goddessfreya]: For selflessly taking over maintainership of glutin, and her
stellar dedication to improving both winit and glutin.
[@tomaka]: https://github.com/tomaka
[@vberger]: https://github.com/vberger
[@francesca64]: https://github.com/francesca64
[@Osspial]: https://github.com/Osspial
[@goddessfreya]: https://github.com/goddessfreya

132
README.md
View File

@@ -1,19 +1,27 @@
# winit - Cross-platform window creation and management in Rust
[![](http://meritbadge.herokuapp.com/winit)](https://crates.io/crates/winit)
[![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)
[![Build Status](https://travis-ci.org/tomaka/winit.png?branch=master)](https://travis-ci.org/tomaka/winit)
[![Build status](https://ci.appveyor.com/api/projects/status/5h87hj0g4q2xe3j9/branch/master?svg=true)](https://ci.appveyor.com/project/tomaka/winit/branch/master)
[![CI Status](https://github.com/rust-windowing/winit/workflows/CI/badge.svg)](https://github.com/rust-windowing/winit/actions)
```toml
[dependencies]
winit = "0.13"
winit = "0.27.1"
```
## [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.
## Contact Us
Join us in any of these:
[![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)
## Usage
Winit is a window creation and management library. It can create windows and lets you handle
@@ -25,32 +33,112 @@ show something on the window you need to use the platform-specific getters provi
another library.
```rust
extern crate winit;
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
fn main() {
let mut events_loop = winit::EventsLoop::new();
let window = winit::Window::new(&events_loop).unwrap();
let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
events_loop.run_forever(|event| {
match event {
winit::Event::WindowEvent {
event: winit::WindowEvent::CloseRequested,
..
} => winit::ControlFlow::Break,
_ => winit::ControlFlow::Continue,
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => *control_flow = ControlFlow::Exit,
_ => (),
}
});
}
```
Winit is only officially supported on the latest stable version of the Rust compiler.
### Cargo Features
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.
### Platform-specific usage
#### Emscripten and WebAssembly
#### Wayland
Building a binary will yield a `.js` file. In order to use it in an HTML file, you need to:
Note that windows don't appear on Wayland until you draw/present to them.
- Put a `<canvas id="my_id"></canvas>` element somewhere. A canvas corresponds to a winit "window".
- Write a Javascript code that creates a global variable named `Module`. Set `Module.canvas` to
the element of the `<canvas>` element (in the example you would retrieve it via `document.getElementById("my_id")`).
More information [here](https://kripken.github.io/emscripten-site/docs/api_reference/module.html).
- Make sure that you insert the `.js` file generated by Rust after the `Module` variable is created.
`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
This library makes use of the [ndk-rs](https://github.com/rust-windowing/android-ndk-rs) crates, refer to that repo for more documentation.
The `ndk-glue` version needs to match the version used by `winit`. Otherwise, the application will not start correctly as `ndk-glue`'s internal `NativeActivity` static is not the same due to version mismatch.
`winit` compatibility table with `ndk-glue`:
| winit | ndk-glue |
| :---: | :------------------: |
| 0.24 | `ndk-glue = "0.2.0"` |
| 0.25 | `ndk-glue = "0.3.0"` |
| 0.26 | `ndk-glue = "0.5.0"` |
| 0.27 | `ndk-glue = "0.7.0"` |
Running on an Android device needs a dynamic system library, add this to Cargo.toml:
```toml
[[example]]
name = "request_redraw_threaded"
crate-type = ["cdylib"]
```
And add this to the example file to add the native activity glue:
```rust
#[cfg_attr(target_os = "android", ndk_glue::main(backtrace = "on"))]
fn main() {
...
}
```
And run the application with `cargo apk run --example request_redraw_threaded`
#### 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)`.
[#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

View File

@@ -1,17 +0,0 @@
environment:
matrix:
- TARGET: x86_64-pc-windows-msvc
- TARGET: i686-pc-windows-msvc
- TARGET: i686-pc-windows-gnu
install:
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe"
- rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
- SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin
- SET PATH=%PATH%;C:\MinGW\bin
- rustc -V
- cargo -V
build: false
test_script:
- cargo test --verbose

114
examples/control_flow.rs Normal file
View File

@@ -0,0 +1,114 @@
#![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: {:?}\n", mode);
}
VirtualKeyCode::Key2 => {
mode = Mode::WaitUntil;
println!("\nmode: {:?}\n", mode);
}
VirtualKeyCode::Key3 => {
mode = Mode::Poll;
println!("\nmode: {:?}\n", mode);
}
VirtualKeyCode::R => {
request_redraw = !request_redraw;
println!("\nrequest_redraw: {}\n", request_redraw);
}
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,32 +1,90 @@
extern crate winit;
#![allow(clippy::single_match)]
use winit::{Event, ElementState, MouseCursor, WindowEvent, KeyboardInput, ControlFlow};
use simple_logger::SimpleLogger;
use winit::{
event::{ElementState, Event, KeyboardInput, WindowEvent},
event_loop::EventLoop,
window::{CursorIcon, WindowBuilder},
};
fn main() {
let mut events_loop = winit::EventsLoop::new();
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let window = winit::WindowBuilder::new().build(&events_loop).unwrap();
let window = WindowBuilder::new().build(&event_loop).unwrap();
window.set_title("A fantastic window!");
let cursors = [MouseCursor::Default, MouseCursor::Crosshair, MouseCursor::Hand, MouseCursor::Arrow, MouseCursor::Move, MouseCursor::Text, MouseCursor::Wait, MouseCursor::Help, MouseCursor::Progress, MouseCursor::NotAllowed, MouseCursor::ContextMenu, MouseCursor::NoneCursor, MouseCursor::Cell, MouseCursor::VerticalText, MouseCursor::Alias, MouseCursor::Copy, MouseCursor::NoDrop, MouseCursor::Grab, MouseCursor::Grabbing, MouseCursor::AllScroll, MouseCursor::ZoomIn, MouseCursor::ZoomOut, MouseCursor::EResize, MouseCursor::NResize, MouseCursor::NeResize, MouseCursor::NwResize, MouseCursor::SResize, MouseCursor::SeResize, MouseCursor::SwResize, MouseCursor::WResize, MouseCursor::EwResize, MouseCursor::NsResize, MouseCursor::NeswResize, MouseCursor::NwseResize, MouseCursor::ColResize, MouseCursor::RowResize];
let mut cursor_idx = 0;
events_loop.run_forever(|event| {
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(cursors[cursor_idx]);
if cursor_idx < cursors.len() - 1 {
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, .. } => {
return ControlFlow::Break;
},
_ => ()
}
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => {
control_flow.set_exit();
}
_ => (),
}
ControlFlow::Continue
});
}
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,
];

70
examples/cursor_grab.rs Normal file
View File

@@ -0,0 +1,70 @@
#![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 {} pressed", button),
ElementState::Released => println!("mouse button {} released", button),
},
_ => (),
},
_ => (),
}
});
}

55
examples/custom_events.rs Normal file
View File

@@ -0,0 +1,55 @@
#![allow(clippy::single_match)]
#[cfg(not(target_arch = "wasm32"))]
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(target_arch = "wasm32")]
fn main() {
panic!("This example is not supported on web.");
}

75
examples/drag_window.rs Normal file
View File

@@ -0,0 +1,75 @@
#![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,79 +1,113 @@
extern crate winit;
#![allow(clippy::single_match)]
use std::io::{self, Write};
use winit::{ControlFlow, Event, WindowEvent};
use simple_logger::SimpleLogger;
use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent};
use winit::event_loop::EventLoop;
use winit::window::{Fullscreen, WindowBuilder};
fn main() {
let mut events_loop = winit::EventsLoop::new();
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
// enumerating monitors
let monitor = {
for (num, monitor) in events_loop.get_available_monitors().enumerate() {
println!("Monitor #{}: {:?}", num, monitor.get_name());
}
let mut decorations = true;
let mut minimized = false;
print!("Please write the number of the monitor to use: ");
io::stdout().flush().unwrap();
let mut num = String::new();
io::stdin().read_line(&mut num).unwrap();
let num = num.trim().parse().ok().expect("Please enter a number");
let monitor = events_loop.get_available_monitors().nth(num).expect("Please enter a valid ID");
println!("Using {:?}", monitor.get_name());
monitor
};
let window = winit::WindowBuilder::new()
let window = WindowBuilder::new()
.with_title("Hello world!")
.with_fullscreen(Some(monitor))
.build(&events_loop)
.build(&event_loop)
.unwrap();
let mut is_fullscreen = true;
let mut is_maximized = false;
let mut decorations = true;
let mut monitor_index = 0;
let mut monitor = event_loop
.available_monitors()
.next()
.expect("no monitor found!");
println!("Monitor: {:?}", monitor.name());
events_loop.run_forever(|event| {
println!("{:?}", event);
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");
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 => return ControlFlow::Break,
WindowEvent::CloseRequested => control_flow.set_exit(),
WindowEvent::KeyboardInput {
input:
winit::KeyboardInput {
KeyboardInput {
virtual_keycode: Some(virtual_code),
state,
state: ElementState::Pressed,
..
},
..
} => match (virtual_code, state) {
(winit::VirtualKeyCode::Escape, _) => return ControlFlow::Break,
(winit::VirtualKeyCode::F, winit::ElementState::Pressed) => {
is_fullscreen = !is_fullscreen;
if !is_fullscreen {
window.set_fullscreen(None);
} => 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);
}
VirtualKeyCode::S => {
monitor_index += 1;
if let Some(mon) = elwt.available_monitors().nth(monitor_index) {
monitor = mon;
} else {
window.set_fullscreen(Some(window.get_current_monitor()));
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);
}
(winit::VirtualKeyCode::M, winit::ElementState::Pressed) => {
is_maximized = !is_maximized;
window.set_maximized(is_maximized);
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);
}
(winit::VirtualKeyCode::D, winit::ElementState::Pressed) => {
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);
}
_ => (),
},
_ => (),
},
_ => {}
}
ControlFlow::Continue
});
}

View File

@@ -1,45 +0,0 @@
extern crate winit;
use winit::{ControlFlow, WindowEvent, ElementState, KeyboardInput};
fn main() {
let mut events_loop = winit::EventsLoop::new();
let window = winit::WindowBuilder::new().build(&events_loop).unwrap();
window.set_title("winit - Cursor grabbing test");
let mut grabbed = false;
events_loop.run_forever(|event| {
println!("{:?}", event);
match event {
winit::Event::WindowEvent { event, .. } => {
match event {
WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, .. }, .. } => {
if grabbed {
grabbed = false;
window.set_cursor_state(winit::CursorState::Normal)
.ok().expect("could not ungrab mouse cursor");
} else {
grabbed = true;
window.set_cursor_state(winit::CursorState::Grab)
.ok().expect("could not grab mouse cursor");
}
},
WindowEvent::CloseRequested => return ControlFlow::Break,
a @ WindowEvent::CursorMoved { .. } => {
println!("{:?}", a);
},
_ => (),
}
}
_ => {}
}
ControlFlow::Continue
});
}

View File

@@ -1,74 +1,86 @@
extern crate winit;
#![allow(clippy::single_match)]
use simple_logger::SimpleLogger;
use winit::{
event::{Event, KeyboardInput, WindowEvent},
event_loop::EventLoop,
window::WindowBuilder,
};
fn main() {
let mut events_loop = winit::EventsLoop::new();
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let _window = winit::WindowBuilder::new()
let _window = WindowBuilder::new()
.with_title("Your faithful window")
.build(&events_loop)
.build(&event_loop)
.unwrap();
let mut close_requested = false;
events_loop.run_forever(|event| {
use winit::WindowEvent::*;
use winit::ElementState::Released;
use winit::VirtualKeyCode::{N, Y};
event_loop.run(move |event, _, control_flow| {
use winit::event::{
ElementState::Released,
VirtualKeyCode::{N, Y},
};
control_flow.set_wait();
match event {
winit::Event::WindowEvent { event, .. } => match event {
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.
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;
// 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.
}
KeyboardInput {
input:
winit::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.
return winit::ControlFlow::Break;
}
// 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.
}
N => {
if close_requested {
println!("Your window will continue to stay by your side.");
close_requested = false;
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;
}
}
_ => (),
}
}
_ => (),
},
_ => (),
},
}
}
_ => (),
}
winit::ControlFlow::Continue
});
}

BIN
examples/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

99
examples/ime.rs Normal file
View File

@@ -0,0 +1,99 @@
#![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::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");
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_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: {}\n", ime_allowed);
}
}
_ => (),
}
});
}

View File

@@ -1,21 +0,0 @@
extern crate winit;
fn main() {
let mut events_loop = winit::EventsLoop::new();
let window = winit::WindowBuilder::new()
.build(&events_loop)
.unwrap();
window.set_min_dimensions(Some((400, 200)));
window.set_max_dimensions(Some((800, 400)));
events_loop.run_forever(|event| {
println!("{:?}", event);
match event {
winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => winit::ControlFlow::Break,
_ => winit::ControlFlow::Continue,
}
});
}

13
examples/monitor_list.rs Normal file
View File

@@ -0,0 +1,13 @@
#![allow(clippy::single_match)]
use simple_logger::SimpleLogger;
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();
dbg!(window.available_monitors().collect::<Vec<_>>());
dbg!(window.primary_monitor());
}

62
examples/mouse_wheel.rs Normal file
View File

@@ -0,0 +1,62 @@
#![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)
}
},
_ => (),
},
_ => (),
}
});
}

197
examples/multithreaded.rs Normal file
View File

@@ -0,0 +1,197 @@
#![allow(clippy::single_match)]
#[cfg(not(target_arch = "wasm32"))]
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},
};
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 {
A => window.set_always_on_top(state),
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(target_arch = "wasm32")]
fn main() {
panic!("Example not supported on Wasm");
}

View File

@@ -1,33 +1,61 @@
extern crate winit;
#![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() {
let mut events_loop = winit::EventsLoop::new();
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let mut windows = HashMap::new();
for _ in 0..3 {
let window = winit::Window::new(&events_loop).unwrap();
let window = Window::new(&event_loop).unwrap();
println!("Opened a new window: {:?}", window.id());
windows.insert(window.id(), window);
}
events_loop.run_forever(|event| {
println!("Press N to open a new window.");
event_loop.run(move |event, event_loop, control_flow| {
control_flow.set_wait();
match event {
winit::Event::WindowEvent {
event: winit::WindowEvent::CloseRequested,
window_id,
} => {
println!("Window {:?} has received the signal to close", window_id);
Event::WindowEvent { event, window_id } => {
match event {
WindowEvent::CloseRequested => {
println!("Window {:?} has received the signal to close", window_id);
// This drops the window, causing it to close.
windows.remove(&window_id);
// This drops the window, causing it to close.
windows.remove(&window_id);
if windows.is_empty() {
return winit::ControlFlow::Break;
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);
}
_ => (),
}
}
_ => (),
}
winit::ControlFlow::Continue
})
}

View File

@@ -1,29 +0,0 @@
extern crate winit;
fn main() {
let mut events_loop = winit::EventsLoop::new();
let _window = winit::WindowBuilder::new()
.with_title("A fantastic window!")
.build(&events_loop)
.unwrap();
let proxy = events_loop.create_proxy();
std::thread::spawn(move || {
// Wake up the `events_loop` once every second.
loop {
std::thread::sleep(std::time::Duration::from_secs(1));
proxy.wakeup().unwrap();
}
});
events_loop.run_forever(|event| {
println!("{:?}", event);
match event {
winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } =>
winit::ControlFlow::Break,
_ => winit::ControlFlow::Continue,
}
});
}

View File

@@ -0,0 +1,41 @@
#![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

@@ -0,0 +1,48 @@
#![allow(clippy::single_match)]
#[cfg(not(target_arch = "wasm32"))]
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(target_arch = "wasm32")]
fn main() {
unimplemented!() // `Window` can't be sent between threads
}

50
examples/resizable.rs Normal file
View File

@@ -0,0 +1,50 @@
#![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);
}
_ => (),
},
_ => (),
};
});
}

42
examples/timer.rs Normal file
View File

@@ -0,0 +1,42 @@
#![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,20 +1,34 @@
extern crate winit;
#![allow(clippy::single_match)]
use simple_logger::SimpleLogger;
use winit::{
event::{Event, WindowEvent},
event_loop::EventLoop,
window::WindowBuilder,
};
fn main() {
let mut events_loop = winit::EventsLoop::new();
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let window = winit::WindowBuilder::new().with_decorations(false)
.with_transparency(true)
.build(&events_loop).unwrap();
let window = WindowBuilder::new()
.with_decorations(false)
.with_transparent(true)
.build(&event_loop)
.unwrap();
window.set_title("A fantastic window!");
events_loop.run_forever(|event| {
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
println!("{:?}", event);
match event {
winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => winit::ControlFlow::Break,
_ => winit::ControlFlow::Continue,
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => control_flow.set_exit(),
_ => (),
}
});
}

22
examples/video_modes.rs Normal file
View File

@@ -0,0 +1,22 @@
#![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);
}
}

90
examples/web.rs Normal file
View File

@@ -0,0 +1,90 @@
#![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(target_arch = "wasm32")]
let log_list = wasm::create_log_list(&window);
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
#[cfg(target_arch = "wasm32")]
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(target_arch = "wasm32")]
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 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 the 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,22 +1,35 @@
extern crate winit;
#![allow(clippy::single_match)]
use simple_logger::SimpleLogger;
use winit::{
event::{Event, WindowEvent},
event_loop::EventLoop,
window::WindowBuilder,
};
fn main() {
let mut events_loop = winit::EventsLoop::new();
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let _window = winit::WindowBuilder::new()
let window = WindowBuilder::new()
.with_title("A fantastic window!")
.build(&events_loop)
.with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0))
.build(&event_loop)
.unwrap();
events_loop.run_forever(|event| {
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
println!("{:?}", event);
match event {
winit::Event::WindowEvent {
event: winit::WindowEvent::CloseRequested,
..
} => winit::ControlFlow::Break,
_ => winit::ControlFlow::Continue,
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => control_flow.set_exit(),
Event::MainEventsCleared => {
window.request_redraw();
}
_ => (),
}
});
}

131
examples/window_debug.rs Normal file
View File

@@ -0,0 +1,131 @@
#![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);
}
}
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(),
_ => (),
}
});
}

59
examples/window_icon.rs Normal file
View File

@@ -0,0 +1,59 @@
#![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

@@ -0,0 +1,66 @@
#![allow(clippy::single_match)]
// Limit this example to only compatible platforms.
#[cfg(any(
target_os = "windows",
target_os = "macos",
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
target_os = "android",
))]
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(target_os = "ios", target_arch = "wasm32"))]
fn main() {
println!("This platform doesn't support run_return.");
}

9
run-wasm/Cargo.toml Normal file
View File

@@ -0,0 +1,9 @@
[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.1.0"

3
run-wasm/src/main.rs Normal file
View File

@@ -0,0 +1,3 @@
fn main() {
cargo_run_wasm::run_wasm();
}

3
rustfmt.toml Normal file
View File

@@ -0,0 +1,3 @@
force_explicit_abi=true
use_field_init_shorthand=true
# merge_imports=true

570
src/dpi.rs Normal file
View File

@@ -0,0 +1,570 @@
//! 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),
}
}
}
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())
}
}

82
src/error.rs Normal file
View File

@@ -0,0 +1,82 @@
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 {}

1281
src/event.rs Normal file

File diff suppressed because it is too large Load Diff

410
src/event_loop.rs Normal file
View File

@@ -0,0 +1,410 @@
//! 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::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.
///
/// [`platform`]: crate::platform
#[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 [`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(),
}
}
}
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()
}
/// 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 / Windows / macOS / iOS / Android / Web:** Unsupported.
///
/// [`DeviceEvent`]: crate::event::DeviceEvent
pub fn set_device_event_filter(&self, _filter: DeviceEventFilter) {
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
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,451 +0,0 @@
use std::path::PathBuf;
use {WindowId, DeviceId};
/// Describes a generic event.
#[derive(Clone, Debug)]
pub enum Event {
WindowEvent {
window_id: WindowId,
event: WindowEvent,
},
DeviceEvent {
device_id: DeviceId,
event: DeviceEvent,
},
Awakened,
/// The application has been suspended or resumed.
///
/// The parameter is true if app was suspended, and false if it has been resumed.
Suspended(bool),
}
/// Describes an event from a `Window`.
#[derive(Clone, Debug)]
pub enum WindowEvent {
/// The size of the window has changed.
Resized(u32, u32),
/// The position of the window has changed.
Moved(i32, i32),
/// The window has been requested to close.
CloseRequested,
/// The window has been destroyed.
Destroyed,
/// A file has been dropped into the window.
DroppedFile(PathBuf),
/// A file is being hovered over the window.
HoveredFile(PathBuf),
/// A file was hovered, but has exited the window.
HoveredFileCancelled,
/// The window received a unicode character.
ReceivedCharacter(char),
/// The window gained or lost focus.
///
/// The parameter is true if the window has gained focus, and false if it has lost focus.
Focused(bool),
/// An event from the keyboard has been received.
KeyboardInput { device_id: DeviceId, input: KeyboardInput },
/// The cursor has moved on the window.
CursorMoved {
device_id: DeviceId,
/// (x,y) coords in pixels relative to the top-left corner of the window. Because the range of this data is
/// limited by the display area and it may have been transformed by the OS to implement effects such as cursor
/// acceleration, it should not be used to implement non-cursor-like interactions such as 3D camera control.
position: (f64, f64),
modifiers: ModifiersState
},
/// The cursor has entered the window.
CursorEntered { device_id: DeviceId },
/// The cursor has left the window.
CursorLeft { device_id: DeviceId },
/// A mouse wheel movement or touchpad scroll occurred.
MouseWheel { device_id: DeviceId, delta: MouseScrollDelta, phase: TouchPhase, modifiers: ModifiersState },
/// An mouse button press has been received.
MouseInput { device_id: DeviceId, state: ElementState, button: MouseButton, modifiers: ModifiersState },
/// Touchpad pressure event.
///
/// At the moment, only supported on Apple forcetouch-capable macbooks.
/// The parameters are: pressure level (value between 0 and 1 representing how hard the touchpad
/// is being pressed) and stage (integer representing the click level).
TouchpadPressure { device_id: DeviceId, pressure: f32, stage: i64 },
/// Motion on some analog axis. May report data redundant to other, more specific events.
AxisMotion { device_id: DeviceId, axis: AxisId, value: f64 },
/// The window needs to be redrawn.
Refresh,
/// Touch event has been received
Touch(Touch),
/// DPI scaling factor of the window has changed.
///
/// The following actions cause DPI changes:
///
/// * A user changes the resolution.
/// * A user changes the desktop scaling value (e.g. in Control Panel on Windows).
/// * A user moves the application window to a display with a different DPI.
HiDPIFactorChanged(f32),
}
/// Represents raw hardware events that are not associated with any particular window.
///
/// Useful for interactions that diverge significantly from a conventional 2D GUI, such as 3D camera or first-person
/// game controls. Many physical actions, such as mouse movement, can produce both device and window events. Because
/// window events typically arise from virtual devices (corresponding to GUI cursors and keyboard focus) the device IDs
/// may not match.
///
/// Note that these events are delivered regardless of input focus.
#[derive(Clone, Debug)]
pub enum DeviceEvent {
Added,
Removed,
/// Change in physical position of a pointing device.
///
/// This represents raw, unfiltered physical motion. Not to be confused with `WindowEvent::CursorMoved`.
MouseMotion {
/// (x, y) change in position in unspecified units.
///
/// Different devices may use different units.
delta: (f64, f64),
},
/// Physical scroll event
MouseWheel {
delta: MouseScrollDelta,
},
/// Motion on some analog axis. This event will be reported for all arbitrary input devices
/// that winit supports on this platform, including mouse devices. If the device is a mouse
/// device then this will be reported alongside the MouseMotion event.
Motion { axis: AxisId, value: f64 },
Button { button: ButtonId, state: ElementState },
Key(KeyboardInput),
Text { codepoint: char },
}
/// Describes a keyboard input event.
#[derive(Debug, Clone, Copy)]
pub struct KeyboardInput {
/// Identifies the physical key pressed
///
/// This should not change if the user adjusts the host's keyboard map. Use when the physical location of the
/// key is more important than the key's host GUI semantics, such as for movement controls in a first-person
/// game.
pub scancode: ScanCode,
pub state: ElementState,
/// Identifies the semantic meaning of the key
///
/// Use when the semantics of the key are more important than the physical location of the key, such as when
/// implementing appropriate behavior for "page up."
pub virtual_keycode: Option<VirtualKeyCode>,
/// Modifier keys active at the time of this input.
///
/// This is tracked internally to avoid tracking errors arising from modifier key state changes when events from
/// this device are not being delivered to the application, e.g. due to keyboard focus being elsewhere.
pub modifiers: ModifiersState
}
/// Describes touch-screen input state.
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum TouchPhase {
Started,
Moved,
Ended,
Cancelled
}
/// Represents touch event
///
/// Every time user touches screen new Start event with some finger id is generated.
/// When the finger is removed from the screen End event with same id is generated.
///
/// For every id there will be at least 2 events with phases Start and End (or Cancelled).
/// There may be 0 or more Move events.
///
///
/// Depending on platform implementation id may or may not be reused by system after End event.
///
/// Gesture regonizer using this event should assume that Start event received with same id
/// as previously received End event is a new finger and has nothing to do with an old one.
///
/// Touch may be cancelled if for example window lost focus.
#[derive(Debug, Clone, Copy)]
pub struct Touch {
pub device_id: DeviceId,
pub phase: TouchPhase,
pub location: (f64,f64),
/// unique identifier of a finger.
pub id: u64
}
/// Hardware-dependent keyboard scan code.
pub type ScanCode = u32;
/// Identifier for a specific analog axis on some device.
pub type AxisId = u32;
/// Identifier for a specific button on some device.
pub type ButtonId = u32;
/// Describes the input state of a key.
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum ElementState {
Pressed,
Released,
}
/// Describes a button of a mouse controller.
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum MouseButton {
Left,
Right,
Middle,
Other(u8),
}
/// Describes a difference in the mouse scroll wheel state.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum MouseScrollDelta {
/// Amount in lines or rows to scroll in the horizontal
/// and vertical directions.
///
/// Positive values indicate movement forward
/// (away from the user) or rightwards.
LineDelta(f32, f32),
/// Amount in pixels to scroll in the horizontal and
/// vertical direction.
///
/// Scroll events are expressed as a PixelDelta if
/// supported by the device (eg. a touchpad) and
/// platform.
PixelDelta(f32, f32)
}
/// Symbolic name for a keyboard key.
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
#[repr(u32)]
pub enum VirtualKeyCode {
/// The '1' key over the letters.
Key1,
/// The '2' key over the letters.
Key2,
/// The '3' key over the letters.
Key3,
/// The '4' key over the letters.
Key4,
/// The '5' key over the letters.
Key5,
/// The '6' key over the letters.
Key6,
/// The '7' key over the letters.
Key7,
/// The '8' key over the letters.
Key8,
/// The '9' key over the letters.
Key9,
/// The '0' key over the 'O' and 'P' keys.
Key0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
/// The Escape key, next to F1.
Escape,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
F13,
F14,
F15,
/// Print Screen/SysRq.
Snapshot,
/// Scroll Lock.
Scroll,
/// Pause/Break key, next to Scroll lock.
Pause,
/// `Insert`, next to Backspace.
Insert,
Home,
Delete,
End,
PageDown,
PageUp,
Left,
Up,
Right,
Down,
/// The Backspace key, right over Enter.
// TODO: rename
Back,
/// The Enter key.
Return,
/// The space bar.
Space,
/// The "Compose" key on Linux.
Compose,
Caret,
Numlock,
Numpad0,
Numpad1,
Numpad2,
Numpad3,
Numpad4,
Numpad5,
Numpad6,
Numpad7,
Numpad8,
Numpad9,
AbntC1,
AbntC2,
Add,
Apostrophe,
Apps,
At,
Ax,
Backslash,
Calculator,
Capital,
Colon,
Comma,
Convert,
Decimal,
Divide,
Equals,
Grave,
Kana,
Kanji,
LAlt,
LBracket,
LControl,
LMenu,
LShift,
LWin,
Mail,
MediaSelect,
MediaStop,
Minus,
Multiply,
Mute,
MyComputer,
NavigateForward, // also called "Prior"
NavigateBackward, // also called "Next"
NextTrack,
NoConvert,
NumpadComma,
NumpadEnter,
NumpadEquals,
OEM102,
Period,
PlayPause,
Power,
PrevTrack,
RAlt,
RBracket,
RControl,
RMenu,
RShift,
RWin,
Semicolon,
Slash,
Sleep,
Stop,
Subtract,
Sysrq,
Tab,
Underline,
Unlabeled,
VolumeDown,
VolumeUp,
Wake,
WebBack,
WebFavorites,
WebForward,
WebHome,
WebRefresh,
WebSearch,
WebStop,
Yen,
}
/// Represents the current state of the keyboard modifiers
///
/// Each field of this struct represents a modifier and is `true` if this modifier is active.
#[derive(Default, Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub struct ModifiersState {
/// The "shift" key
pub shift: bool,
/// The "control" key
pub ctrl: bool,
/// The "alt" key
pub alt: bool,
/// The "logo" key
///
/// This is the "windows" key on PC and "command" key on Mac.
pub logo: bool
}

131
src/icon.rs Normal file
View File

@@ -0,0 +1,131 @@
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 ({:?}) isn't divisible by 4, making it impossible to interpret as 32bpp RGBA pixels.",
byte_count,
),
BadIcon::DimensionsVsPixelCount {
width,
height,
width_x_height,
pixel_count,
} => write!(f,
"The specified dimensions ({:?}x{:?}) don't match the number of pixels supplied by the `rgba` argument ({:?}). For those dimensions, the expected pixel count is {:?}.",
width, height, pixel_count, 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,462 +1,162 @@
//! Winit allows you to build a window on as many platforms as possible.
//! Winit is a cross-platform window creation and event loop management library.
//!
//! # Building a window
//! # Building windows
//!
//! Before you can build a window, you first need to build an `EventsLoop`. This is done with the
//! `EventsLoop::new()` function. Example:
//! 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::EventsLoop;
//! let events_loop = EventsLoop::new();
//! use winit::event_loop::EventLoop;
//! let event_loop = EventLoop::new();
//! ```
//!
//! Once this is done there are two ways to create a window:
//! Once this is done there are two ways to create a [`Window`]:
//!
//! - Calling `Window::new(&events_loop)`.
//! - Calling `let builder = WindowBuilder::new()` then `builder.build(&events_loop)`.
//! - 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 way is the simpliest way and will give you default values for everything.
//! 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`].
//!
//! The second way 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
//!
//! # Events 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.
//!
//! Once a window has been created, it will *generate events*. For example whenever the user moves
//! the window, resizes the window, moves the mouse, etc. an event is generated.
//! 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.
//!
//! The events generated by a window can be retreived from the `EventsLoop` the window was created
//! with.
//! 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.
//!
//! There are two ways to do so. The first is to call `events_loop.poll_events(...)`, which will
//! retreive all the events pending on the windows and immediately return after no new event is
//! available. You usually want to use this method in application that render continuously on the
//! screen, such as video games.
//!
//! ```no_run
//! use winit::{Event, WindowEvent};
//! # use winit::EventsLoop;
//! # let mut events_loop = EventsLoop::new();
//! use winit::{
//! event::{Event, WindowEvent},
//! event_loop::EventLoop,
//! window::WindowBuilder,
//! };
//!
//! loop {
//! events_loop.poll_events(|event| {
//! match event {
//! Event::WindowEvent { event: WindowEvent::Resized(w, h), .. } => {
//! println!("The window was resized to {}x{}", w, h);
//! },
//! _ => ()
//! }
//! });
//! }
//! ```
//! let event_loop = EventLoop::new();
//! let window = WindowBuilder::new().build(&event_loop).unwrap();
//!
//! The second way is to call `events_loop.run_forever(...)`. As its name tells, it will run
//! forever unless it is stopped by returning `ControlFlow::Break`.
//! 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();
//!
//! ```no_run
//! use winit::{ControlFlow, Event, WindowEvent};
//! # use winit::EventsLoop;
//! # let mut events_loop = EventsLoop::new();
//! // 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();
//!
//! events_loop.run_forever(|event| {
//! match event {
//! Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
//! Event::WindowEvent {
//! event: WindowEvent::CloseRequested,
//! ..
//! } => {
//! println!("The close button was pressed; stopping");
//! ControlFlow::Break
//! control_flow.set_exit();
//! },
//! _ => ControlFlow::Continue,
//! 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.
//! },
//! _ => ()
//! }
//! });
//! ```
//!
//! If you use multiple windows, the `WindowEvent` event has a member named `window_id`. You can
//! compare it with the value returned by the `id()` method of `Window` in order to know which
//! window has received the event.
//! [`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 provide any function that allows drawing on a window. However it allows you to
//! retreive the raw handle of the window (see the `os` module for that), which in turn allows you
//! to create an OpenGL/Vulkan/DirectX/Metal/etc. context that will draw 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
#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "windows"))]
#![deny(rust_2018_idioms)]
#![deny(rustdoc::broken_intra_doc_links)]
#![deny(clippy::all)]
#![cfg_attr(feature = "cargo-clippy", deny(warnings))]
#![allow(clippy::missing_safety_doc)]
#[allow(unused_imports)]
#[macro_use]
extern crate lazy_static;
extern crate libc;
#[cfg(target_os = "windows")]
extern crate log;
#[cfg(feature = "serde")]
#[macro_use]
extern crate winapi;
extern crate serde;
#[macro_use]
extern crate bitflags;
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[macro_use]
extern crate objc;
#[cfg(target_os = "macos")]
extern crate cocoa;
#[cfg(target_os = "macos")]
extern crate core_foundation;
#[cfg(target_os = "macos")]
extern crate core_graphics;
#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
extern crate x11_dl;
#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
extern crate percent_encoding;
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))]
pub mod dpi;
#[macro_use]
extern crate wayland_client;
pub mod error;
pub mod event;
pub mod event_loop;
mod icon;
pub mod monitor;
mod platform_impl;
pub mod window;
pub use events::*;
pub use window::{AvailableMonitorsIter, MonitorId};
mod platform;
mod events;
mod window;
pub mod os;
/// Represents a window.
///
/// # Example
///
/// ```no_run
/// use winit::{Event, EventsLoop, Window, WindowEvent, ControlFlow};
///
/// let mut events_loop = EventsLoop::new();
/// let window = Window::new(&events_loop).unwrap();
///
/// events_loop.run_forever(|event| {
/// match event {
/// Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
/// ControlFlow::Break
/// },
/// _ => ControlFlow::Continue,
/// }
/// });
/// ```
pub struct Window {
window: platform::Window,
}
/// Identifier of a window. Unique for each window.
///
/// Can be obtained with `window.id()`.
///
/// Whenever you receive an event specific to a window, this event contains a `WindowId` which you
/// can then compare to the ids of your windows.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WindowId(platform::WindowId);
/// Identifier of an input device.
///
/// Whenever you receive an event arising from a particular input device, this event contains a `DeviceId` which
/// identifies its origin. Note that devices may be virtual (representing an on-screen cursor and keyboard focus) or
/// physical. Virtual devices typically aggregate inputs from multiple physical devices.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeviceId(platform::DeviceId);
/// Provides a way to retreive events from the system and from the windows that were registered to
/// the events loop.
///
/// An `EventsLoop` can be seen more or less as a "context". Calling `EventsLoop::new()`
/// initializes everything that will be required to create windows. For example on Linux creating
/// an events loop opens a connection to the X or Wayland server.
///
/// To wake up an `EventsLoop` from a another thread, see the `EventsLoopProxy` docs.
///
/// Note that the `EventsLoop` cannot be shared accross threads (due to platform-dependant logic
/// forbiding it), as such it is neither `Send` nor `Sync`. If you need cross-thread access, the
/// `Window` created from this `EventsLoop` _can_ be sent to an other thread, and the
/// `EventsLoopProxy` allows you to wakeup an `EventsLoop` from an other thread.
pub struct EventsLoop {
events_loop: platform::EventsLoop,
_marker: ::std::marker::PhantomData<*mut ()> // Not Send nor Sync
}
/// Returned by the user callback given to the `EventsLoop::run_forever` method.
///
/// Indicates whether the `run_forever` method should continue or complete.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ControlFlow {
/// Continue looping and waiting for events.
Continue,
/// Break from the event loop.
Break,
}
impl EventsLoop {
/// Builds a new events loop.
///
/// Usage will result in display backend initialisation, this can be controlled on linux
/// 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 it fails will
/// fallback on x11. If this variable is set with any other value, winit will panic.
pub fn new() -> EventsLoop {
EventsLoop {
events_loop: platform::EventsLoop::new(),
_marker: ::std::marker::PhantomData,
}
}
/// Returns the list of all the monitors available on the system.
///
// Note: should be replaced with `-> impl Iterator` once stable.
#[inline]
pub fn get_available_monitors(&self) -> AvailableMonitorsIter {
let data = self.events_loop.get_available_monitors();
AvailableMonitorsIter{ data: data.into_iter() }
}
/// Returns the primary monitor of the system.
#[inline]
pub fn get_primary_monitor(&self) -> MonitorId {
MonitorId { inner: self.events_loop.get_primary_monitor() }
}
/// Fetches all the events that are pending, calls the callback function for each of them,
/// and returns.
#[inline]
pub fn poll_events<F>(&mut self, callback: F)
where F: FnMut(Event)
{
self.events_loop.poll_events(callback)
}
/// Calls `callback` every time an event is received. If no event is available, sleeps the
/// current thread and waits for an event. If the callback returns `ControlFlow::Break` then
/// `run_forever` will immediately return.
#[inline]
pub fn run_forever<F>(&mut self, callback: F)
where F: FnMut(Event) -> ControlFlow
{
self.events_loop.run_forever(callback)
}
/// Creates an `EventsLoopProxy` that can be used to wake up the `EventsLoop` from another
/// thread.
pub fn create_proxy(&self) -> EventsLoopProxy {
EventsLoopProxy {
events_loop_proxy: self.events_loop.create_proxy(),
}
}
}
/// Used to wake up the `EventsLoop` from another thread.
#[derive(Clone)]
pub struct EventsLoopProxy {
events_loop_proxy: platform::EventsLoopProxy,
}
impl EventsLoopProxy {
/// Wake up the `EventsLoop` from which this proxy was created.
///
/// This causes the `EventsLoop` to emit an `Awakened` event.
///
/// Returns an `Err` if the associated `EventsLoop` no longer exists.
pub fn wakeup(&self) -> Result<(), EventsLoopClosed> {
self.events_loop_proxy.wakeup()
}
}
/// The error that is returned when an `EventsLoopProxy` attempts to wake up an `EventsLoop` that
/// no longer exists.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct EventsLoopClosed;
impl std::fmt::Display for EventsLoopClosed {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", std::error::Error::description(self))
}
}
impl std::error::Error for EventsLoopClosed {
fn description(&self) -> &str {
"Tried to wake up a closed `EventsLoop`"
}
}
/// Object that allows you to build windows.
#[derive(Clone)]
pub struct WindowBuilder {
/// The attributes to use to create the window.
pub window: WindowAttributes,
// Platform-specific configuration. Private.
platform_specific: platform::PlatformSpecificWindowBuilderAttributes,
}
/// Error that can happen while creating a window or a headless renderer.
#[derive(Debug, Clone)]
pub enum CreationError {
OsError(String),
/// TODO: remove this error
NotSupported,
}
impl CreationError {
fn to_string(&self) -> &str {
match *self {
CreationError::OsError(ref text) => &text,
CreationError::NotSupported => "Some of the requested attributes are not supported",
}
}
}
impl std::fmt::Display for CreationError {
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
formatter.write_str(self.to_string())
}
}
impl std::error::Error for CreationError {
fn description(&self) -> &str {
self.to_string()
}
}
/// Describes the appearance of the mouse cursor.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum MouseCursor {
/// The platform-dependent default cursor.
Default,
/// A simple crosshair.
Crosshair,
/// A hand (often used to indicate links in web browsers).
Hand,
/// Self explanatory.
Arrow,
/// Indicates something is to be moved.
Move,
/// Indicates text that may be selected or edited.
Text,
/// Program busy indicator.
Wait,
/// Help indicator (often rendered as a "?")
Help,
/// Progress indicator. Shows that processing is being done. But in contrast
/// with "Wait" the user may still interact with the program. Often rendered
/// as a spinning beach ball, or an arrow with a watch or hourglass.
Progress,
/// Cursor showing that something cannot be done.
NotAllowed,
ContextMenu,
NoneCursor,
Cell,
VerticalText,
Alias,
Copy,
NoDrop,
Grab,
Grabbing,
AllScroll,
ZoomIn,
ZoomOut,
/// Indicate that some edge is to be moved. For example, the 'SeResize' cursor
/// is used when the movement starts from the south-east corner of the box.
EResize,
NResize,
NeResize,
NwResize,
SResize,
SeResize,
SwResize,
WResize,
EwResize,
NsResize,
NeswResize,
NwseResize,
ColResize,
RowResize,
}
/// Describes how winit handles the cursor.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum CursorState {
/// Normal cursor behavior.
Normal,
/// The cursor will be invisible when over the window.
Hide,
/// Grabs the mouse cursor. The cursor's motion will be confined to this
/// window and the window has exclusive access to further events regarding
/// the cursor.
///
/// This is useful for first-person cameras for example.
Grab,
}
/// Attributes to use when creating a window.
#[derive(Clone)]
pub struct WindowAttributes {
/// The dimensions of the window. If this is `None`, some platform-specific dimensions will be
/// used.
///
/// The default is `None`.
pub dimensions: Option<(u32, u32)>,
/// The minimum dimensions a window can be, If this is `None`, the window will have no minimum dimensions (aside from reserved).
///
/// The default is `None`.
pub min_dimensions: Option<(u32, u32)>,
/// The maximum dimensions a window can be, If this is `None`, the maximum will have no maximum or will be set to the primary monitor's dimensions by the platform.
///
/// The default is `None`.
pub max_dimensions: Option<(u32, u32)>,
/// Whether the window should be set as fullscreen upon creation.
///
/// The default is `None`.
pub fullscreen: Option<MonitorId>,
/// The title of the window in the title bar.
///
/// The default is `"winit window"`.
pub title: String,
/// Whether the window should be maximized upon creation.
///
/// The default is `false`.
pub maximized: bool,
/// Whether the window should be immediately visible upon creation.
///
/// The default is `true`.
pub visible: bool,
/// Whether the the window should be transparent. If this is true, writing colors
/// with alpha values different than `1.0` will produce a transparent window.
///
/// The default is `false`.
pub transparent: bool,
/// Whether the window should have borders and bars.
///
/// The default is `true`.
pub decorations: bool,
/// [iOS only] Enable multitouch,
/// see [multipleTouchEnabled](https://developer.apple.com/documentation/uikit/uiview/1622519-multipletouchenabled)
pub multitouch: bool,
}
impl Default for WindowAttributes {
#[inline]
fn default() -> WindowAttributes {
WindowAttributes {
dimensions: None,
min_dimensions: None,
max_dimensions: None,
title: "winit window".to_owned(),
maximized: false,
fullscreen: None,
visible: true,
transparent: false,
decorations: true,
multitouch: false,
}
}
}
pub mod platform;

174
src/monitor.rs Normal file
View File

@@ -0,0 +1,174 @@
//! 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:** 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 {
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.
///
/// 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()
}
}

View File

@@ -1,38 +0,0 @@
#![cfg(any(target_os = "android"))]
use std::os::raw::c_void;
use EventsLoop;
use Window;
use WindowBuilder;
/// Additional methods on `EventsLoop` that are specific to Android.
pub trait EventsLoopExt {
/// Makes it possible for glutin to register a callback when a suspend event happens on Android
fn set_suspend_callback(&self, cb: Option<Box<Fn(bool) -> ()>>);
}
impl EventsLoopExt for EventsLoop {
fn set_suspend_callback(&self, cb: Option<Box<Fn(bool) -> ()>>) {
self.events_loop.set_suspend_callback(cb);
}
}
/// Additional methods on `Window` that are specific to Android.
pub trait WindowExt {
fn get_native_window(&self) -> *const c_void;
}
impl WindowExt for Window {
#[inline]
fn get_native_window(&self) -> *const c_void {
self.window.get_native_window()
}
}
/// Additional methods on `WindowBuilder` that are specific to Android.
pub trait WindowBuilderExt {
}
impl WindowBuilderExt for WindowBuilder {
}

View File

@@ -1,151 +0,0 @@
#![cfg(target_os = "macos")]
use std::convert::From;
use std::os::raw::c_void;
use cocoa::appkit::NSApplicationActivationPolicy;
use {MonitorId, Window, WindowBuilder};
/// Additional methods on `Window` that are specific to MacOS.
pub trait WindowExt {
/// Returns a pointer to the cocoa `NSWindow` that is used by this window.
///
/// The pointer will become invalid when the `Window` is destroyed.
fn get_nswindow(&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 get_nsview(&self) -> *mut c_void;
}
impl WindowExt for Window {
#[inline]
fn get_nswindow(&self) -> *mut c_void {
self.window.get_nswindow()
}
#[inline]
fn get_nsview(&self) -> *mut c_void {
self.window.get_nsview()
}
}
/// Corresponds to `NSApplicationActivationPolicy`.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ActivationPolicy {
/// Corresponds to `NSApplicationActivationPolicyRegular`.
Regular,
/// Corresponds to `NSApplicationActivationPolicyAccessory`.
Accessory,
/// Corresponds to `NSApplicationActivationPolicyProhibited`.
Prohibited,
}
impl Default for ActivationPolicy {
fn default() -> Self {
ActivationPolicy::Regular
}
}
impl From<ActivationPolicy> for NSApplicationActivationPolicy {
fn from(activation_policy: ActivationPolicy) -> Self {
match activation_policy {
ActivationPolicy::Regular =>
NSApplicationActivationPolicy::NSApplicationActivationPolicyRegular,
ActivationPolicy::Accessory =>
NSApplicationActivationPolicy::NSApplicationActivationPolicyAccessory,
ActivationPolicy::Prohibited =>
NSApplicationActivationPolicy::NSApplicationActivationPolicyProhibited,
}
}
}
/// Additional methods on `WindowBuilder` that are specific to MacOS.
///
/// **Note:** Properties dealing with the titlebar will be overwritten by the `with_decorations` method
/// on the base `WindowBuilder`:
///
/// - `with_titlebar_transparent`
/// - `with_title_hidden`
/// - `with_titlebar_hidden`
/// - `with_titlebar_buttons_hidden`
/// - `with_fullsize_content_view`
pub trait WindowBuilderExt {
fn with_activation_policy(self, activation_policy: ActivationPolicy) -> WindowBuilder;
fn with_movable_by_window_background(self, movable_by_window_background: bool) -> WindowBuilder;
fn with_titlebar_transparent(self, titlebar_transparent: bool) -> WindowBuilder;
fn with_title_hidden(self, title_hidden: bool) -> WindowBuilder;
fn with_titlebar_hidden(self, titlebar_hidden: bool) -> WindowBuilder;
fn with_titlebar_buttons_hidden(self, titlebar_buttons_hidden: bool) -> WindowBuilder;
fn with_fullsize_content_view(self, fullsize_content_view: bool) -> WindowBuilder;
}
impl WindowBuilderExt for WindowBuilder {
/// Sets the activation policy for the window being built
#[inline]
fn with_activation_policy(mut self, activation_policy: ActivationPolicy) -> WindowBuilder {
self.platform_specific.activation_policy = activation_policy;
self
}
/// Enables click-and-drag behavior for the entire window, not just the titlebar
#[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
}
/// Makes the titlebar transparent and allows the content to appear behind it
#[inline]
fn with_titlebar_transparent(mut self, titlebar_transparent: bool) -> WindowBuilder {
self.platform_specific.titlebar_transparent = titlebar_transparent;
self
}
/// Hides the window titlebar
#[inline]
fn with_titlebar_hidden(mut self, titlebar_hidden: bool) -> WindowBuilder {
self.platform_specific.titlebar_hidden = titlebar_hidden;
self
}
/// Hides the window titlebar buttons
#[inline]
fn with_titlebar_buttons_hidden(mut self, titlebar_buttons_hidden: bool) -> WindowBuilder {
self.platform_specific.titlebar_buttons_hidden = titlebar_buttons_hidden;
self
}
/// Hides the window title
#[inline]
fn with_title_hidden(mut self, title_hidden: bool) -> WindowBuilder {
self.platform_specific.title_hidden = title_hidden;
self
}
/// Makes the window content appear behind the titlebar
#[inline]
fn with_fullsize_content_view(mut self, fullsize_content_view: bool) -> WindowBuilder {
self.platform_specific.fullsize_content_view = fullsize_content_view;
self
}
}
/// Additional methods on `MonitorId` that are specific to MacOS.
pub trait MonitorIdExt {
/// Returns the identifier of the monitor for Cocoa.
fn native_id(&self) -> u32;
/// Returns a pointer to the NSScreen representing this monitor.
fn get_nsscreen(&self) -> Option<*mut c_void>;
}
impl MonitorIdExt for MonitorId {
#[inline]
fn native_id(&self) -> u32 {
self.inner.get_native_identifier()
}
fn get_nsscreen(&self) -> Option<*mut c_void> {
self.inner.get_nsscreen().map(|s| s as *mut c_void)
}
}

View File

@@ -1,15 +0,0 @@
//! Contains traits with platform-specific methods in them.
//!
//! Contains the follow modules:
//!
//! - `android`
//! - `macos`
//! - `unix`
//! - `windows`
//!
//! However only the module corresponding to the platform you're compiling to will be available.
//!
pub mod android;
pub mod macos;
pub mod unix;
pub mod windows;

View File

@@ -1,231 +0,0 @@
#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
use std::os::raw;
use std::sync::Arc;
use std::ptr;
use EventsLoop;
use MonitorId;
use Window;
use platform::EventsLoop as LinuxEventsLoop;
use platform::Window as LinuxWindow;
use WindowBuilder;
use platform::x11::XConnection;
use platform::x11::ffi::XVisualInfo;
// TODO: stupid hack so that glutin can do its work
#[doc(hidden)]
pub use platform::x11;
pub use platform::XNotSupported;
/// Additional methods on `EventsLoop` that are specific to Linux.
pub trait EventsLoopExt {
/// Builds a new `EventsLoop` that is forced to use X11.
fn new_x11() -> Result<Self, XNotSupported>
where Self: Sized;
/// Builds a new `EventsLoop` that is forced to use Wayland.
fn new_wayland() -> Self
where Self: Sized;
/// True if the `EventsLoop` uses Wayland.
fn is_wayland(&self) -> bool;
/// True if the `EventsLoop` uses X11.
fn is_x11(&self) -> bool;
#[doc(hidden)]
fn get_xlib_xconnection(&self) -> Option<Arc<XConnection>>;
}
impl EventsLoopExt for EventsLoop {
#[inline]
fn new_x11() -> Result<Self, XNotSupported> {
LinuxEventsLoop::new_x11().map(|ev|
EventsLoop {
events_loop: ev,
_marker: ::std::marker::PhantomData,
}
)
}
#[inline]
fn new_wayland() -> Self {
EventsLoop {
events_loop: match LinuxEventsLoop::new_wayland() {
Ok(e) => e,
Err(_) => panic!() // TODO: propagate
},
_marker: ::std::marker::PhantomData,
}
}
#[inline]
fn is_wayland(&self) -> bool {
self.events_loop.is_wayland()
}
#[inline]
fn is_x11(&self) -> bool {
!self.events_loop.is_wayland()
}
#[inline]
fn get_xlib_xconnection(&self) -> Option<Arc<XConnection>> {
self.events_loop.x_connection().cloned()
}
}
/// Additional methods on `Window` that are specific to Unix.
pub trait WindowExt {
/// 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 get_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 glutin `Window` is destroyed.
fn get_xlib_display(&self) -> Option<*mut raw::c_void>;
fn get_xlib_screen_id(&self) -> Option<raw::c_int>;
fn get_xlib_xconnection(&self) -> Option<Arc<XConnection>>;
fn send_xim_spot(&self, x: i16, y: i16);
/// 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 glutin `Window` is destroyed.
fn get_xcb_connection(&self) -> Option<*mut raw::c_void>;
/// 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 glutin `Window` is destroyed.
fn get_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 glutin `Window` is destroyed.
fn get_wayland_display(&self) -> Option<*mut raw::c_void>;
/// Check if the window is ready for drawing
///
/// It is a remnant of a previous implementation detail for the
/// wayland backend, and is no longer relevant.
///
/// Always return true.
#[deprecated]
fn is_ready(&self) -> bool;
}
impl WindowExt for Window {
#[inline]
fn get_xlib_window(&self) -> Option<raw::c_ulong> {
match self.window {
LinuxWindow::X(ref w) => Some(w.get_xlib_window()),
_ => None
}
}
#[inline]
fn get_xlib_display(&self) -> Option<*mut raw::c_void> {
match self.window {
LinuxWindow::X(ref w) => Some(w.get_xlib_display()),
_ => None
}
}
fn get_xlib_screen_id(&self) -> Option<raw::c_int> {
match self.window {
LinuxWindow::X(ref w) => Some(w.get_xlib_screen_id()),
_ => None
}
}
fn get_xlib_xconnection(&self) -> Option<Arc<XConnection>> {
match self.window {
LinuxWindow::X(ref w) => Some(w.get_xlib_xconnection()),
_ => None
}
}
fn get_xcb_connection(&self) -> Option<*mut raw::c_void> {
match self.window {
LinuxWindow::X(ref w) => Some(w.get_xcb_connection()),
_ => None
}
}
fn send_xim_spot(&self, x: i16, y: i16) {
if let LinuxWindow::X(ref w) = self.window {
w.send_xim_spot(x, y);
}
}
#[inline]
fn get_wayland_surface(&self) -> Option<*mut raw::c_void> {
use wayland_client::Proxy;
match self.window {
LinuxWindow::Wayland(ref w) => Some(w.get_surface().ptr() as *mut _),
_ => None
}
}
#[inline]
fn get_wayland_display(&self) -> Option<*mut raw::c_void> {
use wayland_client::Proxy;
match self.window {
LinuxWindow::Wayland(ref w) => Some(w.get_display().ptr() as *mut _),
_ => None
}
}
#[inline]
fn is_ready(&self) -> bool {
true
}
}
/// Additional methods on `WindowBuilder` that are specific to Unix.
pub trait WindowBuilderExt {
fn with_x11_visual<T>(self, visual_infos: *const T) -> WindowBuilder;
fn with_x11_screen(self, screen_id: i32) -> WindowBuilder;
}
impl WindowBuilderExt for WindowBuilder {
#[inline]
fn with_x11_visual<T>(mut self, visual_infos: *const T) -> WindowBuilder {
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) -> WindowBuilder {
self.platform_specific.screen_id = Some(screen_id);
self
}
}
/// Additional methods on `MonitorId` that are specific to Linux.
pub trait MonitorIdExt {
/// Returns the inner identifier of the monitor.
fn native_id(&self) -> u32;
}
impl MonitorIdExt for MonitorId {
#[inline]
fn native_id(&self) -> u32 {
self.inner.get_native_identifier()
}
}

View File

@@ -1,58 +0,0 @@
#![cfg(target_os = "windows")]
use std::os::raw::c_void;
use libc;
use MonitorId;
use Window;
use WindowBuilder;
use winapi::shared::windef::HWND;
/// Additional methods on `Window` that are specific to Windows.
pub trait WindowExt {
/// Returns the native handle that is used by this window.
///
/// The pointer will become invalid when the native window was destroyed.
fn get_hwnd(&self) -> *mut libc::c_void;
}
impl WindowExt for Window {
#[inline]
fn get_hwnd(&self) -> *mut libc::c_void {
self.window.hwnd() as *mut _
}
}
/// Additional methods on `WindowBuilder` that are specific to Windows.
pub trait WindowBuilderExt {
fn with_parent_window(self, parent: HWND) -> WindowBuilder;
}
impl WindowBuilderExt for WindowBuilder {
/// Sets a parent to the window to be created.
#[inline]
fn with_parent_window(mut self, parent: HWND) -> WindowBuilder {
self.platform_specific.parent = Some(parent);
self
}
}
/// Additional methods on `MonitorId` that are specific to Windows.
pub trait MonitorIdExt {
/// 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) -> *mut c_void;
}
impl MonitorIdExt for MonitorId {
#[inline]
fn native_id(&self) -> String {
self.inner.get_native_identifier()
}
#[inline]
fn hmonitor(&self) -> *mut c_void {
self.inner.get_hmonitor() as *mut _
}
}

40
src/platform/android.rs Normal file
View File

@@ -0,0 +1,40 @@
#![cfg(any(target_os = "android"))]
use crate::{
event_loop::{EventLoop, EventLoopWindowTarget},
window::{Window, WindowBuilder},
};
use ndk::configuration::Configuration;
use ndk_glue::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) -> Configuration;
}
impl WindowExtAndroid for Window {
fn content_rect(&self) -> Rect {
self.window.content_rect()
}
fn config(&self) -> Configuration {
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 {}

View File

@@ -1,108 +0,0 @@
#![allow(dead_code)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(non_upper_case_globals)]
use libc;
use std::os::raw;
#[link(name = "android")]
#[link(name = "EGL")]
#[link(name = "GLESv2")]
extern {}
/**
* asset_manager.h
*/
pub type AAssetManager = raw::c_void;
/**
* native_window.h
*/
pub type ANativeWindow = raw::c_void;
extern {
pub fn ANativeWindow_getHeight(window: *const ANativeWindow) -> libc::int32_t;
pub fn ANativeWindow_getWidth(window: *const ANativeWindow) -> libc::int32_t;
}
/**
* native_activity.h
*/
pub type JavaVM = ();
pub type JNIEnv = ();
pub type jobject = *const libc::c_void;
pub type AInputQueue = (); // FIXME: wrong
pub type ARect = (); // FIXME: wrong
#[repr(C)]
pub struct ANativeActivity {
pub callbacks: *mut ANativeActivityCallbacks,
pub vm: *mut JavaVM,
pub env: *mut JNIEnv,
pub clazz: jobject,
pub internalDataPath: *const libc::c_char,
pub externalDataPath: *const libc::c_char,
pub sdkVersion: libc::int32_t,
pub instance: *mut libc::c_void,
pub assetManager: *mut AAssetManager,
pub obbPath: *const libc::c_char,
}
#[repr(C)]
pub struct ANativeActivityCallbacks {
pub onStart: extern fn(*mut ANativeActivity),
pub onResume: extern fn(*mut ANativeActivity),
pub onSaveInstanceState: extern fn(*mut ANativeActivity, *mut libc::size_t),
pub onPause: extern fn(*mut ANativeActivity),
pub onStop: extern fn(*mut ANativeActivity),
pub onDestroy: extern fn(*mut ANativeActivity),
pub onWindowFocusChanged: extern fn(*mut ANativeActivity, libc::c_int),
pub onNativeWindowCreated: extern fn(*mut ANativeActivity, *const ANativeWindow),
pub onNativeWindowResized: extern fn(*mut ANativeActivity, *const ANativeWindow),
pub onNativeWindowRedrawNeeded: extern fn(*mut ANativeActivity, *const ANativeWindow),
pub onNativeWindowDestroyed: extern fn(*mut ANativeActivity, *const ANativeWindow),
pub onInputQueueCreated: extern fn(*mut ANativeActivity, *mut AInputQueue),
pub onInputQueueDestroyed: extern fn(*mut ANativeActivity, *mut AInputQueue),
pub onContentRectChanged: extern fn(*mut ANativeActivity, *const ARect),
pub onConfigurationChanged: extern fn(*mut ANativeActivity),
pub onLowMemory: extern fn(*mut ANativeActivity),
}
/**
* looper.h
*/
pub type ALooper = ();
#[link(name = "android")]
extern {
pub fn ALooper_forThread() -> *const ALooper;
pub fn ALooper_acquire(looper: *const ALooper);
pub fn ALooper_release(looper: *const ALooper);
pub fn ALooper_prepare(opts: libc::c_int) -> *const ALooper;
pub fn ALooper_pollOnce(timeoutMillis: libc::c_int, outFd: *mut libc::c_int,
outEvents: *mut libc::c_int, outData: *mut *mut libc::c_void) -> libc::c_int;
pub fn ALooper_pollAll(timeoutMillis: libc::c_int, outFd: *mut libc::c_int,
outEvents: *mut libc::c_int, outData: *mut *mut libc::c_void) -> libc::c_int;
pub fn ALooper_wake(looper: *const ALooper);
pub fn ALooper_addFd(looper: *const ALooper, fd: libc::c_int, ident: libc::c_int,
events: libc::c_int, callback: ALooper_callbackFunc, data: *mut libc::c_void)
-> libc::c_int;
pub fn ALooper_removeFd(looper: *const ALooper, fd: libc::c_int) -> libc::c_int;
}
pub const ALOOPER_PREPARE_ALLOW_NON_CALLBACKS: libc::c_int = 1 << 0;
pub const ALOOPER_POLL_WAKE: libc::c_int = -1;
pub const ALOOPER_POLL_CALLBACK: libc::c_int = -2;
pub const ALOOPER_POLL_TIMEOUT: libc::c_int = -3;
pub const ALOOPER_POLL_ERROR: libc::c_int = -4;
pub const ALOOPER_EVENT_INPUT: libc::c_int = 1 << 0;
pub const ALOOPER_EVENT_OUTPUT: libc::c_int = 1 << 1;
pub const ALOOPER_EVENT_ERROR: libc::c_int = 1 << 2;
pub const ALOOPER_EVENT_HANGUP: libc::c_int = 1 << 3;
pub const ALOOPER_EVENT_INVALID: libc::c_int = 1 << 4;
pub type ALooper_callbackFunc = extern fn(libc::c_int, libc::c_int, *mut libc::c_void) -> libc::c_int;

View File

@@ -1,340 +0,0 @@
#![cfg(target_os = "android")]
extern crate android_glue;
use libc;
use std::sync::mpsc::{Receiver, channel};
use std::os::raw::c_void;
use {CreationError, Event, WindowEvent, MouseCursor};
use CreationError::OsError;
use WindowId as RootWindowId;
use events::{Touch, TouchPhase};
use window::MonitorId as RootMonitorId;
use std::collections::VecDeque;
use std::cell::RefCell;
use CursorState;
use WindowAttributes;
pub struct EventsLoop {
event_rx: Receiver<android_glue::Event>,
suspend_callback: RefCell<Option<Box<Fn(bool) -> ()>>>
}
#[derive(Clone)]
pub struct EventsLoopProxy;
impl EventsLoop {
pub fn new() -> EventsLoop {
let (tx, rx) = channel();
android_glue::add_sender(tx);
EventsLoop {
event_rx: rx,
suspend_callback: RefCell::new(None),
}
}
#[inline]
pub fn get_available_monitors(&self) -> VecDeque<MonitorId> {
let mut rb = VecDeque::new();
rb.push_back(MonitorId);
rb
}
#[inline]
pub fn get_primary_monitor(&self) -> MonitorId {
MonitorId
}
pub fn poll_events<F>(&mut self, mut callback: F)
where F: FnMut(::Event)
{
while let Ok(event) = self.event_rx.try_recv() {
let e = match event{
android_glue::Event::EventMotion(motion) => {
Some(Event::WindowEvent {
window_id: RootWindowId(WindowId),
event: WindowEvent::Touch(Touch {
phase: match motion.action {
android_glue::MotionAction::Down => TouchPhase::Started,
android_glue::MotionAction::Move => TouchPhase::Moved,
android_glue::MotionAction::Up => TouchPhase::Ended,
android_glue::MotionAction::Cancel => TouchPhase::Cancelled,
},
location: (motion.x as f64, motion.y as f64),
id: motion.pointer_id as u64,
device_id: DEVICE_ID,
}),
})
},
android_glue::Event::InitWindow => {
// The activity went to foreground.
if let Some(cb) = self.suspend_callback.borrow().as_ref() {
(*cb)(false);
}
Some(Event::Suspended(false))
},
android_glue::Event::TermWindow => {
// The activity went to background.
if let Some(cb) = self.suspend_callback.borrow().as_ref() {
(*cb)(true);
}
Some(Event::Suspended(true))
},
android_glue::Event::WindowResized |
android_glue::Event::ConfigChanged => {
// Activity Orientation changed or resized.
let native_window = unsafe { android_glue::get_native_window() };
if native_window.is_null() {
None
} else {
let w = unsafe { ffi::ANativeWindow_getWidth(native_window as *const _) } as u32;
let h = unsafe { ffi::ANativeWindow_getHeight(native_window as *const _) } as u32;
Some(Event::WindowEvent {
window_id: RootWindowId(WindowId),
event: WindowEvent::Resized(w, h),
})
}
},
android_glue::Event::WindowRedrawNeeded => {
// The activity needs to be redrawn.
Some(Event::WindowEvent {
window_id: RootWindowId(WindowId),
event: WindowEvent::Refresh,
})
}
android_glue::Event::Wake => {
Some(Event::Awakened)
}
_ => {
None
}
};
if let Some(event) = e {
callback(event);
}
};
}
pub fn set_suspend_callback(&self, cb: Option<Box<Fn(bool) -> ()>>) {
*self.suspend_callback.borrow_mut() = cb;
}
pub fn run_forever<F>(&mut self, mut callback: F)
where F: FnMut(::Event) -> ::ControlFlow,
{
// Yeah that's a very bad implementation.
loop {
let mut control_flow = ::ControlFlow::Continue;
self.poll_events(|e| {
if let ::ControlFlow::Break = callback(e) {
control_flow = ::ControlFlow::Break;
}
});
if let ::ControlFlow::Break = control_flow {
break;
}
::std::thread::sleep(::std::time::Duration::from_millis(5));
}
}
pub fn create_proxy(&self) -> EventsLoopProxy {
EventsLoopProxy
}
}
impl EventsLoopProxy {
pub fn wakeup(&self) -> Result<(), ::EventsLoopClosed> {
android_glue::wake_event_loop();
Ok(())
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WindowId;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeviceId;
pub struct Window {
native_window: *const c_void,
}
#[derive(Clone)]
pub struct MonitorId;
mod ffi;
impl MonitorId {
#[inline]
pub fn get_name(&self) -> Option<String> {
Some("Primary".to_string())
}
#[inline]
pub fn get_dimensions(&self) -> (u32, u32) {
unsafe {
let window = android_glue::get_native_window();
(ffi::ANativeWindow_getWidth(window) as u32, ffi::ANativeWindow_getHeight(window) as u32)
}
}
#[inline]
pub fn get_position(&self) -> (i32, i32) {
// Android assumes single screen
(0, 0)
}
#[inline]
pub fn get_hidpi_factor(&self) -> f32 {
1.0
}
}
#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes;
#[derive(Clone, Default)]
pub struct PlatformSpecificHeadlessBuilderAttributes;
impl Window {
pub fn new(_: &EventsLoop, win_attribs: &WindowAttributes,
_: &PlatformSpecificWindowBuilderAttributes)
-> Result<Window, CreationError>
{
// not implemented
assert!(win_attribs.min_dimensions.is_none());
assert!(win_attribs.max_dimensions.is_none());
let native_window = unsafe { android_glue::get_native_window() };
if native_window.is_null() {
return Err(OsError(format!("Android's native window is null")));
}
android_glue::set_multitouch(win_attribs.multitouch);
Ok(Window {
native_window: native_window as *const _,
})
}
#[inline]
pub fn get_native_window(&self) -> *const c_void {
self.native_window
}
#[inline]
pub fn set_title(&self, _: &str) {
}
#[inline]
pub fn show(&self) {
}
#[inline]
pub fn hide(&self) {
}
#[inline]
pub fn get_position(&self) -> Option<(i32, i32)> {
None
}
#[inline]
pub fn get_inner_position(&self) -> Option<(i32, i32)> {
None
}
#[inline]
pub fn set_position(&self, _x: i32, _y: i32) {
}
#[inline]
pub fn set_min_dimensions(&self, _dimensions: Option<(u32, u32)>) { }
#[inline]
pub fn set_max_dimensions(&self, _dimensions: Option<(u32, u32)>) { }
#[inline]
pub fn get_inner_size(&self) -> Option<(u32, u32)> {
if self.native_window.is_null() {
None
} else {
Some((
unsafe { ffi::ANativeWindow_getWidth(self.native_window as *const _) } as u32,
unsafe { ffi::ANativeWindow_getHeight(self.native_window as *const _) } as u32
))
}
}
#[inline]
pub fn get_outer_size(&self) -> Option<(u32, u32)> {
self.get_inner_size()
}
#[inline]
pub fn set_inner_size(&self, _x: u32, _y: u32) {
}
#[inline]
pub fn platform_display(&self) -> *mut libc::c_void {
unimplemented!();
}
#[inline]
pub fn platform_window(&self) -> *mut libc::c_void {
unimplemented!()
}
#[inline]
pub fn set_cursor(&self, _: MouseCursor) {
}
#[inline]
pub fn set_cursor_state(&self, _state: CursorState) -> Result<(), String> {
Ok(())
}
#[inline]
pub fn hidpi_factor(&self) -> f32 {
1.0
}
#[inline]
pub fn set_cursor_position(&self, _x: i32, _y: i32) -> Result<(), ()> {
Ok(())
}
#[inline]
pub fn set_maximized(&self, _maximized: bool) {
// Android has single screen maximized apps so nothing to do
}
#[inline]
pub fn set_fullscreen(&self, _monitor: Option<RootMonitorId>) {
// Android has single screen maximized apps so nothing to do
}
#[inline]
pub fn set_decorations(&self, _decorations: bool) {
// N/A
}
#[inline]
pub fn get_current_monitor(&self) -> RootMonitorId {
RootMonitorId{inner: MonitorId}
}
pub fn id(&self) -> WindowId {
WindowId
}
}
unsafe impl Send for Window {}
unsafe impl Sync for Window {}
// Constant device ID, to be removed when this backend is updated to report real device IDs.
const DEVICE_ID: ::DeviceId = ::DeviceId(DeviceId);

View File

@@ -1,316 +0,0 @@
#![allow(dead_code)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
use std::os::raw::{c_int, c_char, c_void, c_ulong, c_double, c_long, c_ushort};
#[cfg(test)]
use std::mem;
pub type EM_BOOL = c_int;
pub type EM_UTF8 = c_char;
pub type EMSCRIPTEN_RESULT = c_int;
pub const EM_TRUE: EM_BOOL = 1;
pub const EM_FALSE: EM_BOOL = 0;
// values for EMSCRIPTEN_RESULT
pub const EMSCRIPTEN_RESULT_SUCCESS: c_int = 0;
pub const EMSCRIPTEN_RESULT_DEFERRED: c_int = 1;
pub const EMSCRIPTEN_RESULT_NOT_SUPPORTED: c_int = -1;
pub const EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED: c_int = -2;
pub const EMSCRIPTEN_RESULT_INVALID_TARGET: c_int = -3;
pub const EMSCRIPTEN_RESULT_UNKNOWN_TARGET: c_int = -4;
pub const EMSCRIPTEN_RESULT_INVALID_PARAM: c_int = -5;
pub const EMSCRIPTEN_RESULT_FAILED: c_int = -6;
pub const EMSCRIPTEN_RESULT_NO_DATA: c_int = -7;
// values for EMSCRIPTEN EVENT
pub const EMSCRIPTEN_EVENT_KEYPRESS: c_int = 1;
pub const EMSCRIPTEN_EVENT_KEYDOWN: c_int = 2;
pub const EMSCRIPTEN_EVENT_KEYUP: c_int = 3;
pub const EMSCRIPTEN_EVENT_CLICK: c_int = 4;
pub const EMSCRIPTEN_EVENT_MOUSEDOWN: c_int = 5;
pub const EMSCRIPTEN_EVENT_MOUSEUP: c_int = 6;
pub const EMSCRIPTEN_EVENT_DBLCLICK: c_int = 7;
pub const EMSCRIPTEN_EVENT_MOUSEMOVE: c_int = 8;
pub const EMSCRIPTEN_EVENT_WHEEL: c_int = 9;
pub const EMSCRIPTEN_EVENT_RESIZE: c_int = 10;
pub const EMSCRIPTEN_EVENT_SCROLL: c_int = 11;
pub const EMSCRIPTEN_EVENT_BLUR: c_int = 12;
pub const EMSCRIPTEN_EVENT_FOCUS: c_int = 13;
pub const EMSCRIPTEN_EVENT_FOCUSIN: c_int = 14;
pub const EMSCRIPTEN_EVENT_FOCUSOUT: c_int = 15;
pub const EMSCRIPTEN_EVENT_DEVICEORIENTATION: c_int = 16;
pub const EMSCRIPTEN_EVENT_DEVICEMOTION: c_int = 17;
pub const EMSCRIPTEN_EVENT_ORIENTATIONCHANGE: c_int = 18;
pub const EMSCRIPTEN_EVENT_FULLSCREENCHANGE: c_int = 19;
pub const EMSCRIPTEN_EVENT_POINTERLOCKCHANGE: c_int = 20;
pub const EMSCRIPTEN_EVENT_VISIBILITYCHANGE: c_int = 21;
pub const EMSCRIPTEN_EVENT_TOUCHSTART: c_int = 22;
pub const EMSCRIPTEN_EVENT_TOUCHEND: c_int = 23;
pub const EMSCRIPTEN_EVENT_TOUCHMOVE: c_int = 24;
pub const EMSCRIPTEN_EVENT_TOUCHCANCEL: c_int = 25;
pub const EMSCRIPTEN_EVENT_GAMEPADCONNECTED: c_int = 26;
pub const EMSCRIPTEN_EVENT_GAMEPADDISCONNECTED: c_int = 27;
pub const EMSCRIPTEN_EVENT_BEFOREUNLOAD: c_int = 28;
pub const EMSCRIPTEN_EVENT_BATTERYCHARGINGCHANGE: c_int = 29;
pub const EMSCRIPTEN_EVENT_BATTERYLEVELCHANGE: c_int = 30;
pub const EMSCRIPTEN_EVENT_WEBGLCONTEXTLOST: c_int = 31;
pub const EMSCRIPTEN_EVENT_WEBGLCONTEXTRESTORED: c_int = 32;
pub const EMSCRIPTEN_EVENT_MOUSEENTER: c_int = 33;
pub const EMSCRIPTEN_EVENT_MOUSELEAVE: c_int = 34;
pub const EMSCRIPTEN_EVENT_MOUSEOVER: c_int = 35;
pub const EMSCRIPTEN_EVENT_MOUSEOUT: c_int = 36;
pub const EMSCRIPTEN_EVENT_CANVASRESIZED: c_int = 37;
pub const EMSCRIPTEN_EVENT_POINTERLOCKERROR: c_int = 38;
pub const EM_HTML5_SHORT_STRING_LEN_BYTES: usize = 32;
pub const DOM_KEY_LOCATION_STANDARD: c_ulong = 0x00;
pub const DOM_KEY_LOCATION_LEFT: c_ulong = 0x01;
pub const DOM_KEY_LOCATION_RIGHT: c_ulong = 0x02;
pub const DOM_KEY_LOCATION_NUMPAD: c_ulong = 0x03;
pub type em_callback_func = Option<unsafe extern "C" fn()>;
pub type em_key_callback_func = Option<unsafe extern "C" fn(
eventType: c_int,
keyEvent: *const EmscriptenKeyboardEvent,
userData: *mut c_void) -> EM_BOOL>;
pub type em_mouse_callback_func = Option<unsafe extern "C" fn(
eventType: c_int,
mouseEvent: *const EmscriptenMouseEvent,
userData: *mut c_void) -> EM_BOOL>;
pub type em_pointerlockchange_callback_func = Option<unsafe extern "C" fn(
eventType: c_int,
pointerlockChangeEvent: *const EmscriptenPointerlockChangeEvent,
userData: *mut c_void) -> EM_BOOL>;
pub type em_fullscreenchange_callback_func = Option<unsafe extern "C" fn(
eventType: c_int,
fullscreenChangeEvent: *const EmscriptenFullscreenChangeEvent,
userData: *mut c_void) -> EM_BOOL>;
pub type em_touch_callback_func = Option<unsafe extern "C" fn(
eventType: c_int,
touchEvent: *const EmscriptenTouchEvent,
userData: *mut c_void) -> EM_BOOL>;
#[repr(C)]
pub struct EmscriptenFullscreenChangeEvent {
pub isFullscreen: c_int,
pub fullscreenEnabled: c_int,
pub nodeName: [c_char; 128usize],
pub id: [c_char; 128usize],
pub elementWidth: c_int,
pub elementHeight: c_int,
pub screenWidth: c_int,
pub screenHeight: c_int,
}
#[test]
fn bindgen_test_layout_EmscriptenFullscreenChangeEvent() {
assert_eq!(mem::size_of::<EmscriptenFullscreenChangeEvent>(), 280usize);
assert_eq!(mem::align_of::<EmscriptenFullscreenChangeEvent>(), 4usize);
}
#[repr(C)]
#[derive(Debug, Copy)]
pub struct EmscriptenKeyboardEvent {
pub key: [c_char; 32usize],
pub code: [c_char; 32usize],
pub location: c_ulong,
pub ctrlKey: c_int,
pub shiftKey: c_int,
pub altKey: c_int,
pub metaKey: c_int,
pub repeat: c_int,
pub locale: [c_char; 32usize],
pub charValue: [c_char; 32usize],
pub charCode: c_ulong,
pub keyCode: c_ulong,
pub which: c_ulong,
}
#[test]
fn bindgen_test_layout_EmscriptenKeyboardEvent() {
assert_eq!(mem::size_of::<EmscriptenKeyboardEvent>(), 184usize);
assert_eq!(mem::align_of::<EmscriptenKeyboardEvent>(), 8usize);
}
impl Clone for EmscriptenKeyboardEvent {
fn clone(&self) -> Self { *self }
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct EmscriptenMouseEvent {
pub timestamp: f64,
pub screenX: c_long,
pub screenY: c_long,
pub clientX: c_long,
pub clientY: c_long,
pub ctrlKey: c_int,
pub shiftKey: c_int,
pub altKey: c_int,
pub metaKey: c_int,
pub button: c_ushort,
pub buttons: c_ushort,
pub movementX: c_long,
pub movementY: c_long,
pub targetX: c_long,
pub targetY: c_long,
pub canvasX: c_long,
pub canvasY: c_long,
pub padding: c_long,
}
#[test]
fn bindgen_test_layout_EmscriptenMouseEvent() {
assert_eq!(mem::size_of::<EmscriptenMouseEvent>(), 120usize);
assert_eq!(mem::align_of::<EmscriptenMouseEvent>(), 8usize);
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct EmscriptenTouchPoint {
pub identifier: c_long,
pub screenX: c_long,
pub screenY: c_long,
pub clientX: c_long,
pub clientY: c_long,
pub pageX: c_long,
pub pageY: c_long,
pub isChanged: c_int,
pub onTarget: c_int,
pub targetX: c_long,
pub targetY: c_long,
pub canvasX: c_long,
pub canvasY: c_long,
}
#[test]
fn bindgen_test_layout_EmscriptenTouchPoint() {
assert_eq!(mem::size_of::<EmscriptenTouchPoint>(), 96usize);
assert_eq!(mem::align_of::<EmscriptenTouchPoint>(), 8usize);
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct EmscriptenTouchEvent {
pub numTouches: c_int,
pub ctrlKey: c_int,
pub shiftKey: c_int,
pub altKey: c_int,
pub metaKey: c_int,
pub touches: [EmscriptenTouchPoint; 32usize],
}
#[test]
fn bindgen_test_layout_EmscriptenTouchEvent() {
assert_eq!(mem::size_of::<EmscriptenTouchEvent>(), 3096usize);
assert_eq!(mem::align_of::<EmscriptenTouchEvent>(), 8usize);
}
#[repr(C)]
pub struct EmscriptenPointerlockChangeEvent {
pub isActive: c_int,
pub nodeName: [c_char; 128usize],
pub id: [c_char; 128usize],
}
#[test]
fn bindgen_test_layout_EmscriptenPointerlockChangeEvent() {
assert_eq!(mem::size_of::<EmscriptenPointerlockChangeEvent>(), 260usize);
assert_eq!(mem::align_of::<EmscriptenPointerlockChangeEvent>(), 4usize);
}
extern "C" {
pub fn emscripten_set_canvas_size(
width: c_int, height: c_int)
-> EMSCRIPTEN_RESULT;
pub fn emscripten_get_canvas_size(
width: *mut c_int, height: *mut c_int,
is_fullscreen: *mut c_int)
-> EMSCRIPTEN_RESULT;
pub fn emscripten_set_element_css_size(
target: *const c_char, width: c_double,
height: c_double) -> EMSCRIPTEN_RESULT;
pub fn emscripten_get_element_css_size(
target: *const c_char, width: *mut c_double,
height: *mut c_double) -> EMSCRIPTEN_RESULT;
pub fn emscripten_request_pointerlock(
target: *const c_char, deferUntilInEventHandler: EM_BOOL)
-> EMSCRIPTEN_RESULT;
pub fn emscripten_exit_pointerlock() -> EMSCRIPTEN_RESULT;
pub fn emscripten_request_fullscreen(
target: *const c_char, deferUntilInEventHandler: EM_BOOL)
-> EMSCRIPTEN_RESULT;
pub fn emscripten_exit_fullscreen() -> EMSCRIPTEN_RESULT;
pub fn emscripten_set_keydown_callback(
target: *const c_char, userData: *mut c_void,
useCapture: EM_BOOL, callback: em_key_callback_func)
-> EMSCRIPTEN_RESULT;
pub fn emscripten_set_keyup_callback(
target: *const c_char, userData: *mut c_void,
useCapture: EM_BOOL, callback: em_key_callback_func)
-> EMSCRIPTEN_RESULT;
pub fn emscripten_set_mousemove_callback(
target: *const c_char, user_data: *mut c_void,
use_capture: EM_BOOL, callback: em_mouse_callback_func)
-> EMSCRIPTEN_RESULT;
pub fn emscripten_set_mousedown_callback(
target: *const c_char, user_data: *mut c_void,
use_capture: EM_BOOL, callback: em_mouse_callback_func)
-> EMSCRIPTEN_RESULT;
pub fn emscripten_set_mouseup_callback(
target: *const c_char, user_data: *mut c_void,
use_capture: EM_BOOL, callback: em_mouse_callback_func)
-> EMSCRIPTEN_RESULT;
pub fn emscripten_hide_mouse();
pub fn emscripten_get_device_pixel_ratio() -> f64;
pub fn emscripten_set_pointerlockchange_callback(
target: *const c_char, userData: *mut c_void, useCapture: EM_BOOL,
callback: em_pointerlockchange_callback_func) -> EMSCRIPTEN_RESULT;
pub fn emscripten_set_fullscreenchange_callback(
target: *const c_char, userData: *mut c_void, useCapture: EM_BOOL,
callback: em_fullscreenchange_callback_func) -> EMSCRIPTEN_RESULT;
pub fn emscripten_asm_const(code: *const c_char);
pub fn emscripten_set_main_loop(
func: em_callback_func, fps: c_int, simulate_infinite_loop: EM_BOOL);
pub fn emscripten_cancel_main_loop();
pub fn emscripten_set_touchstart_callback(
target: *const c_char, userData: *mut c_void,
useCapture: c_int, callback: em_touch_callback_func)
-> EMSCRIPTEN_RESULT;
pub fn emscripten_set_touchend_callback(
target: *const c_char, userData: *mut c_void,
useCapture: c_int, callback: em_touch_callback_func)
-> EMSCRIPTEN_RESULT;
pub fn emscripten_set_touchmove_callback(
target: *const c_char, userData: *mut c_void,
useCapture: c_int, callback: em_touch_callback_func)
-> EMSCRIPTEN_RESULT;
pub fn emscripten_set_touchcancel_callback(
target: *const c_char, userData: *mut c_void,
useCapture: c_int, callback: em_touch_callback_func)
-> EMSCRIPTEN_RESULT;
}

File diff suppressed because it is too large Load Diff

317
src/platform/ios.rs Normal file
View File

@@ -0,0 +1,317 @@
#![cfg(target_os = "ios")]
use std::os::raw::c_void;
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() as _
}
#[inline]
fn ui_view_controller(&self) -> *mut c_void {
self.window.ui_view_controller() as _
}
#[inline]
fn ui_view(&self) -> *mut c_void {
self.window.ui_view() as _
}
#[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 root view class used by the [`Window`], otherwise a barebones [`UIView`] is provided.
///
/// An instance of the class will be initialized by calling [`-[UIView initWithFrame:]`](https://developer.apple.com/documentation/uikit/uiview/1622488-initwithframe?language=objc).
///
/// [`UIView`]: https://developer.apple.com/documentation/uikit/uiview?language=objc
fn with_root_view_class(self, root_view_class: *const c_void) -> WindowBuilder;
/// 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_root_view_class(mut self, root_view_class: *const c_void) -> WindowBuilder {
self.platform_specific.root_view_class = unsafe { &*(root_view_class as *const _) };
self
}
#[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 {
self.inner.ui_screen() as _
}
#[inline]
fn preferred_video_mode(&self) -> VideoMode {
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,107 +0,0 @@
use std::ffi::CString;
use libc;
use objc::runtime::{ Object, Class };
#[allow(non_camel_case_types)]
pub type id = *mut Object;
#[allow(non_camel_case_types)]
#[allow(non_upper_case_globals)]
pub const nil: id = 0 as id;
pub type CFStringRef = *const libc::c_void;
pub type CFTimeInterval = f64;
pub type Boolean = u32;
#[allow(non_upper_case_globals)]
pub const kCFRunLoopRunHandledSource: i32 = 4;
#[cfg(target_pointer_width = "32")]
pub type CGFloat = f32;
#[cfg(target_pointer_width = "64")]
pub type CGFloat = f64;
#[cfg(target_pointer_width = "32")]
pub type NSUInteger = u32;
#[cfg(target_pointer_width = "64")]
pub type NSUInteger = u64;
#[repr(C)]
#[derive(Debug, Clone)]
pub struct CGPoint {
pub x: CGFloat,
pub y: CGFloat,
}
#[repr(C)]
#[derive(Debug, Clone)]
pub struct CGRect {
pub origin: CGPoint,
pub size: CGSize
}
#[repr(C)]
#[derive(Debug, Clone)]
pub struct CGSize {
pub width: CGFloat,
pub height: CGFloat
}
#[link(name = "UIKit", kind = "framework")]
#[link(name = "CoreFoundation", kind = "framework")]
#[link(name = "GlKit", kind = "framework")]
extern {
pub static kCFRunLoopDefaultMode: CFStringRef;
// int UIApplicationMain ( int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName );
pub fn UIApplicationMain(argc: libc::c_int, argv: *const libc::c_char, principalClassName: id, delegateClassName: id) -> libc::c_int;
// SInt32 CFRunLoopRunInMode ( CFStringRef mode, CFTimeInterval seconds, Boolean returnAfterSourceHandled );
pub fn CFRunLoopRunInMode(mode: CFStringRef, seconds: CFTimeInterval, returnAfterSourceHandled: Boolean) -> i32;
}
extern {
pub fn setjmp(env: *mut libc::c_void) -> libc::c_int;
pub fn longjmp(env: *mut libc::c_void, val: libc::c_int);
}
pub trait NSString: Sized {
unsafe fn alloc(_: Self) -> id {
msg_send![class("NSString"), alloc]
}
#[allow(non_snake_case)]
unsafe fn initWithUTF8String_(self, c_string: *const i8) -> id;
#[allow(non_snake_case)]
unsafe fn stringByAppendingString_(self, other: id) -> id;
unsafe fn init_str(self, string: &str) -> Self;
#[allow(non_snake_case)]
unsafe fn UTF8String(self) -> *const libc::c_char;
}
impl NSString for id {
unsafe fn initWithUTF8String_(self, c_string: *const i8) -> id {
msg_send![self, initWithUTF8String:c_string as id]
}
unsafe fn stringByAppendingString_(self, other: id) -> id {
msg_send![self, stringByAppendingString:other]
}
unsafe fn init_str(self, string: &str) -> id {
let cstring = CString::new(string).unwrap();
self.initWithUTF8String_(cstring.as_ptr())
}
unsafe fn UTF8String(self) -> *const libc::c_char {
msg_send![self, UTF8String]
}
}
#[inline]
pub fn class(name: &str) -> *mut Class {
unsafe {
::std::mem::transmute(Class::get(name))
}
}

View File

@@ -1,564 +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_glutin_app() {
//! start_inner()
//! }
//!
//! fn start_inner() {
//! ...
//! }
//!
//! ```
//!
//! Compile project and then drag resulting .a into Xcode project. Add glutin.h to xcode.
//!
//! ```ignore
//! void start_glutin_app();
//! ```
//!
//! Use start_glutin_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 glutin:
//!
//! - applicationDidBecomeActive is Focused(true)
//! - applicationWillResignActive is Focused(false)
//! - applicationDidEnterBackground is Suspended(true)
//! - applicationWillEnterForeground is Suspended(false)
//! - applicationWillTerminate is Destroyed
//!
//! Keep in mind that after Destroyed event is received every attempt to draw with
//! opengl will result in segfault.
//!
//! Also note that app will not receive Destroyed event if suspended, it will be SIGKILL'ed
#![cfg(target_os = "ios")]
use std::collections::VecDeque;
use std::ptr;
use std::mem;
use std::os::raw::c_void;
use libc;
use libc::c_int;
use objc::runtime::{Class, Object, Sel, BOOL, YES };
use objc::declare::{ ClassDecl };
use { CreationError, CursorState, MouseCursor, WindowAttributes };
use WindowId as RootEventId;
use WindowEvent;
use Event;
use events::{ Touch, TouchPhase };
use window::MonitorId as RootMonitorId;
mod ffi;
use self::ffi::{
setjmp,
UIApplicationMain,
CFTimeInterval,
CFRunLoopRunInMode,
kCFRunLoopDefaultMode,
kCFRunLoopRunHandledSource,
id,
nil,
NSString,
CGFloat,
longjmp,
CGRect,
CGPoint
};
static mut jmpbuf: [c_int;27] = [0;27];
#[derive(Clone)]
pub struct MonitorId;
pub struct Window {
delegate_state: *mut DelegateState
}
#[derive(Clone)]
pub struct WindowProxy;
#[derive(Debug)]
struct DelegateState {
events_queue: VecDeque<Event>,
window: id,
controller: id,
size: (u32,u32),
scale: f32
}
impl DelegateState {
#[inline]
fn new(window: id, controller:id, size: (u32,u32), scale: f32) -> DelegateState {
DelegateState {
events_queue: VecDeque::new(),
window: window,
controller: controller,
size: size,
scale: scale
}
}
}
impl MonitorId {
#[inline]
pub fn get_name(&self) -> Option<String> {
Some("Primary".to_string())
}
#[inline]
pub fn get_dimensions(&self) -> (u32, u32) {
unimplemented!()
}
#[inline]
pub fn get_position(&self) -> (i32, i32) {
// iOS assumes single screen
(0, 0)
}
#[inline]
pub fn get_hidpi_factor(&self) -> f32 {
1.0
}
}
pub struct EventsLoop {
delegate_state: *mut DelegateState
}
#[derive(Clone)]
pub struct EventsLoopProxy;
impl EventsLoop {
pub fn new() -> EventsLoop {
unsafe {
if setjmp(mem::transmute(&mut jmpbuf)) != 0 {
let app: id = msg_send![Class::get("UIApplication").unwrap(), sharedApplication];
let delegate: id = msg_send![app, delegate];
let state: *mut c_void = *(&*delegate).get_ivar("glutinState");
let state = state as *mut DelegateState;
let events_loop = EventsLoop {
delegate_state: state
};
return events_loop;
}
}
create_delegate_class();
create_view_class();
start_app();
panic!("Couldn't create UIApplication")
}
#[inline]
pub fn get_available_monitors(&self) -> VecDeque<MonitorId> {
let mut rb = VecDeque::new();
rb.push_back(MonitorId);
rb
}
#[inline]
pub fn get_primary_monitor(&self) -> MonitorId {
MonitorId
}
pub fn poll_events<F>(&mut self, mut callback: F)
where F: FnMut(::Event)
{
unsafe {
let state = &mut *self.delegate_state;
if let Some(event) = state.events_queue.pop_front() {
callback(event);
return;
}
// jump hack, so we won't quit on willTerminate event before processing it
if setjmp(mem::transmute(&mut jmpbuf)) != 0 {
if let Some(event) = state.events_queue.pop_front() {
callback(event);
return;
}
}
// run runloop
let seconds: CFTimeInterval = 0.000002;
while CFRunLoopRunInMode(kCFRunLoopDefaultMode, seconds, 1) == kCFRunLoopRunHandledSource {}
if let Some(event) = state.events_queue.pop_front() {
callback(event)
}
}
}
pub fn run_forever<F>(&mut self, mut callback: F)
where F: FnMut(::Event) -> ::ControlFlow,
{
// Yeah that's a very bad implementation.
loop {
let mut control_flow = ::ControlFlow::Continue;
self.poll_events(|e| {
if let ::ControlFlow::Break = callback(e) {
control_flow = ::ControlFlow::Break;
}
});
if let ::ControlFlow::Break = control_flow {
break;
}
::std::thread::sleep(::std::time::Duration::from_millis(5));
}
}
pub fn create_proxy(&self) -> EventsLoopProxy {
EventsLoopProxy
}
}
impl EventsLoopProxy {
pub fn wakeup(&self) -> Result<(), ::EventsLoopClosed> {
unimplemented!()
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WindowId;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeviceId;
#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes;
impl Window {
pub fn new(ev: &EventsLoop, _: &WindowAttributes, _: &PlatformSpecificWindowBuilderAttributes)
-> Result<Window, CreationError>
{
Ok(Window {
delegate_state: ev.delegate_state,
})
}
#[inline]
pub fn set_title(&self, _: &str) {
}
#[inline]
pub fn show(&self) {
}
#[inline]
pub fn hide(&self) {
}
#[inline]
pub fn get_position(&self) -> Option<(i32, i32)> {
None
}
#[inline]
pub fn get_inner_position(&self) -> Option<(i32, i32)> {
None
}
#[inline]
pub fn set_position(&self, _x: i32, _y: i32) {
}
#[inline]
pub fn get_inner_size(&self) -> Option<(u32, u32)> {
unsafe { Some((&*self.delegate_state).size) }
}
#[inline]
pub fn get_outer_size(&self) -> Option<(u32, u32)> {
self.get_inner_size()
}
#[inline]
pub fn set_inner_size(&self, _x: u32, _y: u32) {
}
#[inline]
pub fn set_min_dimensions(&self, _dimensions: Option<(u32, u32)>) { }
#[inline]
pub fn set_max_dimensions(&self, _dimensions: Option<(u32, u32)>) { }
#[inline]
pub fn platform_display(&self) -> *mut libc::c_void {
unimplemented!();
}
#[inline]
pub fn platform_window(&self) -> *mut libc::c_void {
unimplemented!()
}
#[inline]
pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) {
}
#[inline]
pub fn set_cursor(&self, _: MouseCursor) {
}
#[inline]
pub fn set_cursor_state(&self, _: CursorState) -> Result<(), String> {
Ok(())
}
#[inline]
pub fn hidpi_factor(&self) -> f32 {
unsafe { (&*self.delegate_state) }.scale
}
#[inline]
pub fn set_cursor_position(&self, _x: i32, _y: i32) -> Result<(), ()> {
unimplemented!();
}
#[inline]
pub fn create_window_proxy(&self) -> WindowProxy {
WindowProxy
}
#[inline]
pub fn set_maximized(&self, _maximized: bool) {
// iOS has single screen maximized apps so nothing to do
}
#[inline]
pub fn set_fullscreen(&self, _monitor: Option<RootMonitorId>) {
// iOS has single screen maximized apps so nothing to do
}
#[inline]
pub fn set_decorations(&self, _decorations: bool) {
// N/A
}
#[inline]
pub fn get_current_monitor(&self) -> RootMonitorId {
RootMonitorId{inner: MonitorId}
}
#[inline]
pub fn id(&self) -> WindowId {
WindowId
}
}
fn create_delegate_class() {
extern fn did_finish_launching(this: &mut Object, _: Sel, _: id, _: id) -> BOOL {
unsafe {
let main_screen: id = msg_send![Class::get("UIScreen").unwrap(), mainScreen];
let bounds: CGRect = msg_send![main_screen, bounds];
let scale: CGFloat = msg_send![main_screen, nativeScale];
let window: id = msg_send![Class::get("UIWindow").unwrap(), alloc];
let window: id = msg_send![window, initWithFrame:bounds.clone()];
let size = (bounds.size.width as u32, bounds.size.height as u32);
let view_controller: id = msg_send![Class::get("MainViewController").unwrap(), alloc];
let view_controller: id = msg_send![view_controller, init];
let _: () = msg_send![window, setRootViewController:view_controller];
let _: () = msg_send![window, makeKeyAndVisible];
let state = Box::new(DelegateState::new(window, view_controller, size, scale as f32));
let state_ptr: *mut DelegateState = mem::transmute(state);
this.set_ivar("glutinState", state_ptr as *mut c_void);
let _: () = msg_send![this, performSelector:sel!(postLaunch:) withObject:nil afterDelay:0.0];
}
YES
}
extern fn post_launch(_: &Object, _: Sel, _: id) {
unsafe { longjmp(mem::transmute(&mut jmpbuf),1); }
}
extern fn did_become_active(this: &Object, _: Sel, _: id) {
unsafe {
let state: *mut c_void = *this.get_ivar("glutinState");
let state = &mut *(state as *mut DelegateState);
state.events_queue.push_back(Event::WindowEvent {
window_id: RootEventId(WindowId),
event: WindowEvent::Focused(true),
});
}
}
extern fn will_resign_active(this: &Object, _: Sel, _: id) {
unsafe {
let state: *mut c_void = *this.get_ivar("glutinState");
let state = &mut *(state as *mut DelegateState);
state.events_queue.push_back(Event::WindowEvent {
window_id: RootEventId(WindowId),
event: WindowEvent::Focused(false),
});
}
}
extern fn will_enter_foreground(this: &Object, _: Sel, _: id) {
unsafe {
let state: *mut c_void = *this.get_ivar("glutinState");
let state = &mut *(state as *mut DelegateState);
state.events_queue.push_back(Event::Suspended(false));
}
}
extern fn did_enter_background(this: &Object, _: Sel, _: id) {
unsafe {
let state: *mut c_void = *this.get_ivar("glutinState");
let state = &mut *(state as *mut DelegateState);
state.events_queue.push_back(Event::Suspended(true));
}
}
extern fn will_terminate(this: &Object, _: Sel, _: id) {
unsafe {
let state: *mut c_void = *this.get_ivar("glutinState");
let state = &mut *(state as *mut DelegateState);
// push event to the front to garantee that we'll process it
// immidiatly after jump
state.events_queue.push_front(Event::WindowEvent {
window_id: RootEventId(WindowId),
event: WindowEvent::Destroyed,
});
longjmp(mem::transmute(&mut jmpbuf),1);
}
}
extern fn handle_touches(this: &Object, _: Sel, touches: id, _:id) {
unsafe {
let state: *mut c_void = *this.get_ivar("glutinState");
let state = &mut *(state as *mut DelegateState);
let touches_enum: id = msg_send![touches, objectEnumerator];
loop {
let touch: id = msg_send![touches_enum, nextObject];
if touch == nil {
break
}
let location: CGPoint = msg_send![touch, locationInView:nil];
let touch_id = touch as u64;
let phase: i32 = msg_send![touch, phase];
state.events_queue.push_back(Event::WindowEvent {
window_id: RootEventId(WindowId),
event: WindowEvent::Touch(Touch {
device_id: DEVICE_ID,
id: touch_id,
location: (location.x as f64, location.y as f64),
phase: match phase {
0 => TouchPhase::Started,
1 => TouchPhase::Moved,
// 2 is UITouchPhaseStationary and is not expected here
3 => TouchPhase::Ended,
4 => TouchPhase::Cancelled,
_ => panic!("unexpected touch phase: {:?}", phase)
}
}),
});
}
}
}
let ui_responder = Class::get("UIResponder").unwrap();
let mut decl = ClassDecl::new("AppDelegate", ui_responder).unwrap();
unsafe {
decl.add_method(sel!(application:didFinishLaunchingWithOptions:),
did_finish_launching as extern fn(&mut Object, Sel, id, id) -> BOOL);
decl.add_method(sel!(applicationDidBecomeActive:),
did_become_active as extern fn(&Object, Sel, id));
decl.add_method(sel!(applicationWillResignActive:),
will_resign_active as extern fn(&Object, Sel, id));
decl.add_method(sel!(applicationWillEnterForeground:),
will_enter_foreground as extern fn(&Object, Sel, id));
decl.add_method(sel!(applicationDidEnterBackground:),
did_enter_background as extern fn(&Object, Sel, id));
decl.add_method(sel!(applicationWillTerminate:),
will_terminate as extern fn(&Object, Sel, id));
decl.add_method(sel!(touchesBegan:withEvent:),
handle_touches as extern fn(this: &Object, _: Sel, _: id, _:id));
decl.add_method(sel!(touchesMoved:withEvent:),
handle_touches as extern fn(this: &Object, _: Sel, _: id, _:id));
decl.add_method(sel!(touchesEnded:withEvent:),
handle_touches as extern fn(this: &Object, _: Sel, _: id, _:id));
decl.add_method(sel!(touchesCancelled:withEvent:),
handle_touches as extern fn(this: &Object, _: Sel, _: id, _:id));
decl.add_method(sel!(postLaunch:),
post_launch as extern fn(&Object, Sel, id));
decl.add_ivar::<*mut c_void>("glutinState");
decl.register();
}
}
fn create_view_class() {
let ui_view_controller = Class::get("UIViewController").unwrap();
let decl = ClassDecl::new("MainViewController", ui_view_controller).unwrap();
decl.register();
}
#[inline]
fn start_app() {
unsafe {
UIApplicationMain(0, ptr::null(), nil, NSString::alloc(nil).init_str("AppDelegate"));
}
}
// Constant device ID, to be removed when this backend is updated to report real device IDs.
const DEVICE_ID: ::DeviceId = ::DeviceId(DeviceId);

View File

@@ -1,15 +0,0 @@
#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
#![allow(dead_code)]
use std::os::raw::{c_void, c_char, c_int};
pub const RTLD_LAZY: c_int = 0x001;
pub const RTLD_NOW: c_int = 0x002;
#[link="dl"]
extern {
pub fn dlopen(filename: *const c_char, flag: c_int) -> *mut c_void;
pub fn dlerror() -> *mut c_char;
pub fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void;
pub fn dlclose(handle: *mut c_void) -> c_int;
}

View File

@@ -1,451 +0,0 @@
#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
use std::collections::VecDeque;
use std::sync::Arc;
use std::env;
use {CreationError, CursorState, EventsLoopClosed, MouseCursor, ControlFlow};
use libc;
use self::x11::XConnection;
use self::x11::XError;
use self::x11::ffi::XVisualInfo;
pub use self::x11::XNotSupported;
use window::MonitorId as RootMonitorId;
mod dlopen;
pub mod wayland;
pub mod x11;
/// Environment variable specifying which backend should be used on unix platform.
///
/// Legal values are x11 and wayland. If this variable is set only the named backend
/// will be tried by winit. If it is not set, winit will try to connect to a wayland connection,
/// and if it fails will fallback on x11.
///
/// If this variable is set with any other value, winit will panic.
const BACKEND_PREFERENCE_ENV_VAR: &str = "WINIT_UNIX_BACKEND";
#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes {
pub visual_infos: Option<XVisualInfo>,
pub screen_id: Option<i32>,
}
lazy_static!(
pub static ref X11_BACKEND: Result<Arc<XConnection>, XNotSupported> = {
XConnection::new(Some(x_error_callback)).map(Arc::new)
};
);
pub enum Window {
X(x11::Window),
Wayland(wayland::Window)
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum WindowId {
X(x11::WindowId),
Wayland(wayland::WindowId)
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum DeviceId {
X(x11::DeviceId),
Wayland(wayland::DeviceId)
}
#[derive(Clone)]
pub enum MonitorId {
X(x11::MonitorId),
Wayland(wayland::MonitorId),
}
impl MonitorId {
#[inline]
pub fn get_name(&self) -> Option<String> {
match self {
&MonitorId::X(ref m) => m.get_name(),
&MonitorId::Wayland(ref m) => m.get_name(),
}
}
#[inline]
pub fn get_native_identifier(&self) -> u32 {
match self {
&MonitorId::X(ref m) => m.get_native_identifier(),
&MonitorId::Wayland(ref m) => m.get_native_identifier(),
}
}
#[inline]
pub fn get_dimensions(&self) -> (u32, u32) {
match self {
&MonitorId::X(ref m) => m.get_dimensions(),
&MonitorId::Wayland(ref m) => m.get_dimensions(),
}
}
#[inline]
pub fn get_position(&self) -> (i32, i32) {
match self {
&MonitorId::X(ref m) => m.get_position(),
&MonitorId::Wayland(ref m) => m.get_position(),
}
}
#[inline]
pub fn get_hidpi_factor(&self) -> f32 {
match self {
&MonitorId::X(ref m) => m.get_hidpi_factor(),
&MonitorId::Wayland(ref m) => m.get_hidpi_factor(),
}
}
}
impl Window {
#[inline]
pub fn new(events_loop: &EventsLoop,
window: &::WindowAttributes,
pl_attribs: &PlatformSpecificWindowBuilderAttributes)
-> Result<Self, CreationError>
{
match *events_loop {
EventsLoop::Wayland(ref evlp) => {
wayland::Window::new(evlp, window).map(Window::Wayland)
},
EventsLoop::X(ref el) => {
x11::Window::new(el, window, pl_attribs).map(Window::X)
},
}
}
#[inline]
pub fn id(&self) -> WindowId {
match self {
&Window::X(ref w) => WindowId::X(w.id()),
&Window::Wayland(ref w) => WindowId::Wayland(w.id())
}
}
#[inline]
pub fn set_title(&self, title: &str) {
match self {
&Window::X(ref w) => w.set_title(title),
&Window::Wayland(ref w) => w.set_title(title)
}
}
#[inline]
pub fn show(&self) {
match self {
&Window::X(ref w) => w.show(),
&Window::Wayland(ref w) => w.show()
}
}
#[inline]
pub fn hide(&self) {
match self {
&Window::X(ref w) => w.hide(),
&Window::Wayland(ref w) => w.hide()
}
}
#[inline]
pub fn get_position(&self) -> Option<(i32, i32)> {
match self {
&Window::X(ref w) => w.get_position(),
&Window::Wayland(ref w) => w.get_position()
}
}
#[inline]
pub fn get_inner_position(&self) -> Option<(i32, i32)> {
match self {
&Window::X(ref m) => m.get_inner_position(),
&Window::Wayland(ref m) => m.get_inner_position(),
}
}
#[inline]
pub fn set_position(&self, x: i32, y: i32) {
match self {
&Window::X(ref w) => w.set_position(x, y),
&Window::Wayland(ref w) => w.set_position(x, y)
}
}
#[inline]
pub fn get_inner_size(&self) -> Option<(u32, u32)> {
match self {
&Window::X(ref w) => w.get_inner_size(),
&Window::Wayland(ref w) => w.get_inner_size()
}
}
#[inline]
pub fn get_outer_size(&self) -> Option<(u32, u32)> {
match self {
&Window::X(ref w) => w.get_outer_size(),
&Window::Wayland(ref w) => w.get_outer_size()
}
}
#[inline]
pub fn set_inner_size(&self, x: u32, y: u32) {
match self {
&Window::X(ref w) => w.set_inner_size(x, y),
&Window::Wayland(ref w) => w.set_inner_size(x, y)
}
}
#[inline]
pub fn set_min_dimensions(&self, dimensions: Option<(u32, u32)>) {
match self {
&Window::X(ref w) => w.set_min_dimensions(dimensions),
&Window::Wayland(ref w) => w.set_min_dimensions(dimensions)
}
}
#[inline]
pub fn set_max_dimensions(&self, dimensions: Option<(u32, u32)>) {
match self {
&Window::X(ref w) => w.set_max_dimensions(dimensions),
&Window::Wayland(ref w) => w.set_max_dimensions(dimensions)
}
}
#[inline]
pub fn set_cursor(&self, cursor: MouseCursor) {
match self {
&Window::X(ref w) => w.set_cursor(cursor),
&Window::Wayland(ref w) => w.set_cursor(cursor)
}
}
#[inline]
pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
match self {
&Window::X(ref w) => w.set_cursor_state(state),
&Window::Wayland(ref w) => w.set_cursor_state(state)
}
}
#[inline]
pub fn hidpi_factor(&self) -> f32 {
match self {
&Window::X(ref w) => w.hidpi_factor(),
&Window::Wayland(ref w) => w.hidpi_factor()
}
}
#[inline]
pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
match self {
&Window::X(ref w) => w.set_cursor_position(x, y),
&Window::Wayland(ref w) => w.set_cursor_position(x, y)
}
}
#[inline]
pub fn platform_display(&self) -> *mut libc::c_void {
use wayland_client::Proxy;
match self {
&Window::X(ref w) => w.platform_display(),
&Window::Wayland(ref w) => w.get_display().ptr() as *mut _
}
}
#[inline]
pub fn platform_window(&self) -> *mut libc::c_void {
use wayland_client::Proxy;
match self {
&Window::X(ref w) => w.platform_window(),
&Window::Wayland(ref w) => w.get_surface().ptr() as *mut _
}
}
#[inline]
pub fn set_maximized(&self, maximized: bool) {
match self {
&Window::X(ref w) => w.set_maximized(maximized),
&Window::Wayland(ref w) => w.set_maximized(maximized),
}
}
#[inline]
pub fn set_fullscreen(&self, monitor: Option<RootMonitorId>) {
match self {
&Window::X(ref w) => w.set_fullscreen(monitor),
&Window::Wayland(ref w) => w.set_fullscreen(monitor)
}
}
#[inline]
pub fn set_decorations(&self, decorations: bool) {
match self {
&Window::X(ref w) => w.set_decorations(decorations),
&Window::Wayland(ref w) => w.set_decorations(decorations)
}
}
#[inline]
pub fn get_current_monitor(&self) -> RootMonitorId {
match self {
&Window::X(ref w) => RootMonitorId{inner: MonitorId::X(w.get_current_monitor())},
&Window::Wayland(ref w) => RootMonitorId{inner: MonitorId::Wayland(w.get_current_monitor())},
}
}
}
unsafe extern "C" fn x_error_callback(dpy: *mut x11::ffi::Display, event: *mut x11::ffi::XErrorEvent)
-> libc::c_int
{
use std::ffi::CStr;
if let Ok(ref x) = *X11_BACKEND {
let mut buff: Vec<u8> = Vec::with_capacity(1024);
(x.xlib.XGetErrorText)(dpy, (*event).error_code as i32, buff.as_mut_ptr() as *mut libc::c_char, buff.capacity() as i32);
let description = CStr::from_ptr(buff.as_mut_ptr() as *const libc::c_char).to_string_lossy();
let error = XError {
description: description.into_owned(),
error_code: (*event).error_code,
request_code: (*event).request_code,
minor_code: (*event).minor_code,
};
*x.latest_error.lock().unwrap() = Some(error);
}
0
}
pub enum EventsLoop {
Wayland(wayland::EventsLoop),
X(x11::EventsLoop)
}
#[derive(Clone)]
pub enum EventsLoopProxy {
X(x11::EventsLoopProxy),
Wayland(wayland::EventsLoopProxy),
}
impl EventsLoop {
pub fn new() -> EventsLoop {
if let Ok(env_var) = env::var(BACKEND_PREFERENCE_ENV_VAR) {
match env_var.as_str() {
"x11" => {
return EventsLoop::new_x11().unwrap(); // TODO: propagate
},
"wayland" => {
match EventsLoop::new_wayland() {
Ok(e) => return e,
Err(_) => panic!() // TODO: propagate
}
},
_ => panic!("Unknown environment variable value for {}, try one of `x11`,`wayland`",
BACKEND_PREFERENCE_ENV_VAR),
}
}
if let Ok(el) = EventsLoop::new_wayland() {
return el;
}
if let Ok(el) = EventsLoop::new_x11() {
return el;
}
panic!("No backend is available")
}
pub fn new_wayland() -> Result<EventsLoop, ()> {
wayland::EventsLoop::new()
.map(EventsLoop::Wayland)
.ok_or(())
}
pub fn new_x11() -> Result<EventsLoop, XNotSupported> {
match *X11_BACKEND {
Ok(ref x) => Ok(EventsLoop::X(x11::EventsLoop::new(x.clone()))),
Err(ref err) => Err(err.clone()),
}
}
#[inline]
pub fn get_available_monitors(&self) -> VecDeque<MonitorId> {
match *self {
EventsLoop::Wayland(ref evlp) => evlp.get_available_monitors()
.into_iter()
.map(MonitorId::Wayland)
.collect(),
EventsLoop::X(ref evlp) => x11::get_available_monitors(evlp.x_connection())
.into_iter()
.map(MonitorId::X)
.collect(),
}
}
#[inline]
pub fn get_primary_monitor(&self) -> MonitorId {
match *self {
EventsLoop::Wayland(ref evlp) => MonitorId::Wayland(evlp.get_primary_monitor()),
EventsLoop::X(ref evlp) => MonitorId::X(x11::get_primary_monitor(evlp.x_connection())),
}
}
pub fn create_proxy(&self) -> EventsLoopProxy {
match *self {
EventsLoop::Wayland(ref evlp) => EventsLoopProxy::Wayland(evlp.create_proxy()),
EventsLoop::X(ref evlp) => EventsLoopProxy::X(evlp.create_proxy()),
}
}
pub fn poll_events<F>(&mut self, callback: F)
where F: FnMut(::Event)
{
match *self {
EventsLoop::Wayland(ref mut evlp) => evlp.poll_events(callback),
EventsLoop::X(ref mut evlp) => evlp.poll_events(callback)
}
}
pub fn run_forever<F>(&mut self, callback: F)
where F: FnMut(::Event) -> ControlFlow
{
match *self {
EventsLoop::Wayland(ref mut evlp) => evlp.run_forever(callback),
EventsLoop::X(ref mut evlp) => evlp.run_forever(callback)
}
}
#[inline]
pub fn is_wayland(&self) -> bool {
match *self {
EventsLoop::Wayland(_) => true,
EventsLoop::X(_) => false,
}
}
#[inline]
pub fn x_connection(&self) -> Option<&Arc<XConnection>> {
match *self {
EventsLoop::Wayland(_) => None,
EventsLoop::X(ref ev) => Some(ev.x_connection()),
}
}
}
impl EventsLoopProxy {
pub fn wakeup(&self) -> Result<(), EventsLoopClosed> {
match *self {
EventsLoopProxy::Wayland(ref proxy) => proxy.wakeup(),
EventsLoopProxy::X(ref proxy) => proxy.wakeup(),
}
}
}

View File

@@ -1,594 +0,0 @@
use std::cell::RefCell;
use std::collections::VecDeque;
use std::sync::{Arc, Mutex, Weak};
use std::sync::atomic::{AtomicBool, Ordering};
use {EventsLoopClosed, ControlFlow};
use super::WindowId;
use super::window::WindowStore;
use super::keyboard::init_keyboard;
use wayland_client::{EnvHandler, EnvNotify, default_connect, EventQueue, EventQueueHandle, Proxy, StateToken};
use wayland_client::protocol::{wl_compositor, wl_seat, wl_shell, wl_shm, wl_subcompositor,
wl_display, wl_registry, wl_output, wl_surface,
wl_pointer, wl_keyboard, wl_touch};
use super::wayland_window::{Frame, Shell, create_frame, FrameImplementation};
use super::wayland_protocols::unstable::xdg_shell::v6::client::zxdg_shell_v6;
pub struct EventsLoopSink {
buffer: VecDeque<::Event>
}
unsafe impl Send for EventsLoopSink { }
impl EventsLoopSink {
pub fn new() -> EventsLoopSink{
EventsLoopSink {
buffer: VecDeque::new()
}
}
pub fn send_event(&mut self, evt: ::WindowEvent, wid: WindowId) {
let evt = ::Event::WindowEvent {
event: evt,
window_id: ::WindowId(::platform::WindowId::Wayland(wid))
};
self.buffer.push_back(evt);
}
pub fn send_raw_event(&mut self, evt: ::Event) {
self.buffer.push_back(evt);
}
fn empty_with<F>(&mut self, callback: &mut F) where F: FnMut(::Event) {
for evt in self.buffer.drain(..) {
callback(evt)
}
}
}
pub struct EventsLoop {
// The Event Queue
pub evq: RefCell<EventQueue>,
// our sink, shared with some handlers, buffering the events
sink: Arc<Mutex<EventsLoopSink>>,
// Whether or not there is a pending `Awakened` event to be emitted.
pending_wakeup: Arc<AtomicBool>,
// The window store
pub store: StateToken<WindowStore>,
// the env
env_token: StateToken<EnvHandler<InnerEnv>>,
// the ctxt
pub ctxt_token: StateToken<StateContext>,
// a cleanup switch to prune dead windows
pub cleanup_needed: Arc<Mutex<bool>>,
// The wayland display
pub display: Arc<wl_display::WlDisplay>,
}
// A handle that can be sent across threads and used to wake up the `EventsLoop`.
//
// We should only try and wake up the `EventsLoop` if it still exists, so we hold Weak ptrs.
#[derive(Clone)]
pub struct EventsLoopProxy {
display: Weak<wl_display::WlDisplay>,
pending_wakeup: Weak<AtomicBool>,
}
impl EventsLoopProxy {
// Causes the `EventsLoop` to stop blocking on `run_forever` and emit an `Awakened` event.
//
// Returns `Err` if the associated `EventsLoop` no longer exists.
pub fn wakeup(&self) -> Result<(), EventsLoopClosed> {
let display = self.display.upgrade();
let wakeup = self.pending_wakeup.upgrade();
match (display, wakeup) {
(Some(display), Some(wakeup)) => {
// Update the `EventsLoop`'s `pending_wakeup` flag.
wakeup.store(true, Ordering::Relaxed);
// Cause the `EventsLoop` to break from `dispatch` if it is currently blocked.
display.sync();
display.flush().map_err(|_| EventsLoopClosed)?;
Ok(())
},
_ => Err(EventsLoopClosed),
}
}
}
impl EventsLoop {
pub fn new() -> Option<EventsLoop> {
let (display, mut event_queue) = match default_connect() {
Ok(ret) => ret,
Err(_) => return None
};
let registry = display.get_registry();
let ctxt_token = event_queue.state().insert(
StateContext::new(registry.clone().unwrap())
);
let env_token = EnvHandler::init_with_notify(
&mut event_queue,
&registry,
env_notify(),
ctxt_token.clone()
);
// two round trips to fully initialize
event_queue.sync_roundtrip().expect("Wayland connection unexpectedly lost");
event_queue.sync_roundtrip().expect("Wayland connection unexpectedly lost");
event_queue.state().with_value(&ctxt_token, |proxy, ctxt| {
ctxt.ensure_shell(proxy.get_mut(&env_token))
});
let sink = Arc::new(Mutex::new(EventsLoopSink::new()));
let store = event_queue.state().insert(WindowStore::new());
let seat_idata = SeatIData {
sink: sink.clone(),
keyboard: None,
pointer: None,
touch: None,
windows_token: store.clone()
};
let mut me = EventsLoop {
display: Arc::new(display),
evq: RefCell::new(event_queue),
sink: sink,
pending_wakeup: Arc::new(AtomicBool::new(false)),
store: store,
ctxt_token: ctxt_token,
env_token: env_token,
cleanup_needed: Arc::new(Mutex::new(false))
};
me.init_seat(|evqh, seat| {
evqh.register(seat, seat_implementation(), seat_idata);
});
Some(me)
}
pub fn create_proxy(&self) -> EventsLoopProxy {
EventsLoopProxy {
display: Arc::downgrade(&self.display),
pending_wakeup: Arc::downgrade(&self.pending_wakeup),
}
}
pub fn poll_events<F>(&mut self, mut callback: F)
where F: FnMut(::Event)
{
// send pending events to the server
self.display.flush().expect("Wayland connection lost.");
// dispatch any pre-buffered events
self.sink.lock().unwrap().empty_with(&mut callback);
// try to read pending events
if let Some(h) = self.evq.get_mut().prepare_read() {
h.read_events().expect("Wayland connection lost.");
}
// dispatch wayland events
self.evq.get_mut().dispatch_pending().expect("Wayland connection lost.");
self.post_dispatch_triggers();
// dispatch buffered events to client
self.sink.lock().unwrap().empty_with(&mut callback);
}
pub fn run_forever<F>(&mut self, mut callback: F)
where F: FnMut(::Event) -> ControlFlow,
{
// send pending events to the server
self.display.flush().expect("Wayland connection lost.");
// Check for control flow by wrapping the callback.
let control_flow = ::std::cell::Cell::new(ControlFlow::Continue);
let mut callback = |event| if let ControlFlow::Break = callback(event) {
control_flow.set(ControlFlow::Break);
};
// dispatch any pre-buffered events
self.post_dispatch_triggers();
self.sink.lock().unwrap().empty_with(&mut callback);
loop {
// dispatch events blocking if needed
self.evq.get_mut().dispatch().expect("Wayland connection lost.");
self.post_dispatch_triggers();
// empty buffer of events
self.sink.lock().unwrap().empty_with(&mut callback);
if let ControlFlow::Break = control_flow.get() {
break;
}
}
}
pub fn get_primary_monitor(&self) -> MonitorId {
let mut guard = self.evq.borrow_mut();
let state = guard.state();
let state_ctxt = state.get(&self.ctxt_token);
if let Some(info) = state_ctxt.monitors.iter().next() {
MonitorId {
info: info.clone()
}
} else {
panic!("No monitor is available.")
}
}
pub fn get_available_monitors(&self) -> VecDeque<MonitorId> {
let mut guard = self.evq.borrow_mut();
let state = guard.state();
let state_ctxt = state.get(&self.ctxt_token);
state_ctxt.monitors.iter()
.map(|m| MonitorId { info: m.clone() })
.collect()
}
}
/*
* Private EventsLoop Internals
*/
wayland_env!(InnerEnv,
compositor: wl_compositor::WlCompositor,
shm: wl_shm::WlShm,
subcompositor: wl_subcompositor::WlSubcompositor
);
pub struct StateContext {
registry: wl_registry::WlRegistry,
seat: Option<wl_seat::WlSeat>,
shell: Option<Shell>,
monitors: Vec<Arc<Mutex<OutputInfo>>>
}
impl StateContext {
fn new(registry: wl_registry::WlRegistry) -> StateContext {
StateContext {
registry: registry,
seat: None,
shell: None,
monitors: Vec::new()
}
}
/// Ensures a shell is available
///
/// If a shell is already bound, do nothing. Otherwise,
/// try to bind wl_shell as a fallback. If this fails,
/// panic, as this is a bug from the compositor.
fn ensure_shell(&mut self, env: &mut EnvHandler<InnerEnv>) {
if self.shell.is_some() {
return;
}
// xdg_shell is not available, so initialize wl_shell
for &(name, ref interface, _) in env.globals() {
if interface == "wl_shell" {
self.shell = Some(Shell::Wl(self.registry.bind::<wl_shell::WlShell>(1, name)));
return;
}
}
// This is a compositor bug, it _must_ at least support wl_shell
panic!("Compositor didi not advertize xdg_shell not wl_shell.");
}
pub fn monitor_id_for(&self, output: &wl_output::WlOutput) -> MonitorId {
for info in &self.monitors {
let guard = info.lock().unwrap();
if guard.output.equals(output) {
return MonitorId {
info: info.clone()
};
}
}
panic!("Received an inexistent wl_output?!");
}
}
impl EventsLoop {
pub fn init_seat<F>(&mut self, f: F)
where F: FnOnce(&mut EventQueueHandle, &wl_seat::WlSeat)
{
let mut guard = self.evq.borrow_mut();
if guard.state().get(&self.ctxt_token).seat.is_some() {
// seat has already been init
return;
}
// clone the token to make borrow checker happy
let ctxt_token = self.ctxt_token.clone();
let seat = guard.state().with_value(&self.env_token, |proxy, env| {
let ctxt = proxy.get(&ctxt_token);
for &(name, ref interface, _) in env.globals() {
if interface == wl_seat::WlSeat::interface_name() {
return Some(ctxt.registry.bind::<wl_seat::WlSeat>(5, name));
}
}
None
});
if let Some(seat) = seat {
f(&mut *guard, &seat);
guard.state().get_mut(&self.ctxt_token).seat = Some(seat)
}
}
fn post_dispatch_triggers(&mut self) {
let mut sink = self.sink.lock().unwrap();
let evq = self.evq.get_mut();
// process a possible pending wakeup call
if self.pending_wakeup.load(Ordering::Relaxed) {
sink.send_raw_event(::Event::Awakened);
self.pending_wakeup.store(false, Ordering::Relaxed);
}
// prune possible dead windows
{
let mut cleanup_needed = self.cleanup_needed.lock().unwrap();
if *cleanup_needed {
let pruned = evq.state().get_mut(&self.store).cleanup();
*cleanup_needed = false;
for wid in pruned {
sink.send_event(::WindowEvent::Destroyed, wid);
}
}
}
// process pending resize/refresh
evq.state().get_mut(&self.store).for_each(
|newsize, refresh, frame_refresh, closed, wid, frame| {
if let Some(frame) = frame {
if let Some((w, h)) = newsize {
frame.resize(w as i32, h as i32);
frame.refresh();
sink.send_event(::WindowEvent::Resized(w as u32, h as u32), wid);
} else if frame_refresh {
frame.refresh();
}
}
if refresh {
sink.send_event(::WindowEvent::Refresh, wid);
}
if closed {
sink.send_event(::WindowEvent::CloseRequested, wid);
}
}
)
}
/// Create a new window with given dimensions
///
/// Grabs a lock on the event queue in the process
pub fn create_window<ID: 'static, F>(&self, width: u32, height: u32, implem: FrameImplementation<ID>, idata: F)
-> (wl_surface::WlSurface, Frame)
where F: FnOnce(&wl_surface::WlSurface) -> ID
{
let (surface, frame) = {
let mut guard = self.evq.borrow_mut();
let env = guard.state().get(&self.env_token).clone_inner().unwrap();
let shell = match guard.state().get(&self.ctxt_token).shell {
Some(Shell::Wl(ref wl_shell)) => Shell::Wl(wl_shell.clone().unwrap()),
Some(Shell::Xdg(ref xdg_shell)) => Shell::Xdg(xdg_shell.clone().unwrap()),
None => unreachable!()
};
let seat = guard.state().get(&self.ctxt_token).seat.as_ref().and_then(|s| s.clone());
let surface = env.compositor.create_surface();
let frame = create_frame(
&mut guard,
implem,
idata(&surface),
&surface, width as i32, height as i32,
&env.compositor,
&env.subcompositor,
&env.shm,
&shell,
seat
).expect("Failed to create a tmpfile buffer.");
(surface, frame)
};
(surface, frame)
}
}
/*
* Wayland protocol implementations
*/
fn env_notify() -> EnvNotify<StateToken<StateContext>> {
EnvNotify {
new_global: |evqh, token, registry, id, interface, version| {
use std::cmp::min;
if interface == wl_output::WlOutput::interface_name() {
// a new output is available
let output = registry.bind::<wl_output::WlOutput>(min(version, 3), id);
evqh.register(&output, output_impl(), token.clone());
evqh.state().get_mut(&token).monitors.push(
Arc::new(Mutex::new(OutputInfo::new(output, id)))
);
} else if interface == zxdg_shell_v6::ZxdgShellV6::interface_name() {
// We have an xdg_shell, bind it
let xdg_shell = registry.bind::<zxdg_shell_v6::ZxdgShellV6>(1, id);
evqh.register(&xdg_shell, xdg_ping_implementation(), ());
evqh.state().get_mut(&token).shell = Some(Shell::Xdg(xdg_shell));
}
},
del_global: |evqh, token, _, id| {
// maybe this was a monitor, cleanup
evqh.state().get_mut(&token).monitors.retain(
|m| m.lock().unwrap().id != id
);
},
ready: |_, _, _| {}
}
}
fn xdg_ping_implementation() -> zxdg_shell_v6::Implementation<()> {
zxdg_shell_v6::Implementation {
ping: |_, _, shell, serial| {
shell.pong(serial);
}
}
}
struct SeatIData {
sink: Arc<Mutex<EventsLoopSink>>,
pointer: Option<wl_pointer::WlPointer>,
keyboard: Option<wl_keyboard::WlKeyboard>,
touch: Option<wl_touch::WlTouch>,
windows_token: StateToken<WindowStore>
}
fn seat_implementation() -> wl_seat::Implementation<SeatIData> {
wl_seat::Implementation {
name: |_, _, _, _| {},
capabilities: |evqh, idata, seat, capabilities| {
// create pointer if applicable
if capabilities.contains(wl_seat::Capability::Pointer) && idata.pointer.is_none() {
let pointer = seat.get_pointer().expect("Seat is not dead");
let p_idata = super::pointer::PointerIData::new(
&idata.sink,
idata.windows_token.clone()
);
evqh.register(&pointer, super::pointer::pointer_implementation(), p_idata);
idata.pointer = Some(pointer);
}
// destroy pointer if applicable
if !capabilities.contains(wl_seat::Capability::Pointer) {
if let Some(pointer) = idata.pointer.take() {
pointer.release();
}
}
// create keyboard if applicable
if capabilities.contains(wl_seat::Capability::Keyboard) && idata.keyboard.is_none() {
let kbd = seat.get_keyboard().expect("Seat is not dead");
init_keyboard(evqh, &kbd, &idata.sink);
idata.keyboard = Some(kbd);
}
// destroy keyboard if applicable
if !capabilities.contains(wl_seat::Capability::Keyboard) {
if let Some(kbd) = idata.keyboard.take() {
kbd.release();
}
}
// create touch if applicable
if capabilities.contains(wl_seat::Capability::Touch) && idata.touch.is_none() {
let touch = seat.get_touch().expect("Seat is not dead");
let t_idata = super::touch::TouchIData::new(
&idata.sink,
idata.windows_token.clone()
);
evqh.register(&touch, super::touch::touch_implementation(), t_idata);
idata.touch = Some(touch);
}
// destroy touch if applicable
if !capabilities.contains(wl_seat::Capability::Touch) {
if let Some(touch) = idata.touch.take() {
touch.release();
}
}
}
}
}
/*
* Monitor stuff
*/
fn output_impl() -> wl_output::Implementation<StateToken<StateContext>> {
wl_output::Implementation {
geometry: |evqh, token, output, x, y, _, _, _, make, model, _| {
let ctxt = evqh.state().get_mut(token);
for info in &ctxt.monitors {
let mut guard = info.lock().unwrap();
if guard.output.equals(output) {
guard.pix_pos = (x, y);
guard.name = format!("{} - {}", make, model);
return;
}
}
},
mode: |evqh, token, output, flags, w, h, _refresh| {
if flags.contains(wl_output::Mode::Current) {
let ctxt = evqh.state().get_mut(token);
for info in &ctxt.monitors {
let mut guard = info.lock().unwrap();
if guard.output.equals(output) {
guard.pix_size = (w as u32, h as u32);
return;
}
}
}
},
done: |_, _, _| {},
scale: |evqh, token, output, scale| {
let ctxt = evqh.state().get_mut(token);
for info in &ctxt.monitors {
let mut guard = info.lock().unwrap();
if guard.output.equals(output) {
guard.scale = scale as f32;
return;
}
}
}
}
}
pub struct OutputInfo {
pub output: wl_output::WlOutput,
pub id: u32,
pub scale: f32,
pub pix_size: (u32, u32),
pub pix_pos: (i32, i32),
pub name: String
}
impl OutputInfo {
fn new(output: wl_output::WlOutput, id: u32) -> OutputInfo {
OutputInfo {
output: output,
id: id,
scale: 1.0,
pix_size: (0, 0),
pix_pos: (0, 0),
name: "".into()
}
}
}
#[derive(Clone)]
pub struct MonitorId {
pub info: Arc<Mutex<OutputInfo>>
}
impl MonitorId {
pub fn get_name(&self) -> Option<String> {
Some(self.info.lock().unwrap().name.clone())
}
#[inline]
pub fn get_native_identifier(&self) -> u32 {
self.info.lock().unwrap().id
}
pub fn get_dimensions(&self) -> (u32, u32) {
self.info.lock().unwrap().pix_size
}
pub fn get_position(&self) -> (i32, i32) {
self.info.lock().unwrap().pix_pos
}
#[inline]
pub fn get_hidpi_factor(&self) -> f32 {
self.info.lock().unwrap().scale
}
}

View File

@@ -1,296 +0,0 @@
use std::sync::{Arc, Mutex};
use {VirtualKeyCode, ElementState, WindowEvent as Event, KeyboardInput, ModifiersState};
use super::{EventsLoopSink, WindowId, make_wid, DeviceId};
use super::wayland_kbd::{MappedKeyboardImplementation, register_kbd};
use wayland_client::protocol::wl_keyboard;
use wayland_client::EventQueueHandle;
pub fn init_keyboard(evq: &mut EventQueueHandle, keyboard: &wl_keyboard::WlKeyboard, sink: &Arc<Mutex<EventsLoopSink>>) {
let idata = KeyboardIData {
sink: sink.clone(),
target: None
};
if register_kbd(evq, keyboard, mapped_keyboard_impl(), idata).is_err() {
// initializing libxkbcommon failed :(
// fallback implementation
let idata = KeyboardIData {
sink: sink.clone(),
target: None
};
evq.register(keyboard, raw_keyboard_impl(), idata);
}
}
struct KeyboardIData {
sink: Arc<Mutex<EventsLoopSink>>,
target: Option<WindowId>
}
fn mapped_keyboard_impl() -> MappedKeyboardImplementation<KeyboardIData> {
MappedKeyboardImplementation {
enter: |_, idata, _, _, surface, _, _, _| {
let wid = make_wid(surface);
idata.sink.lock().unwrap().send_event(Event::Focused(true), wid);
idata.target = Some(wid);
},
leave: |_, idata, _, _, surface| {
let wid = make_wid(surface);
idata.sink.lock().unwrap().send_event(Event::Focused(false), wid);
idata.target = None;
},
key: |_, idata, _, _, _, mods, rawkey, keysym, state, utf8| {
if let Some(wid) = idata.target {
let state = match state {
wl_keyboard::KeyState::Pressed => ElementState::Pressed,
wl_keyboard::KeyState::Released => ElementState::Released,
};
let vkcode = key_to_vkey(rawkey, keysym);
let mut guard = idata.sink.lock().unwrap();
guard.send_event(
Event::KeyboardInput {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
input: KeyboardInput {
state: state,
scancode: rawkey,
virtual_keycode: vkcode,
modifiers: ModifiersState {
shift: mods.shift,
ctrl: mods.ctrl,
alt: mods.alt,
logo: mods.logo
},
},
},
wid
);
// send char event only on key press, not release
if let ElementState::Released = state { return }
if let Some(txt) = utf8 {
for chr in txt.chars() {
guard.send_event(Event::ReceivedCharacter(chr), wid);
}
}
}
},
repeat_info: |_, _idata, _, _rate, _delay| {
// TODO: handle repeat info
}
}
}
// This is fallback impl if libxkbcommon was not available
// This case should probably never happen, as most wayland
// compositors _need_ libxkbcommon anyway...
//
// In this case, we don't have the keymap information (it is
// supposed to be serialized by the compositor using libxkbcommon)
fn raw_keyboard_impl() -> wl_keyboard::Implementation<KeyboardIData> {
wl_keyboard::Implementation {
enter: |_, idata, _, _, surface, _| {
let wid = make_wid(surface);
idata.sink.lock().unwrap().send_event(Event::Focused(true), wid);
idata.target = Some(wid);
},
leave: |_, idata, _, _, surface| {
let wid = make_wid(surface);
idata.sink.lock().unwrap().send_event(Event::Focused(false), wid);
idata.target = None;
},
key: |_, idata, _, _, _, key, state| {
if let Some(wid) = idata.target {
let state = match state {
wl_keyboard::KeyState::Pressed => ElementState::Pressed,
wl_keyboard::KeyState::Released => ElementState::Released,
};
idata.sink.lock().unwrap().send_event(
Event::KeyboardInput {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
input: KeyboardInput {
state: state,
scancode: key,
virtual_keycode: None,
modifiers: ModifiersState::default(),
},
},
wid
);
}
},
repeat_info: |_, _idata, _, _rate, _delay| {},
keymap: |_, _, _, _, _, _| {},
modifiers: |_, _, _, _, _, _, _, _| {}
}
}
fn key_to_vkey(rawkey: u32, keysym: u32) -> Option<VirtualKeyCode> {
match rawkey {
1 => Some(VirtualKeyCode::Escape),
2 => Some(VirtualKeyCode::Key1),
3 => Some(VirtualKeyCode::Key2),
4 => Some(VirtualKeyCode::Key3),
5 => Some(VirtualKeyCode::Key4),
6 => Some(VirtualKeyCode::Key5),
7 => Some(VirtualKeyCode::Key6),
8 => Some(VirtualKeyCode::Key7),
9 => Some(VirtualKeyCode::Key8),
10 => Some(VirtualKeyCode::Key9),
11 => Some(VirtualKeyCode::Key0),
_ => keysym_to_vkey(keysym)
}
}
fn keysym_to_vkey(keysym: u32) -> Option<VirtualKeyCode> {
use super::wayland_kbd::keysyms;
match keysym {
// letters
keysyms::XKB_KEY_A | keysyms::XKB_KEY_a => Some(VirtualKeyCode::A),
keysyms::XKB_KEY_B | keysyms::XKB_KEY_b => Some(VirtualKeyCode::B),
keysyms::XKB_KEY_C | keysyms::XKB_KEY_c => Some(VirtualKeyCode::C),
keysyms::XKB_KEY_D | keysyms::XKB_KEY_d => Some(VirtualKeyCode::D),
keysyms::XKB_KEY_E | keysyms::XKB_KEY_e => Some(VirtualKeyCode::E),
keysyms::XKB_KEY_F | keysyms::XKB_KEY_f => Some(VirtualKeyCode::F),
keysyms::XKB_KEY_G | keysyms::XKB_KEY_g => Some(VirtualKeyCode::G),
keysyms::XKB_KEY_H | keysyms::XKB_KEY_h => Some(VirtualKeyCode::H),
keysyms::XKB_KEY_I | keysyms::XKB_KEY_i => Some(VirtualKeyCode::I),
keysyms::XKB_KEY_J | keysyms::XKB_KEY_j => Some(VirtualKeyCode::J),
keysyms::XKB_KEY_K | keysyms::XKB_KEY_k => Some(VirtualKeyCode::K),
keysyms::XKB_KEY_L | keysyms::XKB_KEY_l => Some(VirtualKeyCode::L),
keysyms::XKB_KEY_M | keysyms::XKB_KEY_m => Some(VirtualKeyCode::M),
keysyms::XKB_KEY_N | keysyms::XKB_KEY_n => Some(VirtualKeyCode::N),
keysyms::XKB_KEY_O | keysyms::XKB_KEY_o => Some(VirtualKeyCode::O),
keysyms::XKB_KEY_P | keysyms::XKB_KEY_p => Some(VirtualKeyCode::P),
keysyms::XKB_KEY_Q | keysyms::XKB_KEY_q => Some(VirtualKeyCode::Q),
keysyms::XKB_KEY_R | keysyms::XKB_KEY_r => Some(VirtualKeyCode::R),
keysyms::XKB_KEY_S | keysyms::XKB_KEY_s => Some(VirtualKeyCode::S),
keysyms::XKB_KEY_T | keysyms::XKB_KEY_t => Some(VirtualKeyCode::T),
keysyms::XKB_KEY_U | keysyms::XKB_KEY_u => Some(VirtualKeyCode::U),
keysyms::XKB_KEY_V | keysyms::XKB_KEY_v => Some(VirtualKeyCode::V),
keysyms::XKB_KEY_W | keysyms::XKB_KEY_w => Some(VirtualKeyCode::W),
keysyms::XKB_KEY_X | keysyms::XKB_KEY_x => Some(VirtualKeyCode::X),
keysyms::XKB_KEY_Y | keysyms::XKB_KEY_y => Some(VirtualKeyCode::Y),
keysyms::XKB_KEY_Z | keysyms::XKB_KEY_z => Some(VirtualKeyCode::Z),
// F--
keysyms::XKB_KEY_F1 => Some(VirtualKeyCode::F1),
keysyms::XKB_KEY_F2 => Some(VirtualKeyCode::F2),
keysyms::XKB_KEY_F3 => Some(VirtualKeyCode::F3),
keysyms::XKB_KEY_F4 => Some(VirtualKeyCode::F4),
keysyms::XKB_KEY_F5 => Some(VirtualKeyCode::F5),
keysyms::XKB_KEY_F6 => Some(VirtualKeyCode::F6),
keysyms::XKB_KEY_F7 => Some(VirtualKeyCode::F7),
keysyms::XKB_KEY_F8 => Some(VirtualKeyCode::F8),
keysyms::XKB_KEY_F9 => Some(VirtualKeyCode::F9),
keysyms::XKB_KEY_F10 => Some(VirtualKeyCode::F10),
keysyms::XKB_KEY_F11 => Some(VirtualKeyCode::F11),
keysyms::XKB_KEY_F12 => Some(VirtualKeyCode::F12),
keysyms::XKB_KEY_F13 => Some(VirtualKeyCode::F13),
keysyms::XKB_KEY_F14 => Some(VirtualKeyCode::F14),
keysyms::XKB_KEY_F15 => Some(VirtualKeyCode::F15),
// flow control
keysyms::XKB_KEY_Print => Some(VirtualKeyCode::Snapshot),
keysyms::XKB_KEY_Scroll_Lock => Some(VirtualKeyCode::Scroll),
keysyms::XKB_KEY_Pause => Some(VirtualKeyCode::Pause),
keysyms::XKB_KEY_Insert => Some(VirtualKeyCode::Insert),
keysyms::XKB_KEY_Home => Some(VirtualKeyCode::Home),
keysyms::XKB_KEY_Delete => Some(VirtualKeyCode::Delete),
keysyms::XKB_KEY_End => Some(VirtualKeyCode::End),
keysyms::XKB_KEY_Page_Down => Some(VirtualKeyCode::PageDown),
keysyms::XKB_KEY_Page_Up => Some(VirtualKeyCode::PageUp),
// arrows
keysyms::XKB_KEY_Left => Some(VirtualKeyCode::Left),
keysyms::XKB_KEY_Up => Some(VirtualKeyCode::Up),
keysyms::XKB_KEY_Right => Some(VirtualKeyCode::Right),
keysyms::XKB_KEY_Down => Some(VirtualKeyCode::Down),
//
keysyms::XKB_KEY_BackSpace => Some(VirtualKeyCode::Back),
keysyms::XKB_KEY_Return => Some(VirtualKeyCode::Return),
keysyms::XKB_KEY_space => Some(VirtualKeyCode::Space),
// keypad
keysyms::XKB_KEY_Num_Lock => Some(VirtualKeyCode::Numlock),
keysyms::XKB_KEY_KP_0 => Some(VirtualKeyCode::Numpad0),
keysyms::XKB_KEY_KP_1 => Some(VirtualKeyCode::Numpad1),
keysyms::XKB_KEY_KP_2 => Some(VirtualKeyCode::Numpad2),
keysyms::XKB_KEY_KP_3 => Some(VirtualKeyCode::Numpad3),
keysyms::XKB_KEY_KP_4 => Some(VirtualKeyCode::Numpad4),
keysyms::XKB_KEY_KP_5 => Some(VirtualKeyCode::Numpad5),
keysyms::XKB_KEY_KP_6 => Some(VirtualKeyCode::Numpad6),
keysyms::XKB_KEY_KP_7 => Some(VirtualKeyCode::Numpad7),
keysyms::XKB_KEY_KP_8 => Some(VirtualKeyCode::Numpad8),
keysyms::XKB_KEY_KP_9 => Some(VirtualKeyCode::Numpad9),
// misc
// => Some(VirtualKeyCode::AbntC1),
// => Some(VirtualKeyCode::AbntC2),
keysyms::XKB_KEY_plus => Some(VirtualKeyCode::Add),
keysyms::XKB_KEY_apostrophe => Some(VirtualKeyCode::Apostrophe),
// => Some(VirtualKeyCode::Apps),
// => Some(VirtualKeyCode::At),
// => Some(VirtualKeyCode::Ax),
keysyms::XKB_KEY_backslash => Some(VirtualKeyCode::Backslash),
// => Some(VirtualKeyCode::Calculator),
// => Some(VirtualKeyCode::Capital),
keysyms::XKB_KEY_colon => Some(VirtualKeyCode::Colon),
keysyms::XKB_KEY_comma => Some(VirtualKeyCode::Comma),
// => Some(VirtualKeyCode::Convert),
// => Some(VirtualKeyCode::Decimal),
// => Some(VirtualKeyCode::Divide),
keysyms::XKB_KEY_equal => Some(VirtualKeyCode::Equals),
// => Some(VirtualKeyCode::Grave),
// => Some(VirtualKeyCode::Kana),
// => Some(VirtualKeyCode::Kanji),
keysyms::XKB_KEY_Alt_L => Some(VirtualKeyCode::LAlt),
// => Some(VirtualKeyCode::LBracket),
keysyms::XKB_KEY_Control_L => Some(VirtualKeyCode::LControl),
// => Some(VirtualKeyCode::LMenu),
keysyms::XKB_KEY_Shift_L => Some(VirtualKeyCode::LShift),
// => Some(VirtualKeyCode::LWin),
// => Some(VirtualKeyCode::Mail),
// => Some(VirtualKeyCode::MediaSelect),
// => Some(VirtualKeyCode::MediaStop),
keysyms::XKB_KEY_minus => Some(VirtualKeyCode::Minus),
keysyms::XKB_KEY_asterisk => Some(VirtualKeyCode::Multiply),
// => Some(VirtualKeyCode::Mute),
// => Some(VirtualKeyCode::MyComputer),
// => Some(VirtualKeyCode::NextTrack),
// => Some(VirtualKeyCode::NoConvert),
keysyms::XKB_KEY_KP_Separator => Some(VirtualKeyCode::NumpadComma),
keysyms::XKB_KEY_KP_Enter => Some(VirtualKeyCode::NumpadEnter),
keysyms::XKB_KEY_KP_Equal => Some(VirtualKeyCode::NumpadEquals),
// => Some(VirtualKeyCode::OEM102),
// => Some(VirtualKeyCode::Period),
// => Some(VirtualKeyCode::Playpause),
// => Some(VirtualKeyCode::Power),
// => Some(VirtualKeyCode::Prevtrack),
keysyms::XKB_KEY_Alt_R => Some(VirtualKeyCode::RAlt),
// => Some(VirtualKeyCode::RBracket),
keysyms::XKB_KEY_Control_R => Some(VirtualKeyCode::RControl),
// => Some(VirtualKeyCode::RMenu),
keysyms::XKB_KEY_Shift_R => Some(VirtualKeyCode::RShift),
// => Some(VirtualKeyCode::RWin),
keysyms::XKB_KEY_semicolon => Some(VirtualKeyCode::Semicolon),
keysyms::XKB_KEY_slash => Some(VirtualKeyCode::Slash),
// => Some(VirtualKeyCode::Sleep),
// => Some(VirtualKeyCode::Stop),
// => Some(VirtualKeyCode::Subtract),
// => Some(VirtualKeyCode::Sysrq),
keysyms::XKB_KEY_Tab => Some(VirtualKeyCode::Tab),
keysyms::XKB_KEY_ISO_Left_Tab => Some(VirtualKeyCode::Tab),
// => Some(VirtualKeyCode::Underline),
// => Some(VirtualKeyCode::Unlabeled),
keysyms::XKB_KEY_XF86AudioLowerVolume => Some(VirtualKeyCode::VolumeDown),
keysyms::XKB_KEY_XF86AudioRaiseVolume => Some(VirtualKeyCode::VolumeUp),
// => Some(VirtualKeyCode::Wake),
// => Some(VirtualKeyCode::Webback),
// => Some(VirtualKeyCode::WebFavorites),
// => Some(VirtualKeyCode::WebForward),
// => Some(VirtualKeyCode::WebHome),
// => Some(VirtualKeyCode::WebRefresh),
// => Some(VirtualKeyCode::WebSearch),
// => Some(VirtualKeyCode::WebStop),
// => Some(VirtualKeyCode::Yen),
// fallback
_ => None
}
}

View File

@@ -1,28 +0,0 @@
#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
pub use self::window::Window;
pub use self::event_loop::{EventsLoop, EventsLoopProxy, EventsLoopSink, MonitorId};
extern crate wayland_kbd;
extern crate wayland_window;
extern crate wayland_protocols;
use wayland_client::protocol::wl_surface;
use wayland_client::Proxy;
mod event_loop;
mod pointer;
mod touch;
mod keyboard;
mod window;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeviceId;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WindowId(usize);
#[inline]
fn make_wid(s: &wl_surface::WlSurface) -> WindowId {
WindowId(s.ptr() as usize)
}

View File

@@ -1,194 +0,0 @@
use std::sync::{Arc, Mutex};
use {WindowEvent as Event, ElementState, MouseButton, MouseScrollDelta, TouchPhase};
use events::ModifiersState;
use super::{WindowId, DeviceId};
use super::event_loop::EventsLoopSink;
use super::window::WindowStore;
use wayland_client::{Proxy, StateToken};
use wayland_client::protocol::wl_pointer;
pub struct PointerIData {
sink: Arc<Mutex<EventsLoopSink>>,
windows_token: StateToken<WindowStore>,
mouse_focus: Option<WindowId>,
axis_buffer: Option<(f32, f32)>,
axis_discrete_buffer: Option<(i32, i32)>,
axis_state: TouchPhase,
}
impl PointerIData {
pub fn new(sink: &Arc<Mutex<EventsLoopSink>>, token: StateToken<WindowStore>)
-> PointerIData
{
PointerIData {
sink: sink.clone(),
windows_token: token,
mouse_focus: None,
axis_buffer: None,
axis_discrete_buffer: None,
axis_state: TouchPhase::Cancelled
}
}
}
pub fn pointer_implementation() -> wl_pointer::Implementation<PointerIData> {
wl_pointer::Implementation {
enter: |evqh, idata, _, _, surface, x, y| {
let wid = evqh.state().get(&idata.windows_token).find_wid(surface);
if let Some(wid) = wid {
idata.mouse_focus = Some(wid);
let mut guard = idata.sink.lock().unwrap();
guard.send_event(
Event::CursorEntered {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
},
wid,
);
guard.send_event(
Event::CursorMoved {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
position: (x, y),
// TODO: replace dummy value with actual modifier state
modifiers: ModifiersState::default(),
},
wid,
);
}
},
leave: |evqh, idata, _, _, surface| {
idata.mouse_focus = None;
let wid = evqh.state().get(&idata.windows_token).find_wid(surface);
if let Some(wid) = wid {
let mut guard = idata.sink.lock().unwrap();
guard.send_event(
Event::CursorLeft {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
},
wid,
);
}
},
motion: |_, idata, _, _, x, y| {
if let Some(wid) = idata.mouse_focus {
idata.sink.lock().unwrap().send_event(
Event::CursorMoved {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
position: (x, y),
// TODO: replace dummy value with actual modifier state
modifiers: ModifiersState::default(),
},
wid
);
}
},
button: |_, idata, _, _, _, button, state| {
if let Some(wid) = idata.mouse_focus {
let state = match state {
wl_pointer::ButtonState::Pressed => ElementState::Pressed,
wl_pointer::ButtonState::Released => ElementState::Released
};
let button = match button {
0x110 => MouseButton::Left,
0x111 => MouseButton::Right,
0x112 => MouseButton::Middle,
// TODO figure out the translation ?
_ => return
};
idata.sink.lock().unwrap().send_event(
Event::MouseInput {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
state: state,
button: button,
// TODO: replace dummy value with actual modifier state
modifiers: ModifiersState::default(),
},
wid
);
}
},
axis: |_, idata, pointer, _, axis, value| {
if let Some(wid) = idata.mouse_focus {
if pointer.version() < 5 {
let (mut x, mut y) = (0.0, 0.0);
// old seat compatibility
match axis {
// wayland vertical sign convention is the inverse of winit
wl_pointer::Axis::VerticalScroll => y -= value as f32,
wl_pointer::Axis::HorizontalScroll => x += value as f32
}
idata.sink.lock().unwrap().send_event(
Event::MouseWheel {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
delta: MouseScrollDelta::PixelDelta(x as f32, y as f32),
phase: TouchPhase::Moved,
// TODO: replace dummy value with actual modifier state
modifiers: ModifiersState::default(),
},
wid
);
} else {
let (mut x, mut y) = idata.axis_buffer.unwrap_or((0.0, 0.0));
match axis {
// wayland vertical sign convention is the inverse of winit
wl_pointer::Axis::VerticalScroll => y -= value as f32,
wl_pointer::Axis::HorizontalScroll => x += value as f32
}
idata.axis_buffer = Some((x,y));
idata.axis_state = match idata.axis_state {
TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved,
_ => TouchPhase::Started
}
}
}
},
frame: |_, idata, _| {
let axis_buffer = idata.axis_buffer.take();
let axis_discrete_buffer = idata.axis_discrete_buffer.take();
if let Some(wid) = idata.mouse_focus {
if let Some((x, y)) = axis_discrete_buffer {
idata.sink.lock().unwrap().send_event(
Event::MouseWheel {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
delta: MouseScrollDelta::LineDelta(x as f32, y as f32),
phase: idata.axis_state,
// TODO: replace dummy value with actual modifier state
modifiers: ModifiersState::default(),
},
wid
);
} else if let Some((x, y)) = axis_buffer {
idata.sink.lock().unwrap().send_event(
Event::MouseWheel {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
delta: MouseScrollDelta::PixelDelta(x as f32, y as f32),
phase: idata.axis_state,
// TODO: replace dummy value with actual modifier state
modifiers: ModifiersState::default(),
},
wid
);
}
}
},
axis_source: |_, _, _, _| {},
axis_stop: |_, idata, _, _, _| {
idata.axis_state = TouchPhase::Ended;
},
axis_discrete: |_, idata, _, axis, discrete| {
let (mut x, mut y) = idata.axis_discrete_buffer.unwrap_or((0,0));
match axis {
// wayland vertical sign convention is the inverse of winit
wl_pointer::Axis::VerticalScroll => y -= discrete,
wl_pointer::Axis::HorizontalScroll => x += discrete
}
idata.axis_discrete_buffer = Some((x,y));
idata.axis_state = match idata.axis_state {
TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved,
_ => TouchPhase::Started
}
},
}
}

View File

@@ -1,106 +0,0 @@
use std::sync::{Arc, Mutex};
use {WindowEvent as Event, TouchPhase};
use super::{WindowId, DeviceId};
use super::event_loop::EventsLoopSink;
use super::window::WindowStore;
use wayland_client::StateToken;
use wayland_client::protocol::wl_touch;
pub struct TouchIData {
sink: Arc<Mutex<EventsLoopSink>>,
windows_token: StateToken<WindowStore>,
pending_ids: Vec<TouchPoint>,
}
struct TouchPoint {
wid: WindowId,
location: (f64, f64),
id: i32
}
impl TouchIData {
pub fn new(sink: &Arc<Mutex<EventsLoopSink>>, token: StateToken<WindowStore>)
-> TouchIData
{
TouchIData {
sink: sink.clone(),
windows_token: token,
pending_ids: Vec::new(),
}
}
}
pub fn touch_implementation() -> wl_touch::Implementation<TouchIData> {
wl_touch::Implementation {
down: |evqh, idata, _, _serial, _time, surface, touch_id, x, y| {
let wid = evqh.state().get(&idata.windows_token).find_wid(surface);
if let Some(wid) = wid {
let mut guard = idata.sink.lock().unwrap();
guard.send_event(
Event::Touch(::Touch {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
phase: TouchPhase::Started,
location: (x, y),
id: touch_id as u64
}),
wid,
);
idata.pending_ids.push(TouchPoint {
wid: wid,
location: (x, y),
id: touch_id
});
}
},
up: |_, idata, _, _serial, _time, touch_id| {
let idx = idata.pending_ids.iter().position(|p| p.id == touch_id);
if let Some(idx) = idx {
let pt = idata.pending_ids.remove(idx);
let mut guard = idata.sink.lock().unwrap();
guard.send_event(
Event::Touch(::Touch {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
phase: TouchPhase::Ended,
location: pt.location,
id: touch_id as u64
}),
pt.wid,
);
}
},
motion: |_, idata, _, _time, touch_id, x, y| {
let pt = idata.pending_ids.iter_mut().find(|p| p.id == touch_id);
if let Some(pt) = pt {
let mut guard = idata.sink.lock().unwrap();
pt.location = (x, y);
guard.send_event(
Event::Touch(::Touch {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
phase: TouchPhase::Moved,
location: (x, y),
id: touch_id as u64
}),
pt.wid,
);
}
},
frame: |_, _, _| {},
cancel: |_, idata, _| {
let mut guard = idata.sink.lock().unwrap();
for pt in idata.pending_ids.drain(..) {
guard.send_event(
Event::Touch(::Touch {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
phase: TouchPhase::Cancelled,
location: pt.location,
id: pt.id as u64
}),
pt.wid,
);
}
}
}
}

View File

@@ -1,364 +0,0 @@
use std::sync::{Arc, Mutex, Weak};
use wayland_client::protocol::{wl_display,wl_surface};
use wayland_client::{Proxy, StateToken};
use {CreationError, MouseCursor, CursorState, WindowAttributes};
use platform::MonitorId as PlatformMonitorId;
use window::MonitorId as RootMonitorId;
use super::{EventsLoop, WindowId, make_wid, MonitorId};
use super::wayland_window::{Frame, FrameImplementation, State as FrameState};
use super::event_loop::StateContext;
pub struct Window {
surface: wl_surface::WlSurface,
frame: Arc<Mutex<Frame>>,
monitors: Arc<Mutex<MonitorList>>,
size: Arc<Mutex<(u32, u32)>>,
kill_switch: (Arc<Mutex<bool>>, Arc<Mutex<bool>>),
display: Arc<wl_display::WlDisplay>,
need_frame_refresh: Arc<Mutex<bool>>
}
impl Window {
pub fn new(evlp: &EventsLoop, attributes: &WindowAttributes) -> Result<Window, CreationError>
{
let (width, height) = attributes.dimensions.unwrap_or((800,600));
// Create the decorated surface
let size = Arc::new(Mutex::new((width, height)));
let store_token = evlp.store.clone();
let (surface, mut frame) = evlp.create_window(
width, height, decorated_impl(),
|surface| FrameIData {
surface: surface.clone().unwrap(),
store_token: store_token.clone()
}
);
// Check for fullscreen requirements
if let Some(RootMonitorId { inner: PlatformMonitorId::Wayland(ref monitor_id) }) = attributes.fullscreen {
let info = monitor_id.info.lock().unwrap();
frame.set_state(FrameState::Fullscreen(Some(&info.output)));
} else if attributes.maximized {
frame.set_state(FrameState::Maximized);
}
// set decorations
frame.set_decorate(attributes.decorations);
// min-max dimensions
frame.set_min_size(attributes.min_dimensions.map(|(w, h)| (w as i32, h as i32)));
frame.set_max_size(attributes.max_dimensions.map(|(w, h)| (w as i32, h as i32)));
// setup the monitor tracking
let monitor_list = Arc::new(Mutex::new(MonitorList::default()));
{
let mut evq = evlp.evq.borrow_mut();
let idata = (evlp.ctxt_token.clone(), monitor_list.clone());
evq.register(&surface, surface_impl(), idata);
}
let kill_switch = Arc::new(Mutex::new(false));
let need_frame_refresh = Arc::new(Mutex::new(true));
let frame = Arc::new(Mutex::new(frame));
{
let mut evq = evlp.evq.borrow_mut();
evq.state().get_mut(&store_token).windows.push(InternalWindow {
closed: false,
newsize: None,
need_refresh: false,
need_frame_refresh: need_frame_refresh.clone(),
surface: surface.clone().unwrap(),
kill_switch: kill_switch.clone(),
frame: Arc::downgrade(&frame)
});
evq.sync_roundtrip().unwrap();
}
Ok(Window {
display: evlp.display.clone(),
surface: surface,
frame: frame,
monitors: monitor_list,
size: size,
kill_switch: (kill_switch, evlp.cleanup_needed.clone()),
need_frame_refresh: need_frame_refresh
})
}
#[inline]
pub fn id(&self) -> WindowId {
make_wid(&self.surface)
}
pub fn set_title(&self, title: &str) {
self.frame.lock().unwrap().set_title(title.into());
}
#[inline]
pub fn show(&self) {
// TODO
}
#[inline]
pub fn hide(&self) {
// TODO
}
#[inline]
pub fn get_position(&self) -> Option<(i32, i32)> {
// Not possible with wayland
None
}
#[inline]
pub fn get_inner_position(&self) -> Option<(i32, i32)> {
// Not possible with wayland
None
}
#[inline]
pub fn set_position(&self, _x: i32, _y: i32) {
// Not possible with wayland
}
pub fn get_inner_size(&self) -> Option<(u32, u32)> {
Some(self.size.lock().unwrap().clone())
}
#[inline]
pub fn get_outer_size(&self) -> Option<(u32, u32)> {
let (w, h) = self.size.lock().unwrap().clone();
let (w, h) = super::wayland_window::add_borders(w as i32, h as i32);
Some((w as u32, h as u32))
}
#[inline]
// NOTE: This will only resize the borders, the contents must be updated by the user
pub fn set_inner_size(&self, x: u32, y: u32) {
self.frame.lock().unwrap().resize(x as i32, y as i32);
*(self.size.lock().unwrap()) = (x, y);
}
#[inline]
pub fn set_min_dimensions(&self, dimensions: Option<(u32, u32)>) {
self.frame.lock().unwrap().set_min_size(dimensions.map(|(w, h)| (w as i32, h as i32)));
}
#[inline]
pub fn set_max_dimensions(&self, dimensions: Option<(u32, u32)>) {
self.frame.lock().unwrap().set_max_size(dimensions.map(|(w, h)| (w as i32, h as i32)));
}
#[inline]
pub fn set_cursor(&self, _cursor: MouseCursor) {
// TODO
}
#[inline]
pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
use CursorState::{Grab, Normal, Hide};
// TODO : not yet possible on wayland to grab cursor
match state {
Grab => Err("Cursor cannot be grabbed on wayland yet.".to_string()),
Hide => Err("Cursor cannot be hidden on wayland yet.".to_string()),
Normal => Ok(())
}
}
#[inline]
pub fn hidpi_factor(&self) -> f32 {
let mut factor = 1.0;
let guard = self.monitors.lock().unwrap();
for monitor_id in &guard.monitors {
let info = monitor_id.info.lock().unwrap();
if info.scale > factor { factor = info.scale; }
}
factor
}
pub fn set_decorations(&self, decorate: bool) {
self.frame.lock().unwrap().set_decorate(decorate);
*(self.need_frame_refresh.lock().unwrap()) = true;
}
pub fn set_maximized(&self, maximized: bool) {
if maximized {
self.frame.lock().unwrap().set_state(FrameState::Maximized);
} else {
self.frame.lock().unwrap().set_state(FrameState::Regular);
}
}
pub fn set_fullscreen(&self, monitor: Option<RootMonitorId>) {
if let Some(RootMonitorId { inner: PlatformMonitorId::Wayland(ref monitor_id) }) = monitor {
let info = monitor_id.info.lock().unwrap();
self.frame.lock().unwrap().set_state(FrameState::Fullscreen(Some(&info.output)));
} else {
self.frame.lock().unwrap().set_state(FrameState::Regular);
}
}
#[inline]
pub fn set_cursor_position(&self, _x: i32, _y: i32) -> Result<(), ()> {
// TODO: not yet possible on wayland
Err(())
}
pub fn get_display(&self) -> &wl_display::WlDisplay {
&*self.display
}
pub fn get_surface(&self) -> &wl_surface::WlSurface {
&self.surface
}
pub fn get_current_monitor(&self) -> MonitorId {
// we don't know how much each monitor sees us so...
// just return the most recent one ?
let guard = self.monitors.lock().unwrap();
guard.monitors.last().unwrap().clone()
}
}
impl Drop for Window {
fn drop(&mut self) {
*(self.kill_switch.0.lock().unwrap()) = true;
*(self.kill_switch.1.lock().unwrap()) = true;
}
}
/*
* Internal store for windows
*/
struct InternalWindow {
surface: wl_surface::WlSurface,
newsize: Option<(i32, i32)>,
need_refresh: bool,
need_frame_refresh: Arc<Mutex<bool>>,
closed: bool,
kill_switch: Arc<Mutex<bool>>,
frame: Weak<Mutex<Frame>>
}
pub struct WindowStore {
windows: Vec<InternalWindow>
}
impl WindowStore {
pub fn new() -> WindowStore {
WindowStore { windows: Vec::new() }
}
pub fn find_wid(&self, surface: &wl_surface::WlSurface) -> Option<WindowId> {
for window in &self.windows {
if surface.equals(&window.surface) {
return Some(make_wid(surface));
}
}
None
}
pub fn cleanup(&mut self) -> Vec<WindowId> {
let mut pruned = Vec::new();
self.windows.retain(|w| {
if *w.kill_switch.lock().unwrap() {
// window is dead, cleanup
pruned.push(make_wid(&w.surface));
w.surface.destroy();
false
} else {
true
}
});
pruned
}
pub fn for_each<F>(&mut self, mut f: F)
where F: FnMut(Option<(i32, i32)>, bool, bool, bool, WindowId, Option<&mut Frame>)
{
for window in &mut self.windows {
let opt_arc = window.frame.upgrade();
let mut opt_mutex_lock = opt_arc.as_ref().map(|m| m.lock().unwrap());
f(
window.newsize.take(),
window.need_refresh,
::std::mem::replace(&mut *window.need_frame_refresh.lock().unwrap(), false),
window.closed,
make_wid(&window.surface),
opt_mutex_lock.as_mut().map(|m| &mut **m)
);
window.need_refresh = false;
// avoid re-spamming the event
window.closed = false;
}
}
}
/*
* Protocol implementation
*/
struct FrameIData {
store_token: StateToken<WindowStore>,
surface: wl_surface::WlSurface
}
fn decorated_impl() -> FrameImplementation<FrameIData> {
FrameImplementation {
configure: |evqh, idata, _, newsize| {
let store = evqh.state().get_mut(&idata.store_token);
for window in &mut store.windows {
if window.surface.equals(&idata.surface) {
window.newsize = newsize;
window.need_refresh = true;
*(window.need_frame_refresh.lock().unwrap()) = true;
return;
}
}
},
close: |evqh, idata| {
let store = evqh.state().get_mut(&idata.store_token);
for window in &mut store.windows {
if window.surface.equals(&idata.surface) {
window.closed = true;
return;
}
}
},
refresh: |evqh, idata| {
let store = evqh.state().get_mut(&idata.store_token);
for window in &mut store.windows {
if window.surface.equals(&idata.surface) {
*(window.need_frame_refresh.lock().unwrap()) = true;
return;
}
}
}
}
}
#[derive(Default)]
struct MonitorList {
monitors: Vec<MonitorId>
}
fn surface_impl() -> wl_surface::Implementation<(StateToken<StateContext>, Arc<Mutex<MonitorList>>)> {
wl_surface::Implementation {
enter: |evqh, &mut (ref token, ref list), _, output| {
let mut guard = list.lock().unwrap();
let ctxt = evqh.state().get(token);
let monitor = ctxt.monitor_id_for(output);
guard.monitors.push(monitor);
},
leave: |evqh, &mut (ref token, ref list), _, output| {
let mut guard = list.lock().unwrap();
let ctxt = evqh.state().get(token);
let monitor = ctxt.monitor_id_for(output);
guard.monitors.retain(|m| !Arc::ptr_eq(&m.info, &monitor.info));
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +0,0 @@
pub use x11_dl::keysym::*;
pub use x11_dl::xcursor::*;
pub use x11_dl::xlib::*;
pub use x11_dl::xinput::*;
pub use x11_dl::xinput2::*;
pub use x11_dl::xlib_xcb::*;
pub use x11_dl::error::OpenError;
pub use x11_dl::xrandr::*;

View File

@@ -1,134 +0,0 @@
use std::ptr;
use std::sync::Arc;
use std::os::raw::{c_short, c_void};
use super::{ffi, util, XConnection, XError};
#[derive(Debug)]
pub enum ImeContextCreationError {
XError(XError),
Null,
}
unsafe fn create_pre_edit_attr<'a>(
xconn: &'a Arc<XConnection>,
ic_spot: &'a ffi::XPoint,
) -> util::XSmartPointer<'a, c_void> {
util::XSmartPointer::new(
xconn,
(xconn.xlib.XVaCreateNestedList)(
0,
ffi::XNSpotLocation_0.as_ptr() as *const _,
ic_spot,
ptr::null_mut::<()>(),
),
).expect("XVaCreateNestedList returned NULL")
}
// WARNING: this struct doesn't destroy its XIC resource when dropped.
// This is intentional, as it doesn't have enough information to know whether or not the context
// still exists on the server. Since `ImeInner` has that awareness, destruction must be handled
// through `ImeInner`.
#[derive(Debug)]
pub struct ImeContext {
pub ic: ffi::XIC,
pub ic_spot: ffi::XPoint,
}
impl ImeContext {
pub unsafe fn new(
xconn: &Arc<XConnection>,
im: ffi::XIM,
window: ffi::Window,
ic_spot: Option<ffi::XPoint>,
) -> Result<Self, ImeContextCreationError> {
let ic = if let Some(ic_spot) = ic_spot {
ImeContext::create_ic_with_spot(xconn, im, window, ic_spot)
} else {
ImeContext::create_ic(xconn, im, window)
};
let ic = ic.ok_or(ImeContextCreationError::Null)?;
xconn.check_errors().map_err(ImeContextCreationError::XError)?;
Ok(ImeContext {
ic,
ic_spot: ic_spot.unwrap_or_else(|| ffi::XPoint { x: 0, y: 0 }),
})
}
unsafe fn create_ic(
xconn: &Arc<XConnection>,
im: ffi::XIM,
window: ffi::Window,
) -> Option<ffi::XIC> {
let ic = (xconn.xlib.XCreateIC)(
im,
ffi::XNInputStyle_0.as_ptr() as *const _,
ffi::XIMPreeditNothing | ffi::XIMStatusNothing,
ffi::XNClientWindow_0.as_ptr() as *const _,
window,
ptr::null_mut::<()>(),
);
if ic.is_null() {
None
} else {
Some(ic)
}
}
unsafe fn create_ic_with_spot(
xconn: &Arc<XConnection>,
im: ffi::XIM,
window: ffi::Window,
ic_spot: ffi::XPoint,
) -> Option<ffi::XIC> {
let pre_edit_attr = create_pre_edit_attr(xconn, &ic_spot);
let ic = (xconn.xlib.XCreateIC)(
im,
ffi::XNInputStyle_0.as_ptr() as *const _,
ffi::XIMPreeditNothing | ffi::XIMStatusNothing,
ffi::XNClientWindow_0.as_ptr() as *const _,
window,
ffi::XNPreeditAttributes_0.as_ptr() as *const _,
pre_edit_attr.ptr,
ptr::null_mut::<()>(),
);
if ic.is_null() {
None
} else {
Some(ic)
}
}
pub fn focus(&self, xconn: &Arc<XConnection>) -> Result<(), XError> {
unsafe {
(xconn.xlib.XSetICFocus)(self.ic);
}
xconn.check_errors()
}
pub fn unfocus(&self, xconn: &Arc<XConnection>) -> Result<(), XError> {
unsafe {
(xconn.xlib.XUnsetICFocus)(self.ic);
}
xconn.check_errors()
}
pub fn set_spot(&mut self, xconn: &Arc<XConnection>, x: c_short, y: c_short) {
if self.ic_spot.x == x && self.ic_spot.y == y {
return;
}
self.ic_spot = ffi::XPoint { x, y };
unsafe {
let pre_edit_attr = create_pre_edit_attr(xconn, &self.ic_spot);
(xconn.xlib.XSetICValues)(
self.ic,
ffi::XNPreeditAttributes_0.as_ptr() as *const _,
pre_edit_attr.ptr,
ptr::null_mut::<()>(),
);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,129 +0,0 @@
use std::sync::Arc;
use std::slice;
use super::XConnection;
#[derive(Clone)]
pub struct MonitorId {
/// The actual id
id: u32,
/// The name of the monitor
name: String,
/// The size of the monitor
dimensions: (u32, u32),
/// The position of the monitor in the X screen
position: (i32, i32),
/// If the monitor is the primary one
primary: bool,
/// The DPI scaling factor
hidpi_factor: f32,
}
pub fn get_available_monitors(x: &Arc<XConnection>) -> Vec<MonitorId> {
let mut available = Vec::new();
unsafe {
let root = (x.xlib.XDefaultRootWindow)(x.display);
let resources = (x.xrandr.XRRGetScreenResources)(x.display, root);
if let Some(ref xrandr_1_5) = x.xrandr_1_5 {
// We're in XRandR >= 1.5, enumerate Monitors to handle things like MST and videowalls
let mut nmonitors = 0;
let monitors = (xrandr_1_5.XRRGetMonitors)(x.display, root, 1, &mut nmonitors);
for i in 0..nmonitors {
let monitor = *(monitors.offset(i as isize));
let output = (xrandr_1_5.XRRGetOutputInfo)(x.display, resources, *(monitor.outputs.offset(0)));
let nameslice = slice::from_raw_parts((*output).name as *mut u8, (*output).nameLen as usize);
let name = String::from_utf8_lossy(nameslice).into_owned();
let hidpi_factor = {
let x_mm = (*output).mm_width as f32;
let y_mm = (*output).mm_height as f32;
let x_px = monitor.width as f32;
let y_px = monitor.height as f32;
let ppmm = ((x_px * y_px) / (x_mm * y_mm)).sqrt();
// Quantize 1/12 step size
((ppmm * (12.0 * 25.4 / 96.0)).round() / 12.0).max(1.0)
};
(xrandr_1_5.XRRFreeOutputInfo)(output);
available.push(MonitorId{
id: i as u32,
name,
hidpi_factor,
dimensions: (monitor.width as u32, monitor.height as u32),
position: (monitor.x as i32, monitor.y as i32),
primary: (monitor.primary != 0),
});
}
(xrandr_1_5.XRRFreeMonitors)(monitors);
} else {
// We're in XRandR < 1.5, enumerate CRTCs. Everything will work but MST and
// videowall setups will show more monitors than the logical groups the user
// cares about
for i in 0..(*resources).ncrtc {
let crtcid = *((*resources).crtcs.offset(i as isize));
let crtc = (x.xrandr.XRRGetCrtcInfo)(x.display, resources, crtcid);
if (*crtc).width > 0 && (*crtc).height > 0 && (*crtc).noutput > 0 {
let output = (x.xrandr.XRRGetOutputInfo)(x.display, resources, *((*crtc).outputs.offset(0)));
let nameslice = slice::from_raw_parts((*output).name as *mut u8, (*output).nameLen as usize);
let name = String::from_utf8_lossy(nameslice).into_owned();
let hidpi_factor = {
let x_mm = (*output).mm_width as f32;
let y_mm = (*output).mm_height as f32;
let x_px = (*crtc).width as f32;
let y_px = (*crtc).height as f32;
let ppmm = ((x_px * y_px) / (x_mm * y_mm)).sqrt();
// Quantize 1/12 step size
((ppmm * (12.0 * 25.4 / 96.0)).round() / 12.0).max(1.0)
};
(x.xrandr.XRRFreeOutputInfo)(output);
available.push(MonitorId{
id: crtcid as u32,
name,
hidpi_factor,
dimensions: ((*crtc).width as u32, (*crtc).height as u32),
position: ((*crtc).x as i32, (*crtc).y as i32),
primary: true,
});
}
(x.xrandr.XRRFreeCrtcInfo)(crtc);
}
}
(x.xrandr.XRRFreeScreenResources)(resources);
}
available
}
#[inline]
pub fn get_primary_monitor(x: &Arc<XConnection>) -> MonitorId {
get_available_monitors(x).into_iter().find(|m| m.primary)
// 'no primary' case is better handled picking some existing monitor
.or_else(|| get_available_monitors(x).into_iter().next())
.expect("[winit] Failed to find any x11 monitor")
}
impl MonitorId {
pub fn get_name(&self) -> Option<String> {
Some(self.name.clone())
}
#[inline]
pub fn get_native_identifier(&self) -> u32 {
self.id as u32
}
pub fn get_dimensions(&self) -> (u32, u32) {
self.dimensions
}
pub fn get_position(&self) -> (i32, i32) {
self.position
}
#[inline]
pub fn get_hidpi_factor(&self) -> f32 {
self.hidpi_factor
}
}

View File

@@ -1,365 +0,0 @@
use std::mem;
use std::ptr;
use std::str;
use std::sync::Arc;
use std::ops::{Deref, DerefMut};
use std::os::raw::{c_char, c_double, c_int, c_long, c_short, c_uchar, c_uint, c_ulong};
use super::{ffi, XConnection, XError};
use events::ModifiersState;
pub struct XSmartPointer<'a, T> {
xconn: &'a Arc<XConnection>,
pub ptr: *mut T,
}
impl<'a, T> XSmartPointer<'a, T> {
// You're responsible for only passing things to this that should be XFree'd.
// Returns None if ptr is null.
pub fn new(xconn: &'a Arc<XConnection>, ptr: *mut T) -> Option<Self> {
if !ptr.is_null() {
Some(XSmartPointer {
xconn,
ptr,
})
} else {
None
}
}
}
impl<'a, T> Deref for XSmartPointer<'a, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.ptr }
}
}
impl<'a, T> DerefMut for XSmartPointer<'a, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.ptr }
}
}
impl<'a, T> Drop for XSmartPointer<'a, T> {
fn drop(&mut self) {
unsafe {
(self.xconn.xlib.XFree)(self.ptr as *mut _);
}
}
}
pub unsafe fn get_atom(xconn: &Arc<XConnection>, name: &[u8]) -> Result<ffi::Atom, XError> {
let atom_name: *const c_char = name.as_ptr() as _;
let atom = (xconn.xlib.XInternAtom)(xconn.display, atom_name, ffi::False);
xconn.check_errors().map(|_| atom)
}
pub unsafe fn send_client_msg(
xconn: &Arc<XConnection>,
window: c_ulong, // the window this is "about"; not necessarily this window
target_window: c_ulong, // the window we're sending to
message_type: ffi::Atom,
event_mask: Option<c_long>,
data: (c_long, c_long, c_long, c_long, c_long),
) -> Result<(), XError> {
let mut event: ffi::XClientMessageEvent = mem::uninitialized();
event.type_ = ffi::ClientMessage;
event.display = xconn.display;
event.window = window;
event.message_type = message_type;
event.format = 32;
event.data = ffi::ClientMessageData::new();
event.data.set_long(0, data.0);
event.data.set_long(1, data.1);
event.data.set_long(2, data.2);
event.data.set_long(3, data.3);
event.data.set_long(4, data.4);
let event_mask = event_mask.unwrap_or(ffi::NoEventMask);
(xconn.xlib.XSendEvent)(
xconn.display,
target_window,
ffi::False,
event_mask,
&mut event.into(),
);
xconn.check_errors().map(|_| ())
}
#[derive(Debug, Clone)]
pub enum GetPropertyError {
XError(XError),
TypeMismatch(ffi::Atom),
FormatMismatch(c_int),
NothingAllocated,
}
impl GetPropertyError {
pub fn is_actual_property_type(&self, t: ffi::Atom) -> bool {
if let GetPropertyError::TypeMismatch(actual_type) = *self {
actual_type == t
} else {
false
}
}
}
pub unsafe fn get_property<T>(
xconn: &Arc<XConnection>,
window: c_ulong,
property: ffi::Atom,
property_type: ffi::Atom,
) -> Result<Vec<T>, GetPropertyError> {
let mut data = Vec::new();
let mut done = false;
while !done {
let mut actual_type: ffi::Atom = mem::uninitialized();
let mut actual_format: c_int = mem::uninitialized();
let mut byte_count: c_ulong = mem::uninitialized();
let mut bytes_after: c_ulong = mem::uninitialized();
let mut buf: *mut c_uchar = ptr::null_mut();
(xconn.xlib.XGetWindowProperty)(
xconn.display,
window,
property,
(data.len() / 4) as c_long,
1024,
ffi::False,
property_type,
&mut actual_type,
&mut actual_format,
&mut byte_count,
&mut bytes_after,
&mut buf,
);
if let Err(e) = xconn.check_errors() {
return Err(GetPropertyError::XError(e));
}
if actual_type != property_type {
return Err(GetPropertyError::TypeMismatch(actual_type));
}
// Fun fact: actual_format ISN'T the size of the type; it's more like a really bad enum
let format_mismatch = match actual_format as usize {
8 => mem::size_of::<T>() != mem::size_of::<c_char>(),
16 => mem::size_of::<T>() != mem::size_of::<c_short>(),
32 => mem::size_of::<T>() != mem::size_of::<c_long>(),
_ => true, // this won't actually be reached; the XError condition above is triggered
};
if format_mismatch {
return Err(GetPropertyError::FormatMismatch(actual_format));
}
if !buf.is_null() {
let mut buf =
Vec::from_raw_parts(buf as *mut T, byte_count as usize, byte_count as usize);
data.append(&mut buf);
} else {
return Err(GetPropertyError::NothingAllocated);
}
done = bytes_after == 0;
}
Ok(data)
}
impl From<ffi::XIModifierState> for ModifiersState {
fn from(mods: ffi::XIModifierState) -> Self {
let state = mods.effective as c_uint;
ModifiersState {
alt: state & ffi::Mod1Mask != 0,
shift: state & ffi::ShiftMask != 0,
ctrl: state & ffi::ControlMask != 0,
logo: state & ffi::Mod4Mask != 0,
}
}
}
#[derive(Debug)]
pub struct PointerState {
#[allow(dead_code)]
root: ffi::Window,
#[allow(dead_code)]
child: ffi::Window,
#[allow(dead_code)]
root_x: c_double,
#[allow(dead_code)]
root_y: c_double,
#[allow(dead_code)]
win_x: c_double,
#[allow(dead_code)]
win_y: c_double,
#[allow(dead_code)]
buttons: ffi::XIButtonState,
modifiers: ffi::XIModifierState,
#[allow(dead_code)]
group: ffi::XIGroupState,
#[allow(dead_code)]
relative_to_window: bool,
}
impl PointerState {
pub fn get_modifier_state(&self) -> ModifiersState {
self.modifiers.into()
}
}
pub unsafe fn query_pointer(
xconn: &Arc<XConnection>,
window: ffi::Window,
device_id: c_int,
) -> Result<PointerState, XError> {
let mut root_return = mem::uninitialized();
let mut child_return = mem::uninitialized();
let mut root_x_return = mem::uninitialized();
let mut root_y_return = mem::uninitialized();
let mut win_x_return = mem::uninitialized();
let mut win_y_return = mem::uninitialized();
let mut buttons_return = mem::uninitialized();
let mut modifiers_return = mem::uninitialized();
let mut group_return = mem::uninitialized();
let relative_to_window = (xconn.xinput2.XIQueryPointer)(
xconn.display,
device_id,
window,
&mut root_return,
&mut child_return,
&mut root_x_return,
&mut root_y_return,
&mut win_x_return,
&mut win_y_return,
&mut buttons_return,
&mut modifiers_return,
&mut group_return,
) == ffi::True;
xconn.check_errors()?;
Ok(PointerState {
root: root_return,
child: child_return,
root_x: root_x_return,
root_y: root_y_return,
win_x: win_x_return,
win_y: win_y_return,
buttons: buttons_return,
modifiers: modifiers_return,
group: group_return,
relative_to_window,
})
}
unsafe fn lookup_utf8_inner(
xconn: &Arc<XConnection>,
ic: ffi::XIC,
key_event: &mut ffi::XKeyEvent,
buffer: &mut [u8],
) -> (ffi::KeySym, ffi::Status, c_int) {
let mut keysym: ffi::KeySym = 0;
let mut status: ffi::Status = 0;
let count = (xconn.xlib.Xutf8LookupString)(
ic,
key_event,
buffer.as_mut_ptr() as *mut c_char,
buffer.len() as c_int,
&mut keysym,
&mut status,
);
(keysym, status, count)
}
pub unsafe fn lookup_utf8(
xconn: &Arc<XConnection>,
ic: ffi::XIC,
key_event: &mut ffi::XKeyEvent,
) -> String {
const INIT_BUFF_SIZE: usize = 16;
// Buffer allocated on heap instead of stack, due to the possible reallocation
let mut buffer: Vec<u8> = vec![mem::uninitialized(); INIT_BUFF_SIZE];
let (_, status, mut count) = lookup_utf8_inner(
xconn,
ic,
key_event,
&mut buffer,
);
// Buffer overflowed, dynamically reallocate
if status == ffi::XBufferOverflow {
buffer = vec![mem::uninitialized(); count as usize];
let (_, _, new_count) = lookup_utf8_inner(
xconn,
ic,
key_event,
&mut buffer,
);
count = new_count;
}
str::from_utf8(&buffer[..count as usize]).unwrap_or("").to_string()
}
#[derive(Debug)]
pub struct FrameExtents {
pub left: c_ulong,
pub right: c_ulong,
pub top: c_ulong,
pub bottom: c_ulong,
}
impl FrameExtents {
pub fn new(left: c_ulong, right: c_ulong, top: c_ulong, bottom: c_ulong) -> Self {
FrameExtents { left, right, top, bottom }
}
pub fn from_border(border: c_ulong) -> Self {
Self::new(border, border, border, border)
}
}
#[derive(Debug)]
pub struct WindowGeometry {
pub x: c_int,
pub y: c_int,
pub width: c_uint,
pub height: c_uint,
pub frame: FrameExtents,
}
impl WindowGeometry {
pub fn get_position(&self) -> (i32, i32) {
(self.x as _, self.y as _)
}
pub fn get_inner_position(&self) -> (i32, i32) {
(
self.x.saturating_add(self.frame.left as c_int) as _,
self.y.saturating_add(self.frame.top as c_int) as _,
)
}
pub fn get_inner_size(&self) -> (u32, u32) {
(self.width as _, self.height as _)
}
pub fn get_outer_size(&self) -> (u32, u32) {
(
self.width.saturating_add(
self.frame.left.saturating_add(self.frame.right) as c_uint
) as _,
self.height.saturating_add(
self.frame.top.saturating_add(self.frame.bottom) as c_uint
) as _,
)
}
}

File diff suppressed because it is too large Load Diff

274
src/platform/macos.rs Normal file
View File

@@ -0,0 +1,274 @@
#![cfg(target_os = "macos")]
use std::os::raw::c_void;
use crate::{
dpi::LogicalSize,
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);
}
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)
}
}
/// 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;
/// Build window with `resizeIncrements` property. Values must not be 0.
fn with_resize_increments(self, increments: LogicalSize<f64>) -> WindowBuilder;
fn with_disallow_hidpi(self, disallow_hidpi: bool) -> WindowBuilder;
fn with_has_shadow(self, has_shadow: bool) -> 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_resize_increments(mut self, increments: LogicalSize<f64>) -> WindowBuilder {
self.platform_specific.resize_increments = Some(increments);
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
}
}
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;
}
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
}
}
/// 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| s as *mut c_void)
}
}
/// 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()
}
}

View File

@@ -1,774 +0,0 @@
use {ControlFlow, EventsLoopClosed};
use cocoa::{self, appkit, foundation};
use cocoa::appkit::{NSApplication, NSEvent, NSEventMask, NSEventModifierFlags, NSEventPhase, NSView, NSWindow};
use events::{self, ElementState, Event, MouseButton, TouchPhase, WindowEvent, DeviceEvent, ModifiersState, KeyboardInput};
use std::collections::VecDeque;
use std::sync::{Arc, Mutex, Weak};
use super::window::Window2;
use std;
use super::DeviceId;
pub struct EventsLoop {
modifiers: Modifiers,
pub shared: Arc<Shared>,
}
// State shared between the `EventsLoop` and its registered windows.
pub struct Shared {
pub windows: Mutex<Vec<Weak<Window2>>>,
pub pending_events: Mutex<VecDeque<Event>>,
// The user event callback given via either of the `poll_events` or `run_forever` methods.
//
// We store the user's callback here so that it may be accessed by each of the window delegate
// callbacks (e.g. resize, close, etc) for the duration of a call to either of the
// `poll_events` or `run_forever` methods.
//
// This is *only* `Some` for the duration of a call to either of these methods and will be
// `None` otherwise.
user_callback: UserCallback,
}
#[derive(Clone)]
pub struct Proxy {}
struct Modifiers {
shift_pressed: bool,
ctrl_pressed: bool,
win_pressed: bool,
alt_pressed: bool,
}
// Wrapping the user callback in a type allows us to:
//
// - ensure the callback pointer is never accidentally cloned
// - ensure that only the `EventsLoop` can `store` and `drop` the callback pointer
// - Share access to the user callback with the NSWindow callbacks.
pub struct UserCallback {
mutex: Mutex<Option<*mut FnMut(Event)>>,
}
impl Shared {
pub fn new() -> Self {
Shared {
windows: Mutex::new(Vec::new()),
pending_events: Mutex::new(VecDeque::new()),
user_callback: UserCallback { mutex: Mutex::new(None) },
}
}
fn call_user_callback_with_pending_events(&self) {
loop {
let event = match self.pending_events.lock().unwrap().pop_front() {
Some(event) => event,
None => return,
};
unsafe {
self.user_callback.call_with_event(event);
}
}
}
// Calls the user callback if one exists.
//
// Otherwise, stores the event in the `pending_events` queue.
//
// This is necessary for the case when `WindowDelegate` callbacks are triggered during a call
// to the user's callback.
pub fn call_user_callback_with_event_or_store_in_pending(&self, event: Event) {
if self.user_callback.mutex.lock().unwrap().is_some() {
unsafe {
self.user_callback.call_with_event(event);
}
} else {
self.pending_events.lock().unwrap().push_back(event);
}
}
// Removes the window with the given `Id` from the `windows` list.
//
// This is called in response to `windowWillClose`.
pub fn find_and_remove_window(&self, id: super::window::Id) {
if let Ok(mut windows) = self.windows.lock() {
windows.retain(|w| match w.upgrade() {
Some(w) => w.id() != id,
None => true,
});
}
}
}
impl Modifiers {
pub fn new() -> Self {
Modifiers {
shift_pressed: false,
ctrl_pressed: false,
win_pressed: false,
alt_pressed: false,
}
}
}
impl UserCallback {
// Here we store user's `callback` behind the mutex so that they may be safely shared between
// each of the window delegates.
//
// In order to make sure that the pointer is always valid, we must manually guarantee that it
// is dropped before the callback itself is dropped. Thus, this should *only* be called at the
// beginning of a call to `poll_events` and `run_forever`, both of which *must* drop the
// callback at the end of their scope using the `drop` method.
fn store<F>(&self, callback: &mut F)
where F: FnMut(Event)
{
let trait_object = callback as &mut FnMut(Event);
let trait_object_ptr = trait_object as *const FnMut(Event) as *mut FnMut(Event);
*self.mutex.lock().unwrap() = Some(trait_object_ptr);
}
// Emits the given event via the user-given callback.
//
// This is unsafe as it requires dereferencing the pointer to the user-given callback. We
// guarantee this is safe by ensuring the `UserCallback` never lives longer than the user-given
// callback.
//
// Note that the callback may not always be `Some`. This is because some `NSWindowDelegate`
// callbacks can be triggered by means other than `NSApp().sendEvent`. For example, if a window
// is destroyed or created during a call to the user's callback, the `WindowDelegate` methods
// may be called with `windowShouldClose` or `windowDidResignKey`.
unsafe fn call_with_event(&self, event: Event) {
let callback = match self.mutex.lock().unwrap().take() {
Some(callback) => callback,
None => return,
};
(*callback)(event);
*self.mutex.lock().unwrap() = Some(callback);
}
// Used to drop the user callback pointer at the end of the `poll_events` and `run_forever`
// methods. This is done to enforce our guarantee that the top callback will never live longer
// than the call to either `poll_events` or `run_forever` to which it was given.
fn drop(&self) {
self.mutex.lock().unwrap().take();
}
}
impl EventsLoop {
pub fn new() -> Self {
// Mark this thread as the main thread of the Cocoa event system.
//
// This must be done before any worker threads get a chance to call it
// (e.g., via `EventsLoopProxy::wakeup()`), causing a wrong thread to be
// marked as the main thread.
unsafe { appkit::NSApp(); }
EventsLoop {
shared: Arc::new(Shared::new()),
modifiers: Modifiers::new(),
}
}
pub fn poll_events<F>(&mut self, mut callback: F)
where F: FnMut(Event),
{
unsafe {
if !msg_send![cocoa::base::class("NSThread"), isMainThread] {
panic!("Events can only be polled from the main thread on macOS");
}
}
self.shared.user_callback.store(&mut callback);
// Loop as long as we have pending events to return.
loop {
unsafe {
// First, yield all pending events.
self.shared.call_user_callback_with_pending_events();
let pool = foundation::NSAutoreleasePool::new(cocoa::base::nil);
// Poll for the next event, returning `nil` if there are none.
let ns_event = appkit::NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_(
NSEventMask::NSAnyEventMask.bits() | NSEventMask::NSEventMaskPressure.bits(),
foundation::NSDate::distantPast(cocoa::base::nil),
foundation::NSDefaultRunLoopMode,
cocoa::base::YES);
let event = self.ns_event_to_event(ns_event);
let _: () = msg_send![pool, release];
match event {
// Call the user's callback.
Some(event) => self.shared.user_callback.call_with_event(event),
None => break,
}
}
}
self.shared.user_callback.drop();
}
pub fn run_forever<F>(&mut self, mut callback: F)
where F: FnMut(Event) -> ControlFlow
{
unsafe {
if !msg_send![cocoa::base::class("NSThread"), isMainThread] {
panic!("Events can only be polled from the main thread on macOS");
}
}
// Track whether or not control flow has changed.
let control_flow = std::cell::Cell::new(ControlFlow::Continue);
let mut callback = |event| {
if let ControlFlow::Break = callback(event) {
control_flow.set(ControlFlow::Break);
}
};
self.shared.user_callback.store(&mut callback);
loop {
unsafe {
// First, yield all pending events.
self.shared.call_user_callback_with_pending_events();
if let ControlFlow::Break = control_flow.get() {
break;
}
let pool = foundation::NSAutoreleasePool::new(cocoa::base::nil);
// Wait for the next event. Note that this function blocks during resize.
let ns_event = appkit::NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_(
NSEventMask::NSAnyEventMask.bits() | NSEventMask::NSEventMaskPressure.bits(),
foundation::NSDate::distantFuture(cocoa::base::nil),
foundation::NSDefaultRunLoopMode,
cocoa::base::YES);
let maybe_event = self.ns_event_to_event(ns_event);
// Release the pool before calling the top callback in case the user calls either
// `run_forever` or `poll_events` within the callback.
let _: () = msg_send![pool, release];
if let Some(event) = maybe_event {
self.shared.user_callback.call_with_event(event);
if let ControlFlow::Break = control_flow.get() {
break;
}
}
}
}
self.shared.user_callback.drop();
}
// Convert some given `NSEvent` into a winit `Event`.
unsafe fn ns_event_to_event(&mut self, ns_event: cocoa::base::id) -> Option<Event> {
if ns_event == cocoa::base::nil {
return None;
}
// FIXME: Despite not being documented anywhere, an `NSEvent` is produced when a user opens
// Spotlight while the NSApplication is in focus. This `NSEvent` produces a `NSEventType`
// with value `21`. This causes a SEGFAULT as soon as we try to match on the `NSEventType`
// enum as there is no variant associated with the value. Thus, we return early if this
// sneaky event occurs. If someone does find some documentation on this, please fix this by
// adding an appropriate variant to the `NSEventType` enum in the cocoa-rs crate.
if ns_event.eventType() as u64 == 21 {
return None;
}
let event_type = ns_event.eventType();
let ns_window = ns_event.window();
let window_id = super::window::get_window_id(ns_window);
// FIXME: Document this. Why do we do this? Seems like it passes on events to window/app.
// If we don't do this, window does not become main for some reason.
match event_type {
appkit::NSKeyDown => (),
_ => appkit::NSApp().sendEvent_(ns_event),
}
let windows = self.shared.windows.lock().unwrap();
let maybe_window = windows.iter()
.filter_map(Weak::upgrade)
.find(|window| window_id == window.id());
let into_event = |window_event| Event::WindowEvent {
window_id: ::WindowId(window_id),
event: window_event,
};
// Returns `Some` window if one of our windows is the key window.
let maybe_key_window = || windows.iter()
.filter_map(Weak::upgrade)
.find(|window| {
let is_key_window: cocoa::base::BOOL = msg_send![*window.window, isKeyWindow];
is_key_window == cocoa::base::YES
});
match event_type {
appkit::NSKeyDown => {
let mut events = std::collections::VecDeque::new();
let received_c_str = foundation::NSString::UTF8String(ns_event.characters());
let received_str = std::ffi::CStr::from_ptr(received_c_str);
let vkey = to_virtual_key_code(NSEvent::keyCode(ns_event));
let state = ElementState::Pressed;
let code = NSEvent::keyCode(ns_event) as u32;
let window_event = WindowEvent::KeyboardInput {
device_id: DEVICE_ID,
input: KeyboardInput {
state: state,
scancode: code,
virtual_keycode: vkey,
modifiers: event_mods(ns_event),
},
};
for received_char in std::str::from_utf8(received_str.to_bytes()).unwrap().chars() {
let window_event = WindowEvent::ReceivedCharacter(received_char);
events.push_back(into_event(window_event));
}
self.shared.pending_events.lock().unwrap().extend(events.into_iter());
Some(into_event(window_event))
},
appkit::NSKeyUp => {
let vkey = to_virtual_key_code(NSEvent::keyCode(ns_event));
let state = ElementState::Released;
let code = NSEvent::keyCode(ns_event) as u32;
let window_event = WindowEvent::KeyboardInput {
device_id: DEVICE_ID,
input: KeyboardInput {
state: state,
scancode: code,
virtual_keycode: vkey,
modifiers: event_mods(ns_event),
},
};
Some(into_event(window_event))
},
appkit::NSFlagsChanged => {
unsafe fn modifier_event(event: cocoa::base::id,
keymask: NSEventModifierFlags,
key: events::VirtualKeyCode,
key_pressed: bool) -> Option<WindowEvent>
{
if !key_pressed && NSEvent::modifierFlags(event).contains(keymask) {
let state = ElementState::Pressed;
let code = NSEvent::keyCode(event) as u32;
let window_event = WindowEvent::KeyboardInput {
device_id: DEVICE_ID,
input: KeyboardInput {
state: state,
scancode: code,
virtual_keycode: Some(key),
modifiers: event_mods(event),
},
};
Some(window_event)
} else if key_pressed && !NSEvent::modifierFlags(event).contains(keymask) {
let state = ElementState::Released;
let code = NSEvent::keyCode(event) as u32;
let window_event = WindowEvent::KeyboardInput {
device_id: DEVICE_ID,
input: KeyboardInput {
state: state,
scancode: code,
virtual_keycode: Some(key),
modifiers: event_mods(event),
},
};
Some(window_event)
} else {
None
}
}
let mut events = std::collections::VecDeque::new();
if let Some(window_event) = modifier_event(ns_event,
NSEventModifierFlags::NSShiftKeyMask,
events::VirtualKeyCode::LShift,
self.modifiers.shift_pressed)
{
self.modifiers.shift_pressed = !self.modifiers.shift_pressed;
events.push_back(into_event(window_event));
}
if let Some(window_event) = modifier_event(ns_event,
NSEventModifierFlags::NSControlKeyMask,
events::VirtualKeyCode::LControl,
self.modifiers.ctrl_pressed)
{
self.modifiers.ctrl_pressed = !self.modifiers.ctrl_pressed;
events.push_back(into_event(window_event));
}
if let Some(window_event) = modifier_event(ns_event,
NSEventModifierFlags::NSCommandKeyMask,
events::VirtualKeyCode::LWin,
self.modifiers.win_pressed)
{
self.modifiers.win_pressed = !self.modifiers.win_pressed;
events.push_back(into_event(window_event));
}
if let Some(window_event) = modifier_event(ns_event,
NSEventModifierFlags::NSAlternateKeyMask,
events::VirtualKeyCode::LAlt,
self.modifiers.alt_pressed)
{
self.modifiers.alt_pressed = !self.modifiers.alt_pressed;
events.push_back(into_event(window_event));
}
let event = events.pop_front();
self.shared.pending_events.lock().unwrap().extend(events.into_iter());
event
},
appkit::NSLeftMouseDown => { Some(into_event(WindowEvent::MouseInput { device_id: DEVICE_ID, state: ElementState::Pressed, button: MouseButton::Left, modifiers: event_mods(ns_event) })) },
appkit::NSLeftMouseUp => { Some(into_event(WindowEvent::MouseInput { device_id: DEVICE_ID, state: ElementState::Released, button: MouseButton::Left, modifiers: event_mods(ns_event) })) },
appkit::NSRightMouseDown => { Some(into_event(WindowEvent::MouseInput { device_id: DEVICE_ID, state: ElementState::Pressed, button: MouseButton::Right, modifiers: event_mods(ns_event) })) },
appkit::NSRightMouseUp => { Some(into_event(WindowEvent::MouseInput { device_id: DEVICE_ID, state: ElementState::Released, button: MouseButton::Right, modifiers: event_mods(ns_event) })) },
appkit::NSOtherMouseDown => { Some(into_event(WindowEvent::MouseInput { device_id: DEVICE_ID, state: ElementState::Pressed, button: MouseButton::Middle, modifiers: event_mods(ns_event) })) },
appkit::NSOtherMouseUp => { Some(into_event(WindowEvent::MouseInput { device_id: DEVICE_ID, state: ElementState::Released, button: MouseButton::Middle, modifiers: event_mods(ns_event) })) },
appkit::NSMouseEntered => {
let window = match maybe_window.or_else(maybe_key_window) {
Some(window) => window,
None => return None,
};
let window_point = ns_event.locationInWindow();
let view_point = if ns_window == cocoa::base::nil {
let ns_size = foundation::NSSize::new(0.0, 0.0);
let ns_rect = foundation::NSRect::new(window_point, ns_size);
let window_rect = window.window.convertRectFromScreen_(ns_rect);
window.view.convertPoint_fromView_(window_rect.origin, cocoa::base::nil)
} else {
window.view.convertPoint_fromView_(window_point, cocoa::base::nil)
};
let view_rect = NSView::frame(*window.view);
let scale_factor = window.hidpi_factor();
let x = (scale_factor * view_point.x as f32) as f64;
let y = (scale_factor * (view_rect.size.height - view_point.y) as f32) as f64;
let window_event = WindowEvent::CursorMoved { device_id: DEVICE_ID, position: (x, y), modifiers: event_mods(ns_event) };
let event = Event::WindowEvent { window_id: ::WindowId(window.id()), event: window_event };
self.shared.pending_events.lock().unwrap().push_back(event);
Some(into_event(WindowEvent::CursorEntered { device_id: DEVICE_ID }))
},
appkit::NSMouseExited => { Some(into_event(WindowEvent::CursorLeft { device_id: DEVICE_ID })) },
appkit::NSMouseMoved |
appkit::NSLeftMouseDragged |
appkit::NSOtherMouseDragged |
appkit::NSRightMouseDragged => {
// If the mouse movement was on one of our windows, use it.
// Otherwise, if one of our windows is the key window (receiving input), use it.
// Otherwise, return `None`.
let window = match maybe_window.or_else(maybe_key_window) {
Some(window) => window,
None => return None,
};
let window_point = ns_event.locationInWindow();
let view_point = if ns_window == cocoa::base::nil {
let ns_size = foundation::NSSize::new(0.0, 0.0);
let ns_rect = foundation::NSRect::new(window_point, ns_size);
let window_rect = window.window.convertRectFromScreen_(ns_rect);
window.view.convertPoint_fromView_(window_rect.origin, cocoa::base::nil)
} else {
window.view.convertPoint_fromView_(window_point, cocoa::base::nil)
};
let view_rect = NSView::frame(*window.view);
let scale_factor = window.hidpi_factor();
let mut events = std::collections::VecDeque::new();
{
let x = (scale_factor * view_point.x as f32) as f64;
let y = (scale_factor * (view_rect.size.height - view_point.y) as f32) as f64;
let window_event = WindowEvent::CursorMoved { device_id: DEVICE_ID, position: (x, y), modifiers: event_mods(ns_event) };
let event = Event::WindowEvent { window_id: ::WindowId(window.id()), event: window_event };
events.push_back(event);
}
let delta_x = (scale_factor * ns_event.deltaX() as f32) as f64;
if delta_x != 0.0 {
let motion_event = DeviceEvent::Motion { axis: 0, value: delta_x };
let event = Event::DeviceEvent{ device_id: DEVICE_ID, event: motion_event };
events.push_back(event);
}
let delta_y = (scale_factor * ns_event.deltaY() as f32) as f64;
if delta_y != 0.0 {
let motion_event = DeviceEvent::Motion { axis: 1, value: delta_y };
let event = Event::DeviceEvent{ device_id: DEVICE_ID, event: motion_event };
events.push_back(event);
}
if delta_x != 0.0 || delta_y != 0.0 {
let motion_event = DeviceEvent::MouseMotion { delta: (delta_x, delta_y) };
let event = Event::DeviceEvent{ device_id: DEVICE_ID, event: motion_event };
events.push_back(event);
}
let event = events.pop_front();
self.shared.pending_events.lock().unwrap().extend(events.into_iter());
event
},
appkit::NSScrollWheel => {
// If none of the windows received the scroll, return `None`.
let window = match maybe_window {
Some(window) => window,
None => return None,
};
use events::MouseScrollDelta::{LineDelta, PixelDelta};
let scale_factor = window.hidpi_factor();
let delta = if ns_event.hasPreciseScrollingDeltas() == cocoa::base::YES {
PixelDelta(scale_factor * ns_event.scrollingDeltaX() as f32,
scale_factor * ns_event.scrollingDeltaY() as f32)
} else {
LineDelta(scale_factor * ns_event.scrollingDeltaX() as f32,
scale_factor * ns_event.scrollingDeltaY() as f32)
};
let phase = match ns_event.phase() {
NSEventPhase::NSEventPhaseMayBegin | NSEventPhase::NSEventPhaseBegan => TouchPhase::Started,
NSEventPhase::NSEventPhaseEnded => TouchPhase::Ended,
_ => TouchPhase::Moved,
};
self.shared.pending_events.lock().unwrap().push_back(Event::DeviceEvent {
device_id: DEVICE_ID,
event: DeviceEvent::MouseWheel {
delta: if ns_event.hasPreciseScrollingDeltas() == cocoa::base::YES {
PixelDelta(ns_event.scrollingDeltaX() as f32,
ns_event.scrollingDeltaY() as f32)
} else {
LineDelta(ns_event.scrollingDeltaX() as f32,
ns_event.scrollingDeltaY() as f32)
},
}
});
let window_event = WindowEvent::MouseWheel { device_id: DEVICE_ID, delta: delta, phase: phase, modifiers: event_mods(ns_event) };
Some(into_event(window_event))
},
appkit::NSEventTypePressure => {
let pressure = ns_event.pressure();
let stage = ns_event.stage();
let window_event = WindowEvent::TouchpadPressure { device_id: DEVICE_ID, pressure: pressure, stage: stage };
Some(into_event(window_event))
},
appkit::NSApplicationDefined => match ns_event.subtype() {
appkit::NSEventSubtype::NSApplicationActivatedEventType => {
Some(Event::Awakened)
},
_ => None,
},
_ => None,
}
}
pub fn create_proxy(&self) -> Proxy {
Proxy {}
}
}
impl Proxy {
pub fn wakeup(&self) -> Result<(), EventsLoopClosed> {
// Awaken the event loop by triggering `NSApplicationActivatedEventType`.
unsafe {
let pool = foundation::NSAutoreleasePool::new(cocoa::base::nil);
let event =
NSEvent::otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2_(
cocoa::base::nil,
appkit::NSApplicationDefined,
foundation::NSPoint::new(0.0, 0.0),
appkit::NSEventModifierFlags::empty(),
0.0,
0,
cocoa::base::nil,
appkit::NSEventSubtype::NSApplicationActivatedEventType,
0,
0);
appkit::NSApp().postEvent_atStart_(event, cocoa::base::NO);
foundation::NSAutoreleasePool::drain(pool);
}
Ok(())
}
}
fn to_virtual_key_code(code: u16) -> Option<events::VirtualKeyCode> {
Some(match code {
0x00 => events::VirtualKeyCode::A,
0x01 => events::VirtualKeyCode::S,
0x02 => events::VirtualKeyCode::D,
0x03 => events::VirtualKeyCode::F,
0x04 => events::VirtualKeyCode::H,
0x05 => events::VirtualKeyCode::G,
0x06 => events::VirtualKeyCode::Z,
0x07 => events::VirtualKeyCode::X,
0x08 => events::VirtualKeyCode::C,
0x09 => events::VirtualKeyCode::V,
//0x0a => World 1,
0x0b => events::VirtualKeyCode::B,
0x0c => events::VirtualKeyCode::Q,
0x0d => events::VirtualKeyCode::W,
0x0e => events::VirtualKeyCode::E,
0x0f => events::VirtualKeyCode::R,
0x10 => events::VirtualKeyCode::Y,
0x11 => events::VirtualKeyCode::T,
0x12 => events::VirtualKeyCode::Key1,
0x13 => events::VirtualKeyCode::Key2,
0x14 => events::VirtualKeyCode::Key3,
0x15 => events::VirtualKeyCode::Key4,
0x16 => events::VirtualKeyCode::Key6,
0x17 => events::VirtualKeyCode::Key5,
0x18 => events::VirtualKeyCode::Equals,
0x19 => events::VirtualKeyCode::Key9,
0x1a => events::VirtualKeyCode::Key7,
0x1b => events::VirtualKeyCode::Minus,
0x1c => events::VirtualKeyCode::Key8,
0x1d => events::VirtualKeyCode::Key0,
0x1e => events::VirtualKeyCode::RBracket,
0x1f => events::VirtualKeyCode::O,
0x20 => events::VirtualKeyCode::U,
0x21 => events::VirtualKeyCode::LBracket,
0x22 => events::VirtualKeyCode::I,
0x23 => events::VirtualKeyCode::P,
0x24 => events::VirtualKeyCode::Return,
0x25 => events::VirtualKeyCode::L,
0x26 => events::VirtualKeyCode::J,
0x27 => events::VirtualKeyCode::Apostrophe,
0x28 => events::VirtualKeyCode::K,
0x29 => events::VirtualKeyCode::Semicolon,
0x2a => events::VirtualKeyCode::Backslash,
0x2b => events::VirtualKeyCode::Comma,
0x2c => events::VirtualKeyCode::Slash,
0x2d => events::VirtualKeyCode::N,
0x2e => events::VirtualKeyCode::M,
0x2f => events::VirtualKeyCode::Period,
0x30 => events::VirtualKeyCode::Tab,
0x31 => events::VirtualKeyCode::Space,
0x32 => events::VirtualKeyCode::Grave,
0x33 => events::VirtualKeyCode::Back,
//0x34 => unkown,
0x35 => events::VirtualKeyCode::Escape,
0x36 => events::VirtualKeyCode::RWin,
0x37 => events::VirtualKeyCode::LWin,
0x38 => events::VirtualKeyCode::LShift,
//0x39 => Caps lock,
//0x3a => Left alt,
0x3b => events::VirtualKeyCode::LControl,
0x3c => events::VirtualKeyCode::RShift,
//0x3d => Right alt,
0x3e => events::VirtualKeyCode::RControl,
//0x3f => Fn key,
//0x40 => F17 Key,
0x41 => events::VirtualKeyCode::Decimal,
//0x42 -> unkown,
0x43 => events::VirtualKeyCode::Multiply,
//0x44 => unkown,
0x45 => events::VirtualKeyCode::Add,
//0x46 => unkown,
0x47 => events::VirtualKeyCode::Numlock,
//0x48 => KeypadClear,
0x49 => events::VirtualKeyCode::VolumeUp,
0x4a => events::VirtualKeyCode::VolumeDown,
0x4b => events::VirtualKeyCode::Divide,
0x4c => events::VirtualKeyCode::NumpadEnter,
//0x4d => unkown,
0x4e => events::VirtualKeyCode::Subtract,
//0x4f => F18 key,
//0x50 => F19 Key,
0x51 => events::VirtualKeyCode::NumpadEquals,
0x52 => events::VirtualKeyCode::Numpad0,
0x53 => events::VirtualKeyCode::Numpad1,
0x54 => events::VirtualKeyCode::Numpad2,
0x55 => events::VirtualKeyCode::Numpad3,
0x56 => events::VirtualKeyCode::Numpad4,
0x57 => events::VirtualKeyCode::Numpad5,
0x58 => events::VirtualKeyCode::Numpad6,
0x59 => events::VirtualKeyCode::Numpad7,
//0x5a => F20 Key,
0x5b => events::VirtualKeyCode::Numpad8,
0x5c => events::VirtualKeyCode::Numpad9,
//0x5d => unkown,
//0x5e => unkown,
//0x5f => unkown,
0x60 => events::VirtualKeyCode::F5,
0x61 => events::VirtualKeyCode::F6,
0x62 => events::VirtualKeyCode::F7,
0x63 => events::VirtualKeyCode::F3,
0x64 => events::VirtualKeyCode::F8,
0x65 => events::VirtualKeyCode::F9,
//0x66 => unkown,
0x67 => events::VirtualKeyCode::F11,
//0x68 => unkown,
0x69 => events::VirtualKeyCode::F13,
//0x6a => F16 Key,
0x6b => events::VirtualKeyCode::F14,
//0x6c => unkown,
0x6d => events::VirtualKeyCode::F10,
//0x6e => unkown,
0x6f => events::VirtualKeyCode::F12,
//0x70 => unkown,
0x71 => events::VirtualKeyCode::F15,
0x72 => events::VirtualKeyCode::Insert,
0x73 => events::VirtualKeyCode::Home,
0x74 => events::VirtualKeyCode::PageUp,
0x75 => events::VirtualKeyCode::Delete,
0x76 => events::VirtualKeyCode::F4,
0x77 => events::VirtualKeyCode::End,
0x78 => events::VirtualKeyCode::F2,
0x79 => events::VirtualKeyCode::PageDown,
0x7a => events::VirtualKeyCode::F1,
0x7b => events::VirtualKeyCode::Left,
0x7c => events::VirtualKeyCode::Right,
0x7d => events::VirtualKeyCode::Down,
0x7e => events::VirtualKeyCode::Up,
//0x7f => unkown,
0xa => events::VirtualKeyCode::Caret,
_ => return None,
})
}
fn event_mods(event: cocoa::base::id) -> ModifiersState {
let flags = unsafe {
NSEvent::modifierFlags(event)
};
ModifiersState {
shift: flags.contains(NSEventModifierFlags::NSShiftKeyMask),
ctrl: flags.contains(NSEventModifierFlags::NSControlKeyMask),
alt: flags.contains(NSEventModifierFlags::NSAlternateKeyMask),
logo: flags.contains(NSEventModifierFlags::NSCommandKeyMask),
}
}
// Constant device ID, to be removed when this backend is updated to report real device IDs.
const DEVICE_ID: ::DeviceId = ::DeviceId(DeviceId);

View File

@@ -1,42 +0,0 @@
#![cfg(target_os = "macos")]
pub use self::events_loop::{EventsLoop, Proxy as EventsLoopProxy};
pub use self::monitor::MonitorId;
pub use self::window::{Id as WindowId, PlatformSpecificWindowBuilderAttributes, Window2};
use std::sync::Arc;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeviceId;
use {CreationError};
pub struct Window {
pub window: Arc<Window2>,
}
impl ::std::ops::Deref for Window {
type Target = Window2;
#[inline]
fn deref(&self) -> &Window2 {
&*self.window
}
}
impl Window {
pub fn new(events_loop: &EventsLoop,
attributes: &::WindowAttributes,
pl_attribs: &PlatformSpecificWindowBuilderAttributes) -> Result<Self, CreationError>
{
let weak_shared = Arc::downgrade(&events_loop.shared);
let window = Arc::new(try!(Window2::new(weak_shared, attributes, pl_attribs)));
let weak_window = Arc::downgrade(&window);
events_loop.shared.windows.lock().unwrap().push(weak_window);
Ok(Window { window: window })
}
}
mod events_loop;
mod monitor;
mod window;

View File

@@ -1,94 +0,0 @@
use cocoa::appkit::NSScreen;
use cocoa::base::{id, nil};
use cocoa::foundation::{NSString, NSUInteger};
use core_graphics::display::{CGDirectDisplayID, CGDisplay};
use std::collections::VecDeque;
use super::EventsLoop;
use super::window::IdRef;
#[derive(Clone, PartialEq)]
pub struct MonitorId(CGDirectDisplayID);
impl EventsLoop {
pub fn get_available_monitors(&self) -> VecDeque<MonitorId> {
let mut monitors = VecDeque::new();
if let Ok(displays) = CGDisplay::active_displays() {
for d in displays {
monitors.push_back(MonitorId(d));
}
}
monitors
}
#[inline]
pub fn get_primary_monitor(&self) -> MonitorId {
let id = MonitorId(CGDisplay::main().id);
id
}
pub fn make_monitor_from_display(id: CGDirectDisplayID) -> MonitorId {
let id = MonitorId(id);
id
}
}
impl MonitorId {
pub fn get_name(&self) -> Option<String> {
let MonitorId(display_id) = *self;
let screen_num = CGDisplay::new(display_id).model_number();
Some(format!("Monitor #{}", screen_num))
}
#[inline]
pub fn get_native_identifier(&self) -> u32 {
self.0
}
pub fn get_dimensions(&self) -> (u32, u32) {
let MonitorId(display_id) = *self;
let display = CGDisplay::new(display_id);
let dimension = {
let height = display.pixels_high();
let width = display.pixels_wide();
(width as u32, height as u32)
};
dimension
}
#[inline]
pub fn get_position(&self) -> (i32, i32) {
unimplemented!()
}
pub fn get_hidpi_factor(&self) -> f32 {
let screen = match self.get_nsscreen() {
Some(screen) => screen,
None => return 1.0, // default to 1.0 when we can't find the screen
};
unsafe { NSScreen::backingScaleFactor(screen) as f32 }
}
pub(crate) fn get_nsscreen(&self) -> Option<id> {
unsafe {
let native_id = self.get_native_identifier();
let screens = NSScreen::screens(nil);
let count: NSUInteger = msg_send![screens, count];
let key = IdRef::new(NSString::alloc(nil).init_str("NSScreenNumber"));
let mut matching_screen: Option<id> = None;
for i in 0..count {
let screen = msg_send![screens, objectAtIndex: i as NSUInteger];
let device_description = NSScreen::deviceDescription(screen);
let value: id = msg_send![device_description, objectForKey:*key];
if value != nil {
let screen_number: NSUInteger = msg_send![value, unsignedIntegerValue];
if screen_number as u32 == native_id {
matching_screen = Some(screen);
break;
}
}
}
matching_screen
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,25 +1,25 @@
pub use self::platform::*;
//! 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(target_os = "windows")]
#[path="windows/mod.rs"]
mod platform;
#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
#[path="linux/mod.rs"]
mod platform;
#[cfg(target_os = "macos")]
#[path="macos/mod.rs"]
mod platform;
#[cfg(target_os = "android")]
#[path="android/mod.rs"]
mod platform;
#[cfg(target_os = "ios")]
#[path="ios/mod.rs"]
mod platform;
#[cfg(target_os = "emscripten")]
#[path="emscripten/mod.rs"]
mod platform;
pub mod android;
pub mod ios;
pub mod macos;
pub mod unix;
pub mod web;
pub mod windows;
#[cfg(all(not(target_os = "ios"), not(target_os = "windows"), not(target_os = "linux"),
not(target_os = "macos"), not(target_os = "android"), not(target_os = "dragonfly"),
not(target_os = "freebsd"), not(target_os = "openbsd"), not(target_os = "emscripten")))]
compile_error!("The platform you're compiling for is not supported by winit");
pub mod run_return;

View File

@@ -0,0 +1,64 @@
#![cfg(any(
target_os = "windows",
target_os = "macos",
target_os = "android",
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
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)
}
}

464
src/platform/unix.rs Normal file
View File

@@ -0,0 +1,464 @@
#![cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
use std::os::raw;
#[cfg(feature = "x11")]
use std::{ptr, sync::Arc};
use crate::{
event_loop::{EventLoopBuilder, EventLoopWindowTarget},
monitor::MonitorHandle,
window::{Window, WindowBuilder},
};
#[cfg(feature = "x11")]
use crate::dpi::Size;
#[cfg(feature = "x11")]
use crate::platform_impl::{x11::ffi::XVisualInfo, x11::XConnection, XLIB_ERROR_HOOKS};
use crate::platform_impl::{
ApplicationName, Backend, EventLoopWindowTarget as LinuxEventLoopWindowTarget,
Window as LinuxWindow,
};
// TODO: stupid hack so that glutin can do its work
#[doc(hidden)]
#[cfg(feature = "x11")]
pub use crate::platform_impl::x11;
#[cfg(feature = "x11")]
pub use crate::platform_impl::{x11::util::WindowType as XWindowType, XNotSupported};
#[cfg(feature = "wayland")]
pub use crate::window::Theme;
/// 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
#[cfg(feature = "x11")]
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`].
///
/// [`unsafe`]: https://www.remlab.net/op/xlib.shtml
#[inline]
#[cfg(feature = "x11")]
pub fn register_xlib_error_hook(hook: XlibErrorHook) {
// Append new hook.
unsafe {
XLIB_ERROR_HOOKS.lock().push(hook);
}
}
/// Additional methods on [`EventLoopWindowTarget`] that are specific to Unix.
pub trait EventLoopWindowTargetExtUnix {
/// True if the [`EventLoopWindowTarget`] uses Wayland.
#[cfg(feature = "wayland")]
fn is_wayland(&self) -> bool;
/// True if the [`EventLoopWindowTarget`] uses X11.
#[cfg(feature = "x11")]
fn is_x11(&self) -> bool;
#[doc(hidden)]
#[cfg(feature = "x11")]
fn xlib_xconnection(&self) -> Option<Arc<XConnection>>;
/// 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
#[cfg(feature = "wayland")]
fn wayland_display(&self) -> Option<*mut raw::c_void>;
}
impl<T> EventLoopWindowTargetExtUnix for EventLoopWindowTarget<T> {
#[inline]
#[cfg(feature = "wayland")]
fn is_wayland(&self) -> bool {
self.p.is_wayland()
}
#[inline]
#[cfg(feature = "x11")]
fn is_x11(&self) -> bool {
!self.p.is_wayland()
}
#[inline]
#[cfg(feature = "x11")]
fn xlib_xconnection(&self) -> Option<Arc<XConnection>> {
match self.p {
LinuxEventLoopWindowTarget::X(ref e) => Some(e.x_connection().clone()),
#[cfg(feature = "wayland")]
_ => None,
}
}
#[inline]
#[cfg(feature = "wayland")]
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(feature = "x11")]
_ => None,
}
}
}
/// Additional methods on [`EventLoopBuilder`] that are specific to Unix.
pub trait EventLoopBuilderExtUnix {
/// Force using X11.
#[cfg(feature = "x11")]
fn with_x11(&mut self) -> &mut Self;
/// Force using Wayland.
#[cfg(feature = "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> EventLoopBuilderExtUnix for EventLoopBuilder<T> {
#[inline]
#[cfg(feature = "x11")]
fn with_x11(&mut self) -> &mut Self {
self.platform_specific.forced_backend = Some(Backend::X);
self
}
#[inline]
#[cfg(feature = "wayland")]
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 Unix.
pub trait WindowExtUnix {
/// 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).
#[cfg(feature = "x11")]
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.
#[cfg(feature = "x11")]
fn xlib_display(&self) -> Option<*mut raw::c_void>;
#[cfg(feature = "x11")]
fn xlib_screen_id(&self) -> Option<raw::c_int>;
#[doc(hidden)]
#[cfg(feature = "x11")]
fn xlib_xconnection(&self) -> Option<Arc<XConnection>>;
/// 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.
#[cfg(feature = "x11")]
fn xcb_connection(&self) -> Option<*mut raw::c_void>;
/// 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.
#[cfg(feature = "wayland")]
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.
#[cfg(feature = "wayland")]
fn wayland_display(&self) -> Option<*mut raw::c_void>;
/// Updates [`Theme`] of window decorations.
///
/// You can also use `WINIT_WAYLAND_CSD_THEME` env variable to set the theme.
/// Possible values for env variable are: "dark" and light"
#[cfg(feature = "wayland")]
fn wayland_set_csd_theme(&self, config: Theme);
/// Check if the window is ready for drawing
///
/// It is a remnant of a previous implementation detail for the
/// wayland backend, and is no longer relevant.
///
/// Always return `true`.
#[deprecated]
fn is_ready(&self) -> bool;
}
impl WindowExtUnix for Window {
#[inline]
#[cfg(feature = "x11")]
fn xlib_window(&self) -> Option<raw::c_ulong> {
match self.window {
LinuxWindow::X(ref w) => Some(w.xlib_window()),
#[cfg(feature = "wayland")]
_ => None,
}
}
#[inline]
#[cfg(feature = "x11")]
fn xlib_display(&self) -> Option<*mut raw::c_void> {
match self.window {
LinuxWindow::X(ref w) => Some(w.xlib_display()),
#[cfg(feature = "wayland")]
_ => None,
}
}
#[inline]
#[cfg(feature = "x11")]
fn xlib_screen_id(&self) -> Option<raw::c_int> {
match self.window {
LinuxWindow::X(ref w) => Some(w.xlib_screen_id()),
#[cfg(feature = "wayland")]
_ => None,
}
}
#[inline]
#[cfg(feature = "x11")]
fn xlib_xconnection(&self) -> Option<Arc<XConnection>> {
match self.window {
LinuxWindow::X(ref w) => Some(w.xlib_xconnection()),
#[cfg(feature = "wayland")]
_ => None,
}
}
#[inline]
#[cfg(feature = "x11")]
fn xcb_connection(&self) -> Option<*mut raw::c_void> {
match self.window {
LinuxWindow::X(ref w) => Some(w.xcb_connection()),
#[cfg(feature = "wayland")]
_ => None,
}
}
#[inline]
#[cfg(feature = "wayland")]
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(feature = "x11")]
_ => None,
}
}
#[inline]
#[cfg(feature = "wayland")]
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(feature = "x11")]
_ => None,
}
}
#[inline]
#[cfg(feature = "wayland")]
fn wayland_set_csd_theme(&self, theme: Theme) {
#[allow(clippy::single_match)]
match self.window {
LinuxWindow::Wayland(ref w) => w.set_csd_theme(theme),
#[cfg(feature = "x11")]
_ => (),
}
}
#[inline]
fn is_ready(&self) -> bool {
true
}
}
/// Additional methods on [`WindowBuilder`] that are specific to Unix.
pub trait WindowBuilderExtUnix {
#[cfg(feature = "x11")]
fn with_x11_visual<T>(self, visual_infos: *const T) -> Self;
#[cfg(feature = "x11")]
fn with_x11_screen(self, screen_id: i32) -> Self;
/// Build window with the given `general` and `instance` names.
///
/// On Wayland, the `general` name sets an application ID, which should match the `.desktop`
/// file destributed with your program. The `instance` is a `no-op`.
///
/// On X11, 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.
#[cfg(feature = "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.
#[cfg(feature = "x11")]
fn with_x11_window_type(self, x11_window_type: Vec<XWindowType>) -> Self;
/// Build window with `_GTK_THEME_VARIANT` hint set to the specified value. Currently only relevant on X11.
#[cfg(feature = "x11")]
fn with_gtk_theme_variant(self, variant: String) -> Self;
/// Build window with certain decoration [`Theme`]
///
/// You can also use `WINIT_WAYLAND_CSD_THEME` env variable to set the theme.
/// Possible values for env variable are: "dark" and light"
#[cfg(feature = "wayland")]
fn with_wayland_csd_theme(self, theme: Theme) -> Self;
/// Build window with resize increment hint. Only implemented on X11.
///
/// ```
/// # use winit::dpi::{LogicalSize, PhysicalSize};
/// # use winit::window::WindowBuilder;
/// # use winit::platform::unix::WindowBuilderExtUnix;
/// // Specify the size in logical dimensions like this:
/// WindowBuilder::new().with_resize_increments(LogicalSize::new(400.0, 200.0));
///
/// // Or specify the size in physical dimensions like this:
/// WindowBuilder::new().with_resize_increments(PhysicalSize::new(400, 200));
/// ```
#[cfg(feature = "x11")]
fn with_resize_increments<S: Into<Size>>(self, increments: S) -> Self;
/// Build window with base size hint. Only implemented on X11.
///
/// ```
/// # use winit::dpi::{LogicalSize, PhysicalSize};
/// # use winit::window::WindowBuilder;
/// # use winit::platform::unix::WindowBuilderExtUnix;
/// // 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));
/// ```
#[cfg(feature = "x11")]
fn with_base_size<S: Into<Size>>(self, base_size: S) -> Self;
}
impl WindowBuilderExtUnix for WindowBuilder {
#[inline]
#[cfg(feature = "x11")]
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]
#[cfg(feature = "x11")]
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]
#[cfg(feature = "x11")]
fn with_override_redirect(mut self, override_redirect: bool) -> Self {
self.platform_specific.override_redirect = override_redirect;
self
}
#[inline]
#[cfg(feature = "x11")]
fn with_x11_window_type(mut self, x11_window_types: Vec<XWindowType>) -> Self {
self.platform_specific.x11_window_types = x11_window_types;
self
}
#[inline]
#[cfg(feature = "x11")]
fn with_gtk_theme_variant(mut self, variant: String) -> Self {
self.platform_specific.gtk_theme_variant = Some(variant);
self
}
#[inline]
#[cfg(feature = "wayland")]
fn with_wayland_csd_theme(mut self, theme: Theme) -> Self {
self.platform_specific.csd_theme = Some(theme);
self
}
#[inline]
#[cfg(feature = "x11")]
fn with_resize_increments<S: Into<Size>>(mut self, increments: S) -> Self {
self.platform_specific.resize_increments = Some(increments.into());
self
}
#[inline]
#[cfg(feature = "x11")]
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 Linux.
pub trait MonitorHandleExtUnix {
/// Returns the inner identifier of the monitor.
fn native_id(&self) -> u32;
}
impl MonitorHandleExtUnix for MonitorHandle {
#[inline]
fn native_id(&self) -> u32 {
self.inner.native_identifier()
}
}

91
src/platform/web.rs Normal file
View File

@@ -0,0 +1,91 @@
#![cfg(target_arch = "wasm32")]
//! 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)
}
}

355
src/platform/windows.rs Normal file
View File

@@ -0,0 +1,355 @@
#![cfg(target_os = "windows")]
use std::{ffi::c_void, path::Path};
use crate::{
dpi::PhysicalSize,
event::DeviceId,
event_loop::EventLoopBuilder,
monitor::MonitorHandle,
platform_impl::{Parent, WinIcon},
window::{BadIcon, Icon, Theme, 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>);
/// Returns the current window theme.
fn theme(&self) -> Theme;
/// Whether to show or hide the window icon in the taskbar.
fn set_skip_taskbar(&self, skip: 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 theme(&self) -> Theme {
self.window.theme()
}
#[inline]
fn set_skip_taskbar(&self, skip: bool) {
self.window.set_skip_taskbar(skip)
}
}
/// Additional methods on `WindowBuilder` that are specific to Windows.
pub trait WindowBuilderExtWindows {
/// Sets a parent to the window to be created.
///
/// A child window has the WS_CHILD style and is confined to the client area of its parent window.
///
/// For more information, see <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#child-windows>
fn with_parent_window(self, parent: HWND) -> WindowBuilder;
/// Set an owner to the window to be created. Can be used to create a dialog box, for example.
/// 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;
/// Forces a theme or uses the system settings if `None` was provided.
fn with_theme(self, theme: Option<Theme>) -> WindowBuilder;
/// Whether show or hide the window icon in the taskbar.
fn with_skip_taskbar(self, skip: bool) -> WindowBuilder;
}
impl WindowBuilderExtWindows for WindowBuilder {
#[inline]
fn with_parent_window(mut self, parent: HWND) -> WindowBuilder {
self.platform_specific.parent = Parent::ChildOf(parent);
self
}
#[inline]
fn with_owner_window(mut self, parent: HWND) -> WindowBuilder {
self.platform_specific.parent = Parent::OwnedBy(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_theme(mut self, theme: Option<Theme>) -> WindowBuilder {
self.platform_specific.preferred_theme = theme;
self
}
#[inline]
fn with_skip_taskbar(mut self, skip: bool) -> WindowBuilder {
self.platform_specific.skip_taskbar = skip;
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,232 +0,0 @@
use events::VirtualKeyCode;
use events::ModifiersState;
use winapi::shared::minwindef::{WPARAM, LPARAM};
use winapi::um::winuser;
use ScanCode;
use std::char;
const MAPVK_VK_TO_CHAR: u32 = 2;
const MAPVK_VSC_TO_VK_EX: u32 = 3;
pub fn get_key_mods() -> ModifiersState {
let mut mods = ModifiersState::default();
unsafe {
if winuser::GetKeyState(winuser::VK_SHIFT) & (1 << 15) == (1 << 15) {
mods.shift = true;
}
if winuser::GetKeyState(winuser::VK_CONTROL) & (1 << 15) == (1 << 15) {
mods.ctrl = true;
}
if winuser::GetKeyState(winuser::VK_MENU) & (1 << 15) == (1 << 15) {
mods.alt = true;
}
if (winuser::GetKeyState(winuser::VK_LWIN) | winuser::GetKeyState(winuser::VK_RWIN)) & (1 << 15) == (1 << 15) {
mods.logo = true;
}
}
mods
}
pub fn vkeycode_to_element(wparam: WPARAM, lparam: LPARAM) -> (ScanCode, Option<VirtualKeyCode>) {
let scancode = ((lparam >> 16) & 0xff) as u32;
let extended = (lparam & 0x01000000) != 0;
let vk = match wparam as i32 {
winuser::VK_SHIFT => unsafe { winuser::MapVirtualKeyA(scancode, MAPVK_VSC_TO_VK_EX) as i32 },
winuser::VK_CONTROL => if extended { winuser::VK_RCONTROL } else { winuser::VK_LCONTROL },
winuser::VK_MENU => if extended { winuser::VK_RMENU } else { winuser::VK_LMENU },
other => other
};
// VK_* codes are documented here https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
(scancode, match vk {
//winuser::VK_LBUTTON => Some(VirtualKeyCode::Lbutton),
//winuser::VK_RBUTTON => Some(VirtualKeyCode::Rbutton),
//winuser::VK_CANCEL => Some(VirtualKeyCode::Cancel),
//winuser::VK_MBUTTON => Some(VirtualKeyCode::Mbutton),
//winuser::VK_XBUTTON1 => Some(VirtualKeyCode::Xbutton1),
//winuser::VK_XBUTTON2 => Some(VirtualKeyCode::Xbutton2),
winuser::VK_BACK => Some(VirtualKeyCode::Back),
winuser::VK_TAB => Some(VirtualKeyCode::Tab),
//winuser::VK_CLEAR => Some(VirtualKeyCode::Clear),
winuser::VK_RETURN => Some(VirtualKeyCode::Return),
winuser::VK_LSHIFT => Some(VirtualKeyCode::LShift),
winuser::VK_RSHIFT => Some(VirtualKeyCode::RShift),
winuser::VK_LCONTROL => Some(VirtualKeyCode::LControl),
winuser::VK_RCONTROL => Some(VirtualKeyCode::RControl),
winuser::VK_LMENU => Some(VirtualKeyCode::LMenu),
winuser::VK_RMENU => Some(VirtualKeyCode::RMenu),
winuser::VK_PAUSE => Some(VirtualKeyCode::Pause),
winuser::VK_CAPITAL => Some(VirtualKeyCode::Capital),
winuser::VK_KANA => Some(VirtualKeyCode::Kana),
//winuser::VK_HANGUEL => Some(VirtualKeyCode::Hanguel),
//winuser::VK_HANGUL => Some(VirtualKeyCode::Hangul),
//winuser::VK_JUNJA => Some(VirtualKeyCode::Junja),
//winuser::VK_FINAL => Some(VirtualKeyCode::Final),
//winuser::VK_HANJA => Some(VirtualKeyCode::Hanja),
winuser::VK_KANJI => Some(VirtualKeyCode::Kanji),
winuser::VK_ESCAPE => Some(VirtualKeyCode::Escape),
winuser::VK_CONVERT => Some(VirtualKeyCode::Convert),
winuser::VK_NONCONVERT => Some(VirtualKeyCode::NoConvert),
//winuser::VK_ACCEPT => Some(VirtualKeyCode::Accept),
//winuser::VK_MODECHANGE => Some(VirtualKeyCode::Modechange),
winuser::VK_SPACE => Some(VirtualKeyCode::Space),
winuser::VK_PRIOR => Some(VirtualKeyCode::PageUp),
winuser::VK_NEXT => Some(VirtualKeyCode::PageDown),
winuser::VK_END => Some(VirtualKeyCode::End),
winuser::VK_HOME => Some(VirtualKeyCode::Home),
winuser::VK_LEFT => Some(VirtualKeyCode::Left),
winuser::VK_UP => Some(VirtualKeyCode::Up),
winuser::VK_RIGHT => Some(VirtualKeyCode::Right),
winuser::VK_DOWN => Some(VirtualKeyCode::Down),
//winuser::VK_SELECT => Some(VirtualKeyCode::Select),
//winuser::VK_PRINT => Some(VirtualKeyCode::Print),
//winuser::VK_EXECUTE => Some(VirtualKeyCode::Execute),
winuser::VK_SNAPSHOT => Some(VirtualKeyCode::Snapshot),
winuser::VK_INSERT => Some(VirtualKeyCode::Insert),
winuser::VK_DELETE => Some(VirtualKeyCode::Delete),
//winuser::VK_HELP => Some(VirtualKeyCode::Help),
0x30 => Some(VirtualKeyCode::Key0),
0x31 => Some(VirtualKeyCode::Key1),
0x32 => Some(VirtualKeyCode::Key2),
0x33 => Some(VirtualKeyCode::Key3),
0x34 => Some(VirtualKeyCode::Key4),
0x35 => Some(VirtualKeyCode::Key5),
0x36 => Some(VirtualKeyCode::Key6),
0x37 => Some(VirtualKeyCode::Key7),
0x38 => Some(VirtualKeyCode::Key8),
0x39 => Some(VirtualKeyCode::Key9),
0x41 => Some(VirtualKeyCode::A),
0x42 => Some(VirtualKeyCode::B),
0x43 => Some(VirtualKeyCode::C),
0x44 => Some(VirtualKeyCode::D),
0x45 => Some(VirtualKeyCode::E),
0x46 => Some(VirtualKeyCode::F),
0x47 => Some(VirtualKeyCode::G),
0x48 => Some(VirtualKeyCode::H),
0x49 => Some(VirtualKeyCode::I),
0x4A => Some(VirtualKeyCode::J),
0x4B => Some(VirtualKeyCode::K),
0x4C => Some(VirtualKeyCode::L),
0x4D => Some(VirtualKeyCode::M),
0x4E => Some(VirtualKeyCode::N),
0x4F => Some(VirtualKeyCode::O),
0x50 => Some(VirtualKeyCode::P),
0x51 => Some(VirtualKeyCode::Q),
0x52 => Some(VirtualKeyCode::R),
0x53 => Some(VirtualKeyCode::S),
0x54 => Some(VirtualKeyCode::T),
0x55 => Some(VirtualKeyCode::U),
0x56 => Some(VirtualKeyCode::V),
0x57 => Some(VirtualKeyCode::W),
0x58 => Some(VirtualKeyCode::X),
0x59 => Some(VirtualKeyCode::Y),
0x5A => Some(VirtualKeyCode::Z),
//winuser::VK_LWIN => Some(VirtualKeyCode::Lwin),
//winuser::VK_RWIN => Some(VirtualKeyCode::Rwin),
winuser::VK_APPS => Some(VirtualKeyCode::Apps),
winuser::VK_SLEEP => Some(VirtualKeyCode::Sleep),
winuser::VK_NUMPAD0 => Some(VirtualKeyCode::Numpad0),
winuser::VK_NUMPAD1 => Some(VirtualKeyCode::Numpad1),
winuser::VK_NUMPAD2 => Some(VirtualKeyCode::Numpad2),
winuser::VK_NUMPAD3 => Some(VirtualKeyCode::Numpad3),
winuser::VK_NUMPAD4 => Some(VirtualKeyCode::Numpad4),
winuser::VK_NUMPAD5 => Some(VirtualKeyCode::Numpad5),
winuser::VK_NUMPAD6 => Some(VirtualKeyCode::Numpad6),
winuser::VK_NUMPAD7 => Some(VirtualKeyCode::Numpad7),
winuser::VK_NUMPAD8 => Some(VirtualKeyCode::Numpad8),
winuser::VK_NUMPAD9 => Some(VirtualKeyCode::Numpad9),
winuser::VK_MULTIPLY => Some(VirtualKeyCode::Multiply),
winuser::VK_ADD => Some(VirtualKeyCode::Add),
//winuser::VK_SEPARATOR => Some(VirtualKeyCode::Separator),
winuser::VK_SUBTRACT => Some(VirtualKeyCode::Subtract),
winuser::VK_DECIMAL => Some(VirtualKeyCode::Decimal),
winuser::VK_DIVIDE => Some(VirtualKeyCode::Divide),
winuser::VK_F1 => Some(VirtualKeyCode::F1),
winuser::VK_F2 => Some(VirtualKeyCode::F2),
winuser::VK_F3 => Some(VirtualKeyCode::F3),
winuser::VK_F4 => Some(VirtualKeyCode::F4),
winuser::VK_F5 => Some(VirtualKeyCode::F5),
winuser::VK_F6 => Some(VirtualKeyCode::F6),
winuser::VK_F7 => Some(VirtualKeyCode::F7),
winuser::VK_F8 => Some(VirtualKeyCode::F8),
winuser::VK_F9 => Some(VirtualKeyCode::F9),
winuser::VK_F10 => Some(VirtualKeyCode::F10),
winuser::VK_F11 => Some(VirtualKeyCode::F11),
winuser::VK_F12 => Some(VirtualKeyCode::F12),
winuser::VK_F13 => Some(VirtualKeyCode::F13),
winuser::VK_F14 => Some(VirtualKeyCode::F14),
winuser::VK_F15 => Some(VirtualKeyCode::F15),
/*winuser::VK_F16 => Some(VirtualKeyCode::F16),
winuser::VK_F17 => Some(VirtualKeyCode::F17),
winuser::VK_F18 => Some(VirtualKeyCode::F18),
winuser::VK_F19 => Some(VirtualKeyCode::F19),
winuser::VK_F20 => Some(VirtualKeyCode::F20),
winuser::VK_F21 => Some(VirtualKeyCode::F21),
winuser::VK_F22 => Some(VirtualKeyCode::F22),
winuser::VK_F23 => Some(VirtualKeyCode::F23),
winuser::VK_F24 => Some(VirtualKeyCode::F24),*/
winuser::VK_NUMLOCK => Some(VirtualKeyCode::Numlock),
winuser::VK_SCROLL => Some(VirtualKeyCode::Scroll),
winuser::VK_BROWSER_BACK => Some(VirtualKeyCode::NavigateBackward),
winuser::VK_BROWSER_FORWARD => Some(VirtualKeyCode::NavigateForward),
winuser::VK_BROWSER_REFRESH => Some(VirtualKeyCode::WebRefresh),
winuser::VK_BROWSER_STOP => Some(VirtualKeyCode::WebStop),
winuser::VK_BROWSER_SEARCH => Some(VirtualKeyCode::WebSearch),
winuser::VK_BROWSER_FAVORITES => Some(VirtualKeyCode::WebFavorites),
winuser::VK_BROWSER_HOME => Some(VirtualKeyCode::WebHome),
winuser::VK_VOLUME_MUTE => Some(VirtualKeyCode::Mute),
winuser::VK_VOLUME_DOWN => Some(VirtualKeyCode::VolumeDown),
winuser::VK_VOLUME_UP => Some(VirtualKeyCode::VolumeUp),
winuser::VK_MEDIA_NEXT_TRACK => Some(VirtualKeyCode::NextTrack),
winuser::VK_MEDIA_PREV_TRACK => Some(VirtualKeyCode::PrevTrack),
winuser::VK_MEDIA_STOP => Some(VirtualKeyCode::MediaStop),
winuser::VK_MEDIA_PLAY_PAUSE => Some(VirtualKeyCode::PlayPause),
winuser::VK_LAUNCH_MAIL => Some(VirtualKeyCode::Mail),
winuser::VK_LAUNCH_MEDIA_SELECT => Some(VirtualKeyCode::MediaSelect),
/*winuser::VK_LAUNCH_APP1 => Some(VirtualKeyCode::Launch_app1),
winuser::VK_LAUNCH_APP2 => Some(VirtualKeyCode::Launch_app2),*/
winuser::VK_OEM_PLUS => Some(VirtualKeyCode::Equals),
winuser::VK_OEM_COMMA => Some(VirtualKeyCode::Comma),
winuser::VK_OEM_MINUS => Some(VirtualKeyCode::Minus),
winuser::VK_OEM_PERIOD => Some(VirtualKeyCode::Period),
winuser::VK_OEM_1 => map_text_keys(vk),
winuser::VK_OEM_2 => map_text_keys(vk),
winuser::VK_OEM_3 => map_text_keys(vk),
winuser::VK_OEM_4 => map_text_keys(vk),
winuser::VK_OEM_5 => map_text_keys(vk),
winuser::VK_OEM_6 => map_text_keys(vk),
winuser::VK_OEM_7 => map_text_keys(vk),
/*winuser::VK_OEM_8 => Some(VirtualKeyCode::Oem_8), */
winuser::VK_OEM_102 => Some(VirtualKeyCode::OEM102),
/*winuser::VK_PROCESSKEY => Some(VirtualKeyCode::Processkey),
winuser::VK_PACKET => Some(VirtualKeyCode::Packet),
winuser::VK_ATTN => Some(VirtualKeyCode::Attn),
winuser::VK_CRSEL => Some(VirtualKeyCode::Crsel),
winuser::VK_EXSEL => Some(VirtualKeyCode::Exsel),
winuser::VK_EREOF => Some(VirtualKeyCode::Ereof),
winuser::VK_PLAY => Some(VirtualKeyCode::Play),
winuser::VK_ZOOM => Some(VirtualKeyCode::Zoom),
winuser::VK_NONAME => Some(VirtualKeyCode::Noname),
winuser::VK_PA1 => Some(VirtualKeyCode::Pa1),
winuser::VK_OEM_CLEAR => Some(VirtualKeyCode::Oem_clear),*/
_ => None
})
}
// This is needed as windows doesn't properly distinguish
// some virtual key codes for different keyboard layouts
fn map_text_keys(win_virtual_key: i32) -> Option<VirtualKeyCode> {
let char_key = unsafe { winuser::MapVirtualKeyA(win_virtual_key as u32, MAPVK_VK_TO_CHAR) } & 0x7FFF;
match char::from_u32(char_key) {
Some(';') => Some(VirtualKeyCode::Semicolon),
Some('/') => Some(VirtualKeyCode::Slash),
Some('`') => Some(VirtualKeyCode::Grave),
Some('[') => Some(VirtualKeyCode::LBracket),
Some(']') => Some(VirtualKeyCode::RBracket),
Some('\'') => Some(VirtualKeyCode::Apostrophe),
Some('\\') => Some(VirtualKeyCode::Backslash),
_ => None
}
}

View File

@@ -1,949 +0,0 @@
//! An events loop on Win32 is a background thread.
//!
//! Creating an events loop spawns a thread and blocks it in a permanent Win32 events loop.
//! Destroying the events loop stops the thread.
//!
//! You can use the `execute_in_thread` method to execute some code in the background thread.
//! Since Win32 requires you to create a window in the right thread, you must use this method
//! to create a window.
//!
//! If you create a window whose class is set to `callback`, the window's events will be
//! propagated with `run_forever` and `poll_events`.
//! The closure passed to the `execute_in_thread` method takes an `Inserter` that you can use to
//! add a `WindowState` entry to a list of window to be used by the callback.
use std::cell::RefCell;
use std::collections::HashMap;
use std::ffi::OsString;
use std::mem;
use std::os::windows::ffi::OsStringExt;
use std::os::windows::io::AsRawHandle;
use std::ptr;
use std::sync::mpsc;
use std::sync::Arc;
use std::sync::Barrier;
use std::sync::Mutex;
use std::sync::Condvar;
use std::thread;
use winapi::shared::minwindef::{LOWORD, HIWORD, DWORD, WPARAM, LPARAM, INT, UINT, LRESULT, MAX_PATH};
use winapi::shared::windef::{HWND, POINT, RECT};
use winapi::shared::windowsx;
use winapi::um::{winuser, shellapi, processthreadsapi};
use winapi::um::winnt::LONG;
use platform::platform::event;
use platform::platform::window::adjust_size;
use platform::platform::Cursor;
use platform::platform::WindowId;
use platform::platform::DEVICE_ID;
use ControlFlow;
use CursorState;
use Event;
use EventsLoopClosed;
use KeyboardInput;
use WindowAttributes;
use WindowEvent;
use WindowId as SuperWindowId;
use events::{Touch, TouchPhase};
/// Contains saved window info for switching between fullscreen
#[derive(Clone)]
pub struct SavedWindowInfo {
/// Window style
pub style: LONG,
/// Window ex-style
pub ex_style: LONG,
/// Window position and size
pub rect: RECT,
}
/// Contains information about states and the window that the callback is going to use.
#[derive(Clone)]
pub struct WindowState {
/// Cursor to set at the next `WM_SETCURSOR` event received.
pub cursor: Cursor,
/// Cursor state to set at the next `WM_SETCURSOR` event received.
pub cursor_state: CursorState,
/// Used by `WM_GETMINMAXINFO`.
pub attributes: WindowAttributes,
/// Will contain `true` if the mouse is hovering the window.
pub mouse_in_window: bool,
/// Saved window info for fullscreen restored
pub saved_window_info: Option<SavedWindowInfo>,
}
/// Dummy object that allows inserting a window's state.
// We store a pointer in order to !impl Send and Sync.
pub struct Inserter(*mut u8);
impl Inserter {
/// Inserts a window's state for the callback to use. The state is removed automatically if the
/// callback receives a `WM_CLOSE` message for the window.
pub fn insert(&self, window: HWND, state: Arc<Mutex<WindowState>>) {
CONTEXT_STASH.with(|context_stash| {
let mut context_stash = context_stash.borrow_mut();
let was_in = context_stash.as_mut().unwrap().windows.insert(window, state);
assert!(was_in.is_none());
});
}
}
pub struct EventsLoop {
// Id of the background thread from the Win32 API.
thread_id: DWORD,
// Receiver for the events. The sender is in the background thread.
receiver: mpsc::Receiver<Event>,
// Variable that contains the block state of the win32 event loop thread during a WM_SIZE event.
// The mutex's value is `true` when it's blocked, and should be set to false when it's done
// blocking. That's done by the parent thread when it receives a Resized event.
win32_block_loop: Arc<(Mutex<bool>, Condvar)>
}
impl EventsLoop {
pub fn new() -> EventsLoop {
// The main events transfer channel.
let (tx, rx) = mpsc::channel();
let win32_block_loop = Arc::new((Mutex::new(false), Condvar::new()));
let win32_block_loop_child = win32_block_loop.clone();
// Local barrier in order to block the `new()` function until the background thread has
// an events queue.
let barrier = Arc::new(Barrier::new(2));
let barrier_clone = barrier.clone();
let thread = thread::spawn(move || {
CONTEXT_STASH.with(|context_stash| {
*context_stash.borrow_mut() = Some(ThreadLocalData {
sender: tx,
windows: HashMap::with_capacity(4),
win32_block_loop: win32_block_loop_child,
mouse_buttons_down: 0
});
});
unsafe {
// Calling `PostThreadMessageA` on a thread that does not have an events queue yet
// will fail. In order to avoid this situation, we call `IsGuiThread` to initialize
// it.
winuser::IsGUIThread(1);
// Then only we unblock the `new()` function. We are sure that we don't call
// `PostThreadMessageA()` before `new()` returns.
barrier_clone.wait();
drop(barrier_clone);
let mut msg = mem::uninitialized();
loop {
if winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) == 0 {
// Only happens if the message is `WM_QUIT`.
debug_assert_eq!(msg.message, winuser::WM_QUIT);
break;
}
match msg.message {
x if x == *EXEC_MSG_ID => {
let mut function: Box<Box<FnMut(Inserter)>> = Box::from_raw(msg.wParam as usize as *mut _);
function(Inserter(ptr::null_mut()));
},
x if x == *WAKEUP_MSG_ID => {
send_event(Event::Awakened);
},
_ => {
// Calls `callback` below.
winuser::TranslateMessage(&msg);
winuser::DispatchMessageW(&msg);
}
}
}
}
});
// Blocks this function until the background thread has an events loop. See other comments.
barrier.wait();
let thread_id = unsafe {
let handle = mem::transmute(thread.as_raw_handle());
processthreadsapi::GetThreadId(handle)
};
EventsLoop {
thread_id,
receiver: rx,
win32_block_loop
}
}
pub fn poll_events<F>(&mut self, mut callback: F)
where F: FnMut(Event)
{
loop {
let event = match self.receiver.try_recv() {
Ok(e) => e,
Err(_) => return
};
let is_resize = match event {
Event::WindowEvent{ event: WindowEvent::Resized(..), .. } => true,
_ => false
};
callback(event);
if is_resize {
let (ref mutex, ref cvar) = *self.win32_block_loop;
let mut block_thread = mutex.lock().unwrap();
*block_thread = false;
cvar.notify_all();
}
}
}
pub fn run_forever<F>(&mut self, mut callback: F)
where F: FnMut(Event) -> ControlFlow
{
loop {
let event = match self.receiver.recv() {
Ok(e) => e,
Err(_) => return
};
let is_resize = match event {
Event::WindowEvent{ event: WindowEvent::Resized(..), .. } => true,
_ => false
};
let flow = callback(event);
if is_resize {
let (ref mutex, ref cvar) = *self.win32_block_loop;
let mut block_thread = mutex.lock().unwrap();
*block_thread = false;
cvar.notify_all();
}
match flow {
ControlFlow::Continue => continue,
ControlFlow::Break => break,
}
}
}
pub fn create_proxy(&self) -> EventsLoopProxy {
EventsLoopProxy {
thread_id: self.thread_id,
}
}
/// Executes a function in the background thread.
///
/// Note that we use a FnMut instead of a FnOnce because we're too lazy to create an equivalent
/// to the unstable FnBox.
///
/// The `Inserted` can be used to inject a `WindowState` for the callback to use. The state is
/// removed automatically if the callback receives a `WM_CLOSE` message for the window.
pub(super) fn execute_in_thread<F>(&self, function: F)
where F: FnMut(Inserter) + Send + 'static
{
self.create_proxy().execute_in_thread(function)
}
}
impl Drop for EventsLoop {
fn drop(&mut self) {
unsafe {
// Posting `WM_QUIT` will cause `GetMessage` to stop.
winuser::PostThreadMessageA(self.thread_id, winuser::WM_QUIT, 0, 0);
}
}
}
#[derive(Clone)]
pub struct EventsLoopProxy {
thread_id: DWORD,
}
impl EventsLoopProxy {
pub fn wakeup(&self) -> Result<(), EventsLoopClosed> {
unsafe {
if winuser::PostThreadMessageA(self.thread_id, *WAKEUP_MSG_ID, 0, 0) != 0 {
Ok(())
} else {
// https://msdn.microsoft.com/fr-fr/library/windows/desktop/ms644946(v=vs.85).aspx
// > If the function fails, the return value is zero. To get extended error
// > information, call GetLastError. GetLastError returns ERROR_INVALID_THREAD_ID
// > if idThread is not a valid thread identifier, or if the thread specified by
// > idThread does not have a message queue. GetLastError returns
// > ERROR_NOT_ENOUGH_QUOTA when the message limit is hit.
// TODO: handle ERROR_NOT_ENOUGH_QUOTA
Err(EventsLoopClosed)
}
}
}
/// Executes a function in the background thread.
///
/// Note that we use a FnMut instead of a FnOnce because we're too lazy to create an equivalent
/// to the unstable FnBox.
///
/// The `Inserted` can be used to inject a `WindowState` for the callback to use. The state is
/// removed automatically if the callback receives a `WM_CLOSE` message for the window.
pub fn execute_in_thread<F>(&self, function: F)
where
F: FnMut(Inserter) + Send + 'static,
{
unsafe {
// We are using double-boxing here because it make casting back much easier
let boxed = Box::new(function) as Box<FnMut(_)>;
let boxed2 = Box::new(boxed);
let raw = Box::into_raw(boxed2);
let res = winuser::PostThreadMessageA(
self.thread_id,
*EXEC_MSG_ID,
raw as *mut () as usize as WPARAM,
0,
);
// PostThreadMessage can only fail if the thread ID is invalid (which shouldn't happen
// as the events loop is still alive) or if the queue is full.
assert!(
res != 0,
"PostThreadMessage failed ; is the messages queue full?"
);
}
}
}
lazy_static! {
// Message sent by the `EventsLoopProxy` when we want to wake up the thread.
// WPARAM and LPARAM are unused.
static ref WAKEUP_MSG_ID: u32 = {
unsafe {
winuser::RegisterWindowMessageA("Winit::WakeupMsg\0".as_ptr() as *const i8)
}
};
// Message sent when we want to execute a closure in the thread.
// WPARAM contains a Box<Box<FnMut()>> that must be retreived with `Box::from_raw`,
// and LPARAM is unused.
static ref EXEC_MSG_ID: u32 = {
unsafe {
winuser::RegisterWindowMessageA("Winit::ExecMsg\0".as_ptr() as *const i8)
}
};
// Message sent by a `Window` when it wants to be destroyed by the main thread.
// WPARAM and LPARAM are unused.
pub static ref DESTROY_MSG_ID: u32 = {
unsafe {
winuser::RegisterWindowMessageA("Winit::DestroyMsg\0".as_ptr() as *const i8)
}
};
}
// There's no parameters passed to the callback function, so it needs to get its context stashed
// in a thread-local variable.
thread_local!(static CONTEXT_STASH: RefCell<Option<ThreadLocalData>> = RefCell::new(None));
struct ThreadLocalData {
sender: mpsc::Sender<Event>,
windows: HashMap<HWND, Arc<Mutex<WindowState>>>,
win32_block_loop: Arc<(Mutex<bool>, Condvar)>,
mouse_buttons_down: u32
}
// Utility function that dispatches an event on the current thread.
fn send_event(event: Event) {
CONTEXT_STASH.with(|context_stash| {
let context_stash = context_stash.borrow();
let _ = context_stash.as_ref().unwrap().sender.send(event); // Ignoring if closed
});
}
/// Capture mouse input, allowing `window` to receive mouse events when the cursor is outside of
/// the window.
unsafe fn capture_mouse(window: HWND) {
CONTEXT_STASH.with(|context_stash| {
let mut context_stash = context_stash.borrow_mut();
if let Some(context_stash) = context_stash.as_mut() {
context_stash.mouse_buttons_down += 1;
winuser::SetCapture(window);
}
});
}
/// Release mouse input, stopping windows on this thread from receiving mouse input when the cursor
/// is outside the window.
unsafe fn release_mouse() {
CONTEXT_STASH.with(|context_stash| {
let mut context_stash = context_stash.borrow_mut();
if let Some(context_stash) = context_stash.as_mut() {
context_stash.mouse_buttons_down = context_stash.mouse_buttons_down.saturating_sub(1);
if context_stash.mouse_buttons_down == 0 {
winuser::ReleaseCapture();
}
}
});
}
/// Any window whose callback is configured to this function will have its events propagated
/// through the events loop of the thread the window was created in.
//
// This is the callback that is called by `DispatchMessage` in the events loop.
//
// Returning 0 tells the Win32 API that the message has been processed.
// FIXME: detect WM_DWMCOMPOSITIONCHANGED and call DwmEnableBlurBehindWindow if necessary
pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
wparam: WPARAM, lparam: LPARAM)
-> LRESULT
{
match msg {
winuser::WM_CLOSE => {
use events::WindowEvent::CloseRequested;
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: CloseRequested
});
0
},
winuser::WM_DESTROY => {
use events::WindowEvent::Destroyed;
CONTEXT_STASH.with(|context_stash| {
let mut context_stash = context_stash.borrow_mut();
context_stash.as_mut().unwrap().windows.remove(&window);
});
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: Destroyed
});
0
},
winuser::WM_PAINT => {
use events::WindowEvent::Refresh;
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: Refresh,
});
winuser::DefWindowProcW(window, msg, wparam, lparam)
},
winuser::WM_SIZE => {
use events::WindowEvent::Resized;
let w = LOWORD(lparam as DWORD) as u32;
let h = HIWORD(lparam as DWORD) as u32;
// Wait for the parent thread to process the resize event before returning from the
// callback.
CONTEXT_STASH.with(|context_stash| {
let mut context_stash = context_stash.borrow_mut();
let cstash = context_stash.as_mut().unwrap();
let event = Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: Resized(w, h),
};
// If this window has been inserted into the window map, the resize event happened
// during the event loop. If it hasn't, the event happened on window creation and
// should be ignored.
if cstash.windows.get(&window).is_some() {
let (ref mutex, ref cvar) = *cstash.win32_block_loop;
let mut block_thread = mutex.lock().unwrap();
*block_thread = true;
// The event needs to be sent after the lock to ensure that `notify_all` is
// called after `wait`.
cstash.sender.send(event).ok();
while *block_thread {
block_thread = cvar.wait(block_thread).unwrap();
}
} else {
cstash.sender.send(event).ok();
}
});
0
},
winuser::WM_MOVE => {
use events::WindowEvent::Moved;
let x = LOWORD(lparam as DWORD) as i32;
let y = HIWORD(lparam as DWORD) as i32;
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: Moved(x, y),
});
0
},
winuser::WM_CHAR => {
use std::mem;
use events::WindowEvent::ReceivedCharacter;
let chr: char = mem::transmute(wparam as u32);
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: ReceivedCharacter(chr),
});
0
},
// Prevents default windows menu hotkeys playing unwanted
// "ding" sounds. Alternatively could check for WM_SYSCOMMAND
// with wparam being SC_KEYMENU, but this may prevent some
// other unwanted default hotkeys as well.
winuser::WM_SYSCHAR => {
0
}
winuser::WM_MOUSEMOVE => {
use events::WindowEvent::{CursorEntered, CursorMoved};
let mouse_outside_window = CONTEXT_STASH.with(|context_stash| {
let mut context_stash = context_stash.borrow_mut();
if let Some(context_stash) = context_stash.as_mut() {
if let Some(w) = context_stash.windows.get_mut(&window) {
let mut w = w.lock().unwrap();
if !w.mouse_in_window {
w.mouse_in_window = true;
return true;
}
}
}
false
});
if mouse_outside_window {
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: CursorEntered { device_id: DEVICE_ID },
});
// Calling TrackMouseEvent in order to receive mouse leave events.
winuser::TrackMouseEvent(&mut winuser::TRACKMOUSEEVENT {
cbSize: mem::size_of::<winuser::TRACKMOUSEEVENT>() as DWORD,
dwFlags: winuser::TME_LEAVE,
hwndTrack: window,
dwHoverTime: winuser::HOVER_DEFAULT,
});
}
let x = windowsx::GET_X_LPARAM(lparam) as f64;
let y = windowsx::GET_Y_LPARAM(lparam) as f64;
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: CursorMoved { device_id: DEVICE_ID, position: (x, y), modifiers: event::get_key_mods() },
});
0
},
winuser::WM_MOUSELEAVE => {
use events::WindowEvent::CursorLeft;
let mouse_in_window = CONTEXT_STASH.with(|context_stash| {
let mut context_stash = context_stash.borrow_mut();
if let Some(context_stash) = context_stash.as_mut() {
if let Some(w) = context_stash.windows.get_mut(&window) {
let mut w = w.lock().unwrap();
if w.mouse_in_window {
w.mouse_in_window = false;
return true;
}
}
}
false
});
if mouse_in_window {
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: CursorLeft { device_id: DEVICE_ID }
});
}
0
},
winuser::WM_MOUSEWHEEL => {
use events::{DeviceEvent, WindowEvent};
use events::MouseScrollDelta::LineDelta;
use events::TouchPhase;
let value = (wparam >> 16) as i16;
let value = value as i32;
let value = value as f32 / winuser::WHEEL_DELTA as f32;
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: WindowEvent::MouseWheel { device_id: DEVICE_ID, delta: LineDelta(0.0, value), phase: TouchPhase::Moved, modifiers: event::get_key_mods() },
});
send_event(Event::DeviceEvent {
device_id: DEVICE_ID,
event: DeviceEvent::MouseWheel { delta: LineDelta(0.0, value) },
});
0
},
winuser::WM_KEYDOWN | winuser::WM_SYSKEYDOWN => {
use events::ElementState::Pressed;
use events::VirtualKeyCode;
if msg == winuser::WM_SYSKEYDOWN && wparam as i32 == winuser::VK_F4 {
winuser::DefWindowProcW(window, msg, wparam, lparam)
} else {
let (scancode, vkey) = event::vkeycode_to_element(wparam, lparam);
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: WindowEvent::KeyboardInput {
device_id: DEVICE_ID,
input: KeyboardInput {
state: Pressed,
scancode: scancode,
virtual_keycode: vkey,
modifiers: event::get_key_mods(),
}
}
});
// Windows doesn't emit a delete character by default, but in order to make it
// consistent with the other platforms we'll emit a delete character here.
if vkey == Some(VirtualKeyCode::Delete) {
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: WindowEvent::ReceivedCharacter('\u{7F}'),
});
}
0
}
},
winuser::WM_KEYUP | winuser::WM_SYSKEYUP => {
use events::ElementState::Released;
let (scancode, vkey) = event::vkeycode_to_element(wparam, lparam);
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: WindowEvent::KeyboardInput {
device_id: DEVICE_ID,
input: KeyboardInput {
state: Released,
scancode: scancode,
virtual_keycode: vkey,
modifiers: event::get_key_mods(),
},
}
});
0
},
winuser::WM_LBUTTONDOWN => {
use events::WindowEvent::MouseInput;
use events::MouseButton::Left;
use events::ElementState::Pressed;
capture_mouse(window);
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Left, modifiers: event::get_key_mods() }
});
0
},
winuser::WM_LBUTTONUP => {
use events::WindowEvent::MouseInput;
use events::MouseButton::Left;
use events::ElementState::Released;
release_mouse();
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Left, modifiers: event::get_key_mods() }
});
0
},
winuser::WM_RBUTTONDOWN => {
use events::WindowEvent::MouseInput;
use events::MouseButton::Right;
use events::ElementState::Pressed;
capture_mouse(window);
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Right, modifiers: event::get_key_mods() }
});
0
},
winuser::WM_RBUTTONUP => {
use events::WindowEvent::MouseInput;
use events::MouseButton::Right;
use events::ElementState::Released;
release_mouse();
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Right, modifiers: event::get_key_mods() }
});
0
},
winuser::WM_MBUTTONDOWN => {
use events::WindowEvent::MouseInput;
use events::MouseButton::Middle;
use events::ElementState::Pressed;
capture_mouse(window);
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Middle, modifiers: event::get_key_mods() }
});
0
},
winuser::WM_MBUTTONUP => {
use events::WindowEvent::MouseInput;
use events::MouseButton::Middle;
use events::ElementState::Released;
release_mouse();
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Middle, modifiers: event::get_key_mods() }
});
0
},
winuser::WM_XBUTTONDOWN => {
use events::WindowEvent::MouseInput;
use events::MouseButton::Other;
use events::ElementState::Pressed;
let xbutton = winuser::GET_XBUTTON_WPARAM(wparam);
capture_mouse(window);
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Other(xbutton as u8), modifiers: event::get_key_mods() }
});
0
},
winuser::WM_XBUTTONUP => {
use events::WindowEvent::MouseInput;
use events::MouseButton::Other;
use events::ElementState::Released;
let xbutton = winuser::GET_XBUTTON_WPARAM(wparam);
release_mouse();
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Other(xbutton as u8), modifiers: event::get_key_mods() }
});
0
},
winuser::WM_INPUT => {
use events::DeviceEvent::{Motion, MouseMotion};
let mut data: winuser::RAWINPUT = mem::uninitialized();
let mut data_size = mem::size_of::<winuser::RAWINPUT>() as UINT;
winuser::GetRawInputData(mem::transmute(lparam), winuser::RID_INPUT,
mem::transmute(&mut data), &mut data_size,
mem::size_of::<winuser::RAWINPUTHEADER>() as UINT);
if data.header.dwType == winuser::RIM_TYPEMOUSE {
let mouse = data.data.mouse();
if mouse.usFlags & winuser::MOUSE_MOVE_RELATIVE == winuser::MOUSE_MOVE_RELATIVE {
let x = mouse.lLastX as f64;
let y = mouse.lLastY as f64;
if x != 0.0 {
send_event(Event::DeviceEvent {
device_id: DEVICE_ID,
event: Motion { axis: 0, value: x }
});
}
if y != 0.0 {
send_event(Event::DeviceEvent {
device_id: DEVICE_ID,
event: Motion { axis: 1, value: y }
});
}
if x != 0.0 || y != 0.0 {
send_event(Event::DeviceEvent {
device_id: DEVICE_ID,
event: MouseMotion { delta: (x, y) }
});
}
}
0
} else {
winuser::DefWindowProcW(window, msg, wparam, lparam)
}
},
winuser::WM_TOUCH => {
let pcount = LOWORD( wparam as DWORD ) as usize;
let mut inputs = Vec::with_capacity( pcount );
inputs.set_len( pcount );
let htouch = lparam as winuser::HTOUCHINPUT;
if winuser::GetTouchInputInfo( htouch, pcount as UINT,
inputs.as_mut_ptr(),
mem::size_of::<winuser::TOUCHINPUT>() as INT ) > 0 {
for input in &inputs {
send_event( Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: WindowEvent::Touch(Touch {
phase:
if input.dwFlags & winuser::TOUCHEVENTF_DOWN != 0 {
TouchPhase::Started
} else if input.dwFlags & winuser::TOUCHEVENTF_UP != 0 {
TouchPhase::Ended
} else if input.dwFlags & winuser::TOUCHEVENTF_MOVE != 0 {
TouchPhase::Moved
} else {
continue;
},
location: ((input.x as f64) / 100f64,
(input.y as f64) / 100f64),
id: input.dwID as u64,
device_id: DEVICE_ID,
})
});
}
}
winuser::CloseTouchInputHandle( htouch );
0
}
winuser::WM_SETFOCUS => {
use events::WindowEvent::{Focused, CursorMoved};
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: Focused(true)
});
let x = windowsx::GET_X_LPARAM(lparam) as f64;
let y = windowsx::GET_Y_LPARAM(lparam) as f64;
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: CursorMoved { device_id: DEVICE_ID, position: (x, y), modifiers: event::get_key_mods() },
});
0
},
winuser::WM_KILLFOCUS => {
use events::WindowEvent::Focused;
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: Focused(false)
});
0
},
winuser::WM_SETCURSOR => {
let call_def_window_proc = CONTEXT_STASH.with(|context_stash| {
let cstash = context_stash.borrow();
let mut call_def_window_proc = false;
if let Some(cstash) = cstash.as_ref() {
if let Some(w_stash) = cstash.windows.get(&window) {
if let Ok(window_state) = w_stash.lock() {
if window_state.mouse_in_window {
match window_state.cursor_state {
CursorState::Normal => {
winuser::SetCursor(winuser::LoadCursorW(
ptr::null_mut(),
window_state.cursor));
},
CursorState::Grab | CursorState::Hide => {
winuser::SetCursor(ptr::null_mut());
}
}
} else {
call_def_window_proc = true;
}
}
}
}
call_def_window_proc
});
if call_def_window_proc {
winuser::DefWindowProcW(window, msg, wparam, lparam)
} else {
0
}
},
winuser::WM_DROPFILES => {
use events::WindowEvent::DroppedFile;
let hdrop = wparam as shellapi::HDROP;
let mut pathbuf: [u16; MAX_PATH] = mem::uninitialized();
let num_drops = shellapi::DragQueryFileW(hdrop, 0xFFFFFFFF, ptr::null_mut(), 0);
for i in 0..num_drops {
let nch = shellapi::DragQueryFileW(hdrop, i, pathbuf.as_mut_ptr(),
MAX_PATH as u32) as usize;
if nch > 0 {
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: DroppedFile(OsString::from_wide(&pathbuf[0..nch]).into())
});
}
}
shellapi::DragFinish(hdrop);
0
},
winuser::WM_GETMINMAXINFO => {
let mmi = lparam as *mut winuser::MINMAXINFO;
//(*mmi).max_position = winapi::shared::windef::POINT { x: -8, y: -8 }; // The upper left corner of the window if it were maximized on the primary monitor.
//(*mmi).max_size = winapi::shared::windef::POINT { x: .., y: .. }; // The dimensions of the primary monitor.
CONTEXT_STASH.with(|context_stash| {
if let Some(cstash) = context_stash.borrow().as_ref() {
if let Some(wstash) = cstash.windows.get(&window) {
let window_state = wstash.lock().unwrap();
if window_state.attributes.min_dimensions.is_some() ||
window_state.attributes.max_dimensions.is_some() {
let style = winuser::GetWindowLongA(window, winuser::GWL_STYLE) as DWORD;
let ex_style = winuser::GetWindowLongA(window, winuser::GWL_EXSTYLE) as DWORD;
if let Some(min_dimensions) = window_state.attributes.min_dimensions {
let (width, height) = adjust_size(min_dimensions, style, ex_style);
(*mmi).ptMinTrackSize = POINT { x: width as i32, y: height as i32 };
}
if let Some(max_dimensions) = window_state.attributes.max_dimensions {
let (width, height) = adjust_size(max_dimensions, style, ex_style);
(*mmi).ptMaxTrackSize = POINT { x: width as i32, y: height as i32 };
}
}
}
}
});
0
},
_ => {
if msg == *DESTROY_MSG_ID {
winuser::DestroyWindow(window);
0
} else {
winuser::DefWindowProcW(window, msg, wparam, lparam)
}
}
}
}

View File

@@ -1,34 +0,0 @@
#![cfg(target_os = "windows")]
use winapi;
use winapi::shared::windef::HWND;
pub use self::events_loop::{EventsLoop, EventsLoopProxy};
pub use self::monitor::MonitorId;
pub use self::window::Window;
#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes {
pub parent: Option<HWND>,
}
unsafe impl Send for PlatformSpecificWindowBuilderAttributes {}
unsafe impl Sync for PlatformSpecificWindowBuilderAttributes {}
// TODO: document what this means
pub type Cursor = *const winapi::ctypes::wchar_t;
// Constant device ID, to be removed when this backend is updated to report real device IDs.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeviceId;
const DEVICE_ID: ::DeviceId = ::DeviceId(DeviceId);
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WindowId(HWND);
unsafe impl Send for WindowId {}
unsafe impl Sync for WindowId {}
mod event;
mod events_loop;
mod monitor;
mod window;

View File

@@ -1,178 +0,0 @@
use winapi::ctypes::wchar_t;
use winapi::shared::minwindef::{DWORD, LPARAM, BOOL, TRUE};
use winapi::shared::windef::{HMONITOR, HDC, LPRECT, HWND};
use winapi::um::winuser;
use std::collections::VecDeque;
use std::{mem, ptr};
use super::EventsLoop;
/// Win32 implementation of the main `MonitorId` object.
#[derive(Clone)]
pub struct MonitorId {
/// The system name of the adapter.
adapter_name: [wchar_t; 32],
/// Monitor handle.
hmonitor: HMonitor,
/// The system name of the monitor.
monitor_name: String,
/// True if this is the primary monitor.
primary: bool,
/// The position of the monitor in pixels on the desktop.
///
/// A window that is positioned at these coordinates will overlap the monitor.
position: (i32, i32),
/// The current resolution in pixels on the monitor.
dimensions: (u32, u32),
/// DPI scaling factor.
hidpi_factor: f32,
}
// Send is not implemented for HMONITOR, we have to wrap it and implement it manually.
// For more info see:
// https://github.com/retep998/winapi-rs/issues/360
// https://github.com/retep998/winapi-rs/issues/396
#[derive(Clone)]
struct HMonitor(HMONITOR);
unsafe impl Send for HMonitor {}
fn wchar_as_string(wchar: &[wchar_t]) -> String {
String::from_utf16_lossy(wchar)
.trim_right_matches(0 as char)
.to_string()
}
unsafe extern "system" fn monitor_enum_proc(hmonitor: HMONITOR, _: HDC, place: LPRECT, data: LPARAM) -> BOOL {
let monitors = data as *mut VecDeque<MonitorId>;
let place = *place;
let position = (place.left as i32, place.top as i32);
let dimensions = ((place.right - place.left) as u32, (place.bottom - place.top) as u32);
let mut monitor_info: winuser::MONITORINFOEXW = mem::zeroed();
monitor_info.cbSize = mem::size_of::<winuser::MONITORINFOEXW>() as DWORD;
if winuser::GetMonitorInfoW(hmonitor, &mut monitor_info as *mut winuser::MONITORINFOEXW as *mut winuser::MONITORINFO) == 0 {
// Some error occurred, just skip this monitor and go on.
return TRUE;
}
(*monitors).push_back(MonitorId {
adapter_name: monitor_info.szDevice,
hmonitor: HMonitor(hmonitor),
monitor_name: wchar_as_string(&monitor_info.szDevice),
primary: monitor_info.dwFlags & winuser::MONITORINFOF_PRIMARY != 0,
position,
dimensions,
hidpi_factor: 1.0,
});
// TRUE means continue enumeration.
TRUE
}
impl EventsLoop {
pub fn get_available_monitors(&self) -> VecDeque<MonitorId> {
unsafe {
let mut result: VecDeque<MonitorId> = VecDeque::new();
winuser::EnumDisplayMonitors(ptr::null_mut(), ptr::null_mut(), Some(monitor_enum_proc), &mut result as *mut _ as LPARAM);
result
}
}
pub fn get_current_monitor(handle: HWND) -> MonitorId {
unsafe {
let mut monitor_info: winuser::MONITORINFOEXW = mem::zeroed();
monitor_info.cbSize = mem::size_of::<winuser::MONITORINFOEXW>() as DWORD;
let hmonitor = winuser::MonitorFromWindow(handle, winuser::MONITOR_DEFAULTTONEAREST);
winuser::GetMonitorInfoW(
hmonitor,
&mut monitor_info as *mut winuser::MONITORINFOEXW as *mut winuser::MONITORINFO,
);
let place = monitor_info.rcMonitor;
let position = (place.left as i32, place.top as i32);
let dimensions = (
(place.right - place.left) as u32,
(place.bottom - place.top) as u32,
);
MonitorId {
adapter_name: monitor_info.szDevice,
hmonitor: super::monitor::HMonitor(hmonitor),
monitor_name: wchar_as_string(&monitor_info.szDevice),
primary: monitor_info.dwFlags & winuser::MONITORINFOF_PRIMARY != 0,
position,
dimensions,
hidpi_factor: 1.0,
}
}
}
pub fn get_primary_monitor(&self) -> MonitorId {
// we simply get all available monitors and return the one with the `MONITORINFOF_PRIMARY` flag
// TODO: it is possible to query the win32 API for the primary monitor, this should be done
// instead
for monitor in self.get_available_monitors().into_iter() {
if monitor.primary {
return monitor;
}
}
panic!("Failed to find the primary monitor")
}
}
impl MonitorId {
/// See the docs if the crate root file.
#[inline]
pub fn get_name(&self) -> Option<String> {
Some(self.monitor_name.clone())
}
/// See the docs of the crate root file.
#[inline]
pub fn get_native_identifier(&self) -> String {
self.monitor_name.clone()
}
/// See the docs of the crate root file.
#[inline]
pub fn get_hmonitor(&self) -> HMONITOR {
self.hmonitor.0
}
/// See the docs of the crate root file.
#[inline]
pub fn get_dimensions(&self) -> (u32, u32) {
// TODO: retrieve the dimensions every time this is called
self.dimensions
}
/// This is a Win32-only function for `MonitorId` that returns the system name of the adapter
/// device.
#[inline]
pub fn get_adapter_name(&self) -> &[wchar_t] {
&self.adapter_name
}
/// A window that is positioned at these coordinates will overlap the monitor.
#[inline]
pub fn get_position(&self) -> (i32, i32) {
self.position
}
#[inline]
pub fn get_hidpi_factor(&self) -> f32 {
self.hidpi_factor
}
}

View File

@@ -1,942 +0,0 @@
#![cfg(target_os = "windows")]
use std::ffi::OsStr;
use std::io;
use std::mem;
use std::os::raw;
use std::os::windows::ffi::OsStrExt;
use std::ptr;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::mpsc::channel;
use std::cell::Cell;
use platform::platform::events_loop::{self, DESTROY_MSG_ID};
use platform::platform::EventsLoop;
use platform::platform::PlatformSpecificWindowBuilderAttributes;
use platform::platform::WindowId;
use CreationError;
use CursorState;
use MouseCursor;
use WindowAttributes;
use MonitorId as RootMonitorId;
use winapi::shared::minwindef::{UINT, DWORD, BOOL};
use winapi::shared::windef::{HWND, HDC, RECT, POINT};
use winapi::shared::hidusage;
use winapi::um::{winuser, dwmapi, libloaderapi, processthreadsapi};
use winapi::um::winnt::{LPCWSTR, LONG, HRESULT};
use winapi::um::combaseapi;
use winapi::um::objbase::{COINIT_MULTITHREADED};
use winapi::um::unknwnbase::{IUnknown, IUnknownVtbl};
/// The Win32 implementation of the main `Window` object.
pub struct Window {
/// Main handle for the window.
window: WindowWrapper,
/// The current window state.
window_state: Arc<Mutex<events_loop::WindowState>>,
// The events loop proxy.
events_loop_proxy: events_loop::EventsLoopProxy,
}
unsafe impl Send for Window {}
unsafe impl Sync for Window {}
// https://blogs.msdn.microsoft.com/oldnewthing/20131017-00/?p=2903
// The idea here is that we use the Adjust­Window­Rect­Ex function to calculate how much additional
// non-client area gets added due to the styles we passed. To make the math simple,
// we ask for a zero client rectangle, so that the resulting window is all non-client.
// And then we pass in the empty rectangle represented by the dot in the middle,
// and the Adjust­Window­Rect­Ex expands the rectangle in all dimensions.
// We see that it added ten pixels to the left, right, and bottom,
// and it added fifty pixels to the top.
// From this we can perform the reverse calculation: Instead of expanding the rectangle, we shrink it.
unsafe fn unjust_window_rect(prc: &mut RECT, style: DWORD, ex_style: DWORD) -> BOOL {
let mut rc: RECT = mem::zeroed();
winuser::SetRectEmpty(&mut rc);
let frc = winuser::AdjustWindowRectEx(&mut rc, style, 0, ex_style);
if frc != 0 {
prc.left -= rc.left;
prc.top -= rc.top;
prc.right -= rc.right;
prc.bottom -= rc.bottom;
}
frc
}
impl Window {
pub fn new(events_loop: &EventsLoop, w_attr: &WindowAttributes,
pl_attr: &PlatformSpecificWindowBuilderAttributes) -> Result<Window, CreationError>
{
let mut w_attr = Some(w_attr.clone());
let mut pl_attr = Some(pl_attr.clone());
let (tx, rx) = channel();
let proxy = events_loop.create_proxy();
events_loop.execute_in_thread(move |inserter| {
// We dispatch an `init` function because of code style.
let win = unsafe { init(w_attr.take().unwrap(), pl_attr.take().unwrap(), inserter, proxy.clone()) };
let _ = tx.send(win);
});
rx.recv().unwrap()
}
pub fn set_title(&self, text: &str) {
unsafe {
let text = OsStr::new(text).encode_wide().chain(Some(0).into_iter())
.collect::<Vec<_>>();
winuser::SetWindowTextW(self.window.0, text.as_ptr() as LPCWSTR);
}
}
#[inline]
pub fn show(&self) {
unsafe {
winuser::ShowWindow(self.window.0, winuser::SW_SHOW);
}
}
#[inline]
pub fn hide(&self) {
unsafe {
winuser::ShowWindow(self.window.0, winuser::SW_HIDE);
}
}
/// See the docs in the crate root file.
pub fn get_position(&self) -> Option<(i32, i32)> {
use std::mem;
let mut placement: winuser::WINDOWPLACEMENT = unsafe { mem::zeroed() };
placement.length = mem::size_of::<winuser::WINDOWPLACEMENT>() as UINT;
if unsafe { winuser::GetWindowPlacement(self.window.0, &mut placement) } == 0 {
return None
}
let ref rect = placement.rcNormalPosition;
Some((rect.left as i32, rect.top as i32))
}
pub fn get_inner_position(&self) -> Option<(i32, i32)> {
use std::mem;
let mut position: POINT = unsafe{ mem::zeroed() };
if unsafe{ winuser::ClientToScreen(self.window.0, &mut position) } == 0 {
return None;
}
Some((position.x, position.y))
}
/// See the docs in the crate root file.
pub fn set_position(&self, x: i32, y: i32) {
unsafe {
winuser::SetWindowPos(self.window.0, ptr::null_mut(), x as raw::c_int, y as raw::c_int,
0, 0, winuser::SWP_ASYNCWINDOWPOS | winuser::SWP_NOZORDER | winuser::SWP_NOSIZE);
winuser::UpdateWindow(self.window.0);
}
}
/// See the docs in the crate root file.
#[inline]
pub fn get_inner_size(&self) -> Option<(u32, u32)> {
let mut rect: RECT = unsafe { mem::uninitialized() };
if unsafe { winuser::GetClientRect(self.window.0, &mut rect) } == 0 {
return None
}
Some((
(rect.right - rect.left) as u32,
(rect.bottom - rect.top) as u32
))
}
/// See the docs in the crate root file.
#[inline]
pub fn get_outer_size(&self) -> Option<(u32, u32)> {
let mut rect: RECT = unsafe { mem::uninitialized() };
if unsafe { winuser::GetWindowRect(self.window.0, &mut rect) } == 0 {
return None
}
Some((
(rect.right - rect.left) as u32,
(rect.bottom - rect.top) as u32
))
}
/// See the docs in the crate root file.
pub fn set_inner_size(&self, x: u32, y: u32) {
unsafe {
// Calculate the outer size based upon the specified inner size
let mut rect = RECT { top: 0, left: 0, bottom: y as LONG, right: x as LONG };
let dw_style = winuser::GetWindowLongA(self.window.0, winuser::GWL_STYLE) as DWORD;
let b_menu = !winuser::GetMenu(self.window.0).is_null() as BOOL;
let dw_style_ex = winuser::GetWindowLongA(self.window.0, winuser::GWL_EXSTYLE) as DWORD;
winuser::AdjustWindowRectEx(&mut rect, dw_style, b_menu, dw_style_ex);
let outer_x = (rect.right - rect.left).abs() as raw::c_int;
let outer_y = (rect.top - rect.bottom).abs() as raw::c_int;
winuser::SetWindowPos(self.window.0, ptr::null_mut(), 0, 0, outer_x, outer_y,
winuser::SWP_ASYNCWINDOWPOS | winuser::SWP_NOZORDER | winuser::SWP_NOREPOSITION | winuser::SWP_NOMOVE);
winuser::UpdateWindow(self.window.0);
}
}
/// See the docs in the crate root file.
#[inline]
pub fn set_min_dimensions(&self, dimensions: Option<(u32, u32)>) {
let mut window_state = self.window_state.lock().unwrap();
window_state.attributes.min_dimensions = dimensions;
// Make windows re-check the window size bounds.
if let Some(inner_size) = self.get_inner_size() {
unsafe {
let mut rect = RECT { top: 0, left: 0, bottom: inner_size.1 as LONG, right: inner_size.0 as LONG };
let dw_style = winuser::GetWindowLongA(self.window.0, winuser::GWL_STYLE) as DWORD;
let b_menu = !winuser::GetMenu(self.window.0).is_null() as BOOL;
let dw_style_ex = winuser::GetWindowLongA(self.window.0, winuser::GWL_EXSTYLE) as DWORD;
winuser::AdjustWindowRectEx(&mut rect, dw_style, b_menu, dw_style_ex);
let outer_x = (rect.right - rect.left).abs() as raw::c_int;
let outer_y = (rect.top - rect.bottom).abs() as raw::c_int;
winuser::SetWindowPos(self.window.0, ptr::null_mut(), 0, 0, outer_x, outer_y,
winuser::SWP_ASYNCWINDOWPOS | winuser::SWP_NOZORDER | winuser::SWP_NOREPOSITION | winuser::SWP_NOMOVE);
}
}
}
/// See the docs in the crate root file.
#[inline]
pub fn set_max_dimensions(&self, dimensions: Option<(u32, u32)>) {
let mut window_state = self.window_state.lock().unwrap();
window_state.attributes.max_dimensions = dimensions;
// Make windows re-check the window size bounds.
if let Some(inner_size) = self.get_inner_size() {
unsafe {
let mut rect = RECT { top: 0, left: 0, bottom: inner_size.1 as LONG, right: inner_size.0 as LONG };
let dw_style = winuser::GetWindowLongA(self.window.0, winuser::GWL_STYLE) as DWORD;
let b_menu = !winuser::GetMenu(self.window.0).is_null() as BOOL;
let dw_style_ex = winuser::GetWindowLongA(self.window.0, winuser::GWL_EXSTYLE) as DWORD;
winuser::AdjustWindowRectEx(&mut rect, dw_style, b_menu, dw_style_ex);
let outer_x = (rect.right - rect.left).abs() as raw::c_int;
let outer_y = (rect.top - rect.bottom).abs() as raw::c_int;
winuser::SetWindowPos(self.window.0, ptr::null_mut(), 0, 0, outer_x, outer_y,
winuser::SWP_ASYNCWINDOWPOS | winuser::SWP_NOZORDER | winuser::SWP_NOREPOSITION | winuser::SWP_NOMOVE);
}
}
}
// TODO: remove
pub fn platform_display(&self) -> *mut ::libc::c_void {
panic!() // Deprecated function ; we don't care anymore
}
// TODO: remove
pub fn platform_window(&self) -> *mut ::libc::c_void {
self.window.0 as *mut ::libc::c_void
}
/// Returns the `hwnd` of this window.
#[inline]
pub fn hwnd(&self) -> HWND {
self.window.0
}
#[inline]
pub fn set_cursor(&self, cursor: MouseCursor) {
let cursor_id = match cursor {
MouseCursor::Arrow | MouseCursor::Default => winuser::IDC_ARROW,
MouseCursor::Hand => winuser::IDC_HAND,
MouseCursor::Crosshair => winuser::IDC_CROSS,
MouseCursor::Text | MouseCursor::VerticalText => winuser::IDC_IBEAM,
MouseCursor::NotAllowed | MouseCursor::NoDrop => winuser::IDC_NO,
MouseCursor::Grab | MouseCursor::Grabbing |
MouseCursor::Move | MouseCursor::AllScroll => winuser::IDC_SIZEALL,
MouseCursor::EResize | MouseCursor::WResize |
MouseCursor::EwResize | MouseCursor::ColResize => winuser::IDC_SIZEWE,
MouseCursor::NResize | MouseCursor::SResize |
MouseCursor::NsResize | MouseCursor::RowResize => winuser::IDC_SIZENS,
MouseCursor::NeResize | MouseCursor::SwResize |
MouseCursor::NeswResize => winuser::IDC_SIZENESW,
MouseCursor::NwResize | MouseCursor::SeResize |
MouseCursor::NwseResize => winuser::IDC_SIZENWSE,
MouseCursor::Wait => winuser::IDC_WAIT,
MouseCursor::Progress => winuser::IDC_APPSTARTING,
MouseCursor::Help => winuser::IDC_HELP,
_ => winuser::IDC_ARROW, // use arrow for the missing cases.
};
let mut cur = self.window_state.lock().unwrap();
cur.cursor = cursor_id;
}
// TODO: it should be possible to rework this function by using the `execute_in_thread` method
// of the events loop.
pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
let mut current_state = self.window_state.lock().unwrap();
let foreground_thread_id = unsafe { winuser::GetWindowThreadProcessId(self.window.0, ptr::null_mut()) };
let current_thread_id = unsafe { processthreadsapi::GetCurrentThreadId() };
unsafe { winuser::AttachThreadInput(foreground_thread_id, current_thread_id, 1) };
let res = match (state, current_state.cursor_state) {
(CursorState::Normal, CursorState::Normal) => Ok(()),
(CursorState::Hide, CursorState::Hide) => Ok(()),
(CursorState::Grab, CursorState::Grab) => Ok(()),
(CursorState::Hide, CursorState::Normal) => {
current_state.cursor_state = CursorState::Hide;
Ok(())
},
(CursorState::Normal, CursorState::Hide) => {
current_state.cursor_state = CursorState::Normal;
Ok(())
},
(CursorState::Grab, CursorState::Normal) | (CursorState::Grab, CursorState::Hide) => {
unsafe {
let mut rect = mem::uninitialized();
if winuser::GetClientRect(self.window.0, &mut rect) == 0 {
return Err(format!("GetWindowRect failed"));
}
winuser::ClientToScreen(self.window.0, mem::transmute(&mut rect.left));
winuser::ClientToScreen(self.window.0, mem::transmute(&mut rect.right));
if winuser::ClipCursor(&rect) == 0 {
return Err(format!("ClipCursor failed"));
}
current_state.cursor_state = CursorState::Grab;
Ok(())
}
},
(CursorState::Normal, CursorState::Grab) => {
unsafe {
if winuser::ClipCursor(ptr::null()) == 0 {
return Err(format!("ClipCursor failed"));
}
current_state.cursor_state = CursorState::Normal;
Ok(())
}
},
_ => unimplemented!(),
};
unsafe { winuser::AttachThreadInput(foreground_thread_id, current_thread_id, 0) };
res
}
#[inline]
pub fn hidpi_factor(&self) -> f32 {
1.0
}
pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
let mut point = POINT {
x: x,
y: y,
};
unsafe {
if winuser::ClientToScreen(self.window.0, &mut point) == 0 {
return Err(());
}
if winuser::SetCursorPos(point.x, point.y) == 0 {
return Err(());
}
}
Ok(())
}
#[inline]
pub fn id(&self) -> WindowId {
WindowId(self.window.0)
}
#[inline]
pub fn set_maximized(&self, maximized: bool) {
let mut window_state = self.window_state.lock().unwrap();
window_state.attributes.maximized = maximized;
// we only maximized if we are not in fullscreen
if window_state.attributes.fullscreen.is_some() {
return;
}
let window = self.window.clone();
unsafe {
// And because ShowWindow will resize the window
// We call it in the main thread
self.events_loop_proxy.execute_in_thread(move |_| {
winuser::ShowWindow(
window.0,
if maximized {
winuser::SW_MAXIMIZE
} else {
winuser::SW_RESTORE
},
);
});
}
}
unsafe fn set_fullscreen_style(&self) -> (LONG, LONG) {
let mut window_state = self.window_state.lock().unwrap();
if window_state.attributes.fullscreen.is_none() || window_state.saved_window_info.is_none() {
let mut rect: RECT = mem::zeroed();
winuser::GetWindowRect(self.window.0, &mut rect);
window_state.saved_window_info = Some(events_loop::SavedWindowInfo {
style: winuser::GetWindowLongW(self.window.0, winuser::GWL_STYLE),
ex_style: winuser::GetWindowLongW(self.window.0, winuser::GWL_EXSTYLE),
rect,
});
}
// We sync the system maximized state here, it will be used when restoring
let mut placement: winuser::WINDOWPLACEMENT = mem::zeroed();
placement.length = mem::size_of::<winuser::WINDOWPLACEMENT>() as u32;
winuser::GetWindowPlacement(self.window.0, &mut placement);
window_state.attributes.maximized =
placement.showCmd == (winuser::SW_SHOWMAXIMIZED as u32);
let saved_window_info = window_state.saved_window_info.as_ref().unwrap();
(saved_window_info.style, saved_window_info.ex_style)
}
unsafe fn restore_saved_window(&self) {
let window_state = self.window_state.lock().unwrap();
// Reset original window style and size. The multiple window size/moves
// here are ugly, but if SetWindowPos() doesn't redraw, the taskbar won't be
// repainted. Better-looking methods welcome.
let saved_window_info = window_state.saved_window_info.as_ref().unwrap();
let rect = saved_window_info.rect.clone();
let window = self.window.clone();
let (style, ex_style) = (saved_window_info.style, saved_window_info.ex_style);
let maximized = window_state.attributes.maximized;
// On restore, resize to the previous saved rect size.
// And because SetWindowPos will resize the window
// We call it in the main thread
self.events_loop_proxy.execute_in_thread(move |_| {
winuser::SetWindowLongW(window.0, winuser::GWL_STYLE, style);
winuser::SetWindowLongW(window.0, winuser::GWL_EXSTYLE, ex_style);
winuser::SetWindowPos(
window.0,
ptr::null_mut(),
rect.left,
rect.top,
rect.right - rect.left,
rect.bottom - rect.top,
winuser::SWP_ASYNCWINDOWPOS | winuser::SWP_NOZORDER | winuser::SWP_NOACTIVATE
| winuser::SWP_FRAMECHANGED,
);
// if it was set to maximized when it were fullscreened, we restore it as well
winuser::ShowWindow(
window.0,
if maximized {
winuser::SW_MAXIMIZE
} else {
winuser::SW_RESTORE
},
);
mark_fullscreen(window.0, false);
});
}
#[inline]
pub fn set_fullscreen(&self, monitor: Option<RootMonitorId>) {
unsafe {
match &monitor {
&Some(RootMonitorId { ref inner }) => {
let pos = inner.get_position();
let dim = inner.get_dimensions();
let window = self.window.clone();
let (style, ex_style) = self.set_fullscreen_style();
self.events_loop_proxy.execute_in_thread(move |_| {
winuser::SetWindowLongW(
window.0,
winuser::GWL_STYLE,
((style as DWORD) & !(winuser::WS_CAPTION | winuser::WS_THICKFRAME))
as LONG,
);
winuser::SetWindowLongW(
window.0,
winuser::GWL_EXSTYLE,
((ex_style as DWORD)
& !(winuser::WS_EX_DLGMODALFRAME | winuser::WS_EX_WINDOWEDGE
| winuser::WS_EX_CLIENTEDGE
| winuser::WS_EX_STATICEDGE))
as LONG,
);
winuser::SetWindowPos(
window.0,
ptr::null_mut(),
pos.0,
pos.1,
dim.0 as i32,
dim.1 as i32,
winuser::SWP_ASYNCWINDOWPOS | winuser::SWP_NOZORDER
| winuser::SWP_NOACTIVATE
| winuser::SWP_FRAMECHANGED,
);
mark_fullscreen(window.0, true);
});
}
&None => {
self.restore_saved_window();
}
}
}
let mut window_state = self.window_state.lock().unwrap();
window_state.attributes.fullscreen = monitor;
}
#[inline]
pub fn set_decorations(&self, decorations: bool) {
if let Ok(mut window_state) = self.window_state.lock() {
if window_state.attributes.decorations == decorations {
return;
}
let style_flags = (winuser::WS_CAPTION | winuser::WS_THICKFRAME) as LONG;
let ex_style_flags = (winuser::WS_EX_WINDOWEDGE) as LONG;
// if we are in fullscreen mode, we only change the saved window info
if window_state.attributes.fullscreen.is_some() {
{
let mut saved = window_state.saved_window_info.as_mut().unwrap();
unsafe {
unjust_window_rect(&mut saved.rect, saved.style as _, saved.ex_style as _);
}
if decorations {
saved.style = saved.style | style_flags;
saved.ex_style = saved.ex_style | ex_style_flags;
} else {
saved.style = saved.style & !style_flags;
saved.ex_style = saved.ex_style & !ex_style_flags;
}
unsafe {
winuser::AdjustWindowRectEx(
&mut saved.rect,
saved.style as _,
0,
saved.ex_style as _,
);
}
}
window_state.attributes.decorations = decorations;
return;
}
unsafe {
let mut rect: RECT = mem::zeroed();
winuser::GetWindowRect(self.window.0, &mut rect);
let mut style = winuser::GetWindowLongW(self.window.0, winuser::GWL_STYLE);
let mut ex_style = winuser::GetWindowLongW(self.window.0, winuser::GWL_EXSTYLE);
unjust_window_rect(&mut rect, style as _, ex_style as _);
if decorations {
style = style | style_flags;
ex_style = ex_style | ex_style_flags;
} else {
style = style & !style_flags;
ex_style = ex_style & !ex_style_flags;
}
let window = self.window.clone();
self.events_loop_proxy.execute_in_thread(move |_| {
winuser::SetWindowLongW(window.0, winuser::GWL_STYLE, style);
winuser::SetWindowLongW(window.0, winuser::GWL_EXSTYLE, ex_style);
winuser::AdjustWindowRectEx(&mut rect, style as _, 0, ex_style as _);
winuser::SetWindowPos(
window.0,
ptr::null_mut(),
rect.left,
rect.top,
rect.right - rect.left,
rect.bottom - rect.top,
winuser::SWP_ASYNCWINDOWPOS | winuser::SWP_NOZORDER
| winuser::SWP_NOACTIVATE
| winuser::SWP_FRAMECHANGED,
);
});
}
window_state.attributes.decorations = decorations;
}
}
#[inline]
pub fn get_current_monitor(&self) -> RootMonitorId {
RootMonitorId {
inner: EventsLoop::get_current_monitor(self.window.0),
}
}
}
impl Drop for Window {
#[inline]
fn drop(&mut self) {
unsafe {
// The window must be destroyed from the same thread that created it, so we send a
// custom message to be handled by our callback to do the actual work.
winuser::PostMessageW(self.window.0, *DESTROY_MSG_ID, 0, 0);
}
}
}
/// A simple non-owning wrapper around a window.
#[doc(hidden)]
#[derive(Clone)]
pub struct WindowWrapper(HWND, HDC);
// Send is not implemented for HWND and HDC, we have to wrap it and implement it manually.
// For more info see:
// https://github.com/retep998/winapi-rs/issues/360
// https://github.com/retep998/winapi-rs/issues/396
unsafe impl Send for WindowWrapper {}
pub unsafe fn adjust_size(
(x, y): (u32, u32), style: DWORD, ex_style: DWORD,
) -> (LONG, LONG) {
let mut rect = RECT { left: 0, right: x as LONG, top: 0, bottom: y as LONG };
winuser::AdjustWindowRectEx(&mut rect, style, 0, ex_style);
(rect.right - rect.left, rect.bottom - rect.top)
}
unsafe fn init(window: WindowAttributes, pl_attribs: PlatformSpecificWindowBuilderAttributes,
inserter: events_loop::Inserter, events_loop_proxy: events_loop::EventsLoopProxy) -> Result<Window, CreationError> {
let title = OsStr::new(&window.title).encode_wide().chain(Some(0).into_iter())
.collect::<Vec<_>>();
// registering the window class
let class_name = register_window_class();
// building a RECT object with coordinates
let mut rect = RECT {
left: 0, right: window.dimensions.unwrap_or((1024, 768)).0 as LONG,
top: 0, bottom: window.dimensions.unwrap_or((1024, 768)).1 as LONG,
};
// computing the style and extended style of the window
let (ex_style, style) = if !window.decorations {
(winuser::WS_EX_APPWINDOW,
//winapi::WS_POPUP is incompatible with winapi::WS_CHILD
if pl_attribs.parent.is_some() {
winuser::WS_CLIPSIBLINGS | winuser::WS_CLIPCHILDREN
}
else {
winuser::WS_POPUP | winuser::WS_CLIPSIBLINGS | winuser::WS_CLIPCHILDREN
}
)
} else {
(winuser::WS_EX_APPWINDOW | winuser::WS_EX_WINDOWEDGE,
winuser::WS_OVERLAPPEDWINDOW | winuser::WS_CLIPSIBLINGS | winuser::WS_CLIPCHILDREN)
};
// adjusting the window coordinates using the style
winuser::AdjustWindowRectEx(&mut rect, style, 0, ex_style);
// creating the real window this time, by using the functions in `extra_functions`
let real_window = {
let (width, height) = if window.dimensions.is_some() {
let min_dimensions = window.min_dimensions
.map(|d| adjust_size(d, style, ex_style))
.unwrap_or((0, 0));
let max_dimensions = window.max_dimensions
.map(|d| adjust_size(d, style, ex_style))
.unwrap_or((raw::c_int::max_value(), raw::c_int::max_value()));
(
Some((rect.right - rect.left).min(max_dimensions.0).max(min_dimensions.0)),
Some((rect.bottom - rect.top).min(max_dimensions.1).max(min_dimensions.1))
)
} else {
(None, None)
};
let mut style = if !window.visible {
style
} else {
style | winuser::WS_VISIBLE
};
if pl_attribs.parent.is_some() {
style |= winuser::WS_CHILD;
}
let handle = winuser::CreateWindowExW(ex_style | winuser::WS_EX_ACCEPTFILES,
class_name.as_ptr(),
title.as_ptr() as LPCWSTR,
style | winuser::WS_CLIPSIBLINGS | winuser::WS_CLIPCHILDREN,
winuser::CW_USEDEFAULT, winuser::CW_USEDEFAULT,
width.unwrap_or(winuser::CW_USEDEFAULT), height.unwrap_or(winuser::CW_USEDEFAULT),
pl_attribs.parent.unwrap_or(ptr::null_mut()),
ptr::null_mut(), libloaderapi::GetModuleHandleW(ptr::null()),
ptr::null_mut());
if handle.is_null() {
return Err(CreationError::OsError(format!("CreateWindowEx function failed: {}",
format!("{}", io::Error::last_os_error()))));
}
let hdc = winuser::GetDC(handle);
if hdc.is_null() {
return Err(CreationError::OsError(format!("GetDC function failed: {}",
format!("{}", io::Error::last_os_error()))));
}
WindowWrapper(handle, hdc)
};
// Set up raw mouse input
{
let mut rid: winuser::RAWINPUTDEVICE = mem::uninitialized();
rid.usUsagePage = hidusage::HID_USAGE_PAGE_GENERIC;
rid.usUsage = hidusage::HID_USAGE_GENERIC_MOUSE;
rid.dwFlags = 0;
rid.hwndTarget = real_window.0;
winuser::RegisterRawInputDevices(&rid, 1, mem::size_of::<winuser::RAWINPUTDEVICE>() as u32);
}
// Register for touch events if applicable
{
let digitizer = winuser::GetSystemMetrics( winuser::SM_DIGITIZER ) as u32;
if digitizer & winuser::NID_READY != 0 {
winuser::RegisterTouchWindow( real_window.0, winuser::TWF_WANTPALM );
}
}
// Creating a mutex to track the current window state
let window_state = Arc::new(Mutex::new(events_loop::WindowState {
cursor: winuser::IDC_ARROW, // use arrow by default
cursor_state: CursorState::Normal,
attributes: window.clone(),
mouse_in_window: false,
saved_window_info: None,
}));
// making the window transparent
if window.transparent {
let bb = dwmapi::DWM_BLURBEHIND {
dwFlags: 0x1, // FIXME: DWM_BB_ENABLE;
fEnable: 1,
hRgnBlur: ptr::null_mut(),
fTransitionOnMaximized: 0,
};
dwmapi::DwmEnableBlurBehindWindow(real_window.0, &bb);
}
let win = Window {
window: real_window,
window_state: window_state,
events_loop_proxy
};
win.set_maximized(window.maximized);
if let Some(_) = window.fullscreen {
win.set_fullscreen(window.fullscreen);
force_window_active(win.window.0);
}
inserter.insert(win.window.0, win.window_state.clone());
Ok(win)
}
unsafe fn register_window_class() -> Vec<u16> {
let class_name = OsStr::new("Window Class").encode_wide().chain(Some(0).into_iter())
.collect::<Vec<_>>();
let class = winuser::WNDCLASSEXW {
cbSize: mem::size_of::<winuser::WNDCLASSEXW>() as UINT,
style: winuser::CS_HREDRAW | winuser::CS_VREDRAW | winuser::CS_OWNDC,
lpfnWndProc: Some(events_loop::callback),
cbClsExtra: 0,
cbWndExtra: 0,
hInstance: libloaderapi::GetModuleHandleW(ptr::null()),
hIcon: ptr::null_mut(),
hCursor: ptr::null_mut(), // must be null in order for cursor state to work properly
hbrBackground: ptr::null_mut(),
lpszMenuName: ptr::null(),
lpszClassName: class_name.as_ptr(),
hIconSm: ptr::null_mut(),
};
// We ignore errors because registering the same window class twice would trigger
// an error, and because errors here are detected during CreateWindowEx anyway.
// Also since there is no weird element in the struct, there is no reason for this
// call to fail.
winuser::RegisterClassExW(&class);
class_name
}
struct ComInitialized(*mut ());
impl Drop for ComInitialized {
fn drop(&mut self) {
unsafe { combaseapi::CoUninitialize() };
}
}
thread_local!{
static COM_INITIALIZED: ComInitialized = {
unsafe {
combaseapi::CoInitializeEx(ptr::null_mut(), COINIT_MULTITHREADED);
ComInitialized(ptr::null_mut())
}
};
static TASKBAR_LIST: Cell<*mut taskbar::ITaskbarList2> = Cell::new(ptr::null_mut());
}
pub fn com_initialized() {
COM_INITIALIZED.with(|_| {});
}
// TODO: remove these when they get added to winapi
// https://github.com/retep998/winapi-rs/pull/592
#[allow(non_upper_case_globals)]
#[allow(non_snake_case)]
#[allow(dead_code)]
mod taskbar {
use super::{IUnknown,IUnknownVtbl,HRESULT, HWND,BOOL};
DEFINE_GUID!{CLSID_TaskbarList,
0x56fdf344, 0xfd6d, 0x11d0, 0x95, 0x8a, 0x00, 0x60, 0x97, 0xc9, 0xa0, 0x90}
RIDL!(#[uuid(0x56fdf342, 0xfd6d, 0x11d0, 0x95, 0x8a, 0x00, 0x60, 0x97, 0xc9, 0xa0, 0x90)]
interface ITaskbarList(ITaskbarListVtbl): IUnknown(IUnknownVtbl) {
fn HrInit() -> HRESULT,
fn AddTab(
hwnd: HWND,
) -> HRESULT,
fn DeleteTab(
hwnd: HWND,
) -> HRESULT,
fn ActivateTab(
hwnd: HWND,
) -> HRESULT,
fn SetActiveAlt(
hwnd: HWND,
) -> HRESULT,
});
RIDL!(#[uuid(0x602d4995, 0xb13a, 0x429b, 0xa6, 0x6e, 0x19, 0x35, 0xe4, 0x4f, 0x43, 0x17)]
interface ITaskbarList2(ITaskbarList2Vtbl): ITaskbarList(ITaskbarListVtbl) {
fn MarkFullscreenWindow(
hwnd: HWND,
fFullscreen: BOOL,
) -> HRESULT,
});
}
// Reference Implementation:
// https://github.com/chromium/chromium/blob/f18e79d901f56154f80eea1e2218544285e62623/ui/views/win/fullscreen_handler.cc
//
// As per MSDN marking the window as fullscreen should ensure that the
// taskbar is moved to the bottom of the Z-order when the fullscreen window
// is activated. If the window is not fullscreen, the Shell falls back to
// heuristics to determine how the window should be treated, which means
// that it could still consider the window as fullscreen. :(
unsafe fn mark_fullscreen(handle: HWND, fullscreen: bool) {
com_initialized();
TASKBAR_LIST.with(|task_bar_list_ptr| {
let mut task_bar_list = task_bar_list_ptr.get();
if task_bar_list == ptr::null_mut() {
use winapi::shared::winerror::S_OK;
use winapi::Interface;
let hr = combaseapi::CoCreateInstance(
&taskbar::CLSID_TaskbarList,
ptr::null_mut(),
combaseapi::CLSCTX_ALL,
&taskbar::ITaskbarList2::uuidof(),
&mut task_bar_list as *mut _ as *mut _,
);
if hr != S_OK || (*task_bar_list).HrInit() != S_OK {
// In some old windows, the taskbar object could not be created, we just ignore it
return;
}
task_bar_list_ptr.set(task_bar_list)
}
task_bar_list = task_bar_list_ptr.get();
(*task_bar_list).MarkFullscreenWindow(handle, if fullscreen { 1 } else { 0 });
})
}
unsafe fn force_window_active(handle: HWND) {
// In some situation, calling SetForegroundWindow could not bring up the window,
// This is a little hack which can "steal" the foreground window permission
// We only call this function in the window creation, so it should be fine.
// See : https://stackoverflow.com/questions/10740346/setforegroundwindow-only-working-while-visual-studio-is-open
let alt_sc = winuser::MapVirtualKeyW(winuser::VK_MENU as _, winuser::MAPVK_VK_TO_VSC);
let mut inputs: [winuser::INPUT; 2] = mem::zeroed();
inputs[0].type_ = winuser::INPUT_KEYBOARD;
inputs[0].u.ki_mut().wVk = winuser::VK_LMENU as _;
inputs[0].u.ki_mut().wScan = alt_sc as _;
inputs[0].u.ki_mut().dwFlags = winuser::KEYEVENTF_EXTENDEDKEY;
inputs[1].type_ = winuser::INPUT_KEYBOARD;
inputs[1].u.ki_mut().wVk = winuser::VK_LMENU as _;
inputs[1].u.ki_mut().wScan = alt_sc as _;
inputs[1].u.ki_mut().dwFlags = winuser::KEYEVENTF_EXTENDEDKEY | winuser::KEYEVENTF_KEYUP;
// Simulate a key press and release
winuser::SendInput(
inputs.len() as _,
inputs.as_mut_ptr(),
mem::size_of::<winuser::INPUT>() as _,
);
winuser::SetForegroundWindow(handle);
}

View File

@@ -0,0 +1,945 @@
#![cfg(target_os = "android")]
use std::{
collections::VecDeque,
sync::{mpsc, RwLock},
time::{Duration, Instant},
};
use ndk::{
configuration::Configuration,
event::{InputEvent, KeyAction, Keycode, MotionAction},
looper::{ForeignLooper, Poll, ThreadLooper},
native_window::NativeWindow,
};
use ndk_glue::{Event, LockReadGuard, Rect};
use once_cell::sync::Lazy;
use raw_window_handle::{
AndroidDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle,
};
use crate::{
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
error,
event::{self, VirtualKeyCode},
event_loop::{self, ControlFlow},
monitor,
window::{self, CursorGrabMode},
};
static CONFIG: Lazy<RwLock<Configuration>> = Lazy::new(|| {
RwLock::new(Configuration::from_asset_manager(
#[allow(deprecated)] // TODO: rust-windowing/winit#2196
&ndk_glue::native_activity().asset_manager(),
))
});
// If this is `Some()` a `Poll::Wake` is considered an `EventSource::Internal` with the event
// contained in the `Option`. The event is moved outside of the `Option` replacing it with a
// `None`.
//
// This allows us to inject event into the event loop without going through `ndk-glue` and
// calling unsafe function that should only be called by Android.
static INTERNAL_EVENT: Lazy<RwLock<Option<InternalEvent>>> = Lazy::new(|| RwLock::new(None));
enum InternalEvent {
RedrawRequested,
}
enum EventSource {
Callback,
InputQueue,
User,
Internal(InternalEvent),
}
fn ndk_keycode_to_virtualkeycode(keycode: Keycode) -> Option<event::VirtualKeyCode> {
match keycode {
Keycode::A => Some(VirtualKeyCode::A),
Keycode::B => Some(VirtualKeyCode::B),
Keycode::C => Some(VirtualKeyCode::C),
Keycode::D => Some(VirtualKeyCode::D),
Keycode::E => Some(VirtualKeyCode::E),
Keycode::F => Some(VirtualKeyCode::F),
Keycode::G => Some(VirtualKeyCode::G),
Keycode::H => Some(VirtualKeyCode::H),
Keycode::I => Some(VirtualKeyCode::I),
Keycode::J => Some(VirtualKeyCode::J),
Keycode::K => Some(VirtualKeyCode::K),
Keycode::L => Some(VirtualKeyCode::L),
Keycode::M => Some(VirtualKeyCode::M),
Keycode::N => Some(VirtualKeyCode::N),
Keycode::O => Some(VirtualKeyCode::O),
Keycode::P => Some(VirtualKeyCode::P),
Keycode::Q => Some(VirtualKeyCode::Q),
Keycode::R => Some(VirtualKeyCode::R),
Keycode::S => Some(VirtualKeyCode::S),
Keycode::T => Some(VirtualKeyCode::T),
Keycode::U => Some(VirtualKeyCode::U),
Keycode::V => Some(VirtualKeyCode::V),
Keycode::W => Some(VirtualKeyCode::W),
Keycode::X => Some(VirtualKeyCode::X),
Keycode::Y => Some(VirtualKeyCode::Y),
Keycode::Z => Some(VirtualKeyCode::Z),
Keycode::Keycode0 => Some(VirtualKeyCode::Key0),
Keycode::Keycode1 => Some(VirtualKeyCode::Key1),
Keycode::Keycode2 => Some(VirtualKeyCode::Key2),
Keycode::Keycode3 => Some(VirtualKeyCode::Key3),
Keycode::Keycode4 => Some(VirtualKeyCode::Key4),
Keycode::Keycode5 => Some(VirtualKeyCode::Key5),
Keycode::Keycode6 => Some(VirtualKeyCode::Key6),
Keycode::Keycode7 => Some(VirtualKeyCode::Key7),
Keycode::Keycode8 => Some(VirtualKeyCode::Key8),
Keycode::Keycode9 => Some(VirtualKeyCode::Key9),
Keycode::Numpad0 => Some(VirtualKeyCode::Numpad0),
Keycode::Numpad1 => Some(VirtualKeyCode::Numpad1),
Keycode::Numpad2 => Some(VirtualKeyCode::Numpad2),
Keycode::Numpad3 => Some(VirtualKeyCode::Numpad3),
Keycode::Numpad4 => Some(VirtualKeyCode::Numpad4),
Keycode::Numpad5 => Some(VirtualKeyCode::Numpad5),
Keycode::Numpad6 => Some(VirtualKeyCode::Numpad6),
Keycode::Numpad7 => Some(VirtualKeyCode::Numpad7),
Keycode::Numpad8 => Some(VirtualKeyCode::Numpad8),
Keycode::Numpad9 => Some(VirtualKeyCode::Numpad9),
Keycode::NumpadAdd => Some(VirtualKeyCode::NumpadAdd),
Keycode::NumpadSubtract => Some(VirtualKeyCode::NumpadSubtract),
Keycode::NumpadMultiply => Some(VirtualKeyCode::NumpadMultiply),
Keycode::NumpadDivide => Some(VirtualKeyCode::NumpadDivide),
Keycode::NumpadEnter => Some(VirtualKeyCode::NumpadEnter),
Keycode::NumpadEquals => Some(VirtualKeyCode::NumpadEquals),
Keycode::NumpadComma => Some(VirtualKeyCode::NumpadComma),
Keycode::NumpadDot => Some(VirtualKeyCode::NumpadDecimal),
Keycode::NumLock => Some(VirtualKeyCode::Numlock),
Keycode::DpadLeft => Some(VirtualKeyCode::Left),
Keycode::DpadRight => Some(VirtualKeyCode::Right),
Keycode::DpadUp => Some(VirtualKeyCode::Up),
Keycode::DpadDown => Some(VirtualKeyCode::Down),
Keycode::F1 => Some(VirtualKeyCode::F1),
Keycode::F2 => Some(VirtualKeyCode::F2),
Keycode::F3 => Some(VirtualKeyCode::F3),
Keycode::F4 => Some(VirtualKeyCode::F4),
Keycode::F5 => Some(VirtualKeyCode::F5),
Keycode::F6 => Some(VirtualKeyCode::F6),
Keycode::F7 => Some(VirtualKeyCode::F7),
Keycode::F8 => Some(VirtualKeyCode::F8),
Keycode::F9 => Some(VirtualKeyCode::F9),
Keycode::F10 => Some(VirtualKeyCode::F10),
Keycode::F11 => Some(VirtualKeyCode::F11),
Keycode::F12 => Some(VirtualKeyCode::F12),
Keycode::Space => Some(VirtualKeyCode::Space),
Keycode::Escape => Some(VirtualKeyCode::Escape),
Keycode::Enter => Some(VirtualKeyCode::Return), // not on the Numpad
Keycode::Tab => Some(VirtualKeyCode::Tab),
Keycode::PageUp => Some(VirtualKeyCode::PageUp),
Keycode::PageDown => Some(VirtualKeyCode::PageDown),
Keycode::MoveHome => Some(VirtualKeyCode::Home),
Keycode::MoveEnd => Some(VirtualKeyCode::End),
Keycode::Insert => Some(VirtualKeyCode::Insert),
Keycode::Del => Some(VirtualKeyCode::Back), // Backspace (above Enter)
Keycode::ForwardDel => Some(VirtualKeyCode::Delete), // Delete (below Insert)
Keycode::Copy => Some(VirtualKeyCode::Copy),
Keycode::Paste => Some(VirtualKeyCode::Paste),
Keycode::Cut => Some(VirtualKeyCode::Cut),
Keycode::VolumeUp => Some(VirtualKeyCode::VolumeUp),
Keycode::VolumeDown => Some(VirtualKeyCode::VolumeDown),
Keycode::VolumeMute => Some(VirtualKeyCode::Mute), // ???
Keycode::Mute => Some(VirtualKeyCode::Mute), // ???
Keycode::MediaPlayPause => Some(VirtualKeyCode::PlayPause),
Keycode::MediaStop => Some(VirtualKeyCode::MediaStop), // ??? simple "Stop"?
Keycode::MediaNext => Some(VirtualKeyCode::NextTrack),
Keycode::MediaPrevious => Some(VirtualKeyCode::PrevTrack),
Keycode::Plus => Some(VirtualKeyCode::Plus),
Keycode::Minus => Some(VirtualKeyCode::Minus),
Keycode::Equals => Some(VirtualKeyCode::Equals),
Keycode::Semicolon => Some(VirtualKeyCode::Semicolon),
Keycode::Slash => Some(VirtualKeyCode::Slash),
Keycode::Backslash => Some(VirtualKeyCode::Backslash),
Keycode::Comma => Some(VirtualKeyCode::Comma),
Keycode::Period => Some(VirtualKeyCode::Period),
Keycode::Apostrophe => Some(VirtualKeyCode::Apostrophe),
Keycode::Grave => Some(VirtualKeyCode::Grave),
Keycode::At => Some(VirtualKeyCode::At),
// TODO: Maybe mapping this to Snapshot makes more sense? See: "PrtScr/SysRq"
Keycode::Sysrq => Some(VirtualKeyCode::Sysrq),
// These are usually the same (Pause/Break)
Keycode::Break => Some(VirtualKeyCode::Pause),
// These are exactly the same
Keycode::ScrollLock => Some(VirtualKeyCode::Scroll),
Keycode::Yen => Some(VirtualKeyCode::Yen),
Keycode::Kana => Some(VirtualKeyCode::Kana),
Keycode::CtrlLeft => Some(VirtualKeyCode::LControl),
Keycode::CtrlRight => Some(VirtualKeyCode::RControl),
Keycode::ShiftLeft => Some(VirtualKeyCode::LShift),
Keycode::ShiftRight => Some(VirtualKeyCode::RShift),
Keycode::AltLeft => Some(VirtualKeyCode::LAlt),
Keycode::AltRight => Some(VirtualKeyCode::RAlt),
// Different names for the same keys
Keycode::MetaLeft => Some(VirtualKeyCode::LWin),
Keycode::MetaRight => Some(VirtualKeyCode::RWin),
Keycode::LeftBracket => Some(VirtualKeyCode::LBracket),
Keycode::RightBracket => Some(VirtualKeyCode::RBracket),
Keycode::Power => Some(VirtualKeyCode::Power),
Keycode::Sleep => Some(VirtualKeyCode::Sleep), // what about SoftSleep?
Keycode::Wakeup => Some(VirtualKeyCode::Wake),
Keycode::NavigateNext => Some(VirtualKeyCode::NavigateForward),
Keycode::NavigatePrevious => Some(VirtualKeyCode::NavigateBackward),
Keycode::Calculator => Some(VirtualKeyCode::Calculator),
Keycode::Explorer => Some(VirtualKeyCode::MyComputer), // "close enough"
Keycode::Envelope => Some(VirtualKeyCode::Mail), // "close enough"
Keycode::Star => Some(VirtualKeyCode::Asterisk), // ???
Keycode::AllApps => Some(VirtualKeyCode::Apps), // ???
Keycode::AppSwitch => Some(VirtualKeyCode::Apps), // ???
Keycode::Refresh => Some(VirtualKeyCode::WebRefresh), // ???
_ => None,
}
}
fn poll(poll: Poll) -> Option<EventSource> {
match poll {
Poll::Event { ident, .. } => match ident {
ndk_glue::NDK_GLUE_LOOPER_EVENT_PIPE_IDENT => Some(EventSource::Callback),
ndk_glue::NDK_GLUE_LOOPER_INPUT_QUEUE_IDENT => Some(EventSource::InputQueue),
_ => unreachable!(),
},
Poll::Timeout => None,
Poll::Wake => Some(
INTERNAL_EVENT
.write()
.unwrap()
.take()
.map_or(EventSource::User, EventSource::Internal),
),
Poll::Callback => unreachable!(),
}
}
pub struct EventLoop<T: 'static> {
window_target: event_loop::EventLoopWindowTarget<T>,
user_events_sender: mpsc::Sender<T>,
user_events_receiver: mpsc::Receiver<T>,
first_event: Option<EventSource>,
start_cause: event::StartCause,
looper: ThreadLooper,
running: bool,
window_lock: Option<LockReadGuard<NativeWindow>>,
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub(crate) struct PlatformSpecificEventLoopAttributes {}
macro_rules! call_event_handler {
( $event_handler:expr, $window_target:expr, $cf:expr, $event:expr ) => {{
if let ControlFlow::ExitWithCode(code) = $cf {
$event_handler($event, $window_target, &mut ControlFlow::ExitWithCode(code));
} else {
$event_handler($event, $window_target, &mut $cf);
}
}};
}
impl<T: 'static> EventLoop<T> {
pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> Self {
let (user_events_sender, user_events_receiver) = mpsc::channel();
Self {
window_target: event_loop::EventLoopWindowTarget {
p: EventLoopWindowTarget {
_marker: std::marker::PhantomData,
},
_marker: std::marker::PhantomData,
},
user_events_sender,
user_events_receiver,
first_event: None,
start_cause: event::StartCause::Init,
looper: ThreadLooper::for_thread().unwrap(),
running: false,
window_lock: None,
}
}
pub fn run<F>(mut self, event_handler: F) -> !
where
F: 'static
+ FnMut(event::Event<'_, T>, &event_loop::EventLoopWindowTarget<T>, &mut ControlFlow),
{
let exit_code = self.run_return(event_handler);
::std::process::exit(exit_code);
}
pub fn run_return<F>(&mut self, mut event_handler: F) -> i32
where
F: FnMut(event::Event<'_, T>, &event_loop::EventLoopWindowTarget<T>, &mut ControlFlow),
{
let mut control_flow = ControlFlow::default();
'event_loop: loop {
call_event_handler!(
event_handler,
self.window_target(),
control_flow,
event::Event::NewEvents(self.start_cause)
);
let mut redraw = false;
let mut resized = false;
match self.first_event.take() {
Some(EventSource::Callback) => match ndk_glue::poll_events().unwrap() {
Event::WindowCreated => {
// Acquire a lock on the window to prevent Android from destroying
// it until we've notified and waited for the user in Event::Suspended.
// WARNING: ndk-glue is inherently racy (https://github.com/rust-windowing/winit/issues/2293)
// and may have already received onNativeWindowDestroyed while this thread hasn't yet processed
// the event, and would see a `None` lock+window in that case.
if let Some(next_window_lock) = ndk_glue::native_window() {
assert!(
self.window_lock.replace(next_window_lock).is_none(),
"Received `Event::WindowCreated` while we were already holding a lock"
);
call_event_handler!(
event_handler,
self.window_target(),
control_flow,
event::Event::Resumed
);
} else {
warn!("Received `Event::WindowCreated` while `ndk_glue::native_window()` provides no window");
}
}
Event::WindowResized => resized = true,
Event::WindowRedrawNeeded => redraw = true,
Event::WindowDestroyed => {
// Release the lock, allowing Android to clean up this surface
// WARNING: See above - if ndk-glue is racy, this event may be called
// without having a `self.window_lock` in place.
if self.window_lock.take().is_some() {
call_event_handler!(
event_handler,
self.window_target(),
control_flow,
event::Event::Suspended
);
} else {
warn!("Received `Event::WindowDestroyed` while we were not holding a window lock");
}
}
Event::Pause => self.running = false,
Event::Resume => self.running = true,
Event::ConfigChanged => {
#[allow(deprecated)] // TODO: rust-windowing/winit#2196
let am = ndk_glue::native_activity().asset_manager();
let config = Configuration::from_asset_manager(&am);
let old_scale_factor = MonitorHandle.scale_factor();
*CONFIG.write().unwrap() = config;
let scale_factor = MonitorHandle.scale_factor();
if (scale_factor - old_scale_factor).abs() < f64::EPSILON {
let mut size = MonitorHandle.size();
let event = event::Event::WindowEvent {
window_id: window::WindowId(WindowId),
event: event::WindowEvent::ScaleFactorChanged {
new_inner_size: &mut size,
scale_factor,
},
};
call_event_handler!(
event_handler,
self.window_target(),
control_flow,
event
);
}
}
Event::WindowHasFocus => {
call_event_handler!(
event_handler,
self.window_target(),
control_flow,
event::Event::WindowEvent {
window_id: window::WindowId(WindowId),
event: event::WindowEvent::Focused(true),
}
);
}
Event::WindowLostFocus => {
call_event_handler!(
event_handler,
self.window_target(),
control_flow,
event::Event::WindowEvent {
window_id: window::WindowId(WindowId),
event: event::WindowEvent::Focused(false),
}
);
}
_ => {}
},
Some(EventSource::InputQueue) => {
if let Some(input_queue) = ndk_glue::input_queue().as_ref() {
while let Some(event) = input_queue.get_event().expect("get_event") {
if let Some(event) = input_queue.pre_dispatch(event) {
let mut handled = true;
let window_id = window::WindowId(WindowId);
let device_id = event::DeviceId(DeviceId);
match &event {
InputEvent::MotionEvent(motion_event) => {
let phase = match motion_event.action() {
MotionAction::Down | MotionAction::PointerDown => {
Some(event::TouchPhase::Started)
}
MotionAction::Up | MotionAction::PointerUp => {
Some(event::TouchPhase::Ended)
}
MotionAction::Move => Some(event::TouchPhase::Moved),
MotionAction::Cancel => {
Some(event::TouchPhase::Cancelled)
}
_ => {
handled = false;
None // TODO mouse events
}
};
if let Some(phase) = phase {
let pointers: Box<
dyn Iterator<Item = ndk::event::Pointer<'_>>,
> = match phase {
event::TouchPhase::Started
| event::TouchPhase::Ended => Box::new(
std::iter::once(motion_event.pointer_at_index(
motion_event.pointer_index(),
)),
),
event::TouchPhase::Moved
| event::TouchPhase::Cancelled => {
Box::new(motion_event.pointers())
}
};
for pointer in pointers {
let location = PhysicalPosition {
x: pointer.x() as _,
y: pointer.y() as _,
};
let event = event::Event::WindowEvent {
window_id,
event: event::WindowEvent::Touch(
event::Touch {
device_id,
phase,
location,
id: pointer.pointer_id() as u64,
force: None,
},
),
};
call_event_handler!(
event_handler,
self.window_target(),
control_flow,
event
);
}
}
}
InputEvent::KeyEvent(key) => {
let state = match key.action() {
KeyAction::Down => event::ElementState::Pressed,
KeyAction::Up => event::ElementState::Released,
_ => event::ElementState::Released,
};
#[allow(deprecated)]
let event = event::Event::WindowEvent {
window_id,
event: event::WindowEvent::KeyboardInput {
device_id,
input: event::KeyboardInput {
scancode: key.scan_code() as u32,
state,
virtual_keycode: ndk_keycode_to_virtualkeycode(
key.key_code(),
),
modifiers: event::ModifiersState::default(),
},
is_synthetic: false,
},
};
call_event_handler!(
event_handler,
self.window_target(),
control_flow,
event
);
}
};
input_queue.finish_event(event, handled);
}
}
}
}
Some(EventSource::User) => {
// try_recv only errors when empty (expected) or disconnect. But because Self
// contains a Sender it will never disconnect, so no error handling need.
while let Ok(event) = self.user_events_receiver.try_recv() {
call_event_handler!(
event_handler,
self.window_target(),
control_flow,
event::Event::UserEvent(event)
);
}
}
Some(EventSource::Internal(internal)) => match internal {
InternalEvent::RedrawRequested => redraw = true,
},
None => {}
}
call_event_handler!(
event_handler,
self.window_target(),
control_flow,
event::Event::MainEventsCleared
);
if resized && self.running {
let size = MonitorHandle.size();
let event = event::Event::WindowEvent {
window_id: window::WindowId(WindowId),
event: event::WindowEvent::Resized(size),
};
call_event_handler!(event_handler, self.window_target(), control_flow, event);
}
if redraw && self.running {
let event = event::Event::RedrawRequested(window::WindowId(WindowId));
call_event_handler!(event_handler, self.window_target(), control_flow, event);
}
call_event_handler!(
event_handler,
self.window_target(),
control_flow,
event::Event::RedrawEventsCleared
);
match control_flow {
ControlFlow::ExitWithCode(code) => {
self.first_event = poll(
self.looper
.poll_once_timeout(Duration::from_millis(0))
.unwrap(),
);
self.start_cause = event::StartCause::WaitCancelled {
start: Instant::now(),
requested_resume: None,
};
break 'event_loop code;
}
ControlFlow::Poll => {
self.first_event = poll(
self.looper
.poll_all_timeout(Duration::from_millis(0))
.unwrap(),
);
self.start_cause = event::StartCause::Poll;
}
ControlFlow::Wait => {
self.first_event = poll(self.looper.poll_all().unwrap());
self.start_cause = event::StartCause::WaitCancelled {
start: Instant::now(),
requested_resume: None,
}
}
ControlFlow::WaitUntil(instant) => {
let start = Instant::now();
let duration = if instant <= start {
Duration::default()
} else {
instant - start
};
self.first_event = poll(self.looper.poll_all_timeout(duration).unwrap());
self.start_cause = if self.first_event.is_some() {
event::StartCause::WaitCancelled {
start,
requested_resume: Some(instant),
}
} else {
event::StartCause::ResumeTimeReached {
start,
requested_resume: instant,
}
}
}
}
}
}
pub fn window_target(&self) -> &event_loop::EventLoopWindowTarget<T> {
&self.window_target
}
pub fn create_proxy(&self) -> EventLoopProxy<T> {
EventLoopProxy {
user_events_sender: self.user_events_sender.clone(),
looper: ForeignLooper::for_thread().expect("called from event loop thread"),
}
}
}
pub struct EventLoopProxy<T: 'static> {
user_events_sender: mpsc::Sender<T>,
looper: ForeignLooper,
}
impl<T> EventLoopProxy<T> {
pub fn send_event(&self, event: T) -> Result<(), event_loop::EventLoopClosed<T>> {
self.user_events_sender
.send(event)
.map_err(|mpsc::SendError(x)| event_loop::EventLoopClosed(x))?;
self.looper.wake();
Ok(())
}
}
impl<T> Clone for EventLoopProxy<T> {
fn clone(&self) -> Self {
EventLoopProxy {
user_events_sender: self.user_events_sender.clone(),
looper: self.looper.clone(),
}
}
}
pub struct EventLoopWindowTarget<T: 'static> {
_marker: std::marker::PhantomData<T>,
}
impl<T: 'static> EventLoopWindowTarget<T> {
pub fn primary_monitor(&self) -> Option<monitor::MonitorHandle> {
Some(monitor::MonitorHandle {
inner: MonitorHandle,
})
}
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
let mut v = VecDeque::with_capacity(1);
v.push_back(MonitorHandle);
v
}
pub fn raw_display_handle(&self) -> RawDisplayHandle {
RawDisplayHandle::Android(AndroidDisplayHandle::empty())
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct WindowId;
impl WindowId {
pub const fn dummy() -> Self {
WindowId
}
}
impl From<WindowId> for u64 {
fn from(_: WindowId) -> Self {
0
}
}
impl From<u64> for WindowId {
fn from(_: u64) -> Self {
Self
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct DeviceId;
impl DeviceId {
pub const fn dummy() -> Self {
DeviceId
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct PlatformSpecificWindowBuilderAttributes;
pub struct Window;
impl Window {
pub(crate) fn new<T: 'static>(
_el: &EventLoopWindowTarget<T>,
_window_attrs: window::WindowAttributes,
_: PlatformSpecificWindowBuilderAttributes,
) -> Result<Self, error::OsError> {
// FIXME this ignores requested window attributes
Ok(Self)
}
pub fn id(&self) -> WindowId {
WindowId
}
pub fn primary_monitor(&self) -> Option<monitor::MonitorHandle> {
Some(monitor::MonitorHandle {
inner: MonitorHandle,
})
}
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
let mut v = VecDeque::with_capacity(1);
v.push_back(MonitorHandle);
v
}
pub fn current_monitor(&self) -> Option<monitor::MonitorHandle> {
Some(monitor::MonitorHandle {
inner: MonitorHandle,
})
}
pub fn scale_factor(&self) -> f64 {
MonitorHandle.scale_factor()
}
pub fn request_redraw(&self) {
*INTERNAL_EVENT.write().unwrap() = Some(InternalEvent::RedrawRequested);
ForeignLooper::for_thread().unwrap().wake();
}
pub fn inner_position(&self) -> Result<PhysicalPosition<i32>, error::NotSupportedError> {
Err(error::NotSupportedError::new())
}
pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, error::NotSupportedError> {
Err(error::NotSupportedError::new())
}
pub fn set_outer_position(&self, _position: Position) {
// no effect
}
pub fn inner_size(&self) -> PhysicalSize<u32> {
self.outer_size()
}
pub fn set_inner_size(&self, _size: Size) {
warn!("Cannot set window size on Android");
}
pub fn outer_size(&self) -> PhysicalSize<u32> {
MonitorHandle.size()
}
pub fn set_min_inner_size(&self, _: Option<Size>) {}
pub fn set_max_inner_size(&self, _: Option<Size>) {}
pub fn set_title(&self, _title: &str) {}
pub fn set_visible(&self, _visibility: bool) {}
pub fn is_visible(&self) -> Option<bool> {
None
}
pub fn set_resizable(&self, _resizeable: bool) {}
pub fn is_resizable(&self) -> bool {
false
}
pub fn set_minimized(&self, _minimized: bool) {}
pub fn set_maximized(&self, _maximized: bool) {}
pub fn is_maximized(&self) -> bool {
false
}
pub fn set_fullscreen(&self, _monitor: Option<window::Fullscreen>) {
warn!("Cannot set fullscreen on Android");
}
pub fn fullscreen(&self) -> Option<window::Fullscreen> {
None
}
pub fn set_decorations(&self, _decorations: bool) {}
pub fn is_decorated(&self) -> bool {
true
}
pub fn set_always_on_top(&self, _always_on_top: bool) {}
pub fn set_window_icon(&self, _window_icon: Option<crate::icon::Icon>) {}
pub fn set_ime_position(&self, _position: Position) {}
pub fn set_ime_allowed(&self, _allowed: bool) {}
pub fn focus_window(&self) {}
pub fn request_user_attention(&self, _request_type: Option<window::UserAttentionType>) {}
pub fn set_cursor_icon(&self, _: window::CursorIcon) {}
pub fn set_cursor_position(&self, _: Position) -> Result<(), error::ExternalError> {
Err(error::ExternalError::NotSupported(
error::NotSupportedError::new(),
))
}
pub fn set_cursor_grab(&self, _: CursorGrabMode) -> Result<(), error::ExternalError> {
Err(error::ExternalError::NotSupported(
error::NotSupportedError::new(),
))
}
pub fn set_cursor_visible(&self, _: bool) {}
pub fn drag_window(&self) -> Result<(), error::ExternalError> {
Err(error::ExternalError::NotSupported(
error::NotSupportedError::new(),
))
}
pub fn set_cursor_hittest(&self, _hittest: bool) -> Result<(), error::ExternalError> {
Err(error::ExternalError::NotSupported(
error::NotSupportedError::new(),
))
}
pub fn raw_window_handle(&self) -> RawWindowHandle {
if let Some(native_window) = ndk_glue::native_window() {
native_window.raw_window_handle()
} else {
panic!("Cannot get the native window, it's null and will always be null before Event::Resumed and after Event::Suspended. Make sure you only call this function between those events.");
}
}
pub fn raw_display_handle(&self) -> RawDisplayHandle {
RawDisplayHandle::Android(AndroidDisplayHandle::empty())
}
pub fn config(&self) -> Configuration {
CONFIG.read().unwrap().clone()
}
pub fn content_rect(&self) -> Rect {
ndk_glue::content_rect()
}
}
#[derive(Default, Clone, Debug)]
pub struct OsError;
use std::fmt::{self, Display, Formatter};
impl Display for OsError {
fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), fmt::Error> {
write!(fmt, "Android OS Error")
}
}
pub(crate) use crate::icon::NoIcon as PlatformIcon;
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct MonitorHandle;
impl MonitorHandle {
pub fn name(&self) -> Option<String> {
Some("Android Device".to_owned())
}
pub fn size(&self) -> PhysicalSize<u32> {
if let Some(native_window) = ndk_glue::native_window().as_ref() {
let width = native_window.width() as _;
let height = native_window.height() as _;
PhysicalSize::new(width, height)
} else {
PhysicalSize::new(0, 0)
}
}
pub fn position(&self) -> PhysicalPosition<i32> {
(0, 0).into()
}
pub fn scale_factor(&self) -> f64 {
let config = CONFIG.read().unwrap();
config
.density()
.map(|dpi| dpi as f64 / 160.0)
.unwrap_or(1.0)
}
pub fn refresh_rate_millihertz(&self) -> Option<u32> {
// FIXME no way to get real refresh rate for now.
None
}
pub fn video_modes(&self) -> impl Iterator<Item = monitor::VideoMode> {
let size = self.size().into();
// FIXME this is not the real refresh rate
// (it is guaranteed to support 32 bit color though)
std::iter::once(monitor::VideoMode {
video_mode: VideoMode {
size,
bit_depth: 32,
refresh_rate_millihertz: 60000,
monitor: self.clone(),
},
})
}
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct VideoMode {
size: (u32, u32),
bit_depth: u16,
refresh_rate_millihertz: u32,
monitor: MonitorHandle,
}
impl VideoMode {
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) -> monitor::MonitorHandle {
monitor::MonitorHandle {
inner: self.monitor.clone(),
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,353 @@
use std::{
collections::VecDeque,
ffi::c_void,
fmt::{self, Debug},
marker::PhantomData,
mem, ptr,
sync::mpsc::{self, Receiver, Sender},
};
use raw_window_handle::{RawDisplayHandle, UiKitDisplayHandle};
use crate::{
dpi::LogicalSize,
event::Event,
event_loop::{
ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootEventLoopWindowTarget,
},
monitor::MonitorHandle as RootMonitorHandle,
platform::ios::Idiom,
};
use crate::platform_impl::platform::{
app_state,
ffi::{
id, kCFRunLoopAfterWaiting, kCFRunLoopBeforeWaiting, kCFRunLoopCommonModes,
kCFRunLoopDefaultMode, kCFRunLoopEntry, kCFRunLoopExit, nil, CFIndex, CFRelease,
CFRunLoopActivity, CFRunLoopAddObserver, CFRunLoopAddSource, CFRunLoopGetMain,
CFRunLoopObserverCreate, CFRunLoopObserverRef, CFRunLoopSourceContext,
CFRunLoopSourceCreate, CFRunLoopSourceInvalidate, CFRunLoopSourceRef,
CFRunLoopSourceSignal, CFRunLoopWakeUp, NSStringRust, UIApplicationMain,
UIUserInterfaceIdiom,
},
monitor, view, MonitorHandle,
};
#[derive(Debug)]
pub enum EventWrapper {
StaticEvent(Event<'static, Never>),
EventProxy(EventProxy),
}
#[derive(Debug, PartialEq)]
pub enum EventProxy {
DpiChangedProxy {
window_id: id,
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> {
// guaranteed to be on main thread
unsafe { monitor::uiscreens() }
}
pub fn primary_monitor(&self) -> Option<RootMonitorHandle> {
// guaranteed to be on main thread
let monitor = unsafe { monitor::main_uiscreen() };
Some(RootMonitorHandle { inner: monitor })
}
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> {
static mut SINGLETON_INIT: bool = false;
unsafe {
assert_main_thread!("`EventLoop` can only be created on the main thread on iOS");
assert!(
!SINGLETON_INIT,
"Only one `EventLoop` is supported on iOS. \
`EventLoopProxy` might be helpful"
);
SINGLETON_INIT = true;
view::create_delegate_class();
}
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: *mut c_void = msg_send![class!(UIApplication), sharedApplication];
assert_eq!(
application,
ptr::null_mut(),
"\
`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,
}));
UIApplicationMain(
0,
ptr::null(),
nil,
NSStringRust::alloc(nil).init_str("AppDelegate"),
);
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 {
// guaranteed to be on main thread
unsafe { self::get_idiom() }
}
}
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(_: *mut 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();
// we want all the members of context to be zero/null, except one
let mut context: CFRunLoopSourceContext = mem::zeroed();
context.perform = Some(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(),
kCFRunLoopEntry => unimplemented!(), // not expected to ever happen
_ => 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(),
kCFRunLoopEntry | 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);
}
}
}
// must be called on main thread
pub unsafe fn get_idiom() -> Idiom {
let device: id = msg_send![class!(UIDevice), currentDevice];
let raw_idiom: UIUserInterfaceIdiom = msg_send![device, userInterfaceIdiom];
raw_idiom.into()
}

View File

@@ -0,0 +1,392 @@
#![allow(non_camel_case_types, non_snake_case, non_upper_case_globals)]
use std::{convert::TryInto, ffi::CString, ops::BitOr, os::raw::*};
use objc::{runtime::Object, Encode, Encoding};
use crate::{
dpi::LogicalSize,
platform::ios::{Idiom, ScreenEdge, ValidOrientations},
};
pub type id = *mut Object;
pub const nil: id = 0 as id;
#[cfg(target_pointer_width = "32")]
pub type CGFloat = f32;
#[cfg(target_pointer_width = "64")]
pub type CGFloat = f64;
pub type NSInteger = isize;
pub type NSUInteger = usize;
#[repr(C)]
#[derive(Clone, Debug)]
pub struct NSOperatingSystemVersion {
pub major: NSInteger,
pub minor: NSInteger,
pub patch: NSInteger,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct CGPoint {
pub x: CGFloat,
pub y: CGFloat,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct CGSize {
pub width: CGFloat,
pub height: CGFloat,
}
impl CGSize {
pub fn new(size: LogicalSize<f64>) -> CGSize {
CGSize {
width: size.width as _,
height: size.height as _,
}
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct CGRect {
pub origin: CGPoint,
pub size: CGSize,
}
impl CGRect {
pub fn new(origin: CGPoint, size: CGSize) -> CGRect {
CGRect { origin, size }
}
}
unsafe impl Encode for CGRect {
fn encode() -> Encoding {
unsafe {
if cfg!(target_pointer_width = "32") {
Encoding::from_str("{CGRect={CGPoint=ff}{CGSize=ff}}")
} else if cfg!(target_pointer_width = "64") {
Encoding::from_str("{CGRect={CGPoint=dd}{CGSize=dd}}")
} else {
unimplemented!()
}
}
}
}
#[derive(Debug)]
#[allow(dead_code)]
#[repr(isize)]
pub enum UITouchPhase {
Began = 0,
Moved,
Stationary,
Ended,
Cancelled,
}
#[derive(Debug, PartialEq, Eq)]
#[allow(dead_code)]
#[repr(isize)]
pub enum UIForceTouchCapability {
Unknown = 0,
Unavailable,
Available,
}
#[derive(Debug, PartialEq, Eq)]
#[allow(dead_code)]
#[repr(isize)]
pub enum UITouchType {
Direct = 0,
Indirect,
Pencil,
}
#[repr(C)]
#[derive(Debug, Clone)]
pub struct UIEdgeInsets {
pub top: CGFloat,
pub left: CGFloat,
pub bottom: CGFloat,
pub right: CGFloat,
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct UIUserInterfaceIdiom(NSInteger);
unsafe impl Encode for UIUserInterfaceIdiom {
fn encode() -> Encoding {
NSInteger::encode()
}
}
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)]
pub struct UIInterfaceOrientationMask(NSUInteger);
unsafe impl Encode for UIInterfaceOrientationMask {
fn encode() -> Encoding {
NSUInteger::encode()
}
}
impl UIInterfaceOrientationMask {
pub const Portrait: UIInterfaceOrientationMask = UIInterfaceOrientationMask(1 << 1);
pub const PortraitUpsideDown: UIInterfaceOrientationMask = UIInterfaceOrientationMask(1 << 2);
pub const LandscapeLeft: UIInterfaceOrientationMask = UIInterfaceOrientationMask(1 << 4);
pub const LandscapeRight: UIInterfaceOrientationMask = UIInterfaceOrientationMask(1 << 3);
pub const Landscape: UIInterfaceOrientationMask =
UIInterfaceOrientationMask(Self::LandscapeLeft.0 | Self::LandscapeRight.0);
pub const AllButUpsideDown: UIInterfaceOrientationMask =
UIInterfaceOrientationMask(Self::Landscape.0 | Self::Portrait.0);
pub const All: UIInterfaceOrientationMask =
UIInterfaceOrientationMask(Self::AllButUpsideDown.0 | Self::PortraitUpsideDown.0);
}
impl BitOr for UIInterfaceOrientationMask {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
UIInterfaceOrientationMask(self.0 | rhs.0)
}
}
impl UIInterfaceOrientationMask {
pub fn from_valid_orientations_idiom(
valid_orientations: ValidOrientations,
idiom: Idiom,
) -> UIInterfaceOrientationMask {
match (valid_orientations, idiom) {
(ValidOrientations::LandscapeAndPortrait, Idiom::Phone) => {
UIInterfaceOrientationMask::AllButUpsideDown
}
(ValidOrientations::LandscapeAndPortrait, _) => UIInterfaceOrientationMask::All,
(ValidOrientations::Landscape, _) => UIInterfaceOrientationMask::Landscape,
(ValidOrientations::Portrait, Idiom::Phone) => UIInterfaceOrientationMask::Portrait,
(ValidOrientations::Portrait, _) => {
UIInterfaceOrientationMask::Portrait
| UIInterfaceOrientationMask::PortraitUpsideDown
}
}
}
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct UIRectEdge(NSUInteger);
unsafe impl Encode for UIRectEdge {
fn encode() -> Encoding {
NSUInteger::encode()
}
}
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`")
}
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct UIScreenOverscanCompensation(NSInteger);
unsafe impl Encode for UIScreenOverscanCompensation {
fn encode() -> Encoding {
NSInteger::encode()
}
}
#[allow(dead_code)]
impl UIScreenOverscanCompensation {
pub const Scale: UIScreenOverscanCompensation = UIScreenOverscanCompensation(0);
pub const InsetBounds: UIScreenOverscanCompensation = UIScreenOverscanCompensation(1);
pub const None: UIScreenOverscanCompensation = UIScreenOverscanCompensation(2);
}
#[link(name = "UIKit", kind = "framework")]
#[link(name = "CoreFoundation", kind = "framework")]
extern "C" {
pub static kCFRunLoopDefaultMode: CFRunLoopMode;
pub static kCFRunLoopCommonModes: CFRunLoopMode;
pub fn UIApplicationMain(
argc: c_int,
argv: *const c_char,
principalClassName: id,
delegateClassName: id,
) -> c_int;
pub fn CFRunLoopGetMain() -> CFRunLoopRef;
pub fn CFRunLoopWakeUp(rl: CFRunLoopRef);
pub fn CFRunLoopObserverCreate(
allocator: CFAllocatorRef,
activities: CFOptionFlags,
repeats: Boolean,
order: CFIndex,
callout: CFRunLoopObserverCallBack,
context: *mut CFRunLoopObserverContext,
) -> CFRunLoopObserverRef;
pub fn CFRunLoopAddObserver(
rl: CFRunLoopRef,
observer: CFRunLoopObserverRef,
mode: CFRunLoopMode,
);
pub fn CFRunLoopTimerCreate(
allocator: CFAllocatorRef,
fireDate: CFAbsoluteTime,
interval: CFTimeInterval,
flags: CFOptionFlags,
order: CFIndex,
callout: CFRunLoopTimerCallBack,
context: *mut CFRunLoopTimerContext,
) -> CFRunLoopTimerRef;
pub fn CFRunLoopAddTimer(rl: CFRunLoopRef, timer: CFRunLoopTimerRef, mode: CFRunLoopMode);
pub fn CFRunLoopTimerSetNextFireDate(timer: CFRunLoopTimerRef, fireDate: CFAbsoluteTime);
pub fn CFRunLoopTimerInvalidate(time: CFRunLoopTimerRef);
pub fn CFRunLoopSourceCreate(
allocator: CFAllocatorRef,
order: CFIndex,
context: *mut CFRunLoopSourceContext,
) -> CFRunLoopSourceRef;
pub fn CFRunLoopAddSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFRunLoopMode);
pub fn CFRunLoopSourceInvalidate(source: CFRunLoopSourceRef);
pub fn CFRunLoopSourceSignal(source: CFRunLoopSourceRef);
pub fn CFAbsoluteTimeGetCurrent() -> CFAbsoluteTime;
pub fn CFRelease(cftype: *const c_void);
}
pub type Boolean = u8;
pub enum CFAllocator {}
pub type CFAllocatorRef = *mut CFAllocator;
pub enum CFRunLoop {}
pub type CFRunLoopRef = *mut CFRunLoop;
pub type CFRunLoopMode = CFStringRef;
pub enum CFRunLoopObserver {}
pub type CFRunLoopObserverRef = *mut CFRunLoopObserver;
pub enum CFRunLoopTimer {}
pub type CFRunLoopTimerRef = *mut CFRunLoopTimer;
pub enum CFRunLoopSource {}
pub type CFRunLoopSourceRef = *mut CFRunLoopSource;
pub enum CFString {}
pub type CFStringRef = *const CFString;
pub type CFHashCode = c_ulong;
pub type CFIndex = c_long;
pub type CFOptionFlags = c_ulong;
pub type CFRunLoopActivity = CFOptionFlags;
pub type CFAbsoluteTime = CFTimeInterval;
pub type CFTimeInterval = f64;
pub const kCFRunLoopEntry: CFRunLoopActivity = 0;
pub const kCFRunLoopBeforeWaiting: CFRunLoopActivity = 1 << 5;
pub const kCFRunLoopAfterWaiting: CFRunLoopActivity = 1 << 6;
pub const kCFRunLoopExit: CFRunLoopActivity = 1 << 7;
pub type CFRunLoopObserverCallBack =
extern "C" fn(observer: CFRunLoopObserverRef, activity: CFRunLoopActivity, info: *mut c_void);
pub type CFRunLoopTimerCallBack = extern "C" fn(timer: CFRunLoopTimerRef, info: *mut c_void);
pub enum CFRunLoopObserverContext {}
pub enum CFRunLoopTimerContext {}
#[repr(C)]
pub struct CFRunLoopSourceContext {
pub version: CFIndex,
pub info: *mut c_void,
pub retain: Option<extern "C" fn(*const c_void) -> *const c_void>,
pub release: Option<extern "C" fn(*const c_void)>,
pub copyDescription: Option<extern "C" fn(*const c_void) -> CFStringRef>,
pub equal: Option<extern "C" fn(*const c_void, *const c_void) -> Boolean>,
pub hash: Option<extern "C" fn(*const c_void) -> CFHashCode>,
pub schedule: Option<extern "C" fn(*mut c_void, CFRunLoopRef, CFRunLoopMode)>,
pub cancel: Option<extern "C" fn(*mut c_void, CFRunLoopRef, CFRunLoopMode)>,
pub perform: Option<extern "C" fn(*mut c_void)>,
}
// This is named NSStringRust rather than NSString because the "Debug View Heirarchy" feature of
// Xcode requires a non-ambiguous reference to NSString for unclear reasons. This makes Xcode happy
// so please test if you change the name back to NSString.
pub trait NSStringRust: Sized {
unsafe fn alloc(_: Self) -> id {
msg_send![class!(NSString), alloc]
}
unsafe fn initWithUTF8String_(self, c_string: *const c_char) -> id;
unsafe fn stringByAppendingString_(self, other: id) -> id;
unsafe fn init_str(self, string: &str) -> Self;
unsafe fn UTF8String(self) -> *const c_char;
}
impl NSStringRust for id {
unsafe fn initWithUTF8String_(self, c_string: *const c_char) -> id {
msg_send![self, initWithUTF8String: c_string as id]
}
unsafe fn stringByAppendingString_(self, other: id) -> id {
msg_send![self, stringByAppendingString: other]
}
unsafe fn init_str(self, string: &str) -> id {
let cstring = CString::new(string).unwrap();
self.initWithUTF8String_(cstring.as_ptr())
}
unsafe fn UTF8String(self) -> *const c_char {
msg_send![self, UTF8String]
}
}

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