2019-06-22 01:33:15 +10:00
|
|
|
use crate::{
|
2020-03-07 08:15:49 +11:00
|
|
|
dpi::{PhysicalPosition, Size},
|
Move `ModifiersChanged` variant to `WindowEvent` (#1381)
* Move `ModifiersChanged` variant to `WindowEvent`
* macos: Fix flags_changed for ModifiersChanged variant move
I haven't look too deep at what this does internally, but at least
cargo-check is fully happy now. :)
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* macos: Fire a ModifiersChanged event on window_did_resign_key
From debugging, I determined that macOS' emission of a flagsChanged
around window switching is inconsistent. It is fair to assume, I think,
that when the user switches windows, they do not expect their former
modifiers state to remain effective; so I think it's best to clear that
state by sending a ModifiersChanged(ModifiersState::empty()).
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* windows: Fix build
I don't know enough about the code to implement the fix as it is done on
this branch, but this commit at least fixes the build.
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* windows: Send ModifiersChanged(ModifiersState::empty) on KILLFOCUS
Very similar to the changes made in [1], as focus is lost, send an event
to the window indicating that the modifiers have been released.
It's unclear to me (without a Windows device to test this on) whether
this is necessary, but it certainly ensures that unfocused windows will
have at least received this event, which is an improvement.
[1]: f79f21641a31da3e4039d41be89047cdcc6028f7
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* macos: Add a hook to update stale modifiers
Sometimes, `ViewState` and `event` might have different values for their
stored `modifiers` flags. These are internally stored as a bitmask in
the latter and an enum in the former.
We can check to see if they differ, and if they do, automatically
dispatch an event to update consumers of modifier state as well as the
stored `state.modifiers`. That's what the hook does.
This hook is then called in the key_down, mouse_entered, mouse_exited,
mouse_click, scroll_wheel, and pressure_change_with_event callbacks,
which each will contain updated modifiers.
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* Only call event_mods once when determining whether to update state
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* flags_changed: Memoize window_id collection
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* window_did_resign_key: Remove synthetic ModifiersChanged event
We no longer need to emit this event, since we are checking the state of
our modifiers before emitting most other events.
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* mouse_motion: Add a call to update_potentially_stale_modifiers
Now, cover all events (that I can think of, at least) where stale
modifiers might affect how user programs behave. Effectively, every
human-interface event (keypress, mouse click, keydown, etc.) will cause
a ModifiersChanged event to be fired if something has changed.
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* key_up: Add a call to update_potentially_stale_modifiers
We also want to make sure modifiers state is synchronized here, too.
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* mouse_motion: Remove update_potentially_stale_modifiers invocation
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* Retry CI
* ViewState: Promote visibility of modifiers to the macos impl
This is so that we can interact with the ViewState directly from the
WindowDelegate.
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* window_delegate: Synthetically set modifiers state to empty on resignKey
This logic is implemented similarly on other platforms, so we wish to
regain parity here. Originally this behavior was implemented to always
fire an event with ModifiersState::empty(), but that was not the best as
it was not necessarily correct and could be a duplicate event.
This solution is perhaps the most elegant possible to implement the
desired behavior of sending a synthetic empty modifiers event when a
window loses focus, trading some safety for interoperation between the
NSWindowDelegate and the NSView (as the objc runtime must now be
consulted in order to acquire access to the ViewState which is "owned"
by the NSView).
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* Check for modifiers change in window events
* Fix modifier changed on macOS
Since the `mouse_entered` function was generating a mouse motion, which
updates the modifier state, a modifiers changed event was incorrectly
generated.
The updating of the modifier state has also been changed to make sure it
consistently happens before events that have a modifier state attached
to it, without happening on any other event.
This of course means that no `CursorMoved` event is generated anymore
when the user enters the window without it being focused, however I'd
say that is consistent with how winit should behave.
* Fix unused variable warning
* Move changelog entry into `Unreleased` section
Co-authored-by: Freya Gentz <zegentzy@protonmail.com>
Co-authored-by: Kristofer Rye <kristofer.rye@gmail.com>
Co-authored-by: Christian Duerr <contact@christianduerr.com>
2020-03-07 09:43:55 +11:00
|
|
|
event::ModifiersState,
|
2020-03-08 06:42:21 +11:00
|
|
|
icon::Icon,
|
|
|
|
platform_impl::platform::{event_loop, util},
|
2020-12-01 05:04:26 +11:00
|
|
|
window::{CursorIcon, Fullscreen, Theme, WindowAttributes},
|
2019-06-22 01:33:15 +10:00
|
|
|
};
|
2019-02-06 02:30:33 +11:00
|
|
|
use parking_lot::MutexGuard;
|
2019-06-22 01:33:15 +10:00
|
|
|
use std::{io, ptr};
|
|
|
|
use winapi::{
|
|
|
|
shared::{
|
|
|
|
minwindef::DWORD,
|
|
|
|
windef::{HWND, RECT},
|
|
|
|
},
|
|
|
|
um::winuser,
|
|
|
|
};
|
2019-02-05 03:52:00 +11:00
|
|
|
|
|
|
|
/// Contains information about states and the window that the callback is going to use.
|
|
|
|
pub struct WindowState {
|
|
|
|
pub mouse: MouseProperties,
|
|
|
|
|
|
|
|
/// Used by `WM_GETMINMAXINFO`.
|
2019-06-20 06:49:43 +10:00
|
|
|
pub min_size: Option<Size>,
|
|
|
|
pub max_size: Option<Size>,
|
2019-02-05 03:52:00 +11:00
|
|
|
|
2020-03-08 06:42:21 +11:00
|
|
|
pub window_icon: Option<Icon>,
|
|
|
|
pub taskbar_icon: Option<Icon>,
|
2019-02-05 03:52:00 +11:00
|
|
|
|
|
|
|
pub saved_window: Option<SavedWindow>,
|
2020-02-14 06:41:41 +11:00
|
|
|
pub scale_factor: f64,
|
2019-02-05 03:52:00 +11:00
|
|
|
|
Move `ModifiersChanged` variant to `WindowEvent` (#1381)
* Move `ModifiersChanged` variant to `WindowEvent`
* macos: Fix flags_changed for ModifiersChanged variant move
I haven't look too deep at what this does internally, but at least
cargo-check is fully happy now. :)
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* macos: Fire a ModifiersChanged event on window_did_resign_key
From debugging, I determined that macOS' emission of a flagsChanged
around window switching is inconsistent. It is fair to assume, I think,
that when the user switches windows, they do not expect their former
modifiers state to remain effective; so I think it's best to clear that
state by sending a ModifiersChanged(ModifiersState::empty()).
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* windows: Fix build
I don't know enough about the code to implement the fix as it is done on
this branch, but this commit at least fixes the build.
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* windows: Send ModifiersChanged(ModifiersState::empty) on KILLFOCUS
Very similar to the changes made in [1], as focus is lost, send an event
to the window indicating that the modifiers have been released.
It's unclear to me (without a Windows device to test this on) whether
this is necessary, but it certainly ensures that unfocused windows will
have at least received this event, which is an improvement.
[1]: f79f21641a31da3e4039d41be89047cdcc6028f7
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* macos: Add a hook to update stale modifiers
Sometimes, `ViewState` and `event` might have different values for their
stored `modifiers` flags. These are internally stored as a bitmask in
the latter and an enum in the former.
We can check to see if they differ, and if they do, automatically
dispatch an event to update consumers of modifier state as well as the
stored `state.modifiers`. That's what the hook does.
This hook is then called in the key_down, mouse_entered, mouse_exited,
mouse_click, scroll_wheel, and pressure_change_with_event callbacks,
which each will contain updated modifiers.
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* Only call event_mods once when determining whether to update state
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* flags_changed: Memoize window_id collection
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* window_did_resign_key: Remove synthetic ModifiersChanged event
We no longer need to emit this event, since we are checking the state of
our modifiers before emitting most other events.
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* mouse_motion: Add a call to update_potentially_stale_modifiers
Now, cover all events (that I can think of, at least) where stale
modifiers might affect how user programs behave. Effectively, every
human-interface event (keypress, mouse click, keydown, etc.) will cause
a ModifiersChanged event to be fired if something has changed.
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* key_up: Add a call to update_potentially_stale_modifiers
We also want to make sure modifiers state is synchronized here, too.
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* mouse_motion: Remove update_potentially_stale_modifiers invocation
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* Retry CI
* ViewState: Promote visibility of modifiers to the macos impl
This is so that we can interact with the ViewState directly from the
WindowDelegate.
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* window_delegate: Synthetically set modifiers state to empty on resignKey
This logic is implemented similarly on other platforms, so we wish to
regain parity here. Originally this behavior was implemented to always
fire an event with ModifiersState::empty(), but that was not the best as
it was not necessarily correct and could be a duplicate event.
This solution is perhaps the most elegant possible to implement the
desired behavior of sending a synthetic empty modifiers event when a
window loses focus, trading some safety for interoperation between the
NSWindowDelegate and the NSView (as the objc runtime must now be
consulted in order to acquire access to the ViewState which is "owned"
by the NSView).
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* Check for modifiers change in window events
* Fix modifier changed on macOS
Since the `mouse_entered` function was generating a mouse motion, which
updates the modifier state, a modifiers changed event was incorrectly
generated.
The updating of the modifier state has also been changed to make sure it
consistently happens before events that have a modifier state attached
to it, without happening on any other event.
This of course means that no `CursorMoved` event is generated anymore
when the user enters the window without it being focused, however I'd
say that is consistent with how winit should behave.
* Fix unused variable warning
* Move changelog entry into `Unreleased` section
Co-authored-by: Freya Gentz <zegentzy@protonmail.com>
Co-authored-by: Kristofer Rye <kristofer.rye@gmail.com>
Co-authored-by: Christian Duerr <contact@christianduerr.com>
2020-03-07 09:43:55 +11:00
|
|
|
pub modifiers_state: ModifiersState,
|
2019-07-30 04:16:14 +10:00
|
|
|
pub fullscreen: Option<Fullscreen>,
|
2020-12-01 05:04:26 +11:00
|
|
|
pub current_theme: Theme,
|
|
|
|
pub preferred_theme: Option<Theme>,
|
2019-09-16 12:09:08 +10:00
|
|
|
pub high_surrogate: Option<u16>,
|
2019-02-05 03:52:00 +11:00
|
|
|
window_flags: WindowFlags,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct SavedWindow {
|
|
|
|
pub client_rect: RECT,
|
2020-02-14 06:41:41 +11:00
|
|
|
pub scale_factor: f64,
|
2019-02-05 03:52:00 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct MouseProperties {
|
2019-05-30 11:29:54 +10:00
|
|
|
pub cursor: CursorIcon,
|
2019-02-06 02:30:33 +11:00
|
|
|
pub buttons_down: u32,
|
2019-02-05 03:52:00 +11:00
|
|
|
cursor_flags: CursorFlags,
|
2020-03-07 08:15:49 +11:00
|
|
|
pub last_position: Option<PhysicalPosition<f64>>,
|
2019-02-05 03:52:00 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
bitflags! {
|
|
|
|
pub struct CursorFlags: u8 {
|
|
|
|
const GRABBED = 1 << 0;
|
|
|
|
const HIDDEN = 1 << 1;
|
|
|
|
const IN_WINDOW = 1 << 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bitflags! {
|
|
|
|
pub struct WindowFlags: u32 {
|
|
|
|
const RESIZABLE = 1 << 0;
|
|
|
|
const DECORATIONS = 1 << 1;
|
|
|
|
const VISIBLE = 1 << 2;
|
|
|
|
const ON_TASKBAR = 1 << 3;
|
|
|
|
const ALWAYS_ON_TOP = 1 << 4;
|
|
|
|
const NO_BACK_BUFFER = 1 << 5;
|
|
|
|
const TRANSPARENT = 1 << 6;
|
|
|
|
const CHILD = 1 << 7;
|
|
|
|
const MAXIMIZED = 1 << 8;
|
|
|
|
|
|
|
|
/// Marker flag for fullscreen. Should always match `WindowState::fullscreen`, but is
|
|
|
|
/// included here to make masking easier.
|
2020-10-20 01:15:23 +11:00
|
|
|
const MARKER_EXCLUSIVE_FULLSCREEN = 1 << 9;
|
|
|
|
const MARKER_BORDERLESS_FULLSCREEN = 1 << 13;
|
2019-02-05 03:52:00 +11:00
|
|
|
|
|
|
|
/// The `WM_SIZE` event contains some parameters that can effect the state of `WindowFlags`.
|
|
|
|
/// In most cases, it's okay to let those parameters change the state. However, when we're
|
|
|
|
/// running the `WindowFlags::apply_diff` function, we *don't* want those parameters to
|
|
|
|
/// effect our stored state, because the purpose of `apply_diff` is to update the actual
|
|
|
|
/// window's state to match our stored state. This controls whether to accept those changes.
|
|
|
|
const MARKER_RETAIN_STATE_ON_SIZE = 1 << 10;
|
|
|
|
|
2020-05-05 05:14:13 +10:00
|
|
|
const MARKER_IN_SIZE_MOVE = 1 << 11;
|
|
|
|
|
|
|
|
const MINIMIZED = 1 << 12;
|
2019-12-22 17:04:11 +11:00
|
|
|
|
2019-02-05 03:52:00 +11:00
|
|
|
const FULLSCREEN_AND_MASK = !(
|
|
|
|
WindowFlags::DECORATIONS.bits |
|
|
|
|
WindowFlags::RESIZABLE.bits |
|
|
|
|
WindowFlags::MAXIMIZED.bits
|
|
|
|
);
|
2020-10-20 01:15:23 +11:00
|
|
|
const EXCLUSIVE_FULLSCREEN_OR_MASK = WindowFlags::ALWAYS_ON_TOP.bits;
|
2019-02-05 03:52:00 +11:00
|
|
|
const NO_DECORATIONS_AND_MASK = !WindowFlags::RESIZABLE.bits;
|
|
|
|
const INVISIBLE_AND_MASK = !WindowFlags::MAXIMIZED.bits;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl WindowState {
|
|
|
|
pub fn new(
|
|
|
|
attributes: &WindowAttributes,
|
2020-03-08 06:42:21 +11:00
|
|
|
taskbar_icon: Option<Icon>,
|
2020-02-14 06:41:41 +11:00
|
|
|
scale_factor: f64,
|
2020-12-01 05:04:26 +11:00
|
|
|
current_theme: Theme,
|
|
|
|
preferred_theme: Option<Theme>,
|
2019-02-05 03:52:00 +11:00
|
|
|
) -> WindowState {
|
|
|
|
WindowState {
|
|
|
|
mouse: MouseProperties {
|
2019-05-30 11:29:54 +10:00
|
|
|
cursor: CursorIcon::default(),
|
2019-02-06 02:30:33 +11:00
|
|
|
buttons_down: 0,
|
2019-02-05 03:52:00 +11:00
|
|
|
cursor_flags: CursorFlags::empty(),
|
2020-03-07 08:15:49 +11:00
|
|
|
last_position: None,
|
2019-02-05 03:52:00 +11:00
|
|
|
},
|
|
|
|
|
2019-05-30 11:29:54 +10:00
|
|
|
min_size: attributes.min_inner_size,
|
|
|
|
max_size: attributes.max_inner_size,
|
2019-02-05 03:52:00 +11:00
|
|
|
|
2020-03-08 06:42:21 +11:00
|
|
|
window_icon: attributes.window_icon.clone(),
|
2019-02-05 03:52:00 +11:00
|
|
|
taskbar_icon,
|
|
|
|
|
|
|
|
saved_window: None,
|
2020-02-14 06:41:41 +11:00
|
|
|
scale_factor,
|
2019-02-05 03:52:00 +11:00
|
|
|
|
Move `ModifiersChanged` variant to `WindowEvent` (#1381)
* Move `ModifiersChanged` variant to `WindowEvent`
* macos: Fix flags_changed for ModifiersChanged variant move
I haven't look too deep at what this does internally, but at least
cargo-check is fully happy now. :)
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* macos: Fire a ModifiersChanged event on window_did_resign_key
From debugging, I determined that macOS' emission of a flagsChanged
around window switching is inconsistent. It is fair to assume, I think,
that when the user switches windows, they do not expect their former
modifiers state to remain effective; so I think it's best to clear that
state by sending a ModifiersChanged(ModifiersState::empty()).
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* windows: Fix build
I don't know enough about the code to implement the fix as it is done on
this branch, but this commit at least fixes the build.
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* windows: Send ModifiersChanged(ModifiersState::empty) on KILLFOCUS
Very similar to the changes made in [1], as focus is lost, send an event
to the window indicating that the modifiers have been released.
It's unclear to me (without a Windows device to test this on) whether
this is necessary, but it certainly ensures that unfocused windows will
have at least received this event, which is an improvement.
[1]: f79f21641a31da3e4039d41be89047cdcc6028f7
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* macos: Add a hook to update stale modifiers
Sometimes, `ViewState` and `event` might have different values for their
stored `modifiers` flags. These are internally stored as a bitmask in
the latter and an enum in the former.
We can check to see if they differ, and if they do, automatically
dispatch an event to update consumers of modifier state as well as the
stored `state.modifiers`. That's what the hook does.
This hook is then called in the key_down, mouse_entered, mouse_exited,
mouse_click, scroll_wheel, and pressure_change_with_event callbacks,
which each will contain updated modifiers.
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* Only call event_mods once when determining whether to update state
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* flags_changed: Memoize window_id collection
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* window_did_resign_key: Remove synthetic ModifiersChanged event
We no longer need to emit this event, since we are checking the state of
our modifiers before emitting most other events.
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* mouse_motion: Add a call to update_potentially_stale_modifiers
Now, cover all events (that I can think of, at least) where stale
modifiers might affect how user programs behave. Effectively, every
human-interface event (keypress, mouse click, keydown, etc.) will cause
a ModifiersChanged event to be fired if something has changed.
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* key_up: Add a call to update_potentially_stale_modifiers
We also want to make sure modifiers state is synchronized here, too.
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* mouse_motion: Remove update_potentially_stale_modifiers invocation
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* Retry CI
* ViewState: Promote visibility of modifiers to the macos impl
This is so that we can interact with the ViewState directly from the
WindowDelegate.
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* window_delegate: Synthetically set modifiers state to empty on resignKey
This logic is implemented similarly on other platforms, so we wish to
regain parity here. Originally this behavior was implemented to always
fire an event with ModifiersState::empty(), but that was not the best as
it was not necessarily correct and could be a duplicate event.
This solution is perhaps the most elegant possible to implement the
desired behavior of sending a synthetic empty modifiers event when a
window loses focus, trading some safety for interoperation between the
NSWindowDelegate and the NSView (as the objc runtime must now be
consulted in order to acquire access to the ViewState which is "owned"
by the NSView).
Signed-off-by: Kristofer Rye <kristofer.rye@gmail.com>
* Check for modifiers change in window events
* Fix modifier changed on macOS
Since the `mouse_entered` function was generating a mouse motion, which
updates the modifier state, a modifiers changed event was incorrectly
generated.
The updating of the modifier state has also been changed to make sure it
consistently happens before events that have a modifier state attached
to it, without happening on any other event.
This of course means that no `CursorMoved` event is generated anymore
when the user enters the window without it being focused, however I'd
say that is consistent with how winit should behave.
* Fix unused variable warning
* Move changelog entry into `Unreleased` section
Co-authored-by: Freya Gentz <zegentzy@protonmail.com>
Co-authored-by: Kristofer Rye <kristofer.rye@gmail.com>
Co-authored-by: Christian Duerr <contact@christianduerr.com>
2020-03-07 09:43:55 +11:00
|
|
|
modifiers_state: ModifiersState::default(),
|
2019-02-05 03:52:00 +11:00
|
|
|
fullscreen: None,
|
2020-12-01 05:04:26 +11:00
|
|
|
current_theme,
|
|
|
|
preferred_theme,
|
2019-09-16 12:09:08 +10:00
|
|
|
high_surrogate: None,
|
2019-06-22 01:33:15 +10:00
|
|
|
window_flags: WindowFlags::empty(),
|
2019-02-05 03:52:00 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn window_flags(&self) -> WindowFlags {
|
|
|
|
self.window_flags
|
|
|
|
}
|
|
|
|
|
2019-07-30 04:16:14 +10:00
|
|
|
pub fn set_window_flags<F>(mut this: MutexGuard<'_, Self>, window: HWND, f: F)
|
|
|
|
where
|
2019-06-22 01:33:15 +10:00
|
|
|
F: FnOnce(&mut WindowFlags),
|
2019-02-05 03:52:00 +11:00
|
|
|
{
|
|
|
|
let old_flags = this.window_flags;
|
|
|
|
f(&mut this.window_flags);
|
|
|
|
let new_flags = this.window_flags;
|
|
|
|
|
|
|
|
drop(this);
|
2019-07-30 04:16:14 +10:00
|
|
|
old_flags.apply_diff(window, new_flags);
|
2019-02-05 03:52:00 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_window_flags_in_place<F>(&mut self, f: F)
|
2019-06-22 01:33:15 +10:00
|
|
|
where
|
|
|
|
F: FnOnce(&mut WindowFlags),
|
2019-02-05 03:52:00 +11:00
|
|
|
{
|
|
|
|
f(&mut self.window_flags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl MouseProperties {
|
|
|
|
pub fn cursor_flags(&self) -> CursorFlags {
|
|
|
|
self.cursor_flags
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_cursor_flags<F>(&mut self, window: HWND, f: F) -> Result<(), io::Error>
|
2019-06-22 01:33:15 +10:00
|
|
|
where
|
|
|
|
F: FnOnce(&mut CursorFlags),
|
2019-02-05 03:52:00 +11:00
|
|
|
{
|
|
|
|
let old_flags = self.cursor_flags;
|
|
|
|
f(&mut self.cursor_flags);
|
|
|
|
match self.cursor_flags.refresh_os_cursor(window) {
|
|
|
|
Ok(()) => (),
|
|
|
|
Err(e) => {
|
|
|
|
self.cursor_flags = old_flags;
|
|
|
|
return Err(e);
|
2019-06-25 02:14:55 +10:00
|
|
|
}
|
2019-02-05 03:52:00 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl WindowFlags {
|
|
|
|
fn mask(mut self) -> WindowFlags {
|
2020-10-20 01:15:23 +11:00
|
|
|
if self.contains(WindowFlags::MARKER_EXCLUSIVE_FULLSCREEN) {
|
|
|
|
self &= WindowFlags::FULLSCREEN_AND_MASK;
|
|
|
|
self |= WindowFlags::EXCLUSIVE_FULLSCREEN_OR_MASK;
|
|
|
|
} else if self.contains(WindowFlags::MARKER_BORDERLESS_FULLSCREEN) {
|
2019-02-05 03:52:00 +11:00
|
|
|
self &= WindowFlags::FULLSCREEN_AND_MASK;
|
|
|
|
}
|
|
|
|
if !self.contains(WindowFlags::VISIBLE) {
|
|
|
|
self &= WindowFlags::INVISIBLE_AND_MASK;
|
|
|
|
}
|
|
|
|
if !self.contains(WindowFlags::DECORATIONS) {
|
|
|
|
self &= WindowFlags::NO_DECORATIONS_AND_MASK;
|
|
|
|
}
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn to_window_styles(self) -> (DWORD, DWORD) {
|
|
|
|
use winapi::um::winuser::*;
|
|
|
|
|
|
|
|
let (mut style, mut style_ex) = (0, 0);
|
|
|
|
|
|
|
|
if self.contains(WindowFlags::RESIZABLE) {
|
|
|
|
style |= WS_SIZEBOX | WS_MAXIMIZEBOX;
|
|
|
|
}
|
|
|
|
if self.contains(WindowFlags::DECORATIONS) {
|
|
|
|
style |= WS_CAPTION | WS_MINIMIZEBOX | WS_BORDER;
|
|
|
|
style_ex = WS_EX_WINDOWEDGE;
|
|
|
|
}
|
|
|
|
if self.contains(WindowFlags::VISIBLE) {
|
|
|
|
style |= WS_VISIBLE;
|
|
|
|
}
|
|
|
|
if self.contains(WindowFlags::ON_TASKBAR) {
|
|
|
|
style_ex |= WS_EX_APPWINDOW;
|
|
|
|
}
|
|
|
|
if self.contains(WindowFlags::ALWAYS_ON_TOP) {
|
|
|
|
style_ex |= WS_EX_TOPMOST;
|
|
|
|
}
|
|
|
|
if self.contains(WindowFlags::NO_BACK_BUFFER) {
|
|
|
|
style_ex |= WS_EX_NOREDIRECTIONBITMAP;
|
|
|
|
}
|
2019-07-07 03:29:15 +10:00
|
|
|
if self.contains(WindowFlags::TRANSPARENT) && self.contains(WindowFlags::DECORATIONS) {
|
|
|
|
style_ex |= WS_EX_LAYERED;
|
|
|
|
}
|
2019-02-05 03:52:00 +11:00
|
|
|
if self.contains(WindowFlags::CHILD) {
|
|
|
|
style |= WS_CHILD; // This is incompatible with WS_POPUP if that gets added eventually.
|
|
|
|
}
|
2019-12-22 17:04:11 +11:00
|
|
|
if self.contains(WindowFlags::MINIMIZED) {
|
|
|
|
style |= WS_MINIMIZE;
|
|
|
|
}
|
2019-02-05 03:52:00 +11:00
|
|
|
if self.contains(WindowFlags::MAXIMIZED) {
|
|
|
|
style |= WS_MAXIMIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_SYSMENU;
|
|
|
|
style_ex |= WS_EX_ACCEPTFILES;
|
|
|
|
|
|
|
|
(style, style_ex)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Adjust the window client rectangle to the return value, if present.
|
2019-07-30 04:16:14 +10:00
|
|
|
fn apply_diff(mut self, window: HWND, mut new: WindowFlags) {
|
2019-02-05 03:52:00 +11:00
|
|
|
self = self.mask();
|
|
|
|
new = new.mask();
|
|
|
|
|
|
|
|
let diff = self ^ new;
|
|
|
|
if diff == WindowFlags::empty() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if diff.contains(WindowFlags::VISIBLE) {
|
|
|
|
unsafe {
|
|
|
|
winuser::ShowWindow(
|
|
|
|
window,
|
|
|
|
match new.contains(WindowFlags::VISIBLE) {
|
|
|
|
true => winuser::SW_SHOW,
|
2019-06-22 01:33:15 +10:00
|
|
|
false => winuser::SW_HIDE,
|
|
|
|
},
|
2019-02-05 03:52:00 +11:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if diff.contains(WindowFlags::ALWAYS_ON_TOP) {
|
|
|
|
unsafe {
|
|
|
|
winuser::SetWindowPos(
|
|
|
|
window,
|
|
|
|
match new.contains(WindowFlags::ALWAYS_ON_TOP) {
|
2019-06-22 01:33:15 +10:00
|
|
|
true => winuser::HWND_TOPMOST,
|
2019-02-05 03:52:00 +11:00
|
|
|
false => winuser::HWND_NOTOPMOST,
|
|
|
|
},
|
2019-06-22 01:33:15 +10:00
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
2019-11-27 14:49:15 +11:00
|
|
|
winuser::SWP_ASYNCWINDOWPOS
|
|
|
|
| winuser::SWP_NOMOVE
|
|
|
|
| winuser::SWP_NOSIZE
|
|
|
|
| winuser::SWP_NOACTIVATE,
|
2019-02-05 03:52:00 +11:00
|
|
|
);
|
2020-03-08 06:04:24 +11:00
|
|
|
winuser::InvalidateRgn(window, ptr::null_mut(), 0);
|
2019-02-05 03:52:00 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if diff.contains(WindowFlags::MAXIMIZED) || new.contains(WindowFlags::MAXIMIZED) {
|
|
|
|
unsafe {
|
|
|
|
winuser::ShowWindow(
|
|
|
|
window,
|
|
|
|
match new.contains(WindowFlags::MAXIMIZED) {
|
|
|
|
true => winuser::SW_MAXIMIZE,
|
2019-06-22 01:33:15 +10:00
|
|
|
false => winuser::SW_RESTORE,
|
|
|
|
},
|
2019-02-05 03:52:00 +11:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-22 17:04:11 +11:00
|
|
|
// Minimize operations should execute after maximize for proper window animations
|
|
|
|
if diff.contains(WindowFlags::MINIMIZED) {
|
|
|
|
unsafe {
|
|
|
|
winuser::ShowWindow(
|
|
|
|
window,
|
|
|
|
match new.contains(WindowFlags::MINIMIZED) {
|
|
|
|
true => winuser::SW_MINIMIZE,
|
|
|
|
false => winuser::SW_RESTORE,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-05 03:52:00 +11:00
|
|
|
if diff != WindowFlags::empty() {
|
|
|
|
let (style, style_ex) = new.to_window_styles();
|
|
|
|
|
|
|
|
unsafe {
|
2019-02-06 02:30:33 +11:00
|
|
|
winuser::SendMessageW(window, *event_loop::SET_RETAIN_STATE_ON_SIZE_MSG_ID, 1, 0);
|
2019-02-05 03:52:00 +11:00
|
|
|
|
2019-12-22 17:04:11 +11:00
|
|
|
// This condition is necessary to avoid having an unrestorable window
|
|
|
|
if !new.contains(WindowFlags::MINIMIZED) {
|
|
|
|
winuser::SetWindowLongW(window, winuser::GWL_STYLE, style as _);
|
|
|
|
winuser::SetWindowLongW(window, winuser::GWL_EXSTYLE, style_ex as _);
|
|
|
|
}
|
2019-02-05 03:52:00 +11:00
|
|
|
|
2019-07-30 04:16:14 +10:00
|
|
|
let mut flags = winuser::SWP_NOZORDER
|
|
|
|
| winuser::SWP_NOMOVE
|
|
|
|
| winuser::SWP_NOSIZE
|
|
|
|
| winuser::SWP_FRAMECHANGED;
|
|
|
|
|
|
|
|
// We generally don't want style changes here to affect window
|
|
|
|
// focus, but for fullscreen windows they must be activated
|
|
|
|
// (i.e. focused) so that they appear on top of the taskbar
|
2020-10-20 01:15:23 +11:00
|
|
|
if !new.contains(WindowFlags::MARKER_EXCLUSIVE_FULLSCREEN)
|
|
|
|
&& !new.contains(WindowFlags::MARKER_BORDERLESS_FULLSCREEN)
|
|
|
|
{
|
2019-07-30 04:16:14 +10:00
|
|
|
flags |= winuser::SWP_NOACTIVATE;
|
2019-02-05 03:52:00 +11:00
|
|
|
}
|
2019-07-30 04:16:14 +10:00
|
|
|
|
|
|
|
// Refresh the window frame
|
|
|
|
winuser::SetWindowPos(window, ptr::null_mut(), 0, 0, 0, 0, flags);
|
2019-02-06 02:30:33 +11:00
|
|
|
winuser::SendMessageW(window, *event_loop::SET_RETAIN_STATE_ON_SIZE_MSG_ID, 0, 0);
|
2019-02-05 03:52:00 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CursorFlags {
|
|
|
|
fn refresh_os_cursor(self, window: HWND) -> Result<(), io::Error> {
|
|
|
|
let client_rect = util::get_client_rect(window)?;
|
|
|
|
|
|
|
|
if util::is_focused(window) {
|
2019-09-18 01:34:48 +10:00
|
|
|
let cursor_clip = match self.contains(CursorFlags::GRABBED) {
|
|
|
|
true => Some(client_rect),
|
|
|
|
false => None,
|
|
|
|
};
|
|
|
|
|
|
|
|
let rect_to_tuple = |rect: RECT| (rect.left, rect.top, rect.right, rect.bottom);
|
|
|
|
let active_cursor_clip = rect_to_tuple(util::get_cursor_clip()?);
|
|
|
|
let desktop_rect = rect_to_tuple(util::get_desktop_rect());
|
|
|
|
|
|
|
|
let active_cursor_clip = match desktop_rect == active_cursor_clip {
|
|
|
|
true => None,
|
|
|
|
false => Some(active_cursor_clip),
|
|
|
|
};
|
|
|
|
|
|
|
|
// We do this check because calling `set_cursor_clip` incessantly will flood the event
|
|
|
|
// loop with `WM_MOUSEMOVE` events, and `refresh_os_cursor` is called by `set_cursor_flags`
|
|
|
|
// which at times gets called once every iteration of the eventloop.
|
|
|
|
if active_cursor_clip != cursor_clip.map(rect_to_tuple) {
|
|
|
|
util::set_cursor_clip(cursor_clip)?;
|
2019-02-05 03:52:00 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let cursor_in_client = self.contains(CursorFlags::IN_WINDOW);
|
|
|
|
if cursor_in_client {
|
|
|
|
util::set_cursor_hidden(self.contains(CursorFlags::HIDDEN));
|
|
|
|
} else {
|
|
|
|
util::set_cursor_hidden(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|