<commit_before>// Copyright (c) 2015-2016 Ivo Wetzel

// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
extern crate clock_ticks;

use std::net;
use std::thread;
use std::io::Error;
use std::collections::HashMap;
use std::sync::mpsc::{channel, Receiver, TryRecvError};
use std::net::ToSocketAddrs;
use super::super::{
    Connection, ConnectionID, Config, Handler, Server, Socket, Stats
};

fn precise_time_ms() -> u32 {
    (clock_ticks::precise_time_ns() / 1000000) as u32
}

struct DelayServerHandler {
    pub last_tick_time: u32,
    pub tick_count: u32,
    pub accumulated: u32
}

impl Handler<Server> for DelayServerHandler {

    fn bind(&mut self, _: &mut Server) {
        self.last_tick_time = precise_time_ms();
    }

    fn tick_connections(
        &mut self, server: &mut Server,
        _: &mut HashMap<ConnectionID, Connection>
    ) {

        // Accumulate time so we can check that the artificial delay
        // was correct for by the servers tick loop
        if self.tick_count > 1 {
            self.accumulated += precise_time_ms() - self.last_tick_time;
        }

        self.last_tick_time = precise_time_ms();
        self.tick_count += 1;

        if self.tick_count == 5 {
            server.shutdown().unwrap();
        }

        // Fake some load inside of the tick handler
        let before = precise_time_ms();
        thread::sleep_ms(75);

        // Compensate for slow timers
        let spend = (precise_time_ms() - before) as i32;
        self.accumulated -= spend - 75;

    }

}

struct MockServerStatsHandler {
    pub tick_count: u32,
}

impl Handler<Server> for MockServerStatsHandler {

    fn connect(&mut self, _: &mut Server) {
    }

    fn tick_connections(
        &mut self, server: &mut Server,
        _: &mut HashMap<ConnectionID, Connection>
    ) {

        //conn.send(MessageKind::Instant, b"Hello World".to_vec());
        self.tick_count += 1;

        if self.tick_count == 20 {
            server.shutdown().unwrap();
        }

    }

}

#[test]
fn test_server_tick_delay() {

    let config = Config {
        send_rate: 10,
        .. Config::default()
    };

    let mut handler = DelayServerHandler {
        last_tick_time: 0,
        tick_count: 0,
        accumulated: 0
    };

    let mut server = Server::new(config);
    server.bind(&mut handler, "127.0.0.1:0").unwrap();

    assert!(handler.accumulated <= 350);

}

fn check_messages(conn: &mut Connection) {

    let mut messages = Vec::new();
    for m in conn.received() {
        messages.push(m);
    }

    assert_eq!(messages, [
        [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100].to_vec()

    ].to_vec())

}

struct ConnectionServerHandler {
    pub connection_count: i32
}

impl Handler<Server> for ConnectionServerHandler {

    fn connection(&mut self, _: &mut Server, _: &mut Connection) {
        self.connection_count += 1;
    }

    fn tick_connections(
        &mut self, server: &mut Server,
        connections: &mut HashMap<ConnectionID, Connection>
    ) {

        // expect 1 message from each connection
        for (id, conn) in connections.iter_mut() {
            match *id {
                ConnectionID(1) => check_messages(conn),
                ConnectionID(2) => check_messages(conn),
                _ => unreachable!("Invalid connection ID")
            }
        }

        server.shutdown().unwrap();

    }

}

#[test]
fn test_server_connections() {

    let config = Config::default();

    let mut handler = ConnectionServerHandler {
        connection_count: 0
    };

    let mut socket = MockSocket::new([

        // create a new connection from address 1
        ("127.0.0.1:1234", [
            1, 2, 3, 4, // Protocol Header
            0, 0, 0, 1, // Connection ID
            0, 0,
            0, 0, 0, 0

        ].to_vec()),

        // create a new connection from address 2
        ("127.0.0.1:5678", [
            1, 2, 3, 4, // Protocol Header
            0, 0, 0, 2, // Connection ID
            0, 0,
            0, 0, 0, 0

        ].to_vec()),

        // send message from address 1
        ("127.0.0.1:1234", [
            1, 2, 3, 4, // Protocol Header
            0, 0, 0, 1, // Connection ID
            1, 0,
            0, 0, 0, 0,

            // Hello World
            0, 0, 0, 11, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100

        ].to_vec()),

        // send message from address 2
        ("127.0.0.1:5678", [
            1, 2, 3, 4, // Protocol Header
            0, 0, 0, 2, // Connection ID
            1, 0,
            0, 0, 0, 0,

            // Hello World
            0, 0, 0, 11, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100

        ].to_vec())

    ].to_vec());

    // Expect one packet to be send to each connection
    socket.expect([
        // TODO order depends on how the ID is hashed...
        ("127.0.0.1:1234", [
            1, 2, 3, 4,  // Protocol Header
            0, 0, 0, 0,  // Ignored Connection ID
            0, 1,
            0, 0, 0, 1

        ].to_vec()),

        ("127.0.0.1:5678", [
            1, 2, 3, 4,  // Protocol Header
            0, 0, 0, 0,  // Ignored Connection ID
            0, 1,
            0, 0, 0, 1

        ].to_vec())

    ].to_vec());

    let mut server = Server::new(config);
    server.bind_to_socket(&mut handler, socket).unwrap();

    // expect 2 connections
    assert_eq!(handler.connection_count, 2);

}

struct ConnectionRemapServerHandler {
    pub connection_count: i32
}

impl Handler<Server> for ConnectionRemapServerHandler {

    fn connection(&mut self, _: &mut Server, conn: &mut Connection) {
        let ip = net::Ipv4Addr::new(127, 0, 0, 1);
        let addr = net::SocketAddr::V4(net::SocketAddrV4::new(ip, 1234));
        assert_eq!(conn.peer_addr(), addr);
        self.connection_count += 1;
    }

    fn tick_connections(
        &mut self, server: &mut Server,
        connections: &mut HashMap<ConnectionID, Connection>
    ) {

        // expect 1 message from the connection
        for (id, conn) in connections.iter_mut() {
            let ip = net::Ipv4Addr::new(127, 0, 0, 1);
            let addr = net::SocketAddr::V4(net::SocketAddrV4::new(ip, 5678));
            assert_eq!(*id, ConnectionID(1));
            assert_eq!(conn.peer_addr(), addr);
            check_messages(conn);
        }

        server.shutdown().unwrap();

    }

}

#[test]
fn test_server_connection_remapping() {

    let config = Config::default();

    let mut handler = ConnectionRemapServerHandler {
        connection_count: 0
    };

    let mut socket = MockSocket::new([

        // create a new connection from address 1
        ("127.0.0.1:1234", [
            1, 2, 3, 4, // Protocol Header
            0, 0, 0, 1, // Connection ID
            0, 0,
            0, 0, 0, 0,

        ].to_vec()),

        // send message from address 2, for connection 1
        ("127.0.0.1:5678", [
            1, 2, 3, 4, // Protocol Header
            0, 0, 0, 1, // Connection ID
            1, 0,
            0, 0, 0, 0,

            // Hello World
            0, 0, 0, 11, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100

        ].to_vec())

    ].to_vec());

    // Expect one packet for connection 1 to be send to address 2
    socket.expect([
        ("127.0.0.1:5678", [
            1, 2, 3, 4,  // Protocol Header
            0, 0, 0, 0,  // Ignored Connection ID
            0, 1,
            0, 0, 0, 1

        ].to_vec())

    ].to_vec());

    let mut server = Server::new(config);
    server.bind_to_socket(&mut handler, socket).unwrap();

    // expect 1 connection
    assert_eq!(handler.connection_count, 1);

}

#[test]
fn test_server_stats() {

    let config = Config {
        send_rate: 20,
        .. Config::default()
    };

    let mut handler = MockServerStatsHandler {
        tick_count: 0
    };

    let mut server = Server::new(config);
    server.bind(&mut handler, "127.0.0.1:0").unwrap();

    assert_eq!(server.stats(), Stats {
        bytes_sent: 0,
        bytes_received: 0
    });

}

// Generic receiving socket mock ----------------------------------------------
struct MockSocket {
    send_packets: Vec<(&'static str, Vec<u8>)>,
    receiver: Receiver<(net::SocketAddr, Vec<u8>)>,
    send_count: usize
}

impl MockSocket {

    pub fn new(messages: Vec<(&'static str, Vec<u8>)>) -> MockSocket {

        let (sender, receiver) = channel::<(net::SocketAddr, Vec<u8>)>();
        for (addr, data) in messages.into_iter() {
            let src: net::SocketAddr = addr.parse().ok().unwrap();
            sender.send((src, data.clone())).ok();
        }

        MockSocket {
            send_count: 0,
            send_packets: Vec::new(),
            receiver: receiver
        }

    }

    pub fn expect(&mut self, send_packets: Vec<(&'static str, Vec<u8>)>) {
        self.send_count = send_packets.len();
        self.send_packets = send_packets;
    }

}

impl Socket for MockSocket {

    fn try_recv(&self) -> Result<(net::SocketAddr, Vec<u8>), TryRecvError> {
        self.receiver.try_recv()
    }

    fn send_to(
        &mut self, data: &[u8], addr: net::SocketAddr)
    -> Result<usize, Error> {

        // Don't run out of expected packets
        if self.send_packets.len() == 0 {
            panic!(format!("Expected at most {} packet(s) to be send over socket.", self.send_count));
        }

        let addr_to: net::SocketAddr = addr.to_socket_addrs().unwrap().next().unwrap();

        // Search for the next packet with the matching address
        let mut index: i32 = -1;
        for (i, p) in self.send_packets.iter().enumerate() {

            // Verify receiver address
            let to: net::SocketAddr = p.0.parse().ok().unwrap();
            if to == addr_to {
                index = i as i32;
                break;
            }

        }

        if index == -1 {
            panic!(format!("Expected no more packet(s) to be send over socket to address {}", addr_to));
        }

        let expected = self.send_packets.remove(index as usize);

        // Verify packet data we ignore the connection ID here since it is
        // random and cannot be accessed by the mocks
        assert_eq!(&data[0..4], &expected.1[0..4]);
        assert_eq!(&data[8..], &expected.1[8..]);

        Ok(0)

    }

    fn local_addr(&self) -> Result<net::SocketAddr, Error> {
        let ip = net::Ipv4Addr::new(0, 0, 0, 0);
        Ok(net::SocketAddr::V4(net::SocketAddrV4::new(ip, 12345)))
    }

    fn shutdown(&mut self) {

    }

}

<commit_msg>Fix server tick delay tests.<commit_after>// Copyright (c) 2015-2016 Ivo Wetzel

// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
extern crate clock_ticks;

use std::net;
use std::thread;
use std::io::Error;
use std::collections::HashMap;
use std::sync::mpsc::{channel, Receiver, TryRecvError};
use std::net::ToSocketAddrs;
use super::super::{
    Connection, ConnectionID, Config, Handler, Server, Socket, Stats
};

fn precise_time_ms() -> u32 {
    (clock_ticks::precise_time_ns() / 1000000) as u32
}

struct DelayServerHandler {
    pub last_tick_time: u32,
    pub tick_count: u32,
    pub accumulated: i32
}

impl Handler<Server> for DelayServerHandler {

    fn bind(&mut self, _: &mut Server) {
        self.last_tick_time = precise_time_ms();
    }

    fn tick_connections(
        &mut self, server: &mut Server,
        _: &mut HashMap<ConnectionID, Connection>
    ) {

        // Accumulate time so we can check that the artificial delay
        // was correct for by the servers tick loop
        if self.tick_count > 1 {
            self.accumulated += (precise_time_ms() - self.last_tick_time) as i32;
        }

        self.last_tick_time = precise_time_ms();
        self.tick_count += 1;

        if self.tick_count == 5 {
            server.shutdown().unwrap();
        }

        // Fake some load inside of the tick handler
        let before = precise_time_ms();
        thread::sleep_ms(75);

        // Compensate for slow timers
        let spend = (precise_time_ms() - before) as i32;
        self.accumulated -= spend - 75;

    }

}

struct MockServerStatsHandler {
    pub tick_count: u32,
}

impl Handler<Server> for MockServerStatsHandler {

    fn connect(&mut self, _: &mut Server) {
    }

    fn tick_connections(
        &mut self, server: &mut Server,
        _: &mut HashMap<ConnectionID, Connection>
    ) {

        //conn.send(MessageKind::Instant, b"Hello World".to_vec());
        self.tick_count += 1;

        if self.tick_count == 20 {
            server.shutdown().unwrap();
        }

    }

}

#[test]
fn test_server_tick_delay() {

    let config = Config {
        send_rate: 10,
        .. Config::default()
    };

    let mut handler = DelayServerHandler {
        last_tick_time: 0,
        tick_count: 0,
        accumulated: 0
    };

    let mut server = Server::new(config);
    server.bind(&mut handler, "127.0.0.1:0").unwrap();

    assert!(handler.accumulated <= 350);

}

fn check_messages(conn: &mut Connection) {

    let mut messages = Vec::new();
    for m in conn.received() {
        messages.push(m);
    }

    assert_eq!(messages, [
        [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100].to_vec()

    ].to_vec())

}

struct ConnectionServerHandler {
    pub connection_count: i32
}

impl Handler<Server> for ConnectionServerHandler {

    fn connection(&mut self, _: &mut Server, _: &mut Connection) {
        self.connection_count += 1;
    }

    fn tick_connections(
        &mut self, server: &mut Server,
        connections: &mut HashMap<ConnectionID, Connection>
    ) {

        // expect 1 message from each connection
        for (id, conn) in connections.iter_mut() {
            match *id {
                ConnectionID(1) => check_messages(conn),
                ConnectionID(2) => check_messages(conn),
                _ => unreachable!("Invalid connection ID")
            }
        }

        server.shutdown().unwrap();

    }

}

#[test]
fn test_server_connections() {

    let config = Config::default();

    let mut handler = ConnectionServerHandler {
        connection_count: 0
    };

    let mut socket = MockSocket::new([

        // create a new connection from address 1
        ("127.0.0.1:1234", [
            1, 2, 3, 4, // Protocol Header
            0, 0, 0, 1, // Connection ID
            0, 0,
            0, 0, 0, 0

        ].to_vec()),

        // create a new connection from address 2
        ("127.0.0.1:5678", [
            1, 2, 3, 4, // Protocol Header
            0, 0, 0, 2, // Connection ID
            0, 0,
            0, 0, 0, 0

        ].to_vec()),

        // send message from address 1
        ("127.0.0.1:1234", [
            1, 2, 3, 4, // Protocol Header
            0, 0, 0, 1, // Connection ID
            1, 0,
            0, 0, 0, 0,

            // Hello World
            0, 0, 0, 11, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100

        ].to_vec()),

        // send message from address 2
        ("127.0.0.1:5678", [
            1, 2, 3, 4, // Protocol Header
            0, 0, 0, 2, // Connection ID
            1, 0,
            0, 0, 0, 0,

            // Hello World
            0, 0, 0, 11, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100

        ].to_vec())

    ].to_vec());

    // Expect one packet to be send to each connection
    socket.expect([
        // TODO order depends on how the ID is hashed...
        ("127.0.0.1:1234", [
            1, 2, 3, 4,  // Protocol Header
            0, 0, 0, 0,  // Ignored Connection ID
            0, 1,
            0, 0, 0, 1

        ].to_vec()),

        ("127.0.0.1:5678", [
            1, 2, 3, 4,  // Protocol Header
            0, 0, 0, 0,  // Ignored Connection ID
            0, 1,
            0, 0, 0, 1

        ].to_vec())

    ].to_vec());

    let mut server = Server::new(config);
    server.bind_to_socket(&mut handler, socket).unwrap();

    // expect 2 connections
    assert_eq!(handler.connection_count, 2);

}

struct ConnectionRemapServerHandler {
    pub connection_count: i32
}

impl Handler<Server> for ConnectionRemapServerHandler {

    fn connection(&mut self, _: &mut Server, conn: &mut Connection) {
        let ip = net::Ipv4Addr::new(127, 0, 0, 1);
        let addr = net::SocketAddr::V4(net::SocketAddrV4::new(ip, 1234));
        assert_eq!(conn.peer_addr(), addr);
        self.connection_count += 1;
    }

    fn tick_connections(
        &mut self, server: &mut Server,
        connections: &mut HashMap<ConnectionID, Connection>
    ) {

        // expect 1 message from the connection
        for (id, conn) in connections.iter_mut() {
            let ip = net::Ipv4Addr::new(127, 0, 0, 1);
            let addr = net::SocketAddr::V4(net::SocketAddrV4::new(ip, 5678));
            assert_eq!(*id, ConnectionID(1));
            assert_eq!(conn.peer_addr(), addr);
            check_messages(conn);
        }

        server.shutdown().unwrap();

    }

}

#[test]
fn test_server_connection_remapping() {

    let config = Config::default();

    let mut handler = ConnectionRemapServerHandler {
        connection_count: 0
    };

    let mut socket = MockSocket::new([

        // create a new connection from address 1
        ("127.0.0.1:1234", [
            1, 2, 3, 4, // Protocol Header
            0, 0, 0, 1, // Connection ID
            0, 0,
            0, 0, 0, 0,

        ].to_vec()),

        // send message from address 2, for connection 1
        ("127.0.0.1:5678", [
            1, 2, 3, 4, // Protocol Header
            0, 0, 0, 1, // Connection ID
            1, 0,
            0, 0, 0, 0,

            // Hello World
            0, 0, 0, 11, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100

        ].to_vec())

    ].to_vec());

    // Expect one packet for connection 1 to be send to address 2
    socket.expect([
        ("127.0.0.1:5678", [
            1, 2, 3, 4,  // Protocol Header
            0, 0, 0, 0,  // Ignored Connection ID
            0, 1,
            0, 0, 0, 1

        ].to_vec())

    ].to_vec());

    let mut server = Server::new(config);
    server.bind_to_socket(&mut handler, socket).unwrap();

    // expect 1 connection
    assert_eq!(handler.connection_count, 1);

}

#[test]
fn test_server_stats() {

    let config = Config {
        send_rate: 20,
        .. Config::default()
    };

    let mut handler = MockServerStatsHandler {
        tick_count: 0
    };

    let mut server = Server::new(config);
    server.bind(&mut handler, "127.0.0.1:0").unwrap();

    assert_eq!(server.stats(), Stats {
        bytes_sent: 0,
        bytes_received: 0
    });

}

// Generic receiving socket mock ----------------------------------------------
struct MockSocket {
    send_packets: Vec<(&'static str, Vec<u8>)>,
    receiver: Receiver<(net::SocketAddr, Vec<u8>)>,
    send_count: usize
}

impl MockSocket {

    pub fn new(messages: Vec<(&'static str, Vec<u8>)>) -> MockSocket {

        let (sender, receiver) = channel::<(net::SocketAddr, Vec<u8>)>();
        for (addr, data) in messages.into_iter() {
            let src: net::SocketAddr = addr.parse().ok().unwrap();
            sender.send((src, data.clone())).ok();
        }

        MockSocket {
            send_count: 0,
            send_packets: Vec::new(),
            receiver: receiver
        }

    }

    pub fn expect(&mut self, send_packets: Vec<(&'static str, Vec<u8>)>) {
        self.send_count = send_packets.len();
        self.send_packets = send_packets;
    }

}

impl Socket for MockSocket {

    fn try_recv(&self) -> Result<(net::SocketAddr, Vec<u8>), TryRecvError> {
        self.receiver.try_recv()
    }

    fn send_to(
        &mut self, data: &[u8], addr: net::SocketAddr)
    -> Result<usize, Error> {

        // Don't run out of expected packets
        if self.send_packets.len() == 0 {
            panic!(format!("Expected at most {} packet(s) to be send over socket.", self.send_count));
        }

        let addr_to: net::SocketAddr = addr.to_socket_addrs().unwrap().next().unwrap();

        // Search for the next packet with the matching address
        let mut index: i32 = -1;
        for (i, p) in self.send_packets.iter().enumerate() {

            // Verify receiver address
            let to: net::SocketAddr = p.0.parse().ok().unwrap();
            if to == addr_to {
                index = i as i32;
                break;
            }

        }

        if index == -1 {
            panic!(format!("Expected no more packet(s) to be send over socket to address {}", addr_to));
        }

        let expected = self.send_packets.remove(index as usize);

        // Verify packet data we ignore the connection ID here since it is
        // random and cannot be accessed by the mocks
        assert_eq!(&data[0..4], &expected.1[0..4]);
        assert_eq!(&data[8..], &expected.1[8..]);

        Ok(0)

    }

    fn local_addr(&self) -> Result<net::SocketAddr, Error> {
        let ip = net::Ipv4Addr::new(0, 0, 0, 0);
        Ok(net::SocketAddr::V4(net::SocketAddrV4::new(ip, 12345)))
    }

    fn shutdown(&mut self) {

    }

}

<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Link between Vulkan and a window and/or the screen.
//!
//! Before you can draw on the screen or a window, you have to create two objects:
//!
//! - Create a `Surface` object that represents the location where the image will show up (either
//!   a window or a monitor).
//! - Create a `Swapchain` that uses that `Surface`.
//!
//! Creating a surface can be done with only an `Instance` object. However creating a swapchain
//! requires a `Device` object.
//!
//! Once you have a swapchain, you can retrieve `Image` objects from it and draw to them just like
//! you would draw on any other image.
//!
//! # Surfaces
//!
//! A surface is an object that represents a location where to render. It can be created from an
//! instance and either a window handle (in a platform-specific way) or a monitor.
//!
//! In order to use surfaces, you will have to enable the `VK_KHR_surface` extension on the
//! instance. See the `instance` module for more information about how to enable extensions.
//!
//! ## Creating a surface from a window
//!
//! There are 6 extensions that each allow you to create a surface from a type of window:
//!
//! - `VK_KHR_xlib_surface`
//! - `VK_KHR_xcb_surface`
//! - `VK_KHR_wayland_surface`
//! - `VK_KHR_mir_surface`
//! - `VK_KHR_android_surface`
//! - `VK_KHR_win32_surface`
//!
//! For example if you want to create a surface from an Android surface, you will have to enable
//! the `VK_KHR_android_surface` extension and use `Surface::from_anativewindow`.
//! See the documentation of `Surface` for all the possible constructors.
//!
//! Trying to use one of these functions without enabling the proper extension will result in an
//! error.
//!
//! **Note that the `Surface` object is potentially unsafe**. It is your responsibility to
//! keep the window alive for at least as long as the surface exists. In many cases Surface
//! may be able to do this for you, if you pass it ownership of your Window (or a
//! reference-counting container for it).
//!
//! ### Example
//!
//! ```no_run
//! use std::ptr;
//! use vulkano::instance::Instance;
//! use vulkano::instance::InstanceExtensions;
//! use vulkano::swapchain::Surface;
//!
//! let instance = {
//!     let extensions = InstanceExtensions {
//!         khr_surface: true,
//!         khr_win32_surface: true,        // If you don't enable this, `from_hwnd` will fail.
//!         .. InstanceExtensions::none()
//!     };
//!
//!      match Instance::new(None, &extensions, None) {
//!         Ok(i) => i,
//!         Err(err) => panic!("Couldn't build instance: {:?}", err)
//!     }
//! };
//!
//! # use std::sync::Arc;
//! # struct Window(*const u32);
//! # impl Window {
//! # fn hwnd(&self) -> *const u32 { self.0 }
//! # }
//! #
//! # fn build_window() -> Arc<Window> { Arc::new(Window(ptr::null())) }
//! let window = build_window();        // Third-party function, not provided by vulkano
//! let _surface = unsafe {
//!     let hinstance: *const () = ptr::null();     // Windows-specific object
//!     Surface::from_hwnd(instance.clone(), hinstance, window.hwnd(), Arc::clone(&window)).unwrap()
//! };
//! ```
//!
//! ## Creating a surface from a monitor
//!
//! Currently no system provides the `VK_KHR_display` extension that contains this feature.
//! This feature is still a work-in-progress in vulkano and will reside in the `display` module.
//!
//! # Swapchains
//!
//! A surface represents a location on the screen and can be created from an instance. Once you
//! have a surface, the next step is to create a swapchain. Creating a swapchain requires a device,
//! and allocates the resources that will be used to display images on the screen.
//!
//! A swapchain is composed of one or multiple images. Each image of the swapchain is presented in
//! turn on the screen, one after another. More information below.
//!
//! Swapchains have several properties:
//!
//!  - The number of images that will cycle on the screen.
//!  - The format of the images.
//!  - The 2D dimensions of the images, plus a number of layers, for a total of three dimensions.
//!  - The usage of the images, similar to creating other images.
//!  - The queue families that are going to use the images, similar to creating other images.
//!  - An additional transformation (rotation or mirroring) to perform on the final output.
//!  - How the alpha of the final output will be interpreted.
//!  - How to perform the cycling between images in regard to vsync.
//!
//! You can query the supported values of all these properties with
//! [`Surface::capabilities()]`](struct.Surface.html#method.capabilities).
//!
//! ## Creating a swapchain
//!
//! In order to create a swapchain, you will first have to enable the `VK_KHR_swapchain` extension
//! on the device (and not on the instance like `VK_KHR_surface`):
//!
//! ```no_run
//! # use vulkano::instance::DeviceExtensions;
//! let ext = DeviceExtensions {
//!     khr_swapchain: true,
//!     .. DeviceExtensions::none()
//! };
//! ```
//!
//! Then, query the capabilities of the surface with
//! [`Surface::capabilities()`](struct.Surface.html#method.capabilities)
//! and choose which values you are going to use.
//!
//! ```no_run
//! # use std::sync::Arc;
//! # use vulkano::device::Device;
//! # use vulkano::swapchain::Surface;
//! # use std::cmp::{max, min};
//! # fn choose_caps(device: Arc<Device>, surface: Arc<Surface<()>>) -> Result<(), Box<std::error::Error>> {
//! let caps = surface.capabilities(device.physical_device())?;
//!
//! // Use the current window size or some fixed resolution.
//! let dimensions = caps.current_extent.unwrap_or([640, 480]);
//!
//! // Try to use double-buffering.
//! let buffers_count = max(min(2, caps.min_image_count), caps.max_image_count.unwrap_or(2));
//!
//! // Preserve the current surface transform.
//! let transform = caps.current_transform;
//!
//! // Use the first available format.
//! let (format, color_space) = caps.supported_formats[0];
//! # Ok(())
//! # }
//! ```
//!
//! Then, call [`Swapchain::new()`](struct.Swapchain.html#method.new).
//!
//! ```no_run
//! # use std::sync::Arc;
//! # use vulkano::device::{Device, Queue};
//! # use vulkano::image::ImageUsage;
//! # use vulkano::sync::SharingMode;
//! # use vulkano::format::Format;
//! # use vulkano::swapchain::{Surface, Swapchain, SurfaceTransform, PresentMode, CompositeAlpha};
//! # fn create_swapchain(
//! #     device: Arc<Device>, surface: Arc<Surface<()>>, present_queue: Arc<Queue>,
//! #     buffers_count: u32, format: Format, dimensions: [u32; 2],
//! #     surface_transform: SurfaceTransform, composite_alpha: CompositeAlpha, present_mode: PresentMode
//! # ) -> Result<(), Box<std::error::Error>> {
//! // The created swapchain will be used as a color attachment for rendering.
//! let usage = ImageUsage {
//!     color_attachment: true,
//!     .. ImageUsage::none()
//! };
//!
//! let sharing_mode = SharingMode::Exclusive(present_queue.family().id());
//!
//! // Create the swapchain and its buffers.
//! let (swapchain, buffers) = Swapchain::new(
//!     // Create the swapchain in this `device`'s memory.
//!     device,
//!     // The surface where the images will be presented.
//!     surface,
//!     // How many buffers to use in the swapchain.
//!     buffers_count,
//!     // The format of the images.
//!     format,
//!     // The size of each image.
//!     dimensions,
//!     // How many layers each image has.
//!     1,
//!     // What the images are going to be used for.
//!     usage,
//!     // Describes which queues will interact with the swapchain.
//!     sharing_mode,
//!     // What transformation to use with the surface.
//!     surface_transform,
//!     // How to handle the alpha channel.
//!     composite_alpha,
//!     // How to present images.
//!     present_mode,
//!     // Clip the parts of the buffer which aren't visible.
//!     true,
//!     // No previous swapchain.
//!     None
//! )?;
//!
//! # Ok(())
//! # }
//! ```
//!
//! Creating a swapchain not only returns the swapchain object, but also all the images that belong
//! to it.
//!
//! ## Acquiring and presenting images
//!
//! Once you created a swapchain and retreived all the images that belong to it (see previous
//! section), you can draw on it. This is done in three steps:
//!
//!  - Call `swapchain::acquire_next_image`. This function will return the index of the image
//!    (within the list returned by `Swapchain::new`) that is available to draw, plus a future
//!    representing the moment when the GPU will gain access to that image.
//!  - Draw on that image just like you would draw to any other image (see the documentation of
//!    the `pipeline` module). You need to chain the draw after the future that was returned by
//!    `acquire_next_image`.
//!  - Call `Swapchain::present` with the same index and by chaining the futures, in order to tell
//!    the implementation that you are finished drawing to the image and that it can queue a
//!    command to present the image on the screen after the draw operations are finished.
//!
//! TODO: add example here
//! loop {
//!     let index = swapchain::acquire_next_image(None).unwrap();
//!     draw(images[index]);
//!     swapchain::present(queue, index).unwrap();
//! }
//!
//! ## Recreating a swapchain
//!
//! In some situations, the swapchain will become invalid by itself. This includes for example when
//! the window is resized (as the images of the swapchain will no longer match the window's) or,
//! on Android, when the application went to the background and goes back to the foreground.
//!
//! In this situation, acquiring a swapchain image or presenting it will return an error. Rendering
//! to an image of that swapchain will not produce any error, but may or may not work. To continue
//! rendering, you will need to *recreate* the swapchain by creating a new swapchain and passing
//! as last parameter the old swapchain.
//!
//! TODO: suboptimal stuff
//!
//! ```
//! # use std::time::Duration;
//! use vulkano::swapchain;
//! use vulkano::swapchain::AcquireError;
//! use vulkano::sync::GpuFuture;
//!
//! // let mut swapchain = Swapchain::new(...);
//! # let mut swapchain: (::std::sync::Arc<::vulkano::swapchain::Swapchain<()>>, _) = return;
//! # let queue: ::std::sync::Arc<::vulkano::device::Queue> = return;
//! let mut recreate_swapchain = false;
//!
//! loop {
//!     if recreate_swapchain {
//!         swapchain = swapchain.0.recreate_with_dimension([1024, 768]).unwrap();
//!         recreate_swapchain = false;
//!     }
//!
//!     let (ref swapchain, ref _images) = swapchain;
//!
//!     let (index, acq_future) = match swapchain::acquire_next_image(swapchain.clone(), None) {
//!         Ok(r) => r,
//!         Err(AcquireError::OutOfDate) => { recreate_swapchain = true; continue; },
//!         Err(err) => panic!("{:?}", err)
//!     };
//!
//!     // ...
//!
//!     let final_future = acq_future
//!         // .then_execute(...)
//!         .then_swapchain_present(queue.clone(), swapchain.clone(), index)
//!         .then_signal_fence();
//!
//!     final_future.flush().unwrap();      // TODO: PresentError?
//! }
//! ```
//!

use std::sync::atomic::AtomicBool;

pub use self::capabilities::Capabilities;
pub use self::capabilities::ColorSpace;
pub use self::capabilities::CompositeAlpha;
pub use self::capabilities::PresentMode;
pub use self::capabilities::SupportedCompositeAlpha;
pub use self::capabilities::SupportedCompositeAlphaIter;
pub use self::capabilities::SupportedPresentModes;
pub use self::capabilities::SupportedPresentModesIter;
pub use self::capabilities::SupportedSurfaceTransforms;
pub use self::capabilities::SupportedSurfaceTransformsIter;
pub use self::capabilities::SurfaceTransform;
pub use self::present_region::PresentRegion;
pub use self::present_region::RectangleLayer;
pub use self::surface::CapabilitiesError;
pub use self::surface::Surface;
pub use self::surface::SurfaceCreationError;
pub use self::swapchain::AcquireError;
pub use self::swapchain::AcquiredImage;
pub use self::swapchain::PresentFuture;
pub use self::swapchain::Swapchain;
pub use self::swapchain::SwapchainAcquireFuture;
pub use self::swapchain::SwapchainCreationError;
pub use self::swapchain::acquire_next_image;
pub use self::swapchain::acquire_next_image_raw;
pub use self::swapchain::present;
pub use self::swapchain::present_incremental;

mod capabilities;
pub mod display;
mod present_region;
mod surface;
mod swapchain;

/// Internal trait so that creating/destroying a swapchain can access the surface's "has_swapchain"
/// flag.
// TODO: use pub(crate) maybe?
unsafe trait SurfaceSwapchainLock {
    fn flag(&self) -> &AtomicBool;
}
<commit_msg>Docs: Fix swapchain image count computation. (#997)<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Link between Vulkan and a window and/or the screen.
//!
//! Before you can draw on the screen or a window, you have to create two objects:
//!
//! - Create a `Surface` object that represents the location where the image will show up (either
//!   a window or a monitor).
//! - Create a `Swapchain` that uses that `Surface`.
//!
//! Creating a surface can be done with only an `Instance` object. However creating a swapchain
//! requires a `Device` object.
//!
//! Once you have a swapchain, you can retrieve `Image` objects from it and draw to them just like
//! you would draw on any other image.
//!
//! # Surfaces
//!
//! A surface is an object that represents a location where to render. It can be created from an
//! instance and either a window handle (in a platform-specific way) or a monitor.
//!
//! In order to use surfaces, you will have to enable the `VK_KHR_surface` extension on the
//! instance. See the `instance` module for more information about how to enable extensions.
//!
//! ## Creating a surface from a window
//!
//! There are 6 extensions that each allow you to create a surface from a type of window:
//!
//! - `VK_KHR_xlib_surface`
//! - `VK_KHR_xcb_surface`
//! - `VK_KHR_wayland_surface`
//! - `VK_KHR_mir_surface`
//! - `VK_KHR_android_surface`
//! - `VK_KHR_win32_surface`
//!
//! For example if you want to create a surface from an Android surface, you will have to enable
//! the `VK_KHR_android_surface` extension and use `Surface::from_anativewindow`.
//! See the documentation of `Surface` for all the possible constructors.
//!
//! Trying to use one of these functions without enabling the proper extension will result in an
//! error.
//!
//! **Note that the `Surface` object is potentially unsafe**. It is your responsibility to
//! keep the window alive for at least as long as the surface exists. In many cases Surface
//! may be able to do this for you, if you pass it ownership of your Window (or a
//! reference-counting container for it).
//!
//! ### Example
//!
//! ```no_run
//! use std::ptr;
//! use vulkano::instance::Instance;
//! use vulkano::instance::InstanceExtensions;
//! use vulkano::swapchain::Surface;
//!
//! let instance = {
//!     let extensions = InstanceExtensions {
//!         khr_surface: true,
//!         khr_win32_surface: true,        // If you don't enable this, `from_hwnd` will fail.
//!         .. InstanceExtensions::none()
//!     };
//!
//!      match Instance::new(None, &extensions, None) {
//!         Ok(i) => i,
//!         Err(err) => panic!("Couldn't build instance: {:?}", err)
//!     }
//! };
//!
//! # use std::sync::Arc;
//! # struct Window(*const u32);
//! # impl Window {
//! # fn hwnd(&self) -> *const u32 { self.0 }
//! # }
//! #
//! # fn build_window() -> Arc<Window> { Arc::new(Window(ptr::null())) }
//! let window = build_window();        // Third-party function, not provided by vulkano
//! let _surface = unsafe {
//!     let hinstance: *const () = ptr::null();     // Windows-specific object
//!     Surface::from_hwnd(instance.clone(), hinstance, window.hwnd(), Arc::clone(&window)).unwrap()
//! };
//! ```
//!
//! ## Creating a surface from a monitor
//!
//! Currently no system provides the `VK_KHR_display` extension that contains this feature.
//! This feature is still a work-in-progress in vulkano and will reside in the `display` module.
//!
//! # Swapchains
//!
//! A surface represents a location on the screen and can be created from an instance. Once you
//! have a surface, the next step is to create a swapchain. Creating a swapchain requires a device,
//! and allocates the resources that will be used to display images on the screen.
//!
//! A swapchain is composed of one or multiple images. Each image of the swapchain is presented in
//! turn on the screen, one after another. More information below.
//!
//! Swapchains have several properties:
//!
//!  - The number of images that will cycle on the screen.
//!  - The format of the images.
//!  - The 2D dimensions of the images, plus a number of layers, for a total of three dimensions.
//!  - The usage of the images, similar to creating other images.
//!  - The queue families that are going to use the images, similar to creating other images.
//!  - An additional transformation (rotation or mirroring) to perform on the final output.
//!  - How the alpha of the final output will be interpreted.
//!  - How to perform the cycling between images in regard to vsync.
//!
//! You can query the supported values of all these properties with
//! [`Surface::capabilities()]`](struct.Surface.html#method.capabilities).
//!
//! ## Creating a swapchain
//!
//! In order to create a swapchain, you will first have to enable the `VK_KHR_swapchain` extension
//! on the device (and not on the instance like `VK_KHR_surface`):
//!
//! ```no_run
//! # use vulkano::instance::DeviceExtensions;
//! let ext = DeviceExtensions {
//!     khr_swapchain: true,
//!     .. DeviceExtensions::none()
//! };
//! ```
//!
//! Then, query the capabilities of the surface with
//! [`Surface::capabilities()`](struct.Surface.html#method.capabilities)
//! and choose which values you are going to use.
//!
//! ```no_run
//! # use std::sync::Arc;
//! # use vulkano::device::Device;
//! # use vulkano::swapchain::Surface;
//! # use std::cmp::{max, min};
//! # fn choose_caps(device: Arc<Device>, surface: Arc<Surface<()>>) -> Result<(), Box<std::error::Error>> {
//! let caps = surface.capabilities(device.physical_device())?;
//!
//! // Use the current window size or some fixed resolution.
//! let dimensions = caps.current_extent.unwrap_or([640, 480]);
//!
//! // Try to use double-buffering.
//! let buffers_count = match caps.max_image_count {
//!     None => max(2, caps.min_image_count),
//!     Some(limit) => min(max(2, caps.min_image_count), limit)
//! };
//!
//! // Preserve the current surface transform.
//! let transform = caps.current_transform;
//!
//! // Use the first available format.
//! let (format, color_space) = caps.supported_formats[0];
//! # Ok(())
//! # }
//! ```
//!
//! Then, call [`Swapchain::new()`](struct.Swapchain.html#method.new).
//!
//! ```no_run
//! # use std::sync::Arc;
//! # use vulkano::device::{Device, Queue};
//! # use vulkano::image::ImageUsage;
//! # use vulkano::sync::SharingMode;
//! # use vulkano::format::Format;
//! # use vulkano::swapchain::{Surface, Swapchain, SurfaceTransform, PresentMode, CompositeAlpha};
//! # fn create_swapchain(
//! #     device: Arc<Device>, surface: Arc<Surface<()>>, present_queue: Arc<Queue>,
//! #     buffers_count: u32, format: Format, dimensions: [u32; 2],
//! #     surface_transform: SurfaceTransform, composite_alpha: CompositeAlpha, present_mode: PresentMode
//! # ) -> Result<(), Box<std::error::Error>> {
//! // The created swapchain will be used as a color attachment for rendering.
//! let usage = ImageUsage {
//!     color_attachment: true,
//!     .. ImageUsage::none()
//! };
//!
//! let sharing_mode = SharingMode::Exclusive(present_queue.family().id());
//!
//! // Create the swapchain and its buffers.
//! let (swapchain, buffers) = Swapchain::new(
//!     // Create the swapchain in this `device`'s memory.
//!     device,
//!     // The surface where the images will be presented.
//!     surface,
//!     // How many buffers to use in the swapchain.
//!     buffers_count,
//!     // The format of the images.
//!     format,
//!     // The size of each image.
//!     dimensions,
//!     // How many layers each image has.
//!     1,
//!     // What the images are going to be used for.
//!     usage,
//!     // Describes which queues will interact with the swapchain.
//!     sharing_mode,
//!     // What transformation to use with the surface.
//!     surface_transform,
//!     // How to handle the alpha channel.
//!     composite_alpha,
//!     // How to present images.
//!     present_mode,
//!     // Clip the parts of the buffer which aren't visible.
//!     true,
//!     // No previous swapchain.
//!     None
//! )?;
//!
//! # Ok(())
//! # }
//! ```
//!
//! Creating a swapchain not only returns the swapchain object, but also all the images that belong
//! to it.
//!
//! ## Acquiring and presenting images
//!
//! Once you created a swapchain and retreived all the images that belong to it (see previous
//! section), you can draw on it. This is done in three steps:
//!
//!  - Call `swapchain::acquire_next_image`. This function will return the index of the image
//!    (within the list returned by `Swapchain::new`) that is available to draw, plus a future
//!    representing the moment when the GPU will gain access to that image.
//!  - Draw on that image just like you would draw to any other image (see the documentation of
//!    the `pipeline` module). You need to chain the draw after the future that was returned by
//!    `acquire_next_image`.
//!  - Call `Swapchain::present` with the same index and by chaining the futures, in order to tell
//!    the implementation that you are finished drawing to the image and that it can queue a
//!    command to present the image on the screen after the draw operations are finished.
//!
//! TODO: add example here
//! loop {
//!     let index = swapchain::acquire_next_image(None).unwrap();
//!     draw(images[index]);
//!     swapchain::present(queue, index).unwrap();
//! }
//!
//! ## Recreating a swapchain
//!
//! In some situations, the swapchain will become invalid by itself. This includes for example when
//! the window is resized (as the images of the swapchain will no longer match the window's) or,
//! on Android, when the application went to the background and goes back to the foreground.
//!
//! In this situation, acquiring a swapchain image or presenting it will return an error. Rendering
//! to an image of that swapchain will not produce any error, but may or may not work. To continue
//! rendering, you will need to *recreate* the swapchain by creating a new swapchain and passing
//! as last parameter the old swapchain.
//!
//! TODO: suboptimal stuff
//!
//! ```
//! # use std::time::Duration;
//! use vulkano::swapchain;
//! use vulkano::swapchain::AcquireError;
//! use vulkano::sync::GpuFuture;
//!
//! // let mut swapchain = Swapchain::new(...);
//! # let mut swapchain: (::std::sync::Arc<::vulkano::swapchain::Swapchain<()>>, _) = return;
//! # let queue: ::std::sync::Arc<::vulkano::device::Queue> = return;
//! let mut recreate_swapchain = false;
//!
//! loop {
//!     if recreate_swapchain {
//!         swapchain = swapchain.0.recreate_with_dimension([1024, 768]).unwrap();
//!         recreate_swapchain = false;
//!     }
//!
//!     let (ref swapchain, ref _images) = swapchain;
//!
//!     let (index, acq_future) = match swapchain::acquire_next_image(swapchain.clone(), None) {
//!         Ok(r) => r,
//!         Err(AcquireError::OutOfDate) => { recreate_swapchain = true; continue; },
//!         Err(err) => panic!("{:?}", err)
//!     };
//!
//!     // ...
//!
//!     let final_future = acq_future
//!         // .then_execute(...)
//!         .then_swapchain_present(queue.clone(), swapchain.clone(), index)
//!         .then_signal_fence();
//!
//!     final_future.flush().unwrap();      // TODO: PresentError?
//! }
//! ```
//!

use std::sync::atomic::AtomicBool;

pub use self::capabilities::Capabilities;
pub use self::capabilities::ColorSpace;
pub use self::capabilities::CompositeAlpha;
pub use self::capabilities::PresentMode;
pub use self::capabilities::SupportedCompositeAlpha;
pub use self::capabilities::SupportedCompositeAlphaIter;
pub use self::capabilities::SupportedPresentModes;
pub use self::capabilities::SupportedPresentModesIter;
pub use self::capabilities::SupportedSurfaceTransforms;
pub use self::capabilities::SupportedSurfaceTransformsIter;
pub use self::capabilities::SurfaceTransform;
pub use self::present_region::PresentRegion;
pub use self::present_region::RectangleLayer;
pub use self::surface::CapabilitiesError;
pub use self::surface::Surface;
pub use self::surface::SurfaceCreationError;
pub use self::swapchain::AcquireError;
pub use self::swapchain::AcquiredImage;
pub use self::swapchain::PresentFuture;
pub use self::swapchain::Swapchain;
pub use self::swapchain::SwapchainAcquireFuture;
pub use self::swapchain::SwapchainCreationError;
pub use self::swapchain::acquire_next_image;
pub use self::swapchain::acquire_next_image_raw;
pub use self::swapchain::present;
pub use self::swapchain::present_incremental;

mod capabilities;
pub mod display;
mod present_region;
mod surface;
mod swapchain;

/// Internal trait so that creating/destroying a swapchain can access the surface's "has_swapchain"
/// flag.
// TODO: use pub(crate) maybe?
unsafe trait SurfaceSwapchainLock {
    fn flag(&self) -> &AtomicBool;
}
<|endoftext|>


<commit_before>#![feature(box_syntax)]

struct DroppableStruct;

static mut DROPPED: bool = false;

impl Drop for DroppableStruct {
    fn drop(&mut self) {
        unsafe { DROPPED = true; }
    }
}

trait MyTrait { fn dummy(&self) { } }
impl MyTrait for Box<DroppableStruct> {}

#[allow(dead_code)]
struct Whatever { w: Box<dyn MyTrait+'static> }

impl  Whatever {
    fn new(w: Box<dyn MyTrait+'static>) -> Whatever {
        Whatever { w: w }
    }
}

fn main() {
    {
        let f: Box<_> = box DroppableStruct;
        let _a = Whatever::new(box f as Box<dyn MyTrait>);
    }
    assert!(unsafe { DROPPED });
}
<commit_msg>tweak and slightly extend box-box-trait test<commit_after>struct DroppableStruct;

static mut DROPPED: bool = false;

impl Drop for DroppableStruct {
    fn drop(&mut self) {
        unsafe { DROPPED = true; }
    }
}

trait MyTrait { fn dummy(&self) { } }
impl MyTrait for Box<DroppableStruct> {}

struct Whatever { w: Box<dyn MyTrait+'static> }

impl  Whatever {
    fn new(w: Box<dyn MyTrait+'static>) -> Whatever {
        Whatever { w: w }
    }
}

fn main() {
    {
        let f = Box::new(DroppableStruct);
        let a = Whatever::new(Box::new(f) as Box<dyn MyTrait>);
        a.w.dummy();
    }
    assert!(unsafe { DROPPED });
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::sync::Arc;
use std::fmt::Write;
use super::{Command, CommandGroup};
use ::client::Context;
use ::model::Message;
use ::utils::Colour;

fn error_embed(ctx: &Context, message: &Message, input: &str) {
    let _ = ctx.send_message(message.channel_id, |m| m
        .embed(|e| e
            .colour(Colour::dark_red())
            .description(input)));
}

pub fn with_embeds(ctx: &Context,
                   message: &Message,
                   groups: HashMap<String, Arc<CommandGroup>>,
                   args: Vec<String>) -> Result<(), String> {
    if !args.is_empty() {
        let name = args.join(" ");

        for (group_name, group) in groups {
            let mut found: Option<(&String, &Command)> = None;

            if let Some(ref prefix) = group.prefix {
                for (command_name, command) in &group.commands {
                    if name == format!("{} {}", prefix, command_name) {
                        found = Some((command_name, command));
                    }
                }
            } else {
                for (command_name, command) in &group.commands {
                    if name == command_name[..] {
                        found = Some((command_name, command));
                    }
                }
            };

            if let Some((command_name, command)) = found {
                if !command.help_available {
                    error_embed(ctx, message, "**Error**: No help available.");

                    return Ok(());
                }

                let _ = ctx.send_message(message.channel_id, |m| {
                    m.embed(|e| {
                        let mut embed = e.colour(Colour::rosewater())
                            .title(command_name);
                        if let Some(ref desc) = command.desc {
                            embed = embed.field(|f| {
                                f.name("Description")
                                    .value(desc)
                                    .inline(false)
                            });
                        }

                        if let Some(ref usage) = command.usage {
                            embed = embed.field(|f| {
                                f.name("Usage")
                                    .value(&format!("{} {}", command_name, usage))
                            });
                        }

                        if group_name != "Ungrouped" {
                            embed = embed.field(|f| {
                                f.name("Group")
                                    .value(&group_name)
                            });
                        }

                        let available = if command.dm_only {
                            "Only in DM"
                        } else if command.guild_only {
                            "Only in guilds"
                        } else {
                            "In DM and guilds"
                        };

                        embed = embed.field(|f| {
                            f.name("Available")
                                .value(available)
                        });

                        embed
                    })
                });

                return Ok(());
            }
        }

        let error_msg = format!("**Error**: Command `{}` not found.", name);
        error_embed(ctx, message, &error_msg);

        return Ok(());
    }

    let _ = ctx.send_message(message.channel_id, |m| {
        m.embed(|mut e| {
            e = e.colour(Colour::rosewater())
                .description("To get help about individual command, pass its \
                              name as an argument to this command.");

            for (group_name, group) in groups {
                let mut desc = String::new();

                if let Some(ref x) = group.prefix {
                    let _ = write!(desc, "Prefix: {}\n", x);
                }

                desc.push_str("Commands:\n");

                let mut no_commands = true;

                for (n, cmd) in &group.commands {
                    if cmd.help_available {
                        let _ = write!(desc, "`{}`\n", n);

                        no_commands = false;
                    }
                }

                if no_commands {
                    let _ = write!(desc, "*[No commands]*");
                }

                e = e.field(|f| f.name(&group_name).value(&desc));
            }

            e
        })
    });

    Ok(())
}

pub fn plain(ctx: &Context,
             _: &Message,
             groups: HashMap<String, Arc<CommandGroup>>,
             args: Vec<String>) -> Result<(), String> {
    if !args.is_empty() {
        let name = args.join(" ");

        for (group_name, group) in groups {
            let mut found: Option<(&String, &Command)> = None;

            if let Some(ref prefix) = group.prefix {
                for (command_name, command) in &group.commands {
                    if name == format!("{} {}", prefix, command_name) {
                        found = Some((command_name, command));
                    }
                }
            } else {
                for (command_name, command) in &group.commands {
                    if name == command_name[..] {
                        found = Some((command_name, command));
                    }
                }
            };

            if let Some((command_name, command)) = found {
                if !command.help_available {
                    let _ = ctx.say("**Error**: No help available.");
                    return Ok(());
                }

                let mut result = format!("**{}**\n", command_name);

                if let Some(ref desc) = command.desc {
                    let _ = write!(result, "**Description:** {}\n", desc);
                }

                if let Some(ref usage) = command.usage {
                    let _ = write!(result, "**Usage:** {}\n", usage);
                }

                if group_name != "Ungrouped" {
                    let _ = write!(result, "**Group:** {}\n", group_name);
                }

                result.push_str("**Available:** ");
                result.push_str(if command.dm_only {
                    "Only in DM"
                } else if command.guild_only {
                    "Only in guilds"
                } else {
                    "In DM and guilds"
                });
                result.push_str("\n");

                return Ok(());
            }
        }

        let _ = ctx.say(&format!("**Error**: Command `{}` not found.", name));

        return Ok(());
    }

    let mut result = "**Commands**\nTo get help about individual command, pass \
                      its name as an argument to this command.\n\n"
        .to_string();

    for (group_name, group) in groups {
        let _ = write!(result, "**{}:** ", group_name);

        if let Some(ref x) = group.prefix {
            let _ = write!(result, "(prefix: `{}`): ", x);
        }

        let mut no_commands = true;

        for (n, cmd) in &group.commands {
            if cmd.help_available {
                let _ = write!(result, "`{}` ", n);

                no_commands = false;
            }
        }

        if no_commands {
            result.push_str("*[No Commands]*");
        }
    }

    let _ = ctx.say(&result);

    Ok(())
}
<commit_msg>Fix plain help command usage output<commit_after>use std::collections::HashMap;
use std::sync::Arc;
use std::fmt::Write;
use super::{Command, CommandGroup};
use ::client::Context;
use ::model::Message;
use ::utils::Colour;

fn error_embed(ctx: &Context, message: &Message, input: &str) {
    let _ = ctx.send_message(message.channel_id, |m| m
        .embed(|e| e
            .colour(Colour::dark_red())
            .description(input)));
}

pub fn with_embeds(ctx: &Context,
                   message: &Message,
                   groups: HashMap<String, Arc<CommandGroup>>,
                   args: Vec<String>) -> Result<(), String> {
    if !args.is_empty() {
        let name = args.join(" ");

        for (group_name, group) in groups {
            let mut found: Option<(&String, &Command)> = None;

            if let Some(ref prefix) = group.prefix {
                for (command_name, command) in &group.commands {
                    if name == format!("{} {}", prefix, command_name) {
                        found = Some((command_name, command));
                    }
                }
            } else {
                for (command_name, command) in &group.commands {
                    if name == command_name[..] {
                        found = Some((command_name, command));
                    }
                }
            };

            if let Some((command_name, command)) = found {
                if !command.help_available {
                    error_embed(ctx, message, "**Error**: No help available.");

                    return Ok(());
                }

                let _ = ctx.send_message(message.channel_id, |m| {
                    m.embed(|e| {
                        let mut embed = e.colour(Colour::rosewater())
                            .title(command_name);
                        if let Some(ref desc) = command.desc {
                            embed = embed.field(|f| {
                                f.name("Description")
                                    .value(desc)
                                    .inline(false)
                            });
                        }

                        if let Some(ref usage) = command.usage {
                            embed = embed.field(|f| {
                                f.name("Usage")
                                    .value(&format!("{} {}", command_name, usage))
                            });
                        }

                        if group_name != "Ungrouped" {
                            embed = embed.field(|f| {
                                f.name("Group")
                                    .value(&group_name)
                            });
                        }

                        let available = if command.dm_only {
                            "Only in DM"
                        } else if command.guild_only {
                            "Only in guilds"
                        } else {
                            "In DM and guilds"
                        };

                        embed = embed.field(|f| {
                            f.name("Available")
                                .value(available)
                        });

                        embed
                    })
                });

                return Ok(());
            }
        }

        let error_msg = format!("**Error**: Command `{}` not found.", name);
        error_embed(ctx, message, &error_msg);

        return Ok(());
    }

    let _ = ctx.send_message(message.channel_id, |m| {
        m.embed(|mut e| {
            e = e.colour(Colour::rosewater())
                .description("To get help about individual command, pass its \
                              name as an argument to this command.");

            for (group_name, group) in groups {
                let mut desc = String::new();

                if let Some(ref x) = group.prefix {
                    let _ = write!(desc, "Prefix: {}\n", x);
                }

                desc.push_str("Commands:\n");

                let mut no_commands = true;

                for (n, cmd) in &group.commands {
                    if cmd.help_available {
                        let _ = write!(desc, "`{}`\n", n);

                        no_commands = false;
                    }
                }

                if no_commands {
                    let _ = write!(desc, "*[No commands]*");
                }

                e = e.field(|f| f.name(&group_name).value(&desc));
            }

            e
        })
    });

    Ok(())
}

pub fn plain(ctx: &Context,
             _: &Message,
             groups: HashMap<String, Arc<CommandGroup>>,
             args: Vec<String>) -> Result<(), String> {
    if !args.is_empty() {
        let name = args.join(" ");

        for (group_name, group) in groups {
            let mut found: Option<(&String, &Command)> = None;

            if let Some(ref prefix) = group.prefix {
                for (command_name, command) in &group.commands {
                    if name == format!("{} {}", prefix, command_name) {
                        found = Some((command_name, command));
                    }
                }
            } else {
                for (command_name, command) in &group.commands {
                    if name == command_name[..] {
                        found = Some((command_name, command));
                    }
                }
            };

            if let Some((command_name, command)) = found {
                if !command.help_available {
                    let _ = ctx.say("**Error**: No help available.");
                    return Ok(());
                }

                let mut result = format!("**{}**\n", command_name);

                if let Some(ref desc) = command.desc {
                    let _ = write!(result, "**Description:** {}\n", desc);
                }

                if let Some(ref usage) = command.usage {
                    let _ = write!(result, "**Usage:** {}\n", usage);
                }

                if group_name != "Ungrouped" {
                    let _ = write!(result, "**Group:** {}\n", group_name);
                }

                result.push_str("**Available:** ");
                result.push_str(if command.dm_only {
                    "Only in DM"
                } else if command.guild_only {
                    "Only in guilds"
                } else {
                    "In DM and guilds"
                });
                result.push_str("\n");

                let _ = ctx.say(&result);

                return Ok(());
            }
        }

        let _ = ctx.say(&format!("**Error**: Command `{}` not found.", name));

        return Ok(());
    }

    let mut result = "**Commands**\nTo get help about individual command, pass \
                      its name as an argument to this command.\n\n"
        .to_string();

    for (group_name, group) in groups {
        let _ = write!(result, "**{}:** ", group_name);

        if let Some(ref x) = group.prefix {
            let _ = write!(result, "(prefix: `{}`): ", x);
        }

        let mut no_commands = true;

        for (n, cmd) in &group.commands {
            if cmd.help_available {
                let _ = write!(result, "`{}` ", n);

                no_commands = false;
            }
        }

        if no_commands {
            result.push_str("*[No Commands]*");
        }
    }

    let _ = ctx.say(&result);

    Ok(())
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Off-screen windows.
//!
//! This is used for off-screen rendering mode only; on-screen windows (the default embedding mode)
//! are managed by a platform toolkit (Glutin).

use eutil::Downcast;
use interfaces::CefBrowser;
use render_handler::CefRenderHandlerExtensions;
use rustc_unicode::str::Utf16Encoder;
use types::{cef_cursor_handle_t, cef_cursor_type_t, cef_rect_t};

use compositing::compositor_task::{self, CompositorProxy, CompositorReceiver};
use compositing::windowing::{WindowEvent, WindowMethods};
use geom::scale_factor::ScaleFactor;
use geom::size::TypedSize2D;
use gleam::gl;
use layers::geometry::DevicePixel;
use layers::platform::surface::NativeGraphicsMetadata;
use libc::{c_char, c_void};
use msg::constellation_msg::{Key, KeyModifiers};
use std::ptr;
use std_url::Url;
use util::cursor::Cursor;
use util::geometry::ScreenPx;
use std::cell::RefCell;
use std::ffi::CString;
use std::rc::Rc;
use std::sync::mpsc::{Sender, channel};
#[cfg(target_os="linux")]
extern crate x11;
#[cfg(target_os="linux")]
use self::x11::xlib::XOpenDisplay;

#[cfg(target_os="linux")]
pub static mut DISPLAY: *mut c_void = 0 as *mut c_void;

/// The type of an off-screen window.
#[allow(raw_pointer_derive)]
#[derive(Clone)]
pub struct Window {
    cef_browser: RefCell<Option<CefBrowser>>,
}

#[cfg(target_os="macos")]
fn load_gl() {
    const RTLD_DEFAULT: *mut c_void = (-2) as *mut c_void;

    extern {
        fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void;
    }

    gl::load_with(|s| {
        unsafe {
            let c_str = CString::new(s).unwrap();
            dlsym(RTLD_DEFAULT, c_str.as_ptr()) as *const c_void
        }
    });
}

#[cfg(target_os="linux")]
fn load_gl() {
    extern {
        fn glXGetProcAddress(symbol: *const c_char) -> *mut c_void;
    }

    gl::load_with(|s| {
        unsafe {
            let c_str = CString::new(s).unwrap();
            glXGetProcAddress(c_str.as_ptr()) as *const c_void
        }
    });
}

impl Window {
    /// Creates a new window.
    pub fn new() -> Rc<Window> {
        load_gl();

        Rc::new(Window {
            cef_browser: RefCell::new(None),
        })
    }

    /// Sets the current browser.
    pub fn set_browser(&self, browser: CefBrowser) {
        *self.cef_browser.borrow_mut() = Some(browser)
    }

    /// Currently unimplemented.
    pub fn wait_events(&self) -> Vec<WindowEvent> {
        vec![WindowEvent::Idle]
    }

    fn cursor_type_for_cursor(&self, cursor: Cursor) -> cef_cursor_type_t {
        match cursor {
            Cursor::NoCursor => return cef_cursor_type_t::CT_NONE,
            Cursor::ContextMenuCursor => return cef_cursor_type_t::CT_CONTEXTMENU,
            Cursor::GrabbingCursor => return cef_cursor_type_t::CT_GRABBING,
            Cursor::CrosshairCursor => return cef_cursor_type_t::CT_CROSS,
            Cursor::CopyCursor => return cef_cursor_type_t::CT_COPY,
            Cursor::AliasCursor => return cef_cursor_type_t::CT_ALIAS,
            Cursor::TextCursor => return cef_cursor_type_t::CT_IBEAM,
            Cursor::GrabCursor | Cursor::AllScrollCursor =>
                return cef_cursor_type_t::CT_GRAB,
            Cursor::NoDropCursor => return cef_cursor_type_t::CT_NODROP,
            Cursor::NotAllowedCursor => return cef_cursor_type_t::CT_NOTALLOWED,
            Cursor::PointerCursor => return cef_cursor_type_t::CT_POINTER,
            Cursor::SResizeCursor => return cef_cursor_type_t::CT_SOUTHRESIZE,
            Cursor::WResizeCursor => return cef_cursor_type_t::CT_WESTRESIZE,
            Cursor::EwResizeCursor => return cef_cursor_type_t::CT_EASTWESTRESIZE,
            Cursor::ColResizeCursor => return cef_cursor_type_t::CT_COLUMNRESIZE,
            Cursor::EResizeCursor => return cef_cursor_type_t::CT_EASTRESIZE,
            Cursor::NResizeCursor => return cef_cursor_type_t::CT_NORTHRESIZE,
            Cursor::NsResizeCursor => return cef_cursor_type_t::CT_NORTHSOUTHRESIZE,
            Cursor::RowResizeCursor => return cef_cursor_type_t::CT_ROWRESIZE,
            Cursor::VerticalTextCursor => return cef_cursor_type_t::CT_VERTICALTEXT,
            _ => return cef_cursor_type_t::CT_POINTER,
        }
    }

    /// Returns the Cocoa cursor for a CSS cursor. These match Firefox, except where Firefox
    /// bundles custom resources (which we don't yet do).
    #[cfg(target_os="macos")]
    fn cursor_handle_for_cursor(&self, cursor: Cursor) -> cef_cursor_handle_t {
        use cocoa::base::class;

        unsafe {
            match cursor {
                Cursor::NoCursor => return 0 as cef_cursor_handle_t,
                Cursor::ContextMenuCursor => msg_send![class("NSCursor"), contextualMenuCursor],
                Cursor::GrabbingCursor => msg_send![class("NSCursor"), closedHandCursor],
                Cursor::CrosshairCursor => msg_send![class("NSCursor"), crosshairCursor],
                Cursor::CopyCursor => msg_send![class("NSCursor"), dragCopyCursor],
                Cursor::AliasCursor => msg_send![class("NSCursor"), dragLinkCursor],
                Cursor::TextCursor => msg_send![class("NSCursor"), IBeamCursor],
                Cursor::GrabCursor | Cursor::AllScrollCursor =>
                    msg_send![class("NSCursor"), openHandCursor],
                Cursor::NoDropCursor | Cursor::NotAllowedCursor =>
                    msg_send![class("NSCursor"), operationNotAllowedCursor],
                Cursor::PointerCursor => msg_send![class("NSCursor"), pointingHandCursor],
                Cursor::SResizeCursor => msg_send![class("NSCursor"), resizeDownCursor],
                Cursor::WResizeCursor => msg_send![class("NSCursor"), resizeLeftCursor],
                Cursor::EwResizeCursor | Cursor::ColResizeCursor =>
                    msg_send![class("NSCursor"), resizeLeftRightCursor],
                Cursor::EResizeCursor => msg_send![class("NSCursor"), resizeRightCursor],
                Cursor::NResizeCursor => msg_send![class("NSCursor"), resizeUpCursor],
                Cursor::NsResizeCursor | Cursor::RowResizeCursor =>
                    msg_send![class("NSCursor"), resizeUpDownCursor],
                Cursor::VerticalTextCursor => msg_send![class("NSCursor"), IBeamCursorForVerticalLayout],
                _ => msg_send![class("NSCursor"), arrowCursor],
            }
        }
    }

    #[cfg(not(target_os="macos"))]
    fn cursor_handle_for_cursor(&self, _: Cursor) -> cef_cursor_handle_t {
        0
    }
}

impl WindowMethods for Window {
    fn framebuffer_size(&self) -> TypedSize2D<DevicePixel,u32> {
        let browser = self.cef_browser.borrow();
        match *browser {
            None => TypedSize2D(400, 300),
            Some(ref browser) => {
                let mut rect = cef_rect_t::zero();
                browser.get_host()
                       .get_client()
                       .get_render_handler()
                       .get_backing_rect((*browser).clone(), &mut rect);
                TypedSize2D(rect.width as u32, rect.height as u32)
            }
        }
    }

    fn size(&self) -> TypedSize2D<ScreenPx,f32> {
        let browser = self.cef_browser.borrow();
        match *browser {
            None => TypedSize2D(400.0, 300.0),
            Some(ref browser) => {
                let mut rect = cef_rect_t::zero();
                browser.get_host()
                       .get_client()
                       .get_render_handler()
                       .get_view_rect((*browser).clone(), &mut rect);
                TypedSize2D(rect.width as f32, rect.height as f32)
            }
        }
    }

    fn present(&self) {
        let browser = self.cef_browser.borrow();
        match *browser {
            None => {}
            Some(ref browser) => {
                browser.get_host().get_client().get_render_handler().on_present(browser.clone());
            }
        }
    }

    fn hidpi_factor(&self) -> ScaleFactor<ScreenPx,DevicePixel,f32> {
        let browser = self.cef_browser.borrow();
        match *browser {
            None => ScaleFactor::new(1.0),
            Some(ref browser) => {
                let mut view_rect = cef_rect_t::zero();
                browser.get_host()
                       .get_client()
                       .get_render_handler()
                       .get_view_rect((*browser).clone(), &mut view_rect);
                let mut backing_rect = cef_rect_t::zero();
                browser.get_host()
                       .get_client()
                       .get_render_handler()
                       .get_backing_rect((*browser).clone(), &mut backing_rect);
                ScaleFactor::new(backing_rect.width as f32 / view_rect.width as f32)
            }
        }
    }

    #[cfg(target_os="macos")]
    fn native_metadata(&self) -> NativeGraphicsMetadata {
        use cgl::{CGLGetCurrentContext, CGLGetPixelFormat};

        // FIXME(pcwalton)
        unsafe {
            NativeGraphicsMetadata {
                pixel_format: CGLGetPixelFormat(CGLGetCurrentContext()),
            }
        }
    }

    #[cfg(target_os="linux")]
    fn native_metadata(&self) -> NativeGraphicsMetadata {
       unsafe {
           NativeGraphicsMetadata {
               display: DISPLAY,
           }
       }
    }

    fn create_compositor_channel(_: &Option<Rc<Window>>)
                                 -> (Box<CompositorProxy+Send>, Box<CompositorReceiver>) {
        let (sender, receiver) = channel();
        (box CefCompositorProxy {
             sender: sender,
         } as Box<CompositorProxy+Send>,
         box receiver as Box<CompositorReceiver>)
    }

    fn prepare_for_composite(&self, width: usize, height: usize) -> bool {
        let browser = self.cef_browser.borrow();
        match *browser {
            None => {}
            Some(ref browser) => {
                browser.get_host().get_client().get_render_handler().paint(browser.clone(), width, height);
            }
        }
        true
    }

    fn load_end(&self) {
        // FIXME(pcwalton): The status code 200 is a lie.
        let browser = self.cef_browser.borrow();
        let browser = match *browser {
            None => return,
            Some(ref browser) => browser,
        };
        browser.get_host()
               .get_client()
               .get_load_handler()
               .on_load_end((*browser).clone(), browser.get_main_frame(), 200);
    }

    fn set_page_title(&self, string: Option<String>) {
        let browser = self.cef_browser.borrow();
        let browser = match *browser {
            None => return,
            Some(ref browser) => browser,
        };
        let frame = browser.get_main_frame();
        let frame = frame.downcast();
        let mut title_visitor = frame.title_visitor.borrow_mut();
        match &mut *title_visitor {
            &mut None => {}
            &mut Some(ref mut visitor) => {
                match string {
                    None => visitor.visit(&[]),
                    Some(string) => {
                        let utf16_chars: Vec<u16> = Utf16Encoder::new(string.chars()).collect();
                        visitor.visit(&utf16_chars)
                    }
                }
            }
        }
    }

    fn set_page_url(&self, url: Url) {
        let browser = self.cef_browser.borrow();
        let browser = match *browser {
            None => return,
            Some(ref browser) => browser,
        };
        let frame = browser.get_main_frame();
        let frame = frame.downcast();
        // FIXME(https://github.com/rust-lang/rust/issues/23338)
        let mut frame_url = frame.url.borrow_mut();
        *frame_url = url.to_string()
    }

    fn handle_key(&self, _: Key, _: KeyModifiers) {
        // TODO(negge)
    }

    fn set_cursor(&self, cursor: Cursor) {
        use types::{CefCursorInfo,cef_point_t,cef_size_t};
        let browser = self.cef_browser.borrow();
        match *browser {
            None => {}
            Some(ref browser) => {
                let cursor_handle = self.cursor_handle_for_cursor(cursor);
                let info = CefCursorInfo { hotspot: cef_point_t {x: 0, y: 0}, image_scale_factor: 0.0, buffer: 0 as *mut isize, size: cef_size_t { width: 0, height: 0 } };
                browser.get_host()
                       .get_client()
                       .get_render_handler()
                       .on_cursor_change(browser.clone(), cursor_handle,
                         self.cursor_type_for_cursor(cursor), &info)
            }
        }
    }
}

struct CefCompositorProxy {
    sender: Sender<compositor_task::Msg>,
}

impl CompositorProxy for CefCompositorProxy {
    #[cfg(target_os="macos")]
    fn send(&mut self, msg: compositor_task::Msg) {
        use cocoa::appkit::{NSApp, NSApplication, NSApplicationDefined};
        use cocoa::appkit::{NSEvent, NSEventModifierFlags, NSEventSubtype};
        use cocoa::base::nil;
        use cocoa::foundation::{NSAutoreleasePool, NSPoint};

        // Send a message and kick the OS event loop awake.
        self.sender.send(msg).unwrap();

        unsafe {
            let pool = NSAutoreleasePool::new(nil);
            let event =
                NSEvent::otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2_(
                nil,
                NSApplicationDefined,
                NSPoint::new(0.0, 0.0),
                NSEventModifierFlags::empty(),
                0.0,
                0,
                nil,
                NSEventSubtype::NSWindowExposedEventType,
                0,
                0);
            NSApp().postEvent_atStart_(event, 0);
            pool.drain();
        }
    }

    #[cfg(target_os="linux")]
    fn send(&mut self, msg: compositor_task::Msg) {
        // FIXME(pcwalton): Kick the GTK event loop awake?
        self.sender.send(msg).unwrap();
    }

    fn clone_compositor_proxy(&self) -> Box<CompositorProxy+Send> {
        box CefCompositorProxy {
            sender: self.sender.clone(),
        } as Box<CompositorProxy+Send>
    }
}

#[cfg(target_os="linux")]
pub fn init_window() {
    unsafe { DISPLAY = XOpenDisplay(ptr::null()) as *mut c_void ; }
}
#[cfg(not(target_os="linux"))]
pub fn init_window() {}

#[cfg(target_os="linux")]
#[no_mangle]
pub extern "C" fn cef_get_xdisplay() -> *mut c_void {
    unsafe { DISPLAY }
}
#[cfg(not(target_os="linux"))]
#[no_mangle]
pub extern "C" fn cef_get_xdisplay() -> *mut c_void {
    ptr::null_mut()
}
<commit_msg>remove misleading FIXME(pcwalton) regarding gtk event loops in cef window<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Off-screen windows.
//!
//! This is used for off-screen rendering mode only; on-screen windows (the default embedding mode)
//! are managed by a platform toolkit (Glutin).

use eutil::Downcast;
use interfaces::CefBrowser;
use render_handler::CefRenderHandlerExtensions;
use rustc_unicode::str::Utf16Encoder;
use types::{cef_cursor_handle_t, cef_cursor_type_t, cef_rect_t};

use compositing::compositor_task::{self, CompositorProxy, CompositorReceiver};
use compositing::windowing::{WindowEvent, WindowMethods};
use geom::scale_factor::ScaleFactor;
use geom::size::TypedSize2D;
use gleam::gl;
use layers::geometry::DevicePixel;
use layers::platform::surface::NativeGraphicsMetadata;
use libc::{c_char, c_void};
use msg::constellation_msg::{Key, KeyModifiers};
use std::ptr;
use std_url::Url;
use util::cursor::Cursor;
use util::geometry::ScreenPx;
use std::cell::RefCell;
use std::ffi::CString;
use std::rc::Rc;
use std::sync::mpsc::{Sender, channel};
#[cfg(target_os="linux")]
extern crate x11;
#[cfg(target_os="linux")]
use self::x11::xlib::XOpenDisplay;

#[cfg(target_os="linux")]
pub static mut DISPLAY: *mut c_void = 0 as *mut c_void;

/// The type of an off-screen window.
#[allow(raw_pointer_derive)]
#[derive(Clone)]
pub struct Window {
    cef_browser: RefCell<Option<CefBrowser>>,
}

#[cfg(target_os="macos")]
fn load_gl() {
    const RTLD_DEFAULT: *mut c_void = (-2) as *mut c_void;

    extern {
        fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void;
    }

    gl::load_with(|s| {
        unsafe {
            let c_str = CString::new(s).unwrap();
            dlsym(RTLD_DEFAULT, c_str.as_ptr()) as *const c_void
        }
    });
}

#[cfg(target_os="linux")]
fn load_gl() {
    extern {
        fn glXGetProcAddress(symbol: *const c_char) -> *mut c_void;
    }

    gl::load_with(|s| {
        unsafe {
            let c_str = CString::new(s).unwrap();
            glXGetProcAddress(c_str.as_ptr()) as *const c_void
        }
    });
}

impl Window {
    /// Creates a new window.
    pub fn new() -> Rc<Window> {
        load_gl();

        Rc::new(Window {
            cef_browser: RefCell::new(None),
        })
    }

    /// Sets the current browser.
    pub fn set_browser(&self, browser: CefBrowser) {
        *self.cef_browser.borrow_mut() = Some(browser)
    }

    /// Currently unimplemented.
    pub fn wait_events(&self) -> Vec<WindowEvent> {
        vec![WindowEvent::Idle]
    }

    fn cursor_type_for_cursor(&self, cursor: Cursor) -> cef_cursor_type_t {
        match cursor {
            Cursor::NoCursor => return cef_cursor_type_t::CT_NONE,
            Cursor::ContextMenuCursor => return cef_cursor_type_t::CT_CONTEXTMENU,
            Cursor::GrabbingCursor => return cef_cursor_type_t::CT_GRABBING,
            Cursor::CrosshairCursor => return cef_cursor_type_t::CT_CROSS,
            Cursor::CopyCursor => return cef_cursor_type_t::CT_COPY,
            Cursor::AliasCursor => return cef_cursor_type_t::CT_ALIAS,
            Cursor::TextCursor => return cef_cursor_type_t::CT_IBEAM,
            Cursor::GrabCursor | Cursor::AllScrollCursor =>
                return cef_cursor_type_t::CT_GRAB,
            Cursor::NoDropCursor => return cef_cursor_type_t::CT_NODROP,
            Cursor::NotAllowedCursor => return cef_cursor_type_t::CT_NOTALLOWED,
            Cursor::PointerCursor => return cef_cursor_type_t::CT_POINTER,
            Cursor::SResizeCursor => return cef_cursor_type_t::CT_SOUTHRESIZE,
            Cursor::WResizeCursor => return cef_cursor_type_t::CT_WESTRESIZE,
            Cursor::EwResizeCursor => return cef_cursor_type_t::CT_EASTWESTRESIZE,
            Cursor::ColResizeCursor => return cef_cursor_type_t::CT_COLUMNRESIZE,
            Cursor::EResizeCursor => return cef_cursor_type_t::CT_EASTRESIZE,
            Cursor::NResizeCursor => return cef_cursor_type_t::CT_NORTHRESIZE,
            Cursor::NsResizeCursor => return cef_cursor_type_t::CT_NORTHSOUTHRESIZE,
            Cursor::RowResizeCursor => return cef_cursor_type_t::CT_ROWRESIZE,
            Cursor::VerticalTextCursor => return cef_cursor_type_t::CT_VERTICALTEXT,
            _ => return cef_cursor_type_t::CT_POINTER,
        }
    }

    /// Returns the Cocoa cursor for a CSS cursor. These match Firefox, except where Firefox
    /// bundles custom resources (which we don't yet do).
    #[cfg(target_os="macos")]
    fn cursor_handle_for_cursor(&self, cursor: Cursor) -> cef_cursor_handle_t {
        use cocoa::base::class;

        unsafe {
            match cursor {
                Cursor::NoCursor => return 0 as cef_cursor_handle_t,
                Cursor::ContextMenuCursor => msg_send![class("NSCursor"), contextualMenuCursor],
                Cursor::GrabbingCursor => msg_send![class("NSCursor"), closedHandCursor],
                Cursor::CrosshairCursor => msg_send![class("NSCursor"), crosshairCursor],
                Cursor::CopyCursor => msg_send![class("NSCursor"), dragCopyCursor],
                Cursor::AliasCursor => msg_send![class("NSCursor"), dragLinkCursor],
                Cursor::TextCursor => msg_send![class("NSCursor"), IBeamCursor],
                Cursor::GrabCursor | Cursor::AllScrollCursor =>
                    msg_send![class("NSCursor"), openHandCursor],
                Cursor::NoDropCursor | Cursor::NotAllowedCursor =>
                    msg_send![class("NSCursor"), operationNotAllowedCursor],
                Cursor::PointerCursor => msg_send![class("NSCursor"), pointingHandCursor],
                Cursor::SResizeCursor => msg_send![class("NSCursor"), resizeDownCursor],
                Cursor::WResizeCursor => msg_send![class("NSCursor"), resizeLeftCursor],
                Cursor::EwResizeCursor | Cursor::ColResizeCursor =>
                    msg_send![class("NSCursor"), resizeLeftRightCursor],
                Cursor::EResizeCursor => msg_send![class("NSCursor"), resizeRightCursor],
                Cursor::NResizeCursor => msg_send![class("NSCursor"), resizeUpCursor],
                Cursor::NsResizeCursor | Cursor::RowResizeCursor =>
                    msg_send![class("NSCursor"), resizeUpDownCursor],
                Cursor::VerticalTextCursor => msg_send![class("NSCursor"), IBeamCursorForVerticalLayout],
                _ => msg_send![class("NSCursor"), arrowCursor],
            }
        }
    }

    #[cfg(not(target_os="macos"))]
    fn cursor_handle_for_cursor(&self, _: Cursor) -> cef_cursor_handle_t {
        0
    }
}

impl WindowMethods for Window {
    fn framebuffer_size(&self) -> TypedSize2D<DevicePixel,u32> {
        let browser = self.cef_browser.borrow();
        match *browser {
            None => TypedSize2D(400, 300),
            Some(ref browser) => {
                let mut rect = cef_rect_t::zero();
                browser.get_host()
                       .get_client()
                       .get_render_handler()
                       .get_backing_rect((*browser).clone(), &mut rect);
                TypedSize2D(rect.width as u32, rect.height as u32)
            }
        }
    }

    fn size(&self) -> TypedSize2D<ScreenPx,f32> {
        let browser = self.cef_browser.borrow();
        match *browser {
            None => TypedSize2D(400.0, 300.0),
            Some(ref browser) => {
                let mut rect = cef_rect_t::zero();
                browser.get_host()
                       .get_client()
                       .get_render_handler()
                       .get_view_rect((*browser).clone(), &mut rect);
                TypedSize2D(rect.width as f32, rect.height as f32)
            }
        }
    }

    fn present(&self) {
        let browser = self.cef_browser.borrow();
        match *browser {
            None => {}
            Some(ref browser) => {
                browser.get_host().get_client().get_render_handler().on_present(browser.clone());
            }
        }
    }

    fn hidpi_factor(&self) -> ScaleFactor<ScreenPx,DevicePixel,f32> {
        let browser = self.cef_browser.borrow();
        match *browser {
            None => ScaleFactor::new(1.0),
            Some(ref browser) => {
                let mut view_rect = cef_rect_t::zero();
                browser.get_host()
                       .get_client()
                       .get_render_handler()
                       .get_view_rect((*browser).clone(), &mut view_rect);
                let mut backing_rect = cef_rect_t::zero();
                browser.get_host()
                       .get_client()
                       .get_render_handler()
                       .get_backing_rect((*browser).clone(), &mut backing_rect);
                ScaleFactor::new(backing_rect.width as f32 / view_rect.width as f32)
            }
        }
    }

    #[cfg(target_os="macos")]
    fn native_metadata(&self) -> NativeGraphicsMetadata {
        use cgl::{CGLGetCurrentContext, CGLGetPixelFormat};

        // FIXME(pcwalton)
        unsafe {
            NativeGraphicsMetadata {
                pixel_format: CGLGetPixelFormat(CGLGetCurrentContext()),
            }
        }
    }

    #[cfg(target_os="linux")]
    fn native_metadata(&self) -> NativeGraphicsMetadata {
       unsafe {
           NativeGraphicsMetadata {
               display: DISPLAY,
           }
       }
    }

    fn create_compositor_channel(_: &Option<Rc<Window>>)
                                 -> (Box<CompositorProxy+Send>, Box<CompositorReceiver>) {
        let (sender, receiver) = channel();
        (box CefCompositorProxy {
             sender: sender,
         } as Box<CompositorProxy+Send>,
         box receiver as Box<CompositorReceiver>)
    }

    fn prepare_for_composite(&self, width: usize, height: usize) -> bool {
        let browser = self.cef_browser.borrow();
        match *browser {
            None => {}
            Some(ref browser) => {
                browser.get_host().get_client().get_render_handler().paint(browser.clone(), width, height);
            }
        }
        true
    }

    fn load_end(&self) {
        // FIXME(pcwalton): The status code 200 is a lie.
        let browser = self.cef_browser.borrow();
        let browser = match *browser {
            None => return,
            Some(ref browser) => browser,
        };
        browser.get_host()
               .get_client()
               .get_load_handler()
               .on_load_end((*browser).clone(), browser.get_main_frame(), 200);
    }

    fn set_page_title(&self, string: Option<String>) {
        let browser = self.cef_browser.borrow();
        let browser = match *browser {
            None => return,
            Some(ref browser) => browser,
        };
        let frame = browser.get_main_frame();
        let frame = frame.downcast();
        let mut title_visitor = frame.title_visitor.borrow_mut();
        match &mut *title_visitor {
            &mut None => {}
            &mut Some(ref mut visitor) => {
                match string {
                    None => visitor.visit(&[]),
                    Some(string) => {
                        let utf16_chars: Vec<u16> = Utf16Encoder::new(string.chars()).collect();
                        visitor.visit(&utf16_chars)
                    }
                }
            }
        }
    }

    fn set_page_url(&self, url: Url) {
        let browser = self.cef_browser.borrow();
        let browser = match *browser {
            None => return,
            Some(ref browser) => browser,
        };
        let frame = browser.get_main_frame();
        let frame = frame.downcast();
        // FIXME(https://github.com/rust-lang/rust/issues/23338)
        let mut frame_url = frame.url.borrow_mut();
        *frame_url = url.to_string()
    }

    fn handle_key(&self, _: Key, _: KeyModifiers) {
        // TODO(negge)
    }

    fn set_cursor(&self, cursor: Cursor) {
        use types::{CefCursorInfo,cef_point_t,cef_size_t};
        let browser = self.cef_browser.borrow();
        match *browser {
            None => {}
            Some(ref browser) => {
                let cursor_handle = self.cursor_handle_for_cursor(cursor);
                let info = CefCursorInfo { hotspot: cef_point_t {x: 0, y: 0}, image_scale_factor: 0.0, buffer: 0 as *mut isize, size: cef_size_t { width: 0, height: 0 } };
                browser.get_host()
                       .get_client()
                       .get_render_handler()
                       .on_cursor_change(browser.clone(), cursor_handle,
                         self.cursor_type_for_cursor(cursor), &info)
            }
        }
    }
}

struct CefCompositorProxy {
    sender: Sender<compositor_task::Msg>,
}

impl CompositorProxy for CefCompositorProxy {
    #[cfg(target_os="macos")]
    fn send(&mut self, msg: compositor_task::Msg) {
        use cocoa::appkit::{NSApp, NSApplication, NSApplicationDefined};
        use cocoa::appkit::{NSEvent, NSEventModifierFlags, NSEventSubtype};
        use cocoa::base::nil;
        use cocoa::foundation::{NSAutoreleasePool, NSPoint};

        // Send a message and kick the OS event loop awake.
        self.sender.send(msg).unwrap();

        unsafe {
            let pool = NSAutoreleasePool::new(nil);
            let event =
                NSEvent::otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2_(
                nil,
                NSApplicationDefined,
                NSPoint::new(0.0, 0.0),
                NSEventModifierFlags::empty(),
                0.0,
                0,
                nil,
                NSEventSubtype::NSWindowExposedEventType,
                0,
                0);
            NSApp().postEvent_atStart_(event, 0);
            pool.drain();
        }
    }

    #[cfg(target_os="linux")]
    fn send(&mut self, msg: compositor_task::Msg) {
        self.sender.send(msg).unwrap();
    }

    fn clone_compositor_proxy(&self) -> Box<CompositorProxy+Send> {
        box CefCompositorProxy {
            sender: self.sender.clone(),
        } as Box<CompositorProxy+Send>
    }
}

#[cfg(target_os="linux")]
pub fn init_window() {
    unsafe { DISPLAY = XOpenDisplay(ptr::null()) as *mut c_void ; }
}
#[cfg(not(target_os="linux"))]
pub fn init_window() {}

#[cfg(target_os="linux")]
#[no_mangle]
pub extern "C" fn cef_get_xdisplay() -> *mut c_void {
    unsafe { DISPLAY }
}
#[cfg(not(target_os="linux"))]
#[no_mangle]
pub extern "C" fn cef_get_xdisplay() -> *mut c_void {
    ptr::null_mut()
}
<|endoftext|>