<commit_before>//! Collection module for managing Algorithmia Data Collections
//!
//! # Examples
//!
//! ```no_run
//! use algorithmia::Service;
//! use algorithmia::collection::Collection;
//! use std::fs::File;
//!
//! let service = Service::new("111112222233333444445555566");
//! let my_bucket = service.collection("my_user/my_bucket");
//!
//! my_bucket.create();
//! let mut my_file = File::open("/path/to/file").unwrap();
//! my_bucket.upload_file(&mut my_file);
//!
//! my_bucket.write_file("some_filename", "file_contents".as_bytes());
//! ```

extern crate hyper;

use ::{Service, AlgorithmiaError, ApiErrorResponse, API_BASE_URL};
use hyper::Url;
use rustc_serialize::{json, Decoder};
use std::io::Read;
use std::fs::File;

static COLLECTION_BASE_PATH: &'static str = "data";

/// Algorithmia data collection
pub struct Collection<'a> {
    pub service: Service,
    pub path: &'a str,
}

pub type CollectionShowResult = Result<CollectionShow, AlgorithmiaError>;
pub type CollectionCreatedResult = Result<CollectionCreated, AlgorithmiaError>;
pub type CollectionDeletedResult = Result<CollectionDeleted, AlgorithmiaError>;
pub type CollectionFileAddedResult = Result<CollectionFileAdded, AlgorithmiaError>;
pub type CollectionFileDeletedResult = Result<CollectionFileDeleted, AlgorithmiaError>;

/// Permissions for a data collection
#[derive(RustcDecodable, Debug)]
pub struct CollectionAcl {
    /// Readable by world
    pub read_w: bool,
    /// Readable by group
    pub read_g: bool,
    /// Readable by user
    pub read_u: bool,
    /// Readable by user's algorithms regardless who runs them
    pub read_a: bool,
}

/// Response when creating a new collection
#[derive(RustcDecodable, Debug)]
pub struct CollectionCreated {
    pub collection_id: u32,
    pub object_id: String,
    pub collection_name: String,
    pub username: String,
    pub acl: CollectionAcl,
}

/// Response when deleting a new collection
#[derive(RustcDecodable, Debug)]
pub struct CollectionDeleted {
    pub unknown: String,
}

/// Response when querying an existing collection
#[derive(RustcDecodable, Debug)]
pub struct CollectionShow {
    pub username: String,
    pub collection_name: String,
    pub files: Vec<String>,
}

/// Response when adding a file to a collection
#[derive(RustcDecodable, Debug)]
pub struct CollectionFileAdded {
    pub result: String
}

/// Response when deleting a file to a collection
#[derive(RustcDecodable, Debug)]
pub struct CollectionFileDeleted {
    pub result: String
}

impl<'a> Collection<'a> {

    // assert_eq!(collection.dirname(), "anowell");
    // assert_eq!(collection.basename(), "foo");
    pub fn dirname(&self) -> &'a str {
        match &*self.path.rsplitn(1, "/").collect::<Vec<_>>() {
            [_, path] => path,
            _ => "/"
        }
    }

    pub fn basename(&self) -> &'a str {
        match &*self.path.rsplitn(1, "/").collect::<Vec<_>>() {
            [name, _] => name,
            _ => self.path
        }
    }

    /// Get the API Endpoint URL for a particular collection
    pub fn to_url(&self) -> Url {
        let url_string = format!("{}/{}/{}", API_BASE_URL, COLLECTION_BASE_PATH, self.path);
        Url::parse(&*url_string).unwrap()
    }

    /// Display collection details if it exists
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Service;
    /// # use algorithmia::collection::Collection;
    /// let service = Service::new("111112222233333444445555566");
    /// let my_bucket = service.collection("my_user/my_bucket");
    /// match my_bucket.show() {
    ///   Ok(bucket) => println!("Files: {}", bucket.files.connect(", ")),
    ///   Err(e) => println!("ERROR: {:?}", e),
    /// };
    /// ```
    pub fn show(&'a self) -> CollectionShowResult {
        let ref mut api_client = self.service.api_client();
        let req = api_client.get(self.to_url());

        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        match json::decode::<CollectionShow>(&*res_json) {
            Ok(result) => Ok(result),
            Err(why) => match json::decode::<ApiErrorResponse>(&*res_json) {
                Ok(api_error) => Err(AlgorithmiaError::ApiError(api_error.error)),
                Err(_) => Err(AlgorithmiaError::DecoderErrorWithContext(why, res_json)),
            }
        }
    }

    /// Create a collection
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Service;
    /// # use algorithmia::collection::Collection;
    /// let service = Service::new("111112222233333444445555566");
    /// let my_bucket = service.collection("my_user/my_bucket");
    /// match my_bucket.create() {
    ///   Ok(_) => println!("Successfully created collection"),
    ///   Err(e) => println!("ERROR creating collection: {:?}", e),
    /// };
    /// ```
    pub fn create(&'a self) -> CollectionCreatedResult {
        // Construct URL
        let url_string = format!("{}/{}/{}", API_BASE_URL, COLLECTION_BASE_PATH, self.dirname());
        let url = Url::parse(&*url_string).unwrap();

        // POST request
        let ref mut api_client = self.service.api_client();
        let req = api_client.post(url).body(self.basename());

        // Parse response
        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        Service::decode_to_result::<CollectionCreated>(res_json)
    }

    /// Delete a collection
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Service;
    /// # use algorithmia::collection::Collection;
    /// let service = Service::new("111112222233333444445555566");
    /// let my_bucket = service.collection("my_user/my_bucket");
    /// match my_bucket.delete() {
    ///   Ok(_) => println!("Successfully deleted collection"),
    ///   Err(e) => println!("ERROR deleting collection: {:?}", e),
    /// };
    /// ```
    pub fn delete(&'a self) -> CollectionDeletedResult {
        // DELETE request
        let ref mut api_client = self.service.api_client();
        let req = api_client.delete(self.to_url());

        // Parse response
        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        Service::decode_to_result::<CollectionDeleted>(res_json)
    }

    /// Upload a file to an existing collection
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Service;
    /// # use algorithmia::collection::Collection;
    /// # use std::fs::File;
    /// let service = Service::new("111112222233333444445555566");
    /// let my_bucket = service.collection("my_user/my_bucket");
    ///
    /// let mut my_file = File::open("/path/to/file").unwrap();
    /// match my_bucket.upload_file(&mut my_file) {
    ///   Ok(response) => println!("Successfully uploaded to: {}", response.result),
    ///   Err(e) => println!("ERROR uploading file: {:?}", e),
    /// };
    /// ```
    pub fn upload_file(&'a self, file: &mut File) -> CollectionFileAddedResult {
        let url_string = format!("{}/{}",
            self.to_url(),
            file.path().unwrap().file_name().unwrap().to_str().unwrap()
        );
        let url = Url::parse(&*url_string).unwrap();

        let ref mut api_client = self.service.api_client();
        let req = api_client.post(url).body(file);

        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        Service::decode_to_result::<CollectionFileAdded>(res_json)
    }

    /// Write a file (raw bytes) directly to a data collection
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Service;
    /// # use algorithmia::collection::Collection;
    /// let service = Service::new("111112222233333444445555566");
    /// let my_bucket = service.collection("my_user/my_bucket");
    ///
    /// match my_bucket.write_file("some_filename", "file_contents".as_bytes()) {
    ///   Ok(response) => println!("Successfully uploaded to: {}", response.result),
    ///   Err(e) => println!("ERROR uploading file: {:?}", e),
    /// };
    /// ```
    pub fn write_file(&'a self, filename: &str, input_data: &[u8]) -> CollectionFileAddedResult {
        let url_string = format!("{}/{}", self.to_url(), filename);
        let url = Url::parse(&*url_string).unwrap();

        let ref mut api_client = self.service.api_client();
        let req = api_client.post(url).body(&*input_data);

        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        Service::decode_to_result::<CollectionFileAdded>(res_json)
    }

    /// Delete a file from a data collection
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Service;
    /// # use algorithmia::collection::Collection;
    /// let service = Service::new("111112222233333444445555566");
    /// let my_bucket = service.collection("my_user/my_bucket");
    ///
    /// match my_bucket.delete_file("some_filename") {
    ///   Ok(_) => println!("Successfully deleted file"),
    ///   Err(e) => println!("ERROR deleting file: {:?}", e),
    /// };
    /// ```
    pub fn delete_file(&'a self, filename: &str) -> CollectionFileDeletedResult {
        let url_string = format!("{}/{}", self.to_url(), filename);
        let url = Url::parse(&*url_string).unwrap();

        let ref mut api_client = self.service.api_client();
        let req = api_client.delete(url);

        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        Service::decode_to_result::<CollectionFileDeleted>(res_json)
    }

}

#[test]
fn test_to_url() {
    let collection = Collection { path: "anowell/foo", service: Service::new("")};
    assert_eq!(collection.to_url().serialize(), format!("{}/data/anowell/foo", API_BASE_URL));
}
<commit_msg>some doc cleanup<commit_after>//! Collection module for managing Algorithmia Data Collections
//!
//! # Examples
//!
//! ```no_run
//! use algorithmia::Service;
//! use std::fs::File;
//!
//! let service = Service::new("111112222233333444445555566");
//! let my_dir = service.collection("my_user/my_dir");
//!
//! my_dir.create();
//! let mut my_file = File::open("/path/to/file").unwrap();
//! my_dir.upload_file(&mut my_file);
//!
//! my_dir.write_file("some_filename", "file_contents".as_bytes());
//! ```

extern crate hyper;

use ::{Service, AlgorithmiaError, ApiErrorResponse, API_BASE_URL};
use hyper::Url;
use rustc_serialize::{json, Decoder};
use std::io::Read;
use std::fs::File;

static COLLECTION_BASE_PATH: &'static str = "data";

/// Algorithmia data collection
pub struct Collection<'a> {
    pub service: Service,
    pub path: &'a str,
}

pub type CollectionShowResult = Result<CollectionShow, AlgorithmiaError>;
pub type CollectionCreatedResult = Result<CollectionCreated, AlgorithmiaError>;
pub type CollectionDeletedResult = Result<CollectionDeleted, AlgorithmiaError>;
pub type CollectionFileAddedResult = Result<CollectionFileAdded, AlgorithmiaError>;
pub type CollectionFileDeletedResult = Result<CollectionFileDeleted, AlgorithmiaError>;

/// Permissions for a data collection
#[derive(RustcDecodable, Debug)]
pub struct CollectionAcl {
    /// Readable by world
    pub read_w: bool,
    /// Readable by group
    pub read_g: bool,
    /// Readable by user
    pub read_u: bool,
    /// Readable by user's algorithms regardless who runs them
    pub read_a: bool,
}

/// Response when creating a new collection
#[derive(RustcDecodable, Debug)]
pub struct CollectionCreated {
    pub collection_id: u32,
    pub object_id: String,
    pub collection_name: String,
    pub username: String,
    pub acl: CollectionAcl,
}

/// Response when deleting a new collection
#[derive(RustcDecodable, Debug)]
pub struct CollectionDeleted {
    pub unknown: String,
}

/// Response when querying an existing collection
#[derive(RustcDecodable, Debug)]
pub struct CollectionShow {
    pub username: String,
    pub collection_name: String,
    pub files: Vec<String>,
}

/// Response when adding a file to a collection
#[derive(RustcDecodable, Debug)]
pub struct CollectionFileAdded {
    pub result: String
}

/// Response when deleting a file to a collection
#[derive(RustcDecodable, Debug)]
pub struct CollectionFileDeleted {
    pub result: String
}

impl<'a> Collection<'a> {

    /// Get the parent path of a collection (i.e. unix `dirname`)
    ///
    /// ```
    /// # use algorithmia::Service;
    /// # let service = Service::new("111112222233333444445555566");
    /// let my_dir = service.collection("my_user/my_dir");
    /// assert_eq!(my_dir.parent(), "my_user");
    /// ```
    pub fn parent(&self) -> &'a str {
        match &*self.path.rsplitn(1, "/").collect::<Vec<_>>() {
            [_, path] => path,
            _ => "/"
        }
    }

    /// Get the basename of the collection (i.e. unix `basename`)
    ///
    /// ```
    /// # use algorithmia::Service;
    /// # let service = Service::new("111112222233333444445555566");
    /// let my_dir = service.collection("my_user/my_dir");
    /// assert_eq!(my_dir.basename(), "my_dir");
    /// ```
    pub fn basename(&self) -> &'a str {
        match &*self.path.rsplitn(1, "/").collect::<Vec<_>>() {
            [name, _] => name,
            _ => self.path
        }
    }

    /// Get the API Endpoint URL for a particular collection
    pub fn to_url(&self) -> Url {
        let url_string = format!("{}/{}/{}", API_BASE_URL, COLLECTION_BASE_PATH, self.path);
        Url::parse(&*url_string).unwrap()
    }

    /// Display collection details if it exists
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Service;
    /// let service = Service::new("111112222233333444445555566");
    /// let my_dir = service.collection("my_user/my_dir");
    /// match my_dir.show() {
    ///   Ok(dir) => println!("Files: {}", dir.files.connect(", ")),
    ///   Err(e) => println!("ERROR: {:?}", e),
    /// };
    /// ```
    pub fn show(&'a self) -> CollectionShowResult {
        let ref mut api_client = self.service.api_client();
        let req = api_client.get(self.to_url());

        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        match json::decode::<CollectionShow>(&*res_json) {
            Ok(result) => Ok(result),
            Err(why) => match json::decode::<ApiErrorResponse>(&*res_json) {
                Ok(api_error) => Err(AlgorithmiaError::ApiError(api_error.error)),
                Err(_) => Err(AlgorithmiaError::DecoderErrorWithContext(why, res_json)),
            }
        }
    }

    /// Create a collection
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Service;
    /// let service = Service::new("111112222233333444445555566");
    /// let my_dir = service.collection("my_user/my_dir");
    /// match my_dir.create() {
    ///   Ok(_) => println!("Successfully created collection"),
    ///   Err(e) => println!("ERROR creating collection: {:?}", e),
    /// };
    /// ```
    pub fn create(&'a self) -> CollectionCreatedResult {
        // Construct URL
        let url_string = format!("{}/{}/{}", API_BASE_URL, COLLECTION_BASE_PATH, self.parent());
        let url = Url::parse(&*url_string).unwrap();

        // POST request
        let ref mut api_client = self.service.api_client();
        let req = api_client.post(url).body(self.basename());

        // Parse response
        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        Service::decode_to_result::<CollectionCreated>(res_json)
    }

    /// Delete a collection
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Service;
    /// # use algorithmia::collection::Collection;
    /// let service = Service::new("111112222233333444445555566");
    /// let my_dir = service.collection("my_user/my_dir");
    /// match my_dir.delete() {
    ///   Ok(_) => println!("Successfully deleted collection"),
    ///   Err(e) => println!("ERROR deleting collection: {:?}", e),
    /// };
    /// ```
    pub fn delete(&'a self) -> CollectionDeletedResult {
        // DELETE request
        let ref mut api_client = self.service.api_client();
        let req = api_client.delete(self.to_url());

        // Parse response
        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        Service::decode_to_result::<CollectionDeleted>(res_json)
    }

    /// Upload a file to an existing collection
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Service;
    /// # use algorithmia::collection::Collection;
    /// # use std::fs::File;
    /// let service = Service::new("111112222233333444445555566");
    /// let my_dir = service.collection("my_user/my_dir");
    ///
    /// let mut my_file = File::open("/path/to/file").unwrap();
    /// match my_dir.upload_file(&mut my_file) {
    ///   Ok(response) => println!("Successfully uploaded to: {}", response.result),
    ///   Err(e) => println!("ERROR uploading file: {:?}", e),
    /// };
    /// ```
    pub fn upload_file(&'a self, file: &mut File) -> CollectionFileAddedResult {
        let url_string = format!("{}/{}",
            self.to_url(),
            file.path().unwrap().file_name().unwrap().to_str().unwrap()
        );
        let url = Url::parse(&*url_string).unwrap();

        let ref mut api_client = self.service.api_client();
        let req = api_client.post(url).body(file);

        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        Service::decode_to_result::<CollectionFileAdded>(res_json)
    }

    /// Write a file (raw bytes) directly to a data collection
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Service;
    /// # use algorithmia::collection::Collection;
    /// let service = Service::new("111112222233333444445555566");
    /// let my_dir = service.collection("my_user/my_dir");
    ///
    /// match my_dir.write_file("some_filename", "file_contents".as_bytes()) {
    ///   Ok(response) => println!("Successfully uploaded to: {}", response.result),
    ///   Err(e) => println!("ERROR uploading file: {:?}", e),
    /// };
    /// ```
    pub fn write_file(&'a self, filename: &str, input_data: &[u8]) -> CollectionFileAddedResult {
        let url_string = format!("{}/{}", self.to_url(), filename);
        let url = Url::parse(&*url_string).unwrap();

        let ref mut api_client = self.service.api_client();
        let req = api_client.post(url).body(&*input_data);

        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        Service::decode_to_result::<CollectionFileAdded>(res_json)
    }

    /// Delete a file from a data collection
    ///
    /// # Examples
    /// ```no_run
    /// # use algorithmia::Service;
    /// # use algorithmia::collection::Collection;
    /// let service = Service::new("111112222233333444445555566");
    /// let my_dir = service.collection("my_user/my_dir");
    ///
    /// match my_dir.delete_file("some_filename") {
    ///   Ok(_) => println!("Successfully deleted file"),
    ///   Err(e) => println!("ERROR deleting file: {:?}", e),
    /// };
    /// ```
    pub fn delete_file(&'a self, filename: &str) -> CollectionFileDeletedResult {
        let url_string = format!("{}/{}", self.to_url(), filename);
        let url = Url::parse(&*url_string).unwrap();

        let ref mut api_client = self.service.api_client();
        let req = api_client.delete(url);

        let mut res = try!(req.send());
        let mut res_json = String::new();
        try!(res.read_to_string(&mut res_json));

        Service::decode_to_result::<CollectionFileDeleted>(res_json)
    }

}

#[test]
fn test_to_url() {
    let collection = Collection { path: "anowell/foo", service: Service::new("")};
    assert_eq!(collection.to_url().serialize(), format!("{}/data/anowell/foo", API_BASE_URL));
}

#[test]
fn test_parent() {
    let collection = Collection { path: "anowell/foo", service: Service::new("")};
    assert_eq!(collection.parent(), "anowell");
}<|endoftext|>


<commit_before>//! Main entry point to the library.
//! See examples for documentation on how to use this struct.

use libc;
use std::{env, ptr, any::Any, cell::UnsafeCell, ffi::CStr};

use {DataDeviceManager, SurfaceHandle};
use extensions::server_decoration::ServerDecorationManager;
use manager::{InputManager, InputManagerHandler, OutputManager, OutputManagerHandler,
              WlShellManager, WlShellManagerHandler, XdgV6ShellManager, XdgV6ShellManagerHandler};
use render::GenericRenderer;

use wayland_sys::server::{wl_display, wl_event_loop, signal::wl_signal_add, WAYLAND_SERVER_HANDLE};
use wlroots_sys::{wlr_backend, wlr_backend_autocreate, wlr_backend_destroy, wlr_backend_start,
                  wlr_compositor, wlr_compositor_create, wlr_compositor_destroy, wlr_wl_shell,
                  wlr_wl_shell_create, wlr_xdg_shell_v6, wlr_xdg_shell_v6_create};
use wlroots_sys::wayland_server::sys::wl_display_init_shm;

/// Global compositor pointer, used to refer to the compositor state unsafely.
pub static mut COMPOSITOR_PTR: *mut Compositor = 0 as *mut _;

pub trait CompositorHandler {
    /// Callback that's triggered when a surface is provided to the compositor.
    fn new_surface(&mut self, &mut Compositor, &mut SurfaceHandle) {}

    /// Callback that's triggered during shutdown.
    fn on_shutdown(&mut self) {}
}

wayland_listener!(InternalCompositor, Box<CompositorHandler>, [
    new_surface_listener => new_surface_notify: |this: &mut InternalCompositor,
                                                 surface: *mut libc::c_void,|
    unsafe {
        let handler = &mut this.data;
        let compositor = &mut *COMPOSITOR_PTR;
        let mut surface = SurfaceHandle::from_ptr(surface as _);
        handler.new_surface(compositor, &mut surface);
    };
    shutdown_listener => shutdown_notify: |this: &mut InternalCompositor,
                                           _data: *mut libc::c_void,|
    unsafe {
        let handler = &mut this.data;
        assert!(COMPOSITOR_PTR.is_null(), "COMPOSITOR_PTR was not NULL!");
        handler.on_shutdown();
    };
]);

#[allow(dead_code)]
pub struct Compositor {
    terminating: bool,
    /// User data.
    pub data: Box<Any>,
    /// Internal compositor handler
    compositor_handler: Option<Box<InternalCompositor>>,
    /// Manager for the inputs.
    input_manager: Option<Box<InputManager>>,
    /// Manager for the outputs.
    output_manager: Option<Box<OutputManager>>,
    /// Manager for Wayland shells.
    wl_shell_manager: Option<Box<WlShellManager>>,
    /// Manager for XDG shells v6.
    xdg_v6_shell_manager: Option<Box<XdgV6ShellManager>>,
    /// Pointer to wl_shell global.
    /// If wl_shell_manager is `None`, this value will be `NULL`.
    wl_shell_global: *mut wlr_wl_shell,
    /// Pointer to the xdg_shell_v6 global.
    /// If xdg_v6_shell_manager is `None`, this value will be `NULL`.
    xdg_v6_shell_global: *mut wlr_xdg_shell_v6,
    /// Pointer to the wlr_compositor.
    compositor: *mut wlr_compositor,
    /// Pointer to the wlroots backend in use.
    backend: *mut wlr_backend,
    /// Pointer to the wayland display.
    display: *mut wl_display,
    /// Pointer to the event loop.
    event_loop: *mut wl_event_loop,
    /// Shared memory buffer file descriptor.
    shm_fd: i32,
    /// Name of the Wayland socket that we are binding to.
    socket_name: String,
    /// Optional decoration manager extension.
    pub server_decoration_manager: Option<ServerDecorationManager>,
    /// The renderer used to draw things to the screen.
    pub renderer: Option<GenericRenderer>,
    /// The DnD manager
    data_device_manager: Option<DataDeviceManager>,
    /// The error from the panic, if there was one.
    panic_error: Option<Box<Any + Send>>
}

pub struct CompositorBuilder {
    compositor_handler: Option<Box<CompositorHandler>>,
    input_manager_handler: Option<Box<InputManagerHandler>>,
    output_manager_handler: Option<Box<OutputManagerHandler>>,
    wl_shell_manager_handler: Option<Box<WlShellManagerHandler>>,
    xdg_v6_shell_manager_handler: Option<Box<XdgV6ShellManagerHandler>>,
    gles2: bool,
    server_decoration_manager: bool,
    data_device_manager: bool
}

impl CompositorBuilder {
    /// Make a new compositor builder.
    ///
    /// Unless otherwise noted, each option is `false`/`None`.
    pub fn new() -> Self {
        CompositorBuilder { gles2: false,
                            server_decoration_manager: false,
                            data_device_manager: false,
                            compositor_handler: None,
                            input_manager_handler: None,
                            output_manager_handler: None,
                            wl_shell_manager_handler: None,
                            xdg_v6_shell_manager_handler: None }
    }

    /// Set the handler for global compositor callbacks.
    pub fn compositor_handler(mut self, compositor_handler: Box<CompositorHandler>) -> Self {
        self.compositor_handler = Some(compositor_handler);
        self
    }

    /// Set the handler for inputs.
    pub fn input_manager(mut self, input_manager_handler: Box<InputManagerHandler>) -> Self {
        self.input_manager_handler = Some(input_manager_handler);
        self
    }

    /// Set the handler for outputs.
    pub fn output_manager(mut self, output_manager_handler: Box<OutputManagerHandler>) -> Self {
        self.output_manager_handler = Some(output_manager_handler);
        self
    }

    /// Set the handler for Wayland shells.
    pub fn wl_shell_manager(mut self,
                            wl_shell_manager_handler: Box<WlShellManagerHandler>)
                            -> Self {
        self.wl_shell_manager_handler = Some(wl_shell_manager_handler);
        self
    }

    /// Set the handler for xdg v6 shells.
    pub fn xdg_shell_v6_manager(mut self,
                                xdg_v6_shell_manager_handler: Box<XdgV6ShellManagerHandler>)
                                -> Self {
        self.xdg_v6_shell_manager_handler = Some(xdg_v6_shell_manager_handler);
        self
    }

    /// Decide whether or not to enable the data device manager.
    ///
    /// This is used to do DnD, or "drag 'n drop" copy paste.
    pub fn data_device(mut self, data_device_manager: bool) -> Self {
        self.data_device_manager = data_device_manager;
        self
    }

    /// Decide whether or not to enable the GLES2 extension.
    pub fn gles2(mut self, gles2_renderer: bool) -> Self {
        self.gles2 = gles2_renderer;
        self
    }

    /// Decide whether or not to enable the server decoration manager protocol
    /// extension.
    pub fn server_decoration_manager(mut self, server_decoration_manager: bool) -> Self {
        self.server_decoration_manager = server_decoration_manager;
        self
    }

    /// Makes a new compositor that handles the setup of the graphical backend
    /// (e.g, Wayland, X11, or DRM).
    ///
    /// Also automatically opens the socket for clients to communicate to the
    /// compositor with.
    pub fn build_auto<D>(self, data: D) -> Compositor
        where D: Any + 'static
    {
        unsafe {
            let display =
                ffi_dispatch!(WAYLAND_SERVER_HANDLE, wl_display_create,) as *mut wl_display;
            let event_loop =
                ffi_dispatch!(WAYLAND_SERVER_HANDLE, wl_display_get_event_loop, display);
            let backend = wlr_backend_autocreate(display as *mut _);
            if backend.is_null() {
                // NOTE Rationale for panicking:
                // * Won't be in C land just yet, so it's safe to panic
                // * Can always be returned in a Result instead, but for now
                //   if you auto create it's assumed you can't recover.
                panic!("Could not auto-create backend");
            }
            // Set up shared memory buffer for Wayland clients.
            let shm_fd = wl_display_init_shm(display as *mut _);
            // Create optional extensions.
            let server_decoration_manager = if self.server_decoration_manager {
                ServerDecorationManager::new(display)
            } else {
                None
            };
            let data_device_manager = if self.data_device_manager {
                DataDeviceManager::new(display as _)
            } else {
                None
            };
            let compositor;
            let renderer = if self.gles2 {
                let gles2 = GenericRenderer::gles2_renderer(backend);
                // Set up wlr_compositor
                let gles2_ptr = gles2.as_ptr();
                compositor = wlr_compositor_create(display as *mut _, gles2_ptr);
                Some(gles2)
            } else {
                compositor = wlr_compositor_create(display as *mut _, ptr::null_mut());
                None
            };

            // Set up compositor handler, if the user provided it.
            let compositor_handler = self.compositor_handler.map(|handler| {
                let mut compositor_handler = InternalCompositor::new(handler);
                wl_signal_add(&mut (*compositor).events.new_surface as *mut _ as _,
                              compositor_handler.new_surface_listener() as *mut _ as _);
                wl_signal_add(&mut (*compositor).events.destroy as *mut _ as _,
                              compositor_handler.shutdown_listener() as *mut _ as _);
                compositor_handler
            });

            // Set up input manager, if the user provided it.
            let input_manager = self.input_manager_handler.map(|handler| {
                let mut input_manager = InputManager::new((vec![], handler));
                wl_signal_add(&mut (*backend).events.new_input as *mut _ as _,
                              input_manager.add_listener() as *mut _ as _);
                input_manager
            });

            // Set up output manager, if the user provided it.
            let output_manager = self.output_manager_handler.map(|handler| {
                let mut output_manager = OutputManager::new((vec![], handler));
                wl_signal_add(&mut (*backend).events.new_output as *mut _ as _,
                              output_manager.add_listener() as *mut _ as _);
                output_manager
            });

            // Set up wl_shell handler and associated Wayland global,
            // if user provided a manager for it.
            let mut wl_shell_global = ptr::null_mut();
            let wl_shell_manager = self.wl_shell_manager_handler.map(|handler| {
                wl_shell_global = wlr_wl_shell_create(display as *mut _);
                let mut wl_shell_manager = WlShellManager::new(handler);
                wl_signal_add(&mut (*wl_shell_global).events.new_surface as *mut _ as _,
                              wl_shell_manager.add_listener() as *mut _ as _);
                wl_shell_manager
            });

            // Set up the xdg_shell_v6 handler and associated Wayland global,
            // if user provided a manager for it.
            let mut xdg_v6_shell_global = ptr::null_mut();
            let xdg_v6_shell_manager = self.xdg_v6_shell_manager_handler.map(|handler| {
                xdg_v6_shell_global = wlr_xdg_shell_v6_create(display as *mut _);
                let mut xdg_v6_shell_manager = XdgV6ShellManager::new((vec![], handler));
                wl_signal_add(&mut (*xdg_v6_shell_global).events.new_surface as *mut _ as _,
                              xdg_v6_shell_manager.add_listener() as *mut _ as _);
                xdg_v6_shell_manager
            });

            // Open the socket to the Wayland server.
            let socket = ffi_dispatch!(WAYLAND_SERVER_HANDLE, wl_display_add_socket_auto, display);
            if socket.is_null() {
                // NOTE Rationale for panicking:
                // * Won't be in C land just yet, so it's safe to panic
                // * Can always be returned in a Result instead, but for now
                //   if you auto create it's assumed you can't recover.
                panic!("Unable to open wayland socket");
            }
            let socket_name = CStr::from_ptr(socket).to_string_lossy().into_owned();
            wlr_log!(L_DEBUG,
                     "Running compositor on wayland display {}",
                     socket_name);
            env::set_var("_WAYLAND_DISPLAY", socket_name.clone());
            Compositor { data: Box::new(data),
                         terminating: false,
                         compositor_handler,
                         socket_name,
                         input_manager,
                         output_manager,
                         wl_shell_manager,
                         wl_shell_global,
                         xdg_v6_shell_manager,
                         xdg_v6_shell_global,
                         data_device_manager,
                         compositor,
                         backend,
                         display,
                         event_loop,
                         shm_fd,
                         server_decoration_manager,
                         renderer,
                         panic_error: None }
        }
    }
}

impl Compositor {
    /// Enters the wayland event loop. Won't return until the compositor is
    /// shut off
    pub fn run(self) {
        unsafe {
            let compositor = UnsafeCell::new(self);
            if COMPOSITOR_PTR != 0 as _ {
                // NOTE Rationale for panicking:
                // * Nicer than an abort
                // * Not yet in C land
                panic!("A compositor is already running!")
            }
            COMPOSITOR_PTR = compositor.get();
            wlr_log!(L_INFO, "Starting compositor");
            if !wlr_backend_start((*compositor.get()).backend) {
                wlr_backend_destroy((*compositor.get()).backend);
                // NOTE Rationale for panicking:
                // * Won't be in C land just yet, so it's safe to panic
                // * Can always be returned in a Result instead, but for now
                //   if you auto create it's assumed you can't recover.
                panic!("Failed to start backend");
            }
            env::set_var("WAYLAND_DISPLAY", (*COMPOSITOR_PTR).socket_name.clone());
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_display_run,
                          (*compositor.get()).display);
            if (*compositor.get()).terminating {
                return
            }
            match (*compositor.get()).panic_error.take() {
                None => {}
                Some(err) => {
                    // A panic occured, now we can re-throw it safely.
                    ::std::panic::resume_unwind(err)
                }
            }
        }
    }

    pub fn terminate(&mut self) -> ! {
        unsafe {
            self.terminating = true;
            COMPOSITOR_PTR = 0 as _;
            ffi_dispatch!(WAYLAND_SERVER_HANDLE, wl_display_terminate, self.display);
            panic!("terminating gracefully");
        }
    }

    pub unsafe fn display(&self) -> *mut wl_display {
        self.display
    }

    pub unsafe fn event_loop(&self) -> *mut wl_event_loop {
        self.event_loop
    }

    /// Saves the panic error information in the compositor, to be re-thrown
    /// later when we are out of the C callback stack.
    pub(crate) fn save_panic_error(&mut self, error: Box<Any + Send>) {
        self.panic_error = Some(error);
    }
}

impl Drop for Compositor {
    fn drop(&mut self) {
        unsafe { wlr_compositor_destroy(self.compositor) }
    }
}

/// Terminates the compositor.
/// If one is not running, does nothing
pub fn terminate() {
    unsafe {
        if COMPOSITOR_PTR != 0 as _ {
            (*COMPOSITOR_PTR).terminate();
        }
    }
}
<commit_msg>Don't set global pointer to null during shutdown<commit_after>//! Main entry point to the library.
//! See examples for documentation on how to use this struct.

use libc;
use std::{env, ptr, any::Any, cell::UnsafeCell, ffi::CStr};

use {DataDeviceManager, SurfaceHandle};
use extensions::server_decoration::ServerDecorationManager;
use manager::{InputManager, InputManagerHandler, OutputManager, OutputManagerHandler,
              WlShellManager, WlShellManagerHandler, XdgV6ShellManager, XdgV6ShellManagerHandler};
use render::GenericRenderer;

use wayland_sys::server::{wl_display, wl_event_loop, signal::wl_signal_add, WAYLAND_SERVER_HANDLE};
use wlroots_sys::{wlr_backend, wlr_backend_autocreate, wlr_backend_destroy, wlr_backend_start,
                  wlr_compositor, wlr_compositor_create, wlr_compositor_destroy, wlr_wl_shell,
                  wlr_wl_shell_create, wlr_xdg_shell_v6, wlr_xdg_shell_v6_create};
use wlroots_sys::wayland_server::sys::wl_display_init_shm;

/// Global compositor pointer, used to refer to the compositor state unsafely.
pub static mut COMPOSITOR_PTR: *mut Compositor = 0 as *mut _;

pub trait CompositorHandler {
    /// Callback that's triggered when a surface is provided to the compositor.
    fn new_surface(&mut self, &mut Compositor, &mut SurfaceHandle) {}

    /// Callback that's triggered during shutdown.
    fn on_shutdown(&mut self) {}
}

wayland_listener!(InternalCompositor, Box<CompositorHandler>, [
    new_surface_listener => new_surface_notify: |this: &mut InternalCompositor,
                                                 surface: *mut libc::c_void,|
    unsafe {
        let handler = &mut this.data;
        let compositor = &mut *COMPOSITOR_PTR;
        let mut surface = SurfaceHandle::from_ptr(surface as _);
        handler.new_surface(compositor, &mut surface);
    };
    shutdown_listener => shutdown_notify: |this: &mut InternalCompositor,
                                           _data: *mut libc::c_void,|
    unsafe {
        let handler = &mut this.data;
        assert!(COMPOSITOR_PTR.is_null(), "COMPOSITOR_PTR was not NULL!");
        handler.on_shutdown();
    };
]);

#[allow(dead_code)]
pub struct Compositor {
    /// User data.
    pub data: Box<Any>,
    /// Internal compositor handler
    compositor_handler: Option<Box<InternalCompositor>>,
    /// Manager for the inputs.
    input_manager: Option<Box<InputManager>>,
    /// Manager for the outputs.
    output_manager: Option<Box<OutputManager>>,
    /// Manager for Wayland shells.
    wl_shell_manager: Option<Box<WlShellManager>>,
    /// Manager for XDG shells v6.
    xdg_v6_shell_manager: Option<Box<XdgV6ShellManager>>,
    /// Pointer to wl_shell global.
    /// If wl_shell_manager is `None`, this value will be `NULL`.
    wl_shell_global: *mut wlr_wl_shell,
    /// Pointer to the xdg_shell_v6 global.
    /// If xdg_v6_shell_manager is `None`, this value will be `NULL`.
    xdg_v6_shell_global: *mut wlr_xdg_shell_v6,
    /// Pointer to the wlr_compositor.
    compositor: *mut wlr_compositor,
    /// Pointer to the wlroots backend in use.
    backend: *mut wlr_backend,
    /// Pointer to the wayland display.
    display: *mut wl_display,
    /// Pointer to the event loop.
    event_loop: *mut wl_event_loop,
    /// Shared memory buffer file descriptor.
    shm_fd: i32,
    /// Name of the Wayland socket that we are binding to.
    socket_name: String,
    /// Optional decoration manager extension.
    pub server_decoration_manager: Option<ServerDecorationManager>,
    /// The renderer used to draw things to the screen.
    pub renderer: Option<GenericRenderer>,
    /// The DnD manager
    data_device_manager: Option<DataDeviceManager>,
    /// The error from the panic, if there was one.
    panic_error: Option<Box<Any + Send>>
}

pub struct CompositorBuilder {
    compositor_handler: Option<Box<CompositorHandler>>,
    input_manager_handler: Option<Box<InputManagerHandler>>,
    output_manager_handler: Option<Box<OutputManagerHandler>>,
    wl_shell_manager_handler: Option<Box<WlShellManagerHandler>>,
    xdg_v6_shell_manager_handler: Option<Box<XdgV6ShellManagerHandler>>,
    gles2: bool,
    server_decoration_manager: bool,
    data_device_manager: bool
}

impl CompositorBuilder {
    /// Make a new compositor builder.
    ///
    /// Unless otherwise noted, each option is `false`/`None`.
    pub fn new() -> Self {
        CompositorBuilder { gles2: false,
                            server_decoration_manager: false,
                            data_device_manager: false,
                            compositor_handler: None,
                            input_manager_handler: None,
                            output_manager_handler: None,
                            wl_shell_manager_handler: None,
                            xdg_v6_shell_manager_handler: None }
    }

    /// Set the handler for global compositor callbacks.
    pub fn compositor_handler(mut self, compositor_handler: Box<CompositorHandler>) -> Self {
        self.compositor_handler = Some(compositor_handler);
        self
    }

    /// Set the handler for inputs.
    pub fn input_manager(mut self, input_manager_handler: Box<InputManagerHandler>) -> Self {
        self.input_manager_handler = Some(input_manager_handler);
        self
    }

    /// Set the handler for outputs.
    pub fn output_manager(mut self, output_manager_handler: Box<OutputManagerHandler>) -> Self {
        self.output_manager_handler = Some(output_manager_handler);
        self
    }

    /// Set the handler for Wayland shells.
    pub fn wl_shell_manager(mut self,
                            wl_shell_manager_handler: Box<WlShellManagerHandler>)
                            -> Self {
        self.wl_shell_manager_handler = Some(wl_shell_manager_handler);
        self
    }

    /// Set the handler for xdg v6 shells.
    pub fn xdg_shell_v6_manager(mut self,
                                xdg_v6_shell_manager_handler: Box<XdgV6ShellManagerHandler>)
                                -> Self {
        self.xdg_v6_shell_manager_handler = Some(xdg_v6_shell_manager_handler);
        self
    }

    /// Decide whether or not to enable the data device manager.
    ///
    /// This is used to do DnD, or "drag 'n drop" copy paste.
    pub fn data_device(mut self, data_device_manager: bool) -> Self {
        self.data_device_manager = data_device_manager;
        self
    }

    /// Decide whether or not to enable the GLES2 extension.
    pub fn gles2(mut self, gles2_renderer: bool) -> Self {
        self.gles2 = gles2_renderer;
        self
    }

    /// Decide whether or not to enable the server decoration manager protocol
    /// extension.
    pub fn server_decoration_manager(mut self, server_decoration_manager: bool) -> Self {
        self.server_decoration_manager = server_decoration_manager;
        self
    }

    /// Makes a new compositor that handles the setup of the graphical backend
    /// (e.g, Wayland, X11, or DRM).
    ///
    /// Also automatically opens the socket for clients to communicate to the
    /// compositor with.
    pub fn build_auto<D>(self, data: D) -> Compositor
        where D: Any + 'static
    {
        unsafe {
            let display =
                ffi_dispatch!(WAYLAND_SERVER_HANDLE, wl_display_create,) as *mut wl_display;
            let event_loop =
                ffi_dispatch!(WAYLAND_SERVER_HANDLE, wl_display_get_event_loop, display);
            let backend = wlr_backend_autocreate(display as *mut _);
            if backend.is_null() {
                // NOTE Rationale for panicking:
                // * Won't be in C land just yet, so it's safe to panic
                // * Can always be returned in a Result instead, but for now
                //   if you auto create it's assumed you can't recover.
                panic!("Could not auto-create backend");
            }
            // Set up shared memory buffer for Wayland clients.
            let shm_fd = wl_display_init_shm(display as *mut _);
            // Create optional extensions.
            let server_decoration_manager = if self.server_decoration_manager {
                ServerDecorationManager::new(display)
            } else {
                None
            };
            let data_device_manager = if self.data_device_manager {
                DataDeviceManager::new(display as _)
            } else {
                None
            };
            let compositor;
            let renderer = if self.gles2 {
                let gles2 = GenericRenderer::gles2_renderer(backend);
                // Set up wlr_compositor
                let gles2_ptr = gles2.as_ptr();
                compositor = wlr_compositor_create(display as *mut _, gles2_ptr);
                Some(gles2)
            } else {
                compositor = wlr_compositor_create(display as *mut _, ptr::null_mut());
                None
            };

            // Set up compositor handler, if the user provided it.
            let compositor_handler = self.compositor_handler.map(|handler| {
                let mut compositor_handler = InternalCompositor::new(handler);
                wl_signal_add(&mut (*compositor).events.new_surface as *mut _ as _,
                              compositor_handler.new_surface_listener() as *mut _ as _);
                wl_signal_add(&mut (*compositor).events.destroy as *mut _ as _,
                              compositor_handler.shutdown_listener() as *mut _ as _);
                compositor_handler
            });

            // Set up input manager, if the user provided it.
            let input_manager = self.input_manager_handler.map(|handler| {
                let mut input_manager = InputManager::new((vec![], handler));
                wl_signal_add(&mut (*backend).events.new_input as *mut _ as _,
                              input_manager.add_listener() as *mut _ as _);
                input_manager
            });

            // Set up output manager, if the user provided it.
            let output_manager = self.output_manager_handler.map(|handler| {
                let mut output_manager = OutputManager::new((vec![], handler));
                wl_signal_add(&mut (*backend).events.new_output as *mut _ as _,
                              output_manager.add_listener() as *mut _ as _);
                output_manager
            });

            // Set up wl_shell handler and associated Wayland global,
            // if user provided a manager for it.
            let mut wl_shell_global = ptr::null_mut();
            let wl_shell_manager = self.wl_shell_manager_handler.map(|handler| {
                wl_shell_global = wlr_wl_shell_create(display as *mut _);
                let mut wl_shell_manager = WlShellManager::new(handler);
                wl_signal_add(&mut (*wl_shell_global).events.new_surface as *mut _ as _,
                              wl_shell_manager.add_listener() as *mut _ as _);
                wl_shell_manager
            });

            // Set up the xdg_shell_v6 handler and associated Wayland global,
            // if user provided a manager for it.
            let mut xdg_v6_shell_global = ptr::null_mut();
            let xdg_v6_shell_manager = self.xdg_v6_shell_manager_handler.map(|handler| {
                xdg_v6_shell_global = wlr_xdg_shell_v6_create(display as *mut _);
                let mut xdg_v6_shell_manager = XdgV6ShellManager::new((vec![], handler));
                wl_signal_add(&mut (*xdg_v6_shell_global).events.new_surface as *mut _ as _,
                              xdg_v6_shell_manager.add_listener() as *mut _ as _);
                xdg_v6_shell_manager
            });

            // Open the socket to the Wayland server.
            let socket = ffi_dispatch!(WAYLAND_SERVER_HANDLE, wl_display_add_socket_auto, display);
            if socket.is_null() {
                // NOTE Rationale for panicking:
                // * Won't be in C land just yet, so it's safe to panic
                // * Can always be returned in a Result instead, but for now
                //   if you auto create it's assumed you can't recover.
                panic!("Unable to open wayland socket");
            }
            let socket_name = CStr::from_ptr(socket).to_string_lossy().into_owned();
            wlr_log!(L_DEBUG,
                     "Running compositor on wayland display {}",
                     socket_name);
            env::set_var("_WAYLAND_DISPLAY", socket_name.clone());
            Compositor { data: Box::new(data),
                         compositor_handler,
                         socket_name,
                         input_manager,
                         output_manager,
                         wl_shell_manager,
                         wl_shell_global,
                         xdg_v6_shell_manager,
                         xdg_v6_shell_global,
                         data_device_manager,
                         compositor,
                         backend,
                         display,
                         event_loop,
                         shm_fd,
                         server_decoration_manager,
                         renderer,
                         panic_error: None }
        }
    }
}

impl Compositor {
    /// Enters the wayland event loop. Won't return until the compositor is
    /// shut off
    pub fn run(self) {
        unsafe {
            let compositor = UnsafeCell::new(self);
            if COMPOSITOR_PTR != 0 as _ {
                // NOTE Rationale for panicking:
                // * Nicer than an abort
                // * Not yet in C land
                panic!("A compositor is already running!")
            }
            COMPOSITOR_PTR = compositor.get();
            wlr_log!(L_INFO, "Starting compositor");
            if !wlr_backend_start((*compositor.get()).backend) {
                wlr_backend_destroy((*compositor.get()).backend);
                // NOTE Rationale for panicking:
                // * Won't be in C land just yet, so it's safe to panic
                // * Can always be returned in a Result instead, but for now
                //   if you auto create it's assumed you can't recover.
                panic!("Failed to start backend");
            }
            env::set_var("WAYLAND_DISPLAY", (*COMPOSITOR_PTR).socket_name.clone());
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_display_run,
                          (*compositor.get()).display);
            match (*compositor.get()).panic_error.take() {
                None => {}
                Some(err) => {
                    // A panic occured, now we can re-throw it safely.
                    ::std::panic::resume_unwind(err)
                }
            }
        }
    }

    pub fn terminate(&mut self) {
        unsafe {
            ffi_dispatch!(WAYLAND_SERVER_HANDLE, wl_display_terminate, self.display);
        }
    }

    pub unsafe fn display(&self) -> *mut wl_display {
        self.display
    }

    pub unsafe fn event_loop(&self) -> *mut wl_event_loop {
        self.event_loop
    }

    /// Saves the panic error information in the compositor, to be re-thrown
    /// later when we are out of the C callback stack.
    pub(crate) fn save_panic_error(&mut self, error: Box<Any + Send>) {
        self.panic_error = Some(error);
    }
}

impl Drop for Compositor {
    fn drop(&mut self) {
        unsafe { wlr_compositor_destroy(self.compositor) }
    }
}

/// Terminates the compositor.
/// If one is not running, does nothing
pub fn terminate() {
    unsafe {
        if COMPOSITOR_PTR != 0 as _ {
            (*COMPOSITOR_PTR).terminate();
        }
    }
}
<|endoftext|>


<commit_before>static START_ADDR: u16 = 0x200;
static MEM_SIZE: uint = 4096;
pub static DISPLAY_WIDTH: uint = 64;
pub static DISPLAY_HEIGHT: uint = 32;

static fontset: [[u8, .. 5], .. 0x10] = [
    [0xF0, 0x90, 0x90, 0x90, 0xF0], // 0
    [0x20, 0x60, 0x20, 0x20, 0x70], // 1
    [0xF0, 0x10, 0xF0, 0x80, 0xF0], // 2
    [0xF0, 0x10, 0xF0, 0x10, 0xF0], // 3
    [0x90, 0x90, 0xF0, 0x10, 0x10], // 4
    [0xF0, 0x80, 0xF0, 0x10, 0xF0], // 5
    [0xF0, 0x80, 0xF0, 0x90, 0xF0], // 6
    [0xF0, 0x10, 0x20, 0x40, 0x40], // 7
    [0xF0, 0x90, 0xF0, 0x90, 0xF0], // 8
    [0xF0, 0x90, 0xF0, 0x10, 0xF0], // 9
    [0xF0, 0x90, 0xF0, 0x90, 0x90], // A
    [0xE0, 0x90, 0xE0, 0x90, 0xE0], // B
    [0xF0, 0x80, 0x80, 0x80, 0xF0], // C
    [0xE0, 0x90, 0x90, 0x90, 0xE0], // D
    [0xF0, 0x80, 0xF0, 0x80, 0xF0], // E
    [0xF0, 0x80, 0xF0, 0x80, 0x80], // F
];

pub struct Chip8 {
    ram: [u8, .. MEM_SIZE],
    v: [u8, .. 16],
    i: u16,
    delay_timer: u8,
    sound_timer: u8,
    pc: u16,
    sp: u8,
    stack: [u16, .. 16],
    display: [u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT]
}

impl Chip8 {
    pub fn new() -> Chip8 {
        Chip8 {
            ram: [0u8, .. MEM_SIZE],
            v: [0u8, .. 16],
            i: 0u16,
            delay_timer: 0u8,
            sound_timer: 0u8,
            pc: START_ADDR,
            sp: 0,
            stack: [0u16, .. 16],
            display: [0u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT]
        }
    }

    pub fn load_rom(&mut self, rom: &[u8]) {
        use std::slice::bytes::copy_memory;
        let len = self.ram.len();
        copy_memory(self.ram.mut_slice(START_ADDR as uint, len), rom);
    }

    pub fn get_display(&self) -> [u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT] {
        self.display
    }

    pub fn do_cycle(&mut self) {
        let ins = self.get_ins();

        match ins & 0xF000 {
            0x1000 => self.jump_addr(ins & 0x0FFF),
            0x3000 => self.skip_next_vx_eq(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0x7000 => self.add_vx_byte(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0xA000 => self.set_i(ins & 0x0FFF),
            0xC000 => self.set_vx_rand_and(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0xD000 => self.display_sprite(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint, ((ins & 0x000F)) as uint),
            _ => fail!("Unkown instruction: {:x}", ins)
        }

        self.pc += 2;
    }

    fn get_ins(&self) -> u16 {
        let b1 = self.ram[self.pc as uint];
        let b2 = self.ram[(self.pc + 1) as uint];
        b1 as u16 << 8 | b2 as u16
    }

    fn set_i(&mut self, to: u16) {
        self.i = to;
    }

    fn set_vx_rand_and(&mut self, x: uint, to: u8) {
        use std::rand::{task_rng, Rng};
        let mut rgen = task_rng();
        self.v[x] = rgen.gen::<u8>() & to;
    }

    fn skip_next_vx_eq(&mut self, x: uint, to: u8) {
        if self.v[x] == to {
            self.pc += 2;
        }
    }

    fn display_sprite(&mut self, x: uint, y: uint, n: uint) {
        let bytes = self.ram.slice(self.i as uint, self.i as uint + n);
        let start = y * DISPLAY_WIDTH + x;
        let mut i = 0;

        for b in bytes.iter() {
            let before = self.display[start + i];
            self.display[start + i] ^= *b;

            if before != 0 && self.display[start + i] == 0 {
                self.v[0xf] = 1;
            } else {
                self.v[0xf] = 0;
            }

            i += 1;
        }
    }

    fn add_vx_byte(&mut self, x: uint, byte: u8) {
        self.v[x] = byte;
    }

    fn jump_addr(&mut self, addr: u16) {
        self.pc = addr;
    }
}
<commit_msg>Increment PC before handling instructions and improve sprite drawing<commit_after>static START_ADDR: u16 = 0x200;
static MEM_SIZE: uint = 4096;
pub static DISPLAY_WIDTH: uint = 64;
pub static DISPLAY_HEIGHT: uint = 32;

static fontset: [[u8, .. 5], .. 0x10] = [
    [0xF0, 0x90, 0x90, 0x90, 0xF0], // 0
    [0x20, 0x60, 0x20, 0x20, 0x70], // 1
    [0xF0, 0x10, 0xF0, 0x80, 0xF0], // 2
    [0xF0, 0x10, 0xF0, 0x10, 0xF0], // 3
    [0x90, 0x90, 0xF0, 0x10, 0x10], // 4
    [0xF0, 0x80, 0xF0, 0x10, 0xF0], // 5
    [0xF0, 0x80, 0xF0, 0x90, 0xF0], // 6
    [0xF0, 0x10, 0x20, 0x40, 0x40], // 7
    [0xF0, 0x90, 0xF0, 0x90, 0xF0], // 8
    [0xF0, 0x90, 0xF0, 0x10, 0xF0], // 9
    [0xF0, 0x90, 0xF0, 0x90, 0x90], // A
    [0xE0, 0x90, 0xE0, 0x90, 0xE0], // B
    [0xF0, 0x80, 0x80, 0x80, 0xF0], // C
    [0xE0, 0x90, 0x90, 0x90, 0xE0], // D
    [0xF0, 0x80, 0xF0, 0x80, 0xF0], // E
    [0xF0, 0x80, 0xF0, 0x80, 0x80], // F
];

pub struct Chip8 {
    ram: [u8, .. MEM_SIZE],
    v: [u8, .. 16],
    i: u16,
    delay_timer: u8,
    sound_timer: u8,
    pc: u16,
    sp: u8,
    stack: [u16, .. 16],
    display: [u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT]
}

impl Chip8 {
    pub fn new() -> Chip8 {
        Chip8 {
            ram: [0u8, .. MEM_SIZE],
            v: [0u8, .. 16],
            i: 0u16,
            delay_timer: 0u8,
            sound_timer: 0u8,
            pc: START_ADDR,
            sp: 0,
            stack: [0u16, .. 16],
            display: [0u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT]
        }
    }

    pub fn load_rom(&mut self, rom: &[u8]) {
        use std::slice::bytes::copy_memory;
        let len = self.ram.len();
        copy_memory(self.ram.mut_slice(START_ADDR as uint, len), rom);
    }

    pub fn get_display(&self) -> [u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT] {
        self.display
    }

    pub fn do_cycle(&mut self) {
        let ins = self.get_ins();
        self.pc += 2;

        match ins & 0xF000 {
            0x1000 => self.jump_addr(ins & 0x0FFF),
            0x3000 => self.skip_next_vx_eq(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0x7000 => self.add_vx_byte(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0xA000 => self.set_i(ins & 0x0FFF),
            0xC000 => self.set_vx_rand_and(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0xD000 => self.display_sprite(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint, ((ins & 0x000F)) as uint),
            _ => fail!("Unkown instruction: {:x}", ins)
        }
    }

    fn get_ins(&self) -> u16 {
        let b1 = self.ram[self.pc as uint];
        let b2 = self.ram[(self.pc + 1) as uint];
        b1 as u16 << 8 | b2 as u16
    }

    fn set_i(&mut self, to: u16) {
        self.i = to;
    }

    fn set_vx_rand_and(&mut self, x: uint, to: u8) {
        use std::rand::{task_rng, Rng};
        let mut rgen = task_rng();
        self.v[x] = rgen.gen::<u8>() & to;
    }

    fn skip_next_vx_eq(&mut self, x: uint, to: u8) {
        if self.v[x] == to {
            self.pc += 2;
        }
    }

    fn display_sprite(&mut self, vx: uint, vy: uint, n: uint) {
        let offset = self.v[vx] as uint + (self.v[vy] as uint * DISPLAY_WIDTH);
        println!("n={}", n);

        for y in range(0u, n) {
            let b = self.ram[self.i as uint + y];
            for x in range(0u, 8) {
                self.display[offset + (y * DISPLAY_WIDTH) + x] ^= b & (1 << x);
            }
        }
    }

    fn add_vx_byte(&mut self, x: uint, byte: u8) {
        self.v[x] = byte;
    }

    fn jump_addr(&mut self, addr: u16) {
        self.pc = addr;
    }
}
<|endoftext|>


<commit_before>use ::monet::glium::{DisplayBuild, glutin};
use kay::{ActorSystem, ID, Individual, Recipient, Fate};
use descartes::{N, P2, P3, V3, Into2d, Shape};
use ::monet::{Renderer, Scene, GlutinFacade, MoveEye};
use ::monet::glium::glutin::{Event, MouseScrollDelta, ElementState, MouseButton};
pub use ::monet::glium::glutin::{VirtualKeyCode};
use core::geometry::AnyShape;
use ::std::collections::HashMap;

pub struct UserInterface {
    interactables_2d: HashMap<ID, (AnyShape, usize)>,
    interactables_3d: HashMap<ID, (AnyShape, usize)>,
    cursor_2d: P2,
    cursor_3d: P3,
    drag_start_2d: Option<P2>,
    drag_start_3d: Option<P3>,
    hovered_interactable: Option<ID>,
    active_interactable: Option<ID>,
    focused_interactable: Option<ID>,
    space_pressed: bool,
    shift_pressed: bool
}
impl Individual for UserInterface{}

impl UserInterface{
    fn new() -> UserInterface {
        UserInterface {
            interactables_2d: HashMap::new(),
            interactables_3d: HashMap::new(),
            cursor_2d: P2::new(0.0, 0.0),
            cursor_3d: P3::new(0.0, 0.0, 0.0),
            drag_start_2d: None,
            drag_start_3d: None,
            hovered_interactable: None,
            active_interactable: None,
            focused_interactable: None,
            space_pressed: false,
            shift_pressed: false
        }
    }
}

#[derive(Compact, Clone)]
pub enum Add{Interactable2d(ID, AnyShape, usize), Interactable3d(ID, AnyShape, usize)}

impl Recipient<Add> for UserInterface {
    fn receive(&mut self, msg: &Add) -> Fate {match *msg{
        Add::Interactable2d(_id, ref _shape, _z_index) => unimplemented!(),
        Add::Interactable3d(id, ref shape, z_index) => {
            self.interactables_3d.insert(id, (shape.clone(), z_index));
            Fate::Live
        }
    }}
}

#[derive(Copy, Clone)]
pub enum Remove{Interactable2d(ID), Interactable3d(ID)}

impl Recipient<Remove> for UserInterface {
    fn receive(&mut self, msg: &Remove) -> Fate {match *msg{
        Remove::Interactable2d(_id) => unimplemented!(),
        Remove::Interactable3d(id) => {
            self.interactables_3d.remove(&id);
            Fate::Live
        }
    }}
}

#[derive(Copy, Clone)]
pub struct Focus(pub ID);

impl Recipient<Focus> for UserInterface {
    fn receive(&mut self, msg: &Focus) -> Fate {match *msg{
        Focus(id) => {
            self.focused_interactable = Some(id);
            Fate::Live
        }
    }}
}

#[derive(Copy, Clone)]
enum Mouse{Moved(P2), Scrolled(P2), Down, Up}

use ::monet::Project2dTo3d;

#[derive(Copy, Clone)]
pub enum Event3d{
    DragStarted{at: P3},
    DragOngoing{from: P3, to: P3},
    DragFinished{from: P3, to: P3},
    DragAborted,
    HoverStarted{at: P3},
    HoverOngoing{at: P3},
    HoverStopped,
    KeyDown(VirtualKeyCode),
    KeyUp(VirtualKeyCode)
}

impl Recipient<Mouse> for UserInterface {
    fn receive(&mut self, msg: &Mouse) -> Fate {match *msg{
        Mouse::Moved(position) => {
            let delta = self.cursor_2d - position;
            if self.space_pressed {
                if self.shift_pressed {
                    Renderer::id() << MoveEye{scene_id: 0, movement: ::monet::Movement::Rotate(-delta.x/300.0)};
                    Renderer::id() << MoveEye{scene_id: 0, movement: ::monet::Movement::Zoom(-delta.y)};
                    self.cursor_2d = position;
                } else {
                    Renderer::id() << MoveEye{scene_id: 0, movement: ::monet::Movement::Shift(V3::new(-delta.y / 3.0, delta.x / 3.0, 0.0))};
                    self.cursor_2d = position;
                }
            } else {
                self.cursor_2d = position;
                Renderer::id() << Project2dTo3d{
                    scene_id: 0,
                    position_2d: position,
                    requester: Self::id()
                };
            }
            Fate::Live
        },
        Mouse::Scrolled(delta) => {
            Renderer::id() << MoveEye{scene_id: 0, movement: ::monet::Movement::Shift(V3::new(delta.y / 5.0, -delta.x / 5.0, 0.0))};
            Fate::Live
        },
        Mouse::Down => {
            self.drag_start_2d = Some(self.cursor_2d);
            self.drag_start_3d = Some(self.cursor_3d);
            let cursor_3d = self.cursor_3d;
            self.receive(&Projected3d{position_3d: cursor_3d});
            self.active_interactable = self.hovered_interactable;
            if let Some(active_interactable) = self.active_interactable{
                active_interactable << Event3d::DragStarted{at: self.cursor_3d};
            }
            Fate::Live
        },
        Mouse::Up => {
            if let Some(active_interactable) = self.active_interactable {
                active_interactable << Event3d::DragFinished{
                    from: self.drag_start_3d.expect("active interactable but no drag start"),
                    to: self.cursor_3d
                };
            }
            self.drag_start_2d = None;
            self.drag_start_3d = None;
            self.active_interactable = None;
            Fate::Live
        }
    }}
}

#[derive(Copy, Clone)]
enum Key{Up(VirtualKeyCode), Down(VirtualKeyCode)}

impl Recipient<Key> for UserInterface {
    fn receive(&mut self, msg: &Key) -> Fate {match *msg {
        Key::Down(key_code) => {
            match key_code {
                VirtualKeyCode::Space => {
                    self.space_pressed = true;
                },
                VirtualKeyCode::LShift | VirtualKeyCode::RShift => {
                    self.shift_pressed = true;
                },
                _ => {}
            }
            self.focused_interactable.map(|interactable|
                interactable << Event3d::KeyDown(key_code)
            );
            Fate::Live
        },
        Key::Up(key_code) => {
            match key_code {
                VirtualKeyCode::Space => {
                    self.space_pressed = false;
                },
                VirtualKeyCode::LShift | VirtualKeyCode::RShift => {
                    self.shift_pressed = false;
                },
                _ => {}
            }
            self.focused_interactable.map(|interactable|
                interactable << Event3d::KeyUp(key_code)
            );
            Fate::Live
        }
    }}
}

use ::monet::Projected3d;

impl Recipient<Projected3d> for UserInterface {
    fn receive(&mut self, msg: &Projected3d) -> Fate {match *msg{
        Projected3d{position_3d} => {
            self.cursor_3d = position_3d;
            if let Some(active_interactable) = self.active_interactable {
                active_interactable << Event3d::DragOngoing{
                    from: self.drag_start_3d.expect("active interactable but no drag start"),
                    to: position_3d
                };
            } else {
                let new_hovered_interactable = self.interactables_3d.iter().filter(|&(_id, &(ref shape, _z_index))|
                    shape.contains(position_3d.into_2d())
                ).max_by_key(|&(_id, &(ref _shape, z_index))|
                    z_index
                ).map(|(id, _shape)| *id);

                if self.hovered_interactable != new_hovered_interactable {
                    if let Some(previous) = self.hovered_interactable {
                        previous << Event3d::HoverStopped;
                    }
                    if let Some(next) = new_hovered_interactable {
                        next << Event3d::HoverStarted{at: self.cursor_3d};
                    }
                } else if let Some(hovered_interactable) = self.hovered_interactable {
                    hovered_interactable << Event3d::HoverOngoing{at: self.cursor_3d};
                }
                self.hovered_interactable = new_hovered_interactable;
            }
            Fate::Live
        }
    }}
}

pub fn setup_window_and_renderer(system: &mut ActorSystem, renderables: Vec<ID>) -> GlutinFacade {
    let window = glutin::WindowBuilder::new()
        .with_title("Citybound".to_string())
        .with_dimensions(1024, 512)
        .with_multitouch()
        .with_vsync().build_glium().unwrap();

    let ui = UserInterface::new();

    system.add_individual(ui);
    system.add_inbox::<Add, UserInterface>();
    system.add_inbox::<Remove, UserInterface>();
    system.add_inbox::<Focus, UserInterface>();
    system.add_unclearable_inbox::<Mouse, UserInterface>();
    system.add_unclearable_inbox::<Key, UserInterface>();
    system.add_unclearable_inbox::<Projected3d, UserInterface>();

    let mut renderer = Renderer::new(window.clone());
    let mut scene = Scene::new();
    scene.eye.position *= 30.0;
    scene.renderables = renderables;
    renderer.scenes.insert(0, scene);

    ::monet::setup(system, renderer);

    window
}

pub fn process_events(window: &GlutinFacade) -> bool {
    let mut cleaned_events = window.poll_events().collect::<Vec<_>>();
    if let Some(last_mouse_move_event_pos) = cleaned_events.iter().rposition(|event| match *event { Event::MouseMoved(..) => true, _ => false}) {
        let mut i = 0;
        cleaned_events.retain(|event| {
            let keep = match *event {
                Event::MouseMoved(..) => i == last_mouse_move_event_pos,
                _ => true
            };
            i += 1;
            keep
        });
    }
    for event in cleaned_events {
        match event {
            Event::Closed => return false,
            Event::MouseWheel(MouseScrollDelta::PixelDelta(x, y), _) =>
                UserInterface::id() << Mouse::Scrolled(P2::new(x as N, y as N)),
            Event::MouseMoved(x, y) =>
                UserInterface::id() << Mouse::Moved(P2::new(x as N, y as N)),
            Event::MouseInput(ElementState::Pressed, MouseButton::Left) =>
                UserInterface::id() << Mouse::Down,
            Event::MouseInput(ElementState::Released, MouseButton::Left) =>
                UserInterface::id() << Mouse::Up,
            Event::KeyboardInput(ElementState::Pressed, _, Some(key_code)) =>
                UserInterface::id() << Key::Down(key_code),
            Event::KeyboardInput(ElementState::Released, _, Some(key_code)) =>
                UserInterface::id() << Key::Up(key_code),
            _ => {}
        }
    }
    true
}<commit_msg>Changed camera controls to a more traditional RTS style<commit_after>use ::monet::glium::{DisplayBuild, glutin};
use kay::{ActorSystem, ID, Individual, Recipient, Fate};
use descartes::{N, P2, P3, V3, Into2d, Shape};
use ::monet::{Renderer, Scene, GlutinFacade, MoveEye};
use ::monet::glium::glutin::{Event, MouseScrollDelta, ElementState, MouseButton};
pub use ::monet::glium::glutin::{VirtualKeyCode};
use core::geometry::AnyShape;
use ::std::collections::HashMap;

#[derive(Copy, Clone)]
enum Mouse {
    Moved(P2),
    Scrolled(P2),
    Down(MouseButton),
    Up(MouseButton),
}

pub struct InputState {
    forward: bool,
    backward: bool,

    left: bool,
    right: bool,

    rotate_mod: bool,
    pan_mod: bool,

    mouse: Vec<Mouse>,
}

impl InputState {
    fn new() -> InputState {
        InputState {
            forward: false,
            backward: false,
            left: false,
            right: false,

            rotate_mod: false,
            pan_mod: false,

            mouse: vec![],
        }
    }
}

pub struct UserInterface {
    interactables_2d: HashMap<ID, (AnyShape, usize)>,
    interactables_3d: HashMap<ID, (AnyShape, usize)>,
    cursor_2d: P2,
    cursor_3d: P3,
    drag_start_2d: Option<P2>,
    drag_start_3d: Option<P3>,
    hovered_interactable: Option<ID>,
    active_interactable: Option<ID>,
    focused_interactable: Option<ID>,
    input_state: InputState,
}

impl Individual for UserInterface {}

impl UserInterface {
    fn new() -> UserInterface {
        UserInterface {
            interactables_2d: HashMap::new(),
            interactables_3d: HashMap::new(),
            cursor_2d: P2::new(0.0, 0.0),
            cursor_3d: P3::new(0.0, 0.0, 0.0),
            drag_start_2d: None,
            drag_start_3d: None,
            hovered_interactable: None,
            active_interactable: None,
            focused_interactable: None,
            input_state: InputState::new(),
        }
    }
}

#[derive(Compact, Clone)]
pub enum Add {
    Interactable2d(ID, AnyShape, usize),
    Interactable3d(ID, AnyShape, usize)
}

impl Recipient<Add> for UserInterface {
    fn receive(&mut self, msg: &Add) -> Fate {
        match *msg {
            Add::Interactable2d(_id, ref _shape, _z_index) => unimplemented!(),
            Add::Interactable3d(id, ref shape, z_index) => {
                self.interactables_3d.insert(id, (shape.clone(), z_index));
                Fate::Live
            }
        }
    }
}

#[derive(Copy, Clone)]
pub enum Remove {
    Interactable2d(ID),
    Interactable3d(ID)
}

impl Recipient<Remove> for UserInterface {
    fn receive(&mut self, msg: &Remove) -> Fate {
        match *msg {
            Remove::Interactable2d(_id) => unimplemented!(),
            Remove::Interactable3d(id) => {
                self.interactables_3d.remove(&id);
                Fate::Live
            }
        }
    }
}

#[derive(Copy, Clone)]
pub struct Focus(pub ID);

impl Recipient<Focus> for UserInterface {
    fn receive(&mut self, msg: &Focus) -> Fate {
        match *msg {
            Focus(id) => {
                self.focused_interactable = Some(id);
                Fate::Live
            }
        }
    }
}

use ::monet::Project2dTo3d;

#[derive(Copy, Clone)]
pub enum Event3d {
    DragStarted {
        at: P3
    },
    DragOngoing {
        from: P3,
        to: P3
    },
    DragFinished {
        from: P3,
        to: P3
    },
    DragAborted,
    HoverStarted {
        at: P3
    },
    HoverOngoing {
        at: P3
    },
    HoverStopped,
    KeyDown(VirtualKeyCode),
    KeyUp(VirtualKeyCode)
}

impl Recipient<Mouse> for UserInterface {
    fn receive(&mut self, msg: &Mouse) -> Fate {
        self.input_state.mouse.push(*msg);
        match *msg {
            Mouse::Down(MouseButton::Middle) => self.input_state.rotate_mod = true,
            Mouse::Up(MouseButton::Middle) => self.input_state.rotate_mod = false,
            _ => ()
        }
        Fate::Live
    }
}

#[derive(Copy, Clone)]
enum Key {
    Up(VirtualKeyCode),
    Down(VirtualKeyCode)
}

impl Recipient<Key> for UserInterface {
    fn receive(&mut self, msg: &Key) -> Fate {
        match *msg {
            Key::Down(key_code) => {
                match key_code {
                    VirtualKeyCode::W => {
                        self.input_state.forward = true;
                    },
                    VirtualKeyCode::S => {
                        self.input_state.backward = true;
                    },
                    VirtualKeyCode::A => {
                        self.input_state.left = true;
                    },
                    VirtualKeyCode::D => {
                        self.input_state.right = true;
                    },

                    VirtualKeyCode::LShift | VirtualKeyCode::RShift => {
                        self.input_state.pan_mod = true;
                    },
                    _ => {}
                }
                self.focused_interactable.map(|interactable|
                    interactable << Event3d::KeyDown(key_code)
                );
                Fate::Live
            },
            Key::Up(key_code) => {
                match key_code {
                    VirtualKeyCode::W => {
                        self.input_state.forward = false;
                    },
                    VirtualKeyCode::S => {
                        self.input_state.backward = false;
                    },
                    VirtualKeyCode::A => {
                        self.input_state.left = false;
                    },
                    VirtualKeyCode::D => {
                        self.input_state.right = false;
                    },

                    VirtualKeyCode::LShift | VirtualKeyCode::RShift => {
                        self.input_state.pan_mod = false;
                    },
                    _ => {}
                }
                self.focused_interactable.map(|interactable|
                    interactable << Event3d::KeyUp(key_code)
                );
                Fate::Live
            }
        }
    }
}

use ::monet::Projected3d;

impl Recipient<Projected3d> for UserInterface {
    fn receive(&mut self, msg: &Projected3d) -> Fate {
        match *msg {
            Projected3d { position_3d } => {
                self.cursor_3d = position_3d;
                if let Some(active_interactable) = self.active_interactable {
                    active_interactable << Event3d::DragOngoing {
                        from: self.drag_start_3d.expect("active interactable but no drag start"),
                        to: position_3d
                    };
                } else {
                    let new_hovered_interactable = self.interactables_3d.iter().filter(|&(_id, &(ref shape, _z_index))|
                        shape.contains(position_3d.into_2d())
                    ).max_by_key(|&(_id, &(ref _shape, z_index))|
                        z_index
                    ).map(|(id, _shape)| *id);

                    if self.hovered_interactable != new_hovered_interactable {
                        if let Some(previous) = self.hovered_interactable {
                            previous << Event3d::HoverStopped;
                        }
                        if let Some(next) = new_hovered_interactable {
                            next << Event3d::HoverStarted { at: self.cursor_3d };
                        }
                    } else if let Some(hovered_interactable) = self.hovered_interactable {
                        hovered_interactable << Event3d::HoverOngoing { at: self.cursor_3d };
                    }
                    self.hovered_interactable = new_hovered_interactable;
                }
                Fate::Live
            }
        }
    }
}

#[derive(Copy, Clone)]
struct UIUpdate;

impl Recipient<UIUpdate> for UserInterface {
    fn receive(&mut self, msg: &UIUpdate) -> Fate {
        for mouse_action in &self.input_state.mouse.clone() {
            match *mouse_action {
                Mouse::Moved(position) => {
                    let delta = self.cursor_2d - position;
                    if self.input_state.rotate_mod {
                        Renderer::id() << MoveEye { scene_id: 0, movement: ::monet::Movement::Rotate(-delta.x / 300.0) };
                        self.cursor_2d = position;
                    } else if self.input_state.pan_mod {
                        Renderer::id() << MoveEye { scene_id: 0, movement: ::monet::Movement::Shift(V3::new(-delta.y / 3.0, delta.x / 3.0, 0.0)) };
                        self.cursor_2d = position;
                    } else {
                        self.cursor_2d = position;
                        Renderer::id() << Project2dTo3d {
                            scene_id: 0,
                            position_2d: position,
                            requester: Self::id()
                        };
                    }
                },
                Mouse::Scrolled(delta) => {
                    Renderer::id() << MoveEye{scene_id: 0, movement: ::monet::Movement::Zoom(delta.y)};
                },
                Mouse::Down(MouseButton::Left) => {
                    self.drag_start_2d = Some(self.cursor_2d);
                    self.drag_start_3d = Some(self.cursor_3d);
                    let cursor_3d = self.cursor_3d;
                    self.receive(&Projected3d { position_3d: cursor_3d });
                    self.active_interactable = self.hovered_interactable;
                    if let Some(active_interactable) = self.active_interactable {
                        active_interactable << Event3d::DragStarted { at: self.cursor_3d };
                    }
                },
                Mouse::Up(MouseButton::Left) => {
                    if let Some(active_interactable) = self.active_interactable {
                        active_interactable << Event3d::DragFinished {
                            from: self.drag_start_3d.expect("active interactable but no drag start"),
                            to: self.cursor_3d
                        };
                    }
                    self.drag_start_2d = None;
                    self.drag_start_3d = None;
                    self.active_interactable = None;
                },
                _ => ()
            }
        }
        if self.input_state.forward {
            Renderer::id() << MoveEye { scene_id: 0, movement: ::monet::Movement::Shift(V3::new(5.0, 0.0, 0.0))};
        }
        if self.input_state.backward {
            Renderer::id() << MoveEye { scene_id: 0, movement: ::monet::Movement::Shift(V3::new(-5.0, 0.0, 0.0))};
        }
        if self.input_state.left {
            Renderer::id() << MoveEye { scene_id: 0, movement: ::monet::Movement::Shift(V3::new(0.0, -5.0, 0.0))};
        }
        if self.input_state.right {
            Renderer::id() << MoveEye { scene_id: 0, movement: ::monet::Movement::Shift(V3::new(0.0, 5.0, 0.0))};
        }

        self.input_state.mouse.clear();
        Fate::Live
    }
}

pub fn setup_window_and_renderer(system: &mut ActorSystem, renderables: Vec<ID>) -> GlutinFacade {
    let window = glutin::WindowBuilder::new()
        .with_title("Citybound".to_string())
        .with_dimensions(1024, 512)
        .with_multitouch()
        .with_vsync().build_glium().unwrap();

    let ui = UserInterface::new();

    system.add_individual(ui);
    system.add_inbox::<Add, UserInterface>();
    system.add_inbox::<Remove, UserInterface>();
    system.add_inbox::<Focus, UserInterface>();
    system.add_unclearable_inbox::<Mouse, UserInterface>();
    system.add_unclearable_inbox::<Key, UserInterface>();
    system.add_unclearable_inbox::<UIUpdate, UserInterface>();
    system.add_unclearable_inbox::<Projected3d, UserInterface>();

    let mut renderer = Renderer::new(window.clone());
    let mut scene = Scene::new();
    scene.eye.position *= 30.0;
    scene.renderables = renderables;
    renderer.scenes.insert(0, scene);

    ::monet::setup(system, renderer);

    window
}

pub fn process_events(window: &GlutinFacade) -> bool {
    for event in window.poll_events().collect::<Vec<_>>() {
        match event {
            Event::Closed => return false,
            Event::MouseWheel(delta, _) => {
                UserInterface::id() << Mouse::Scrolled(match delta{
                    MouseScrollDelta::LineDelta(x, y) => P2::new(x * 50 as N, y * 50 as N),
                    MouseScrollDelta::PixelDelta(x, y) => P2::new(x as N, y as N)
                })
            },
            Event::MouseMoved(x, y) =>
                UserInterface::id() << Mouse::Moved(P2::new(x as N, y as N)),
            Event::MouseInput(ElementState::Pressed, button) =>
                UserInterface::id() << Mouse::Down(button),
            Event::MouseInput(ElementState::Released, button) =>
                UserInterface::id() << Mouse::Up(button),
            Event::KeyboardInput(ElementState::Pressed, _, Some(key_code)) =>
                UserInterface::id() << Key::Down(key_code),
            Event::KeyboardInput(ElementState::Released, _, Some(key_code)) =>
                UserInterface::id() << Key::Up(key_code),
            _ => {}
        }
    }
    UserInterface::id() << UIUpdate {};
    true
}<|endoftext|>