Rate limit resize events

This commit is contained in:
Brian Anderson 2012-10-14 04:07:34 -07:00
parent a06d45f2a5
commit c41ff73847
5 changed files with 78 additions and 5 deletions

View file

@ -326,7 +326,7 @@ impl Content {
// TODO: actually perform DOM event dispatch. // TODO: actually perform DOM event dispatch.
fn handle_event(event: Event) -> bool { fn handle_event(event: Event) -> bool {
match event { match event {
ResizeEvent(new_width, new_height) => { ResizeEvent(new_width, new_height, response_chan) => {
debug!("content got resize event: %u, %u", new_width, new_height); debug!("content got resize event: %u, %u", new_width, new_height);
self.window_size = Size2D(new_width, new_height); self.window_size = Size2D(new_width, new_height);
match copy self.document { match copy self.document {
@ -338,6 +338,7 @@ impl Content {
self.relayout(document, &self.doc_url.get()); self.relayout(document, &self.doc_url.get());
} }
} }
response_chan.send(());
return true; return true;
} }
ReflowEvent => { ReflowEvent => {

View file

@ -1,5 +1,5 @@
enum Event { enum Event {
ResizeEvent(uint, uint), ResizeEvent(uint, uint, pipes::Chan<()>),
ReflowEvent ReflowEvent
} }

View file

@ -15,6 +15,7 @@ use task::TaskBuilder;
use vec::push; use vec::push;
use pipes::Chan; use pipes::Chan;
use std::cell::Cell; use std::cell::Cell;
use resize_rate_limiter::ResizeRateLimiter;
pub type OSMain = comm::Chan<Msg>; pub type OSMain = comm::Chan<Msg>;
@ -56,8 +57,6 @@ fn OSMain(dom_event_chan: pipes::SharedChan<Event>) -> OSMain {
fn mainloop(mode: Mode, po: comm::Port<Msg>, dom_event_chan: pipes::SharedChan<Event>) { fn mainloop(mode: Mode, po: comm::Port<Msg>, dom_event_chan: pipes::SharedChan<Event>) {
let dom_event_chan = @move dom_event_chan;
let key_handlers: @DVec<pipes::Chan<()>> = @DVec(); let key_handlers: @DVec<pipes::Chan<()>> = @DVec();
let window; let window;
@ -90,12 +89,18 @@ fn mainloop(mode: Mode, po: comm::Port<Msg>, dom_event_chan: pipes::SharedChan<E
let done = @mut false; let done = @mut false;
let resize_rate_limiter = @ResizeRateLimiter(move dom_event_chan);
#macro[ #macro[
[#moov[x], [#moov[x],
unsafe { let y <- *ptr::addr_of(x); y }] unsafe { let y <- *ptr::addr_of(x); y }]
]; ];
let check_for_messages = fn@() { let check_for_messages = fn@() {
// Periodically check if content responded to our last resize event
resize_rate_limiter.check_resize_response();
// Handle messages // Handle messages
#debug("osmain: peeking"); #debug("osmain: peeking");
while po.peek() { while po.peek() {
@ -136,7 +141,7 @@ fn mainloop(mode: Mode, po: comm::Port<Msg>, dom_event_chan: pipes::SharedChan<E
check_for_messages(); check_for_messages();
#debug("osmain: window resized to %d,%d", width as int, height as int); #debug("osmain: window resized to %d,%d", width as int, height as int);
dom_event_chan.send(ResizeEvent(width as uint, height as uint)); resize_rate_limiter.window_resized(width as uint, height as uint);
} }
do glut::display_func() { do glut::display_func() {

View file

@ -0,0 +1,66 @@
/*!
A little class that rate limits the number of resize events sent to the content task
based on how fast content dispatches those events. It waits until each event is handled
before sending the next. If the window is resized multiple times before an event is handled
then some events will never be sent.
*/
use dom::event::{Event, ResizeEvent};
pub struct ResizeRateLimiter {
/// The channel we send resize events on
/* priv */ dom_event_chan: pipes::SharedChan<Event>,
/// The port we are waiting on for a response to the last resize event
/* priv */ mut last_response_port: Option<pipes::Port<()>>,
/// The next window resize event we should fire
/* priv */ mut next_resize_event: Option<(uint, uint)>
}
pub fn ResizeRateLimiter(dom_event_chan: pipes::SharedChan<Event>) -> ResizeRateLimiter {
ResizeRateLimiter {
dom_event_chan: move dom_event_chan,
last_response_port: None,
next_resize_event: None
}
}
impl ResizeRateLimiter {
fn window_resized(width: uint, height: uint) {
match self.last_response_port {
None => {
assert self.next_resize_event.is_none();
self.send_event(width, height);
}
Some(*) => {
if self.last_response_port.get_ref().peek() {
self.send_event(width, height);
self.next_resize_event = None;
} else {
if self.next_resize_event.is_some() {
warn!("osmain: content can't keep up. skipping resize event");
}
self.next_resize_event = Some((width, height));
}
}
}
}
fn check_resize_response() {
match self.next_resize_event {
Some((copy width, copy height)) => {
assert self.last_response_port.is_some();
if self.last_response_port.get_ref().peek() {
self.send_event(width, height);
self.next_resize_event = None;
}
}
None => ()
}
}
priv fn send_event(width: uint, height: uint) {
let (chan, port) = pipes::stream();
self.dom_event_chan.send(ResizeEvent(width, height, move chan));
self.last_response_port = Some(move port);
}
}

View file

@ -95,6 +95,7 @@ pub mod html {
pub mod platform { pub mod platform {
pub mod base; pub mod base;
pub mod osmain; pub mod osmain;
priv mod resize_rate_limiter;
} }
pub mod text { pub mod text {