diff --git a/mk/sub.mk b/mk/sub.mk index f0a66c2825a..79f67e72954 100644 --- a/mk/sub.mk +++ b/mk/sub.mk @@ -29,6 +29,7 @@ NATIVE_BUILDS += \ skia \ nss \ nspr \ + glfw \ $(NULL) # NOTE: the make magic can only compute transitive build dependencies, @@ -40,18 +41,22 @@ NATIVE_BUILDS += \ DEPS_rust-azure += \ rust-opengles \ rust-layers \ - rust-glut \ rust-geom \ + glfw-rs \ + glfw \ skia \ $(NULL) +DEPS_glfw-rs += \ + glfw \ + $(NULL) + DEPS_rust-glut += \ rust-opengles \ $(NULL) DEPS_rust-layers += \ rust-geom \ - rust-glut \ rust-opengles \ $(NULL) diff --git a/src/components/main/compositing/mod.rs b/src/components/main/compositing/mod.rs index ebd1a81636f..2dc4794a420 100644 --- a/src/components/main/compositing/mod.rs +++ b/src/components/main/compositing/mod.rs @@ -23,6 +23,8 @@ use std::comm; use std::comm::{Chan, SharedChan, Port}; use std::num::Orderable; use std::task; +use extra::uv_global_loop; +use extra::timer; use geom::matrix::identity; use geom::point::Point2D; use geom::size::Size2D; @@ -80,15 +82,24 @@ impl CompositorChan { chan: SharedChan::new(chan), } } + pub fn send(&self, msg: Msg) { self.chan.send(msg); } + + pub fn get_size(&self) -> Size2D { + let (port, chan) = comm::stream(); + self.chan.send(GetSize(chan)); + port.recv() + } } /// Messages to the compositor. pub enum Msg { /// Requests that the compositor shut down. Exit, + /// Requests the window size + GetSize(Chan>), /// Requests the compositors GL context. GetGLContext(Chan), /// Requests that the compositor paint the given layer buffer set for the given page size. @@ -169,15 +180,18 @@ impl CompositorTask { // list. This is only here because we don't have that logic in the renderer yet. let context = rendergl::init_render_context(); let root_layer = @mut ContainerLayer(); - let scene = @mut Scene(ContainerLayerKind(root_layer), Size2D(800.0f32, 600.0), identity()); + let window_size = window.size(); + let scene = @mut Scene(ContainerLayerKind(root_layer), window_size, identity()); let done = @mut false; + let recomposite = @mut false; // FIXME: This should not be a separate offset applied after the fact but rather should be // applied to the layers themselves on a per-layer basis. However, this won't work until scroll // positions are sent to content. let world_offset = @mut Point2D(0f32, 0f32); let page_size = @mut Size2D(0f32, 0f32); - let window_size = @mut Size2D(800, 600); + let window_size = @mut Size2D(window_size.width as int, + window_size.height as int); // Keeps track of the current zoom factor let world_zoom = @mut 1f32; @@ -271,6 +285,11 @@ impl CompositorTask { response_chan.send(CompositorAck(new_pipeline_id)); } + GetSize(chan) => { + let size = window.size(); + chan.send(Size2D(size.width as int, size.height as int)); + } + GetGLContext(chan) => chan.send(current_gl_context()), Paint(id, new_layer_buffer_set, new_size) => { @@ -343,14 +362,14 @@ impl CompositorTask { // TODO: Recycle the old buffers; send them back to the renderer to reuse if // it wishes. - window.set_needs_display(); + *recomposite = true; } } } }; let profiler_chan = self.profiler_chan.clone(); - do window.set_composite_callback { + let composite = || { do profile(time::CompositingCategory, profiler_chan.clone()) { debug!("compositor: compositing"); // Adjust the layer dimensions as necessary to correspond to the size of the window. @@ -361,7 +380,7 @@ impl CompositorTask { } window.present(); - } + }; // When the user scrolls, move the layer around. do window.set_scroll_callback |delta| { @@ -390,7 +409,7 @@ impl CompositorTask { root_layer.common.set_transform(scroll_transform); - window.set_needs_display() + *recomposite = true; } @@ -429,8 +448,7 @@ impl CompositorTask { 0.0); root_layer.common.set_transform(zoom_transform); - - window.set_needs_display() + *recomposite = true; } // Enter the main event loop. @@ -440,6 +458,13 @@ impl CompositorTask { // Check for messages coming from the windowing system. window.check_loop(); + + if *recomposite { + *recomposite = false; + composite(); + } + + timer::sleep(&uv_global_loop::get(), 100); } self.shutdown_chan.send(()) diff --git a/src/components/main/pipeline.rs b/src/components/main/pipeline.rs index ab9ccc6cade..42f76d1b537 100644 --- a/src/components/main/pipeline.rs +++ b/src/components/main/pipeline.rs @@ -57,13 +57,14 @@ impl Pipeline { profiler_chan); ScriptTask::create(id, - compositor_chan, + compositor_chan.clone(), layout_chan.clone(), script_port, script_chan.clone(), constellation_chan, resource_task, - image_cache_task); + image_cache_task, + compositor_chan.get_size()); Pipeline::new(id, script_chan, diff --git a/src/components/main/platform/common/glut_windowing.rs b/src/components/main/platform/common/glfw_windowing.rs similarity index 69% rename from src/components/main/platform/common/glut_windowing.rs rename to src/components/main/platform/common/glfw_windowing.rs index 95fd22d9ef4..4aadfea486b 100644 --- a/src/components/main/platform/common/glut_windowing.rs +++ b/src/components/main/platform/common/glfw_windowing.rs @@ -2,10 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -//! A windowing implementation using GLUT. -/// -/// GLUT is a very old and bare-bones toolkit. However, it has good cross-platform support, at -/// least on desktops. It is designed for testing Servo without the need of a UI. +//! A windowing implementation using GLFW. use windowing::{ApplicationMethods, CompositeCallback, LoadUrlCallback, MouseCallback}; use windowing::{ResizeCallback, ScrollCallback, WindowMethods, WindowMouseEvent, WindowClickEvent}; @@ -17,10 +14,8 @@ use geom::point::Point2D; use geom::size::Size2D; use servo_msg::compositor_msg::{IdleRenderState, RenderState, RenderingRenderState}; use servo_msg::compositor_msg::{FinishedLoading, Loading, PerformingLayout, ReadyState}; -use glut::glut::{ACTIVE_CTRL, ACTIVE_SHIFT, DOUBLE, HAVE_PRECISE_MOUSE_WHEEL, WindowHeight}; -use glut::glut::WindowWidth; -use glut::glut; -use glut::machack; + +use glfw; static THROBBER: [char, ..8] = [ '⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷' ]; @@ -29,15 +24,21 @@ pub struct Application; impl ApplicationMethods for Application { pub fn new() -> Application { - glut::init(); - glut::init_display_mode(DOUBLE); + glfw::private::WindowDataMap::init(); + unsafe { glfw::ll::glfwInit(); } Application } } +impl Drop for Application { + fn finalize(&self) { + unsafe { glfw::ll::glfwTerminate(); } + } +} + /// The type of a window. pub struct Window { - glut_window: glut::Window, + glfw_window: glfw::Window, composite_callback: Option, resize_callback: Option, @@ -60,13 +61,13 @@ pub struct Window { impl WindowMethods for Window { /// Creates a new window. pub fn new(_: &Application) -> @mut Window { - // Create the GLUT window. - unsafe { glut::glutInitWindowSize(800, 600); } - let glut_window = glut::create_window(~"Servo"); + // Create the GLFW window. + let glfw_window = glfw::Window::create(800, 600, "Servo", glfw::Windowed).unwrap(); + glfw_window.make_context_current(); // Create our window object. let window = @mut Window { - glut_window: glut_window, + glfw_window: glfw_window, composite_callback: None, resize_callback: None, @@ -86,68 +87,51 @@ impl WindowMethods for Window { throbber_frame: 0, }; - // Spin the event loop every 50 ms to allow the Rust channels to be polled. - // - // This requirement is pretty much the nail in the coffin for GLUT's usefulness. - // - // FIXME(pcwalton): What a mess. - let register_timer_callback: @mut @fn() = @mut ||{}; - *register_timer_callback = || { - glut::timer_func(50, *register_timer_callback); - window.throbber_frame = (window.throbber_frame + 1) % (THROBBER.len() as u8); - window.update_window_title() - }; - // Register event handlers. - do glut::reshape_func(window.glut_window) |width, height| { + do window.glfw_window.set_framebuffer_size_callback |_win, width, height| { match window.resize_callback { None => {} Some(callback) => callback(width as uint, height as uint), } } - do glut::display_func { + do window.glfw_window.set_refresh_callback |_win| { // FIXME(pcwalton): This will not work with multiple windows. match window.composite_callback { None => {} Some(callback) => callback(), } + window.present(); } - do glut::keyboard_func |key, _, _| { - window.handle_key(key) + do window.glfw_window.set_key_callback |_win, key, _scancode, action, mods| { + if action == glfw::PRESS { + window.handle_key(key, mods) + } } - do glut::mouse_func |button, state, x, y| { + do window.glfw_window.set_mouse_button_callback |win, button, action, _mods| { + let (x, y) = win.get_cursor_pos(); if button < 3 { - window.handle_mouse(button, state, x, y); + window.handle_mouse(button, action, x as i32, y as i32); } } - do glut::mouse_wheel_func |wheel, direction, _x, _y| { - let delta = if HAVE_PRECISE_MOUSE_WHEEL { - (direction as f32) / 10000.0 - } else { - (direction as f32) * 30.0 - }; - - match wheel { - 1 => window.handle_scroll(Point2D(delta, 0.0)), - 2 => window.handle_zoom(delta), - _ => window.handle_scroll(Point2D(0.0, delta)), - } + do window.glfw_window.set_scroll_callback |_win, x_offset, y_offset| { + let dx = (x_offset as f32) * 30.0; + let dy = (y_offset as f32) * 30.0; + + window.handle_scroll(Point2D(dx, dy)); } - (*register_timer_callback)(); - - machack::perform_scroll_wheel_hack(); window } /// Returns the size of the window. pub fn size(&self) -> Size2D { - Size2D(glut::get(WindowWidth) as f32, glut::get(WindowHeight) as f32) + let (width, height) = self.glfw_window.get_framebuffer_size(); + Size2D(width as f32, height as f32) } /// Presents the window to the screen (perhaps by page flipping). pub fn present(&mut self) { - glut::swap_buffers(); + self.glfw_window.swap_buffers(); } /// Registers a callback to run when a composite event occurs. @@ -187,12 +171,9 @@ impl WindowMethods for Window { /// Spins the event loop. pub fn check_loop(@mut self) { - glut::check_loop() - } - - /// Schedules a redisplay. - pub fn set_needs_display(@mut self) { - glut::post_redisplay() + glfw::poll_events(); + self.throbber_frame = (self.throbber_frame + 1) % (THROBBER.len() as u8); + self.update_window_title(); } /// Sets the ready state. @@ -214,71 +195,65 @@ impl Window { let throbber = THROBBER[self.throbber_frame]; match self.ready_state { Loading => { - glut::set_window_title(self.glut_window, fmt!("%c Loading — Servo", throbber)) + self.glfw_window.set_title(fmt!("%c Loading — Servo", throbber)) } PerformingLayout => { - glut::set_window_title(self.glut_window, - fmt!("%c Performing Layout — Servo", throbber)) + self.glfw_window.set_title(fmt!("%c Performing Layout — Servo", throbber)) } FinishedLoading => { match self.render_state { RenderingRenderState => { - glut::set_window_title(self.glut_window, - fmt!("%c Rendering — Servo", throbber)) + self.glfw_window.set_title(fmt!("%c Rendering — Servo", throbber)) } - IdleRenderState => glut::set_window_title(self.glut_window, "Servo"), + IdleRenderState => self.glfw_window.set_title("Servo"), } } } } /// Helper function to handle keyboard events. - fn handle_key(&self, key: u8) { - debug!("got key: %?", key); - let modifiers = glut::get_modifiers(); + fn handle_key(&self, key: c_int, mods: c_int) { match key { - 12 => self.load_url(), // Ctrl+L - 31 if (modifiers & ACTIVE_CTRL) != 0 => { // Ctrl+- + glfw::KEY_L if mods & glfw::MOD_CONTROL != 0 => self.load_url(), // Ctrl+L + glfw::KEY_EQUAL if mods & glfw::MOD_CONTROL != 0 => { // Ctrl-+ for self.zoom_callback.iter().advance |&callback| { - callback(-0.1); + callback(1.1); } } - 127 => { + glfw::KEY_MINUS if mods & glfw::MOD_CONTROL != 0 => { // Ctrl-- + for self.zoom_callback.iter().advance |&callback| { + callback(0.90909090909); + } + } + glfw::KEY_BACKSPACE if mods & glfw::MOD_SHIFT != 0 => { // Shift-Backspace for self.navigation_callback.iter().advance |&callback| { - if (modifiers & ACTIVE_SHIFT) != 0 { // Shift+Backspace - callback(Forward); - } - else { - callback(Back); - } + callback(Forward); } } - c => match c as char { - '=' if (modifiers & ACTIVE_CTRL) != 0 => { // Ctrl++ - for self.zoom_callback.iter().advance |&callback| { - callback(0.1); - } + glfw::KEY_BACKSPACE => { // Backspace + for self.navigation_callback.iter().advance |&callback| { + callback(Back); } - _ => {} } + _ => {} } } /// Helper function to handle a click - fn handle_mouse(&self, button: c_int, state: c_int, x: c_int, y: c_int) { + fn handle_mouse(&self, button: c_int, action: c_int, x: c_int, y: c_int) { // FIXME(tkuehn): max pixel dist should be based on pixel density let max_pixel_dist = 10f; match self.mouse_callback { None => {} Some(callback) => { let event: WindowMouseEvent; - match state { - glut::MOUSE_DOWN => { + match action { + glfw::PRESS => { event = WindowMouseDownEvent(button as uint, Point2D(x as f32, y as f32)); *self.mouse_down_point = Point2D(x, y); *self.mouse_down_button = button; } - glut::MOUSE_UP => { + glfw::RELEASE => { event = WindowMouseUpEvent(button as uint, Point2D(x as f32, y as f32)); if *self.mouse_down_button == button { let pixel_dist = *self.mouse_down_point - Point2D(x, y); diff --git a/src/components/main/platform/mod.rs b/src/components/main/platform/mod.rs index fdbd3bf42d9..3467234d0e6 100644 --- a/src/components/main/platform/mod.rs +++ b/src/components/main/platform/mod.rs @@ -5,13 +5,13 @@ //! Platform-specific functionality for Servo. #[cfg(not(shared_gl_windowing))] -pub use platform::common::glut_windowing::{Application, Window}; +pub use platform::common::glfw_windowing::{Application, Window}; #[cfg(shared_gl_windowing)] pub use platform::common::shared_gl_windowing::{Application, Window}; pub mod common { #[cfg(not(shared_gl_windowing))] - pub mod glut_windowing; + pub mod glfw_windowing; #[cfg(shared_gl_windowing)] pub mod shared_gl_windowing; } diff --git a/src/components/main/servo.rc b/src/components/main/servo.rc index 3ee37198619..424e90b33f3 100755 --- a/src/components/main/servo.rc +++ b/src/components/main/servo.rc @@ -15,7 +15,7 @@ extern mod alert; extern mod azure; extern mod geom; extern mod gfx (name = "gfx"); -extern mod glut; +extern mod glfw; extern mod http_client; extern mod js; extern mod layers; diff --git a/src/components/main/windowing.rs b/src/components/main/windowing.rs index 8a102c055c4..edf4bd3800f 100644 --- a/src/components/main/windowing.rs +++ b/src/components/main/windowing.rs @@ -70,8 +70,6 @@ pub trait WindowMethods { /// Spins the event loop. pub fn check_loop(@mut self); - /// Schedules a redisplay at the next turn of the event loop. - pub fn set_needs_display(@mut self); /// Sets the ready state of the current page. pub fn set_ready_state(@mut self, ready_state: ReadyState); /// Sets the render state of the current page. diff --git a/src/components/script/script_task.rs b/src/components/script/script_task.rs index 4d46b241b3c..e6d2ef28436 100644 --- a/src/components/script/script_task.rs +++ b/src/components/script/script_task.rs @@ -183,7 +183,8 @@ impl ScriptTask { script_chan: ScriptChan, constellation_chan: ConstellationChan, resource_task: ResourceTask, - img_cache_task: ImageCacheTask) + img_cache_task: ImageCacheTask, + initial_size: Size2D) -> @mut ScriptTask { let js_runtime = js::rust::rt(); let js_context = js_runtime.cx(); @@ -219,7 +220,7 @@ impl ScriptTask { root_frame: None, - window_size: Size2D(800u, 600), + window_size: Size2D(initial_size.width as uint, initial_size.height as uint), damage: None, last_loaded_url: None, @@ -253,7 +254,8 @@ impl ScriptTask { script_chan: ScriptChan, constellation_chan: ConstellationChan, resource_task: ResourceTask, - image_cache_task: ImageCacheTask) { + image_cache_task: ImageCacheTask, + initial_size: Size2D) { let compositor = Cell::new(compositor); let script_port = Cell::new(script_port); // FIXME: rust#6399 @@ -267,7 +269,8 @@ impl ScriptTask { script_chan.clone(), constellation_chan.clone(), resource_task.clone(), - image_cache_task.clone()); + image_cache_task.clone(), + initial_size); script_task.start(); } } diff --git a/src/support/azure/rust-azure b/src/support/azure/rust-azure index 6daaffe3b6c..d265202c324 160000 --- a/src/support/azure/rust-azure +++ b/src/support/azure/rust-azure @@ -1 +1 @@ -Subproject commit 6daaffe3b6cf226c6da4979d0fb907a8258b0288 +Subproject commit d265202c324d566a52d5946e08ad148dcf068252 diff --git a/src/support/layers/rust-layers b/src/support/layers/rust-layers index a1454f07d3d..41b967cf1a1 160000 --- a/src/support/layers/rust-layers +++ b/src/support/layers/rust-layers @@ -1 +1 @@ -Subproject commit a1454f07d3df11b16dc88bedf79d20693bfc3bb7 +Subproject commit 41b967cf1a1bf91227a4e8ee52c82a228eeb7e94 diff --git a/src/support/skia/skia b/src/support/skia/skia index 3f41e98925b..f889ab32a6f 160000 --- a/src/support/skia/skia +++ b/src/support/skia/skia @@ -1 +1 @@ -Subproject commit 3f41e98925b9d4c0d4074046388e73f0e0032ab9 +Subproject commit f889ab32a6fc249b2a8667a7c7c1e5c24d5daf7c