mirror of
https://github.com/rust-windowing/winit.git
synced 2026-06-27 07:03:15 -04:00
Compare commits
34 Commits
request-ig
...
v0.19.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8119a7df13 | ||
|
|
5c02c20b05 | ||
|
|
744913d482 | ||
|
|
7dc48ed9ef | ||
|
|
30c0058a88 | ||
|
|
8794157370 | ||
|
|
1a92c46ad7 | ||
|
|
22288ec4c1 | ||
|
|
ffa6815321 | ||
|
|
8ddc7fdaf6 | ||
|
|
594cd18567 | ||
|
|
4469f29e70 | ||
|
|
4e5321b0aa | ||
|
|
4b2e9da4e4 | ||
|
|
b94572621a | ||
|
|
7203ec45b5 | ||
|
|
fc835f383b | ||
|
|
2f9607694f | ||
|
|
cd5caf6a22 | ||
|
|
8522071c2c | ||
|
|
dfa972eab1 | ||
|
|
69585fe2f2 | ||
|
|
c0b2cad3f9 | ||
|
|
57680d2d17 | ||
|
|
0019ff210c | ||
|
|
4a103387e5 | ||
|
|
b6ca584ecf | ||
|
|
e0340d52b0 | ||
|
|
f928a4b917 | ||
|
|
c5d22fda2b | ||
|
|
9ea2810b46 | ||
|
|
9a23ec3c37 | ||
|
|
84c812e568 | ||
|
|
f0ce5b0c8d |
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -2,3 +2,4 @@
|
|||||||
- [ ] Added an entry to `CHANGELOG.md` if knowledge of this change could be valuable to users
|
- [ ] 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
|
- [ ] Updated documentation to reflect any user-facing changes, including notes of platform-specific behavior
|
||||||
- [ ] Created an example program if it would help users understand this functionality
|
- [ ] Created 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
|
||||||
|
|||||||
2
.gitmodules
vendored
2
.gitmodules
vendored
@@ -1,3 +1,3 @@
|
|||||||
[submodule "deps/apk-builder"]
|
[submodule "deps/apk-builder"]
|
||||||
path = deps/apk-builder
|
path = deps/apk-builder
|
||||||
url = https://github.com/tomaka/android-rs-glue
|
url = https://github.com/rust-windowing/android-rs-glue
|
||||||
|
|||||||
24
CHANGELOG.md
24
CHANGELOG.md
@@ -1,12 +1,36 @@
|
|||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
# Version 0.19.2 (2019-07-29)
|
||||||
|
|
||||||
|
- 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.
|
||||||
|
|
||||||
|
# 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 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
|
- On Wayland, add `set_wayland_theme()` to control client decoration color theme
|
||||||
- Added serde serialization to `os::unix::XWindowType`.
|
- Added serde serialization to `os::unix::XWindowType`.
|
||||||
- **Breaking:** `image` crate upgraded to 0.21. This is exposed as part of the `icon_loading` API.
|
- **Breaking:** `image` crate upgraded to 0.21. This is exposed as part of the `icon_loading` API.
|
||||||
|
- 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.
|
- On Windows, fix malformed function pointer typecast that could invoke undefined behavior.
|
||||||
- Refactored Windows state/flag-setting code.
|
- 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, 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, 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.
|
||||||
|
- 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
|
||||||
|
|
||||||
# Version 0.18.1 (2018-12-30)
|
# Version 0.18.1 (2018-12-30)
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,14 @@
|
|||||||
|
# PLEASE MAKE PRs AGAINST THE `eventloop-2.0` BRANCH.
|
||||||
|
|
||||||
|
All development work for our next version is being done against that branch. Refer to [#459](https://github.com/rust-windowing/winit/issues/459) and [the associated milestone](https://github.com/rust-windowing/winit/milestone/2) for details on what that branch changes.
|
||||||
|
|
||||||
# Winit Contributing Guidelines
|
# Winit Contributing Guidelines
|
||||||
|
|
||||||
## Scope
|
## 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.
|
||||||
|
|
||||||
Winit aims to provide a generic platform abstracting the main graphic platforms (Windows, macOS, X11,
|
|
||||||
Wayland, Android, iOS and the web platform via Emscripten).
|
|
||||||
|
|
||||||
Most platforms expose capabilities that cannot be meaningfully transposed to the others. Winit does not
|
|
||||||
aim to support every single functionality of every platform, but rather to abstract the set of
|
|
||||||
capabilities that is common to all platforms. In this context, APIs exposed in winit can be split into
|
|
||||||
different "support levels":
|
|
||||||
|
|
||||||
- Tier 1: features which are in the main scope of winit. They are part of the common API of winit, and
|
|
||||||
are taken care of by the maintainers. Any part of these features that is not working correctly is
|
|
||||||
considered a bug in winit.
|
|
||||||
- Tier 2: some platform-specific features can be sufficiently fundamental to the platform that winit can
|
|
||||||
integrate support for them in the platform-specific part of the API. These features are not considered
|
|
||||||
directly handled by the maintainers of winit. If you have a strong incentive to have such a feature
|
|
||||||
integrated in winit, consider implementing it and proposing yourself to maintain it in the future.
|
|
||||||
- Tier 3: these features are not directly exposed by winit, but rather can be implemented using the
|
|
||||||
raw handles to the underlying platform that winit exposes. If your feature of interest is rather
|
|
||||||
niche, this is probably where it belongs.
|
|
||||||
|
|
||||||
The exact list of supported Tier 1 features is tracked in this issue:
|
|
||||||
[#252](https://github.com/tomaka/winit/issues/252).
|
|
||||||
|
|
||||||
## Reporting an issue
|
## Reporting an issue
|
||||||
|
|
||||||
@@ -44,6 +30,9 @@ When making a code contribution to winit, before opening your pull request, plea
|
|||||||
- you left comments in your code explaining any part that is not straightforward, so that the
|
- 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
|
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
|
- your PR adds an entry to the changelog file if the introduced change is relevant to winit users
|
||||||
|
- 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
|
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
|
is that a PR must be approved by at least two maintainers of winit before being merged, including
|
||||||
@@ -56,15 +45,14 @@ backends of winit. As such, depending on your platform of interest, your contact
|
|||||||
|
|
||||||
This table summarizes who can be contacted in which case, with the following legend:
|
This table summarizes who can be contacted in which case, with the following legend:
|
||||||
|
|
||||||
- `M`: is a main maintainer for this platform
|
- `M` - Maintainer: is a main maintainer for this platform
|
||||||
- `R`: can review code for this platform
|
- `C` - Collaborator: can review code and address issues on this platform
|
||||||
- `T`: has the ability of testing the platform
|
- `T` - Tester: has the ability of testing the platform
|
||||||
- ` `: knows nothing of this platform
|
- ` `: knows nothing of this platform
|
||||||
|
|
||||||
| Platform | Windows | macOS | X11 | Wayland | Android | iOS | Emscripten |
|
| Platform | Windows | macOS | X11 | Wayland | Android | iOS | Emscripten |
|
||||||
| :--- | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
|
| :--- | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
|
||||||
| @francesca64 | R | M | M | | M | R | |
|
| @mitchmindtree | T | | T | T | | | |
|
||||||
| @mitchmindtree | T | | T | T | | | |
|
| @Osspial | M | | T | T | T | | T |
|
||||||
| @Osspial | M | | T | T | T | | T |
|
| @vberger | | | T | M | | | |
|
||||||
| @vberger | | | T | M | | | |
|
| @mtak- | | T | | | T | M | |
|
||||||
| @mtak- | | T | | | T | M | |
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "winit"
|
name = "winit"
|
||||||
version = "0.18.1"
|
version = "0.19.2"
|
||||||
authors = ["The winit contributors", "Pierre Krieger <pierre.krieger1708@gmail.com>"]
|
authors = ["The winit contributors", "Pierre Krieger <pierre.krieger1708@gmail.com>"]
|
||||||
description = "Cross-platform window creation library."
|
description = "Cross-platform window creation library."
|
||||||
keywords = ["windowing"]
|
keywords = ["windowing"]
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
repository = "https://github.com/tomaka/winit"
|
repository = "https://github.com/rust-windowing/winit"
|
||||||
documentation = "https://docs.rs/winit"
|
documentation = "https://docs.rs/winit"
|
||||||
categories = ["gui"]
|
categories = ["gui"]
|
||||||
|
|
||||||
@@ -66,5 +66,5 @@ features = [
|
|||||||
wayland-client = { version = "0.21", features = [ "dlopen", "egl", "cursor"] }
|
wayland-client = { version = "0.21", features = [ "dlopen", "egl", "cursor"] }
|
||||||
smithay-client-toolkit = "0.4.3"
|
smithay-client-toolkit = "0.4.3"
|
||||||
x11-dl = "2.18.3"
|
x11-dl = "2.18.3"
|
||||||
parking_lot = "0.7"
|
parking_lot = "0.8"
|
||||||
percent-encoding = "1.0"
|
percent-encoding = "2.0"
|
||||||
|
|||||||
209
FEATURES.md
Normal file
209
FEATURES.md
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
# 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 Emscripten
|
||||||
|
- 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.
|
||||||
|
- **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.
|
||||||
|
- **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.
|
||||||
|
|
||||||
|
### 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 grab**: Locking the cursor so it cannot exit the client area of a window.
|
||||||
|
- **Cursor icon**: Changing the cursor icon, or hiding the cursor.
|
||||||
|
- **Touch events**: Single-touch events.
|
||||||
|
- **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 gampads and joysticks.
|
||||||
|
- **Device movement events:**: Capturing input from the device gyroscope and accelerometer.
|
||||||
|
|
||||||
|
## Platform
|
||||||
|
### Windows
|
||||||
|
* Setting the taskbar icon
|
||||||
|
* Setting the parent window
|
||||||
|
* `WS_EX_NOREDIRECTIONBITMAP` support
|
||||||
|
|
||||||
|
### 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
|
||||||
|
|
||||||
|
## 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 |Emscripten|
|
||||||
|
|-------------------------------- | ----- | ---- | ------- | ----------- | ----- | ----- | -------- |
|
||||||
|
|Window initialization |✔️ |✔️ |▢[#5] |✔️ |▢[#33]|▢[#33] |❓ |
|
||||||
|
|Providing pointer to init OpenGL |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |❓ |
|
||||||
|
|Providing pointer to init Vulkan |✔️ |✔️ |✔️ |✔️ |✔️ |❓ |**N/A** |
|
||||||
|
|Window decorations |✔️ |✔️ |✔️ |▢[#306] |**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 |❌ |❌ |❌ |❌ |❌ |❌ |❌ |
|
||||||
|
|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** |
|
||||||
|
|Fullscreen |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|❌ |
|
||||||
|
|Fullscreen toggle |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|❌ |
|
||||||
|
|HiDPI support |✔️ |✔️ |✔️ |✔️ |▢[#721]|✔️ |✔️ |
|
||||||
|
|Popup windows |❌ |❌ |❌ |❌ |❌ |❌ |❌ |
|
||||||
|
|
||||||
|
### System information
|
||||||
|
|Feature |Windows|MacOS |Linux x11|Linux Wayland|Android|iOS |Emscripten|
|
||||||
|
|------------ | ----- | ---- | ------- | ----------- | ----- | ----- | -------- |
|
||||||
|
|Monitor list |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A** |
|
||||||
|
|
||||||
|
### Input handling
|
||||||
|
|Feature |Windows |MacOS |Linux x11|Linux Wayland|Android|iOS |Emscripten|
|
||||||
|
|----------------------- | ----- | ---- | ------- | ----------- | ----- | ----- | -------- |
|
||||||
|
|Mouse events |✔️ |▢[#63] |✔️ |✔️ |**N/A**|**N/A**|✔️ |
|
||||||
|
|Mouse set location |✔️ |✔️ |✔️ |❓ |**N/A**|**N/A**|**N/A** |
|
||||||
|
|Cursor grab |✔️ |▢[#165] |▢[#242] |❌[#306] |**N/A**|**N/A**|✔️ |
|
||||||
|
|Cursor icon |✔️ |✔️ |✔️ |❌[#306] |**N/A**|**N/A**|❌ |
|
||||||
|
|Touch events |✔️ |❌ |✔️ |✔️ |✔️ |✔️ |✔️ |
|
||||||
|
|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 |❓ |❓ |❓ |❓ |❌ |❌ |❌ |
|
||||||
|
|
||||||
|
### 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 |Emscripten|
|
||||||
|
|------------------------------ | ----- | ---- | ------- | ----------- | ----- | ----- | -------- |
|
||||||
|
|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 |Emscripten|
|
||||||
|
|------------------------------ | ----- | ---- | ------- | ----------- | ----- | ----- | -------- |
|
||||||
|
|
||||||
|
[#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
|
||||||
11
HALL_OF_CHAMPIONS.md
Normal file
11
HALL_OF_CHAMPIONS.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# 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.
|
||||||
|
* @francesca64: For taking over the responsibility of maintaining almost every
|
||||||
|
Winit backend, and standardizing HiDPI support across all of them
|
||||||
26
README.md
26
README.md
@@ -1,17 +1,35 @@
|
|||||||
|
# This branch has been archived
|
||||||
|
|
||||||
|
Please direct all work against `master`.
|
||||||
|
|
||||||
|
--------
|
||||||
|
|
||||||
# winit - Cross-platform window creation and management in Rust
|
# winit - Cross-platform window creation and management in Rust
|
||||||
|
|
||||||
[](https://crates.io/crates/winit)
|
[](https://crates.io/crates/winit)
|
||||||
[](https://docs.rs/winit)
|
[](https://docs.rs/winit)
|
||||||
[](https://travis-ci.org/tomaka/winit)
|
[](https://travis-ci.org/rust-windowing/winit)
|
||||||
[](https://ci.appveyor.com/project/tomaka/winit/branch/master)
|
[](https://ci.appveyor.com/project/Osspial/winit/branch/master)
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
winit = "0.18.1"
|
winit = "0.19.2"
|
||||||
```
|
```
|
||||||
|
|
||||||
## [Documentation](https://docs.rs/winit)
|
## [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:
|
||||||
|
|
||||||
|
[](http://webchat.freenode.net?channels=%23glutin&uio=MTY9dHJ1ZSYyPXRydWUmND10cnVlJjExPTE4NSYxMj10cnVlJjE1PXRydWU7a)
|
||||||
|
[](https://matrix.to/#/#Glutin:matrix.org)
|
||||||
|
[](https://gitter.im/tomaka/glutin?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Winit is a window creation and management library. It can create windows and lets you handle
|
Winit is a window creation and management library. It can create windows and lets you handle
|
||||||
|
|||||||
@@ -82,6 +82,15 @@ fn main() {
|
|||||||
window.set_fullscreen(Some(window.get_current_monitor()));
|
window.set_fullscreen(Some(window.get_current_monitor()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(winit::VirtualKeyCode::S, winit::ElementState::Pressed) => {
|
||||||
|
println!("window.get_fullscreen {:?}", window.get_fullscreen());
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
{
|
||||||
|
use winit::os::macos::WindowExt;
|
||||||
|
println!("window.get_simple_fullscreen {:?}", WindowExt::get_simple_fullscreen(&window));
|
||||||
|
}
|
||||||
|
}
|
||||||
(winit::VirtualKeyCode::M, winit::ElementState::Pressed) => {
|
(winit::VirtualKeyCode::M, winit::ElementState::Pressed) => {
|
||||||
is_maximized = !is_maximized;
|
is_maximized = !is_maximized;
|
||||||
window.set_maximized(is_maximized);
|
window.set_maximized(is_maximized);
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ pub trait WindowExt {
|
|||||||
/// - `true`: the dock icon will bounce until the application is focused.
|
/// - `true`: the dock icon will bounce until the application is focused.
|
||||||
fn request_user_attention(&self, is_critical: bool);
|
fn request_user_attention(&self, is_critical: bool);
|
||||||
|
|
||||||
|
/// Returns whether or not the window is in simple fullscreen mode.
|
||||||
|
fn get_simple_fullscreen(&self) -> bool;
|
||||||
|
|
||||||
/// Toggles a fullscreen mode that doesn't require a new macOS space.
|
/// Toggles a fullscreen mode that doesn't require a new macOS space.
|
||||||
/// Returns a boolean indicating whether the transition was successful (this
|
/// Returns a boolean indicating whether the transition was successful (this
|
||||||
/// won't work if the window was already in the native fullscreen).
|
/// won't work if the window was already in the native fullscreen).
|
||||||
@@ -49,6 +52,11 @@ impl WindowExt for Window {
|
|||||||
self.window.request_user_attention(is_critical)
|
self.window.request_user_attention(is_critical)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_simple_fullscreen(&self) -> bool {
|
||||||
|
self.window.get_simple_fullscreen()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn set_simple_fullscreen(&self, fullscreen: bool) -> bool {
|
fn set_simple_fullscreen(&self, fullscreen: bool) -> bool {
|
||||||
self.window.set_simple_fullscreen(fullscreen)
|
self.window.set_simple_fullscreen(fullscreen)
|
||||||
|
|||||||
@@ -113,6 +113,13 @@ pub trait EventsLoopExt {
|
|||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
fn get_xlib_xconnection(&self) -> Option<Arc<XConnection>>;
|
fn get_xlib_xconnection(&self) -> Option<Arc<XConnection>>;
|
||||||
|
|
||||||
|
/// Returns a pointer to the `wl_display` object of wayland that is used by this `EventsLoop`.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the `EventsLoop` doesn't use wayland (if it uses xlib for example).
|
||||||
|
///
|
||||||
|
/// The pointer will become invalid when the glutin `EventsLoop` is destroyed.
|
||||||
|
fn get_wayland_display(&self) -> Option<*mut raw::c_void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventsLoopExt for EventsLoop {
|
impl EventsLoopExt for EventsLoop {
|
||||||
@@ -152,6 +159,14 @@ impl EventsLoopExt for EventsLoop {
|
|||||||
fn get_xlib_xconnection(&self) -> Option<Arc<XConnection>> {
|
fn get_xlib_xconnection(&self) -> Option<Arc<XConnection>> {
|
||||||
self.events_loop.x_connection().cloned()
|
self.events_loop.x_connection().cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_wayland_display(&self) -> Option<*mut raw::c_void> {
|
||||||
|
match self.events_loop {
|
||||||
|
LinuxEventsLoop::Wayland(ref e) => Some(e.get_display().c_ptr() as *mut _),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Additional methods on `Window` that are specific to Unix.
|
/// Additional methods on `Window` that are specific to Unix.
|
||||||
|
|||||||
@@ -368,6 +368,13 @@ impl Window {
|
|||||||
// Android has single screen maximized apps so nothing to do
|
// Android has single screen maximized apps so nothing to do
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_fullscreen(&self) -> Option<RootMonitorId> {
|
||||||
|
// N/A
|
||||||
|
// Android has single screen maximized apps so nothing to do
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_fullscreen(&self, _monitor: Option<RootMonitorId>) {
|
pub fn set_fullscreen(&self, _monitor: Option<RootMonitorId>) {
|
||||||
// N/A
|
// N/A
|
||||||
|
|||||||
@@ -580,6 +580,11 @@ impl Window {
|
|||||||
// iOS has single screen maximized apps so nothing to do
|
// iOS has single screen maximized apps so nothing to do
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_fullscreen(&self) -> Option<::MonitorId> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_fullscreen(&self, _monitor: Option<::MonitorId>) {
|
pub fn set_fullscreen(&self, _monitor: Option<::MonitorId>) {
|
||||||
// iOS has single screen maximized apps so nothing to do
|
// iOS has single screen maximized apps so nothing to do
|
||||||
|
|||||||
@@ -473,6 +473,13 @@ impl Window {
|
|||||||
// iOS has single screen maximized apps so nothing to do
|
// iOS has single screen maximized apps so nothing to do
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_fullscreen(&self) -> Option<RootMonitorId> {
|
||||||
|
// N/A
|
||||||
|
// iOS has single screen maximized apps so nothing to do
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_fullscreen(&self, _monitor: Option<RootMonitorId>) {
|
pub fn set_fullscreen(&self, _monitor: Option<RootMonitorId>) {
|
||||||
// N/A
|
// N/A
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use std::os::raw::{c_void, c_char, c_int};
|
|||||||
pub const RTLD_LAZY: c_int = 0x001;
|
pub const RTLD_LAZY: c_int = 0x001;
|
||||||
pub const RTLD_NOW: c_int = 0x002;
|
pub const RTLD_NOW: c_int = 0x002;
|
||||||
|
|
||||||
#[link="dl"]
|
#[link(name = "dl")]
|
||||||
extern {
|
extern {
|
||||||
pub fn dlopen(filename: *const c_char, flag: c_int) -> *mut c_void;
|
pub fn dlopen(filename: *const c_char, flag: c_int) -> *mut c_void;
|
||||||
pub fn dlerror() -> *mut c_char;
|
pub fn dlerror() -> *mut c_char;
|
||||||
|
|||||||
@@ -301,6 +301,15 @@ impl Window {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_fullscreen(&self) -> Option<RootMonitorId> {
|
||||||
|
match self {
|
||||||
|
&Window::X(ref w) => w.get_fullscreen(),
|
||||||
|
&Window::Wayland(ref w) => w.get_fullscreen()
|
||||||
|
.map(|monitor_id| RootMonitorId { inner: MonitorId::Wayland(monitor_id) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_fullscreen(&self, monitor: Option<RootMonitorId>) {
|
pub fn set_fullscreen(&self, monitor: Option<RootMonitorId>) {
|
||||||
match self {
|
match self {
|
||||||
|
|||||||
@@ -229,6 +229,10 @@ impl EventsLoop {
|
|||||||
pub fn get_available_monitors(&self) -> VecDeque<MonitorId> {
|
pub fn get_available_monitors(&self) -> VecDeque<MonitorId> {
|
||||||
get_available_monitors(&self.env.outputs)
|
get_available_monitors(&self.env.outputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_display(&self) -> &Display {
|
||||||
|
&*self.display
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -312,6 +312,13 @@ fn keysym_to_vkey(keysym: u32) -> Option<VirtualKeyCode> {
|
|||||||
keysyms::XKB_KEY_KP_Separator => Some(VirtualKeyCode::NumpadComma),
|
keysyms::XKB_KEY_KP_Separator => Some(VirtualKeyCode::NumpadComma),
|
||||||
keysyms::XKB_KEY_KP_Enter => Some(VirtualKeyCode::NumpadEnter),
|
keysyms::XKB_KEY_KP_Enter => Some(VirtualKeyCode::NumpadEnter),
|
||||||
keysyms::XKB_KEY_KP_Equal => Some(VirtualKeyCode::NumpadEquals),
|
keysyms::XKB_KEY_KP_Equal => Some(VirtualKeyCode::NumpadEquals),
|
||||||
|
keysyms::XKB_KEY_KP_Add => Some(VirtualKeyCode::Add),
|
||||||
|
keysyms::XKB_KEY_KP_Subtract => Some(VirtualKeyCode::Subtract),
|
||||||
|
keysyms::XKB_KEY_KP_Divide => Some(VirtualKeyCode::Divide),
|
||||||
|
keysyms::XKB_KEY_KP_Page_Up => Some(VirtualKeyCode::PageUp),
|
||||||
|
keysyms::XKB_KEY_KP_Page_Down => Some(VirtualKeyCode::PageDown),
|
||||||
|
keysyms::XKB_KEY_KP_Home => Some(VirtualKeyCode::Home),
|
||||||
|
keysyms::XKB_KEY_KP_End => Some(VirtualKeyCode::End),
|
||||||
// => Some(VirtualKeyCode::OEM102),
|
// => Some(VirtualKeyCode::OEM102),
|
||||||
// => Some(VirtualKeyCode::Period),
|
// => Some(VirtualKeyCode::Period),
|
||||||
// => Some(VirtualKeyCode::Playpause),
|
// => Some(VirtualKeyCode::Playpause),
|
||||||
|
|||||||
@@ -16,21 +16,9 @@ mod window;
|
|||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct DeviceId;
|
pub struct DeviceId;
|
||||||
|
|
||||||
impl DeviceId {
|
|
||||||
pub unsafe fn dummy() -> Self {
|
|
||||||
DeviceId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct WindowId(usize);
|
pub struct WindowId(usize);
|
||||||
|
|
||||||
impl WindowId {
|
|
||||||
pub unsafe fn dummy() -> Self {
|
|
||||||
WindowId(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn make_wid(s: &Proxy<wl_surface::WlSurface>) -> WindowId {
|
fn make_wid(s: &Proxy<wl_surface::WlSurface>) -> WindowId {
|
||||||
WindowId(s.c_ptr() as usize)
|
WindowId(s.c_ptr() as usize)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use platform::{MonitorId as PlatformMonitorId, PlatformSpecificWindowBuilderAttr
|
|||||||
use window::MonitorId as RootMonitorId;
|
use window::MonitorId as RootMonitorId;
|
||||||
|
|
||||||
use sctk::surface::{get_dpi_factor, get_outputs};
|
use sctk::surface::{get_dpi_factor, get_outputs};
|
||||||
use sctk::window::{ConceptFrame, Event as WEvent, Window as SWindow, Theme};
|
use sctk::window::{ConceptFrame, Event as WEvent, State as WState, Window as SWindow, Theme};
|
||||||
use sctk::reexports::client::{Display, Proxy};
|
use sctk::reexports::client::{Display, Proxy};
|
||||||
use sctk::reexports::client::protocol::{wl_seat, wl_surface};
|
use sctk::reexports::client::protocol::{wl_seat, wl_surface};
|
||||||
use sctk::reexports::client::protocol::wl_surface::RequestsTrait as SurfaceRequests;
|
use sctk::reexports::client::protocol::wl_surface::RequestsTrait as SurfaceRequests;
|
||||||
@@ -24,6 +24,7 @@ pub struct Window {
|
|||||||
kill_switch: (Arc<Mutex<bool>>, Arc<Mutex<bool>>),
|
kill_switch: (Arc<Mutex<bool>>, Arc<Mutex<bool>>),
|
||||||
display: Arc<Display>,
|
display: Arc<Display>,
|
||||||
need_frame_refresh: Arc<Mutex<bool>>,
|
need_frame_refresh: Arc<Mutex<bool>>,
|
||||||
|
fullscreen: Arc<Mutex<bool>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
@@ -31,6 +32,7 @@ impl Window {
|
|||||||
let (width, height) = attributes.dimensions.map(Into::into).unwrap_or((800, 600));
|
let (width, height) = attributes.dimensions.map(Into::into).unwrap_or((800, 600));
|
||||||
// Create the window
|
// Create the window
|
||||||
let size = Arc::new(Mutex::new((width, height)));
|
let size = Arc::new(Mutex::new((width, height)));
|
||||||
|
let fullscreen = Arc::new(Mutex::new(false));
|
||||||
|
|
||||||
let window_store = evlp.store.clone();
|
let window_store = evlp.store.clone();
|
||||||
let surface = evlp.env.create_surface(move |dpi, surface| {
|
let surface = evlp.env.create_surface(move |dpi, surface| {
|
||||||
@@ -45,12 +47,15 @@ impl Window {
|
|||||||
surface.clone(),
|
surface.clone(),
|
||||||
(width, height),
|
(width, height),
|
||||||
move |event| match event {
|
move |event| match event {
|
||||||
WEvent::Configure { new_size, .. } => {
|
WEvent::Configure { new_size, states } => {
|
||||||
let mut store = window_store.lock().unwrap();
|
let mut store = window_store.lock().unwrap();
|
||||||
|
let is_fullscreen = states.contains(&WState::Fullscreen);
|
||||||
|
|
||||||
for window in &mut store.windows {
|
for window in &mut store.windows {
|
||||||
if window.surface.equals(&my_surface) {
|
if window.surface.equals(&my_surface) {
|
||||||
window.newsize = new_size;
|
window.newsize = new_size;
|
||||||
window.need_refresh = true;
|
window.need_refresh = true;
|
||||||
|
*(window.fullscreen.lock().unwrap()) = is_fullscreen;
|
||||||
*(window.need_frame_refresh.lock().unwrap()) = true;
|
*(window.need_frame_refresh.lock().unwrap()) = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -81,6 +86,8 @@ impl Window {
|
|||||||
frame.set_app_id(app_id);
|
frame.set_app_id(app_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frame.set_title(attributes.title);
|
||||||
|
|
||||||
for &(_, ref seat) in evlp.seats.lock().unwrap().iter() {
|
for &(_, ref seat) in evlp.seats.lock().unwrap().iter() {
|
||||||
frame.new_seat(seat);
|
frame.new_seat(seat);
|
||||||
}
|
}
|
||||||
@@ -112,6 +119,7 @@ impl Window {
|
|||||||
closed: false,
|
closed: false,
|
||||||
newsize: None,
|
newsize: None,
|
||||||
size: size.clone(),
|
size: size.clone(),
|
||||||
|
fullscreen: fullscreen.clone(),
|
||||||
need_refresh: false,
|
need_refresh: false,
|
||||||
need_frame_refresh: need_frame_refresh.clone(),
|
need_frame_refresh: need_frame_refresh.clone(),
|
||||||
surface: surface.clone(),
|
surface: surface.clone(),
|
||||||
@@ -130,6 +138,7 @@ impl Window {
|
|||||||
size: size,
|
size: size,
|
||||||
kill_switch: (kill_switch, evlp.cleanup_needed.clone()),
|
kill_switch: (kill_switch, evlp.cleanup_needed.clone()),
|
||||||
need_frame_refresh: need_frame_refresh,
|
need_frame_refresh: need_frame_refresh,
|
||||||
|
fullscreen: fullscreen,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,6 +230,14 @@ impl Window {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_fullscreen(&self) -> Option<MonitorId> {
|
||||||
|
if *(self.fullscreen.lock().unwrap()) {
|
||||||
|
Some(self.get_current_monitor())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_fullscreen(&self, monitor: Option<RootMonitorId>) {
|
pub fn set_fullscreen(&self, monitor: Option<RootMonitorId>) {
|
||||||
if let Some(RootMonitorId {
|
if let Some(RootMonitorId {
|
||||||
inner: PlatformMonitorId::Wayland(ref monitor_id),
|
inner: PlatformMonitorId::Wayland(ref monitor_id),
|
||||||
@@ -300,6 +317,7 @@ struct InternalWindow {
|
|||||||
surface: Proxy<wl_surface::WlSurface>,
|
surface: Proxy<wl_surface::WlSurface>,
|
||||||
newsize: Option<(u32, u32)>,
|
newsize: Option<(u32, u32)>,
|
||||||
size: Arc<Mutex<(u32, u32)>>,
|
size: Arc<Mutex<(u32, u32)>>,
|
||||||
|
fullscreen: Arc<Mutex<bool>>,
|
||||||
need_refresh: bool,
|
need_refresh: bool,
|
||||||
need_frame_refresh: Arc<Mutex<bool>>,
|
need_frame_refresh: Arc<Mutex<bool>>,
|
||||||
closed: bool,
|
closed: bool,
|
||||||
|
|||||||
@@ -82,11 +82,11 @@ pub fn keysym_to_element(keysym: libc::c_uint) -> Option<VirtualKeyCode> {
|
|||||||
ffi::XK_KP_Delete => events::VirtualKeyCode::Delete,
|
ffi::XK_KP_Delete => events::VirtualKeyCode::Delete,
|
||||||
ffi::XK_KP_Equal => events::VirtualKeyCode::NumpadEquals,
|
ffi::XK_KP_Equal => events::VirtualKeyCode::NumpadEquals,
|
||||||
//ffi::XK_KP_Multiply => events::VirtualKeyCode::NumpadMultiply,
|
//ffi::XK_KP_Multiply => events::VirtualKeyCode::NumpadMultiply,
|
||||||
//ffi::XK_KP_Add => events::VirtualKeyCode::NumpadAdd,
|
ffi::XK_KP_Add => events::VirtualKeyCode::Add,
|
||||||
//ffi::XK_KP_Separator => events::VirtualKeyCode::Kp_separator,
|
//ffi::XK_KP_Separator => events::VirtualKeyCode::Kp_separator,
|
||||||
//ffi::XK_KP_Subtract => events::VirtualKeyCode::NumpadSubtract,
|
ffi::XK_KP_Subtract => events::VirtualKeyCode::Subtract,
|
||||||
//ffi::XK_KP_Decimal => events::VirtualKeyCode::Kp_decimal,
|
//ffi::XK_KP_Decimal => events::VirtualKeyCode::Kp_decimal,
|
||||||
//ffi::XK_KP_Divide => events::VirtualKeyCode::NumpadDivide,
|
ffi::XK_KP_Divide => events::VirtualKeyCode::Divide,
|
||||||
ffi::XK_KP_0 => events::VirtualKeyCode::Numpad0,
|
ffi::XK_KP_0 => events::VirtualKeyCode::Numpad0,
|
||||||
ffi::XK_KP_1 => events::VirtualKeyCode::Numpad1,
|
ffi::XK_KP_1 => events::VirtualKeyCode::Numpad1,
|
||||||
ffi::XK_KP_2 => events::VirtualKeyCode::Numpad2,
|
ffi::XK_KP_2 => events::VirtualKeyCode::Numpad2,
|
||||||
|
|||||||
@@ -19,6 +19,13 @@ use std::collections::HashMap;
|
|||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::os::raw::*;
|
use std::os::raw::*;
|
||||||
|
use libc::{select, fd_set, FD_SET, FD_ZERO, FD_ISSET, EINTR, EINVAL, ENOMEM, EBADF};
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
use libc::__errno_location;
|
||||||
|
#[cfg(target_os = "freebsd")]
|
||||||
|
use libc::__error as __errno_location;
|
||||||
|
#[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
|
||||||
|
use libc::__errno as __errno_location;
|
||||||
use std::sync::{Arc, mpsc, Weak};
|
use std::sync::{Arc, mpsc, Weak};
|
||||||
use std::sync::atomic::{self, AtomicBool};
|
use std::sync::atomic::{self, AtomicBool};
|
||||||
|
|
||||||
@@ -185,6 +192,70 @@ impl EventsLoop {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn poll_one_event(&mut self, event_ptr : *mut ffi::XEvent) -> bool {
|
||||||
|
// This function is used to poll and remove a single event
|
||||||
|
// from the Xlib event queue in a non-blocking, atomic way.
|
||||||
|
// XCheckIfEvent is non-blocking and removes events from queue.
|
||||||
|
// XNextEvent can't be used because it blocks while holding the
|
||||||
|
// global Xlib mutex.
|
||||||
|
// XPeekEvent does not remove events from the queue.
|
||||||
|
unsafe extern "C" fn predicate(
|
||||||
|
_display: *mut ffi::Display,
|
||||||
|
_event: *mut ffi::XEvent,
|
||||||
|
_arg : *mut c_char) -> c_int {
|
||||||
|
// This predicate always returns "true" (1) to accept all events
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = (self.xconn.xlib.XCheckIfEvent)(
|
||||||
|
self.xconn.display,
|
||||||
|
event_ptr,
|
||||||
|
Some(predicate),
|
||||||
|
std::ptr::null_mut());
|
||||||
|
|
||||||
|
result != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn wait_for_input(&mut self) {
|
||||||
|
// XNextEvent can not be used in multi-threaded applications
|
||||||
|
// because it is blocking for input while holding the global
|
||||||
|
// Xlib mutex.
|
||||||
|
// To work around this issue, first flush the X11 display, then
|
||||||
|
// use select(2) to wait for input to arrive
|
||||||
|
loop {
|
||||||
|
// First use XFlush to flush any buffered x11 requests
|
||||||
|
(self.xconn.xlib.XFlush)(self.xconn.display);
|
||||||
|
|
||||||
|
// Then use select(2) to wait for input data
|
||||||
|
let mut fds : fd_set = mem::uninitialized();
|
||||||
|
FD_ZERO(&mut fds);
|
||||||
|
FD_SET(self.xconn.x11_fd, &mut fds);
|
||||||
|
let err = select(
|
||||||
|
self.xconn.x11_fd + 1,
|
||||||
|
&mut fds, // read fds
|
||||||
|
std::ptr::null_mut(), // write fds
|
||||||
|
std::ptr::null_mut(), // except fds (could be used to detect errors)
|
||||||
|
std::ptr::null_mut()); // timeout
|
||||||
|
|
||||||
|
if err < 0 {
|
||||||
|
let errno_ptr = __errno_location();
|
||||||
|
let errno = *errno_ptr;
|
||||||
|
|
||||||
|
if errno == EINTR {
|
||||||
|
// try again if errno is EINTR
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(errno == EBADF || errno == EINVAL || errno == ENOMEM);
|
||||||
|
panic!("select(2) returned fatal error condition");
|
||||||
|
}
|
||||||
|
|
||||||
|
if FD_ISSET(self.xconn.x11_fd, &mut fds) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn poll_events<F>(&mut self, mut callback: F)
|
pub fn poll_events<F>(&mut self, mut callback: F)
|
||||||
where F: FnMut(Event)
|
where F: FnMut(Event)
|
||||||
{
|
{
|
||||||
@@ -192,13 +263,9 @@ impl EventsLoop {
|
|||||||
loop {
|
loop {
|
||||||
// Get next event
|
// Get next event
|
||||||
unsafe {
|
unsafe {
|
||||||
// Ensure XNextEvent won't block
|
if !self.poll_one_event(&mut xev) {
|
||||||
let count = (self.xconn.xlib.XPending)(self.xconn.display);
|
|
||||||
if count == 0 {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
(self.xconn.xlib.XNextEvent)(self.xconn.display, &mut xev);
|
|
||||||
}
|
}
|
||||||
self.process_event(&mut xev, &mut callback);
|
self.process_event(&mut xev, &mut callback);
|
||||||
}
|
}
|
||||||
@@ -210,7 +277,12 @@ impl EventsLoop {
|
|||||||
let mut xev = unsafe { mem::uninitialized() };
|
let mut xev = unsafe { mem::uninitialized() };
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
unsafe { (self.xconn.xlib.XNextEvent)(self.xconn.display, &mut xev) }; // Blocks as necessary
|
unsafe {
|
||||||
|
while !self.poll_one_event(&mut xev) {
|
||||||
|
// block until input is available
|
||||||
|
self.wait_for_input();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let mut control_flow = ControlFlow::Continue;
|
let mut control_flow = ControlFlow::Continue;
|
||||||
|
|
||||||
|
|||||||
@@ -131,9 +131,14 @@ impl XConnection {
|
|||||||
fn query_monitor_list(&self) -> Vec<MonitorId> {
|
fn query_monitor_list(&self) -> Vec<MonitorId> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let root = (self.xlib.XDefaultRootWindow)(self.display);
|
let root = (self.xlib.XDefaultRootWindow)(self.display);
|
||||||
// WARNING: this function is supposedly very slow, on the order of hundreds of ms.
|
let resources = if version_is_at_least(1, 3) {
|
||||||
// Upon failure, `resources` will be null.
|
(self.xrandr.XRRGetScreenResourcesCurrent)(self.display, root)
|
||||||
let resources = (self.xrandr.XRRGetScreenResources)(self.display, root);
|
} else {
|
||||||
|
// WARNING: this function is supposedly very slow, on the order of hundreds of ms.
|
||||||
|
// Upon failure, `resources` will be null.
|
||||||
|
(self.xrandr.XRRGetScreenResources)(self.display, root)
|
||||||
|
};
|
||||||
|
|
||||||
if resources.is_null() {
|
if resources.is_null() {
|
||||||
panic!("[winit] `XRRGetScreenResources` returned NULL. That should only happen if the root window doesn't exist.");
|
panic!("[winit] `XRRGetScreenResources` returned NULL. That should only happen if the root window doesn't exist.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ pub fn calc_dpi_factor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// See http://xpra.org/trac/ticket/728 for more information.
|
// See http://xpra.org/trac/ticket/728 for more information.
|
||||||
if width_mm == 0 || width_mm == 0 {
|
if width_mm == 0 || height_mm == 0 {
|
||||||
warn!("XRandR reported that the display's 0mm in size, which is certifiably insane");
|
warn!("XRandR reported that the display's 0mm in size, which is certifiably insane");
|
||||||
return 1.0;
|
return 1.0;
|
||||||
}
|
}
|
||||||
@@ -79,6 +79,24 @@ impl From<*mut ffi::XRRCrtcInfo> for MonitorRepr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl XConnection {
|
impl XConnection {
|
||||||
|
// Retrieve DPI from Xft.dpi property
|
||||||
|
pub unsafe fn get_xft_dpi(&self) -> Option<f64> {
|
||||||
|
(self.xlib.XrmInitialize)();
|
||||||
|
let resource_manager_str = (self.xlib.XResourceManagerString)(self.display);
|
||||||
|
if resource_manager_str == ptr::null_mut() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if let Ok(res) = ::std::ffi::CStr::from_ptr(resource_manager_str).to_str() {
|
||||||
|
let name : &str = "Xft.dpi:\t";
|
||||||
|
for pair in res.split("\n") {
|
||||||
|
if pair.starts_with(&name) {
|
||||||
|
let res = &pair[name.len()..];
|
||||||
|
return f64::from_str(&res).ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
pub unsafe fn get_output_info(
|
pub unsafe fn get_output_info(
|
||||||
&self,
|
&self,
|
||||||
resources: *mut ffi::XRRScreenResources,
|
resources: *mut ffi::XRRScreenResources,
|
||||||
@@ -101,10 +119,15 @@ impl XConnection {
|
|||||||
(*output_info).nameLen as usize,
|
(*output_info).nameLen as usize,
|
||||||
);
|
);
|
||||||
let name = String::from_utf8_lossy(name_slice).into();
|
let name = String::from_utf8_lossy(name_slice).into();
|
||||||
let hidpi_factor = calc_dpi_factor(
|
let hidpi_factor = if let Some(dpi) = self.get_xft_dpi() {
|
||||||
repr.get_dimensions(),
|
dpi / 96.
|
||||||
((*output_info).mm_width as u64, (*output_info).mm_height as u64),
|
} else {
|
||||||
);
|
calc_dpi_factor(
|
||||||
|
repr.get_dimensions(),
|
||||||
|
((*output_info).mm_width as u64, (*output_info).mm_height as u64),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
(self.xrandr.XRRFreeOutputInfo)(output_info);
|
(self.xrandr.XRRFreeOutputInfo)(output_info);
|
||||||
Some((name, hidpi_factor))
|
Some((name, hidpi_factor))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ pub struct SharedState {
|
|||||||
pub guessed_dpi: Option<f64>,
|
pub guessed_dpi: Option<f64>,
|
||||||
pub last_monitor: Option<X11MonitorId>,
|
pub last_monitor: Option<X11MonitorId>,
|
||||||
pub dpi_adjusted: Option<(f64, f64)>,
|
pub dpi_adjusted: Option<(f64, f64)>,
|
||||||
|
pub fullscreen: Option<RootMonitorId>,
|
||||||
// Used to restore position after exiting fullscreen.
|
// Used to restore position after exiting fullscreen.
|
||||||
pub restore_position: Option<(i32, i32)>,
|
pub restore_position: Option<(i32, i32)>,
|
||||||
pub frame_extents: Option<util::FrameExtentsHeuristic>,
|
pub frame_extents: Option<util::FrameExtentsHeuristic>,
|
||||||
@@ -533,8 +534,14 @@ impl UnownedWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_fullscreen(&self) -> Option<RootMonitorId> {
|
||||||
|
self.shared_state.lock().fullscreen.clone()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_fullscreen(&self, monitor: Option<RootMonitorId>) {
|
pub fn set_fullscreen(&self, monitor: Option<RootMonitorId>) {
|
||||||
|
self.shared_state.lock().fullscreen = monitor.clone();
|
||||||
self.set_fullscreen_inner(monitor)
|
self.set_fullscreen_inner(monitor)
|
||||||
.flush()
|
.flush()
|
||||||
.expect("Failed to change window fullscreen state");
|
.expect("Failed to change window fullscreen state");
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
use std::os::raw::c_int;
|
||||||
|
|
||||||
use libc;
|
use libc;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
@@ -18,6 +19,7 @@ pub struct XConnection {
|
|||||||
pub xinput2: ffi::XInput2,
|
pub xinput2: ffi::XInput2,
|
||||||
pub xlib_xcb: ffi::Xlib_xcb,
|
pub xlib_xcb: ffi::Xlib_xcb,
|
||||||
pub display: *mut ffi::Display,
|
pub display: *mut ffi::Display,
|
||||||
|
pub x11_fd: c_int,
|
||||||
pub latest_error: Mutex<Option<XError>>,
|
pub latest_error: Mutex<Option<XError>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,6 +50,11 @@ impl XConnection {
|
|||||||
display
|
display
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Get X11 socket file descriptor
|
||||||
|
let fd = unsafe {
|
||||||
|
(xlib.XConnectionNumber)(display)
|
||||||
|
};
|
||||||
|
|
||||||
Ok(XConnection {
|
Ok(XConnection {
|
||||||
xlib,
|
xlib,
|
||||||
xrandr,
|
xrandr,
|
||||||
@@ -56,6 +63,7 @@ impl XConnection {
|
|||||||
xinput2,
|
xinput2,
|
||||||
xlib_xcb,
|
xlib_xcb,
|
||||||
display,
|
display,
|
||||||
|
x11_fd: fd,
|
||||||
latest_error: Mutex::new(None),
|
latest_error: Mutex::new(None),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -544,7 +544,67 @@ impl Proxy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_virtual_key_code(code: c_ushort) -> Option<events::VirtualKeyCode> {
|
pub fn char_to_keycode(c: char) -> Option<events::VirtualKeyCode> {
|
||||||
|
// We only translate keys that are affected by keyboard layout.
|
||||||
|
//
|
||||||
|
// Note that since keys are translated in a somewhat "dumb" way (reading character)
|
||||||
|
// there is a concern that some combination, i.e. Cmd+char, causes the wrong
|
||||||
|
// letter to be received, and so we receive the wrong key.
|
||||||
|
//
|
||||||
|
// Implementation reference: https://github.com/WebKit/webkit/blob/82bae82cf0f329dbe21059ef0986c4e92fea4ba6/Source/WebCore/platform/cocoa/KeyEventCocoa.mm#L626
|
||||||
|
Some(match c {
|
||||||
|
'a' | 'A' => events::VirtualKeyCode::A,
|
||||||
|
'b' | 'B' => events::VirtualKeyCode::B,
|
||||||
|
'c' | 'C' => events::VirtualKeyCode::C,
|
||||||
|
'd' | 'D' => events::VirtualKeyCode::D,
|
||||||
|
'e' | 'E' => events::VirtualKeyCode::E,
|
||||||
|
'f' | 'F' => events::VirtualKeyCode::F,
|
||||||
|
'g' | 'G' => events::VirtualKeyCode::G,
|
||||||
|
'h' | 'H' => events::VirtualKeyCode::H,
|
||||||
|
'i' | 'I' => events::VirtualKeyCode::I,
|
||||||
|
'j' | 'J' => events::VirtualKeyCode::J,
|
||||||
|
'k' | 'K' => events::VirtualKeyCode::K,
|
||||||
|
'l' | 'L' => events::VirtualKeyCode::L,
|
||||||
|
'm' | 'M' => events::VirtualKeyCode::M,
|
||||||
|
'n' | 'N' => events::VirtualKeyCode::N,
|
||||||
|
'o' | 'O' => events::VirtualKeyCode::O,
|
||||||
|
'p' | 'P' => events::VirtualKeyCode::P,
|
||||||
|
'q' | 'Q' => events::VirtualKeyCode::Q,
|
||||||
|
'r' | 'R' => events::VirtualKeyCode::R,
|
||||||
|
's' | 'S' => events::VirtualKeyCode::S,
|
||||||
|
't' | 'T' => events::VirtualKeyCode::T,
|
||||||
|
'u' | 'U' => events::VirtualKeyCode::U,
|
||||||
|
'v' | 'V' => events::VirtualKeyCode::V,
|
||||||
|
'w' | 'W' => events::VirtualKeyCode::W,
|
||||||
|
'x' | 'X' => events::VirtualKeyCode::X,
|
||||||
|
'y' | 'Y' => events::VirtualKeyCode::Y,
|
||||||
|
'z' | 'Z' => events::VirtualKeyCode::Z,
|
||||||
|
'1' | '!' => events::VirtualKeyCode::Key1,
|
||||||
|
'2' | '@' => events::VirtualKeyCode::Key2,
|
||||||
|
'3' | '#' => events::VirtualKeyCode::Key3,
|
||||||
|
'4' | '$' => events::VirtualKeyCode::Key4,
|
||||||
|
'5' | '%' => events::VirtualKeyCode::Key5,
|
||||||
|
'6' | '^' => events::VirtualKeyCode::Key6,
|
||||||
|
'7' | '&' => events::VirtualKeyCode::Key7,
|
||||||
|
'8' | '*' => events::VirtualKeyCode::Key8,
|
||||||
|
'9' | '(' => events::VirtualKeyCode::Key9,
|
||||||
|
'0' | ')' => events::VirtualKeyCode::Key0,
|
||||||
|
'=' | '+' => events::VirtualKeyCode::Equals,
|
||||||
|
'-' | '_' => events::VirtualKeyCode::Minus,
|
||||||
|
']' | '}' => events::VirtualKeyCode::RBracket,
|
||||||
|
'[' | '{' => events::VirtualKeyCode::LBracket,
|
||||||
|
'\''| '"' => events::VirtualKeyCode::Apostrophe,
|
||||||
|
';' | ':' => events::VirtualKeyCode::Semicolon,
|
||||||
|
'\\'| '|' => events::VirtualKeyCode::Backslash,
|
||||||
|
',' | '<' => events::VirtualKeyCode::Comma,
|
||||||
|
'/' | '?' => events::VirtualKeyCode::Slash,
|
||||||
|
'.' | '>' => events::VirtualKeyCode::Period,
|
||||||
|
'`' | '~' => events::VirtualKeyCode::Grave,
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scancode_to_keycode(code: c_ushort) -> Option<events::VirtualKeyCode> {
|
||||||
Some(match code {
|
Some(match code {
|
||||||
0x00 => events::VirtualKeyCode::A,
|
0x00 => events::VirtualKeyCode::A,
|
||||||
0x01 => events::VirtualKeyCode::S,
|
0x01 => events::VirtualKeyCode::S,
|
||||||
@@ -600,8 +660,8 @@ pub fn to_virtual_key_code(code: c_ushort) -> Option<events::VirtualKeyCode> {
|
|||||||
0x33 => events::VirtualKeyCode::Back,
|
0x33 => events::VirtualKeyCode::Back,
|
||||||
//0x34 => unkown,
|
//0x34 => unkown,
|
||||||
0x35 => events::VirtualKeyCode::Escape,
|
0x35 => events::VirtualKeyCode::Escape,
|
||||||
0x36 => events::VirtualKeyCode::LWin,
|
0x36 => events::VirtualKeyCode::RWin,
|
||||||
0x37 => events::VirtualKeyCode::RWin,
|
0x37 => events::VirtualKeyCode::LWin,
|
||||||
0x38 => events::VirtualKeyCode::LShift,
|
0x38 => events::VirtualKeyCode::LShift,
|
||||||
//0x39 => Caps lock,
|
//0x39 => Caps lock,
|
||||||
0x3a => events::VirtualKeyCode::LAlt,
|
0x3a => events::VirtualKeyCode::LAlt,
|
||||||
@@ -623,6 +683,7 @@ pub fn to_virtual_key_code(code: c_ushort) -> Option<events::VirtualKeyCode> {
|
|||||||
0x4a => events::VirtualKeyCode::VolumeDown,
|
0x4a => events::VirtualKeyCode::VolumeDown,
|
||||||
0x4b => events::VirtualKeyCode::Divide,
|
0x4b => events::VirtualKeyCode::Divide,
|
||||||
0x4c => events::VirtualKeyCode::NumpadEnter,
|
0x4c => events::VirtualKeyCode::NumpadEnter,
|
||||||
|
0x4e => events::VirtualKeyCode::Subtract,
|
||||||
//0x4d => unkown,
|
//0x4d => unkown,
|
||||||
0x4e => events::VirtualKeyCode::Subtract,
|
0x4e => events::VirtualKeyCode::Subtract,
|
||||||
0x4f => events::VirtualKeyCode::F18,
|
0x4f => events::VirtualKeyCode::F18,
|
||||||
@@ -680,20 +741,19 @@ pub fn to_virtual_key_code(code: c_ushort) -> Option<events::VirtualKeyCode> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_additional_virtual_key_codes(
|
pub fn check_function_keys(
|
||||||
s: &Option<String>
|
s: &String
|
||||||
) -> Option<events::VirtualKeyCode> {
|
) -> Option<events::VirtualKeyCode> {
|
||||||
if let &Some(ref s) = s {
|
if let Some(ch) = s.encode_utf16().next() {
|
||||||
if let Some(ch) = s.encode_utf16().next() {
|
return Some(match ch {
|
||||||
return Some(match ch {
|
0xf718 => events::VirtualKeyCode::F21,
|
||||||
0xf718 => events::VirtualKeyCode::F21,
|
0xf719 => events::VirtualKeyCode::F22,
|
||||||
0xf719 => events::VirtualKeyCode::F22,
|
0xf71a => events::VirtualKeyCode::F23,
|
||||||
0xf71a => events::VirtualKeyCode::F23,
|
0xf71b => events::VirtualKeyCode::F24,
|
||||||
0xf71b => events::VirtualKeyCode::F24,
|
_ => return None,
|
||||||
_ => return None,
|
})
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -709,6 +769,16 @@ pub fn event_mods(event: cocoa::base::id) -> ModifiersState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_scancode(event: cocoa::base::id) -> c_ushort {
|
||||||
|
// In AppKit, `keyCode` refers to the position (scancode) of a key rather than its character,
|
||||||
|
// and there is no easy way to navtively retrieve the layout-dependent character.
|
||||||
|
// In winit, we use keycode to refer to the key's character, and so this function aligns
|
||||||
|
// AppKit's terminology with ours.
|
||||||
|
unsafe {
|
||||||
|
msg_send![event, keyCode]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn modifier_event(
|
unsafe fn modifier_event(
|
||||||
ns_event: cocoa::base::id,
|
ns_event: cocoa::base::id,
|
||||||
keymask: NSEventModifierFlags,
|
keymask: NSEventModifierFlags,
|
||||||
@@ -721,14 +791,14 @@ unsafe fn modifier_event(
|
|||||||
} else {
|
} else {
|
||||||
ElementState::Pressed
|
ElementState::Pressed
|
||||||
};
|
};
|
||||||
let keycode = NSEvent::keyCode(ns_event);
|
|
||||||
let scancode = keycode as u32;
|
let scancode = get_scancode(ns_event);
|
||||||
let virtual_keycode = to_virtual_key_code(keycode);
|
let virtual_keycode = scancode_to_keycode(scancode);
|
||||||
Some(WindowEvent::KeyboardInput {
|
Some(WindowEvent::KeyboardInput {
|
||||||
device_id: DEVICE_ID,
|
device_id: DEVICE_ID,
|
||||||
input: KeyboardInput {
|
input: KeyboardInput {
|
||||||
state,
|
state,
|
||||||
scancode,
|
scancode: scancode as u32,
|
||||||
virtual_keycode,
|
virtual_keycode,
|
||||||
modifiers: event_mods(ns_event),
|
modifiers: event_mods(ns_event),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -14,10 +14,11 @@ use objc::declare::ClassDecl;
|
|||||||
use objc::runtime::{Class, Object, Protocol, Sel, BOOL, YES};
|
use objc::runtime::{Class, Object, Protocol, Sel, BOOL, YES};
|
||||||
|
|
||||||
use {ElementState, Event, KeyboardInput, MouseButton, WindowEvent, WindowId};
|
use {ElementState, Event, KeyboardInput, MouseButton, WindowEvent, WindowId};
|
||||||
use platform::platform::events_loop::{DEVICE_ID, event_mods, Shared, to_virtual_key_code, check_additional_virtual_key_codes};
|
use platform::platform::events_loop::{DEVICE_ID, event_mods, Shared, scancode_to_keycode, char_to_keycode, check_function_keys, get_scancode};
|
||||||
use platform::platform::util;
|
use platform::platform::util;
|
||||||
use platform::platform::ffi::*;
|
use platform::platform::ffi::*;
|
||||||
use platform::platform::window::{get_window_id, IdRef};
|
use platform::platform::window::{get_window_id, IdRef};
|
||||||
|
use events;
|
||||||
|
|
||||||
struct ViewState {
|
struct ViewState {
|
||||||
window: id,
|
window: id,
|
||||||
@@ -391,36 +392,68 @@ extern fn do_command_by_selector(this: &Object, _sel: Sel, command: Sel) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_characters(event: id) -> Option<String> {
|
fn get_characters(event: id, ignore_modifiers: bool) -> String {
|
||||||
unsafe {
|
unsafe {
|
||||||
let characters: id = msg_send![event, characters];
|
let characters: id = if ignore_modifiers {
|
||||||
|
msg_send![event, charactersIgnoringModifiers]
|
||||||
|
} else {
|
||||||
|
msg_send![event, characters]
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_ne!(characters, nil);
|
||||||
let slice = slice::from_raw_parts(
|
let slice = slice::from_raw_parts(
|
||||||
characters.UTF8String() as *const c_uchar,
|
characters.UTF8String() as *const c_uchar,
|
||||||
characters.len(),
|
characters.len(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let string = str::from_utf8_unchecked(slice);
|
let string = str::from_utf8_unchecked(slice);
|
||||||
Some(string.to_owned())
|
|
||||||
|
string.to_owned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Retrieves a layout-independent keycode given an event.
|
||||||
|
fn retrieve_keycode(event: id) -> Option<events::VirtualKeyCode> {
|
||||||
|
#[inline]
|
||||||
|
fn get_code(ev: id, raw: bool) -> Option<events::VirtualKeyCode> {
|
||||||
|
let characters = get_characters(ev, raw);
|
||||||
|
characters.chars().next().map_or(None, |c| char_to_keycode(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cmd switches Roman letters for Dvorak-QWERTY layout, so we try modified characters first.
|
||||||
|
// If we don't get a match, then we fall back to unmodified characters.
|
||||||
|
let code = get_code(event, false)
|
||||||
|
.or_else(|| {
|
||||||
|
get_code(event, true)
|
||||||
|
});
|
||||||
|
|
||||||
|
// We've checked all layout related keys, so fall through to scancode.
|
||||||
|
// Reaching this code means that the key is layout-independent (e.g. Backspace, Return).
|
||||||
|
//
|
||||||
|
// We're additionally checking here for F21-F24 keys, since their keycode
|
||||||
|
// can vary, but we know that they are encoded
|
||||||
|
// in characters property.
|
||||||
|
code.or_else(|| {
|
||||||
|
let scancode = get_scancode(event);
|
||||||
|
scancode_to_keycode(scancode)
|
||||||
|
.or_else(|| {
|
||||||
|
check_function_keys(&get_characters(event, true))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
extern fn key_down(this: &Object, _sel: Sel, event: id) {
|
extern fn key_down(this: &Object, _sel: Sel, event: id) {
|
||||||
//println!("keyDown");
|
//println!("keyDown");
|
||||||
unsafe {
|
unsafe {
|
||||||
let state_ptr: *mut c_void = *this.get_ivar("winitState");
|
let state_ptr: *mut c_void = *this.get_ivar("winitState");
|
||||||
let state = &mut *(state_ptr as *mut ViewState);
|
let state = &mut *(state_ptr as *mut ViewState);
|
||||||
let window_id = WindowId(get_window_id(state.window));
|
let window_id = WindowId(get_window_id(state.window));
|
||||||
|
let characters = get_characters(event, false);
|
||||||
|
|
||||||
state.raw_characters = get_characters(event);
|
state.raw_characters = Some(characters.clone());
|
||||||
|
|
||||||
let keycode: c_ushort = msg_send![event, keyCode];
|
let scancode = get_scancode(event) as u32;
|
||||||
// We are checking here for F21-F24 keys, since their keycode
|
let virtual_keycode = retrieve_keycode(event);
|
||||||
// can vary, but we know that they are encoded
|
|
||||||
// in characters property.
|
|
||||||
let virtual_keycode = to_virtual_key_code(keycode)
|
|
||||||
.or_else(|| {
|
|
||||||
check_additional_virtual_key_codes(&state.raw_characters)
|
|
||||||
});
|
|
||||||
let scancode = keycode as u32;
|
|
||||||
let is_repeat = msg_send![event, isARepeat];
|
let is_repeat = msg_send![event, isARepeat];
|
||||||
|
|
||||||
let window_event = Event::WindowEvent {
|
let window_event = Event::WindowEvent {
|
||||||
@@ -436,17 +469,6 @@ extern fn key_down(this: &Object, _sel: Sel, event: id) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let characters: id = msg_send![event, characters];
|
|
||||||
let slice = slice::from_raw_parts(
|
|
||||||
characters.UTF8String() as *const c_uchar,
|
|
||||||
characters.len(),
|
|
||||||
);
|
|
||||||
let string = str::from_utf8_unchecked(slice);
|
|
||||||
|
|
||||||
state.raw_characters = {
|
|
||||||
Some(string.to_owned())
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(shared) = state.shared.upgrade() {
|
if let Some(shared) = state.shared.upgrade() {
|
||||||
shared.pending_events
|
shared.pending_events
|
||||||
.lock()
|
.lock()
|
||||||
@@ -454,7 +476,7 @@ extern fn key_down(this: &Object, _sel: Sel, event: id) {
|
|||||||
.push_back(window_event);
|
.push_back(window_event);
|
||||||
// Emit `ReceivedCharacter` for key repeats
|
// Emit `ReceivedCharacter` for key repeats
|
||||||
if is_repeat && state.is_key_down{
|
if is_repeat && state.is_key_down{
|
||||||
for character in string.chars() {
|
for character in characters.chars() {
|
||||||
let window_event = Event::WindowEvent {
|
let window_event = Event::WindowEvent {
|
||||||
window_id,
|
window_id,
|
||||||
event: WindowEvent::ReceivedCharacter(character),
|
event: WindowEvent::ReceivedCharacter(character),
|
||||||
@@ -483,16 +505,9 @@ extern fn key_up(this: &Object, _sel: Sel, event: id) {
|
|||||||
|
|
||||||
state.is_key_down = false;
|
state.is_key_down = false;
|
||||||
|
|
||||||
// We need characters here to check for additional keys such as
|
let scancode = get_scancode(event) as u32;
|
||||||
// F21-F24.
|
let virtual_keycode = retrieve_keycode(event);
|
||||||
let characters = get_characters(event);
|
|
||||||
|
|
||||||
let keycode: c_ushort = msg_send![event, keyCode];
|
|
||||||
let virtual_keycode = to_virtual_key_code(keycode)
|
|
||||||
.or_else(|| {
|
|
||||||
check_additional_virtual_key_codes(&characters)
|
|
||||||
});
|
|
||||||
let scancode = keycode as u32;
|
|
||||||
let window_event = Event::WindowEvent {
|
let window_event = Event::WindowEvent {
|
||||||
window_id: WindowId(get_window_id(state.window)),
|
window_id: WindowId(get_window_id(state.window)),
|
||||||
event: WindowEvent::KeyboardInput {
|
event: WindowEvent::KeyboardInput {
|
||||||
|
|||||||
@@ -618,6 +618,11 @@ impl WindowExt for Window2 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_simple_fullscreen(&self) -> bool {
|
||||||
|
self.delegate.state.is_simple_fullscreen.get()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn set_simple_fullscreen(&self, fullscreen: bool) -> bool {
|
fn set_simple_fullscreen(&self, fullscreen: bool) -> bool {
|
||||||
let state = &self.delegate.state;
|
let state = &self.delegate.state;
|
||||||
@@ -1137,6 +1142,14 @@ impl Window2 {
|
|||||||
self.delegate.state.perform_maximized(maximized)
|
self.delegate.state.perform_maximized(maximized)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_fullscreen(&self) -> Option<RootMonitorId> {
|
||||||
|
let state = &self.delegate.state;
|
||||||
|
let win_attribs = state.win_attribs.borrow();
|
||||||
|
|
||||||
|
win_attribs.fullscreen.clone()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// TODO: Right now set_fullscreen do not work on switching monitors
|
/// TODO: Right now set_fullscreen do not work on switching monitors
|
||||||
/// in fullscreen mode
|
/// in fullscreen mode
|
||||||
|
|||||||
@@ -1,33 +1,87 @@
|
|||||||
use std::char;
|
use std::{char, ptr};
|
||||||
use std::os::raw::c_int;
|
use std::os::raw::c_int;
|
||||||
|
use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
|
||||||
|
|
||||||
use events::VirtualKeyCode;
|
use events::VirtualKeyCode;
|
||||||
use events::ModifiersState;
|
use events::ModifiersState;
|
||||||
|
|
||||||
use winapi::shared::minwindef::{WPARAM, LPARAM, UINT};
|
use winapi::shared::minwindef::{WPARAM, LPARAM, UINT, HKL, HKL__};
|
||||||
use winapi::um::winuser;
|
use winapi::um::winuser;
|
||||||
|
|
||||||
use ScanCode;
|
use ScanCode;
|
||||||
|
|
||||||
|
fn key_pressed(vkey: c_int) -> bool {
|
||||||
|
unsafe {
|
||||||
|
(winuser::GetKeyState(vkey) & (1 << 15)) == (1 << 15)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_key_mods() -> ModifiersState {
|
pub fn get_key_mods() -> ModifiersState {
|
||||||
let mut mods = ModifiersState::default();
|
let mut mods = ModifiersState::default();
|
||||||
unsafe {
|
let filter_out_altgr = layout_uses_altgr() && key_pressed(winuser::VK_RMENU);
|
||||||
if winuser::GetKeyState(winuser::VK_SHIFT) & (1 << 15) == (1 << 15) {
|
|
||||||
mods.shift = true;
|
mods.shift = key_pressed(winuser::VK_SHIFT);
|
||||||
}
|
mods.ctrl = key_pressed(winuser::VK_CONTROL) && !filter_out_altgr;
|
||||||
if winuser::GetKeyState(winuser::VK_CONTROL) & (1 << 15) == (1 << 15) {
|
mods.alt = key_pressed(winuser::VK_MENU) && !filter_out_altgr;
|
||||||
mods.ctrl = true;
|
mods.logo = key_pressed(winuser::VK_LWIN) || key_pressed(winuser::VK_RWIN);
|
||||||
}
|
|
||||||
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
|
mods
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn get_char(keyboard_state: &[u8; 256], v_key: u32, hkl: HKL) -> Option<char> {
|
||||||
|
let mut unicode_bytes = [0u16; 5];
|
||||||
|
let len = winuser::ToUnicodeEx(v_key, 0, keyboard_state.as_ptr(), unicode_bytes.as_mut_ptr(), unicode_bytes.len() as _, 0, hkl);
|
||||||
|
if len >= 1 {
|
||||||
|
char::decode_utf16(unicode_bytes.into_iter().cloned()).next().and_then(|c| c.ok())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Figures out if the keyboard layout has an AltGr key instead of an Alt key.
|
||||||
|
///
|
||||||
|
/// Unfortunately, the Windows API doesn't give a way for us to conveniently figure that out. So,
|
||||||
|
/// we use a technique blatantly stolen from [the Firefox source code][source]: iterate over every
|
||||||
|
/// possible virtual key and compare the `char` output when AltGr is pressed vs when it isn't. If
|
||||||
|
/// pressing AltGr outputs characters that are different from the standard characters, the layout
|
||||||
|
/// uses AltGr. Otherwise, it doesn't.
|
||||||
|
///
|
||||||
|
/// [source]: https://github.com/mozilla/gecko-dev/blob/265e6721798a455604328ed5262f430cfcc37c2f/widget/windows/KeyboardLayout.cpp#L4356-L4416
|
||||||
|
fn layout_uses_altgr() -> bool {
|
||||||
|
unsafe {
|
||||||
|
static ACTIVE_LAYOUT: AtomicPtr<HKL__> = AtomicPtr::new(ptr::null_mut());
|
||||||
|
static USES_ALTGR: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
|
let hkl = winuser::GetKeyboardLayout(0);
|
||||||
|
let old_hkl = ACTIVE_LAYOUT.swap(hkl, Ordering::SeqCst);
|
||||||
|
|
||||||
|
if hkl == old_hkl {
|
||||||
|
return USES_ALTGR.load(Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut keyboard_state_altgr = [0u8; 256];
|
||||||
|
// AltGr is an alias for Ctrl+Alt for... some reason. Whatever it is, those are the keypresses
|
||||||
|
// we have to emulate to do an AltGr test.
|
||||||
|
keyboard_state_altgr[winuser::VK_MENU as usize] = 0x80;
|
||||||
|
keyboard_state_altgr[winuser::VK_CONTROL as usize] = 0x80;
|
||||||
|
|
||||||
|
let keyboard_state_empty = [0u8; 256];
|
||||||
|
|
||||||
|
for v_key in 0..=255 {
|
||||||
|
let key_noaltgr = get_char(&keyboard_state_empty, v_key, hkl);
|
||||||
|
let key_altgr = get_char(&keyboard_state_altgr, v_key, hkl);
|
||||||
|
if let (Some(noaltgr), Some(altgr)) = (key_noaltgr, key_altgr) {
|
||||||
|
if noaltgr != altgr {
|
||||||
|
USES_ALTGR.store(true, Ordering::SeqCst);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
USES_ALTGR.store(false, Ordering::SeqCst);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn vkey_to_winit_vkey(vkey: c_int) -> Option<VirtualKeyCode> {
|
pub fn vkey_to_winit_vkey(vkey: c_int) -> Option<VirtualKeyCode> {
|
||||||
// VK_* codes are documented here https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
|
// VK_* codes are documented here https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
|
||||||
match vkey {
|
match vkey {
|
||||||
|
|||||||
@@ -711,6 +711,22 @@ unsafe fn callback_inner(
|
|||||||
0
|
0
|
||||||
},
|
},
|
||||||
|
|
||||||
|
winuser::WM_MOUSEHWHEEL => {
|
||||||
|
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(value, 0.0), phase: TouchPhase::Moved, modifiers: event::get_key_mods() },
|
||||||
|
});
|
||||||
|
|
||||||
|
0
|
||||||
|
},
|
||||||
|
|
||||||
winuser::WM_KEYDOWN | winuser::WM_SYSKEYDOWN => {
|
winuser::WM_KEYDOWN | winuser::WM_SYSKEYDOWN => {
|
||||||
use events::ElementState::Pressed;
|
use events::ElementState::Pressed;
|
||||||
use events::VirtualKeyCode;
|
use events::VirtualKeyCode;
|
||||||
@@ -1036,22 +1052,12 @@ unsafe fn callback_inner(
|
|||||||
}
|
}
|
||||||
|
|
||||||
winuser::WM_SETFOCUS => {
|
winuser::WM_SETFOCUS => {
|
||||||
use events::WindowEvent::{Focused, CursorMoved};
|
use events::WindowEvent::Focused;
|
||||||
send_event(Event::WindowEvent {
|
send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: Focused(true)
|
event: Focused(true)
|
||||||
});
|
});
|
||||||
|
|
||||||
let x = windowsx::GET_X_LPARAM(lparam) as f64;
|
|
||||||
let y = windowsx::GET_Y_LPARAM(lparam) as f64;
|
|
||||||
let dpi_factor = get_hwnd_scale_factor(window);
|
|
||||||
let position = LogicalPosition::from_physical((x, y), dpi_factor);
|
|
||||||
|
|
||||||
send_event(Event::WindowEvent {
|
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
|
||||||
event: CursorMoved { device_id: DEVICE_ID, position, modifiers: event::get_key_mods() },
|
|
||||||
});
|
|
||||||
|
|
||||||
0
|
0
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -355,6 +355,12 @@ impl Window {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_fullscreen(&self) -> Option<RootMonitorId> {
|
||||||
|
let window_state = self.window_state.lock().unwrap();
|
||||||
|
window_state.fullscreen.clone()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_fullscreen(&self, monitor: Option<RootMonitorId>) {
|
pub fn set_fullscreen(&self, monitor: Option<RootMonitorId>) {
|
||||||
unsafe {
|
unsafe {
|
||||||
@@ -625,9 +631,6 @@ unsafe fn init(
|
|||||||
format!("{}", io::Error::last_os_error()))));
|
format!("{}", io::Error::last_os_error()))));
|
||||||
}
|
}
|
||||||
|
|
||||||
winuser::SetWindowLongW(handle, winuser::GWL_STYLE, 0);
|
|
||||||
winuser::SetWindowLongW(handle, winuser::GWL_EXSTYLE, 0);
|
|
||||||
|
|
||||||
WindowWrapper(handle)
|
WindowWrapper(handle)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -369,6 +369,12 @@ impl Window {
|
|||||||
self.window.set_fullscreen(monitor)
|
self.window.set_fullscreen(monitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the window's current fullscreen state.
|
||||||
|
#[inline]
|
||||||
|
pub fn get_fullscreen(&self) -> Option<MonitorId> {
|
||||||
|
self.window.get_fullscreen()
|
||||||
|
}
|
||||||
|
|
||||||
/// Turn window decorations on or off.
|
/// Turn window decorations on or off.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_decorations(&self, decorations: bool) {
|
pub fn set_decorations(&self, decorations: bool) {
|
||||||
@@ -485,7 +491,7 @@ impl MonitorId {
|
|||||||
///
|
///
|
||||||
/// ## Platform-specific
|
/// ## Platform-specific
|
||||||
///
|
///
|
||||||
/// - **X11:** Can be overridden using the `WINIT_HIDPI_FACTOR` environment variable.
|
/// - **X11:** This respects Xft.dpi XResource, and can be overridden using the `WINIT_HIDPI_FACTOR` environment variable.
|
||||||
/// - **Android:** Always returns 1.0.
|
/// - **Android:** Always returns 1.0.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_hidpi_factor(&self) -> f64 {
|
pub fn get_hidpi_factor(&self) -> f64 {
|
||||||
|
|||||||
Reference in New Issue
Block a user