Skip to content

Instantly share code, notes, and snippets.

@dylanede
Created February 4, 2015 22:51
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dylanede/57d01b60fdff96844fb1 to your computer and use it in GitHub Desktop.
Save dylanede/57d01b60fdff96844fb1 to your computer and use it in GitHub Desktop.
#![feature(os, core)]
extern crate cef;
extern crate glium;
extern crate glutin;
extern crate image;
use std::cell::RefCell;
use std::default::Default;
use std::rc::Rc;
use glium::{DisplayBuild, Surface, Rect, Texture2d, Display, Texture};
use glium::texture::{Texture2dDataSource, RawImage2d, ClientFormat};
use cef::{CefRc, Browser, Void};
struct SharedData {
display: Rc<Display>,
size: (u32, u32),
tex: Option<Texture2d>,//Option<image::ImageBuffer<image::Rgba<u8>, Vec<u8>>>,
changed: bool
}
struct MyRenderHandler(Rc<RefCell<SharedData>>);
impl cef::RenderHandler for MyRenderHandler {
// This callback notifies CEF of the intended view size
fn get_view_rect(&mut self, _: CefRc<Browser>) -> Option<cef::Rect> {
let shared = self.0.borrow();
Some(cef::Rect { x: 0, y: 0, width: shared.size.0 as i32, height: shared.size.1 as i32 })
}
// On every invalidation of the browser frame
fn on_paint(&mut self,
_: CefRc<Browser>,
_: cef::PaintElementType,
_: &[cef::Rect],
buffer: &[u8], // The current image in BGRA
width: i32, // width
height: i32) { // and height in pixels
let mut shared = self.0.borrow_mut();
shared.changed = true;
let display = shared.display.clone();
struct MyDataSource<'a>(&'a [u8], u32, u32, ClientFormat);
impl<'a, 'b> Texture2dDataSource<'a> for &'b MyDataSource<'a> {
type Data = u8;
fn into_raw(self) -> RawImage2d<'a, u8> {
RawImage2d {
data: ::std::borrow::Cow::Borrowed(self.0),
width: self.1,
height: self.2,
format: self.3
}
}
}
let source = MyDataSource(buffer, width as u32, height as u32, ClientFormat::UB8G8R8A8);
match &mut shared.tex {
&mut Some(ref mut tex) => {
let tex_width = tex.get_width();
let tex_height = tex.get_height().unwrap();
if tex_width == width as u32 && tex_height == height as u32 {
tex.write(
Rect {
left: 0,
bottom: 0,
width: tex_width,
height: tex_height
},
&source);
} else {
*tex = Texture2d::new(&*display, &source);
}
},
x => {
*x = Some(Texture2d::new(&*display, &source));
}
}
}
}
struct MyBrowserClient(Rc<RefCell<SharedData>>);
impl cef::BrowserClient for MyBrowserClient {
// When associated types are fully implemented all of these Void definitions can be removed
type OutContextMenuHandler = Void;
type OutDialogHandler = Void;
type OutDisplayHandler = Void;
type OutDownloadHandler = Void;
type OutDragHandler = Void;
type OutFindHandler = Void;
type OutFocusHandler = Void;
type OutGeolocationHandler = Void;
type OutJSDialogHandler = Void;
type OutKeyboardHandler = Void;
type OutLifeSpanHandler = Void;
type OutLoadHandler = Void;
type OutRequestHandler = Void;
type OutRenderHandler = MyRenderHandler;
fn get_render_handler(&mut self) -> Option<MyRenderHandler> {
Some(MyRenderHandler(self.0.clone()))
}
}
fn main() {
// This is used by helper processes. For more details see the CEF docs.
let result_code = cef::execute_process::<()>(None);
if result_code >= 0 {
std::os::set_exit_status(result_code);
return;
}
let settings = cef::Settings {
log_file: Some("log.log"),
locale: Some("en_GB"),
windowless_rendering_enabled: true,
.. Default::default()
};
if !cef::initialize::<()>(&settings, None) {
panic!("Initialising CEF failed. Please check the log file.")
}
let window_info = cef::WindowInfo {
windowless_rendering_enabled: true,
transparent_painting_enabled: true,
.. Default::default()
};
// Create the window
let display = Rc::new(glutin::WindowBuilder::new()
.with_dimensions(1024, 768)
.with_vsync()
.build_glium()
.unwrap());
let mut mouse_event: cef::MouseEvent = Default::default();
let shared = Rc::new(RefCell::new(SharedData {
display: display.clone(),
size: (1024, 768),
tex: None,
changed: false
}));
let browser = cef::BrowserHost::create_browser_sync(
&window_info, MyBrowserClient(shared.clone()), "http://www.google.com",
&cef::BrowserSettings::new(), None);
'main: loop { // The UI/render loop
let target = display.draw();
// Update the browser
cef::do_message_loop_work(); // <--- shared is only locked by the render handler within this call
{ // This scope limits the RefCell borrow
let mut shared = shared.borrow_mut();
if shared.changed { // Update the texture
// The texture is completely reallocated - this is actually the best for performance.
//browser_texture = glium::Texture2d::new(&*display, shared.buffer.take().unwrap());
shared.changed = false;
}
shared.tex.as_mut().map(|x| {
x.as_surface().fill(&target, glium::uniforms::MagnifySamplerFilter::Linear)
});
}
target.finish();
display.synchronize();
for event in display.poll_events() {
use glutin::MouseButton::*;
use cef::event_flags::*;
use cef::MouseButtonType as MouseButton;
match event {
glutin::Event::Closed => {
browser.get_host().close_browser(false);
cef::do_message_loop_work();
break 'main
},
glutin::Event::Focused(focused) => {
browser.get_host().set_focus(focused);
},
glutin::Event::Resized(w, h) => {
{
let mut shared = shared.borrow_mut();
shared.size = (w, h);
}
browser.get_host().was_resized();
},
glutin::Event::MouseMoved((x, y)) => {
mouse_event.x = x;
mouse_event.y = {shared.borrow().size.1-(y as u32)} as i32;
browser.get_host().send_mouse_move_event(&mouse_event, false);
},
glutin::Event::MouseInput(pressed, button) => {
let pressed = match pressed {
glutin::ElementState::Pressed => true,
glutin::ElementState::Released => false
};
match button {
LeftMouseButton => Some((LEFT_MOUSE_BUTTON, MouseButton::Left)),
RightMouseButton => Some((RIGHT_MOUSE_BUTTON, MouseButton::Right)),
MiddleMouseButton => Some((MIDDLE_MOUSE_BUTTON, MouseButton::Middle)),
OtherMouseButton(..) => None
}.map(|(a, b)| {
browser.get_host().send_mouse_click_event(&mouse_event, b, !pressed, 1);
mouse_event.modifiers.insert(a);
println!("Sent {:?} Down at {}, {}", button, mouse_event.x, mouse_event.y);
});
},
_ => ()
}
}
}
// Important to do this to close helper processes and clean up.
cef::shutdown();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment