Skip to content

Commit 5b6e9a0

Browse files
committed
wip:
- use a wrapper around just the new_inner_size - use interior mutability - add a method to poison the wrapper
1 parent 5f52d7c commit 5b6e9a0

File tree

7 files changed

+198
-49
lines changed

7 files changed

+198
-49
lines changed

examples/dpi.rs

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
use winit::dpi::LogicalSize;
2+
use winit::dpi::PhysicalSize;
3+
use winit::{
4+
event::{Event, WindowEvent},
5+
event_loop::{ControlFlow, EventLoop},
6+
window::WindowBuilder,
7+
};
8+
9+
/// Change the DPI settings in Windows while running this.
10+
fn main() {
11+
simple_logger::init().unwrap();
12+
let event_loop = EventLoop::new();
13+
14+
let window = WindowBuilder::new()
15+
.with_title("A fantastic window!")
16+
.with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0))
17+
.build(&event_loop)
18+
.unwrap();
19+
20+
event_loop.run(move |event, _, control_flow| {
21+
*control_flow = ControlFlow::Wait;
22+
23+
match event {
24+
Event::WindowEvent {
25+
event: WindowEvent::CloseRequested,
26+
window_id,
27+
} if window_id == window.id() => *control_flow = ControlFlow::Exit,
28+
Event::MainEventsCleared => {
29+
window.request_redraw();
30+
}
31+
32+
// DPI changed happened!
33+
Event::WindowEvent {
34+
event:
35+
WindowEvent::ScaleFactorChanged {
36+
scale_factor,
37+
new_inner_size,
38+
},
39+
..
40+
} => {
41+
dbg!((scale_factor, new_inner_size.inner_size()));
42+
43+
new_inner_size
44+
.set_inner_size(
45+
LogicalSize {
46+
width: 100,
47+
height: 200,
48+
}
49+
.to_physical(scale_factor),
50+
)
51+
.unwrap();
52+
}
53+
54+
_ => (),
55+
}
56+
});
57+
}

src/event.rs

+93-9
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,10 @@ use crate::{
4545
/// Describes a generic event.
4646
///
4747
/// See the module-level docs for more information on the event loop manages each event.
48+
///
49+
/// `T` is a user-defined custom event type.
4850
#[derive(Debug, PartialEq)]
49-
pub enum Event<'a, T: 'static> {
51+
pub enum Event<T: 'static> {
5052
/// Emitted when new events arrive from the OS to be processed.
5153
///
5254
/// This event type is useful as a place to put code that should be done before you start
@@ -58,7 +60,7 @@ pub enum Event<'a, T: 'static> {
5860
/// Emitted when the OS sends an event to a winit window.
5961
WindowEvent {
6062
window_id: WindowId,
61-
event: WindowEvent<'a>,
63+
event: WindowEvent,
6264
},
6365

6466
/// Emitted when the OS sends an event to a device.
@@ -114,8 +116,8 @@ pub enum Event<'a, T: 'static> {
114116
LoopDestroyed,
115117
}
116118

117-
impl<'a, T> Event<'a, T> {
118-
pub fn map_nonuser_event<U>(self) -> Result<Event<'a, U>, Event<'a, T>> {
119+
impl<T> Event<T> {
120+
pub fn map_nonuser_event<U>(self) -> Result<Event<U>, Event<T>> {
119121
use self::Event::*;
120122
match self {
121123
UserEvent(_) => Err(self),
@@ -133,7 +135,8 @@ impl<'a, T> Event<'a, T> {
133135

134136
/// If the event doesn't contain a reference, turn it into an event with a `'static` lifetime.
135137
/// Otherwise, return `None`.
136-
pub fn to_static(self) -> Option<Event<'static, T>> {
138+
// TODO: remove?
139+
pub fn to_static(self) -> Option<Event<T>> {
137140
use self::Event::*;
138141
match self {
139142
WindowEvent { window_id, event } => event
@@ -180,7 +183,7 @@ pub enum StartCause {
180183

181184
/// Describes an event from a `Window`.
182185
#[derive(Debug, PartialEq)]
183-
pub enum WindowEvent<'a> {
186+
pub enum WindowEvent {
184187
/// The size of the window has changed. Contains the client area's new dimensions.
185188
Resized(PhysicalSize<u32>),
186189

@@ -307,7 +310,7 @@ pub enum WindowEvent<'a> {
307310
/// For more information about DPI in general, see the [`dpi`](crate::dpi) module.
308311
ScaleFactorChanged {
309312
scale_factor: f64,
310-
new_inner_size: &'a mut PhysicalSize<u32>,
313+
new_inner_size: NewInnerSizeInteriorMutCoolThing,
311314
},
312315

313316
/// The system window theme has changed.
@@ -319,8 +322,89 @@ pub enum WindowEvent<'a> {
319322
ThemeChanged(Theme),
320323
}
321324

322-
impl<'a> WindowEvent<'a> {
323-
pub fn to_static(self) -> Option<WindowEvent<'static>> {
325+
use std::{
326+
cell::Cell,
327+
fmt::Debug,
328+
sync::{Arc, Mutex},
329+
};
330+
331+
// TODO naming
332+
#[derive(Debug, Clone)]
333+
pub struct NewInnerSizeInteriorMutCoolThing {
334+
inner: Arc<Mutex<NewInnerSizeInteriorMutCoolThingInner>>,
335+
}
336+
337+
#[derive(Debug, Clone)]
338+
struct NewInnerSizeInteriorMutCoolThingInner {
339+
/// TODO doc this uses interior mutability in `set_inner_size`!
340+
new_inner_size: Cell<PhysicalSize<u32>>,
341+
342+
/// If the event that this originated from was handled, this struct is essential read-only. Once this field is `true`, no further calls to `set_inner_size` will succeed.
343+
is_readonly: bool,
344+
}
345+
346+
pub struct NewInnerSizeInteriorMutCoolThingIsReadonlyNowError;
347+
348+
impl Debug for NewInnerSizeInteriorMutCoolThingIsReadonlyNowError {
349+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
350+
write!(f, "todo error message, but this new_inner_size cell is being mutated after winit has consumed it, so there will be no effect on the window")
351+
}
352+
}
353+
354+
/// Manually implement `PartialEq` to treat `Self` like just a `PhysicalSize<u32>`.
355+
///
356+
/// Ignores the `Mutex` (i.e. unconditionally locks).
357+
impl PartialEq<NewInnerSizeInteriorMutCoolThing> for NewInnerSizeInteriorMutCoolThing {
358+
/// Note: will deadlock when `other` == `self`!
359+
fn eq(&self, other: &NewInnerSizeInteriorMutCoolThing) -> bool {
360+
// Note: ignoring `is_readonly` flag!
361+
self.inner.lock().unwrap().new_inner_size == other.inner.lock().unwrap().new_inner_size
362+
}
363+
}
364+
365+
impl From<NewInnerSizeInteriorMutCoolThing> for PhysicalSize<u32> {
366+
fn from(new_inner_size: NewInnerSizeInteriorMutCoolThing) -> Self {
367+
new_inner_size.inner_size()
368+
}
369+
}
370+
371+
impl NewInnerSizeInteriorMutCoolThing {
372+
pub fn new(new_inner_size: PhysicalSize<u32>) -> Self {
373+
Self {
374+
inner: Arc::new(Mutex::new(NewInnerSizeInteriorMutCoolThingInner {
375+
new_inner_size: Cell::new(new_inner_size),
376+
is_readonly: false,
377+
})),
378+
}
379+
}
380+
381+
// todo: doc that this needs to be called after the winit event loop processes the containing event and looks at the resulting `inner_size`.
382+
pub(crate) fn mark_new_inner_size_consumed(self) {
383+
self.inner.lock().unwrap().is_readonly = true;
384+
}
385+
386+
pub fn inner_size(&self) -> PhysicalSize<u32> {
387+
self.inner.lock().unwrap().new_inner_size.get()
388+
}
389+
390+
pub fn set_inner_size(
391+
&self,
392+
new_size: PhysicalSize<u32>,
393+
) -> Result<(), NewInnerSizeInteriorMutCoolThingIsReadonlyNowError> {
394+
let a = self.inner.lock().unwrap();
395+
if a.is_readonly {
396+
Err(NewInnerSizeInteriorMutCoolThingIsReadonlyNowError)
397+
} else {
398+
// Only one borrow guarenteed by `Mutex`.
399+
a.new_inner_size.set(new_size);
400+
Ok(())
401+
}
402+
}
403+
}
404+
405+
impl WindowEvent {
406+
// TODO remove?
407+
pub fn to_static(self) -> Option<WindowEvent> {
324408
use self::WindowEvent::*;
325409
match self {
326410
Resized(size) => Some(Resized(size)),

src/event_loop.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ impl<T> EventLoop<T> {
143143
#[inline]
144144
pub fn run<F>(self, event_handler: F) -> !
145145
where
146-
F: 'static + FnMut(Event<'_, T>, &EventLoopWindowTarget<T>, &mut ControlFlow),
146+
F: 'static + FnMut(Event<T>, &EventLoopWindowTarget<T>, &mut ControlFlow),
147147
{
148148
self.event_loop.run(event_handler)
149149
}

src/platform/desktop.rs

+2-10
Original file line numberDiff line numberDiff line change
@@ -30,23 +30,15 @@ pub trait EventLoopExtDesktop {
3030
/// You are strongly encouraged to use `run`, unless the use of this is absolutely necessary.
3131
fn run_return<F>(&mut self, event_handler: F)
3232
where
33-
F: FnMut(
34-
Event<'_, Self::UserEvent>,
35-
&EventLoopWindowTarget<Self::UserEvent>,
36-
&mut ControlFlow,
37-
);
33+
F: FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>, &mut ControlFlow);
3834
}
3935

4036
impl<T> EventLoopExtDesktop for EventLoop<T> {
4137
type UserEvent = T;
4238

4339
fn run_return<F>(&mut self, event_handler: F)
4440
where
45-
F: FnMut(
46-
Event<'_, Self::UserEvent>,
47-
&EventLoopWindowTarget<Self::UserEvent>,
48-
&mut ControlFlow,
49-
),
41+
F: FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>, &mut ControlFlow),
5042
{
5143
self.event_loop.run_return(event_handler)
5244
}

src/platform_impl/windows/drop_handler.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ pub struct FileDropHandlerData {
3131
pub interface: IDropTarget,
3232
refcount: AtomicUsize,
3333
window: HWND,
34-
send_event: Box<dyn Fn(Event<'static, ()>)>,
34+
send_event: Box<dyn Fn(Event<()>)>,
3535
cursor_effect: DWORD,
3636
hovered_is_valid: bool, /* If the currently hovered item is not valid there must not be any `HoveredFileCancelled` emitted */
3737
}
@@ -42,7 +42,7 @@ pub struct FileDropHandler {
4242

4343
#[allow(non_snake_case)]
4444
impl FileDropHandler {
45-
pub fn new(window: HWND, send_event: Box<dyn Fn(Event<'static, ()>)>) -> FileDropHandler {
45+
pub fn new(window: HWND, send_event: Box<dyn Fn(Event<()>)>) -> FileDropHandler {
4646
let data = Box::new(FileDropHandlerData {
4747
interface: IDropTarget {
4848
lpVtbl: &DROP_TARGET_VTBL as *const IDropTargetVtbl,
@@ -227,7 +227,7 @@ impl FileDropHandler {
227227
}
228228

229229
impl FileDropHandlerData {
230-
fn send_event(&self, event: Event<'static, ()>) {
230+
fn send_event(&self, event: Event<()>) {
231231
(self.send_event)(event);
232232
}
233233
}

src/platform_impl/windows/event_loop.rs

+14-8
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@ use winapi::{
4444
use self::runner::{ELRShared, EventLoopRunnerShared};
4545
use crate::{
4646
dpi::{PhysicalPosition, PhysicalSize},
47-
event::{DeviceEvent, Event, Force, KeyboardInput, Touch, TouchPhase, WindowEvent},
47+
event::{
48+
DeviceEvent, Event, Force, KeyboardInput, NewInnerSizeInteriorMutCoolThing, Touch,
49+
TouchPhase, WindowEvent,
50+
},
4851
event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW},
4952
platform_impl::platform::{
5053
dark_mode::try_dark_mode,
@@ -100,7 +103,7 @@ pub(crate) struct SubclassInput<T: 'static> {
100103
}
101104

102105
impl<T> SubclassInput<T> {
103-
unsafe fn send_event(&self, event: Event<'_, T>) {
106+
unsafe fn send_event(&self, event: Event<T>) {
104107
self.event_loop_runner.send_event(event);
105108
}
106109
}
@@ -112,7 +115,7 @@ struct ThreadMsgTargetSubclassInput<T: 'static> {
112115
}
113116

114117
impl<T> ThreadMsgTargetSubclassInput<T> {
115-
unsafe fn send_event(&self, event: Event<'_, T>) {
118+
unsafe fn send_event(&self, event: Event<T>) {
116119
self.event_loop_runner.send_event(event);
117120
}
118121
}
@@ -187,15 +190,15 @@ impl<T: 'static> EventLoop<T> {
187190

188191
pub fn run<F>(mut self, event_handler: F) -> !
189192
where
190-
F: 'static + FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
193+
F: 'static + FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
191194
{
192195
self.run_return(event_handler);
193196
::std::process::exit(0);
194197
}
195198

196199
pub fn run_return<F>(&mut self, mut event_handler: F)
197200
where
198-
F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
201+
F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
199202
{
200203
let event_loop_windows_ref = &self.window_target;
201204

@@ -1512,23 +1515,26 @@ unsafe extern "system" fn public_window_callback<T: 'static>(
15121515

15131516
// `allow_resize` prevents us from re-applying DPI adjustment to the restored size after
15141517
// exiting fullscreen (the restored size is already DPI adjusted).
1515-
let mut new_physical_inner_size = match allow_resize {
1518+
let inner_size_cell = NewInnerSizeInteriorMutCoolThing::new(match allow_resize {
15161519
// We calculate our own size because the default suggested rect doesn't do a great job
15171520
// of preserving the window's logical size.
15181521
true => old_physical_inner_size
15191522
.to_logical::<f64>(old_dpi_factor)
15201523
.to_physical::<u32>(new_dpi_factor),
15211524
false => old_physical_inner_size,
1522-
};
1525+
});
15231526

15241527
let _ = subclass_input.send_event(Event::WindowEvent {
15251528
window_id: RootWindowId(WindowId(window)),
15261529
event: ScaleFactorChanged {
15271530
scale_factor: new_dpi_factor,
1528-
new_inner_size: &mut new_physical_inner_size,
1531+
new_inner_size: inner_size_cell.clone(),
15291532
},
15301533
});
15311534

1535+
let new_physical_inner_size = inner_size_cell.inner_size();
1536+
inner_size_cell.mark_new_inner_size_consumed();
1537+
15321538
// Unset maximized if we're changing the window's size.
15331539
if new_physical_inner_size != old_physical_inner_size {
15341540
WindowState::set_window_flags(subclass_input.window_state.lock(), window, |f| {

0 commit comments

Comments
 (0)