mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2025-01-11 21:31:29 +11:00
Prevent stealing focus on new windows (#1176)
This commit is contained in:
parent
695547f4ca
commit
eb20612d77
|
@ -15,6 +15,8 @@
|
||||||
- On macOS, fix events not being emitted during modal loops, such as when windows are being resized
|
- On macOS, fix events not being emitted during modal loops, such as when windows are being resized
|
||||||
by the user.
|
by the user.
|
||||||
- On Windows, fix hovering the mouse over the active window creating an endless stream of CursorMoved events.
|
- On Windows, fix hovering the mouse over the active window creating an endless stream of CursorMoved events.
|
||||||
|
- On X11, prevent stealing input focus when creating a new window.
|
||||||
|
Only steal input focus when entering fullscreen mode.
|
||||||
|
|
||||||
# 0.20.0 Alpha 3 (2019-08-14)
|
# 0.20.0 Alpha 3 (2019-08-14)
|
||||||
|
|
||||||
|
|
|
@ -56,12 +56,14 @@ pub struct SharedState {
|
||||||
pub frame_extents: Option<util::FrameExtentsHeuristic>,
|
pub frame_extents: Option<util::FrameExtentsHeuristic>,
|
||||||
pub min_inner_size: Option<LogicalSize>,
|
pub min_inner_size: Option<LogicalSize>,
|
||||||
pub max_inner_size: Option<LogicalSize>,
|
pub max_inner_size: Option<LogicalSize>,
|
||||||
|
pub is_visible: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SharedState {
|
impl SharedState {
|
||||||
fn new(dpi_factor: f64) -> Mutex<Self> {
|
fn new(dpi_factor: f64, is_visible: bool) -> Mutex<Self> {
|
||||||
let mut shared_state = SharedState::default();
|
let mut shared_state = SharedState::default();
|
||||||
shared_state.guessed_dpi = Some(dpi_factor);
|
shared_state.guessed_dpi = Some(dpi_factor);
|
||||||
|
shared_state.is_visible = is_visible;
|
||||||
Mutex::new(shared_state)
|
Mutex::new(shared_state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -230,7 +232,7 @@ impl UnownedWindow {
|
||||||
cursor_grabbed: Mutex::new(false),
|
cursor_grabbed: Mutex::new(false),
|
||||||
cursor_visible: Mutex::new(true),
|
cursor_visible: Mutex::new(true),
|
||||||
ime_sender: Mutex::new(event_loop.ime_sender.clone()),
|
ime_sender: Mutex::new(event_loop.ime_sender.clone()),
|
||||||
shared_state: SharedState::new(dpi_factor),
|
shared_state: SharedState::new(dpi_factor, window_attrs.visible),
|
||||||
pending_redraws: event_loop.pending_redraws.clone(),
|
pending_redraws: event_loop.pending_redraws.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -355,6 +357,8 @@ impl UnownedWindow {
|
||||||
unsafe {
|
unsafe {
|
||||||
(xconn.xlib.XMapRaised)(xconn.display, window.xwindow);
|
(xconn.xlib.XMapRaised)(xconn.display, window.xwindow);
|
||||||
} //.queue();
|
} //.queue();
|
||||||
|
|
||||||
|
window.wait_for_visibility_notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to make keyboard input repeat detectable
|
// Attempt to make keyboard input repeat detectable
|
||||||
|
@ -420,27 +424,6 @@ impl UnownedWindow {
|
||||||
.set_always_on_top_inner(window_attrs.always_on_top)
|
.set_always_on_top_inner(window_attrs.always_on_top)
|
||||||
.queue();
|
.queue();
|
||||||
}
|
}
|
||||||
|
|
||||||
if window_attrs.visible {
|
|
||||||
unsafe {
|
|
||||||
// XSetInputFocus generates an error if the window is not visible, so we wait
|
|
||||||
// until we receive VisibilityNotify.
|
|
||||||
let mut event = MaybeUninit::uninit();
|
|
||||||
(xconn.xlib.XIfEvent)(
|
|
||||||
// This will flush the request buffer IF it blocks.
|
|
||||||
xconn.display,
|
|
||||||
event.as_mut_ptr(),
|
|
||||||
Some(visibility_predicate),
|
|
||||||
window.xwindow as _,
|
|
||||||
);
|
|
||||||
(xconn.xlib.XSetInputFocus)(
|
|
||||||
xconn.display,
|
|
||||||
window.xwindow,
|
|
||||||
ffi::RevertToParent,
|
|
||||||
ffi::CurrentTime,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We never want to give the user a broken window, since by then, it's too late to handle.
|
// We never want to give the user a broken window, since by then, it's too late to handle.
|
||||||
|
@ -566,11 +549,32 @@ impl UnownedWindow {
|
||||||
fn set_fullscreen_hint(&self, fullscreen: bool) -> util::Flusher<'_> {
|
fn set_fullscreen_hint(&self, fullscreen: bool) -> util::Flusher<'_> {
|
||||||
let fullscreen_atom =
|
let fullscreen_atom =
|
||||||
unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_STATE_FULLSCREEN\0") };
|
unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_STATE_FULLSCREEN\0") };
|
||||||
self.set_netwm(fullscreen.into(), (fullscreen_atom as c_long, 0, 0, 0))
|
let flusher = self.set_netwm(fullscreen.into(), (fullscreen_atom as c_long, 0, 0, 0));
|
||||||
|
|
||||||
|
if fullscreen {
|
||||||
|
// Ensure that the fullscreen window receives input focus to prevent
|
||||||
|
// locking up the user's display.
|
||||||
|
unsafe {
|
||||||
|
(self.xconn.xlib.XSetInputFocus)(
|
||||||
|
self.xconn.display,
|
||||||
|
self.xwindow,
|
||||||
|
ffi::RevertToParent,
|
||||||
|
ffi::CurrentTime,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flusher
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_fullscreen_inner(&self, fullscreen: Option<Fullscreen>) -> Option<util::Flusher<'_>> {
|
fn set_fullscreen_inner(&self, fullscreen: Option<Fullscreen>) -> Option<util::Flusher<'_>> {
|
||||||
let mut shared_state_lock = self.shared_state.lock();
|
let mut shared_state_lock = self.shared_state.lock();
|
||||||
|
|
||||||
|
if !shared_state_lock.is_visible {
|
||||||
|
// Setting fullscreen on a window that is not visible will generate an error.
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let old_fullscreen = shared_state_lock.fullscreen.clone();
|
let old_fullscreen = shared_state_lock.fullscreen.clone();
|
||||||
if old_fullscreen == fullscreen {
|
if old_fullscreen == fullscreen {
|
||||||
return None;
|
return None;
|
||||||
|
@ -681,7 +685,7 @@ impl UnownedWindow {
|
||||||
pub fn set_fullscreen(&self, fullscreen: Option<Fullscreen>) {
|
pub fn set_fullscreen(&self, fullscreen: Option<Fullscreen>) {
|
||||||
if let Some(flusher) = self.set_fullscreen_inner(fullscreen) {
|
if let Some(flusher) = self.set_fullscreen_inner(fullscreen) {
|
||||||
flusher
|
flusher
|
||||||
.flush()
|
.sync()
|
||||||
.expect("Failed to change window fullscreen state");
|
.expect("Failed to change window fullscreen state");
|
||||||
self.invalidate_cached_frame_extents();
|
self.invalidate_cached_frame_extents();
|
||||||
}
|
}
|
||||||
|
@ -837,12 +841,22 @@ impl UnownedWindow {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_visible(&self, visible: bool) {
|
pub fn set_visible(&self, visible: bool) {
|
||||||
|
let is_visible = self.shared_state.lock().is_visible;
|
||||||
|
|
||||||
|
if visible == is_visible {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
match visible {
|
match visible {
|
||||||
true => unsafe {
|
true => unsafe {
|
||||||
(self.xconn.xlib.XMapRaised)(self.xconn.display, self.xwindow);
|
(self.xconn.xlib.XMapRaised)(self.xconn.display, self.xwindow);
|
||||||
self.xconn
|
self.xconn
|
||||||
.flush_requests()
|
.flush_requests()
|
||||||
.expect("Failed to call XMapRaised");
|
.expect("Failed to call XMapRaised");
|
||||||
|
|
||||||
|
// Some X requests may generate an error if the window is not
|
||||||
|
// visible, so we must wait until the window becomes visible.
|
||||||
|
self.wait_for_visibility_notify();
|
||||||
},
|
},
|
||||||
false => unsafe {
|
false => unsafe {
|
||||||
(self.xconn.xlib.XUnmapWindow)(self.xconn.display, self.xwindow);
|
(self.xconn.xlib.XUnmapWindow)(self.xconn.display, self.xwindow);
|
||||||
|
@ -851,6 +865,21 @@ impl UnownedWindow {
|
||||||
.expect("Failed to call XUnmapWindow");
|
.expect("Failed to call XUnmapWindow");
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.shared_state.lock().is_visible = visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wait_for_visibility_notify(&self) {
|
||||||
|
unsafe {
|
||||||
|
let mut event = MaybeUninit::uninit();
|
||||||
|
|
||||||
|
(self.xconn.xlib.XIfEvent)(
|
||||||
|
self.xconn.display,
|
||||||
|
event.as_mut_ptr(),
|
||||||
|
Some(visibility_predicate),
|
||||||
|
self.xwindow as _,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_cached_frame_extents(&self) {
|
fn update_cached_frame_extents(&self) {
|
||||||
|
|
Loading…
Reference in a new issue