├── .gitignore ├── glium_text ├── .gitignore ├── examples │ ├── font.ttf │ ├── hello_world.rs │ └── user_text.rs ├── README.md ├── Cargo.toml ├── .travis.yml └── src │ └── lib.rs ├── screenshot.png ├── Hack-Regular.ttf ├── Cargo.toml ├── README.md ├── LICENSE.md ├── src ├── main.rs ├── file_dialog.rs ├── text.rs ├── renderer.rs ├── core.rs └── controller.rs └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /glium_text/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/potocpav/xi_glium/HEAD/screenshot.png -------------------------------------------------------------------------------- /Hack-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/potocpav/xi_glium/HEAD/Hack-Regular.ttf -------------------------------------------------------------------------------- /glium_text/examples/font.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/potocpav/xi_glium/HEAD/glium_text/examples/font.ttf -------------------------------------------------------------------------------- /glium_text/README.md: -------------------------------------------------------------------------------- 1 | # Easy text drawing with glium 2 | 3 | [Documentation](http://tomaka.github.io/glium_text/glium_text/index.html) 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "xi_glium" 3 | version = "0.0.0" 4 | authors = ["Pavel Potocek "] 5 | license = "MIT" 6 | 7 | [dependencies] 8 | clipboard = "0.1.2" 9 | glib = "0.1.0" 10 | glium = "0.15.0" 11 | gtk = "0.1.0" 12 | serde_json = "0.8.1" 13 | 14 | [dependencies.glium_text] 15 | path = "glium_text" 16 | -------------------------------------------------------------------------------- /glium_text/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "glium_text" 3 | version = "0.10.0" 4 | authors = ["Pierre Krieger "] 5 | description = "Text drawing with glium and freetype" 6 | keywords = ["text", "opengl"] 7 | license = "MIT" 8 | 9 | [dependencies] 10 | freetype-sys = "0.4" 11 | libc = "0.2" 12 | 13 | [dependencies.glium] 14 | version = "0.15" 15 | default-features = false 16 | 17 | [dev-dependencies] 18 | cgmath = "0.10" 19 | 20 | [dev-dependencies.glium] 21 | version = "0.15" 22 | features = ["glutin"] 23 | -------------------------------------------------------------------------------- /glium_text/.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | 3 | rust: 4 | - stable 5 | - nightly 6 | 7 | addons: 8 | apt: 9 | packages: 10 | - libxxf86vm-dev 11 | - libosmesa6-dev 12 | 13 | after_success: 14 | - | 15 | [ $TRAVIS_BRANCH = master ] && 16 | [ $TRAVIS_PULL_REQUEST = false ] && 17 | cargo doc && 18 | sudo pip install ghp-import && 19 | ghp-import target/doc && 20 | git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages 21 | - | 22 | [ $TRAVIS_BRANCH = master ] && 23 | [ $TRAVIS_PULL_REQUEST = false ] && 24 | cargo publish --token ${CRATESIO_TOKEN} 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # xi glium 2 | 3 | **Xi glium** is a `glium` and `glium_text`-based interface on top of the 4 | [**xi editor**](https://github.com/google/xi-editor) project back-end. 5 | 6 | Screenshot: 7 | 8 | ![xi glium](/screenshot.png?raw=true) 9 | 10 | ## Features 11 | 12 | * Write and backspace text, 13 | * navigate using mouse, arrows, page-up and page-down, 14 | * select text using keyboard and mouse, 15 | * cut, copy, paste and delete selection, 16 | * load (`ctrl-o`), save (`ctrl-s`) and save-as (`ctrl-shift-s`) using GTK dialogs, 17 | * F1 to line-wrap 18 | 19 | You must specify a path to the `xi-core` executable (build by cargo inside 20 | the `rust` subdirectory of xi-editor). Works with the xi-editor commit `2e88632`, 21 | but the HEAD is a good bet. 22 | 23 | ## Dependencies 24 | 25 | On Linux you might need to install the package `xmu` first. 26 | 27 | ``` 28 | sudo apt-get install libxmu-dev libxi-dev 29 | ``` 30 | 31 | ## Example usage 32 | 33 | `xicore=../xi-editor/rust/target/debug/xi-core cargo run README.md` 34 | 35 | 36 | ## License 37 | 38 | [MIT License](LICENSE.md) 39 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2016 Pavel Potocek 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | 2 | mod core; 3 | mod renderer; 4 | mod controller; 5 | mod text; 6 | mod file_dialog; 7 | 8 | #[macro_use] 9 | extern crate glium; 10 | extern crate glium_text; 11 | extern crate serde_json; 12 | extern crate gtk; 13 | extern crate glib; // Needed by gtk to supply a threaded fn idle_add 14 | extern crate clipboard; 15 | 16 | fn main() { 17 | let filename = std::env::args().nth(1); 18 | let core_path = std::env::var("xicore").unwrap_or("../xi-editor/rust/target/debug/xi-core".into()); 19 | 20 | // I read that GTK on Mac needs to be in the main thread. We must let it have it. 21 | ::std::thread::spawn(move || { 22 | use glium::DisplayBuild; 23 | let display = glium::glutin::WindowBuilder::new() 24 | .with_dimensions(760, 380) 25 | .with_title(String::from("xi_glium")) 26 | .build_glium() 27 | .unwrap(); 28 | display.get_window().unwrap().set_cursor(glium::glutin::MouseCursor::Text); 29 | 30 | controller::run(&core_path, filename, display); 31 | 32 | glib::idle_add(|| { gtk::main_quit(); glib::Continue(false) }); 33 | }); 34 | 35 | gtk::init().expect("Failed to initialize GTK."); 36 | gtk::main(); 37 | } 38 | -------------------------------------------------------------------------------- /glium_text/examples/hello_world.rs: -------------------------------------------------------------------------------- 1 | extern crate glium; 2 | extern crate glium_text; 3 | extern crate cgmath; 4 | 5 | use std::thread; 6 | use std::time::Duration; 7 | use glium::Surface; 8 | use glium::glutin; 9 | 10 | fn main() { 11 | use glium::DisplayBuild; 12 | 13 | let display = glutin::WindowBuilder::new().with_dimensions(1024, 768).build_glium().unwrap(); 14 | let system = glium_text::TextSystem::new(&display); 15 | 16 | let font = glium_text::FontTexture::new(&display, &include_bytes!("font.ttf")[..], 70).unwrap(); 17 | 18 | let text = glium_text::TextDisplay::new(&system, &font, "Hello world!"); 19 | let text_width = text.get_width(); 20 | println!("Text width: {:?}", text_width); 21 | 22 | let sleep_duration = Duration::from_millis(17); 23 | 24 | 'main: loop { 25 | let (w, h) = display.get_framebuffer_dimensions(); 26 | 27 | let matrix:[[f32; 4]; 4] = cgmath::Matrix4::new( 28 | 2.0 / text_width, 0.0, 0.0, 0.0, 29 | 0.0, 2.0 * (w as f32) / (h as f32) / text_width, 0.0, 0.0, 30 | 0.0, 0.0, 1.0, 0.0, 31 | -1.0, -1.0, 0.0, 1.0f32, 32 | ).into(); 33 | 34 | let mut target = display.draw(); 35 | target.clear_color(0.0, 0.0, 0.0, 1.0); 36 | glium_text::draw(&text, &system, &mut target, matrix, (1.0, 1.0, 0.0, 1.0)); 37 | target.finish().unwrap(); 38 | 39 | thread::sleep(sleep_duration); 40 | 41 | for event in display.poll_events() { 42 | match event { 43 | glutin::Event::Closed => break 'main, 44 | _ => () 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/file_dialog.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::sync::mpsc; 3 | use std::path; 4 | use gtk; 5 | use gtk::prelude::*; 6 | use glib; 7 | 8 | 9 | pub fn open() -> mpsc::Receiver> { 10 | spawn(Action::Open) 11 | } 12 | 13 | pub fn save() -> mpsc::Receiver> { 14 | spawn(Action::Save) 15 | } 16 | 17 | enum Action { 18 | Open, 19 | Save, 20 | } 21 | 22 | fn spawn(action: Action) -> mpsc::Receiver> { 23 | let (sx, rx) = mpsc::sync_channel(0); 24 | glib::idle_add(move || { 25 | let file_chooser = match action { 26 | Action::Open => { 27 | let fc = gtk::FileChooserDialog::new( 28 | Some("Open File"), None::<>k::Window>, gtk::FileChooserAction::Open); 29 | fc.add_buttons(&[ 30 | ("Open", gtk::ResponseType::Ok.into()), 31 | ("Cancel", gtk::ResponseType::Cancel.into()), 32 | ]); 33 | fc 34 | }, Action::Save => { 35 | let fc = gtk::FileChooserDialog::new( 36 | Some("Save File"), None::<>k::Window>, gtk::FileChooserAction::Save); 37 | fc.add_buttons(&[ 38 | ("Save", gtk::ResponseType::Ok.into()), 39 | ("Cancel", gtk::ResponseType::Cancel.into()), 40 | ]); 41 | fc 42 | } 43 | }; 44 | 45 | if file_chooser.run() == gtk::ResponseType::Ok.into() { 46 | let filename = file_chooser.get_filename().unwrap(); 47 | sx.send(Some(filename)).unwrap(); 48 | } else { 49 | sx.send(None).unwrap(); 50 | } 51 | file_chooser.destroy(); 52 | 53 | glib::Continue(false) 54 | }); 55 | rx 56 | } 57 | -------------------------------------------------------------------------------- /glium_text/examples/user_text.rs: -------------------------------------------------------------------------------- 1 | extern crate glium; 2 | extern crate glium_text; 3 | extern crate cgmath; 4 | 5 | use std::path::Path; 6 | use std::thread; 7 | use std::time::Duration; 8 | use glium::Surface; 9 | use glium::glutin; 10 | 11 | fn main() { 12 | use glium::DisplayBuild; 13 | use std::fs::File; 14 | 15 | let display = glutin::WindowBuilder::new().with_dimensions(1024, 768).build_glium().unwrap(); 16 | let system = glium_text::TextSystem::new(&display); 17 | 18 | let font = match std::env::args().nth(1) { 19 | Some(file) => glium_text::FontTexture::new(&display, File::open(&Path::new(&file)).unwrap(), 70), 20 | None => { 21 | match File::open(&Path::new("C:\\Windows\\Fonts\\Arial.ttf")) { 22 | Ok(f) => glium_text::FontTexture::new(&display, f, 70), 23 | Err(_) => glium_text::FontTexture::new(&display, &include_bytes!("font.ttf")[..], 70), 24 | } 25 | } 26 | }.unwrap(); 27 | 28 | let mut buffer = String::new(); 29 | 30 | let sleep_duration = Duration::from_millis(17); 31 | 32 | println!("Type with your keyboard"); 33 | 34 | 'main: loop { 35 | let text = glium_text::TextDisplay::new(&system, &font, &buffer); 36 | 37 | let (w, h) = display.get_framebuffer_dimensions(); 38 | 39 | let matrix:[[f32; 4]; 4] = cgmath::Matrix4::new( 40 | 0.1, 0.0, 0.0, 0.0, 41 | 0.0, 0.1 * (w as f32) / (h as f32), 0.0, 0.0, 42 | 0.0, 0.0, 1.0, 0.0, 43 | -0.9, 0.0, 0.0, 1.0f32, 44 | ).into(); 45 | 46 | let mut target = display.draw(); 47 | target.clear_color(0.0, 0.0, 0.0, 1.0); 48 | glium_text::draw(&text, &system, &mut target, matrix, (1.0, 1.0, 0.0, 1.0)); 49 | target.finish().unwrap(); 50 | 51 | thread::sleep(sleep_duration); 52 | 53 | for event in display.poll_events() { 54 | match event { 55 | glutin::Event::ReceivedCharacter('\r') => buffer.clear(), 56 | glutin::Event::ReceivedCharacter(c) if c as u32 == 8 => { buffer.pop(); }, 57 | glutin::Event::ReceivedCharacter(chr) => buffer.push(chr), 58 | glutin::Event::Closed => break 'main, 59 | _ => () 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/text.rs: -------------------------------------------------------------------------------- 1 | use std::collections::BTreeMap; 2 | use serde_json::Value; 3 | 4 | use renderer::*; 5 | 6 | const LINE_HEIGHT: f32 = 20.; 7 | const LEFT_MARGIN: f32 = 15.; 8 | 9 | // #[derive(Clone)] 10 | pub struct Line<'a> { 11 | pub text: String, 12 | pub cursor: Option, 13 | selection: Option<(u64,u64)>, 14 | pub renderer: LineRenderer<'a>, // This is the lifetime that infects the hierarchy up to State 15 | } 16 | 17 | impl<'a> Line<'a> { 18 | 19 | pub fn placeholder(renderer: &'a Renderer) -> Line<'a> { 20 | let text = ">>> NOT IN CACHE <<<"; 21 | let renderer = LineRenderer::new(renderer, text); 22 | Line { text: text.into(), cursor: None, selection: None, renderer: renderer } 23 | } 24 | } 25 | 26 | pub struct Text<'a> { 27 | cache: BTreeMap>, 28 | placeholder_line: Line<'a>, 29 | pub top: f64, 30 | pub height: f64, 31 | n_lines: u64, 32 | renderer: TextRenderer, 33 | // scrollbar: Primitive, 34 | } 35 | 36 | impl<'a> Text<'a> { 37 | pub fn new(renderer: &Renderer) -> Text { 38 | Text { 39 | cache: BTreeMap::new(), 40 | placeholder_line: Line::placeholder(renderer), 41 | top: 0., 42 | height: 0., 43 | n_lines: 0, 44 | renderer: TextRenderer::new(renderer, LEFT_MARGIN) 45 | } 46 | } 47 | 48 | pub fn refresh(&mut self, n_lines: u64) { 49 | self.cache.clear(); 50 | self.n_lines = n_lines; 51 | } 52 | 53 | pub fn render(&self, target: &mut Target) { 54 | self.renderer.draw(target, &self.get_lines(), self.top, self.height, self.n_lines); 55 | } 56 | 57 | pub fn add_lines(&mut self, renderer: &'a Renderer, value: &Value, first: u64) { 58 | for (i, line) in value.as_array().unwrap().into_iter().enumerate() { 59 | let line = line.as_array().unwrap(); 60 | let text = line[0].as_str().unwrap().to_string(); 61 | // annotations 62 | let mut cursor = None; 63 | let mut selection = None; 64 | for annotation in line.iter().skip(1).map(|a| a.as_array().unwrap()) { 65 | match annotation[0].as_str().unwrap() { 66 | "cursor" => { 67 | cursor = Some(annotation[1].as_u64().unwrap()); 68 | }, 69 | "sel" => { 70 | selection = Some((annotation[1].as_u64().unwrap(), annotation[2].as_u64().unwrap())); 71 | }, _ => () // ignore unknown annotations 72 | } 73 | } 74 | let renderer = LineRenderer::new(renderer, &text); 75 | self.cache.insert(i as u64+first, Line { text: text, cursor: cursor, selection: selection, renderer: renderer }); 76 | } 77 | } 78 | 79 | pub fn scroll_to(&mut self, line: u64, _column: u64) { 80 | let min = |a,b| if a > b { b } else { a }; 81 | let max = |a,b| if a < b { b } else { a }; 82 | self.top = max(0., min(self.top, line as f64 - 2.)); // scroll up 83 | self.top = min(self.n_lines as f64, max(self.top, line as f64 - self.height + 1. + 2.)); // scroll dn 84 | } 85 | 86 | pub fn scroll(&mut self, delta_y: f64) { 87 | let mut y = self.top + delta_y; 88 | let max = self.n_lines as f64 - self.height; 89 | if y > max { y = max } 90 | if y < 0. { y = 0. } 91 | self.top = y; 92 | } 93 | 94 | pub fn get_lines(&self) -> Vec<(f32, &Line)> { 95 | self.get_line_pos().into_iter().filter_map(|(pos,i)| self.get_line(i).map(|x| (pos,x))).collect() 96 | } 97 | 98 | // Return: Vec<(line_pos, line_id)> 99 | pub fn get_line_pos(&self) -> Vec<(f32, u64)> { 100 | (self.top as u64 .. (self.top + self.height).ceil() as u64) 101 | .map(|i| ((self.height - i as f64 + self.top - 0.5) as f32 * LINE_HEIGHT, i) 102 | ).collect() 103 | } 104 | 105 | pub fn get_line_col(&self, px: i32, py: i32) -> (u64,u64) { 106 | let line = self.get_line_pos().into_iter().min_by_key(|&(y,_)| (y as i32 - py).abs()).unwrap().1; 107 | let column = if let Some(line) = self.get_line(line) { 108 | line.renderer.char_pos_x.iter().enumerate().min_by_key(|&(_,x)| { 109 | (*x as i32 - px + LEFT_MARGIN as i32).abs() 110 | }).unwrap().0 as u64 111 | } else { // after the text 112 | 0 113 | }; 114 | (line, column) 115 | } 116 | 117 | fn get_line(&self, n: u64) -> Option<&Line> { 118 | if n >= self.n_lines { 119 | None 120 | } else { 121 | Some(self.cache.get(&n).unwrap_or(&self.placeholder_line)) 122 | } 123 | } 124 | 125 | pub fn set_size(&mut self, _w: u32, h: u32) { 126 | self.height = h as f64 / LINE_HEIGHT as f64; 127 | } 128 | } 129 | 130 | pub struct TextRenderer { 131 | cursor: Primitive, 132 | line_bg: Primitive, 133 | left_margin: f32, 134 | } 135 | 136 | impl TextRenderer { 137 | pub fn new(renderer: &Renderer, left_margin: f32) -> TextRenderer { 138 | let cursor = Primitive::new_line(&renderer, (0.,-10.), (0.,10.), [0.,0.,0.,1.]); 139 | let line_bg = Primitive::new_rect(&renderer, (0., -10.), (2000., 10.), [1.,1.,0.7,1.]); 140 | 141 | TextRenderer { cursor: cursor, line_bg: line_bg, left_margin: left_margin } 142 | } 143 | 144 | pub fn draw_line(&self, target: &mut Target, line: &Line, (px, py): (f32, f32)) { 145 | let offset = |pos| { 146 | let ch_pos_x = &line.renderer.char_pos_x; 147 | ch_pos_x[::std::cmp::min(pos as usize, ch_pos_x.len() - 1)] 148 | }; 149 | 150 | if let Some(pos) = line.cursor { 151 | self.line_bg.draw(target, (px, py)).unwrap(); 152 | self.cursor.draw(target, (offset(pos) + px, py)).unwrap(); 153 | } 154 | 155 | if let Some(sel) = line.selection { 156 | let selection_bg = Primitive::new_rect(&target.renderer, 157 | (offset(sel.0) as f32 + px, -10.), 158 | (offset(sel.1) as f32 + px, 10.), 159 | [0.5,0.5,1.,1.]); 160 | selection_bg.draw(target, (0.,py)).unwrap(); 161 | } 162 | 163 | line.renderer.draw(target, px, py); 164 | } 165 | 166 | pub fn draw(&self, target: &mut Target, lines: &[(f32,&Line)], top: f64, height: f64, n_lines: u64) { 167 | for &(y, line) in lines { 168 | self.draw_line(target, &line, (self.left_margin, y)); 169 | } 170 | 171 | // draw scrollbar 172 | let dims = target.get_dimensions(); 173 | let (w, h) = (dims.0 as f32, dims.1 as f32); 174 | let (rel_y, rel_h) = (top / n_lines as f64, height / n_lines as f64); 175 | let scrollbar = Primitive::new_rect(&target.renderer, 176 | (w - 20., h - rel_y as f32 * h), (w, h - (rel_y + rel_h) as f32 * h), 177 | [0.5,0.5,0.5,1.]); 178 | scrollbar.draw(target, (0.,0.)).unwrap(); 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /src/renderer.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::path::Path; 3 | use std::fs::File; 4 | 5 | use glium; 6 | use glium_text; 7 | use glium::Surface; 8 | use glium::index::PrimitiveType; 9 | 10 | pub struct Target<'a> { 11 | target: glium::Frame, 12 | // TODO: make it somehow not public (is public to enable 13 | // creating new objects from Target). 14 | pub renderer: &'a Renderer, 15 | } 16 | 17 | impl<'a> Target<'a> { 18 | pub fn get_dimensions(&self) -> (u32,u32) { 19 | self.target.get_dimensions() 20 | } 21 | 22 | pub fn finish(self) { 23 | self.target.finish().unwrap(); 24 | } 25 | } 26 | 27 | pub struct Renderer { 28 | display: glium::backend::glutin_backend::GlutinFacade, 29 | program: glium::Program, 30 | text_system: glium_text::TextSystem, 31 | font_texture: glium_text::FontTexture, 32 | } 33 | 34 | impl Renderer { 35 | pub fn new(display: glium::backend::glutin_backend::GlutinFacade) -> Renderer { 36 | let font_size = 15; 37 | 38 | let text_system = glium_text::TextSystem::new(&display); 39 | let font_texture = glium_text::FontTexture::new(&display, File::open(&Path::new("Hack-Regular.ttf")).unwrap(), font_size).unwrap(); 40 | 41 | let program = program!(&display, 42 | 140 => { 43 | vertex: " 44 | #version 140 45 | in vec2 position; 46 | in vec4 color; 47 | out vec4 v_color; 48 | uniform vec2 win_size; 49 | uniform vec2 offset; 50 | void main() { 51 | v_color = color; 52 | gl_Position = vec4((position + offset) / win_size * 2. - 1., 0.0, 1.0); 53 | } 54 | ", 55 | fragment: " 56 | #version 140 57 | in vec4 v_color; 58 | out vec4 color; 59 | void main() { 60 | color = v_color; 61 | } 62 | " 63 | }, 64 | 110 => { 65 | vertex: " 66 | #version 110 67 | 68 | attribute vec2 position; 69 | attribute vec4 color; 70 | varying vec4 v_color; 71 | 72 | uniform vec2 win_size; 73 | uniform vec2 offset; 74 | 75 | void main() { 76 | v_color = color; 77 | gl_Position = vec4((position + offset) / win_size * 2. - 1., 0.0, 1.0); 78 | } 79 | ", 80 | fragment: " 81 | #version 110 82 | 83 | varying vec4 v_color; 84 | 85 | void main() { 86 | gl_FragColor = v_color; 87 | } 88 | " 89 | }).unwrap(); 90 | 91 | Renderer { 92 | display: display, 93 | program: program, 94 | text_system: text_system, 95 | font_texture: font_texture, 96 | } 97 | } 98 | 99 | pub fn draw(&self) -> Target { 100 | let mut target = self.display.draw(); 101 | target.clear_color(1.0, 1.0, 1.0, 0.0); 102 | Target { target: target, renderer: &self } 103 | } 104 | } 105 | 106 | pub struct LineRenderer<'a> { 107 | text_display: glium_text::TextDisplay<&'a glium_text::FontTexture>, 108 | pub char_pos_x: Vec, // in screen coordinates 109 | } 110 | 111 | impl<'a> LineRenderer<'a> { 112 | pub fn new(renderer: &'a Renderer, text: &str) -> LineRenderer<'a> { 113 | let text_display = glium_text::TextDisplay::new(&renderer.text_system, &renderer.font_texture, text); 114 | let em_pixels = renderer.font_texture.em_pixels() as f32; 115 | let char_pos_x = text_display.get_char_pos_x().into_iter().map(|&x| x * em_pixels).collect(); 116 | 117 | LineRenderer { 118 | text_display: text_display, 119 | char_pos_x: char_pos_x, 120 | } 121 | } 122 | 123 | pub fn draw(&self, target: &mut Target, px: f32, py: f32) { 124 | let size = target.renderer.font_texture.em_pixels(); 125 | let (w, h) = target.target.get_dimensions(); 126 | let text_tf = |px: f32, py: f32| -> [[f32; 4]; 4] { 127 | let (x, y) = (px / w as f32 * 2. - 1., 128 | (py - size as f32 / 2.) / h as f32 * 2. - 1.); 129 | 130 | let scale = 2. * size as f32; 131 | 132 | [[scale / w as f32, 0.0, 0.0, 0.0], 133 | [0.0, scale / h as f32, 0.0, 0.0], 134 | [0.0, 0.0, 1.0, 0.0], 135 | [ x, y, 0.0, 1.0]] 136 | }; 137 | glium_text::draw(&self.text_display, &target.renderer.text_system, &mut target.target, text_tf(px, py), (0., 0., 0., 1.)); 138 | } 139 | } 140 | 141 | #[derive(Copy, Clone)] 142 | pub struct Vertex { 143 | pub position: [f32; 2], 144 | pub color: [f32; 4], 145 | } 146 | implement_vertex!(Vertex, position, color); 147 | 148 | pub struct Primitive { 149 | vertex_buffer: glium::VertexBuffer, 150 | index_buffer: glium::index::NoIndices, 151 | fill: bool, 152 | } 153 | 154 | impl Primitive { 155 | // pub fn new(renderer: &Renderer, verts: &[Vertex], primitive_type: glium::index::PrimitiveType, fill: bool) -> Self { 156 | // Primitive { 157 | // vertex_buffer: glium::VertexBuffer::new(&renderer.display, verts).unwrap(), 158 | // index_buffer: glium::index::NoIndices(primitive_type), 159 | // fill: fill, 160 | // } 161 | // } 162 | 163 | pub fn new_rect(renderer: &Renderer, p1: (f32,f32), p2: (f32,f32), color: [f32; 4]) -> Self { 164 | let verts = vec![ 165 | Vertex { position: [p1.0, p1.1], color: color }, 166 | Vertex { position: [p2.0, p1.1], color: color }, 167 | Vertex { position: [p1.0, p2.1], color: color }, 168 | Vertex { position: [p2.0, p2.1], color: color }, 169 | ]; 170 | Primitive { 171 | vertex_buffer: glium::VertexBuffer::new(&renderer.display, &verts).unwrap(), 172 | index_buffer: glium::index::NoIndices(PrimitiveType::TriangleStrip), 173 | fill: true, 174 | } 175 | } 176 | 177 | pub fn new_line(renderer: &Renderer, p1: (f32,f32), p2: (f32,f32), color: [f32; 4]) -> Self { 178 | let verts = vec![ 179 | Vertex { position: [p1.0, p1.1], color: color }, 180 | Vertex { position: [p2.0, p2.1], color: color }, 181 | ]; 182 | Primitive { 183 | vertex_buffer: glium::VertexBuffer::new(&renderer.display, &verts).unwrap(), 184 | index_buffer: glium::index::NoIndices(PrimitiveType::LinesList), 185 | fill: false, 186 | } 187 | } 188 | 189 | pub fn draw(&self, target: &mut Target, offset: (f32, f32)) -> Result<(), glium::DrawError> { 190 | let (w, h) = target.target.get_dimensions(); 191 | let params = glium::DrawParameters { 192 | polygon_mode: if self.fill { glium::draw_parameters::PolygonMode::Fill } else { glium::draw_parameters::PolygonMode::Line }, 193 | blend: glium::draw_parameters::Blend::alpha_blending(), 194 | ..Default::default() 195 | }; 196 | target.target.draw(&self.vertex_buffer, &self.index_buffer, &target.renderer.program, &uniform!{ win_size: (w as f32, h as f32), offset: offset }, ¶ms) 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /src/core.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::sync::mpsc; 3 | use std::thread; 4 | use std::process::{Stdio,Command,ChildStdin}; 5 | use std::io::BufReader; 6 | use std::io::prelude::*; 7 | 8 | use serde_json::{self,Value}; 9 | use serde_json::builder::*; 10 | 11 | macro_rules! println_err ( 12 | ($($arg:tt)*) => { { 13 | writeln!(&mut ::std::io::stderr(), $($arg)*).expect("failed printing to stderr"); 14 | } } 15 | ); 16 | 17 | pub struct Core { 18 | stdin: ChildStdin, 19 | pub update_rx: mpsc::Receiver, 20 | rpc_rx: mpsc::Receiver<(u64,Value)>, // ! A simple piping works only for synchronous calls. 21 | rpc_index: u64, 22 | tab: String, 23 | } 24 | 25 | impl Core { 26 | pub fn new(executable: &str) -> Core { 27 | // spawn the core process 28 | let process = Command::new(executable) 29 | .arg("test-file") 30 | .stdout(Stdio::piped()) 31 | .stdin(Stdio::piped()) 32 | .stderr(Stdio::piped()) 33 | .env("RUST_BACKTRACE", "1") 34 | .spawn() 35 | .unwrap_or_else(|e| { panic!("failed to execute core: {}", e) }); 36 | 37 | 38 | let (update_tx, update_rx) = mpsc::channel(); 39 | let (rpc_tx, rpc_rx) = mpsc::channel(); 40 | let stdout = process.stdout.unwrap(); 41 | thread::spawn(move || { 42 | for line in BufReader::new(stdout).lines() { 43 | if let Ok(data) = serde_json::from_slice::(line.unwrap().as_bytes()) { 44 | let req = data.as_object().unwrap(); 45 | println!("received {:?}", req); 46 | if let (Some(id), Some(result)) = (req.get("id"), req.get("result")) { 47 | // println!("res: {:?}", result); 48 | rpc_tx.send((id.as_u64().unwrap(), result.clone())).unwrap(); 49 | println!("Sent: {:?}", (id.as_u64().unwrap(), result.clone())); 50 | } else if let (Some(method), Some(params)) = (req.get("method"), req.get("params")) { 51 | if method.as_str().unwrap() == "update" { 52 | update_tx.send(params.clone()).unwrap(); 53 | } else { 54 | panic!("Unknown method {:?}.", method.as_str().unwrap()); 55 | } 56 | } else { 57 | panic!("Could not parse the core output: {:?}", req); 58 | } 59 | } 60 | } 61 | }); 62 | 63 | let stderr = process.stderr.unwrap(); 64 | thread::spawn(move || { 65 | let buf_reader = BufReader::new(stderr); 66 | for line in buf_reader.lines() { 67 | if let Ok(line) = line { 68 | println_err!("[core] {}", line); 69 | } 70 | } 71 | }); 72 | 73 | let stdin = process.stdin.unwrap(); 74 | 75 | let mut core = Core { stdin: stdin, update_rx: update_rx, rpc_rx: rpc_rx, rpc_index: 0, tab: "".into() }; 76 | core.tab = core.call_sync("new_tab", ArrayBuilder::new().build()).as_str().map(|s|s.into()).unwrap(); 77 | core 78 | } 79 | 80 | /// Build and send a JSON RPC request, returning the associated request ID to pair it with 81 | /// the response 82 | fn request(&mut self, method: &str, params: Value) -> u64 { 83 | self.rpc_index += 1; 84 | let message = ObjectBuilder::new() 85 | .insert("id", self.rpc_index) 86 | .insert("method", method) 87 | .insert("params", params) 88 | .build(); 89 | self.send(&message); 90 | self.rpc_index 91 | } 92 | 93 | /// Build and send a JSON RPC notification. No synchronous response is expected, so 94 | /// there is no ID. 95 | fn notify(&mut self, method: &str, params: Value) { 96 | let message = ObjectBuilder::new() 97 | .insert("method", method) 98 | .insert("params", params) 99 | .build(); 100 | self.send(&message); 101 | } 102 | 103 | /// Serialize JSON object and send it to the server 104 | fn send(&mut self, message: &Value) { 105 | let mut str_msg = serde_json::ser::to_string(&message).unwrap(); 106 | str_msg.push('\n'); 107 | self.stdin.write(&str_msg.as_bytes()).unwrap(); 108 | } 109 | 110 | fn call_sync(&mut self, method: &str, params: Value) -> Value { 111 | let i = self.request(method, params); 112 | let (id,result) = self.rpc_rx.recv().unwrap(); 113 | assert_eq!(i, id); 114 | result 115 | } 116 | 117 | fn call_edit(&mut self, method: &str, params: Option) { 118 | let obj = ObjectBuilder::new() 119 | .insert("method", method) 120 | .insert("tab", &self.tab) 121 | .insert("params", params.unwrap_or(ArrayBuilder::new().build())); 122 | self.notify("edit", obj.build()); 123 | } 124 | 125 | fn call_edit_sync(&mut self, method: &str, params: Option) -> Value{ 126 | let obj = ObjectBuilder::new() 127 | .insert("method", method) 128 | .insert("tab", &self.tab) 129 | .insert("params", params.unwrap_or(ArrayBuilder::new().build())); 130 | self.call_sync("edit", obj.build()) 131 | } 132 | 133 | pub fn save(&mut self, filename: &str) { 134 | self.call_edit("save", Some(ObjectBuilder::new().insert("filename", filename).build())); 135 | } 136 | 137 | pub fn open(&mut self, filename: &str) { 138 | self.call_edit("open", Some(ObjectBuilder::new().insert("filename", filename).build())); 139 | } 140 | 141 | pub fn left(&mut self) { self.call_edit("move_left", None); } 142 | pub fn left_sel(&mut self) { self.call_edit("move_left_and_modify_selection", None); } 143 | 144 | pub fn right(&mut self) { self.call_edit("move_right", None); } 145 | pub fn right_sel(&mut self) { self.call_edit("move_right_and_modify_selection", None); } 146 | 147 | pub fn up(&mut self) { self.call_edit("move_up", None); } 148 | pub fn up_sel(&mut self) { self.call_edit("move_up_and_modify_selection", None); } 149 | 150 | pub fn down(&mut self) { self.call_edit("move_down", None); } 151 | pub fn down_sel(&mut self) { self.call_edit("move_down_and_modify_selection", None); } 152 | 153 | pub fn del(&mut self) { self.call_edit("delete_backward", None); } 154 | 155 | pub fn page_up(&mut self) { self.call_edit("page_up", None); } 156 | pub fn page_up_sel(&mut self) { self.call_edit("page_up_and_modify_selection", None); } 157 | 158 | pub fn page_down(&mut self) { self.call_edit("page_down", None); } 159 | pub fn page_down_sel(&mut self) { self.call_edit("page_down_and_modify_selection", None); } 160 | 161 | pub fn insert_newline(&mut self) { self.call_edit("insert_newline", None); } 162 | 163 | pub fn f1(&mut self) { self.call_edit("debug_rewrap", None); } 164 | 165 | pub fn f2(&mut self) { self.call_edit("debug_test_fg_spans", None); } 166 | 167 | pub fn char(&mut self, ch: char) { 168 | self.call_edit("insert", Some(ObjectBuilder::new().insert("chars", ch).build())); 169 | } 170 | 171 | pub fn scroll(&mut self, start: u64, end: u64) { 172 | self.call_edit("scroll", Some(ArrayBuilder::new().push(start).push(end).build())); 173 | } 174 | 175 | pub fn click(&mut self, line: u64, column: u64) { 176 | self.call_edit("click", Some(ArrayBuilder::new().push(line).push(column).push(0).push(1).build())); 177 | } 178 | pub fn drag(&mut self, line: u64, column: u64) { 179 | self.call_edit("drag", Some(ArrayBuilder::new().push(line).push(column).push(0).push(1).build())); 180 | } 181 | 182 | pub fn copy(&mut self) -> String { 183 | self.call_edit_sync("copy", None).as_str().map(|x|x.into()).unwrap() 184 | } 185 | pub fn cut(&mut self) -> String { 186 | self.call_edit_sync("cut", None).as_str().map(|x|x.into()).unwrap() 187 | } 188 | pub fn paste(&mut self, s: String) { 189 | self.call_edit("insert", Some(ObjectBuilder::new().insert("chars", s).build())); 190 | } 191 | 192 | #[allow(dead_code)] 193 | pub fn test(&mut self) { 194 | self.render_lines(0, 10); 195 | } 196 | 197 | pub fn render_lines(&mut self, _start: u64, _end: u64) { 198 | unimplemented!() 199 | // self.rpc_index += 1; 200 | // println!("render_lines"); 201 | // let value = ArrayBuilder::new() 202 | // .push("rpc") 203 | // .push_object(|builder| builder 204 | // .insert("index", self.rpc_index) 205 | // .insert_array("request", |builder| builder 206 | // .push("render_lines") 207 | // .push_object(|builder| builder 208 | // .insert("first_line", _start) 209 | // .insert("last_line", _end) 210 | // ) 211 | // ) 212 | // ).unwrap(); 213 | // self.write(value); 214 | } 215 | 216 | pub fn render_lines_sync(&mut self, _start: u64, _end: u64) -> Value { 217 | unimplemented!() 218 | // self.render_lines(_start, _end); 219 | // let value = self.rpc_rx.recv().unwrap(); 220 | // let object = value.as_object().unwrap(); 221 | // assert_eq!(self.rpc_index, object.get("index").unwrap().as_u64().unwrap()); 222 | // object.get("result").unwrap().clone() 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /src/controller.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::time::Duration; 3 | use std::thread; 4 | 5 | use glium::backend::glutin_backend::GlutinFacade; 6 | use serde_json::Value; 7 | use clipboard::ClipboardContext; 8 | 9 | use core::Core; 10 | use renderer::Renderer; 11 | use text::Text; 12 | use file_dialog; 13 | 14 | // pub struct Controller { 15 | // core: Core, 16 | // display: GlutinFacade, 17 | // renderer: Renderer, 18 | // 19 | // state: State, 20 | // } 21 | 22 | pub struct State<'a> { 23 | pub filename: Option, 24 | pub text: Text<'a>, 25 | pub first_line: u64, 26 | pub line_count: u64, 27 | pub scroll_to: (u64, u64), 28 | } 29 | 30 | impl<'a> State<'a> { 31 | pub fn new(filename: Option, renderer: &'a Renderer) -> State<'a> { 32 | State { 33 | filename: filename, 34 | text: Text::new(&renderer), 35 | first_line: 0, 36 | line_count: 1, 37 | scroll_to: (0, 0), 38 | } 39 | } 40 | 41 | // the 'params' field is specified in 42 | // https://github.com/google/xi-editor/blob/master/doc/frontend.md#settext 43 | // The line data itself is updated in fn update_lines 44 | // renderer is needed, because the new lines are rendered as they come. 45 | pub fn update(&mut self, renderer: &'a Renderer, params: Value) { 46 | // println!("{:?}", params); 47 | let dict = params.as_object().unwrap().get("update").unwrap().as_object().unwrap(); 48 | 49 | self.first_line = dict.get("first_line").unwrap().as_u64().unwrap(); 50 | self.line_count = dict.get("height").unwrap().as_u64().unwrap(); 51 | self.text.refresh(self.line_count); 52 | self.text.add_lines(&renderer, dict.get("lines").unwrap(), self.first_line); 53 | // TODO: is this supposed to be in every message, or not? 54 | if let Some(x) = dict.get("scrollto") 55 | .and_then(|x| x.as_array()) { 56 | self.text.scroll_to(x[0].as_u64().unwrap(), x[1].as_u64().unwrap()); 57 | } 58 | } 59 | } 60 | 61 | #[derive(Debug)] 62 | struct MouseState { 63 | pub line: u64, 64 | pub column: u64, 65 | pub pressed: bool, 66 | } 67 | 68 | pub fn run(core_path: &str, filename: Option, display: GlutinFacade) { 69 | let mut core = Core::new(&core_path); 70 | 71 | if let Some(ref filename) = filename { 72 | core.open(filename); 73 | } 74 | 75 | let renderer = Renderer::new(display.clone()); 76 | let mut state = State::new(filename, &renderer); 77 | let mut clipboard = ClipboardContext::new().unwrap(); 78 | 79 | // the main loop 80 | // TODO: replace stateful ctrl/shift modifiers by stateless ones 81 | let (mut ctrl, mut shift) = (false, false); 82 | let (mut file_open_rx, mut file_save_rx) = (None, None); // The receiver of a file dialog. 83 | let mut mouse = MouseState { line: 0, column: 0, pressed: false }; 84 | let mut window_height = 0; 85 | 'a: loop { 86 | while let Ok(value) = core.update_rx.try_recv() { 87 | state.update(&renderer, value); 88 | } 89 | 90 | // polling and handling the events received by the window 91 | for event in display.poll_events() { 92 | use glium::glutin::*; 93 | match event { 94 | Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::O)) => { 95 | if ctrl && file_open_rx.is_none() { 96 | file_open_rx = Some(file_dialog::open()); 97 | ctrl = false; // ctrl is typically released over the dialog 98 | } 99 | }, Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::S)) => { 100 | if ctrl { 101 | if let Some(ref filename) = state.filename { 102 | core.save(filename); 103 | } else { 104 | file_save_rx = Some(file_dialog::save()); 105 | ctrl = false; 106 | } 107 | 108 | if shift { 109 | file_save_rx = Some(file_dialog::save()); 110 | ctrl = false; 111 | shift = false; 112 | } 113 | } 114 | }, Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::T)) => { 115 | if ctrl { 116 | println!("Testing.."); 117 | println!("res: {:?}", core.render_lines_sync(0, 10)); 118 | } 119 | }, Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::C)) => { 120 | if ctrl { 121 | let s = core.copy(); 122 | clipboard.set_contents(s).unwrap(); 123 | clipboard.get_contents().unwrap(); // if this is not done, get_contents() gets an old value 124 | } 125 | }, Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::X)) => { 126 | if ctrl { 127 | let s = core.cut(); 128 | clipboard.set_contents(s).unwrap(); 129 | clipboard.get_contents().unwrap(); // if this is not done, get_contents() gets an old value 130 | } 131 | }, Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::V)) => { 132 | if ctrl { 133 | let s = clipboard.get_contents().unwrap(); 134 | core.paste(s); 135 | } 136 | }, Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::Left)) => { 137 | if shift { core.left_sel() } else { core.left() }; 138 | }, Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::Right)) => { 139 | if shift { core.right_sel() } else { core.right() }; 140 | }, Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::Up)) => { 141 | if shift { core.up_sel() } else { core.up() }; 142 | }, Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::Down)) => { 143 | if shift { core.down_sel() } else { core.down() }; 144 | }, Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::PageUp)) => { 145 | if shift { core.page_up_sel() } else { core.page_up() }; 146 | }, Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::PageDown)) => { 147 | if shift { core.page_down_sel() } else { core.page_down() }; 148 | }, Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::Back)) => { 149 | core.del(); 150 | }, Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::Return)) 151 | | Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::NumpadEnter)) => { 152 | core.insert_newline(); 153 | }, Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::F1)) => { 154 | core.f1(); 155 | }, Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::F2)) => { 156 | core.f2(); 157 | 158 | }, Event::KeyboardInput(state, _, Some(VirtualKeyCode::LControl)) 159 | | Event::KeyboardInput(state, _, Some(VirtualKeyCode::RControl)) => { 160 | ctrl = state == ElementState::Pressed; 161 | println!("ctrl: {}", ctrl); 162 | }, Event::KeyboardInput(state, _, Some(VirtualKeyCode::LShift)) 163 | | Event::KeyboardInput(state, _, Some(VirtualKeyCode::RShift)) => { 164 | shift = state == ElementState::Pressed; 165 | println!("shift: {}", shift); 166 | }, 167 | Event::ReceivedCharacter(ch) => { 168 | // filter out: delete, backspace, enter, ctrl-modified chars 169 | if ch == '\x08' || ch == '\x7f' || ch == '\r' || ctrl { 170 | continue; 171 | } 172 | println!("ch: {:?}", ch); 173 | core.char(ch); 174 | }, 175 | Event::MouseWheel(MouseScrollDelta::LineDelta(_dx,dy), TouchPhase::Moved) => { 176 | state.text.scroll((-dy*3.) as f64); 177 | core.scroll(state.text.top as u64, (state.text.top + state.text.height) as u64); 178 | }, Event::MouseMoved(x, y) => { 179 | let (line, column) = state.text.get_line_col(x, window_height - y); 180 | if mouse.line != line || mouse.column != column { // update only if needed 181 | mouse.line = line; 182 | mouse.column = column; 183 | if mouse.pressed { 184 | core.drag(line, column); 185 | } 186 | } 187 | }, 188 | Event::MouseInput(button_state, MouseButton::Left) => { 189 | mouse.pressed = button_state == ElementState::Pressed; 190 | if mouse.pressed { 191 | core.click(mouse.line, mouse.column); 192 | } 193 | }, 194 | Event::Resized(w, h) => { 195 | window_height = h as i32; 196 | state.text.set_size(w, h); 197 | core.scroll(state.text.top as u64, (state.text.top + state.text.height.round()) as u64); 198 | }, Event::Closed => break 'a, 199 | _ => () 200 | } 201 | } 202 | 203 | if let Some(rx) = file_open_rx.take() { 204 | match rx.try_recv() { 205 | Ok(Some(filename)) => { 206 | // TODO: replace String by Path or OsString 207 | core.open(filename.to_str().unwrap()); 208 | state.filename = Some(filename.to_str().unwrap().into()); 209 | file_open_rx = None; 210 | }, _ => { 211 | file_open_rx = Some(rx); 212 | } 213 | } 214 | } 215 | 216 | if let Some(rx) = file_save_rx.take() { 217 | match rx.try_recv() { 218 | Ok(Some(filename)) => { 219 | // TODO: replace String by Path or OsString 220 | core.save(filename.to_str().unwrap()); 221 | state.filename = Some(filename.to_str().unwrap().into()); 222 | file_save_rx = None; 223 | }, _ => { 224 | file_save_rx = Some(rx); 225 | } 226 | } 227 | } 228 | 229 | let mut target = renderer.draw(); 230 | 231 | state.text.render(&mut target); 232 | 233 | target.finish(); 234 | 235 | thread::sleep(Duration::from_millis(15)); 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /glium_text/src/lib.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | 3 | This crate allows you to easily write text. 4 | 5 | Usage: 6 | 7 | ```no_run 8 | # extern crate glium; 9 | # extern crate glium_text; 10 | # extern crate cgmath; 11 | # fn main() { 12 | # let display: glium::Display = unsafe { std::mem::uninitialized() }; 13 | // The `TextSystem` contains the shaders and elements used for text display. 14 | let system = glium_text::TextSystem::new(&display); 15 | 16 | // Creating a `FontTexture`, which a regular `Texture` which contains the font. 17 | // Note that loading the systems fonts is not covered by this library. 18 | let font = glium_text::FontTexture::new(&display, std::fs::File::open(&std::path::Path::new("my_font.ttf")).unwrap(), 24).unwrap(); 19 | 20 | // Creating a `TextDisplay` which contains the elements required to draw a specific sentence. 21 | let text = glium_text::TextDisplay::new(&system, &font, "Hello world!"); 22 | 23 | // Finally, drawing the text is done like this: 24 | let matrix = [[1.0, 0.0, 0.0, 0.0], 25 | [0.0, 1.0, 0.0, 0.0], 26 | [0.0, 0.0, 1.0, 0.0], 27 | [0.0, 0.0, 0.0, 1.0]]; 28 | glium_text::draw(&text, &system, &mut display.draw(), matrix, (1.0, 1.0, 0.0, 1.0)); 29 | # } 30 | ``` 31 | 32 | */ 33 | 34 | #![warn(missing_docs)] 35 | 36 | extern crate libc; 37 | extern crate freetype_sys as freetype; 38 | #[macro_use] 39 | extern crate glium; 40 | 41 | use glium::DrawParameters; 42 | use glium::backend::Context; 43 | use glium::backend::Facade; 44 | use std::borrow::Cow; 45 | use std::default::Default; 46 | use std::io::Read; 47 | use std::ops::Deref; 48 | use std::rc::Rc; 49 | 50 | /// Texture which contains the characters of the font. 51 | pub struct FontTexture { 52 | texture: glium::texture::Texture2d, 53 | character_infos: Vec<(char, CharacterInfos)>, 54 | em_pixels: u32, 55 | } 56 | 57 | /// Object that contains the elements shared by all `TextDisplay` objects. 58 | /// 59 | /// Required to create a `TextDisplay`. 60 | pub struct TextSystem { 61 | context: Rc, 62 | program: glium::Program, 63 | } 64 | 65 | /// Object that will allow you to draw a text. 66 | pub struct TextDisplay where F: Deref { 67 | context: Rc, 68 | texture: F, 69 | vertex_buffer: Option>, 70 | index_buffer: Option>, 71 | char_pos_x: Vec, 72 | is_empty: bool, 73 | } 74 | 75 | // structure containing informations about a character of a font 76 | #[derive(Copy, Clone, Debug)] 77 | struct CharacterInfos { 78 | // coordinates of the character top-left hand corner on the font's texture 79 | tex_coords: (f32, f32), 80 | 81 | // width and height of character in texture units 82 | tex_size: (f32, f32), 83 | 84 | // size of the character in EMs 85 | size: (f32, f32), 86 | 87 | // number of EMs between the bottom of the character and the base line of text 88 | height_over_line: f32, 89 | 90 | // number of EMs at the left of the character 91 | left_padding: f32, 92 | 93 | // number of EMs at the right of the character 94 | right_padding: f32, 95 | } 96 | 97 | struct TextureData { 98 | data: Vec, 99 | width: u32, 100 | height: u32, 101 | } 102 | 103 | impl<'a> glium::texture::Texture2dDataSource<'a> for &'a TextureData { 104 | type Data = f32; 105 | 106 | fn into_raw(self) -> glium::texture::RawImage2d<'a, f32> { 107 | glium::texture::RawImage2d { 108 | data: Cow::Borrowed(&self.data), 109 | width: self.width, 110 | height: self.height, 111 | format: glium::texture::ClientFormat::F32, 112 | } 113 | } 114 | } 115 | 116 | #[derive(Copy, Clone)] 117 | struct VertexFormat { 118 | position: [f32; 2], 119 | tex_coords: [f32; 2], 120 | } 121 | 122 | implement_vertex!(VertexFormat, position, tex_coords); 123 | 124 | impl FontTexture { 125 | /// Creates a new texture representing a font stored in a `FontTexture`. 126 | pub fn new(facade: &F, font: R, font_size: u32) 127 | -> Result where R: Read, F: Facade 128 | { 129 | // building the freetype library 130 | // FIXME: call FT_Done_Library 131 | let library = unsafe { 132 | // taken from https://github.com/PistonDevelopers/freetype-rs/blob/master/src/library.rs 133 | extern "C" fn alloc_library(_memory: freetype::FT_Memory, size: libc::c_long) -> *mut libc::c_void { 134 | unsafe { 135 | libc::malloc(size as libc::size_t) 136 | } 137 | } 138 | extern "C" fn free_library(_memory: freetype::FT_Memory, block: *mut libc::c_void) { 139 | unsafe { 140 | libc::free(block) 141 | } 142 | } 143 | extern "C" fn realloc_library(_memory: freetype::FT_Memory, 144 | _cur_size: libc::c_long, 145 | new_size: libc::c_long, 146 | block: *mut libc::c_void) -> *mut libc::c_void { 147 | unsafe { 148 | libc::realloc(block, new_size as libc::size_t) 149 | } 150 | } 151 | static mut MEMORY: freetype::FT_MemoryRec = freetype::FT_MemoryRec { 152 | user: 0 as *mut libc::c_void, 153 | alloc: alloc_library, 154 | free: free_library, 155 | realloc: realloc_library, 156 | }; 157 | 158 | let mut raw = ::std::ptr::null_mut(); 159 | if freetype::FT_New_Library(&mut MEMORY, &mut raw) != freetype::FT_Err_Ok { 160 | return Err(()); 161 | } 162 | freetype::FT_Add_Default_Modules(raw); 163 | 164 | raw 165 | }; 166 | 167 | // building the freetype face object 168 | let font: Vec = font.bytes().map(|c| c.unwrap()).collect(); 169 | 170 | let face: freetype::FT_Face = unsafe { 171 | let mut face = ::std::ptr::null_mut(); 172 | let err = freetype::FT_New_Memory_Face(library, font.as_ptr(), 173 | font.len() as freetype::FT_Long, 0, &mut face); 174 | if err == freetype::FT_Err_Ok { 175 | face 176 | } else { 177 | return Err(()); 178 | } 179 | }; 180 | 181 | // computing the list of characters in the font 182 | let characters_list = unsafe { 183 | // TODO: unresolved symbol 184 | /*if freetype::FT_Select_CharMap(face, freetype::FT_ENCODING_UNICODE) != 0 { 185 | return Err(()); 186 | }*/ 187 | 188 | let mut result = Vec::new(); 189 | 190 | let mut g: freetype::FT_UInt = std::mem::uninitialized(); 191 | let mut c = freetype::FT_Get_First_Char(face, &mut g); 192 | 193 | while g != 0 { 194 | result.push(std::mem::transmute(c as u32)); // TODO: better solution? 195 | c = freetype::FT_Get_Next_Char(face, c, &mut g); 196 | } 197 | 198 | result 199 | }; 200 | 201 | // building the infos 202 | let (texture_data, chr_infos, em_pixels) = unsafe { 203 | build_font_image(face, characters_list, font_size) 204 | }; 205 | 206 | // we load the texture in the display 207 | let texture = glium::texture::Texture2d::new(facade, &texture_data).unwrap(); 208 | 209 | Ok(FontTexture { 210 | texture: texture, 211 | character_infos: chr_infos, 212 | em_pixels: em_pixels, 213 | }) 214 | } 215 | 216 | /// Return the size of an em-unit for the generated font texture. 217 | /// This is needed for a pixel-perfect display: the text geometry is scaled so that 218 | /// 1em == 1 unit. We must scale the geometry up by em_pixels to match the screen pixels. 219 | pub fn em_pixels(&self) -> u32 { 220 | self.em_pixels 221 | } 222 | } 223 | 224 | /*impl glium::uniforms::AsUniformValue for FontTexture { 225 | fn as_uniform_value(&self) -> glium::uniforms::UniformValue { 226 | glium::uniforms::AsUniformValue::as_uniform_value(&self.texture) 227 | } 228 | }*/ 229 | 230 | impl TextSystem { 231 | /// Builds a new text system that must be used to build `TextDisplay` objects. 232 | pub fn new(facade: &F) -> TextSystem where F: Facade { 233 | TextSystem { 234 | context: facade.get_context().clone(), 235 | program: program!(facade, 236 | 140 => { 237 | vertex: " 238 | #version 140 239 | 240 | uniform mat4 matrix; 241 | in vec2 position; 242 | in vec2 tex_coords; 243 | 244 | out vec2 v_tex_coords; 245 | 246 | void main() { 247 | gl_Position = matrix * vec4(position, 0.0, 1.0); 248 | v_tex_coords = tex_coords; 249 | } 250 | ", 251 | fragment: " 252 | #version 140 253 | in vec2 v_tex_coords; 254 | out vec4 f_color; 255 | uniform vec4 color; 256 | uniform sampler2D tex; 257 | void main() { 258 | vec4 c = vec4(color.rgb, color.a * texture(tex, v_tex_coords)); 259 | if (c.a <= 0.01) { 260 | discard; 261 | } else { 262 | f_color = c; 263 | } 264 | } 265 | " 266 | }, 267 | 268 | 110 => { 269 | vertex: " 270 | #version 110 271 | 272 | attribute vec2 position; 273 | attribute vec2 tex_coords; 274 | varying vec2 v_tex_coords; 275 | uniform mat4 matrix; 276 | 277 | void main() { 278 | gl_Position = matrix * vec4(position.x, position.y, 0.0, 1.0); 279 | v_tex_coords = tex_coords; 280 | } 281 | ", 282 | fragment: " 283 | #version 110 284 | 285 | varying vec2 v_tex_coords; 286 | uniform vec4 color; 287 | uniform sampler2D tex; 288 | 289 | void main() { 290 | gl_FragColor = vec4(color.rgb, color.a * texture2D(tex, v_tex_coords)); 291 | if (gl_FragColor.a <= 0.01) { 292 | discard; 293 | } 294 | } 295 | " 296 | }, 297 | 298 | ).unwrap() 299 | } 300 | } 301 | } 302 | 303 | impl TextDisplay where F: Deref { 304 | /// Builds a new text display that allows you to draw text. 305 | pub fn new(system: &TextSystem, texture: F, text: &str) -> TextDisplay { 306 | let mut text_display = TextDisplay { 307 | context: system.context.clone(), 308 | texture: texture, 309 | vertex_buffer: None, 310 | index_buffer: None, 311 | char_pos_x: vec![], 312 | is_empty: true, 313 | }; 314 | 315 | text_display.set_text(text); 316 | 317 | text_display 318 | } 319 | 320 | /// Return the x-positions (in em-units) of the breaks between characters. 321 | /// When a character starts at n-th byte, then get_char_pos_x()[n] is the x-pos of the character. 322 | /// The last value of the array is the x-pos of the end of the string 323 | pub fn get_char_pos_x(&self) -> &[f32] { 324 | &self.char_pos_x 325 | } 326 | 327 | /// Modifies the text on this display. 328 | pub fn set_text(&mut self, text: &str) { 329 | self.is_empty = true; 330 | self.char_pos_x = vec![0.]; 331 | self.vertex_buffer = None; 332 | self.index_buffer = None; 333 | 334 | // returning if no text 335 | if text.len() == 0 { 336 | return; 337 | } 338 | 339 | // these arrays will contain the vertex buffer and index buffer data 340 | let mut vertex_buffer_data = Vec::with_capacity(text.len() * 4 * 4); 341 | let mut index_buffer_data = Vec::with_capacity(text.len() * 6); 342 | 343 | // iterating over the characters of the string 344 | let mut pos_x = 0.; 345 | for character in text.chars() { // FIXME: wrong, but only thing stable 346 | 347 | let infos = match self.texture.character_infos 348 | .iter().find(|&&(chr, _)| chr == character) 349 | { 350 | Some(infos) => infos, 351 | None => continue // character not found in the font, ignoring it 352 | }; 353 | let infos = infos.1; 354 | 355 | self.is_empty = false; 356 | 357 | // adding the quad in the index buffer 358 | { 359 | let first_vertex_offset = vertex_buffer_data.len() as u16; 360 | index_buffer_data.push(first_vertex_offset); 361 | index_buffer_data.push(first_vertex_offset + 1); 362 | index_buffer_data.push(first_vertex_offset + 2); 363 | index_buffer_data.push(first_vertex_offset + 2); 364 | index_buffer_data.push(first_vertex_offset + 1); 365 | index_buffer_data.push(first_vertex_offset + 3); 366 | } 367 | 368 | // 369 | pos_x += infos.left_padding; 370 | 371 | // calculating coords 372 | let left_coord = pos_x; 373 | let right_coord = left_coord + infos.size.0; 374 | let top_coord = infos.height_over_line; 375 | let bottom_coord = infos.height_over_line - infos.size.1; 376 | 377 | // top-left vertex 378 | vertex_buffer_data.push(VertexFormat { 379 | position: [left_coord, top_coord], 380 | tex_coords: [infos.tex_coords.0, infos.tex_coords.1], 381 | }); 382 | 383 | // top-right vertex 384 | vertex_buffer_data.push(VertexFormat { 385 | position: [right_coord, top_coord], 386 | tex_coords: [infos.tex_coords.0 + infos.tex_size.0, infos.tex_coords.1], 387 | }); 388 | 389 | // bottom-left vertex 390 | vertex_buffer_data.push(VertexFormat { 391 | position: [left_coord, bottom_coord], 392 | tex_coords: [infos.tex_coords.0, infos.tex_coords.1 + infos.tex_size.1], 393 | }); 394 | 395 | // bottom-right vertex 396 | vertex_buffer_data.push(VertexFormat { 397 | position: [right_coord, bottom_coord], 398 | tex_coords: [ 399 | infos.tex_coords.0 + infos.tex_size.0, 400 | infos.tex_coords.1 + infos.tex_size.1 401 | ], 402 | }); 403 | 404 | // going to next char 405 | pos_x = right_coord + infos.right_padding; 406 | for _ in 0..character.len_utf8() { 407 | self.char_pos_x.push(pos_x); 408 | } 409 | } 410 | 411 | if !vertex_buffer_data.len() != 0 { 412 | // building the vertex buffer 413 | self.vertex_buffer = Some(glium::VertexBuffer::new(&self.context, 414 | &vertex_buffer_data).unwrap()); 415 | 416 | // building the index buffer 417 | self.index_buffer = Some(glium::IndexBuffer::new(&self.context, 418 | glium::index::PrimitiveType::TrianglesList, 419 | &index_buffer_data).unwrap()); 420 | } 421 | } 422 | } 423 | 424 | /// 425 | /// ## About the matrix 426 | /// 427 | /// The matrix must be column-major post-muliplying (which is the usual way to do in OpenGL). 428 | /// 429 | /// One unit in height corresponds to a line of text, but the text can go above or under. 430 | /// The bottom of the line is at `0.0`, the top is at `1.0`. 431 | /// You need to adapt your matrix by taking these into consideration. 432 | pub fn draw(text: &TextDisplay, system: &TextSystem, target: &mut S, 433 | matrix: M, color: (f32, f32, f32, f32)) 434 | where S: glium::Surface, M: Into<[[f32; 4]; 4]>, 435 | F: Deref 436 | { 437 | let matrix = matrix.into(); 438 | 439 | let &TextDisplay { ref vertex_buffer, ref index_buffer, ref texture, is_empty, .. } = text; 440 | let color = [color.0, color.1, color.2, color.3]; 441 | 442 | // returning if nothing to draw 443 | if is_empty || vertex_buffer.is_none() || index_buffer.is_none() { 444 | return; 445 | } 446 | 447 | let vertex_buffer = vertex_buffer.as_ref().unwrap(); 448 | let index_buffer = index_buffer.as_ref().unwrap(); 449 | 450 | let uniforms = uniform! { 451 | matrix: matrix, 452 | color: color, 453 | tex: glium::uniforms::Sampler(&texture.texture, glium::uniforms::SamplerBehavior { 454 | magnify_filter: glium::uniforms::MagnifySamplerFilter::Linear, 455 | minify_filter: glium::uniforms::MinifySamplerFilter::Linear, 456 | .. Default::default() 457 | }) 458 | }; 459 | 460 | 461 | let params = { 462 | use glium::BlendingFunction::Addition; 463 | use glium::LinearBlendingFactor::*; 464 | 465 | let blending_function = Addition { 466 | source: SourceAlpha, 467 | destination: OneMinusSourceAlpha 468 | }; 469 | 470 | let blend = glium::Blend { 471 | color: blending_function, 472 | alpha: blending_function, 473 | constant_value: (1.0, 1.0, 1.0, 1.0), 474 | }; 475 | 476 | DrawParameters { 477 | blend: blend, 478 | .. Default::default() 479 | } 480 | }; 481 | target.draw(vertex_buffer, index_buffer, &system.program, &uniforms, 482 | ¶ms).unwrap(); 483 | } 484 | 485 | unsafe fn build_font_image(face: freetype::FT_Face, characters_list: Vec, font_size: u32) 486 | -> (TextureData, Vec<(char, CharacterInfos)>, u32) 487 | { 488 | use std::iter; 489 | 490 | // a margin around each character to prevent artifacts 491 | const MARGIN: u32 = 2; 492 | 493 | // setting the right pixel size 494 | if freetype::FT_Set_Pixel_Sizes(face, font_size, font_size) != 0 { 495 | panic!(); 496 | } 497 | 498 | // this variable will store the texture data 499 | // we set an arbitrary capacity that we think will match what we will need 500 | let mut texture_data: Vec = Vec::with_capacity(characters_list.len() * 501 | font_size as usize * font_size as usize); 502 | 503 | // the width is chosen more or less arbitrarily, because we can store everything as long as 504 | // the texture is at least as wide as the widest character 505 | // we just try to estimate a width so that width ~= height 506 | let texture_width = get_nearest_po2(std::cmp::max(font_size * 2 as u32, 507 | ((((characters_list.len() as u32) * font_size * font_size) as f32).sqrt()) as u32)); 508 | 509 | // we store the position of the "cursor" in the destination texture 510 | // this cursor points to the top-left pixel of the next character to write on the texture 511 | let mut cursor_offset = (0u32, 0u32); 512 | 513 | // number of rows to skip at next carriage return 514 | let mut rows_to_skip = 0u32; 515 | 516 | // now looping through the list of characters, filling the texture and returning the informations 517 | let mut em_pixels = font_size; 518 | let mut characters_infos: Vec<(char, CharacterInfos)> = characters_list.into_iter().filter_map(|character| { 519 | // loading wanted glyph in the font face 520 | if freetype::FT_Load_Glyph(face, freetype::FT_Get_Char_Index(face, character as freetype::FT_ULong), freetype::FT_LOAD_RENDER) != 0 { 521 | return None; 522 | } 523 | let bitmap = &(*(*face).glyph).bitmap; 524 | 525 | // adding a left margin before our character to prevent artifacts 526 | cursor_offset.0 += MARGIN; 527 | 528 | // computing em_pixels 529 | // FIXME: this is hacky 530 | if character == 'M' { 531 | // println!("M [{}x{}] bitmap: {:?}", bitmap.width, bitmap.rows, std::slice::from_raw_parts(bitmap.buffer, (bitmap.rows * bitmap.width) as usize)); 532 | em_pixels = bitmap.rows as u32; 533 | } 534 | 535 | // carriage return our cursor if we don't have enough room to write the next caracter 536 | // we add a margin to prevent artifacts 537 | if cursor_offset.0 + (bitmap.width as u32) + MARGIN >= texture_width { 538 | assert!(bitmap.width as u32 <= texture_width); // if this fails, we should increase texture_width 539 | cursor_offset.0 = 0; 540 | cursor_offset.1 += rows_to_skip; 541 | rows_to_skip = 0; 542 | } 543 | 544 | // if the texture data buffer has not enough lines, adding some 545 | if rows_to_skip < MARGIN + bitmap.rows as u32 { 546 | let diff = MARGIN + (bitmap.rows as u32) - rows_to_skip; 547 | rows_to_skip = MARGIN + bitmap.rows as u32; 548 | texture_data.extend(iter::repeat(0.0).take((diff * texture_width) as usize)); 549 | } 550 | 551 | // copying the data to the texture 552 | let offset_x_before_copy = cursor_offset.0; 553 | if bitmap.rows >= 1 { 554 | let destination = &mut texture_data[(cursor_offset.0 + cursor_offset.1 * texture_width) as usize ..]; 555 | let source = std::mem::transmute(bitmap.buffer); 556 | let source = std::slice::from_raw_parts(source, destination.len()); 557 | 558 | for y in 0 .. bitmap.rows as u32 { 559 | let source = &source[(y * bitmap.width as u32) as usize ..]; 560 | let destination = &mut destination[(y * texture_width) as usize ..]; 561 | 562 | for x in 0 .. bitmap.width { 563 | // the values in source are bytes between 0 and 255, but we want floats between 0 and 1 564 | let val: u8 = *source.get(x as usize).unwrap(); 565 | let val = (val as f32) / (std::u8::MAX as f32); 566 | let dest = destination.get_mut(x as usize).unwrap(); 567 | *dest = val; 568 | } 569 | } 570 | 571 | cursor_offset.0 += bitmap.width as u32; 572 | debug_assert!(cursor_offset.0 <= texture_width); 573 | } 574 | 575 | // filling infos about that character 576 | // tex_size and tex_coords are in pixels for the moment ; they will be divided 577 | // by the texture dimensions later 578 | let left_padding = (*(*face).glyph).bitmap_left; 579 | 580 | Some((character, CharacterInfos { 581 | tex_size: (bitmap.width as f32, bitmap.rows as f32), 582 | tex_coords: (offset_x_before_copy as f32, cursor_offset.1 as f32), 583 | size: (bitmap.width as f32, bitmap.rows as f32), 584 | left_padding: left_padding as f32, 585 | right_padding: ((*(*face).glyph).advance.x as i32 - bitmap.width * 64 - left_padding * 64) as f32 / 64.0, 586 | height_over_line: (*(*face).glyph).bitmap_top as f32, 587 | })) 588 | }).collect(); 589 | 590 | // adding blank lines at the end until the height of the texture is a power of two 591 | { 592 | let current_height = texture_data.len() as u32 / texture_width; 593 | let requested_height = get_nearest_po2(current_height); 594 | texture_data.extend(iter::repeat(0.0).take((texture_width * (requested_height - current_height)) as usize)); 595 | } 596 | 597 | // now our texture is finished 598 | // we know its final dimensions, so we can divide all the pixels values into (0,1) range 599 | assert!((texture_data.len() as u32 % texture_width) == 0); 600 | let texture_height = (texture_data.len() as u32 / texture_width) as f32; 601 | let float_texture_width = texture_width as f32; 602 | for chr in characters_infos.iter_mut() { 603 | chr.1.tex_size.0 /= float_texture_width; 604 | chr.1.tex_size.1 /= texture_height; 605 | chr.1.tex_coords.0 /= float_texture_width; 606 | chr.1.tex_coords.1 /= texture_height; 607 | chr.1.size.0 /= em_pixels as f32; 608 | chr.1.size.1 /= em_pixels as f32; 609 | chr.1.left_padding /= em_pixels as f32; 610 | chr.1.right_padding /= em_pixels as f32; 611 | chr.1.height_over_line /= em_pixels as f32; 612 | } 613 | 614 | // returning 615 | (TextureData { 616 | data: texture_data, 617 | width: texture_width, 618 | height: texture_height as u32, 619 | }, characters_infos, em_pixels) 620 | } 621 | 622 | /// Function that will calculate the nearest power of two. 623 | fn get_nearest_po2(mut x: u32) -> u32 { 624 | assert!(x > 0); 625 | x -= 1; 626 | x = x | (x >> 1); 627 | x = x | (x >> 2); 628 | x = x | (x >> 4); 629 | x = x | (x >> 8); 630 | x = x | (x >> 16); 631 | x + 1 632 | } 633 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | [root] 2 | name = "xi_glium" 3 | version = "0.0.0" 4 | dependencies = [ 5 | "clipboard 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 6 | "glib 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 7 | "glium 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", 8 | "glium_text 0.10.0", 9 | "gtk 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 10 | "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", 11 | ] 12 | 13 | [[package]] 14 | name = "android_glue" 15 | version = "0.2.1" 16 | source = "registry+https://github.com/rust-lang/crates.io-index" 17 | 18 | [[package]] 19 | name = "atk-sys" 20 | version = "0.3.1" 21 | source = "registry+https://github.com/rust-lang/crates.io-index" 22 | dependencies = [ 23 | "bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 24 | "glib-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 25 | "gobject-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 26 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 27 | "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 28 | ] 29 | 30 | [[package]] 31 | name = "backtrace" 32 | version = "0.2.3" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | dependencies = [ 35 | "backtrace-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 36 | "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 37 | "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 38 | "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 39 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 40 | "rustc-demangle 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 41 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 42 | ] 43 | 44 | [[package]] 45 | name = "backtrace-sys" 46 | version = "0.1.4" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | dependencies = [ 49 | "gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", 50 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 51 | ] 52 | 53 | [[package]] 54 | name = "bitflags" 55 | version = "0.3.3" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | 58 | [[package]] 59 | name = "bitflags" 60 | version = "0.4.0" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | 63 | [[package]] 64 | name = "bitflags" 65 | version = "0.5.0" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | 68 | [[package]] 69 | name = "bitflags" 70 | version = "0.7.0" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | 73 | [[package]] 74 | name = "block" 75 | version = "0.1.6" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | 78 | [[package]] 79 | name = "byteorder" 80 | version = "0.5.3" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | 83 | [[package]] 84 | name = "c_vec" 85 | version = "1.0.12" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | 88 | [[package]] 89 | name = "cairo-rs" 90 | version = "0.1.0" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | dependencies = [ 93 | "c_vec 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)", 94 | "cairo-sys-rs 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 95 | "glib 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 96 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 97 | ] 98 | 99 | [[package]] 100 | name = "cairo-sys-rs" 101 | version = "0.3.1" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | dependencies = [ 104 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 105 | "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 106 | ] 107 | 108 | [[package]] 109 | name = "cfg-if" 110 | version = "0.1.0" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | 113 | [[package]] 114 | name = "cgl" 115 | version = "0.1.5" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | dependencies = [ 118 | "gleam 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", 119 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 120 | ] 121 | 122 | [[package]] 123 | name = "clipboard" 124 | version = "0.1.2" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | dependencies = [ 127 | "clipboard-win 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 128 | "objc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 129 | "objc-foundation 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 130 | "objc_id 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 131 | "x11 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 132 | ] 133 | 134 | [[package]] 135 | name = "clipboard-win" 136 | version = "1.8.0" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | dependencies = [ 139 | "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 140 | "user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 141 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 142 | "windows-error 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 143 | ] 144 | 145 | [[package]] 146 | name = "cocoa" 147 | version = "0.3.3" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | dependencies = [ 150 | "bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 151 | "core-graphics 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 152 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 153 | "objc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 154 | ] 155 | 156 | [[package]] 157 | name = "core-foundation" 158 | version = "0.2.2" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | dependencies = [ 161 | "core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 162 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 163 | ] 164 | 165 | [[package]] 166 | name = "core-foundation-sys" 167 | version = "0.2.2" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | dependencies = [ 170 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 171 | ] 172 | 173 | [[package]] 174 | name = "core-graphics" 175 | version = "0.3.2" 176 | source = "registry+https://github.com/rust-lang/crates.io-index" 177 | dependencies = [ 178 | "core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 179 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 180 | "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", 181 | ] 182 | 183 | [[package]] 184 | name = "crossbeam" 185 | version = "0.2.10" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | 188 | [[package]] 189 | name = "dbghelp-sys" 190 | version = "0.2.0" 191 | source = "registry+https://github.com/rust-lang/crates.io-index" 192 | dependencies = [ 193 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 194 | "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 195 | ] 196 | 197 | [[package]] 198 | name = "dlib" 199 | version = "0.3.0" 200 | source = "registry+https://github.com/rust-lang/crates.io-index" 201 | dependencies = [ 202 | "libloading 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", 203 | ] 204 | 205 | [[package]] 206 | name = "dtoa" 207 | version = "0.2.2" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | 210 | [[package]] 211 | name = "dwmapi-sys" 212 | version = "0.1.0" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | dependencies = [ 215 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 216 | "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 217 | ] 218 | 219 | [[package]] 220 | name = "freetype-sys" 221 | version = "0.4.0" 222 | source = "registry+https://github.com/rust-lang/crates.io-index" 223 | dependencies = [ 224 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 225 | "libz-sys 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 226 | "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 227 | ] 228 | 229 | [[package]] 230 | name = "fs2" 231 | version = "0.2.5" 232 | source = "registry+https://github.com/rust-lang/crates.io-index" 233 | dependencies = [ 234 | "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 235 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 236 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 237 | ] 238 | 239 | [[package]] 240 | name = "gcc" 241 | version = "0.3.35" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | 244 | [[package]] 245 | name = "gdi32-sys" 246 | version = "0.1.1" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | dependencies = [ 249 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 250 | ] 251 | 252 | [[package]] 253 | name = "gdk" 254 | version = "0.5.0" 255 | source = "registry+https://github.com/rust-lang/crates.io-index" 256 | dependencies = [ 257 | "bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", 258 | "cairo-rs 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 259 | "gdk-pixbuf 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 260 | "gdk-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 261 | "gio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 262 | "glib 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 263 | "glib-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 264 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 265 | "pango 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 266 | ] 267 | 268 | [[package]] 269 | name = "gdk-pixbuf" 270 | version = "0.1.0" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | dependencies = [ 273 | "gdk-pixbuf-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 274 | "glib 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 275 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 276 | ] 277 | 278 | [[package]] 279 | name = "gdk-pixbuf-sys" 280 | version = "0.3.1" 281 | source = "registry+https://github.com/rust-lang/crates.io-index" 282 | dependencies = [ 283 | "bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 284 | "gio-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 285 | "glib-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 286 | "gobject-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 287 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 288 | "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 289 | ] 290 | 291 | [[package]] 292 | name = "gdk-sys" 293 | version = "0.3.1" 294 | source = "registry+https://github.com/rust-lang/crates.io-index" 295 | dependencies = [ 296 | "bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 297 | "cairo-sys-rs 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 298 | "gdk-pixbuf-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 299 | "gio-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 300 | "glib-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 301 | "gobject-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 302 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 303 | "pango-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 304 | "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 305 | ] 306 | 307 | [[package]] 308 | name = "gio" 309 | version = "0.1.0" 310 | source = "registry+https://github.com/rust-lang/crates.io-index" 311 | dependencies = [ 312 | "bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", 313 | "gio-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 314 | "glib 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 315 | "glib-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 316 | "gobject-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 317 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 318 | ] 319 | 320 | [[package]] 321 | name = "gio-sys" 322 | version = "0.3.1" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | dependencies = [ 325 | "bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 326 | "glib-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 327 | "gobject-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 328 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 329 | "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 330 | ] 331 | 332 | [[package]] 333 | name = "gl_generator" 334 | version = "0.5.2" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | dependencies = [ 337 | "khronos_api 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 338 | "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 339 | "xml-rs 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", 340 | ] 341 | 342 | [[package]] 343 | name = "gleam" 344 | version = "0.2.21" 345 | source = "registry+https://github.com/rust-lang/crates.io-index" 346 | dependencies = [ 347 | "gl_generator 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 348 | ] 349 | 350 | [[package]] 351 | name = "glib" 352 | version = "0.1.0" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | dependencies = [ 355 | "gio-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 356 | "glib-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 357 | "gobject-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 358 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 359 | ] 360 | 361 | [[package]] 362 | name = "glib-sys" 363 | version = "0.3.1" 364 | source = "registry+https://github.com/rust-lang/crates.io-index" 365 | dependencies = [ 366 | "bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 367 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 368 | "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 369 | ] 370 | 371 | [[package]] 372 | name = "glium" 373 | version = "0.15.0" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | dependencies = [ 376 | "backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 377 | "gl_generator 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 378 | "glutin 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", 379 | "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 380 | "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", 381 | ] 382 | 383 | [[package]] 384 | name = "glium_text" 385 | version = "0.10.0" 386 | dependencies = [ 387 | "freetype-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 388 | "glium 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", 389 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 390 | ] 391 | 392 | [[package]] 393 | name = "glutin" 394 | version = "0.6.1" 395 | source = "registry+https://github.com/rust-lang/crates.io-index" 396 | dependencies = [ 397 | "android_glue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 398 | "cgl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 399 | "cocoa 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 400 | "core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 401 | "core-graphics 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 402 | "dwmapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 403 | "gdi32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 404 | "gl_generator 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 405 | "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 406 | "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 407 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 408 | "objc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 409 | "osmesa-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 410 | "shared_library 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 411 | "shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 412 | "user32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 413 | "wayland-client 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)", 414 | "wayland-kbd 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 415 | "wayland-window 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 416 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 417 | "x11-dl 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 418 | ] 419 | 420 | [[package]] 421 | name = "gobject-sys" 422 | version = "0.3.1" 423 | source = "registry+https://github.com/rust-lang/crates.io-index" 424 | dependencies = [ 425 | "bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 426 | "glib-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 427 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 428 | "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 429 | ] 430 | 431 | [[package]] 432 | name = "gtk" 433 | version = "0.1.0" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | dependencies = [ 436 | "bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", 437 | "cairo-rs 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 438 | "cairo-sys-rs 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 439 | "gdk 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", 440 | "gdk-pixbuf 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 441 | "gdk-pixbuf-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 442 | "gdk-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 443 | "gio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 444 | "gio-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 445 | "glib 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 446 | "glib-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 447 | "gobject-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 448 | "gtk-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 449 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 450 | "pango 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 451 | ] 452 | 453 | [[package]] 454 | name = "gtk-sys" 455 | version = "0.3.1" 456 | source = "registry+https://github.com/rust-lang/crates.io-index" 457 | dependencies = [ 458 | "atk-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 459 | "bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 460 | "cairo-sys-rs 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 461 | "gdk-pixbuf-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 462 | "gdk-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 463 | "gio-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 464 | "glib-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 465 | "gobject-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 466 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 467 | "pango-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 468 | "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 469 | ] 470 | 471 | [[package]] 472 | name = "itoa" 473 | version = "0.1.1" 474 | source = "registry+https://github.com/rust-lang/crates.io-index" 475 | 476 | [[package]] 477 | name = "kernel32-sys" 478 | version = "0.2.2" 479 | source = "registry+https://github.com/rust-lang/crates.io-index" 480 | dependencies = [ 481 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 482 | "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 483 | ] 484 | 485 | [[package]] 486 | name = "khronos_api" 487 | version = "1.0.0" 488 | source = "registry+https://github.com/rust-lang/crates.io-index" 489 | 490 | [[package]] 491 | name = "lazy_static" 492 | version = "0.1.16" 493 | source = "registry+https://github.com/rust-lang/crates.io-index" 494 | 495 | [[package]] 496 | name = "lazy_static" 497 | version = "0.2.1" 498 | source = "registry+https://github.com/rust-lang/crates.io-index" 499 | 500 | [[package]] 501 | name = "libc" 502 | version = "0.2.15" 503 | source = "registry+https://github.com/rust-lang/crates.io-index" 504 | 505 | [[package]] 506 | name = "libloading" 507 | version = "0.2.4" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | dependencies = [ 510 | "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 511 | "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 512 | "target_build_utils 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 513 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 514 | ] 515 | 516 | [[package]] 517 | name = "libz-sys" 518 | version = "1.0.6" 519 | source = "registry+https://github.com/rust-lang/crates.io-index" 520 | dependencies = [ 521 | "gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", 522 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 523 | "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 524 | ] 525 | 526 | [[package]] 527 | name = "log" 528 | version = "0.3.6" 529 | source = "registry+https://github.com/rust-lang/crates.io-index" 530 | 531 | [[package]] 532 | name = "malloc_buf" 533 | version = "0.0.6" 534 | source = "registry+https://github.com/rust-lang/crates.io-index" 535 | dependencies = [ 536 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 537 | ] 538 | 539 | [[package]] 540 | name = "memmap" 541 | version = "0.2.3" 542 | source = "registry+https://github.com/rust-lang/crates.io-index" 543 | dependencies = [ 544 | "fs2 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", 545 | "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 546 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 547 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 548 | ] 549 | 550 | [[package]] 551 | name = "num-traits" 552 | version = "0.1.35" 553 | source = "registry+https://github.com/rust-lang/crates.io-index" 554 | 555 | [[package]] 556 | name = "objc" 557 | version = "0.2.1" 558 | source = "registry+https://github.com/rust-lang/crates.io-index" 559 | dependencies = [ 560 | "malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 561 | ] 562 | 563 | [[package]] 564 | name = "objc-foundation" 565 | version = "0.1.1" 566 | source = "registry+https://github.com/rust-lang/crates.io-index" 567 | dependencies = [ 568 | "block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 569 | "objc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 570 | "objc_id 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 571 | ] 572 | 573 | [[package]] 574 | name = "objc_id" 575 | version = "0.1.0" 576 | source = "registry+https://github.com/rust-lang/crates.io-index" 577 | dependencies = [ 578 | "objc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 579 | ] 580 | 581 | [[package]] 582 | name = "osmesa-sys" 583 | version = "0.1.1" 584 | source = "registry+https://github.com/rust-lang/crates.io-index" 585 | dependencies = [ 586 | "shared_library 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 587 | ] 588 | 589 | [[package]] 590 | name = "pango" 591 | version = "0.1.0" 592 | source = "registry+https://github.com/rust-lang/crates.io-index" 593 | dependencies = [ 594 | "glib 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 595 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 596 | "pango-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 597 | ] 598 | 599 | [[package]] 600 | name = "pango-sys" 601 | version = "0.3.1" 602 | source = "registry+https://github.com/rust-lang/crates.io-index" 603 | dependencies = [ 604 | "bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 605 | "glib-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 606 | "gobject-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 607 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 608 | "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 609 | ] 610 | 611 | [[package]] 612 | name = "pkg-config" 613 | version = "0.3.8" 614 | source = "registry+https://github.com/rust-lang/crates.io-index" 615 | 616 | [[package]] 617 | name = "rand" 618 | version = "0.3.14" 619 | source = "registry+https://github.com/rust-lang/crates.io-index" 620 | dependencies = [ 621 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 622 | ] 623 | 624 | [[package]] 625 | name = "rustc-demangle" 626 | version = "0.1.1" 627 | source = "registry+https://github.com/rust-lang/crates.io-index" 628 | 629 | [[package]] 630 | name = "rustc_version" 631 | version = "0.1.7" 632 | source = "registry+https://github.com/rust-lang/crates.io-index" 633 | dependencies = [ 634 | "semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", 635 | ] 636 | 637 | [[package]] 638 | name = "semver" 639 | version = "0.1.20" 640 | source = "registry+https://github.com/rust-lang/crates.io-index" 641 | 642 | [[package]] 643 | name = "serde" 644 | version = "0.7.15" 645 | source = "registry+https://github.com/rust-lang/crates.io-index" 646 | 647 | [[package]] 648 | name = "serde" 649 | version = "0.8.7" 650 | source = "registry+https://github.com/rust-lang/crates.io-index" 651 | 652 | [[package]] 653 | name = "serde_json" 654 | version = "0.8.1" 655 | source = "registry+https://github.com/rust-lang/crates.io-index" 656 | dependencies = [ 657 | "dtoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 658 | "itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 659 | "num-traits 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", 660 | "serde 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)", 661 | ] 662 | 663 | [[package]] 664 | name = "shared_library" 665 | version = "0.1.5" 666 | source = "registry+https://github.com/rust-lang/crates.io-index" 667 | dependencies = [ 668 | "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 669 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 670 | ] 671 | 672 | [[package]] 673 | name = "shell32-sys" 674 | version = "0.1.1" 675 | source = "registry+https://github.com/rust-lang/crates.io-index" 676 | dependencies = [ 677 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 678 | "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 679 | ] 680 | 681 | [[package]] 682 | name = "smallvec" 683 | version = "0.1.8" 684 | source = "registry+https://github.com/rust-lang/crates.io-index" 685 | 686 | [[package]] 687 | name = "target_build_utils" 688 | version = "0.1.1" 689 | source = "registry+https://github.com/rust-lang/crates.io-index" 690 | dependencies = [ 691 | "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", 692 | ] 693 | 694 | [[package]] 695 | name = "tempfile" 696 | version = "2.1.4" 697 | source = "registry+https://github.com/rust-lang/crates.io-index" 698 | dependencies = [ 699 | "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 700 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 701 | "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", 702 | "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 703 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 704 | ] 705 | 706 | [[package]] 707 | name = "user32-sys" 708 | version = "0.1.2" 709 | source = "registry+https://github.com/rust-lang/crates.io-index" 710 | dependencies = [ 711 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 712 | "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 713 | ] 714 | 715 | [[package]] 716 | name = "user32-sys" 717 | version = "0.2.0" 718 | source = "registry+https://github.com/rust-lang/crates.io-index" 719 | dependencies = [ 720 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 721 | "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 722 | ] 723 | 724 | [[package]] 725 | name = "wayland-client" 726 | version = "0.5.12" 727 | source = "registry+https://github.com/rust-lang/crates.io-index" 728 | dependencies = [ 729 | "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 730 | "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", 731 | "dlib 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 732 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 733 | "wayland-scanner 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", 734 | "wayland-sys 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", 735 | ] 736 | 737 | [[package]] 738 | name = "wayland-kbd" 739 | version = "0.3.6" 740 | source = "registry+https://github.com/rust-lang/crates.io-index" 741 | dependencies = [ 742 | "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 743 | "dlib 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 744 | "lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", 745 | "memmap 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 746 | "wayland-client 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)", 747 | ] 748 | 749 | [[package]] 750 | name = "wayland-scanner" 751 | version = "0.5.11" 752 | source = "registry+https://github.com/rust-lang/crates.io-index" 753 | dependencies = [ 754 | "xml-rs 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", 755 | ] 756 | 757 | [[package]] 758 | name = "wayland-sys" 759 | version = "0.5.11" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | dependencies = [ 762 | "dlib 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 763 | "lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", 764 | ] 765 | 766 | [[package]] 767 | name = "wayland-window" 768 | version = "0.2.3" 769 | source = "registry+https://github.com/rust-lang/crates.io-index" 770 | dependencies = [ 771 | "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", 772 | "tempfile 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 773 | "wayland-client 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)", 774 | ] 775 | 776 | [[package]] 777 | name = "winapi" 778 | version = "0.2.8" 779 | source = "registry+https://github.com/rust-lang/crates.io-index" 780 | 781 | [[package]] 782 | name = "winapi-build" 783 | version = "0.1.1" 784 | source = "registry+https://github.com/rust-lang/crates.io-index" 785 | 786 | [[package]] 787 | name = "windows-error" 788 | version = "1.0.0" 789 | source = "registry+https://github.com/rust-lang/crates.io-index" 790 | dependencies = [ 791 | "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 792 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 793 | ] 794 | 795 | [[package]] 796 | name = "x11" 797 | version = "2.8.0" 798 | source = "registry+https://github.com/rust-lang/crates.io-index" 799 | dependencies = [ 800 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 801 | "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 802 | ] 803 | 804 | [[package]] 805 | name = "x11-dl" 806 | version = "2.8.0" 807 | source = "registry+https://github.com/rust-lang/crates.io-index" 808 | dependencies = [ 809 | "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 810 | "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 811 | "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 812 | ] 813 | 814 | [[package]] 815 | name = "xml-rs" 816 | version = "0.3.4" 817 | source = "registry+https://github.com/rust-lang/crates.io-index" 818 | dependencies = [ 819 | "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 820 | ] 821 | 822 | [metadata] 823 | "checksum android_glue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e2b80445d331077679dfc6f3014f3e9ab7083e588423d35041d3fc017198189" 824 | "checksum atk-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "52dba8b14510e6d21395f6176396993782f8d1097a7b56bda448213a745311fd" 825 | "checksum backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "346d7644f0b5f9bc73082d3b2236b69a05fd35cce0cfa3724e184e6a5c9e2a2f" 826 | "checksum backtrace-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ff73785ae8e06bb4a7b09e09f06d7434f9748b86d2f67bdf334b603354497e08" 827 | "checksum bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "32866f4d103c4e438b1db1158aa1b1a80ee078e5d77a59a2f906fd62a577389c" 828 | "checksum bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dead7461c1127cf637931a1e50934eb6eee8bff2f74433ac7909e9afcee04a3" 829 | "checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23" 830 | "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" 831 | "checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" 832 | "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" 833 | "checksum c_vec 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "aa9e1d9f7d49e289f36f19effbf3d5a5e30163ecf9c7a3c9be94d5374dec5b9a" 834 | "checksum cairo-rs 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7897ceda29077c3d87f2d46a0f23ed6c552e48e8d1943ac755f8956f81a8a20d" 835 | "checksum cairo-sys-rs 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e43dcd461d0b014b01443cbda24684e88060e462a757a732e30309bb5fa26c9e" 836 | "checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c" 837 | "checksum cgl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8bdd78cca65a739cb5475dbf6b6bbb49373e327f4a6f2b499c0f98632df38c10" 838 | "checksum clipboard 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "811169a9ffda99ed1841a6db3c48cffbab9a9101376f77fee3c14a7581ab933d" 839 | "checksum clipboard-win 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "238830bd83336a8620cbc1d6edf6b9222f45a2c52d02c164348fb6b466277b21" 840 | "checksum cocoa 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3afe4613f57a171039a98db1773f5840b5743cf85aaf03afb65ddfade4f4a9db" 841 | "checksum core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "20a6d0448d3a99d977ae4a2aa5a98d886a923e863e81ad9ff814645b6feb3bbd" 842 | "checksum core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "05eed248dc504a5391c63794fe4fb64f46f071280afaa1b73308f3c0ce4574c5" 843 | "checksum core-graphics 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0c56c6022ba22aedbaa7d231be545778becbe1c7aceda4c82ba2f2084dd4c723" 844 | "checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97" 845 | "checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" 846 | "checksum dlib 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8bd015f00d33d7e4ff66f1589fb824ccf3ccb10209b66c7b756f26ba9aa90215" 847 | "checksum dtoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd841b58510c9618291ffa448da2e4e0f699d984d436122372f446dae62263d" 848 | "checksum dwmapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07c4c7cc7b396419bc0a4d90371d0cee16cb5053b53647d287c0b728000c41fe" 849 | "checksum freetype-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eccfb6d96cac99921f0c2142a91765f6c219868a2c45bdfe7d65a08775f18127" 850 | "checksum fs2 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bcd414e5a1a979b931bb92f41b7a54106d3f6d2e6c253e9ce943b7cd468251ef" 851 | "checksum gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "91ecd03771effb0c968fd6950b37e89476a578aaf1c70297d8e92b6516ec3312" 852 | "checksum gdi32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "65256ec4dc2592e6f05bfc1ca3b956a4e0698aa90b1dff1f5687d55a5a3fd59a" 853 | "checksum gdk 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dbdd6a10d03581c2de537ad016f33522476091c05094ad9cf2e284985eb7d208" 854 | "checksum gdk-pixbuf 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c4fd94e8cb37a8e25f84dd18b574a5d54823da3e8a9fe9b0adc154c77ca5c98" 855 | "checksum gdk-pixbuf-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4db256fec7cfbb3ec00e45096a67b676dc255d5cdeb10770b8f0137932ec0944" 856 | "checksum gdk-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dce70d89e26b1b97a9ea580ef1f9d08a75b8623627a8452821c9357fc57fafbe" 857 | "checksum gio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7ac814c79b301903e2f43428d26497c5d58fc1f34f4376d6f8a12bb296612a47" 858 | "checksum gio-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f858f0e536ce876868583a3a8df1025832d76567897da7f8ad860851eff3" 859 | "checksum gl_generator 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1d8edc81c5ae84605a62f5dac661a2313003b26d59839f81d47d46cf0f16a55" 860 | "checksum gleam 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "2c41f3a5972e6a8796d70fdc37787bcbfedc6e06385eea0937f64324f5819061" 861 | "checksum glib 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bf2e0735d142ea9c5f29b1df3cfe1f818be83acd5f639a4c5516c70807574b53" 862 | "checksum glib-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "512bc05befa05ae5fa84470205bae44d60c2209d95921d1a605e96f2f6578ac7" 863 | "checksum glium 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30bfe6ac8600d25f7f2a1e3203566b156d66e7c2f358f6bb79b5419ddaecd671" 864 | "checksum glutin 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "87dbcee0682bd1bc09b584f80c43a90f960213601ddfb69882a24756839c606d" 865 | "checksum gobject-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70a2806ba2978a5072660797bc76c06ebf1b29dd7f857c6b485ac33423677529" 866 | "checksum gtk 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f4d3d0f046cb1473bfe9e6fbcc8478a5cbab07cfb21495734a37c9d8cd463dc7" 867 | "checksum gtk-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91d0e8c624c3b4e8047b960b350b208c82e2eb0d4e3db5da9a55590c10f2616d" 868 | "checksum itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3088ea4baeceb0284ee9eea42f591226e6beaecf65373e41b38d95a1b8e7a1" 869 | "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" 870 | "checksum khronos_api 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "09c9d3760673c427d46f91a0350f0a84a52e6bc5a84adf26dc610b6c52436630" 871 | "checksum lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "cf186d1a8aa5f5bee5fd662bc9c1b949e0259e1bcc379d1f006847b0080c7417" 872 | "checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f" 873 | "checksum libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "23e3757828fa702a20072c37ff47938e9dd331b92fac6e223d26d4b7a55f7ee2" 874 | "checksum libloading 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "eceb2637ee9a27c7f19764048a9f377e40e3a70a322722f348e6bc7704d565f2" 875 | "checksum libz-sys 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "40f2df7730b5d29426c3e44ce4d088d8c5def6471c2c93ba98585b89fb201ce6" 876 | "checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054" 877 | "checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" 878 | "checksum memmap 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f20f72ed93291a72e22e8b16bb18762183bb4943f0f483da5b8be1a9e8192752" 879 | "checksum num-traits 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "8359ea48994f253fa958b5b90b013728b06f54872e5a58bce39540fcdd0f2527" 880 | "checksum objc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7c9311aa5acd7bee14476afa0f0557f564e9d0d61218a8b833d9b1f871fa5fba" 881 | "checksum objc-foundation 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" 882 | "checksum objc_id 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e4730aa1c64d722db45f7ccc4113a3e2c465d018de6db4d3e7dfe031e8c8a297" 883 | "checksum osmesa-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b0040392971435cdab6bb52f0d4dc2fbb959c90b4263bec33af6ef092f8f828d" 884 | "checksum pango 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9163a579a31a3a07023f8ac47a27b62d3f59fae058f37993ec2815afaeb6d4d9" 885 | "checksum pango-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d4e9d57dc8bb3a28b59d9339b13f67c456238921d82c3ae8eefd1ac815247b" 886 | "checksum pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8cee804ecc7eaf201a4a207241472cc870e825206f6c031e3ee2a72fa425f2fa" 887 | "checksum rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2791d88c6defac799c3f20d74f094ca33b9332612d9aef9078519c82e4fe04a5" 888 | "checksum rustc-demangle 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c4c2d35b2ed94cec4fad26a36eee4d6eff394ce70a8ceea064b0b6ca42ea4cf0" 889 | "checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" 890 | "checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" 891 | "checksum serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)" = "1b0e0732aa8ec4267f61815a396a942ba3525062e3bd5520aa8419927cfc0a92" 892 | "checksum serde 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9e1979331bc87240ef63a5cd79c69cced8261185d9ca5647ae357f17eaef16f4" 893 | "checksum serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e10f8a9d94b06cf5d3bef66475f04c8ff90950f1be7004c357ff9472ccbaebc" 894 | "checksum shared_library 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fb04126b6fcfd2710fb5b6d18f4207b6c535f2850a7e1a43bcd526d44f30a79a" 895 | "checksum shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72f20b8f3c060374edb8046591ba28f62448c369ccbdc7b02075103fb3a9e38d" 896 | "checksum smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fcc8d19212aacecf95e4a7a2179b26f7aeb9732a915cf01f05b0d3e044865410" 897 | "checksum target_build_utils 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a1be18d4d908e4e5697908de04fdd5099505463fc8eaf1ceb8133ae486936aa" 898 | "checksum tempfile 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9270837a93bad1b1dac18fe67e786b3c960513af86231f6f4f57fddd594ff0c8" 899 | "checksum user32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6717129de5ac253f5642fc78a51d0c7de6f9f53d617fc94e9bae7f6e71cf5504" 900 | "checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47" 901 | "checksum wayland-client 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ced3094c157b5cc0a08d40530e1a627d9f88b9a436971338d2646439128a559e" 902 | "checksum wayland-kbd 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "73bc10e84c1da90777beffecd24742baea17564ffc2a9918af41871c748eb050" 903 | "checksum wayland-scanner 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "5a1869370d6bafcbabae8724511d803f4e209a70e94ad94a4249269534364f66" 904 | "checksum wayland-sys 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9633f7fe5de56544215f82eaf1b76bf1b584becf7f08b58cbef4c2c7d10e803a" 905 | "checksum wayland-window 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "309b69d3a863c9c21422d889fb7d98cf02f8a2ca054960a49243ce5b67ad884c" 906 | "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" 907 | "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" 908 | "checksum windows-error 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dfa34b3180ad6b4fe63cbc4fb773da4a83c5b3db8db15789051a4785f2b43e58" 909 | "checksum x11 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bfc828b6baf54ccdde44e0b5f16e035ab9c54f60a0f0c218fb5ddbc6ab38a2a9" 910 | "checksum x11-dl 2.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6acc29bdc98d7565e18dc71b3e933aa94a195d0c2f4ec84f675679d9744b0d6b" 911 | "checksum xml-rs 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "65e74b96bd3179209dc70a980da6df843dff09e46eee103a0376c0949257e3ef" 912 | --------------------------------------------------------------------------------