* 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.
* 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.
* 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
* 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.
* macOS: fix regression in 03c3e794097676888234b3cc82c01228dcbe48c8
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
* 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
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.
* 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
* 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
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.
* bump minor version
* update changelog date and fix typo
* Updated date (we're going to release for real this time)
* Update version in README for the first time in a long time
* Replace Closed event with CloseRequested and Destroyed
Implements #434
The existing Closed event had ambiguous meaning, both in name and in
cross-platform behavior. Closed is now split into two more precise events:
* CloseRequested - the window has been requested to close, most commonly by
having clicked the window's close button. Whether or not you respond by
closing the window is up to you.
* Destroyed - the window has been destroyed, and can no longer be safely
used.
Most notably, now you can reliably implement classic patterns like
prompting the user to save their work before closing, and have the
opportunity to perform any necessary cleanup.
Migrating to the new API is straightforward. In most cases, you can simply
replace all existing usages of Closed with CloseRequested. For more
information, see the example programs, particularly handling_close and
multiwindow.
iOS applications must replace all usages of Closed with Destroyed, and
require no other changes.
* x11: Windows are Sync again
Fixes#472
* Add test ensuring that Window is Sync
Window must be Sync for Vulkano's Arc<FramebufferAbstract> to be usable.
This reverts commit 19cd53193b.
Testing fullscreen functionality revealed that windowDidResize is invoked in more cases than previously thought, causing the user's events to be eaten and HiDPI problems.
* Added helper function for make monitor from display.
* Implement get_current_monitor for macos
* Implemented with_fullscreen and set_fullscreen for macos
* Implemented set_decorations for macos
* Implement set_maximized and with_maximized for macos
* Changed fullscreen example fullscreen keypress from F11 to F
* Update CHANGELOG.md
* Add and fixed some comments
* Reformat and add more comments
* Better handling window and maximized state
* Reformat and typo fix
* Add get_inner_position for windows, prototypes for other platforms
* Fix linux builds
* Implement get_inner_position for osx
* Add get_inner_pos implementations for other platforms
* Fixed get_inner_position on macOS
* Corrected set_position on macOS
* Added CHANGELOG entry
* Discard mouse down after Cocoa window resize
We are sending the mouse down event after the window resize has
completed, because Cocoa uses a modal event loop to implement window
resize. This leads to a mouse down without a matching mouse up.
* Also handle event discard in poll_events
Add some explanatory comments and a changelog entry.