Add 'request_user_attention' to Window
This commit introduces a cross platform way to request a user attention to the window via a 'request_user_attention' method on a Window struct. This method is inspired by macOS's 'request_user_attention' method and thus reuses its signature and semantics to some extent.
This commit is contained in:
parent
f79efec7ef
commit
0861a353d6
11 changed files with 136 additions and 79 deletions
|
|
@ -484,6 +484,8 @@ impl Window {
|
|||
|
||||
pub fn set_ime_position(&self, _position: Position) {}
|
||||
|
||||
pub fn request_user_attention(&self, _request_type: Option<window::UserAttentionType>) {}
|
||||
|
||||
pub fn set_cursor_icon(&self, _: window::CursorIcon) {}
|
||||
|
||||
pub fn set_cursor_position(&self, _: Position) -> Result<(), error::ExternalError> {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,9 @@ use crate::{
|
|||
},
|
||||
monitor, view, EventLoopWindowTarget, MonitorHandle,
|
||||
},
|
||||
window::{CursorIcon, Fullscreen, WindowAttributes, WindowId as RootWindowId},
|
||||
window::{
|
||||
CursorIcon, Fullscreen, UserAttentionType, WindowAttributes, WindowId as RootWindowId,
|
||||
},
|
||||
};
|
||||
|
||||
pub struct Inner {
|
||||
|
|
@ -260,6 +262,10 @@ impl Inner {
|
|||
warn!("`Window::set_ime_position` is ignored on iOS")
|
||||
}
|
||||
|
||||
pub fn request_user_attention(&self, _request_type: Option<UserAttentionType>) {
|
||||
warn!("`Window::request_user_attention` is ignored on iOS")
|
||||
}
|
||||
|
||||
// Allow directly accessing the current monitor internally without unwrapping.
|
||||
fn current_monitor_inner(&self) -> RootMonitorHandle {
|
||||
unsafe {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ use crate::{
|
|||
event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW},
|
||||
icon::Icon,
|
||||
monitor::{MonitorHandle as RootMonitorHandle, VideoMode as RootVideoMode},
|
||||
window::{CursorIcon, Fullscreen, WindowAttributes},
|
||||
window::{CursorIcon, Fullscreen, UserAttentionType, WindowAttributes},
|
||||
};
|
||||
|
||||
pub(crate) use crate::icon::RgbaIcon as PlatformIcon;
|
||||
|
|
@ -418,6 +418,16 @@ impl Window {
|
|||
x11_or_wayland!(match self; Window(w) => w.set_ime_position(position))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn request_user_attention(&self, _request_type: Option<UserAttentionType>) {
|
||||
match self {
|
||||
#[cfg(feature = "x11")]
|
||||
&Window::X(ref w) => w.request_user_attention(_request_type),
|
||||
#[cfg(feature = "wayland")]
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn request_redraw(&self) {
|
||||
x11_or_wayland!(match self; Window(w) => w.request_redraw())
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ use crate::{
|
|||
MonitorHandle as PlatformMonitorHandle, OsError, PlatformSpecificWindowBuilderAttributes,
|
||||
VideoMode as PlatformVideoMode,
|
||||
},
|
||||
window::{CursorIcon, Fullscreen, Icon, WindowAttributes},
|
||||
window::{CursorIcon, Fullscreen, Icon, UserAttentionType, WindowAttributes},
|
||||
};
|
||||
|
||||
use super::{ffi, util, EventLoopWindowTarget, ImeSender, WindowId, XConnection, XError};
|
||||
|
|
@ -523,23 +523,6 @@ impl UnownedWindow {
|
|||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_urgent(&self, is_urgent: bool) {
|
||||
let mut wm_hints = self
|
||||
.xconn
|
||||
.get_wm_hints(self.xwindow)
|
||||
.expect("`XGetWMHints` failed");
|
||||
if is_urgent {
|
||||
(*wm_hints).flags |= ffi::XUrgencyHint;
|
||||
} else {
|
||||
(*wm_hints).flags &= !ffi::XUrgencyHint;
|
||||
}
|
||||
self.xconn
|
||||
.set_wm_hints(self.xwindow, wm_hints)
|
||||
.flush()
|
||||
.expect("Failed to set urgency hint");
|
||||
}
|
||||
|
||||
fn set_netwm(
|
||||
&self,
|
||||
operation: util::StateOperation,
|
||||
|
|
@ -1306,6 +1289,23 @@ impl UnownedWindow {
|
|||
self.set_ime_position_physical(x, y);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn request_user_attention(&self, request_type: Option<UserAttentionType>) {
|
||||
let mut wm_hints = self
|
||||
.xconn
|
||||
.get_wm_hints(self.xwindow)
|
||||
.expect("`XGetWMHints` failed");
|
||||
if request_type.is_some() {
|
||||
(*wm_hints).flags |= ffi::XUrgencyHint;
|
||||
} else {
|
||||
(*wm_hints).flags &= !ffi::XUrgencyHint;
|
||||
}
|
||||
self.xconn
|
||||
.set_wm_hints(self.xwindow, wm_hints)
|
||||
.flush()
|
||||
.expect("Failed to set urgency hint");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn id(&self) -> WindowId {
|
||||
WindowId(self.xwindow)
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use crate::{
|
|||
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
||||
icon::Icon,
|
||||
monitor::{MonitorHandle as RootMonitorHandle, VideoMode as RootVideoMode},
|
||||
platform::macos::{ActivationPolicy, RequestUserAttentionType, WindowExtMacOS},
|
||||
platform::macos::{ActivationPolicy, WindowExtMacOS},
|
||||
platform_impl::platform::{
|
||||
app_state::AppState,
|
||||
app_state::INTERRUPT_EVENT_LOOP_EXIT,
|
||||
|
|
@ -28,7 +28,9 @@ use crate::{
|
|||
window_delegate::new_delegate,
|
||||
OsError,
|
||||
},
|
||||
window::{CursorIcon, Fullscreen, WindowAttributes, WindowId as RootWindowId},
|
||||
window::{
|
||||
CursorIcon, Fullscreen, UserAttentionType, WindowAttributes, WindowId as RootWindowId,
|
||||
},
|
||||
};
|
||||
use cocoa::{
|
||||
appkit::{
|
||||
|
|
@ -977,6 +979,19 @@ impl UnownedWindow {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn request_user_attention(&self, request_type: Option<UserAttentionType>) {
|
||||
let ns_request_type = request_type.map(|ty| match ty {
|
||||
UserAttentionType::Critical => NSRequestUserAttentionType::NSCriticalRequest,
|
||||
UserAttentionType::Informational => NSRequestUserAttentionType::NSInformationalRequest,
|
||||
});
|
||||
unsafe {
|
||||
if let Some(ty) = ns_request_type {
|
||||
NSApp().requestUserAttention_(ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
// Allow directly accessing the current monitor internally without unwrapping.
|
||||
pub(crate) fn current_monitor_inner(&self) -> RootMonitorHandle {
|
||||
|
|
@ -1030,18 +1045,6 @@ impl WindowExtMacOS for UnownedWindow {
|
|||
*self.ns_view as *mut _
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn request_user_attention(&self, request_type: RequestUserAttentionType) {
|
||||
unsafe {
|
||||
NSApp().requestUserAttention_(match request_type {
|
||||
RequestUserAttentionType::Critical => NSRequestUserAttentionType::NSCriticalRequest,
|
||||
RequestUserAttentionType::Informational => {
|
||||
NSRequestUserAttentionType::NSInformationalRequest
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simple_fullscreen(&self) -> bool {
|
||||
let shared_state_lock = self.shared_state.lock().unwrap();
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ use crate::error::{ExternalError, NotSupportedError, OsError as RootOE};
|
|||
use crate::event;
|
||||
use crate::icon::Icon;
|
||||
use crate::monitor::MonitorHandle as RootMH;
|
||||
use crate::window::{CursorIcon, Fullscreen, WindowAttributes, WindowId as RootWI};
|
||||
use crate::window::{
|
||||
CursorIcon, Fullscreen, UserAttentionType, WindowAttributes, WindowId as RootWI,
|
||||
};
|
||||
|
||||
use raw_window_handle::web::WebHandle;
|
||||
|
||||
|
|
@ -268,6 +270,11 @@ impl Window {
|
|||
// Currently a no-op as it does not seem there is good support for this on web
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn request_user_attention(&self, _request_type: Option<UserAttentionType>) {
|
||||
// Currently an intentional no-op
|
||||
}
|
||||
|
||||
#[inline]
|
||||
// Allow directly accessing the current monitor internally without unwrapping.
|
||||
fn current_monitor_inner(&self) -> RootMH {
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ use crate::{
|
|||
window_state::{CursorFlags, SavedWindow, WindowFlags, WindowState},
|
||||
PlatformSpecificWindowBuilderAttributes, WindowId,
|
||||
},
|
||||
window::{CursorIcon, Fullscreen, WindowAttributes},
|
||||
window::{CursorIcon, Fullscreen, UserAttentionType, WindowAttributes},
|
||||
};
|
||||
|
||||
/// The Win32 implementation of the main `Window` object.
|
||||
|
|
@ -621,6 +621,37 @@ impl Window {
|
|||
warn!("`Window::set_ime_position` is ignored on Windows")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn request_user_attention(&self, request_type: Option<UserAttentionType>) {
|
||||
let window = self.window.clone();
|
||||
let active_window_handle = unsafe { winuser::GetActiveWindow() };
|
||||
if window.0 == active_window_handle {
|
||||
return;
|
||||
}
|
||||
|
||||
self.thread_executor.execute_in_thread(move || unsafe {
|
||||
let (flags, count) = request_type
|
||||
.map(|ty| match ty {
|
||||
UserAttentionType::Critical => {
|
||||
(winuser::FLASHW_ALL | winuser::FLASHW_TIMERNOFG, u32::MAX)
|
||||
}
|
||||
UserAttentionType::Informational => {
|
||||
(winuser::FLASHW_TRAY | winuser::FLASHW_TIMERNOFG, 0)
|
||||
}
|
||||
})
|
||||
.unwrap_or((winuser::FLASHW_STOP, 0));
|
||||
|
||||
let mut flash_info = winuser::FLASHWINFO {
|
||||
cbSize: mem::size_of::<winuser::FLASHWINFO>() as UINT,
|
||||
hwnd: window.0,
|
||||
dwFlags: flags,
|
||||
uCount: count,
|
||||
dwTimeout: 0,
|
||||
};
|
||||
winuser::FlashWindowEx(&mut flash_info);
|
||||
});
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_dark_mode(&self) -> bool {
|
||||
self.window_state.lock().is_dark_mode
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue