From e0164997e4fc5e468d34ff33942a197bad844194 Mon Sep 17 00:00:00 2001 From: Jack Moffitt Date: Fri, 20 May 2016 16:28:50 -0600 Subject: [PATCH] Make Servo DPI aware on Windows This implements system level DPI awareness for Windows. It has three parts: 1. Add a application manifest which is copied alongside servo.exe during build that declares our DPI awareness level. This is needed otherwise DPI queries will return 96dpi and our application will be upscaled on high DPI displays. 2. Rename hidpi_factor to avoid confusion with Glutin's hidpi_factor which does something else. 3. Correctly convert windows sizes on window creation for Windows. Unlike OS X, Windows uses device pixels for window creation. --- components/compositing/compositor.rs | 14 +++++----- components/compositing/windowing.rs | 4 +-- components/servo/Cargo.lock | 41 +++++++++++++++------------- components/servo/lib.rs | 4 +-- components/servo/servo.exe.manifest | 24 ++++++++++++++++ ports/cef/Cargo.lock | 3 ++ ports/geckolib/Cargo.lock | 12 ++++---- ports/glutin/Cargo.toml | 5 ++++ ports/glutin/lib.rs | 9 +++--- ports/glutin/window.rs | 35 +++++++++++++++++++++--- python/servo/build_commands.py | 4 +++ 11 files changed, 110 insertions(+), 45 deletions(-) create mode 100644 components/servo/servo.exe.manifest diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index b296fff68db8c..61bc6bbd5b155 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -144,7 +144,7 @@ pub struct IOCompositor { page_zoom: ScaleFactor, /// The device pixel ratio for this window. - hidpi_factor: ScaleFactor, + scale_factor: ScaleFactor, channel_to_self: Box, @@ -405,7 +405,7 @@ impl IOCompositor { mem::ProfilerMsg::RegisterReporter(reporter_name(), reporter)); let window_size = window.framebuffer_size(); - let hidpi_factor = window.hidpi_factor(); + let scale_factor = window.scale_factor(); let composite_target = match opts::get().output_file { Some(_) => CompositeTarget::PngFile, None => CompositeTarget::Window @@ -434,7 +434,7 @@ impl IOCompositor { }), window_size: window_size, viewport: None, - hidpi_factor: hidpi_factor, + scale_factor: scale_factor, channel_to_self: state.sender.clone_compositor_proxy(), delayed_composition_timer: DelayedCompositionTimerProxy::new(state.sender), composition_request: CompositionRequest::NoCompositingNecessary, @@ -1315,9 +1315,9 @@ impl IOCompositor { debug!("compositor resizing to {:?}", new_size.to_untyped()); // A size change could also mean a resolution change. - let new_hidpi_factor = self.window.hidpi_factor(); - if self.hidpi_factor != new_hidpi_factor { - self.hidpi_factor = new_hidpi_factor; + let new_scale_factor = self.window.scale_factor(); + if self.scale_factor != new_scale_factor { + self.scale_factor = new_scale_factor; self.update_zoom_transform(); } @@ -1744,7 +1744,7 @@ impl IOCompositor { Some(device_pixels_per_px) => ScaleFactor::new(device_pixels_per_px), None => match opts::get().output_file { Some(_) => ScaleFactor::new(1.0), - None => self.hidpi_factor + None => self.scale_factor } } } diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs index b07298d3fc3df..72cb276121d16 100644 --- a/components/compositing/windowing.rs +++ b/components/compositing/windowing.rs @@ -133,8 +133,8 @@ pub trait WindowMethods { /// Called when the tag has finished parsing fn head_parsed(&self); - /// Returns the hidpi factor of the monitor. - fn hidpi_factor(&self) -> ScaleFactor; + /// Returns the scale factor of the system (device pixels / screen pixels). + fn scale_factor(&self) -> ScaleFactor; /// Gets the OS native graphics display for this window. fn native_display(&self) -> NativeDisplay; diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 4a0520edfdf06..1f1e2a572f3fa 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -125,7 +125,7 @@ dependencies = [ "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -259,7 +259,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "windows-error 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -435,7 +435,7 @@ name = "dbghelp-sys" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -517,7 +517,7 @@ name = "dwmapi-sys" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -696,7 +696,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -728,7 +728,7 @@ name = "gdi32-sys" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -847,6 +847,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "compositing 0.0.1", "euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "layers 0.2.5 (git+https://github.com/servo/rust-layers)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -857,7 +858,9 @@ dependencies = [ "servo-glutin 0.4.22 (registry+https://github.com/rust-lang/crates.io-index)", "style_traits 0.0.1", "url 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "x11 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1080,7 +1083,7 @@ name = "kernel32-sys" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1217,7 +1220,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1287,7 +1290,7 @@ dependencies = [ "fs2 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1392,7 +1395,7 @@ dependencies = [ "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2049,7 +2052,7 @@ dependencies = [ "wayland-client 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)", "wayland-kbd 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "wayland-window 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "x11-dl 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2086,7 +2089,7 @@ name = "shell32-sys" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2208,7 +2211,7 @@ dependencies = [ "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2257,7 +2260,7 @@ dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2334,7 +2337,7 @@ name = "user32-sys" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2408,7 +2411,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2550,7 +2553,7 @@ dependencies = [ [[package]] name = "winapi" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2564,7 +2567,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2572,7 +2575,7 @@ name = "ws2_32-sys" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/components/servo/lib.rs b/components/servo/lib.rs index edc362985b970..5f4b571625a82 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -129,12 +129,12 @@ impl Browser { resource_path.push("shaders"); // TODO(gw): Duplicates device_pixels_per_screen_px from compositor. Tidy up! - let hidpi_factor = window.hidpi_factor().get(); + let scale_factor = window.scale_factor().get(); let device_pixel_ratio = match opts.device_pixels_per_px { Some(device_pixels_per_px) => device_pixels_per_px, None => match opts.output_file { Some(_) => 1.0, - None => hidpi_factor, + None => scale_factor, } }; diff --git a/components/servo/servo.exe.manifest b/components/servo/servo.exe.manifest new file mode 100644 index 0000000000000..3748cdaca4031 --- /dev/null +++ b/components/servo/servo.exe.manifest @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + true + + + + diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index dcd63e56c6e82..7f582f400f8cb 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -759,6 +759,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "compositing 0.0.1", "euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "layers 0.2.5 (git+https://github.com/servo/rust-layers)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -769,7 +770,9 @@ dependencies = [ "servo-glutin 0.4.22 (registry+https://github.com/rust-lang/crates.io-index)", "style_traits 0.0.1", "url 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "x11 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/ports/geckolib/Cargo.lock b/ports/geckolib/Cargo.lock index 6dda945f10fcd..7d9674d6f7fae 100644 --- a/ports/geckolib/Cargo.lock +++ b/ports/geckolib/Cargo.lock @@ -58,7 +58,7 @@ dependencies = [ "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -114,7 +114,7 @@ name = "dbghelp-sys" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -271,7 +271,7 @@ name = "kernel32-sys" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -517,7 +517,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -606,12 +606,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "winapi" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] diff --git a/ports/glutin/Cargo.toml b/ports/glutin/Cargo.toml index 465f352c950f0..b4e5fffbf3e01 100644 --- a/ports/glutin/Cargo.toml +++ b/ports/glutin/Cargo.toml @@ -27,3 +27,8 @@ x11 = "2.0.0" [target.'cfg(target_os = "android")'.dependencies] servo-egl = "0.2" + +[target.'cfg(target_os = "windows")'.dependencies] +winapi = "0.2" +user32-sys = "0.2" +gdi32-sys = "0.2" diff --git a/ports/glutin/lib.rs b/ports/glutin/lib.rs index 0f557e1409708..64ad3fc632ded 100644 --- a/ports/glutin/lib.rs +++ b/ports/glutin/lib.rs @@ -22,9 +22,11 @@ extern crate style_traits; extern crate url; extern crate util; #[cfg(target_os = "linux")] extern crate x11; +#[cfg(target_os = "windows")] extern crate winapi; +#[cfg(target_os = "windows")] extern crate user32; +#[cfg(target_os = "windows")] extern crate gdi32; use compositing::windowing::WindowEvent; -use euclid::scale_factor::ScaleFactor; use std::rc::Rc; use util::opts; use window::Window; @@ -41,10 +43,7 @@ pub fn create_window(parent: Option) -> Rc { // Read command-line options. let opts = opts::get(); let foreground = opts.output_file.is_none() && !opts.headless; - let scale_factor = ScaleFactor::new(opts.device_pixels_per_px.unwrap_or(1.0)); - let size_f32 = opts.initial_window_size.as_f32() * scale_factor; - let size_u32 = size_f32.as_uint().cast().expect("Window size should fit in a u32."); // Open a window. - Window::new(foreground, size_u32, parent) + Window::new(foreground, opts.initial_window_size, parent) } diff --git a/ports/glutin/window.rs b/ports/glutin/window.rs index c74a1adb6a2c6..131e9ee0823be 100644 --- a/ports/glutin/window.rs +++ b/ports/glutin/window.rs @@ -11,6 +11,7 @@ use compositing::windowing::{WindowEvent, WindowMethods}; use euclid::scale_factor::ScaleFactor; use euclid::size::TypedSize2D; use euclid::{Size2D, Point2D}; +#[cfg(target_os = "windows")] use gdi32; use gleam::gl; use glutin; #[cfg(target_os = "macos")] @@ -30,12 +31,14 @@ use std::rc::Rc; use std::sync::mpsc::{channel, Sender}; use style_traits::cursor::Cursor; use url::Url; +#[cfg(target_os = "windows")] use user32; use util::geometry::ScreenPx; use util::opts; #[cfg(not(target_os = "android"))] use util::opts::RenderApi; use util::prefs; use util::resource_files; +#[cfg(target_os = "windows")] use winapi; static mut g_nested_event_loop_listener: Option<*mut (NestedEventLoopListener + 'static)> = None; @@ -98,12 +101,28 @@ pub struct Window { current_url: RefCell>, } +#[cfg(not(target_os = "windows"))] +fn window_creation_scale_factor() -> ScaleFactor { + ScaleFactor::new(1.0) +} + +#[cfg(target_os = "windows")] +fn window_creation_scale_factor() -> ScaleFactor { + let hdc = unsafe { user32::GetDC(::std::ptr::null_mut()) }; + let ppi = unsafe { gdi32::GetDeviceCaps(hdc, winapi::wingdi::LOGPIXELSY) }; + ScaleFactor::new(ppi as f32 / 96.0) +} + + impl Window { pub fn new(is_foreground: bool, - window_size: TypedSize2D, + window_size: TypedSize2D, parent: Option) -> Rc { - let width = window_size.to_untyped().width; - let height = window_size.to_untyped().height; + let win_size: TypedSize2D = + (window_size.as_f32() * window_creation_scale_factor()) + .as_uint().cast().expect("Window size should fit in u32"); + let width = win_size.to_untyped().width; + let height = win_size.to_untyped().height; // If there's no chrome, start off with the window invisible. It will be set to visible in // `load_end()`. This avoids an ugly flash of unstyled content (especially important since @@ -644,10 +663,18 @@ impl WindowMethods for Window { box receiver as Box) } - fn hidpi_factor(&self) -> ScaleFactor { + #[cfg(not(target_os = "windows"))] + fn scale_factor(&self) -> ScaleFactor { ScaleFactor::new(self.window.hidpi_factor()) } + #[cfg(target_os = "windows")] + fn scale_factor(&self) -> ScaleFactor { + let hdc = unsafe { user32::GetDC(::std::ptr::null_mut()) }; + let ppi = unsafe { gdi32::GetDeviceCaps(hdc, winapi::wingdi::LOGPIXELSY) }; + ScaleFactor::new(ppi as f32 / 96.0) + } + fn set_page_title(&self, title: Option) { let fallback_title: String = if let Some(ref current_url) = *self.current_url.borrow() { current_url.to_string() diff --git a/python/servo/build_commands.py b/python/servo/build_commands.py index 3dca0f3fae6f5..369918595cea0 100644 --- a/python/servo/build_commands.py +++ b/python/servo/build_commands.py @@ -231,6 +231,10 @@ def build(self, target=None, release=False, dev=False, jobs=None, env=env, cwd=self.servo_crate(), verbose=verbose) elapsed = time() - build_start + if sys.platform == "win32" or sys.platform == "msys": + shutil.copy(path.join(self.get_top_dir(), "components", "servo", "servo.exe.manifest"), + path.join(base_path, "debug" if dev else "release")) + # Generate Desktop Notification if elapsed-time > some threshold value notify_build_done(elapsed)