Compare commits

...
Sign in to create a new pull request.

1 commit
main ... focus

Author SHA1 Message Date
Antonio Scandurra
3fbab23daa WIP 2024-02-05 11:09:10 -07:00

View file

@ -95,8 +95,8 @@ type AnyObserver = Box<dyn FnMut(&mut WindowContext) -> bool + 'static>;
type AnyWindowFocusListener = Box<dyn FnMut(&FocusEvent, &mut WindowContext) -> bool + 'static>;
struct FocusEvent {
previous_focus_path: SmallVec<[FocusId; 8]>,
current_focus_path: SmallVec<[FocusId; 8]>,
old_focus_path: SmallVec<[FocusId; 8]>,
new_focus_path: SmallVec<[FocusId; 8]>,
}
slotmap::new_key_type! {
@ -344,24 +344,55 @@ impl Window {
let last_input_timestamp = Rc::new(Cell::new(Instant::now()));
platform_window.on_request_frame(Box::new({
let mut cx = cx.to_async();
let mut cx = AsyncWindowContext::new(cx.to_async(), handle);
let dirty = dirty.clone();
let last_input_timestamp = last_input_timestamp.clone();
move || {
if dirty.get() {
measure("frame duration", || {
handle
.update(&mut cx, |_, cx| {
cx.draw();
cx.present();
})
.log_err();
})
} else if last_input_timestamp.get().elapsed() < Duration::from_secs(1) {
// Keep presenting the current scene for 1 extra second since the
// last input to prevent the display from underclocking the refresh rate.
handle.update(&mut cx, |_, cx| cx.present()).log_err();
fn handle_frame_request(
dirty: &Rc<Cell<bool>>,
last_input_timestamp: &Rc<Cell<Instant>>,
cx: &mut AsyncWindowContext,
) -> Result<()> {
if dirty.get() {
measure("frame duration", || {
let original_focus_path =
cx.update(|cx| cx.window.rendered_frame.focus_path())?;
let mut draw_count = 0;
while dirty.get() {
cx.update(|cx| {
let old_window_active = cx.window.rendered_frame.focus_path();
let old_focus_path = cx.window.rendered_frame.focus_path();
cx.draw();
cx.notify_focus_listeners(
&original_focus_path,
old_focus_path,
old_window_active,
);
})?;
draw_count += 1;
if draw_count > 2 {
log::warn!(
"redrew frame {} times due to focus changes",
draw_count
);
}
}
cx.update(|cx| cx.present())?;
Ok(())
})?;
} else if last_input_timestamp.get().elapsed() < Duration::from_secs(1) {
// Keep presenting the current scene for 1 extra second since the
// last input to prevent the display from underclocking the refresh rate.
cx.update(|cx| cx.present())?;
}
Ok(())
}
handle_frame_request(&dirty, &last_input_timestamp, &mut cx).log_err();
}
}));
platform_window.on_resize(Box::new({
@ -1071,18 +1102,28 @@ impl<'a> WindowContext<'a> {
}
element_arena.clear();
});
let previous_focus_path = self.window.rendered_frame.focus_path();
let previous_window_active = self.window.rendered_frame.window_active;
mem::swap(&mut self.window.rendered_frame, &mut self.window.next_frame);
self.window.next_frame.clear();
let current_focus_path = self.window.rendered_frame.focus_path();
let current_window_active = self.window.rendered_frame.window_active;
self.window.refreshing = false;
self.window.drawing = false;
}
if previous_focus_path != current_focus_path
|| previous_window_active != current_window_active
{
if !previous_focus_path.is_empty() && current_focus_path.is_empty() {
fn notify_focus_listeners(
&mut self,
original_focus_path: &SmallVec<[FocusId; 8]>,
old_focus_path: SmallVec<[FocusId; 8]>,
old_window_active: bool,
) {
let new_window_active = self.window.rendered_frame.window_active;
let new_focus_path = self.window.rendered_frame.focus_path();
if new_window_active == old_window_active && new_focus_path == *original_focus_path {
log::warn!("skipping focus notifications due to restoring focus to the original handle in a single frame");
return;
}
if new_focus_path != old_focus_path || new_window_active != old_window_active {
if !old_focus_path.is_empty() && new_focus_path.is_empty() {
self.window
.focus_lost_listeners
.clone()
@ -1090,15 +1131,15 @@ impl<'a> WindowContext<'a> {
}
let event = FocusEvent {
previous_focus_path: if previous_window_active {
previous_focus_path
old_focus_path: if old_window_active {
old_focus_path
} else {
Default::default()
SmallVec::new()
},
current_focus_path: if current_window_active {
current_focus_path
new_focus_path: if new_window_active {
new_focus_path
} else {
Default::default()
SmallVec::new()
},
};
self.window
@ -1106,8 +1147,6 @@ impl<'a> WindowContext<'a> {
.clone()
.retain(&(), |listener| listener(&event, self));
}
self.window.refreshing = false;
self.window.drawing = false;
}
fn present(&self) {
@ -2124,8 +2163,8 @@ impl<'a, V: 'static> ViewContext<'a, V> {
(),
Box::new(move |event, cx| {
view.update(cx, |view, cx| {
if event.previous_focus_path.last() != Some(&focus_id)
&& event.current_focus_path.last() == Some(&focus_id)
if event.old_focus_path.last() != Some(&focus_id)
&& event.new_focus_path.last() == Some(&focus_id)
{
listener(view, cx)
}
@ -2150,8 +2189,8 @@ impl<'a, V: 'static> ViewContext<'a, V> {
(),
Box::new(move |event, cx| {
view.update(cx, |view, cx| {
if !event.previous_focus_path.contains(&focus_id)
&& event.current_focus_path.contains(&focus_id)
if !event.old_focus_path.contains(&focus_id)
&& event.new_focus_path.contains(&focus_id)
{
listener(view, cx)
}
@ -2176,8 +2215,8 @@ impl<'a, V: 'static> ViewContext<'a, V> {
(),
Box::new(move |event, cx| {
view.update(cx, |view, cx| {
if event.previous_focus_path.last() == Some(&focus_id)
&& event.current_focus_path.last() != Some(&focus_id)
if event.old_focus_path.last() == Some(&focus_id)
&& event.new_focus_path.last() != Some(&focus_id)
{
listener(view, cx)
}
@ -2219,8 +2258,8 @@ impl<'a, V: 'static> ViewContext<'a, V> {
(),
Box::new(move |event, cx| {
view.update(cx, |view, cx| {
if event.previous_focus_path.contains(&focus_id)
&& !event.current_focus_path.contains(&focus_id)
if event.old_focus_path.contains(&focus_id)
&& !event.new_focus_path.contains(&focus_id)
{
listener(view, cx)
}