Skip to content

Commit

Permalink
On Windows and MacOS, add Window::has_focus
Browse files Browse the repository at this point in the history
  • Loading branch information
amrbashir authored and kchibisov committed Jan 17, 2023
1 parent 067535e commit 3798762
Show file tree
Hide file tree
Showing 17 changed files with 102 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ And please only add new entries to the top of this list, right below the `# Unre

# Unreleased

- Add `Window::has_focus`.
- On Windows, fix `Window::set_minimized(false)` not working for windows minimized by `Win + D` hotkey.
- **Breaking:** On Web, touch input no longer fires `WindowEvent::Cursor*`, `WindowEvent::MouseInput`, or `DeviceEvent::MouseMotion` like other platforms, but instead it fires `WindowEvent::Touch`.
- **Breaking:** Removed platform specific `WindowBuilder::with_parent` API in favor of `WindowBuilder::with_parent_window`.
Expand Down
11 changes: 10 additions & 1 deletion src/platform_impl/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::{
hash::Hash,
sync::{
atomic::{AtomicBool, Ordering},
mpsc, Arc,
mpsc, Arc, RwLock,
},
time::{Duration, Instant},
};
Expand All @@ -14,6 +14,7 @@ use android_activity::input::{InputEvent, KeyAction, Keycode, MotionAction};
use android_activity::{
AndroidApp, AndroidAppWaker, ConfigurationRef, InputStatus, MainEvent, Rect,
};
use once_cell::sync::Lazy;
use raw_window_handle::{
AndroidDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle,
};
Expand All @@ -27,6 +28,8 @@ use crate::{
window::{self, CursorGrabMode, ResizeDirection, Theme, WindowButtons, WindowLevel},
};

static HAS_FOCUS: Lazy<RwLock<bool>> = Lazy::new(|| RwLock::new(true));

fn ndk_keycode_to_virtualkeycode(keycode: Keycode) -> Option<event::VirtualKeyCode> {
match keycode {
Keycode::A => Some(VirtualKeyCode::A),
Expand Down Expand Up @@ -394,6 +397,7 @@ impl<T: 'static> EventLoop<T> {
warn!("TODO: find a way to notify application of content rect change");
}
MainEvent::GainedFocus => {
*HAS_FOCUS.write().unwrap() = true;
sticky_exit_callback(
event::Event::WindowEvent {
window_id: window::WindowId(WindowId),
Expand All @@ -405,6 +409,7 @@ impl<T: 'static> EventLoop<T> {
);
}
MainEvent::LostFocus => {
*HAS_FOCUS.write().unwrap() = false;
sticky_exit_callback(
event::Event::WindowEvent {
window_id: window::WindowId(WindowId),
Expand Down Expand Up @@ -1064,6 +1069,10 @@ impl Window {
None
}

pub fn has_focus(&self) -> bool {
*HAS_FOCUS.read().unwrap()
}

pub fn title(&self) -> String {
String::new()
}
Expand Down
3 changes: 3 additions & 0 deletions src/platform_impl/ios/uikit/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,8 @@ extern_methods!(

#[sel(makeKeyAndVisible)]
pub fn makeKeyAndVisible(&self);

#[sel(isKeyWindow)]
pub fn isKeyWindow(&self) -> bool;
}
);
4 changes: 4 additions & 0 deletions src/platform_impl/ios/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,10 @@ impl Inner {
None
}

pub fn has_focus(&self) -> bool {
self.window.isKeyWindow()
}

#[inline]
pub fn set_theme(&self, _theme: Option<Theme>) {
warn!("`Window::set_theme` is ignored on iOS");
Expand Down
4 changes: 4 additions & 0 deletions src/platform_impl/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,10 @@ impl Window {
}

#[inline]
pub fn has_focus(&self) -> bool {
x11_or_wayland!(match self; Window(window) => window.has_focus())
}

pub fn title(&self) -> String {
x11_or_wayland!(match self; Window(window) => window.title())
}
Expand Down
8 changes: 8 additions & 0 deletions src/platform_impl/linux/wayland/seat/keyboard/handlers.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Handling of various keyboard events.
use std::sync::atomic::Ordering;

use sctk::reexports::client::protocol::wl_keyboard::KeyState;

use sctk::seat::keyboard::Event as KeyboardEvent;
Expand All @@ -22,6 +24,9 @@ pub(super) fn handle_keyboard(
KeyboardEvent::Enter { surface, .. } => {
let window_id = wayland::make_wid(&surface);

let window_handle = winit_state.window_map.get_mut(&window_id).unwrap();
window_handle.has_focus.store(true, Ordering::Relaxed);

// Window gained focus.
event_sink.push_window_event(WindowEvent::Focused(true), window_id);

Expand All @@ -44,6 +49,9 @@ pub(super) fn handle_keyboard(
);
}

let window_handle = winit_state.window_map.get_mut(&window_id).unwrap();
window_handle.has_focus.store(false, Ordering::Relaxed);

// Window lost focus.
event_sink.push_window_event(WindowEvent::Focused(false), window_id);

Expand Down
10 changes: 10 additions & 0 deletions src/platform_impl/linux/wayland/window/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ pub struct Window {

/// Grabbing mode.
cursor_grab_mode: Mutex<CursorGrabMode>,

/// Whether the window has keyboard focus.
has_focus: Arc<AtomicBool>,
}

impl Window {
Expand Down Expand Up @@ -244,6 +247,7 @@ impl Window {
window.surface().commit();

let size = Arc::new(Mutex::new(LogicalSize::new(width, height)));
let has_focus = Arc::new(AtomicBool::new(true));

// We should trigger redraw and commit the surface for the newly created window.
let mut window_user_request = WindowUserRequest::new();
Expand All @@ -258,6 +262,7 @@ impl Window {
&event_loop_window_target.env,
window,
size.clone(),
has_focus.clone(),
window_requests.clone(),
);

Expand Down Expand Up @@ -318,6 +323,7 @@ impl Window {
resizeable: AtomicBool::new(attributes.resizable),
decorated: AtomicBool::new(attributes.decorations),
cursor_grab_mode: Mutex::new(CursorGrabMode::None),
has_focus,
};

Ok(window)
Expand Down Expand Up @@ -650,6 +656,10 @@ impl Window {
}

#[inline]
pub fn has_focus(&self) -> bool {
self.has_focus.load(Ordering::Relaxed)
}

pub fn title(&self) -> String {
String::new()
}
Expand Down
6 changes: 6 additions & 0 deletions src/platform_impl/linux/wayland/window/shim.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::cell::Cell;
use std::mem::ManuallyDrop;
use std::sync::atomic::AtomicBool;
use std::sync::{Arc, Mutex};

use sctk::reexports::client::protocol::wl_compositor::WlCompositor;
Expand Down Expand Up @@ -154,6 +155,9 @@ pub struct WindowHandle {
/// Whether the window is resizable.
pub is_resizable: Cell<bool>,

/// Whether the window has keyboard focus.
pub has_focus: Arc<AtomicBool>,

/// Allow IME events for that window.
pub ime_allowed: Cell<bool>,

Expand Down Expand Up @@ -187,6 +191,7 @@ impl WindowHandle {
env: &Environment<WinitEnv>,
window: Window<WinitFrame>,
size: Arc<Mutex<LogicalSize<u32>>>,
has_focus: Arc<AtomicBool>,
pending_window_requests: Arc<Mutex<Vec<WindowRequest>>>,
) -> Self {
let xdg_activation = env.get_global::<XdgActivationV1>();
Expand All @@ -209,6 +214,7 @@ impl WindowHandle {
attention_requested: Cell::new(false),
compositor,
ime_allowed: Cell::new(false),
has_focus,
}
}

Expand Down
8 changes: 8 additions & 0 deletions src/platform_impl/linux/x11/event_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,10 @@ impl<T: 'static> EventProcessor<T> {
let window_id = mkwid(xev.event);
let position = PhysicalPosition::new(xev.event_x, xev.event_y);

if let Some(window) = self.with_window(xev.event, Arc::clone) {
window.shared_state_lock().has_focus = true;
}

callback(Event::WindowEvent {
window_id,
event: Focused(true),
Expand Down Expand Up @@ -1002,6 +1006,10 @@ impl<T: 'static> EventProcessor<T> {
event: WindowEvent::ModifiersChanged(ModifiersState::empty()),
});

if let Some(window) = self.with_window(xev.event, Arc::clone) {
window.shared_state_lock().has_focus = false;
}

callback(Event::WindowEvent {
window_id,
event: Focused(false),
Expand Down
6 changes: 6 additions & 0 deletions src/platform_impl/linux/x11/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ pub struct SharedState {
pub resize_increments: Option<Size>,
pub base_size: Option<Size>,
pub visibility: Visibility,
pub has_focus: bool,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
Expand Down Expand Up @@ -94,6 +95,7 @@ impl SharedState {
max_inner_size: None,
resize_increments: None,
base_size: None,
has_focus: true,
})
}
}
Expand Down Expand Up @@ -1602,6 +1604,10 @@ impl UnownedWindow {
}

#[inline]
pub fn has_focus(&self) -> bool {
self.shared_state_lock().has_focus
}

pub fn title(&self) -> String {
String::new()
}
Expand Down
3 changes: 3 additions & 0 deletions src/platform_impl/macos/appkit/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,9 @@ extern_methods!(
#[sel(isVisible)]
pub fn isVisible(&self) -> bool;

#[sel(isKeyWindow)]
pub fn isKeyWindow(&self) -> bool;

#[sel(isZoomed)]
pub fn isZoomed(&self) -> bool;

Expand Down
4 changes: 4 additions & 0 deletions src/platform_impl/macos/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1215,6 +1215,10 @@ impl WinitWindow {
}

#[inline]
pub fn has_focus(&self) -> bool {
self.isKeyWindow()
}

pub fn set_theme(&self, theme: Option<Theme>) {
set_ns_theme(theme);
self.lock_shared_state("set_theme").current_theme = theme.or_else(|| Some(get_ns_theme()));
Expand Down
5 changes: 5 additions & 0 deletions src/platform_impl/orbital/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,11 @@ impl Window {
None
}

#[inline]
pub fn has_focus(&self) -> bool {
false
}

#[inline]
pub fn set_theme(&self, _theme: Option<window::Theme>) {}
}
Expand Down
7 changes: 7 additions & 0 deletions src/platform_impl/web/event_loop/window_target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ impl<T> EventLoopWindowTarget<T> {
canvas: &Rc<RefCell<backend::Canvas>>,
id: WindowId,
prevent_default: bool,
has_focus: Rc<RefCell<bool>>,
) {
self.runner.add_canvas(RootWindowId(id), canvas);
let mut canvas = canvas.borrow_mut();
Expand All @@ -65,15 +66,19 @@ impl<T> EventLoopWindowTarget<T> {
canvas.on_touch_end(prevent_default);

let runner = self.runner.clone();
let has_focus_clone = has_focus.clone();
canvas.on_blur(move || {
*has_focus_clone.borrow_mut() = false;
runner.send_event(Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::Focused(false),
});
});

let runner = self.runner.clone();
let has_focus_clone = has_focus.clone();
canvas.on_focus(move || {
*has_focus_clone.borrow_mut() = true;
runner.send_event(Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::Focused(true),
Expand Down Expand Up @@ -191,6 +196,8 @@ impl<T> EventLoopWindowTarget<T> {
let runner_touch = self.runner.clone();
canvas.on_mouse_press(
move |pointer_id, position, button, modifiers| {
*has_focus.borrow_mut() = true;

// A mouse down event may come in without any prior CursorMoved events,
// therefore we should send a CursorMoved event to make sure that the
// user code has the correct cursor position.
Expand Down
9 changes: 8 additions & 1 deletion src/platform_impl/web/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub struct Window {
register_redraw_request: Box<dyn Fn()>,
resize_notify_fn: Box<dyn Fn(PhysicalSize<u32>)>,
destroy_fn: Option<Box<dyn FnOnce()>>,
has_focus: Rc<RefCell<bool>>,
}

impl Window {
Expand All @@ -42,7 +43,8 @@ impl Window {

let register_redraw_request = Box::new(move || runner.request_redraw(RootWI(id)));

target.register(&canvas, id, prevent_default);
let has_focus = Rc::new(RefCell::new(false));
target.register(&canvas, id, prevent_default, has_focus.clone());

let runner = target.runner.clone();
let resize_notify_fn = Box::new(move |new_size| {
Expand All @@ -62,6 +64,7 @@ impl Window {
register_redraw_request,
resize_notify_fn,
destroy_fn: Some(destroy_fn),
has_focus,
};

backend::set_canvas_size(
Expand Down Expand Up @@ -399,6 +402,10 @@ impl Window {
}

#[inline]
pub fn has_focus(&self) -> bool {
*self.has_focus.borrow()
}

pub fn title(&self) -> String {
String::new()
}
Expand Down
5 changes: 5 additions & 0 deletions src/platform_impl/windows/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,11 @@ impl Window {
}

#[inline]
pub fn has_focus(&self) -> bool {
let window_state = self.window_state.lock().unwrap();
window_state.has_active_focus()
}

pub fn title(&self) -> String {
let len = unsafe { GetWindowTextLengthW(self.window.0) } + 1;
let mut buf = vec![0; len as usize];
Expand Down
10 changes: 10 additions & 0 deletions src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1022,6 +1022,16 @@ impl Window {
self.window.focus_window()
}

/// Gets whether the window has keyboard focus.
///
/// This queries the same state information as [`WindowEvent::Focused`].
///
/// [`WindowEvent::Focused`]: crate::event::WindowEvent::Focused
#[inline]
pub fn has_focus(&self) -> bool {
self.window.has_focus()
}

/// Requests user attention to the window, this has no effect if the application
/// is already focused. How requesting for user attention manifests is platform dependent,
/// see [`UserAttentionType`] for details.
Expand Down

0 comments on commit 3798762

Please sign in to comment.