extern crate egli;
extern crate x11;
extern crate libc;
extern crate gl;
use std::mem;
use egli::{Display, SurfaceType, RenderableType};
fn main() {
println!("This example requires GL, EGL and xlib installed.");
println!("On Ubuntu they are named `libegl1-mesa-dev`, `libx11-dev`.");
let display_and_window = X11DisplayAndWindow::new("Hello EGL", 640, 480);
let egl_display = Display::from_display_id(display_and_window.display as *mut _)
.expect("failed to get EGL display");
println!("Using EGL {}",
egl_display.initialize_and_get_version().expect("failed to initialize"));
let configs = egl_display.config_filter()
.with_red_size(8)
.with_green_size(8)
.with_blue_size(8)
.with_depth_size(24)
.with_surface_type(SurfaceType::WINDOW)
.with_renderable_type(RenderableType::OPENGL)
.choose_configs()
.expect("failed to get configurations");
let first_config = *configs.first()
.expect("no compatible EGL configuration was found");
let surface = egl_display.create_window_surface(first_config,
display_and_window.window as *mut _)
.expect("failed to create window surface");
let context = egl_display.create_context(first_config)
.expect("failed to create OpenGL context");
egl_display.make_current(&surface, &surface, &context)
.expect("make current failed");
gl::load_with(|s| unsafe { mem::transmute(egli::egl::get_proc_address(s)) });
display_and_window.wait_for_close(move || {
unsafe {
gl::ClearColor(0.0, 0.0, 1.0, 1.0);
gl::Clear(gl::COLOR_BUFFER_BIT);
}
egl_display.swap_buffers(&surface)
.expect("failed to swap buffers");
});
}
use std::ffi::CString;
use std::mem::zeroed;
use std::ptr::{null, null_mut};
use std::os::raw::c_uint;
use x11::xlib;
struct X11DisplayAndWindow {
pub window: std::os::raw::c_ulong,
pub display: *mut x11::xlib::Display,
wm_delete_window: std::os::raw::c_ulong,
wm_protocols: std::os::raw::c_ulong,
}
impl X11DisplayAndWindow {
pub fn new(title: &'static str,
default_width: c_uint,
default_height: c_uint)
-> X11DisplayAndWindow {
let window;
let display;
let wm_delete_window;
let wm_protocols;
unsafe {
display = xlib::XOpenDisplay(null());
if display == null_mut() {
panic!("can't open display");
}
let wm_delete_window_str = CString::new("WM_DELETE_WINDOW").unwrap();
let wm_protocols_str = CString::new("WM_PROTOCOLS").unwrap();
wm_delete_window = xlib::XInternAtom(display,
wm_delete_window_str.as_ptr(),
xlib::False);
wm_protocols = xlib::XInternAtom(display, wm_protocols_str.as_ptr(), xlib::False);
if wm_delete_window == 0 || wm_protocols == 0 {
panic!("can't load atoms");
}
let screen_num = xlib::XDefaultScreen(display);
let root = xlib::XRootWindow(display, screen_num);
let white_pixel = xlib::XWhitePixel(display, screen_num);
let mut attributes: xlib::XSetWindowAttributes = zeroed();
attributes.background_pixel = white_pixel;
window = xlib::XCreateWindow(display,
root,
0,
0,
default_width,
default_height,
0,
0,
xlib::InputOutput as c_uint,
null_mut(),
xlib::CWBackPixel,
&mut attributes);
let title_str = CString::new(title).unwrap();
xlib::XStoreName(display, window, title_str.as_ptr() as *mut _);
}
X11DisplayAndWindow {
window: window,
display: display,
wm_delete_window: wm_delete_window,
wm_protocols: wm_protocols,
}
}
pub fn wait_for_close<F>(&self, render: F)
where F: Fn()
{
unsafe {
let mut protocols = [self.wm_delete_window];
if xlib::XSetWMProtocols(self.display,
self.window,
&mut protocols[0] as *mut xlib::Atom,
1) == xlib::False {
panic!("can't set WM protocols");
}
xlib::XMapWindow(self.display, self.window);
let mut event: xlib::XEvent = zeroed();
'main: loop {
while xlib::XPending(self.display) > 0 {
xlib::XNextEvent(self.display, &mut event);
match event.get_type() {
xlib::ClientMessage => {
let xclient: xlib::XClientMessageEvent = From::from(event);
if xclient.message_type == self.wm_protocols && xclient.format == 32 {
let protocol = xclient.data.get_long(0) as xlib::Atom;
if protocol == self.wm_delete_window {
break 'main;
}
}
}
_ => {}
}
}
render();
}
}
}
}
impl Drop for X11DisplayAndWindow {
fn drop(&mut self) {
unsafe {
xlib::XDestroyWindow(self.display, self.window);
xlib::XCloseDisplay(self.display);
}
}
}