mirror of
https://github.com/servo/servo.git
synced 2025-06-22 08:08:59 +01:00
Change glutin headless mode to be a build config, as it breaks some Linux distros linking to both.
The majority of this change is simply re-arranging the code in the glutin port so that the windowed/headless code is configured at build time rather than runtime. There shouldn't be any functional difference as a result of this change.
This commit is contained in:
parent
59bca2962c
commit
0f525d908d
10 changed files with 462 additions and 449 deletions
2
components/servo/Cargo.lock
generated
2
components/servo/Cargo.lock
generated
|
@ -335,7 +335,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glutin"
|
name = "glutin"
|
||||||
version = "0.0.2"
|
version = "0.0.2"
|
||||||
source = "git+https://github.com/servo/glutin?ref=servo#db27370a1cbafcbfcaeee52a44076a61b3e0573c"
|
source = "git+https://github.com/servo/glutin?ref=servo#ec6b4d0fff12ef607db422508ae005ba91406f5b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"android_glue 0.0.1 (git+https://github.com/servo/android-rs-glue?ref=servo)",
|
"android_glue 0.0.1 (git+https://github.com/servo/android-rs-glue?ref=servo)",
|
||||||
"cocoa 0.1.1 (git+https://github.com/servo/rust-cocoa)",
|
"cocoa 0.1.1 (git+https://github.com/servo/rust-cocoa)",
|
||||||
|
|
|
@ -27,8 +27,10 @@ path = "../../tests/contenttest.rs"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["glutin_app"]
|
default = ["glutin_app", "window"]
|
||||||
glfw = ["glfw_app"]
|
glfw = ["glfw_app"]
|
||||||
|
window = ["glutin_app/window"]
|
||||||
|
headless = ["glutin_app/headless"]
|
||||||
|
|
||||||
[dependencies.compositing]
|
[dependencies.compositing]
|
||||||
path = "../compositing"
|
path = "../compositing"
|
||||||
|
|
|
@ -11,7 +11,6 @@ use geom::scale_factor::ScaleFactor;
|
||||||
use geom::size::TypedSize2D;
|
use geom::size::TypedSize2D;
|
||||||
use layers::geometry::DevicePixel;
|
use layers::geometry::DevicePixel;
|
||||||
use getopts;
|
use getopts;
|
||||||
use std::borrow::ToOwned;
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
@ -20,12 +19,6 @@ use std::os;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::rt;
|
use std::rt;
|
||||||
|
|
||||||
#[deriving(Clone, Copy)]
|
|
||||||
pub enum RenderApi {
|
|
||||||
OpenGL,
|
|
||||||
Mesa,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Global flags for Servo, currently set on the command line.
|
/// Global flags for Servo, currently set on the command line.
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
pub struct Opts {
|
pub struct Opts {
|
||||||
|
@ -113,8 +106,6 @@ pub struct Opts {
|
||||||
/// Whether to show an error when display list geometry escapes flow overflow regions.
|
/// Whether to show an error when display list geometry escapes flow overflow regions.
|
||||||
pub validate_display_list_geometry: bool,
|
pub validate_display_list_geometry: bool,
|
||||||
|
|
||||||
pub render_api: RenderApi,
|
|
||||||
|
|
||||||
/// A specific path to find required resources (such as user-agent.css).
|
/// A specific path to find required resources (such as user-agent.css).
|
||||||
pub resources_path: Option<String>,
|
pub resources_path: Option<String>,
|
||||||
}
|
}
|
||||||
|
@ -183,7 +174,6 @@ pub fn default_opts() -> Opts {
|
||||||
dump_flow_tree: false,
|
dump_flow_tree: false,
|
||||||
validate_display_list_geometry: false,
|
validate_display_list_geometry: false,
|
||||||
profile_tasks: false,
|
profile_tasks: false,
|
||||||
render_api: RenderApi::OpenGL,
|
|
||||||
resources_path: None,
|
resources_path: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -303,15 +293,6 @@ pub fn from_cmdline_args(args: &[String]) -> bool {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let render_api = match opt_match.opt_str("r").unwrap_or("gl".to_owned()).as_slice() {
|
|
||||||
"mesa" => RenderApi::Mesa,
|
|
||||||
"gl" => RenderApi::OpenGL,
|
|
||||||
_ => {
|
|
||||||
args_fail("Unknown render api specified");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let opts = Opts {
|
let opts = Opts {
|
||||||
urls: urls,
|
urls: urls,
|
||||||
n_paint_threads: n_paint_threads,
|
n_paint_threads: n_paint_threads,
|
||||||
|
@ -337,7 +318,6 @@ pub fn from_cmdline_args(args: &[String]) -> bool {
|
||||||
enable_text_antialiasing: !debug_options.contains(&"disable-text-aa"),
|
enable_text_antialiasing: !debug_options.contains(&"disable-text-aa"),
|
||||||
dump_flow_tree: debug_options.contains(&"dump-flow-tree"),
|
dump_flow_tree: debug_options.contains(&"dump-flow-tree"),
|
||||||
validate_display_list_geometry: debug_options.contains(&"validate-display-list-geometry"),
|
validate_display_list_geometry: debug_options.contains(&"validate-display-list-geometry"),
|
||||||
render_api: render_api,
|
|
||||||
resources_path: opt_match.opt_str("resources-path"),
|
resources_path: opt_match.opt_str("resources-path"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
2
ports/cef/Cargo.lock
generated
2
ports/cef/Cargo.lock
generated
|
@ -314,7 +314,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glutin"
|
name = "glutin"
|
||||||
version = "0.0.2"
|
version = "0.0.2"
|
||||||
source = "git+https://github.com/servo/glutin?ref=servo#db27370a1cbafcbfcaeee52a44076a61b3e0573c"
|
source = "git+https://github.com/servo/glutin?ref=servo#ec6b4d0fff12ef607db422508ae005ba91406f5b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"android_glue 0.0.1 (git+https://github.com/servo/android-rs-glue?ref=servo)",
|
"android_glue 0.0.1 (git+https://github.com/servo/android-rs-glue?ref=servo)",
|
||||||
"cocoa 0.1.1 (git+https://github.com/servo/rust-cocoa)",
|
"cocoa 0.1.1 (git+https://github.com/servo/rust-cocoa)",
|
||||||
|
|
|
@ -11,7 +11,6 @@ use libc::{c_char, c_int, c_void};
|
||||||
use rustrt::local::Local;
|
use rustrt::local::Local;
|
||||||
use rustrt::task;
|
use rustrt::task;
|
||||||
use servo_util::opts;
|
use servo_util::opts;
|
||||||
use servo_util::opts::RenderApi;
|
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
use std::c_str::CString;
|
use std::c_str::CString;
|
||||||
use std::rt;
|
use std::rt;
|
||||||
|
@ -105,7 +104,6 @@ pub extern "C" fn cef_initialize(args: *const cef_main_args_t,
|
||||||
user_agent: None,
|
user_agent: None,
|
||||||
dump_flow_tree: false,
|
dump_flow_tree: false,
|
||||||
validate_display_list_geometry: false,
|
validate_display_list_geometry: false,
|
||||||
render_api: RenderApi::OpenGL,
|
|
||||||
resources_path: resources_path(),
|
resources_path: resources_path(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,10 @@ authors = ["The Servo Project Developers"]
|
||||||
name = "glutin_app"
|
name = "glutin_app"
|
||||||
path = "lib.rs"
|
path = "lib.rs"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
window = ["glutin/window"]
|
||||||
|
headless = ["glutin/headless"]
|
||||||
|
|
||||||
[dependencies.compositing]
|
[dependencies.compositing]
|
||||||
path = "../../components/compositing"
|
path = "../../components/compositing"
|
||||||
|
|
||||||
|
@ -25,7 +29,6 @@ path = "../../components/util"
|
||||||
[dependencies.glutin]
|
[dependencies.glutin]
|
||||||
git = "https://github.com/servo/glutin"
|
git = "https://github.com/servo/glutin"
|
||||||
branch = "servo"
|
branch = "servo"
|
||||||
features = ["window", "headless"]
|
|
||||||
|
|
||||||
[dependencies.gleam]
|
[dependencies.gleam]
|
||||||
git = "https://github.com/servo/gleam"
|
git = "https://github.com/servo/gleam"
|
||||||
|
|
|
@ -40,5 +40,5 @@ pub fn create_window() -> Rc<Window> {
|
||||||
let size = opts.initial_window_size.as_f32() * scale_factor;
|
let size = opts.initial_window_size.as_f32() * scale_factor;
|
||||||
|
|
||||||
// Open a window.
|
// Open a window.
|
||||||
Window::new(foreground, size.as_uint(), opts.render_api)
|
Window::new(foreground, size.as_uint())
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,57 +5,46 @@
|
||||||
//! A windowing implementation using glutin.
|
//! A windowing implementation using glutin.
|
||||||
|
|
||||||
use compositing::compositor_task::{mod, CompositorProxy, CompositorReceiver};
|
use compositing::compositor_task::{mod, CompositorProxy, CompositorReceiver};
|
||||||
use compositing::windowing::WindowNavigateMsg;
|
use compositing::windowing::{WindowEvent, WindowMethods};
|
||||||
use compositing::windowing::{MouseWindowEvent, WindowEvent, WindowMethods};
|
|
||||||
use geom::point::{Point2D, TypedPoint2D};
|
|
||||||
use geom::scale_factor::ScaleFactor;
|
use geom::scale_factor::ScaleFactor;
|
||||||
use geom::size::TypedSize2D;
|
use geom::size::TypedSize2D;
|
||||||
|
use gleam::gl;
|
||||||
|
use glutin;
|
||||||
use layers::geometry::DevicePixel;
|
use layers::geometry::DevicePixel;
|
||||||
use layers::platform::surface::NativeGraphicsMetadata;
|
use layers::platform::surface::NativeGraphicsMetadata;
|
||||||
use msg::constellation_msg;
|
use msg::constellation_msg;
|
||||||
use msg::constellation_msg::{Key, KeyState, CONTROL, SHIFT, ALT};
|
use msg::constellation_msg::Key;
|
||||||
use msg::compositor_msg::{PaintState, ReadyState};
|
use msg::compositor_msg::{PaintState, ReadyState};
|
||||||
use msg::constellation_msg::LoadData;
|
use msg::constellation_msg::LoadData;
|
||||||
use std::cell::{Cell, RefCell};
|
|
||||||
use std::num::Float;
|
|
||||||
use std::rc::Rc;
|
|
||||||
use time::{mod, Timespec};
|
|
||||||
use util::geometry::ScreenPx;
|
|
||||||
use util::opts;
|
|
||||||
use util::opts::RenderApi;
|
|
||||||
use gleam::gl;
|
|
||||||
use glutin;
|
|
||||||
use glutin::{ElementState, Event, MouseButton, VirtualKeyCode};
|
|
||||||
use NestedEventLoopListener;
|
use NestedEventLoopListener;
|
||||||
|
use std::rc::Rc;
|
||||||
use util::cursor::Cursor;
|
use util::cursor::Cursor;
|
||||||
|
use util::geometry::ScreenPx;
|
||||||
|
|
||||||
#[cfg(target_os="linux")]
|
#[cfg(feature = "window")]
|
||||||
|
use compositing::windowing::{MouseWindowEvent, WindowNavigateMsg};
|
||||||
|
#[cfg(feature = "window")]
|
||||||
|
use geom::point::{Point2D, TypedPoint2D};
|
||||||
|
#[cfg(feature = "window")]
|
||||||
|
use glutin::{ElementState, Event, MouseButton, VirtualKeyCode};
|
||||||
|
#[cfg(feature = "window")]
|
||||||
|
use msg::constellation_msg::{KeyState, CONTROL, SHIFT, ALT};
|
||||||
|
#[cfg(feature = "window")]
|
||||||
|
use std::cell::{Cell, RefCell};
|
||||||
|
#[cfg(feature = "window")]
|
||||||
|
use std::num::Float;
|
||||||
|
#[cfg(feature = "window")]
|
||||||
|
use time::{mod, Timespec};
|
||||||
|
#[cfg(feature = "window")]
|
||||||
|
use util::opts;
|
||||||
|
|
||||||
|
#[cfg(all(feature = "headless", target_os="linux"))]
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
struct HeadlessContext {
|
#[cfg(feature = "window")]
|
||||||
#[allow(dead_code)]
|
|
||||||
context: glutin::HeadlessContext,
|
|
||||||
size: TypedSize2D<DevicePixel, uint>,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum WindowHandle {
|
|
||||||
Windowed(glutin::Window),
|
|
||||||
Headless(HeadlessContext),
|
|
||||||
}
|
|
||||||
|
|
||||||
static mut g_nested_event_loop_listener: Option<*mut (NestedEventLoopListener + 'static)> = None;
|
static mut g_nested_event_loop_listener: Option<*mut (NestedEventLoopListener + 'static)> = None;
|
||||||
|
|
||||||
fn nested_window_resize(width: uint, height: uint) {
|
#[cfg(feature = "window")]
|
||||||
unsafe {
|
|
||||||
match g_nested_event_loop_listener {
|
|
||||||
None => {}
|
|
||||||
Some(listener) => {
|
|
||||||
(*listener).handle_event_from_nested_event_loop(WindowEvent::Resize(TypedSize2D(width, height)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bitflags!(
|
bitflags!(
|
||||||
#[deriving(Show, Copy)]
|
#[deriving(Show, Copy)]
|
||||||
flags KeyModifiers: u8 {
|
flags KeyModifiers: u8 {
|
||||||
|
@ -69,8 +58,9 @@ bitflags!(
|
||||||
)
|
)
|
||||||
|
|
||||||
/// The type of a window.
|
/// The type of a window.
|
||||||
|
#[cfg(feature = "window")]
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
glutin: WindowHandle,
|
window: glutin::Window,
|
||||||
|
|
||||||
mouse_down_button: Cell<Option<glutin::MouseButton>>,
|
mouse_down_button: Cell<Option<glutin::MouseButton>>,
|
||||||
mouse_down_point: Cell<Point2D<int>>,
|
mouse_down_point: Cell<Point2D<int>>,
|
||||||
|
@ -84,67 +74,24 @@ pub struct Window {
|
||||||
last_title_set_time: Cell<Timespec>,
|
last_title_set_time: Cell<Timespec>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os="android"))]
|
#[cfg(feature = "window")]
|
||||||
fn load_gl_functions(glutin: &WindowHandle) {
|
|
||||||
match glutin {
|
|
||||||
&WindowHandle::Windowed(ref window) => gl::load_with(|s| window.get_proc_address(s)),
|
|
||||||
&WindowHandle::Headless(ref headless) => gl::load_with(|s| headless.context.get_proc_address(s)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os="android")]
|
|
||||||
fn load_gl_functions(_glutin: &WindowHandle) {
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(target_os="android"))]
|
|
||||||
fn gl_version() -> (uint, uint) {
|
|
||||||
(3, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os="android")]
|
|
||||||
fn gl_version() -> (uint, uint) {
|
|
||||||
(2, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
/// Creates a new window.
|
pub fn new(is_foreground: bool, window_size: TypedSize2D<DevicePixel, uint>) -> Rc<Window> {
|
||||||
pub fn new(is_foreground: bool, size: TypedSize2D<DevicePixel, uint>, render_api: RenderApi)
|
let mut glutin_window = glutin::WindowBuilder::new()
|
||||||
-> Rc<Window> {
|
.with_title("Servo [glutin]".to_string())
|
||||||
|
.with_dimensions(window_size.to_untyped().width, window_size.to_untyped().height)
|
||||||
|
.with_gl_version(Window::gl_version())
|
||||||
|
.with_visibility(is_foreground)
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
unsafe { glutin_window.make_current() };
|
||||||
|
|
||||||
// Create the glutin window.
|
glutin_window.set_window_resize_callback(Some(Window::nested_window_resize));
|
||||||
let window_size = size.to_untyped();
|
|
||||||
|
|
||||||
let glutin = match render_api {
|
Window::load_gl_functions(&glutin_window);
|
||||||
RenderApi::OpenGL => {
|
|
||||||
let mut glutin_window = glutin::WindowBuilder::new()
|
|
||||||
.with_title("Servo [glutin]".to_string())
|
|
||||||
.with_dimensions(window_size.width, window_size.height)
|
|
||||||
.with_gl_version(gl_version())
|
|
||||||
.with_visibility(is_foreground)
|
|
||||||
.build()
|
|
||||||
.unwrap();
|
|
||||||
unsafe { glutin_window.make_current() };
|
|
||||||
|
|
||||||
glutin_window.set_window_resize_callback(Some(nested_window_resize));
|
|
||||||
WindowHandle::Windowed(glutin_window)
|
|
||||||
}
|
|
||||||
RenderApi::Mesa => {
|
|
||||||
let headless_builder = glutin::HeadlessRendererBuilder::new(window_size.width,
|
|
||||||
window_size.height);
|
|
||||||
let headless_context = headless_builder.build().unwrap();
|
|
||||||
unsafe { headless_context.make_current() };
|
|
||||||
|
|
||||||
WindowHandle::Headless(HeadlessContext {
|
|
||||||
context: headless_context,
|
|
||||||
size: size,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
load_gl_functions(&glutin);
|
|
||||||
|
|
||||||
let window = Window {
|
let window = Window {
|
||||||
glutin: glutin,
|
window: glutin_window,
|
||||||
event_queue: RefCell::new(vec!()),
|
event_queue: RefCell::new(vec!()),
|
||||||
mouse_down_button: Cell::new(None),
|
mouse_down_button: Cell::new(None),
|
||||||
mouse_down_point: Cell::new(Point2D(0, 0)),
|
mouse_down_point: Cell::new(Point2D(0, 0)),
|
||||||
|
@ -164,303 +111,37 @@ impl Window {
|
||||||
|
|
||||||
Rc::new(window)
|
Rc::new(window)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl WindowMethods for Window {
|
fn nested_window_resize(width: uint, height: uint) {
|
||||||
/// Returns the size of the window in hardware pixels.
|
|
||||||
fn framebuffer_size(&self) -> TypedSize2D<DevicePixel, uint> {
|
|
||||||
let (width, height) = match self.glutin {
|
|
||||||
WindowHandle::Windowed(ref window) => {
|
|
||||||
let scale_factor = window.hidpi_factor() as uint;
|
|
||||||
let (width, height) = window.get_inner_size().unwrap();
|
|
||||||
Some((width * scale_factor, height * scale_factor))
|
|
||||||
}
|
|
||||||
WindowHandle::Headless(ref context) => Some((context.size.to_untyped().width,
|
|
||||||
context.size.to_untyped().height)),
|
|
||||||
}.unwrap();
|
|
||||||
TypedSize2D(width as uint, height as uint)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the size of the window in density-independent "px" units.
|
|
||||||
fn size(&self) -> TypedSize2D<ScreenPx, f32> {
|
|
||||||
// TODO: Handle hidpi
|
|
||||||
let (width, height) = match self.glutin {
|
|
||||||
WindowHandle::Windowed(ref window) => window.get_inner_size(),
|
|
||||||
WindowHandle::Headless(ref context) => Some((context.size.to_untyped().width,
|
|
||||||
context.size.to_untyped().height)),
|
|
||||||
}.unwrap();
|
|
||||||
TypedSize2D(width as f32, height as f32)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Presents the window to the screen (perhaps by page flipping).
|
|
||||||
fn present(&self) {
|
|
||||||
match self.glutin {
|
|
||||||
WindowHandle::Windowed(ref window) => window.swap_buffers(),
|
|
||||||
WindowHandle::Headless(_) => {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_compositor_channel(window: &Option<Rc<Window>>)
|
|
||||||
-> (Box<CompositorProxy+Send>, Box<CompositorReceiver>) {
|
|
||||||
let (sender, receiver) = channel();
|
|
||||||
|
|
||||||
let window_proxy = match window {
|
|
||||||
&Some(ref window) => {
|
|
||||||
match window.glutin {
|
|
||||||
WindowHandle::Windowed(ref window) => Some(window.create_window_proxy()),
|
|
||||||
WindowHandle::Headless(_) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&None => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
(box GlutinCompositorProxy {
|
|
||||||
sender: sender,
|
|
||||||
window_proxy: window_proxy,
|
|
||||||
} as Box<CompositorProxy+Send>,
|
|
||||||
box receiver as Box<CompositorReceiver>)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the ready state.
|
|
||||||
fn set_ready_state(&self, ready_state: ReadyState) {
|
|
||||||
self.ready_state.set(ready_state);
|
|
||||||
self.update_window_title()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the paint state.
|
|
||||||
fn set_paint_state(&self, paint_state: PaintState) {
|
|
||||||
self.paint_state.set(paint_state);
|
|
||||||
self.update_window_title()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn hidpi_factor(&self) -> ScaleFactor<ScreenPx, DevicePixel, f32> {
|
|
||||||
match self.glutin {
|
|
||||||
WindowHandle::Windowed(ref window) => ScaleFactor(window.hidpi_factor()),
|
|
||||||
WindowHandle::Headless(_) => ScaleFactor(1.0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_page_title(&self, _: Option<String>) {
|
|
||||||
// TODO(gw)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_page_load_data(&self, _: LoadData) {
|
|
||||||
// TODO(gw)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_end(&self) {
|
|
||||||
// TODO(gw)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_cursor(&self, _: Cursor) {
|
|
||||||
// No-op. We could take over mouse handling ourselves and draw the cursor as an extra
|
|
||||||
// layer with our own custom bitmaps or something, but it doesn't seem worth the
|
|
||||||
// trouble.
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prepare_for_composite(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os="linux")]
|
|
||||||
fn native_metadata(&self) -> NativeGraphicsMetadata {
|
|
||||||
match self.glutin {
|
|
||||||
WindowHandle::Windowed(ref window) => {
|
|
||||||
NativeGraphicsMetadata {
|
|
||||||
display: unsafe { window.platform_display() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
WindowHandle::Headless(_) => {
|
|
||||||
NativeGraphicsMetadata {
|
|
||||||
display: ptr::null_mut()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os="macos")]
|
|
||||||
fn native_metadata(&self) -> NativeGraphicsMetadata {
|
|
||||||
use cgl::{CGLGetCurrentContext, CGLGetPixelFormat};
|
|
||||||
unsafe {
|
unsafe {
|
||||||
NativeGraphicsMetadata {
|
match g_nested_event_loop_listener {
|
||||||
pixel_format: CGLGetPixelFormat(CGLGetCurrentContext()),
|
None => {}
|
||||||
|
Some(listener) => {
|
||||||
|
(*listener).handle_event_from_nested_event_loop(WindowEvent::Resize(TypedSize2D(width, height)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os="android"))]
|
||||||
|
fn gl_version() -> (uint, uint) {
|
||||||
|
(3, 0)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(target_os="android")]
|
#[cfg(target_os="android")]
|
||||||
fn native_metadata(&self) -> NativeGraphicsMetadata {
|
fn gl_version() -> (uint, uint) {
|
||||||
use egl::egl::GetCurrentDisplay;
|
(2, 0)
|
||||||
NativeGraphicsMetadata {
|
|
||||||
display: GetCurrentDisplay(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to handle keyboard events.
|
#[cfg(not(target_os="android"))]
|
||||||
fn handle_key(&self, key: Key, mods: constellation_msg::KeyModifiers) {
|
fn load_gl_functions(window: &glutin::Window) {
|
||||||
match key {
|
gl::load_with(|s| window.get_proc_address(s));
|
||||||
Key::Equal if mods.contains(CONTROL) => { // Ctrl-+
|
|
||||||
self.event_queue.borrow_mut().push(WindowEvent::Zoom(1.1));
|
|
||||||
}
|
|
||||||
Key::Minus if mods.contains(CONTROL) => { // Ctrl--
|
|
||||||
self.event_queue.borrow_mut().push(WindowEvent::Zoom(1.0/1.1));
|
|
||||||
}
|
|
||||||
Key::Backspace if mods.contains(SHIFT) => { // Shift-Backspace
|
|
||||||
self.event_queue.borrow_mut().push(WindowEvent::Navigation(WindowNavigateMsg::Forward));
|
|
||||||
}
|
|
||||||
Key::Backspace => { // Backspace
|
|
||||||
self.event_queue.borrow_mut().push(WindowEvent::Navigation(WindowNavigateMsg::Back));
|
|
||||||
}
|
|
||||||
Key::PageDown => {
|
|
||||||
self.scroll_window(0.0, -self.framebuffer_size().as_f32().to_untyped().height);
|
|
||||||
}
|
|
||||||
Key::PageUp => {
|
|
||||||
self.scroll_window(0.0, self.framebuffer_size().as_f32().to_untyped().height);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Window {
|
#[cfg(target_os="android")]
|
||||||
/// Helper function to set the window title in accordance with the ready state.
|
fn load_gl_functions(_: &glutin::Window) {
|
||||||
fn update_window_title(&self) {
|
|
||||||
match self.glutin {
|
|
||||||
WindowHandle::Windowed(ref window) => {
|
|
||||||
let now = time::get_time();
|
|
||||||
if now.sec == self.last_title_set_time.get().sec {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.last_title_set_time.set(now);
|
|
||||||
|
|
||||||
match self.ready_state.get() {
|
|
||||||
ReadyState::Blank => {
|
|
||||||
window.set_title("blank - Servo [glutin]")
|
|
||||||
}
|
|
||||||
ReadyState::Loading => {
|
|
||||||
window.set_title("Loading - Servo [glutin]")
|
|
||||||
}
|
|
||||||
ReadyState::PerformingLayout => {
|
|
||||||
window.set_title("Performing Layout - Servo [glutin]")
|
|
||||||
}
|
|
||||||
ReadyState::FinishedLoading => {
|
|
||||||
match self.paint_state.get() {
|
|
||||||
PaintState::Painting => {
|
|
||||||
window.set_title("Rendering - Servo [glutin]")
|
|
||||||
}
|
|
||||||
PaintState::Idle => {
|
|
||||||
window.set_title("Servo [glutin]")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
WindowHandle::Headless(_) => {},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn glutin_mods_to_script_mods(modifiers: KeyModifiers) -> constellation_msg::KeyModifiers {
|
|
||||||
let mut result = constellation_msg::KeyModifiers::from_bits(0).unwrap();
|
|
||||||
if modifiers.intersects(LEFT_SHIFT | RIGHT_SHIFT) {
|
|
||||||
result.insert(SHIFT);
|
|
||||||
}
|
|
||||||
if modifiers.intersects(LEFT_CONTROL | RIGHT_CONTROL) {
|
|
||||||
result.insert(CONTROL);
|
|
||||||
}
|
|
||||||
if modifiers.intersects(LEFT_ALT | RIGHT_ALT) {
|
|
||||||
result.insert(ALT);
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
fn glutin_key_to_script_key(key: glutin::VirtualKeyCode) -> Result<constellation_msg::Key, ()> {
|
|
||||||
// TODO(negge): add more key mappings
|
|
||||||
match key {
|
|
||||||
VirtualKeyCode::A => Ok(Key::A),
|
|
||||||
VirtualKeyCode::B => Ok(Key::B),
|
|
||||||
VirtualKeyCode::C => Ok(Key::C),
|
|
||||||
VirtualKeyCode::D => Ok(Key::D),
|
|
||||||
VirtualKeyCode::E => Ok(Key::E),
|
|
||||||
VirtualKeyCode::F => Ok(Key::F),
|
|
||||||
VirtualKeyCode::G => Ok(Key::G),
|
|
||||||
VirtualKeyCode::H => Ok(Key::H),
|
|
||||||
VirtualKeyCode::I => Ok(Key::I),
|
|
||||||
VirtualKeyCode::J => Ok(Key::J),
|
|
||||||
VirtualKeyCode::K => Ok(Key::K),
|
|
||||||
VirtualKeyCode::L => Ok(Key::L),
|
|
||||||
VirtualKeyCode::M => Ok(Key::M),
|
|
||||||
VirtualKeyCode::N => Ok(Key::N),
|
|
||||||
VirtualKeyCode::O => Ok(Key::O),
|
|
||||||
VirtualKeyCode::P => Ok(Key::P),
|
|
||||||
VirtualKeyCode::Q => Ok(Key::Q),
|
|
||||||
VirtualKeyCode::R => Ok(Key::R),
|
|
||||||
VirtualKeyCode::S => Ok(Key::S),
|
|
||||||
VirtualKeyCode::T => Ok(Key::T),
|
|
||||||
VirtualKeyCode::U => Ok(Key::U),
|
|
||||||
VirtualKeyCode::V => Ok(Key::V),
|
|
||||||
VirtualKeyCode::W => Ok(Key::W),
|
|
||||||
VirtualKeyCode::X => Ok(Key::X),
|
|
||||||
VirtualKeyCode::Y => Ok(Key::Y),
|
|
||||||
VirtualKeyCode::Z => Ok(Key::Z),
|
|
||||||
|
|
||||||
VirtualKeyCode::Numpad0 => Ok(Key::Num0),
|
|
||||||
VirtualKeyCode::Numpad1 => Ok(Key::Num1),
|
|
||||||
VirtualKeyCode::Numpad2 => Ok(Key::Num2),
|
|
||||||
VirtualKeyCode::Numpad3 => Ok(Key::Num3),
|
|
||||||
VirtualKeyCode::Numpad4 => Ok(Key::Num4),
|
|
||||||
VirtualKeyCode::Numpad5 => Ok(Key::Num5),
|
|
||||||
VirtualKeyCode::Numpad6 => Ok(Key::Num6),
|
|
||||||
VirtualKeyCode::Numpad7 => Ok(Key::Num7),
|
|
||||||
VirtualKeyCode::Numpad8 => Ok(Key::Num8),
|
|
||||||
VirtualKeyCode::Numpad9 => Ok(Key::Num9),
|
|
||||||
|
|
||||||
VirtualKeyCode::Key0 => Ok(Key::Kp0),
|
|
||||||
VirtualKeyCode::Key1 => Ok(Key::Kp1),
|
|
||||||
VirtualKeyCode::Key2 => Ok(Key::Kp2),
|
|
||||||
VirtualKeyCode::Key3 => Ok(Key::Kp3),
|
|
||||||
VirtualKeyCode::Key4 => Ok(Key::Kp4),
|
|
||||||
VirtualKeyCode::Key5 => Ok(Key::Kp5),
|
|
||||||
VirtualKeyCode::Key6 => Ok(Key::Kp6),
|
|
||||||
VirtualKeyCode::Key7 => Ok(Key::Kp7),
|
|
||||||
VirtualKeyCode::Key8 => Ok(Key::Kp8),
|
|
||||||
VirtualKeyCode::Key9 => Ok(Key::Kp9),
|
|
||||||
|
|
||||||
VirtualKeyCode::Return => Ok(Key::Enter),
|
|
||||||
VirtualKeyCode::Space => Ok(Key::Space),
|
|
||||||
VirtualKeyCode::Escape => Ok(Key::Escape),
|
|
||||||
VirtualKeyCode::Equals => Ok(Key::Equal),
|
|
||||||
VirtualKeyCode::Minus => Ok(Key::Minus),
|
|
||||||
VirtualKeyCode::Back => Ok(Key::Backspace),
|
|
||||||
VirtualKeyCode::PageDown => Ok(Key::PageDown),
|
|
||||||
VirtualKeyCode::PageUp => Ok(Key::PageUp),
|
|
||||||
|
|
||||||
VirtualKeyCode::Insert => Ok(Key::Insert),
|
|
||||||
VirtualKeyCode::Home => Ok(Key::Home),
|
|
||||||
VirtualKeyCode::Delete => Ok(Key::Delete),
|
|
||||||
VirtualKeyCode::End => Ok(Key::End),
|
|
||||||
|
|
||||||
VirtualKeyCode::Left => Ok(Key::Left),
|
|
||||||
VirtualKeyCode::Up => Ok(Key::Up),
|
|
||||||
VirtualKeyCode::Right => Ok(Key::Right),
|
|
||||||
VirtualKeyCode::Down => Ok(Key::Down),
|
|
||||||
|
|
||||||
VirtualKeyCode::Apostrophe => Ok(Key::Apostrophe),
|
|
||||||
VirtualKeyCode::Backslash => Ok(Key::Backslash),
|
|
||||||
VirtualKeyCode::Comma => Ok(Key::Comma),
|
|
||||||
VirtualKeyCode::Grave => Ok(Key::GraveAccent),
|
|
||||||
VirtualKeyCode::LBracket => Ok(Key::LeftBracket),
|
|
||||||
VirtualKeyCode::Period => Ok(Key::Period),
|
|
||||||
VirtualKeyCode::RBracket => Ok(Key::RightBracket),
|
|
||||||
VirtualKeyCode::Semicolon => Ok(Key::Semicolon),
|
|
||||||
VirtualKeyCode::Slash => Ok(Key::Slash),
|
|
||||||
VirtualKeyCode::Tab => Ok(Key::Tab),
|
|
||||||
|
|
||||||
_ => Err(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Window {
|
|
||||||
fn handle_window_event(&self, event: glutin::Event) -> bool {
|
fn handle_window_event(&self, event: glutin::Event) -> bool {
|
||||||
match event {
|
match event {
|
||||||
Event::KeyboardInput(element_state, _scan_code, virtual_key_code) => {
|
Event::KeyboardInput(element_state, _scan_code, virtual_key_code) => {
|
||||||
|
@ -476,10 +157,10 @@ impl Window {
|
||||||
(_, VirtualKeyCode::RAlt) => self.toggle_modifier(RIGHT_ALT),
|
(_, VirtualKeyCode::RAlt) => self.toggle_modifier(RIGHT_ALT),
|
||||||
(ElementState::Pressed, VirtualKeyCode::Escape) => return true,
|
(ElementState::Pressed, VirtualKeyCode::Escape) => return true,
|
||||||
(ElementState::Pressed, key_code) => {
|
(ElementState::Pressed, key_code) => {
|
||||||
match glutin_key_to_script_key(key_code) {
|
match Window::glutin_key_to_script_key(key_code) {
|
||||||
Ok(key) => {
|
Ok(key) => {
|
||||||
let state = KeyState::Pressed;
|
let state = KeyState::Pressed;
|
||||||
let modifiers = glutin_mods_to_script_mods(self.key_modifiers.get());
|
let modifiers = Window::glutin_mods_to_script_mods(self.key_modifiers.get());
|
||||||
self.event_queue.borrow_mut().push(WindowEvent::KeyEvent(key, state, modifiers));
|
self.event_queue.borrow_mut().push(WindowEvent::KeyEvent(key, state, modifiers));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -574,14 +255,34 @@ impl Window {
|
||||||
self.event_queue.borrow_mut().push(WindowEvent::MouseWindowEventClass(event));
|
self.event_queue.borrow_mut().push(WindowEvent::MouseWindowEventClass(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn set_nested_event_loop_listener(
|
fn update_window_title(&self) {
|
||||||
&self,
|
let now = time::get_time();
|
||||||
listener: *mut (NestedEventLoopListener + 'static)) {
|
if now.sec == self.last_title_set_time.get().sec {
|
||||||
g_nested_event_loop_listener = Some(listener)
|
return
|
||||||
}
|
}
|
||||||
|
self.last_title_set_time.set(now);
|
||||||
|
|
||||||
pub unsafe fn remove_nested_event_loop_listener(&self) {
|
match self.ready_state.get() {
|
||||||
g_nested_event_loop_listener = None
|
ReadyState::Blank => {
|
||||||
|
self.window.set_title("blank - Servo [glutin]")
|
||||||
|
}
|
||||||
|
ReadyState::Loading => {
|
||||||
|
self.window.set_title("Loading - Servo [glutin]")
|
||||||
|
}
|
||||||
|
ReadyState::PerformingLayout => {
|
||||||
|
self.window.set_title("Performing Layout - Servo [glutin]")
|
||||||
|
}
|
||||||
|
ReadyState::FinishedLoading => {
|
||||||
|
match self.paint_state.get() {
|
||||||
|
PaintState::Painting => {
|
||||||
|
self.window.set_title("Rendering - Servo [glutin]")
|
||||||
|
}
|
||||||
|
PaintState::Idle => {
|
||||||
|
self.window.set_title("Servo [glutin]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wait_events(&self) -> WindowEvent {
|
pub fn wait_events(&self) -> WindowEvent {
|
||||||
|
@ -592,39 +293,364 @@ impl Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.glutin {
|
let mut close_event = false;
|
||||||
WindowHandle::Windowed(ref window) => {
|
|
||||||
let mut close_event = false;
|
|
||||||
|
|
||||||
// When writing to a file then exiting, use event
|
// When writing to a file then exiting, use event
|
||||||
// polling so that we don't block on a GUI event
|
// polling so that we don't block on a GUI event
|
||||||
// such as mouse click.
|
// such as mouse click.
|
||||||
if opts::get().output_file.is_some() {
|
if opts::get().output_file.is_some() {
|
||||||
for event in window.poll_events() {
|
for event in self.window.poll_events() {
|
||||||
close_event = self.handle_window_event(event);
|
close_event = self.handle_window_event(event);
|
||||||
if close_event {
|
if close_event {
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for event in window.wait_events() {
|
|
||||||
close_event = self.handle_window_event(event);
|
|
||||||
if close_event {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if close_event || window.is_closed() {
|
|
||||||
WindowEvent::Quit
|
|
||||||
} else {
|
|
||||||
self.event_queue.borrow_mut().remove(0).unwrap_or(WindowEvent::Idle)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WindowHandle::Headless(_) => {
|
} else {
|
||||||
self.event_queue.borrow_mut().remove(0).unwrap_or(WindowEvent::Idle)
|
for event in self.window.wait_events() {
|
||||||
|
close_event = self.handle_window_event(event);
|
||||||
|
if close_event {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if close_event || self.window.is_closed() {
|
||||||
|
WindowEvent::Quit
|
||||||
|
} else {
|
||||||
|
self.event_queue.borrow_mut().remove(0).unwrap_or(WindowEvent::Idle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn set_nested_event_loop_listener(
|
||||||
|
&self,
|
||||||
|
listener: *mut (NestedEventLoopListener + 'static)) {
|
||||||
|
g_nested_event_loop_listener = Some(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn remove_nested_event_loop_listener(&self) {
|
||||||
|
g_nested_event_loop_listener = None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn glutin_key_to_script_key(key: glutin::VirtualKeyCode) -> Result<constellation_msg::Key, ()> {
|
||||||
|
// TODO(negge): add more key mappings
|
||||||
|
match key {
|
||||||
|
VirtualKeyCode::A => Ok(Key::A),
|
||||||
|
VirtualKeyCode::B => Ok(Key::B),
|
||||||
|
VirtualKeyCode::C => Ok(Key::C),
|
||||||
|
VirtualKeyCode::D => Ok(Key::D),
|
||||||
|
VirtualKeyCode::E => Ok(Key::E),
|
||||||
|
VirtualKeyCode::F => Ok(Key::F),
|
||||||
|
VirtualKeyCode::G => Ok(Key::G),
|
||||||
|
VirtualKeyCode::H => Ok(Key::H),
|
||||||
|
VirtualKeyCode::I => Ok(Key::I),
|
||||||
|
VirtualKeyCode::J => Ok(Key::J),
|
||||||
|
VirtualKeyCode::K => Ok(Key::K),
|
||||||
|
VirtualKeyCode::L => Ok(Key::L),
|
||||||
|
VirtualKeyCode::M => Ok(Key::M),
|
||||||
|
VirtualKeyCode::N => Ok(Key::N),
|
||||||
|
VirtualKeyCode::O => Ok(Key::O),
|
||||||
|
VirtualKeyCode::P => Ok(Key::P),
|
||||||
|
VirtualKeyCode::Q => Ok(Key::Q),
|
||||||
|
VirtualKeyCode::R => Ok(Key::R),
|
||||||
|
VirtualKeyCode::S => Ok(Key::S),
|
||||||
|
VirtualKeyCode::T => Ok(Key::T),
|
||||||
|
VirtualKeyCode::U => Ok(Key::U),
|
||||||
|
VirtualKeyCode::V => Ok(Key::V),
|
||||||
|
VirtualKeyCode::W => Ok(Key::W),
|
||||||
|
VirtualKeyCode::X => Ok(Key::X),
|
||||||
|
VirtualKeyCode::Y => Ok(Key::Y),
|
||||||
|
VirtualKeyCode::Z => Ok(Key::Z),
|
||||||
|
|
||||||
|
VirtualKeyCode::Numpad0 => Ok(Key::Num0),
|
||||||
|
VirtualKeyCode::Numpad1 => Ok(Key::Num1),
|
||||||
|
VirtualKeyCode::Numpad2 => Ok(Key::Num2),
|
||||||
|
VirtualKeyCode::Numpad3 => Ok(Key::Num3),
|
||||||
|
VirtualKeyCode::Numpad4 => Ok(Key::Num4),
|
||||||
|
VirtualKeyCode::Numpad5 => Ok(Key::Num5),
|
||||||
|
VirtualKeyCode::Numpad6 => Ok(Key::Num6),
|
||||||
|
VirtualKeyCode::Numpad7 => Ok(Key::Num7),
|
||||||
|
VirtualKeyCode::Numpad8 => Ok(Key::Num8),
|
||||||
|
VirtualKeyCode::Numpad9 => Ok(Key::Num9),
|
||||||
|
|
||||||
|
VirtualKeyCode::Key0 => Ok(Key::Kp0),
|
||||||
|
VirtualKeyCode::Key1 => Ok(Key::Kp1),
|
||||||
|
VirtualKeyCode::Key2 => Ok(Key::Kp2),
|
||||||
|
VirtualKeyCode::Key3 => Ok(Key::Kp3),
|
||||||
|
VirtualKeyCode::Key4 => Ok(Key::Kp4),
|
||||||
|
VirtualKeyCode::Key5 => Ok(Key::Kp5),
|
||||||
|
VirtualKeyCode::Key6 => Ok(Key::Kp6),
|
||||||
|
VirtualKeyCode::Key7 => Ok(Key::Kp7),
|
||||||
|
VirtualKeyCode::Key8 => Ok(Key::Kp8),
|
||||||
|
VirtualKeyCode::Key9 => Ok(Key::Kp9),
|
||||||
|
|
||||||
|
VirtualKeyCode::Return => Ok(Key::Enter),
|
||||||
|
VirtualKeyCode::Space => Ok(Key::Space),
|
||||||
|
VirtualKeyCode::Escape => Ok(Key::Escape),
|
||||||
|
VirtualKeyCode::Equals => Ok(Key::Equal),
|
||||||
|
VirtualKeyCode::Minus => Ok(Key::Minus),
|
||||||
|
VirtualKeyCode::Back => Ok(Key::Backspace),
|
||||||
|
VirtualKeyCode::PageDown => Ok(Key::PageDown),
|
||||||
|
VirtualKeyCode::PageUp => Ok(Key::PageUp),
|
||||||
|
|
||||||
|
VirtualKeyCode::Insert => Ok(Key::Insert),
|
||||||
|
VirtualKeyCode::Home => Ok(Key::Home),
|
||||||
|
VirtualKeyCode::Delete => Ok(Key::Delete),
|
||||||
|
VirtualKeyCode::End => Ok(Key::End),
|
||||||
|
|
||||||
|
VirtualKeyCode::Left => Ok(Key::Left),
|
||||||
|
VirtualKeyCode::Up => Ok(Key::Up),
|
||||||
|
VirtualKeyCode::Right => Ok(Key::Right),
|
||||||
|
VirtualKeyCode::Down => Ok(Key::Down),
|
||||||
|
|
||||||
|
VirtualKeyCode::Apostrophe => Ok(Key::Apostrophe),
|
||||||
|
VirtualKeyCode::Backslash => Ok(Key::Backslash),
|
||||||
|
VirtualKeyCode::Comma => Ok(Key::Comma),
|
||||||
|
VirtualKeyCode::Grave => Ok(Key::GraveAccent),
|
||||||
|
VirtualKeyCode::LBracket => Ok(Key::LeftBracket),
|
||||||
|
VirtualKeyCode::Period => Ok(Key::Period),
|
||||||
|
VirtualKeyCode::RBracket => Ok(Key::RightBracket),
|
||||||
|
VirtualKeyCode::Semicolon => Ok(Key::Semicolon),
|
||||||
|
VirtualKeyCode::Slash => Ok(Key::Slash),
|
||||||
|
VirtualKeyCode::Tab => Ok(Key::Tab),
|
||||||
|
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn glutin_mods_to_script_mods(modifiers: KeyModifiers) -> constellation_msg::KeyModifiers {
|
||||||
|
let mut result = constellation_msg::KeyModifiers::from_bits(0).unwrap();
|
||||||
|
if modifiers.intersects(LEFT_SHIFT | RIGHT_SHIFT) {
|
||||||
|
result.insert(SHIFT);
|
||||||
|
}
|
||||||
|
if modifiers.intersects(LEFT_CONTROL | RIGHT_CONTROL) {
|
||||||
|
result.insert(CONTROL);
|
||||||
|
}
|
||||||
|
if modifiers.intersects(LEFT_ALT | RIGHT_ALT) {
|
||||||
|
result.insert(ALT);
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "window")]
|
||||||
|
impl WindowMethods for Window {
|
||||||
|
fn framebuffer_size(&self) -> TypedSize2D<DevicePixel, uint> {
|
||||||
|
let scale_factor = self.window.hidpi_factor() as uint;
|
||||||
|
let (width, height) = self.window.get_inner_size().unwrap();
|
||||||
|
TypedSize2D(width * scale_factor, height * scale_factor)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size(&self) -> TypedSize2D<ScreenPx, f32> {
|
||||||
|
let (width, height) = self.window.get_inner_size().unwrap();
|
||||||
|
TypedSize2D(width as f32, height as f32)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn present(&self) {
|
||||||
|
self.window.swap_buffers()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_compositor_channel(window: &Option<Rc<Window>>)
|
||||||
|
-> (Box<CompositorProxy+Send>, Box<CompositorReceiver>) {
|
||||||
|
let (sender, receiver) = channel();
|
||||||
|
|
||||||
|
let window_proxy = match window {
|
||||||
|
&Some(ref window) => Some(window.window.create_window_proxy()),
|
||||||
|
&None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
(box GlutinCompositorProxy {
|
||||||
|
sender: sender,
|
||||||
|
window_proxy: window_proxy,
|
||||||
|
} as Box<CompositorProxy+Send>,
|
||||||
|
box receiver as Box<CompositorReceiver>)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the ready state.
|
||||||
|
fn set_ready_state(&self, ready_state: ReadyState) {
|
||||||
|
self.ready_state.set(ready_state);
|
||||||
|
self.update_window_title()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the paint state.
|
||||||
|
fn set_paint_state(&self, paint_state: PaintState) {
|
||||||
|
self.paint_state.set(paint_state);
|
||||||
|
self.update_window_title()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hidpi_factor(&self) -> ScaleFactor<ScreenPx, DevicePixel, f32> {
|
||||||
|
ScaleFactor(self.window.hidpi_factor())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_page_title(&self, _: Option<String>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_page_load_data(&self, _: LoadData) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_end(&self) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_cursor(&self, _: Cursor) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prepare_for_composite(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os="linux")]
|
||||||
|
fn native_metadata(&self) -> NativeGraphicsMetadata {
|
||||||
|
NativeGraphicsMetadata {
|
||||||
|
display: unsafe { self.window.platform_display() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os="macos")]
|
||||||
|
fn native_metadata(&self) -> NativeGraphicsMetadata {
|
||||||
|
use cgl::{CGLGetCurrentContext, CGLGetPixelFormat};
|
||||||
|
unsafe {
|
||||||
|
NativeGraphicsMetadata {
|
||||||
|
pixel_format: CGLGetPixelFormat(CGLGetCurrentContext()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os="android")]
|
||||||
|
fn native_metadata(&self) -> NativeGraphicsMetadata {
|
||||||
|
use egl::egl::GetCurrentDisplay;
|
||||||
|
NativeGraphicsMetadata {
|
||||||
|
display: GetCurrentDisplay(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper function to handle keyboard events.
|
||||||
|
fn handle_key(&self, key: Key, mods: constellation_msg::KeyModifiers) {
|
||||||
|
match key {
|
||||||
|
Key::Equal if mods.contains(CONTROL) => { // Ctrl-+
|
||||||
|
self.event_queue.borrow_mut().push(WindowEvent::Zoom(1.1));
|
||||||
|
}
|
||||||
|
Key::Minus if mods.contains(CONTROL) => { // Ctrl--
|
||||||
|
self.event_queue.borrow_mut().push(WindowEvent::Zoom(1.0/1.1));
|
||||||
|
}
|
||||||
|
Key::Backspace if mods.contains(SHIFT) => { // Shift-Backspace
|
||||||
|
self.event_queue.borrow_mut().push(WindowEvent::Navigation(WindowNavigateMsg::Forward));
|
||||||
|
}
|
||||||
|
Key::Backspace => { // Backspace
|
||||||
|
self.event_queue.borrow_mut().push(WindowEvent::Navigation(WindowNavigateMsg::Back));
|
||||||
|
}
|
||||||
|
Key::PageDown => {
|
||||||
|
self.scroll_window(0.0, -self.framebuffer_size().as_f32().to_untyped().height);
|
||||||
|
}
|
||||||
|
Key::PageUp => {
|
||||||
|
self.scroll_window(0.0, self.framebuffer_size().as_f32().to_untyped().height);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The type of a window.
|
||||||
|
#[cfg(feature = "headless")]
|
||||||
|
pub struct Window {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
context: glutin::HeadlessContext,
|
||||||
|
width: uint,
|
||||||
|
height: uint,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "headless")]
|
||||||
|
impl Window {
|
||||||
|
pub fn new(_is_foreground: bool, window_size: TypedSize2D<DevicePixel, uint>) -> Rc<Window> {
|
||||||
|
let window_size = window_size.to_untyped();
|
||||||
|
let headless_builder = glutin::HeadlessRendererBuilder::new(window_size.width,
|
||||||
|
window_size.height);
|
||||||
|
let headless_context = headless_builder.build().unwrap();
|
||||||
|
unsafe { headless_context.make_current() };
|
||||||
|
|
||||||
|
gl::load_with(|s| headless_context.get_proc_address(s));
|
||||||
|
|
||||||
|
let window = Window {
|
||||||
|
context: headless_context,
|
||||||
|
width: window_size.width,
|
||||||
|
height: window_size.height,
|
||||||
|
};
|
||||||
|
|
||||||
|
Rc::new(window)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wait_events(&self) -> WindowEvent {
|
||||||
|
WindowEvent::Idle
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn set_nested_event_loop_listener(
|
||||||
|
&self,
|
||||||
|
_listener: *mut (NestedEventLoopListener + 'static)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn remove_nested_event_loop_listener(&self) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "headless")]
|
||||||
|
impl WindowMethods for Window {
|
||||||
|
fn framebuffer_size(&self) -> TypedSize2D<DevicePixel, uint> {
|
||||||
|
TypedSize2D(self.width, self.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size(&self) -> TypedSize2D<ScreenPx, f32> {
|
||||||
|
TypedSize2D(self.width as f32, self.height as f32)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn present(&self) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_compositor_channel(_: &Option<Rc<Window>>)
|
||||||
|
-> (Box<CompositorProxy+Send>, Box<CompositorReceiver>) {
|
||||||
|
let (sender, receiver) = channel();
|
||||||
|
|
||||||
|
(box GlutinCompositorProxy {
|
||||||
|
sender: sender,
|
||||||
|
window_proxy: None,
|
||||||
|
} as Box<CompositorProxy+Send>,
|
||||||
|
box receiver as Box<CompositorReceiver>)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the ready state.
|
||||||
|
fn set_ready_state(&self, _: ReadyState) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the paint state.
|
||||||
|
fn set_paint_state(&self, _: PaintState) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hidpi_factor(&self) -> ScaleFactor<ScreenPx, DevicePixel, f32> {
|
||||||
|
ScaleFactor(1.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_page_title(&self, _: Option<String>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_page_load_data(&self, _: LoadData) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_end(&self) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_cursor(&self, _: Cursor) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prepare_for_composite(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os="linux")]
|
||||||
|
fn native_metadata(&self) -> NativeGraphicsMetadata {
|
||||||
|
NativeGraphicsMetadata {
|
||||||
|
display: ptr::null_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper function to handle keyboard events.
|
||||||
|
fn handle_key(&self, _: Key, _: constellation_msg::KeyModifiers) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from __future__ import print_function, unicode_literals
|
from __future__ import print_function, unicode_literals
|
||||||
|
|
||||||
|
import os
|
||||||
import os.path as path
|
import os.path as path
|
||||||
import subprocess
|
import subprocess
|
||||||
from time import time
|
from time import time
|
||||||
|
@ -12,6 +13,8 @@ from mach.decorators import (
|
||||||
|
|
||||||
from servo.command_base import CommandBase, cd
|
from servo.command_base import CommandBase, cd
|
||||||
|
|
||||||
|
def is_headless_build():
|
||||||
|
return int(os.getenv('SERVO_HEADLESS', 0)) == 1
|
||||||
|
|
||||||
@CommandProvider
|
@CommandProvider
|
||||||
class MachCommands(CommandBase):
|
class MachCommands(CommandBase):
|
||||||
|
@ -69,6 +72,10 @@ class MachCommands(CommandBase):
|
||||||
if debug_mozjs or self.config["build"]["debug-mozjs"]:
|
if debug_mozjs or self.config["build"]["debug-mozjs"]:
|
||||||
features += ["script/debugmozjs"]
|
features += ["script/debugmozjs"]
|
||||||
|
|
||||||
|
if is_headless_build():
|
||||||
|
opts += ["--no-default-features"]
|
||||||
|
features += ["glutin_app", "headless"]
|
||||||
|
|
||||||
if features:
|
if features:
|
||||||
opts += ["--features", "%s" % ' '.join(features)]
|
opts += ["--features", "%s" % ' '.join(features)]
|
||||||
|
|
||||||
|
@ -132,11 +139,11 @@ class MachCommands(CommandBase):
|
||||||
help='Number of jobs to run in parallel')
|
help='Number of jobs to run in parallel')
|
||||||
def build_tests(self, jobs=None):
|
def build_tests(self, jobs=None):
|
||||||
self.ensure_bootstrapped()
|
self.ensure_bootstrapped()
|
||||||
opts = []
|
args = ["cargo", "test", "--no-run"]
|
||||||
if jobs is not None:
|
if is_headless_build():
|
||||||
opts += ["-j", jobs]
|
args += ["--no-default-features", "--features", "glutin_app headless"]
|
||||||
return subprocess.call(
|
return subprocess.call(
|
||||||
["cargo", "test", "--no-run"],
|
args,
|
||||||
env=self.build_env(), cwd=self.servo_crate())
|
env=self.build_env(), cwd=self.servo_crate())
|
||||||
|
|
||||||
@Command('clean',
|
@Command('clean',
|
||||||
|
|
|
@ -276,9 +276,6 @@ fn capture(reftest: &Reftest, side: uint) -> (u32, u32, Vec<u8>) {
|
||||||
if reftest.experimental {
|
if reftest.experimental {
|
||||||
command.arg("--experimental");
|
command.arg("--experimental");
|
||||||
}
|
}
|
||||||
if cfg!(target_os = "linux") {
|
|
||||||
command.args(["-r", "mesa"].as_slice());
|
|
||||||
}
|
|
||||||
let retval = match command.status() {
|
let retval = match command.status() {
|
||||||
Ok(status) => status,
|
Ok(status) => status,
|
||||||
Err(e) => panic!("failed to execute process: {}", e),
|
Err(e) => panic!("failed to execute process: {}", e),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue