<commit_before>use dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize};
use event::{Event, WindowEvent};
use icon::Icon;
use monitor::{MonitorHandle as RootMH};
use window::{CreationError, MouseCursor, WindowAttributes, WindowId as RootWI};
use super::{EventLoopWindowTarget, register};
use std::collections::VecDeque;
use std::collections::vec_deque::IntoIter as VecDequeIter;
use std::cell::RefCell;
use stdweb::{
    traits::*,
    unstable::TryInto
};
use stdweb::web::{
    document, window,
    html_element::CanvasElement,
};

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MonitorHandle;

impl MonitorHandle {
    pub fn get_hidpi_factor(&self) -> f64 {
        1.0
    }

    pub fn get_position(&self) -> PhysicalPosition {
        unimplemented!();
    }

    pub fn get_dimensions(&self) -> PhysicalSize {
        unimplemented!();
    }

    pub fn get_name(&self) -> Option<String> {
        unimplemented!();
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WindowId;

#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PlatformSpecificWindowBuilderAttributes;

impl WindowId {
    pub unsafe fn dummy() -> WindowId {
        WindowId
    }
}

pub struct Window {
    pub(crate) canvas: CanvasElement,
    pub(crate) redraw: Box<dyn Fn()>,
    previous_pointer: RefCell<&'static str>,
    position: RefCell<LogicalPosition>,
}

impl Window {
    pub fn new<T>(target: &EventLoopWindowTarget<T>, attr: WindowAttributes,
                  _: PlatformSpecificWindowBuilderAttributes) -> Result<Self, CreationError> {
        let element = document()
            .create_element("canvas")
            .map_err(|_| CreationError::OsError("Failed to create canvas element".to_owned()))?;
        let canvas: CanvasElement = element.try_into()
            .map_err(|_| CreationError::OsError("Failed to create canvas element".to_owned()))?;
        document().body()
            .ok_or_else(|| CreationError::OsError("Failed to find body node".to_owned()))?
            .append_child(&canvas);

        register(&target.runner, &canvas);

        let runner = target.runner.clone();
        let redraw = Box::new(move || window().request_animation_frame(|| runner.send_event(Event::WindowEvent {
            window_id: RootWI(WindowId),
            event: WindowEvent::RedrawRequested
        })));

        let window = Window {
            canvas,
            redraw,
            previous_pointer: RefCell::new("auto"),
            position: RefCell::new(LogicalPosition {
                x: 0.0,
                y: 0.0
            })
        };

        if let Some(dimensions) = attr.dimensions {
            window.set_inner_size(dimensions);
        } else {
            window.set_inner_size(LogicalSize {
                width: 1024.0,
                height: 768.0,
            })
        }
        window.set_min_dimensions(attr.min_dimensions);
        window.set_max_dimensions(attr.max_dimensions);
        window.set_resizable(attr.resizable);
        window.set_title(&attr.title);
        window.set_maximized(attr.maximized);
        if attr.visible {
            window.show();
        } else {
            window.hide();
        }
        //window.set_transparent(attr.transparent);
        window.set_decorations(attr.decorations);
        window.set_always_on_top(attr.always_on_top);
        window.set_window_icon(attr.window_icon);

        Ok(window)
    }

    pub fn set_title(&self, title: &str) {
        document().set_title(title);
    }

    pub fn show(&self) {
        // Intentionally a no-op
    }

    pub fn hide(&self) {
        // Intentionally a no-op
    }

    pub fn request_redraw(&self) {
        (self.redraw)();
    }

    pub fn get_position(&self) -> Option<LogicalPosition> {
        let bounds = self.canvas.get_bounding_client_rect();
        Some(LogicalPosition {
            x: bounds.get_x(),
            y: bounds.get_y(),
        })
    }

    pub fn get_inner_position(&self) -> Option<LogicalPosition> {
        Some(*self.position.borrow())
    }

    pub fn set_position(&self, position: LogicalPosition) {
        *self.position.borrow_mut() = position;
        self.canvas.set_attribute("position", "fixed")
            .expect("Setting the position for the canvas");
        self.canvas.set_attribute("left", &position.x.to_string())
            .expect("Setting the position for the canvas");
        self.canvas.set_attribute("top", &position.y.to_string())
            .expect("Setting the position for the canvas");
    }

    #[inline]
    pub fn get_inner_size(&self) -> Option<LogicalSize> {
        Some(LogicalSize {
            width: self.canvas.width() as f64,
            height: self.canvas.height() as f64
        })
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<LogicalSize> {
        Some(LogicalSize {
            width: self.canvas.width() as f64,
            height: self.canvas.height() as f64
        })
    }

    #[inline]
    pub fn set_inner_size(&self, size: LogicalSize) {
        self.canvas.set_width(size.width as u32);
        self.canvas.set_height(size.height as u32);
    }

    #[inline]
    pub fn set_min_dimensions(&self, _dimensions: Option<LogicalSize>) {
        // Intentionally a no-op: users can't resize canvas elements
    }

    #[inline]
    pub fn set_max_dimensions(&self, _dimensions: Option<LogicalSize>) {
        // Intentionally a no-op: users can't resize canvas elements
    }

    #[inline]
    pub fn set_resizable(&self, _resizable: bool) {
        // Intentionally a no-op: users can't resize canvas elements
    }

    #[inline]
    pub fn get_hidpi_factor(&self) -> f64 {
        1.0
    }

    #[inline]
    pub fn set_cursor(&self, cursor: MouseCursor) {
        let text = match cursor {
            MouseCursor::Default => "auto",
            MouseCursor::Crosshair => "crosshair",
            MouseCursor::Hand => "pointer",
            MouseCursor::Arrow => "default",
            MouseCursor::Move => "move",
            MouseCursor::Text => "text",
            MouseCursor::Wait => "wait",
            MouseCursor::Help => "help",
            MouseCursor::Progress => "progress",

            MouseCursor::NotAllowed => "not-allowed",
            MouseCursor::ContextMenu => "context-menu",
            MouseCursor::Cell => "cell",
            MouseCursor::VerticalText => "vertical-text",
            MouseCursor::Alias => "alias",
            MouseCursor::Copy => "copy",
            MouseCursor::NoDrop => "no-drop",
            MouseCursor::Grab => "grab",
            MouseCursor::Grabbing => "grabbing",
            MouseCursor::AllScroll => "all-scroll",
            MouseCursor::ZoomIn => "zoom-in",
            MouseCursor::ZoomOut => "zoom-out",

            MouseCursor::EResize => "e-resize",
            MouseCursor::NResize => "n-resize",
            MouseCursor::NeResize => "ne-resize",
            MouseCursor::NwResize => "nw-resize",
            MouseCursor::SResize => "s-resize",
            MouseCursor::SeResize => "se-resize",
            MouseCursor::SwResize => "sw-resize",
            MouseCursor::WResize => "w-resize",
            MouseCursor::EwResize => "ew-resize",
            MouseCursor::NsResize => "ns-resize",
            MouseCursor::NeswResize => "nesw-resize",
            MouseCursor::NwseResize => "nwse-resize",
            MouseCursor::ColResize => "col-resize",
            MouseCursor::RowResize => "row-resize",
        };
        *self.previous_pointer.borrow_mut() = text;
        self.canvas.set_attribute("cursor", text)
            .expect("Setting the cursor on the canvas");
    }

    #[inline]
    pub fn set_cursor_position(&self, _position: LogicalPosition) -> Result<(), String> {
        // TODO: pointer capture
        Ok(())
    }

    #[inline]
    pub fn grab_cursor(&self, _grab: bool) -> Result<(), String> {
        // TODO: pointer capture
        Ok(())
    }

    #[inline]
    pub fn hide_cursor(&self, hide: bool) {
        if hide {
            self.canvas.set_attribute("cursor", "none")
                .expect("Setting the cursor on the canvas");
        } else {
            self.canvas.set_attribute("cursor", *self.previous_pointer.borrow())
                .expect("Setting the cursor on the canvas");
        }
    }

    #[inline]
    pub fn set_maximized(&self, _maximized: bool) {
        // TODO: should there be a maximization / fullscreen API?
    }

    #[inline]
    pub fn set_fullscreen(&self, _monitor: Option<RootMH>) {
        // TODO: should there be a maximization / fullscreen API?
    }

    #[inline]
    pub fn set_decorations(&self, _decorations: bool) {
        // Intentionally a no-op, no canvas decorations
    }

    #[inline]
    pub fn set_always_on_top(&self, _always_on_top: bool) {
        // Intentionally a no-op, no window ordering
    }

    #[inline]
    pub fn set_window_icon(&self, _window_icon: Option<Icon>) {
        // Currently an intentional no-op
    }

    #[inline]
    pub fn set_ime_spot(&self, _position: LogicalPosition) {
        // TODO: what is this?
    }

    #[inline]
    pub fn get_current_monitor(&self) -> RootMH {
        RootMH {
            inner: MonitorHandle
        }
    }

    #[inline]
    pub fn get_available_monitors(&self) -> VecDequeIter<MonitorHandle> {
        VecDeque::new().into_iter()
    }

    #[inline]
    pub fn get_primary_monitor(&self) -> MonitorHandle {
        MonitorHandle
    }

    #[inline]
    pub fn id(&self) -> WindowId {
        // TODO ?
        unsafe { WindowId::dummy() }
    }
}
<commit_msg>Fix the request_animation_frame lifetimes<commit_after>use dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize};
use event::{Event, WindowEvent};
use icon::Icon;
use monitor::{MonitorHandle as RootMH};
use window::{CreationError, MouseCursor, WindowAttributes, WindowId as RootWI};
use super::{EventLoopWindowTarget, register};
use std::collections::VecDeque;
use std::collections::vec_deque::IntoIter as VecDequeIter;
use std::cell::RefCell;
use stdweb::{
    traits::*,
    unstable::TryInto
};
use stdweb::web::{
    document, window,
    html_element::CanvasElement,
};

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MonitorHandle;

impl MonitorHandle {
    pub fn get_hidpi_factor(&self) -> f64 {
        1.0
    }

    pub fn get_position(&self) -> PhysicalPosition {
        unimplemented!();
    }

    pub fn get_dimensions(&self) -> PhysicalSize {
        unimplemented!();
    }

    pub fn get_name(&self) -> Option<String> {
        unimplemented!();
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WindowId;

#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PlatformSpecificWindowBuilderAttributes;

impl WindowId {
    pub unsafe fn dummy() -> WindowId {
        WindowId
    }
}

pub struct Window {
    pub(crate) canvas: CanvasElement,
    pub(crate) redraw: Box<dyn Fn()>,
    previous_pointer: RefCell<&'static str>,
    position: RefCell<LogicalPosition>,
}

impl Window {
    pub fn new<T>(target: &EventLoopWindowTarget<T>, attr: WindowAttributes,
                  _: PlatformSpecificWindowBuilderAttributes) -> Result<Self, CreationError> {
        let element = document()
            .create_element("canvas")
            .map_err(|_| CreationError::OsError("Failed to create canvas element".to_owned()))?;
        let canvas: CanvasElement = element.try_into()
            .map_err(|_| CreationError::OsError("Failed to create canvas element".to_owned()))?;
        document().body()
            .ok_or_else(|| CreationError::OsError("Failed to find body node".to_owned()))?
            .append_child(&canvas);

        register(&target.runner, &canvas);

        let runner = target.runner.clone();
        let redraw = Box::new(move || {
            let runner = runner.clone();
            window().request_animation_frame(move |_| runner.send_event(Event::WindowEvent {
                window_id: RootWI(WindowId),
                event: WindowEvent::RedrawRequested
            }));
        });

        let window = Window {
            canvas,
            redraw,
            previous_pointer: RefCell::new("auto"),
            position: RefCell::new(LogicalPosition {
                x: 0.0,
                y: 0.0
            })
        };

        if let Some(dimensions) = attr.dimensions {
            window.set_inner_size(dimensions);
        } else {
            window.set_inner_size(LogicalSize {
                width: 1024.0,
                height: 768.0,
            })
        }
        window.set_min_dimensions(attr.min_dimensions);
        window.set_max_dimensions(attr.max_dimensions);
        window.set_resizable(attr.resizable);
        window.set_title(&attr.title);
        window.set_maximized(attr.maximized);
        if attr.visible {
            window.show();
        } else {
            window.hide();
        }
        //window.set_transparent(attr.transparent);
        window.set_decorations(attr.decorations);
        window.set_always_on_top(attr.always_on_top);
        window.set_window_icon(attr.window_icon);

        Ok(window)
    }

    pub fn set_title(&self, title: &str) {
        document().set_title(title);
    }

    pub fn show(&self) {
        // Intentionally a no-op
    }

    pub fn hide(&self) {
        // Intentionally a no-op
    }

    pub fn request_redraw(&self) {
        (self.redraw)();
    }

    pub fn get_position(&self) -> Option<LogicalPosition> {
        let bounds = self.canvas.get_bounding_client_rect();
        Some(LogicalPosition {
            x: bounds.get_x(),
            y: bounds.get_y(),
        })
    }

    pub fn get_inner_position(&self) -> Option<LogicalPosition> {
        Some(*self.position.borrow())
    }

    pub fn set_position(&self, position: LogicalPosition) {
        *self.position.borrow_mut() = position;
        self.canvas.set_attribute("position", "fixed")
            .expect("Setting the position for the canvas");
        self.canvas.set_attribute("left", &position.x.to_string())
            .expect("Setting the position for the canvas");
        self.canvas.set_attribute("top", &position.y.to_string())
            .expect("Setting the position for the canvas");
    }

    #[inline]
    pub fn get_inner_size(&self) -> Option<LogicalSize> {
        Some(LogicalSize {
            width: self.canvas.width() as f64,
            height: self.canvas.height() as f64
        })
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<LogicalSize> {
        Some(LogicalSize {
            width: self.canvas.width() as f64,
            height: self.canvas.height() as f64
        })
    }

    #[inline]
    pub fn set_inner_size(&self, size: LogicalSize) {
        self.canvas.set_width(size.width as u32);
        self.canvas.set_height(size.height as u32);
    }

    #[inline]
    pub fn set_min_dimensions(&self, _dimensions: Option<LogicalSize>) {
        // Intentionally a no-op: users can't resize canvas elements
    }

    #[inline]
    pub fn set_max_dimensions(&self, _dimensions: Option<LogicalSize>) {
        // Intentionally a no-op: users can't resize canvas elements
    }

    #[inline]
    pub fn set_resizable(&self, _resizable: bool) {
        // Intentionally a no-op: users can't resize canvas elements
    }

    #[inline]
    pub fn get_hidpi_factor(&self) -> f64 {
        1.0
    }

    #[inline]
    pub fn set_cursor(&self, cursor: MouseCursor) {
        let text = match cursor {
            MouseCursor::Default => "auto",
            MouseCursor::Crosshair => "crosshair",
            MouseCursor::Hand => "pointer",
            MouseCursor::Arrow => "default",
            MouseCursor::Move => "move",
            MouseCursor::Text => "text",
            MouseCursor::Wait => "wait",
            MouseCursor::Help => "help",
            MouseCursor::Progress => "progress",

            MouseCursor::NotAllowed => "not-allowed",
            MouseCursor::ContextMenu => "context-menu",
            MouseCursor::Cell => "cell",
            MouseCursor::VerticalText => "vertical-text",
            MouseCursor::Alias => "alias",
            MouseCursor::Copy => "copy",
            MouseCursor::NoDrop => "no-drop",
            MouseCursor::Grab => "grab",
            MouseCursor::Grabbing => "grabbing",
            MouseCursor::AllScroll => "all-scroll",
            MouseCursor::ZoomIn => "zoom-in",
            MouseCursor::ZoomOut => "zoom-out",

            MouseCursor::EResize => "e-resize",
            MouseCursor::NResize => "n-resize",
            MouseCursor::NeResize => "ne-resize",
            MouseCursor::NwResize => "nw-resize",
            MouseCursor::SResize => "s-resize",
            MouseCursor::SeResize => "se-resize",
            MouseCursor::SwResize => "sw-resize",
            MouseCursor::WResize => "w-resize",
            MouseCursor::EwResize => "ew-resize",
            MouseCursor::NsResize => "ns-resize",
            MouseCursor::NeswResize => "nesw-resize",
            MouseCursor::NwseResize => "nwse-resize",
            MouseCursor::ColResize => "col-resize",
            MouseCursor::RowResize => "row-resize",
        };
        *self.previous_pointer.borrow_mut() = text;
        self.canvas.set_attribute("cursor", text)
            .expect("Setting the cursor on the canvas");
    }

    #[inline]
    pub fn set_cursor_position(&self, _position: LogicalPosition) -> Result<(), String> {
        // TODO: pointer capture
        Ok(())
    }

    #[inline]
    pub fn grab_cursor(&self, _grab: bool) -> Result<(), String> {
        // TODO: pointer capture
        Ok(())
    }

    #[inline]
    pub fn hide_cursor(&self, hide: bool) {
        if hide {
            self.canvas.set_attribute("cursor", "none")
                .expect("Setting the cursor on the canvas");
        } else {
            self.canvas.set_attribute("cursor", *self.previous_pointer.borrow())
                .expect("Setting the cursor on the canvas");
        }
    }

    #[inline]
    pub fn set_maximized(&self, _maximized: bool) {
        // TODO: should there be a maximization / fullscreen API?
    }

    #[inline]
    pub fn set_fullscreen(&self, _monitor: Option<RootMH>) {
        // TODO: should there be a maximization / fullscreen API?
    }

    #[inline]
    pub fn set_decorations(&self, _decorations: bool) {
        // Intentionally a no-op, no canvas decorations
    }

    #[inline]
    pub fn set_always_on_top(&self, _always_on_top: bool) {
        // Intentionally a no-op, no window ordering
    }

    #[inline]
    pub fn set_window_icon(&self, _window_icon: Option<Icon>) {
        // Currently an intentional no-op
    }

    #[inline]
    pub fn set_ime_spot(&self, _position: LogicalPosition) {
        // TODO: what is this?
    }

    #[inline]
    pub fn get_current_monitor(&self) -> RootMH {
        RootMH {
            inner: MonitorHandle
        }
    }

    #[inline]
    pub fn get_available_monitors(&self) -> VecDequeIter<MonitorHandle> {
        VecDeque::new().into_iter()
    }

    #[inline]
    pub fn get_primary_monitor(&self) -> MonitorHandle {
        MonitorHandle
    }

    #[inline]
    pub fn id(&self) -> WindowId {
        // TODO ?
        unsafe { WindowId::dummy() }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

use context::GraphicsContextMethods;

use std::libc::{c_char, c_int, c_long, c_uint, c_ulong, c_void};
use std::ptr::null;
use std::ptr;
use extra::arc::Arc;

// Constants.

static GLX_RGBA: c_int = 4;
static GLX_RED_SIZE: c_int = 8;
static GLX_GREEN_SIZE: c_int = 9;
static GLX_BLUE_SIZE: c_int = 10;
static GLX_DEPTH_SIZE: c_int = 12;

static ATTRIBUTES: [c_int, ..4] = [
    GLX_RGBA,
    GLX_DEPTH_SIZE, 24,
    0,
];

// External bindings to Xlib.

// Opaque structures.
struct _XPrivate;
struct _XrmHashBucketRec;
struct Depth;
struct GLXContextOpaque;
struct Visual;

// Sadly we need to copy some of this definition in here because the Xlib macros need to access it.
struct Display {
    ext_data: *XExtData,
    private1: *_XPrivate,
    fd: c_int,
    private2: c_int,
    proto_major_version: c_int,
    proto_minor_version: c_int,
    vendor: *c_char,
    private3: XID,
    private4: XID,
    private5: XID,
    private6: c_int,
    resource_alloc: *c_void,
    byte_order: c_int,
    bitmap_unit: c_int,
    bitmap_pad: c_int,
    bitmap_bit_order: c_int,
    nformats: c_int,
    pixmap_format: *ScreenFormat,
    private8: c_int,
    release: c_int,
    private9: *_XPrivate,
    private10: *_XPrivate,
    qlen: c_int,
    last_request_read: c_ulong,
    request: c_ulong,
    private11: XPointer,
    private12: XPointer,
    private13: XPointer,
    private14: XPointer,
    max_request_size: c_uint,
    db: *_XrmHashBucketRec,
    private15: *c_void,
    display_name: *c_char,

    // FIXME(pcwalton): These are needed for some reason...
    pad: *c_void,
    pad1: *c_void,

    default_screen: c_int,
    nscreens: c_int,
    screens: *Screen,
}

struct Screen {
    ext_data: *XExtData,
    display: *Display,
    root: Window,
    width: c_int,
    height: c_int,
    mwidth: c_int,
    mheight: c_int,
    ndepths: c_int,
    depths: *Depth,
    root_depth: c_int,
    root_visual: *Visual,
    default_gc: GC,
    cmap: Colormap,
    white_pixel: c_ulong,
    black_pixel: c_ulong,
    max_maps: c_int,
    min_maps: c_int,
    backing_store: c_int,
    save_unders: Bool,
    root_input_mask: c_long,
    pad: *c_void,
}

struct ScreenFormat;
struct XExtData;

struct XVisualInfo {
    visual: *Visual,
    visualid: VisualID,
    screen: c_int,
    depth: c_int,
    class: c_int,
    red_mask: c_ulong,
    green_mask: c_ulong,
    blue_mask: c_ulong,
    colormap_size: c_int,
    bits_per_rgb: c_int,
}

type Bool = c_int;
type Colormap = XID;
type Drawable = c_uint;                 // compatible with Window
type GC = *c_void;
type GLXContext = *GLXContextOpaque;
type GLXDrawable = c_uint;              // compatible with GLXPixmap
type GLXPixmap = c_uint;                // compatible with GLXDrawable
type Pixmap = c_uint;
type VisualID = c_ulong;
type Window = c_uint;                   // compatible with Drawable
type XID = c_uint;
type XPointer = *c_void;

#[link_args="-lX11"]
#[nolink]
extern {
    fn XOpenDisplay(n: c_int) -> *Display;
    fn XCreatePixmap(display: *Display, d: Drawable, width: c_uint, height: c_uint, depth: c_uint)
                     -> Pixmap;

    fn glXChooseVisual(dpy: *Display, screen: c_int, attribList: *c_int) -> *XVisualInfo;
    fn glXCreateContext(dpy: *Display, vis: *XVisualInfo, shareList: GLXContext, direct: Bool)
                        -> GLXContext;
    fn glXCreateGLXPixmap(dpy: *Display, vis: *XVisualInfo, pixmap: Pixmap) -> GLXPixmap;
    fn glXMakeContextCurrent(dpy: *Display, draw: GLXDrawable, read: GLXDrawable, ctx: GLXContext)
                             -> Bool;
}

// X11 macros

fn DefaultScreen(dpy: *Display) -> c_int {
    unsafe {
        (*dpy).default_screen
    }
}
fn RootWindow(dpy: *Display, scr: c_int) -> Window {
    unsafe {
        (*ScreenOfDisplay(dpy, scr)).root
    }
}
fn ScreenOfDisplay(dpy: *Display, scr: c_int) -> *Screen {
    unsafe {
        *ptr::offset(&(*dpy).screens, scr as int)
    }
}

// Implementation

/// Linux-specific interface to 3D graphics contexts.
pub struct GraphicsContext {
    priv display: *Display,
    priv pixmap: GLXPixmap,
    priv context: Arc<GLXContext>,
}

impl GraphicsContext {
    // Creates a new, possibly shared, GLX context.
    fn new_possibly_shared(share_context: Option<GraphicsContext>) -> GraphicsContext {
        let (display, visual, pixmap) = GraphicsContext::create_display_visual_and_pixmap();

        unsafe {
            let context = match share_context {
                None => glXCreateContext(display, visual, null(), 1),
                Some(share_context) => {
                    let native_share_context = share_context.native();
                    glXCreateContext(display, visual, *native_share_context.get(), 1)
                }
            };

            assert!(context != null());

            GraphicsContext {
                display: display,
                pixmap: pixmap,
                context: Arc::new(context),
            }
        }
    }

    fn create_display_visual_and_pixmap() -> (*Display, *XVisualInfo, GLXPixmap) {
        unsafe {
            // Get a connection.
            let display = XOpenDisplay(0);

            // Get an appropriate visual.
            let visual = glXChooseVisual(display, DefaultScreen(display), &ATTRIBUTES[0]);

            // Create the pixmap.
            let root_window = RootWindow(display, DefaultScreen(display));
            let pixmap = XCreatePixmap(display, root_window, 10, 10, 24);
            let glx_pixmap = glXCreateGLXPixmap(display, visual, pixmap);

            debug!("XCreatePixmap returned %?, glXCreateGLXPixmap returned %?",
                   pixmap,
                   glx_pixmap);

            (display, visual, glx_pixmap)
        }
    }
}

impl GraphicsContextMethods<GLXContext> for GraphicsContext {
    /// Wraps the given instance of the native GLX graphics context, bumping the reference count in
    /// the process.
    fn wrap(instance: Arc<GLXContext>) -> GraphicsContext {
        let (display, _, pixmap) = GraphicsContext::create_display_visual_and_pixmap();
        GraphicsContext {
            display: display,
            pixmap: pixmap,
            context: instance.clone(),
        }
    }

    /// Returns the underlying native 3D context.
    fn native(&self) -> Arc<GLXContext> {
        self.context.clone()
    }

    /// Creates a new offscreen 3D graphics context.
    fn new() -> GraphicsContext {
        GraphicsContext::new_possibly_shared(None)
    }

    /// Creates a new offscreen 3D graphics context shared with the given context.
    fn new_shared(share_context: GraphicsContext) -> GraphicsContext {
        GraphicsContext::new_possibly_shared(Some(share_context))
    }

    /// Makes this context the current context.
    fn make_current(&self) {
        unsafe {
            let result = glXMakeContextCurrent(self.display,
                                               self.pixmap,
                                               self.pixmap,
                                               *self.context.get());
            assert!(result != 0);
        }
    }
}

impl Clone for GraphicsContext {
    fn clone(&self) -> GraphicsContext {
        GraphicsContext {
            display: self.display,
            pixmap: self.pixmap,
            context: self.context.clone(),
        }
    }
}

<commit_msg>Link libGL on Linux<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

use context::GraphicsContextMethods;

use std::libc::{c_char, c_int, c_long, c_uint, c_ulong, c_void};
use std::ptr::null;
use std::ptr;
use extra::arc::Arc;

// Constants.

static GLX_RGBA: c_int = 4;
static GLX_RED_SIZE: c_int = 8;
static GLX_GREEN_SIZE: c_int = 9;
static GLX_BLUE_SIZE: c_int = 10;
static GLX_DEPTH_SIZE: c_int = 12;

static ATTRIBUTES: [c_int, ..4] = [
    GLX_RGBA,
    GLX_DEPTH_SIZE, 24,
    0,
];

// External bindings to Xlib.

// Opaque structures.
struct _XPrivate;
struct _XrmHashBucketRec;
struct Depth;
struct GLXContextOpaque;
struct Visual;

// Sadly we need to copy some of this definition in here because the Xlib macros need to access it.
struct Display {
    ext_data: *XExtData,
    private1: *_XPrivate,
    fd: c_int,
    private2: c_int,
    proto_major_version: c_int,
    proto_minor_version: c_int,
    vendor: *c_char,
    private3: XID,
    private4: XID,
    private5: XID,
    private6: c_int,
    resource_alloc: *c_void,
    byte_order: c_int,
    bitmap_unit: c_int,
    bitmap_pad: c_int,
    bitmap_bit_order: c_int,
    nformats: c_int,
    pixmap_format: *ScreenFormat,
    private8: c_int,
    release: c_int,
    private9: *_XPrivate,
    private10: *_XPrivate,
    qlen: c_int,
    last_request_read: c_ulong,
    request: c_ulong,
    private11: XPointer,
    private12: XPointer,
    private13: XPointer,
    private14: XPointer,
    max_request_size: c_uint,
    db: *_XrmHashBucketRec,
    private15: *c_void,
    display_name: *c_char,

    // FIXME(pcwalton): These are needed for some reason...
    pad: *c_void,
    pad1: *c_void,

    default_screen: c_int,
    nscreens: c_int,
    screens: *Screen,
}

struct Screen {
    ext_data: *XExtData,
    display: *Display,
    root: Window,
    width: c_int,
    height: c_int,
    mwidth: c_int,
    mheight: c_int,
    ndepths: c_int,
    depths: *Depth,
    root_depth: c_int,
    root_visual: *Visual,
    default_gc: GC,
    cmap: Colormap,
    white_pixel: c_ulong,
    black_pixel: c_ulong,
    max_maps: c_int,
    min_maps: c_int,
    backing_store: c_int,
    save_unders: Bool,
    root_input_mask: c_long,
    pad: *c_void,
}

struct ScreenFormat;
struct XExtData;

struct XVisualInfo {
    visual: *Visual,
    visualid: VisualID,
    screen: c_int,
    depth: c_int,
    class: c_int,
    red_mask: c_ulong,
    green_mask: c_ulong,
    blue_mask: c_ulong,
    colormap_size: c_int,
    bits_per_rgb: c_int,
}

type Bool = c_int;
type Colormap = XID;
type Drawable = c_uint;                 // compatible with Window
type GC = *c_void;
type GLXContext = *GLXContextOpaque;
type GLXDrawable = c_uint;              // compatible with GLXPixmap
type GLXPixmap = c_uint;                // compatible with GLXDrawable
type Pixmap = c_uint;
type VisualID = c_ulong;
type Window = c_uint;                   // compatible with Drawable
type XID = c_uint;
type XPointer = *c_void;

#[link_args="-lX11 -lGL"]
#[nolink]
extern {
    fn XOpenDisplay(n: c_int) -> *Display;
    fn XCreatePixmap(display: *Display, d: Drawable, width: c_uint, height: c_uint, depth: c_uint)
                     -> Pixmap;

    fn glXChooseVisual(dpy: *Display, screen: c_int, attribList: *c_int) -> *XVisualInfo;
    fn glXCreateContext(dpy: *Display, vis: *XVisualInfo, shareList: GLXContext, direct: Bool)
                        -> GLXContext;
    fn glXCreateGLXPixmap(dpy: *Display, vis: *XVisualInfo, pixmap: Pixmap) -> GLXPixmap;
    fn glXMakeContextCurrent(dpy: *Display, draw: GLXDrawable, read: GLXDrawable, ctx: GLXContext)
                             -> Bool;
}

// X11 macros

fn DefaultScreen(dpy: *Display) -> c_int {
    unsafe {
        (*dpy).default_screen
    }
}
fn RootWindow(dpy: *Display, scr: c_int) -> Window {
    unsafe {
        (*ScreenOfDisplay(dpy, scr)).root
    }
}
fn ScreenOfDisplay(dpy: *Display, scr: c_int) -> *Screen {
    unsafe {
        *ptr::offset(&(*dpy).screens, scr as int)
    }
}

// Implementation

/// Linux-specific interface to 3D graphics contexts.
pub struct GraphicsContext {
    priv display: *Display,
    priv pixmap: GLXPixmap,
    priv context: Arc<GLXContext>,
}

impl GraphicsContext {
    // Creates a new, possibly shared, GLX context.
    fn new_possibly_shared(share_context: Option<GraphicsContext>) -> GraphicsContext {
        let (display, visual, pixmap) = GraphicsContext::create_display_visual_and_pixmap();

        unsafe {
            let context = match share_context {
                None => glXCreateContext(display, visual, null(), 1),
                Some(share_context) => {
                    let native_share_context = share_context.native();
                    glXCreateContext(display, visual, *native_share_context.get(), 1)
                }
            };

            assert!(context != null());

            GraphicsContext {
                display: display,
                pixmap: pixmap,
                context: Arc::new(context),
            }
        }
    }

    fn create_display_visual_and_pixmap() -> (*Display, *XVisualInfo, GLXPixmap) {
        unsafe {
            // Get a connection.
            let display = XOpenDisplay(0);

            // Get an appropriate visual.
            let visual = glXChooseVisual(display, DefaultScreen(display), &ATTRIBUTES[0]);

            // Create the pixmap.
            let root_window = RootWindow(display, DefaultScreen(display));
            let pixmap = XCreatePixmap(display, root_window, 10, 10, 24);
            let glx_pixmap = glXCreateGLXPixmap(display, visual, pixmap);

            debug!("XCreatePixmap returned %?, glXCreateGLXPixmap returned %?",
                   pixmap,
                   glx_pixmap);

            (display, visual, glx_pixmap)
        }
    }
}

impl GraphicsContextMethods<GLXContext> for GraphicsContext {
    /// Wraps the given instance of the native GLX graphics context, bumping the reference count in
    /// the process.
    fn wrap(instance: Arc<GLXContext>) -> GraphicsContext {
        let (display, _, pixmap) = GraphicsContext::create_display_visual_and_pixmap();
        GraphicsContext {
            display: display,
            pixmap: pixmap,
            context: instance.clone(),
        }
    }

    /// Returns the underlying native 3D context.
    fn native(&self) -> Arc<GLXContext> {
        self.context.clone()
    }

    /// Creates a new offscreen 3D graphics context.
    fn new() -> GraphicsContext {
        GraphicsContext::new_possibly_shared(None)
    }

    /// Creates a new offscreen 3D graphics context shared with the given context.
    fn new_shared(share_context: GraphicsContext) -> GraphicsContext {
        GraphicsContext::new_possibly_shared(Some(share_context))
    }

    /// Makes this context the current context.
    fn make_current(&self) {
        unsafe {
            let result = glXMakeContextCurrent(self.display,
                                               self.pixmap,
                                               self.pixmap,
                                               *self.context.get());
            assert!(result != 0);
        }
    }
}

impl Clone for GraphicsContext {
    fn clone(&self) -> GraphicsContext {
        GraphicsContext {
            display: self.display,
            pixmap: self.pixmap,
            context: self.context.clone(),
        }
    }
}

<|endoftext|>


<commit_before>pub unsafe fn remap() {
    asm!("
        mov al, 0x11
        mov dx, 0x20
        out dx, al
        mov dx, 0xA0
        out dx, al

        mov al, 0x20
        mov dx, 0x21
        mov bx, 0xA1
        out dx, al
        mov al, 0x28
        xchg bx, dx
        out dx, al

        mov al, 4
        xchg bx, dx
        out dx, al
        mov al, 2
        xchg bx, dx
        out dx, al

        mov al, 1
        xchg bx, dx
        out dx, al
        xchg bx, dx
        out dx, al

        mov al, 0xff
        xchg bx, dx
        out dx, al
        xchg bx, dx
        out dx, al"
        ::: "al", "bx", "dx" : "volatile", "intel");
}

#[inline(never)]
pub unsafe fn enable(irq: u8) {
    let port: u16 = if (irq & 0b1000) == 0 { 0x21 } else { 0xa1 };
    let mask: u8 = !(1u8 << (irq & 0b111));

    asm!("
        mov dx, $0
        in al, dx
        and al, $1
        out dx, al"
        :: "r"(port), "r"(mask) : "al", "dx" : "intel")
}
<commit_msg>Modify pic::remap (bug in LLVM Intel Assembly syntax?)<commit_after>pub unsafe fn remap() {
    asm!("
        mov al, 0x11
        outb 0x20
        outb 0xA0

        mov al, 0x20
        outb 0x21
        mov al, 0x28
        outb 0xA1

        mov al, 4
        outb 0x21
        mov al, 2
        outb 0xA1

        mov al, 1
        outb 0x21
        outb 0xA1

        mov al, 0xff
        outb 0x21
        outb 0xA1"
        ::: "al" : "volatile", "intel");
}

#[inline(never)]
pub unsafe fn enable(irq: u8) {
    let port: u16 = if (irq & 0b1000) == 0 { 0x21 } else { 0xa1 };
    let mask: u8 = !(1u8 << (irq & 0b111));

    asm!("
        mov dx, $0
        in al, dx
        and al, $1
        out dx, al"
        :: "r"(port), "r"(mask) : "al", "dx" : "intel")
}
<|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.

use std::mem;
use std::ptr;
use std::sync::Arc;
use smallvec::SmallVec;

use check_errors;
use OomError;
use SynchronizedVulkanObject;
use VulkanObject;
use VulkanPointers;
use vk;

use buffer::Buffer;
use buffer::BufferInner;
use buffer::BufferView;
use descriptor::descriptor::DescriptorType;
use descriptor::descriptor_set::UnsafeDescriptorSetLayout;
use descriptor::descriptor_set::DescriptorPool;
use device::Device;
use image::ImageView;
use sampler::Sampler;

/// Low-level descriptor set.
pub struct UnsafeDescriptorSet {
    set: vk::DescriptorSet,
    pool: Arc<DescriptorPool>,
    layout: Arc<UnsafeDescriptorSetLayout>,
}

impl UnsafeDescriptorSet {
    /// See the docs of uninitialized().
    // FIXME: this has to check whether there's still enough room in the pool
    pub unsafe fn uninitialized_raw(pool: &Arc<DescriptorPool>,
                                    layout: &Arc<UnsafeDescriptorSetLayout>)
                                    -> Result<UnsafeDescriptorSet, OomError>
    {
        assert_eq!(&**pool.device() as *const Device, &**layout.device() as *const Device);

        let vk = pool.device().pointers();

        let set = {
            let pool_obj = pool.internal_object_guard();

            let infos = vk::DescriptorSetAllocateInfo {
                sType: vk::STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
                pNext: ptr::null(),
                descriptorPool: *pool_obj,
                descriptorSetCount: 1,
                pSetLayouts: &layout.internal_object(),
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.AllocateDescriptorSets(pool.device().internal_object(), &infos,
                                                        &mut output)));
            output
        };

        Ok(UnsafeDescriptorSet {
            set: set,
            pool: pool.clone(),
            layout: layout.clone(),
        })
    }

    /// Builds a new descriptor set.
    ///
    /// # Panic
    ///
    /// - Panics if the pool and the layout were not created from the same `Device`.
    /// - Panics if the device or host ran out of memory.
    ///
    // FIXME: this has to check whether there's still enough room in the pool
    #[inline]
    pub unsafe fn uninitialized(pool: &Arc<DescriptorPool>,
                                layout: &Arc<UnsafeDescriptorSetLayout>)
                                -> UnsafeDescriptorSet
    {
        UnsafeDescriptorSet::uninitialized_raw(pool, layout).unwrap()
    }

    // TODO: add copying from other descriptor sets
    //       add a `copy` method that just takes a copy, and an `update` method that takes both
    //       writes and copies and that actually performs the operation

    /// Modifies a descriptor set. Doesn't check that the writes or copies are correct.
    ///
    /// # Safety
    ///
    /// - Doesn't verify that the things you write in the descriptor set match its layout.
    /// - Doesn't keep the resources alive. You have to do that yourself.
    /// - Updating a descriptor set obeys synchronization rules that aren't checked here.
    ///
    pub unsafe fn write<I>(&mut self, write: I)
        where I: Iterator<Item = DescriptorWrite> + Clone       // TODO (low prio): don't require Clone
    {
        let vk = self.pool.device().pointers();

        let buffer_descriptors = write.clone().filter_map(|write| {
            match write.inner {
                DescriptorWriteInner::UniformBuffer(buffer, offset, size) |
                DescriptorWriteInner::DynamicUniformBuffer(buffer, offset, size) => {
                    Some(vk::DescriptorBufferInfo {
                        buffer: buffer,
                        offset: offset as u64,
                        range: size as u64,
                    })
                },
                DescriptorWriteInner::StorageBuffer(buffer, offset, size) |
                DescriptorWriteInner::DynamicStorageBuffer(buffer, offset, size) => {
                    Some(vk::DescriptorBufferInfo {
                        buffer: buffer,
                        offset: offset as u64,
                        range: size as u64,
                    })
                },
                _ => None
            }
        }).collect::<SmallVec<[_; 64]>>();

        let image_descriptors = write.clone().filter_map(|write| {
            match write.inner {
                DescriptorWriteInner::Sampler(sampler) => {
                    Some(vk::DescriptorImageInfo {
                        sampler: sampler,
                        imageView: 0,
                        imageLayout: 0,
                    })
                },
                DescriptorWriteInner::CombinedImageSampler(sampler, view, layout) => {
                    Some(vk::DescriptorImageInfo {
                        sampler: sampler,
                        imageView: view,
                        imageLayout: layout,
                    })
                },
                DescriptorWriteInner::StorageImage(view, layout) => {
                    Some(vk::DescriptorImageInfo {
                        sampler: 0,
                        imageView: view,
                        imageLayout: layout,
                    })
                },
                DescriptorWriteInner::SampledImage(view, layout) => {
                    Some(vk::DescriptorImageInfo {
                        sampler: 0,
                        imageView: view,
                        imageLayout: layout,
                    })
                },
                DescriptorWriteInner::InputAttachment(view, layout) => {
                    Some(vk::DescriptorImageInfo {
                        sampler: 0,
                        imageView: view,
                        imageLayout: layout,
                    })
                },
                _ => None
            }
        }).collect::<SmallVec<[_; 64]>>();

        let buffer_views_descriptors = write.clone().filter_map(|write| {
            match write.inner {
                DescriptorWriteInner::UniformTexelBuffer(view) |
                DescriptorWriteInner::StorageTexelBuffer(view) => {
                    Some(view)
                },
                _ => None
            }
        }).collect::<SmallVec<[_; 16]>>();

        let mut next_buffer_desc = 0;
        let mut next_image_desc = 0;
        let mut next_buffer_view_desc = 0;

        let vk_writes = write.clone().map(|write| {
            let (buffer_info, image_info, buffer_view_info) = match write.inner {
                DescriptorWriteInner::Sampler(_) | DescriptorWriteInner::CombinedImageSampler(_, _, _) |
                DescriptorWriteInner::SampledImage(_, _) | DescriptorWriteInner::StorageImage(_, _) |
                DescriptorWriteInner::InputAttachment(_, _) => {
                    let img = image_descriptors.as_ptr().offset(next_image_desc as isize);
                    next_image_desc += 1;
                    (ptr::null(), img, ptr::null())
                },
                DescriptorWriteInner::UniformBuffer(_, _, _) | DescriptorWriteInner::StorageBuffer(_, _, _) |
                DescriptorWriteInner::DynamicUniformBuffer(_, _, _) |
                DescriptorWriteInner::DynamicStorageBuffer(_, _, _) => {
                    let buf = buffer_descriptors.as_ptr().offset(next_buffer_desc as isize);
                    next_buffer_desc += 1;
                    (buf, ptr::null(), ptr::null())
                },
                DescriptorWriteInner::UniformTexelBuffer(_) |
                DescriptorWriteInner::StorageTexelBuffer(_) => {
                    let buf = buffer_views_descriptors.as_ptr().offset(next_buffer_view_desc as isize);
                    next_buffer_view_desc += 1;
                    (ptr::null(), ptr::null(), buf)
                },
            };

            vk::WriteDescriptorSet {
                sType: vk::STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
                pNext: ptr::null(),
                dstSet: self.set,
                dstBinding: write.binding,
                dstArrayElement: write.first_array_element,
                descriptorCount: 1,
                descriptorType: write.ty() as u32,
                pImageInfo: image_info,
                pBufferInfo: buffer_info,
                pTexelBufferView: buffer_view_info,
            }
        }).collect::<SmallVec<[_; 64]>>();

        debug_assert_eq!(next_buffer_desc, buffer_descriptors.len());
        debug_assert_eq!(next_image_desc, image_descriptors.len());
        debug_assert_eq!(next_buffer_view_desc, buffer_views_descriptors.len());

        if !vk_writes.is_empty() {
            vk.UpdateDescriptorSets(self.pool.device().internal_object(),
                                    vk_writes.len() as u32, vk_writes.as_ptr(), 0, ptr::null());
        }
    }

    /// Returns the layout used to create this descriptor set.
    #[inline]
    pub fn layout(&self) -> &Arc<UnsafeDescriptorSetLayout> {
        &self.layout
    }
}

unsafe impl VulkanObject for UnsafeDescriptorSet {
    type Object = vk::DescriptorSet;

    #[inline]
    fn internal_object(&self) -> vk::DescriptorSet {
        self.set
    }
}

impl Drop for UnsafeDescriptorSet {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.pool.device().pointers();
            vk.FreeDescriptorSets(self.pool.device().internal_object(),
                                  *self.pool.internal_object_guard(), 1, &self.set);
        }
    }
}

/// Represents a single write entry to a descriptor set.
///
/// Use the various constructors to build a `DescriptorWrite`. While it is not unsafe to build a
/// `DescriptorWrite`, it is unsafe to actually use it to write to a descriptor set.
pub struct DescriptorWrite {
    binding: u32,
    first_array_element: u32,
    inner: DescriptorWriteInner,
}

#[derive(Debug, Clone)]
enum DescriptorWriteInner {
    Sampler(vk::Sampler),
    StorageImage(vk::ImageView, vk::ImageLayout),
    SampledImage(vk::ImageView, vk::ImageLayout),
    CombinedImageSampler(vk::Sampler, vk::ImageView, vk::ImageLayout),
    UniformTexelBuffer(vk::BufferView),
    StorageTexelBuffer(vk::BufferView),
    UniformBuffer(vk::Buffer, usize, usize),
    StorageBuffer(vk::Buffer, usize, usize),
    DynamicUniformBuffer(vk::Buffer, usize, usize),
    DynamicStorageBuffer(vk::Buffer, usize, usize),
    InputAttachment(vk::ImageView, vk::ImageLayout),
}

impl DescriptorWrite {
    #[inline]
    pub fn storage_image<I>(binding: u32, image: &I) -> DescriptorWrite
        where I: ImageView
    {
        DescriptorWrite {
            binding: binding,
            first_array_element: 0,
            inner: {
                let layout = image.descriptor_set_storage_image_layout() as u32;
                DescriptorWriteInner::StorageImage(image.inner().internal_object(), layout)
            },
        }
    }

    #[inline]
    pub fn sampler(binding: u32, sampler: &Arc<Sampler>) -> DescriptorWrite {
        DescriptorWrite {
            binding: binding,
            first_array_element: 0,
            inner: DescriptorWriteInner::Sampler(sampler.internal_object())
        }
    }

    #[inline]
    pub fn sampled_image<I>(binding: u32, image: &I) -> DescriptorWrite
        where I: ImageView
    {
        DescriptorWrite {
            binding: binding,
            first_array_element: 0,
            inner: {
                let layout = image.descriptor_set_sampled_image_layout() as u32;
                DescriptorWriteInner::SampledImage(image.inner().internal_object(), layout)
            },
        }
    }

    #[inline]
    pub fn combined_image_sampler<I>(binding: u32, sampler: &Arc<Sampler>, image: &I) -> DescriptorWrite
        where I: ImageView
    {
        DescriptorWrite {
            binding: binding,
            first_array_element: 0,
            inner: {
                let layout = image.descriptor_set_combined_image_sampler_layout() as u32;
                DescriptorWriteInner::CombinedImageSampler(sampler.internal_object(), image.inner().internal_object(), layout)
            },
        }
    }

    #[inline]
    pub fn uniform_texel_buffer<'a, F, B>(binding: u32, view: &Arc<BufferView<F, B>>) -> DescriptorWrite
        where B: Buffer,
              F: 'static + Send + Sync,
    {
        assert!(view.uniform_texel_buffer());

        DescriptorWrite {
            binding: binding,
            first_array_element: 0,
            inner: DescriptorWriteInner::UniformTexelBuffer(view.internal_object()),
        }
    }

    #[inline]
    pub fn storage_texel_buffer<'a, F, B>(binding: u32, view: &Arc<BufferView<F, B>>) -> DescriptorWrite
        where B: Buffer + 'static,
              F: 'static + Send + Sync,
    {
        assert!(view.storage_texel_buffer());

        DescriptorWrite {
            binding: binding,
            first_array_element: 0,
            inner: DescriptorWriteInner::StorageTexelBuffer(view.internal_object()),
        }
    }

    #[inline]
    pub unsafe fn uniform_buffer<B>(binding: u32, buffer: &B) -> DescriptorWrite
        where B: Buffer
    {
        let size = buffer.size();
        let BufferInner { buffer, offset } = buffer.inner();

        DescriptorWrite {
            binding: binding,
            first_array_element: 0,
            inner: DescriptorWriteInner::UniformBuffer(buffer.internal_object(), offset, size),
        }
    }

    #[inline]
    pub unsafe fn storage_buffer<B>(binding: u32, buffer: &B) -> DescriptorWrite
        where B: Buffer
    {
        let size = buffer.size();
        let BufferInner { buffer, offset } = buffer.inner();

        DescriptorWrite {
            binding: binding,
            first_array_element: 0,
            inner: DescriptorWriteInner::StorageBuffer(buffer.internal_object(), offset, size),
        }
    }

    #[inline]
    pub unsafe fn dynamic_uniform_buffer<B>(binding: u32, buffer: &B) -> DescriptorWrite
        where B: Buffer
    {
        let size = buffer.size();
        let BufferInner { buffer, offset } = buffer.inner();

        DescriptorWrite {
            binding: binding,
            first_array_element: 0,
            inner: DescriptorWriteInner::DynamicUniformBuffer(buffer.internal_object(),
                                                              offset, size),
        }
    }

    #[inline]
    pub unsafe fn dynamic_storage_buffer<B>(binding: u32, buffer: &B) -> DescriptorWrite
        where B: Buffer
    {
        let size = buffer.size();
        let BufferInner { buffer, offset } = buffer.inner();

        DescriptorWrite {
            binding: binding,
            first_array_element: 0,
            inner: DescriptorWriteInner::DynamicStorageBuffer(buffer.internal_object(),
                                                              offset, size),
        }
    }

    #[inline]
    pub fn input_attachment<I>(binding: u32, image: &I) -> DescriptorWrite
        where I: ImageView
    {
        DescriptorWrite {
            binding: binding,
            first_array_element: 0,
            inner: {
                let layout = image.descriptor_set_input_attachment_layout() as u32;
                DescriptorWriteInner::InputAttachment(image.inner().internal_object(), layout)
            },
        }
    }

    /// Returns the type corresponding to this write.
    #[inline]
    pub fn ty(&self) -> DescriptorType {
        match self.inner {
            DescriptorWriteInner::Sampler(_) => DescriptorType::Sampler,
            DescriptorWriteInner::CombinedImageSampler(_, _, _) => DescriptorType::CombinedImageSampler,
            DescriptorWriteInner::SampledImage(_, _) => DescriptorType::SampledImage,
            DescriptorWriteInner::StorageImage(_, _) => DescriptorType::StorageImage,
            DescriptorWriteInner::UniformTexelBuffer(_) => DescriptorType::UniformTexelBuffer,
            DescriptorWriteInner::StorageTexelBuffer(_) => DescriptorType::StorageTexelBuffer,
            DescriptorWriteInner::UniformBuffer(_, _, _) => DescriptorType::UniformBuffer,
            DescriptorWriteInner::StorageBuffer(_, _, _) => DescriptorType::StorageBuffer,
            DescriptorWriteInner::DynamicUniformBuffer(_, _, _) => DescriptorType::UniformBufferDynamic,
            DescriptorWriteInner::DynamicStorageBuffer(_, _, _) => DescriptorType::StorageBufferDynamic,
            DescriptorWriteInner::InputAttachment(_, _) => DescriptorType::InputAttachment,
        }
    }
}
<commit_msg>Rework descriptor_set::sys to allow arrays eventually<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.

use std::mem;
use std::ptr;
use std::sync::Arc;
use smallvec::SmallVec;

use check_errors;
use OomError;
use SynchronizedVulkanObject;
use VulkanObject;
use VulkanPointers;
use vk;

use buffer::Buffer;
use buffer::BufferInner;
use buffer::BufferView;
use descriptor::descriptor::DescriptorType;
use descriptor::descriptor_set::UnsafeDescriptorSetLayout;
use descriptor::descriptor_set::DescriptorPool;
use device::Device;
use image::ImageView;
use sampler::Sampler;

/// Low-level descriptor set.
pub struct UnsafeDescriptorSet {
    set: vk::DescriptorSet,
    pool: Arc<DescriptorPool>,
    layout: Arc<UnsafeDescriptorSetLayout>,
}

impl UnsafeDescriptorSet {
    /// See the docs of uninitialized().
    // FIXME: this has to check whether there's still enough room in the pool
    pub unsafe fn uninitialized_raw(pool: &Arc<DescriptorPool>,
                                    layout: &Arc<UnsafeDescriptorSetLayout>)
                                    -> Result<UnsafeDescriptorSet, OomError>
    {
        assert_eq!(&**pool.device() as *const Device, &**layout.device() as *const Device);

        let vk = pool.device().pointers();

        let set = {
            let pool_obj = pool.internal_object_guard();

            let infos = vk::DescriptorSetAllocateInfo {
                sType: vk::STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
                pNext: ptr::null(),
                descriptorPool: *pool_obj,
                descriptorSetCount: 1,
                pSetLayouts: &layout.internal_object(),
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.AllocateDescriptorSets(pool.device().internal_object(), &infos,
                                                        &mut output)));
            output
        };

        Ok(UnsafeDescriptorSet {
            set: set,
            pool: pool.clone(),
            layout: layout.clone(),
        })
    }

    /// Builds a new descriptor set.
    ///
    /// # Panic
    ///
    /// - Panics if the pool and the layout were not created from the same `Device`.
    /// - Panics if the device or host ran out of memory.
    ///
    // FIXME: this has to check whether there's still enough room in the pool
    #[inline]
    pub unsafe fn uninitialized(pool: &Arc<DescriptorPool>,
                                layout: &Arc<UnsafeDescriptorSetLayout>)
                                -> UnsafeDescriptorSet
    {
        UnsafeDescriptorSet::uninitialized_raw(pool, layout).unwrap()
    }

    // TODO: add copying from other descriptor sets
    //       add a `copy` method that just takes a copy, and an `update` method that takes both
    //       writes and copies and that actually performs the operation

    /// Modifies a descriptor set. Doesn't check that the writes or copies are correct.
    ///
    /// # Safety
    ///
    /// - Doesn't verify that the things you write in the descriptor set match its layout.
    /// - Doesn't keep the resources alive. You have to do that yourself.
    /// - Updating a descriptor set obeys synchronization rules that aren't checked here.
    ///
    pub unsafe fn write<I>(&mut self, writes: I)
        where I: Iterator<Item = DescriptorWrite>
    {
        let vk = self.pool.device().pointers();

        let mut buffer_descriptors: SmallVec<[_; 64]> = SmallVec::new();
        let mut image_descriptors: SmallVec<[_; 64]> = SmallVec::new();
        let mut buffer_views_descriptors: SmallVec<[_; 64]> = SmallVec::new();

        let mut raw_writes: SmallVec<[_; 64]> = SmallVec::new();
        let mut raw_writes_img_infos: SmallVec<[_; 64]> = SmallVec::new();
        let mut raw_writes_buf_infos: SmallVec<[_; 64]> = SmallVec::new();
        let mut raw_writes_buf_view_infos: SmallVec<[_; 64]> = SmallVec::new();

        for indiv_write in writes {
            if indiv_write.inner.is_empty() {
                continue;
            }

            raw_writes.push(vk::WriteDescriptorSet {
                sType: vk::STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
                pNext: ptr::null(),
                dstSet: self.set,
                dstBinding: indiv_write.binding,
                dstArrayElement: indiv_write.first_array_element,
                descriptorCount: indiv_write.inner.len() as u32,
                descriptorType: indiv_write.ty() as u32,
                pImageInfo: ptr::null(),
                pBufferInfo: ptr::null(),
                pTexelBufferView: ptr::null(),
            });

            match indiv_write.inner[0] {
                DescriptorWriteInner::Sampler(_) |
                DescriptorWriteInner::CombinedImageSampler(_, _, _) |
                DescriptorWriteInner::SampledImage(_, _) |
                DescriptorWriteInner::StorageImage(_, _) |
                DescriptorWriteInner::InputAttachment(_, _) => {
                    raw_writes_img_infos.push(Some(image_descriptors.len()));
                    raw_writes_buf_infos.push(None);
                    raw_writes_buf_view_infos.push(None);
                },
                DescriptorWriteInner::UniformBuffer(_, _, _) |
                DescriptorWriteInner::StorageBuffer(_, _, _) |
                DescriptorWriteInner::DynamicUniformBuffer(_, _, _) |
                DescriptorWriteInner::DynamicStorageBuffer(_, _, _) => {
                    raw_writes_img_infos.push(None);
                    raw_writes_buf_infos.push(Some(buffer_descriptors.len()));
                    raw_writes_buf_view_infos.push(None);
                },
                DescriptorWriteInner::UniformTexelBuffer(_) |
                DescriptorWriteInner::StorageTexelBuffer(_) => {
                    raw_writes_img_infos.push(None);
                    raw_writes_buf_infos.push(None);
                    raw_writes_buf_view_infos.push(Some(buffer_views_descriptors.len()));
                },
            }

            for elem in indiv_write.inner.iter() {
                match *elem {
                    DescriptorWriteInner::UniformBuffer(buffer, offset, size) |
                    DescriptorWriteInner::DynamicUniformBuffer(buffer, offset, size) => {
                        buffer_descriptors.push(vk::DescriptorBufferInfo {
                            buffer: buffer,
                            offset: offset as u64,
                            range: size as u64,
                        });
                    },
                    DescriptorWriteInner::StorageBuffer(buffer, offset, size) |
                    DescriptorWriteInner::DynamicStorageBuffer(buffer, offset, size) => {
                        buffer_descriptors.push(vk::DescriptorBufferInfo {
                            buffer: buffer,
                            offset: offset as u64,
                            range: size as u64,
                        });
                    },
                    DescriptorWriteInner::Sampler(sampler) => {
                        image_descriptors.push(vk::DescriptorImageInfo {
                            sampler: sampler,
                            imageView: 0,
                            imageLayout: 0,
                        });
                    },
                    DescriptorWriteInner::CombinedImageSampler(sampler, view, layout) => {
                        image_descriptors.push(vk::DescriptorImageInfo {
                            sampler: sampler,
                            imageView: view,
                            imageLayout: layout,
                        });
                    },
                    DescriptorWriteInner::StorageImage(view, layout) => {
                        image_descriptors.push(vk::DescriptorImageInfo {
                            sampler: 0,
                            imageView: view,
                            imageLayout: layout,
                        });
                    },
                    DescriptorWriteInner::SampledImage(view, layout) => {
                        image_descriptors.push(vk::DescriptorImageInfo {
                            sampler: 0,
                            imageView: view,
                            imageLayout: layout,
                        });
                    },
                    DescriptorWriteInner::InputAttachment(view, layout) => {
                        image_descriptors.push(vk::DescriptorImageInfo {
                            sampler: 0,
                            imageView: view,
                            imageLayout: layout,
                        });
                    },
                    DescriptorWriteInner::UniformTexelBuffer(view) |
                    DescriptorWriteInner::StorageTexelBuffer(view) => {
                        buffer_views_descriptors.push(view);
                    },
                }
            }
        }

        for (i, write) in raw_writes.iter_mut().enumerate() {
            write.pImageInfo = match raw_writes_img_infos[i] {
                Some(off) => image_descriptors.as_ptr().offset(off as isize),
                None => ptr::null()
            };

            write.pBufferInfo = match raw_writes_buf_infos[i] {
                Some(off) => buffer_descriptors.as_ptr().offset(off as isize),
                None => ptr::null()
            };

            write.pTexelBufferView = match raw_writes_buf_view_infos[i] {
                Some(off) => buffer_views_descriptors.as_ptr().offset(off as isize),
                None => ptr::null()
            };
        }

        if !raw_writes.is_empty() {
            vk.UpdateDescriptorSets(self.pool.device().internal_object(),
                                    raw_writes.len() as u32, raw_writes.as_ptr(), 0, ptr::null());
        }
    }

    /// Returns the layout used to create this descriptor set.
    #[inline]
    pub fn layout(&self) -> &Arc<UnsafeDescriptorSetLayout> {
        &self.layout
    }
}

unsafe impl VulkanObject for UnsafeDescriptorSet {
    type Object = vk::DescriptorSet;

    #[inline]
    fn internal_object(&self) -> vk::DescriptorSet {
        self.set
    }
}

impl Drop for UnsafeDescriptorSet {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.pool.device().pointers();
            vk.FreeDescriptorSets(self.pool.device().internal_object(),
                                  *self.pool.internal_object_guard(), 1, &self.set);
        }
    }
}

/// Represents a single write entry to a descriptor set.
///
/// Use the various constructors to build a `DescriptorWrite`. While it is not unsafe to build a
/// `DescriptorWrite`, it is unsafe to actually use it to write to a descriptor set.
pub struct DescriptorWrite {
    binding: u32,
    first_array_element: u32,
    inner: SmallVec<[DescriptorWriteInner; 1]>,
}

#[derive(Debug, Clone)]
enum DescriptorWriteInner {
    Sampler(vk::Sampler),
    StorageImage(vk::ImageView, vk::ImageLayout),
    SampledImage(vk::ImageView, vk::ImageLayout),
    CombinedImageSampler(vk::Sampler, vk::ImageView, vk::ImageLayout),
    UniformTexelBuffer(vk::BufferView),
    StorageTexelBuffer(vk::BufferView),
    UniformBuffer(vk::Buffer, usize, usize),
    StorageBuffer(vk::Buffer, usize, usize),
    DynamicUniformBuffer(vk::Buffer, usize, usize),
    DynamicStorageBuffer(vk::Buffer, usize, usize),
    InputAttachment(vk::ImageView, vk::ImageLayout),
}

macro_rules! smallvec {
    ($elem:expr) => ({ let mut s = SmallVec::new(); s.push($elem); s });
}

impl DescriptorWrite {
    #[inline]
    pub fn storage_image<I>(binding: u32, image: &I) -> DescriptorWrite
        where I: ImageView
    {
        DescriptorWrite {
            binding: binding,
            first_array_element: 0,
            inner: smallvec!({
                let layout = image.descriptor_set_storage_image_layout() as u32;
                DescriptorWriteInner::StorageImage(image.inner().internal_object(), layout)
            }),
        }
    }

    #[inline]
    pub fn sampler(binding: u32, sampler: &Arc<Sampler>) -> DescriptorWrite {
        DescriptorWrite {
            binding: binding,
            first_array_element: 0,
            inner: smallvec!(DescriptorWriteInner::Sampler(sampler.internal_object()))
        }
    }

    #[inline]
    pub fn sampled_image<I>(binding: u32, image: &I) -> DescriptorWrite
        where I: ImageView
    {
        DescriptorWrite {
            binding: binding,
            first_array_element: 0,
            inner: smallvec!({
                let layout = image.descriptor_set_sampled_image_layout() as u32;
                DescriptorWriteInner::SampledImage(image.inner().internal_object(), layout)
            }),
        }
    }

    #[inline]
    pub fn combined_image_sampler<I>(binding: u32, sampler: &Arc<Sampler>, image: &I) -> DescriptorWrite
        where I: ImageView
    {
        DescriptorWrite {
            binding: binding,
            first_array_element: 0,
            inner: smallvec!({
                let layout = image.descriptor_set_combined_image_sampler_layout() as u32;
                DescriptorWriteInner::CombinedImageSampler(sampler.internal_object(), image.inner().internal_object(), layout)
            }),
        }
    }

    #[inline]
    pub fn uniform_texel_buffer<'a, F, B>(binding: u32, view: &Arc<BufferView<F, B>>) -> DescriptorWrite
        where B: Buffer,
              F: 'static + Send + Sync,
    {
        assert!(view.uniform_texel_buffer());

        DescriptorWrite {
            binding: binding,
            first_array_element: 0,
            inner: smallvec!(DescriptorWriteInner::UniformTexelBuffer(view.internal_object())),
        }
    }

    #[inline]
    pub fn storage_texel_buffer<'a, F, B>(binding: u32, view: &Arc<BufferView<F, B>>) -> DescriptorWrite
        where B: Buffer + 'static,
              F: 'static + Send + Sync,
    {
        assert!(view.storage_texel_buffer());

        DescriptorWrite {
            binding: binding,
            first_array_element: 0,
            inner: smallvec!(DescriptorWriteInner::StorageTexelBuffer(view.internal_object())),
        }
    }

    #[inline]
    pub unsafe fn uniform_buffer<B>(binding: u32, buffer: &B) -> DescriptorWrite
        where B: Buffer
    {
        let size = buffer.size();
        let BufferInner { buffer, offset } = buffer.inner();

        DescriptorWrite {
            binding: binding,
            first_array_element: 0,
            inner: smallvec!({
                DescriptorWriteInner::UniformBuffer(buffer.internal_object(), offset, size)
            }),
        }
    }

    #[inline]
    pub unsafe fn storage_buffer<B>(binding: u32, buffer: &B) -> DescriptorWrite
        where B: Buffer
    {
        let size = buffer.size();
        let BufferInner { buffer, offset } = buffer.inner();

        DescriptorWrite {
            binding: binding,
            first_array_element: 0,
            inner: smallvec!({
                DescriptorWriteInner::StorageBuffer(buffer.internal_object(), offset, size)
            }),
        }
    }

    #[inline]
    pub unsafe fn dynamic_uniform_buffer<B>(binding: u32, buffer: &B) -> DescriptorWrite
        where B: Buffer
    {
        let size = buffer.size();
        let BufferInner { buffer, offset } = buffer.inner();

        DescriptorWrite {
            binding: binding,
            first_array_element: 0,
            inner: smallvec!(DescriptorWriteInner::DynamicUniformBuffer(buffer.internal_object(),
                                                                        offset, size)),
        }
    }

    #[inline]
    pub unsafe fn dynamic_storage_buffer<B>(binding: u32, buffer: &B) -> DescriptorWrite
        where B: Buffer
    {
        let size = buffer.size();
        let BufferInner { buffer, offset } = buffer.inner();

        DescriptorWrite {
            binding: binding,
            first_array_element: 0,
            inner: smallvec!(DescriptorWriteInner::DynamicStorageBuffer(buffer.internal_object(),
                                                                        offset, size)),
        }
    }

    #[inline]
    pub fn input_attachment<I>(binding: u32, image: &I) -> DescriptorWrite
        where I: ImageView
    {
        DescriptorWrite {
            binding: binding,
            first_array_element: 0,
            inner: smallvec!({
                let layout = image.descriptor_set_input_attachment_layout() as u32;
                DescriptorWriteInner::InputAttachment(image.inner().internal_object(), layout)
            }),
        }
    }

    /// Returns the type corresponding to this write.
    #[inline]
    pub fn ty(&self) -> DescriptorType {
        match self.inner[0] {
            DescriptorWriteInner::Sampler(_) => DescriptorType::Sampler,
            DescriptorWriteInner::CombinedImageSampler(_, _, _) => DescriptorType::CombinedImageSampler,
            DescriptorWriteInner::SampledImage(_, _) => DescriptorType::SampledImage,
            DescriptorWriteInner::StorageImage(_, _) => DescriptorType::StorageImage,
            DescriptorWriteInner::UniformTexelBuffer(_) => DescriptorType::UniformTexelBuffer,
            DescriptorWriteInner::StorageTexelBuffer(_) => DescriptorType::StorageTexelBuffer,
            DescriptorWriteInner::UniformBuffer(_, _, _) => DescriptorType::UniformBuffer,
            DescriptorWriteInner::StorageBuffer(_, _, _) => DescriptorType::StorageBuffer,
            DescriptorWriteInner::DynamicUniformBuffer(_, _, _) => DescriptorType::UniformBufferDynamic,
            DescriptorWriteInner::DynamicStorageBuffer(_, _, _) => DescriptorType::StorageBufferDynamic,
            DescriptorWriteInner::InputAttachment(_, _) => DescriptorType::InputAttachment,
        }
    }
}
<|endoftext|>


<commit_before>// Third attempt.

use mio::{self, unix, Ready};
use mio::unix::UnixReady;
use std::io;
use dbus::{Connection, ConnectionItems, ConnectionItem, Watch, WatchEvent, Message, Error as DBusError};
use futures::{Async, Future, Stream, Poll};
use futures::sync::{oneshot, mpsc};
use tokio_core::reactor::{PollEvented, Handle as CoreHandle};
use std::rc::Rc;
use std::os::raw::c_uint;
use std::cell::RefCell;
use std::collections::HashMap;
use std::os::unix::io::RawFd;

type MCallMap = Rc<RefCell<HashMap<u32, oneshot::Sender<Message>>>>;

type MStream = Rc<RefCell<Option<mpsc::UnboundedSender<Message>>>>;

#[derive(Debug)]
/// A Tokio enabled D-Bus connection.
///
/// While an AConnection exists, it will consume all incoming messages.
/// Creating more than one AConnection for the same Connection is not recommended.
pub struct AConnection {
    conn: Rc<Connection>,
    quit: Option<oneshot::Sender<()>>,
    callmap: MCallMap,
    msgstream: MStream,
}

impl AConnection {
    /// Create an AConnection, which spawns a task on the core.
    ///
    /// The task handles incoming messages, and continues to do so until the
    /// AConnection is dropped.
    pub fn new(c: Rc<Connection>, h: CoreHandle) -> io::Result<AConnection> {
        let (tx, rx) = oneshot::channel();
        let map: MCallMap = Default::default();
        let istream: MStream = Default::default();
        let mut d = ADriver {
            conn: c.clone(),
            fds: HashMap::new(),
            core: h.clone(),
            quit: rx,
            callmap: map.clone(),
            msgstream: istream.clone(),
        };
        let i = AConnection {
            conn: c,
            quit: Some(tx),
            callmap: map,
            msgstream: istream,
        };
        for w in i.conn.watch_fds() { d.modify_watch(w)?; }
        h.spawn(d);
        Ok(i)
    }

    /// Sends a method call message, and returns a Future for the method return.
    pub fn method_call(&self, m: Message) -> Result<AMethodCall, &'static str> {
        let r = self.conn.send(m).map_err(|_| "D-Bus send error")?;
        let (tx, rx) = oneshot::channel();
        let mut map = self.callmap.borrow_mut();
        map.insert(r, tx); // TODO: error check for duplicate entries. Should not happen, but if it does...
        let mc = AMethodCall { serial: r, callmap: self.callmap.clone(), inner: rx };
        Ok(mc)
    }

    /// Returns a stream of incoming messages.
    ///
    /// Creating more than one stream for the same AConnection is not supported; this function will
    /// fail with an error if you try. Drop the first stream if you need to create a second one.
    pub fn messages(&self) -> Result<AMessageStream, &'static str> {
        let mut i = self.msgstream.borrow_mut();
        if i.is_some() { return Err("Another instance of AMessageStream already exists"); }
        let (tx, rx) = mpsc::unbounded();
        *i = Some(tx);
        Ok(AMessageStream { inner: rx, stream: self.msgstream.clone() })
    }
}

impl Drop for AConnection {
    fn drop(&mut self) { let _ = self.quit.take().unwrap().send(()); }
}

#[derive(Debug)]
// Internal struct; this is the future spawned on the core.
struct ADriver {
    conn: Rc<Connection>,
    fds: HashMap<RawFd, PollEvented<AWatch>>,
    core: CoreHandle,
    quit: oneshot::Receiver<()>,
    callmap: MCallMap,
    msgstream: MStream,
}

impl ADriver {
    fn modify_watch(&mut self, w: Watch) -> io::Result<()> {
        if !w.readable() && !w.writable() {
            self.fds.remove(&w.fd());
        } else {

            if let Some(evented) = self.fds.get(&w.fd()) {
                let ww = evented.get_ref().0;
                if ww.readable() == w.readable() || ww.readable() == w.readable() { return Ok(()) };
            }
            self.fds.remove(&w.fd());

            let z = PollEvented::new(AWatch(w), &self.core)?;

            self.fds.insert(w.fd(), z);
        }
        Ok(())
    }

    fn send_stream(&self, m: Message) {
        self.msgstream.borrow().as_ref().map(|z| { z.send(m).unwrap() });
    }

    fn handle_items(&mut self, items: ConnectionItems) {
        // TODO: What about all unwrapping in this function
        for i in items {
            // println!("Got: {:?}", i);
            match i {
                ConnectionItem::WatchFd(w) => { self.modify_watch(w).unwrap(); },
                ConnectionItem::MethodReturn(m) => {
                    let mut map = self.callmap.borrow_mut();
                    let serial = m.get_reply_serial().unwrap();
                    let r = map.remove(&serial);
                    if let Some(r) = r { r.send(m).unwrap(); }
                    else { self.send_stream(m) }
                }
                ConnectionItem::Nothing => return,
                ConnectionItem::Signal(m) => self.send_stream(m),
                ConnectionItem::MethodCall(m) => self.send_stream(m),
            }
        }
    }
}

impl Future for ADriver {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Result<Async<()>, ()> {
        let q = self.quit.poll();
        if q != Ok(Async::NotReady) { return Ok(Async::Ready(())); }

        let cc = self.conn.clone(); // Borrow checker made me do this
        let mut items = None;
        for w in self.fds.values() {
            let mut mask = UnixReady::hup() | UnixReady::error();
            if w.get_ref().0.readable() { mask = mask | Ready::readable().into(); }
            if w.get_ref().0.writable() { mask = mask | Ready::writable().into(); }
            let pr = w.poll_ready(*mask);
            // println!("{:?} is {:?}", w.get_ref().0.fd(), pr);
            let ur = if let Async::Ready(t) = pr { UnixReady::from(t) } else { continue };
            let flags =
                if ur.is_readable() { WatchEvent::Readable as c_uint } else { 0 } +
                if ur.is_writable() { WatchEvent::Writable as c_uint } else { 0 } +
                if ur.is_hup() { WatchEvent::Hangup as c_uint } else { 0 } +
                if ur.is_error() { WatchEvent::Error as c_uint } else { 0 };
            // println!("{:?} is {:?}", w.get_ref().0.fd(), ur);
            items = Some(cc.watch_handle(w.get_ref().0.fd(), flags));
            if ur.is_readable() { w.need_read() };
            if ur.is_writable() { w.need_write() };
        };
        self.handle_items(items.unwrap_or(cc.iter(0)));
        Ok(Async::NotReady)
    }
}

#[derive(Debug)]
struct AWatch(Watch);

impl mio::Evented for AWatch {
    fn register(&self,
                poll: &mio::Poll,
                token: mio::Token,
                mut interest: mio::Ready,
                mut opts: mio::PollOpt) -> io::Result<()>
    {
        if !self.0.readable() { interest.remove(mio::Ready::readable()) };
        if !self.0.writable() { interest.remove(mio::Ready::writable()) };
        opts.remove(mio::PollOpt::edge());
        opts.insert(mio::PollOpt::level());
        unix::EventedFd(&self.0.fd()).register(poll, token, interest, opts)
    }

    fn reregister(&self,
                  poll: &mio::Poll,
                  token: mio::Token,
                  mut interest: mio::Ready,
                  mut opts: mio::PollOpt) -> io::Result<()>
    {
        if !self.0.readable() { interest.remove(mio::Ready::readable()) };
        if !self.0.writable() { interest.remove(mio::Ready::writable()) };
        opts.remove(mio::PollOpt::edge());
        opts.insert(mio::PollOpt::level());
        unix::EventedFd(&self.0.fd()).reregister(poll, token, interest, opts)
    }

    fn deregister(&self, poll: &mio::Poll) -> io::Result<()> {
        unix::EventedFd(&self.0.fd()).deregister(poll)
    }
}

#[derive(Debug)]
/// A Future that resolves when a method call is replied to.
pub struct AMethodCall {
    serial: u32,
    callmap: MCallMap,
    inner: oneshot::Receiver<Message>,
}

impl Future for AMethodCall {
    type Item = Message;
    type Error = DBusError;

    fn poll(&mut self) -> Result<Async<Self::Item>, Self::Error> {
        let x = self.inner.poll().map_err(|_| DBusError::new_custom("org.freedesktop.DBus.Failed", "Tokio cancelled future"))?;
        if let Async::Ready(mut m) = x {
            m.as_result()?;
            Ok(Async::Ready(m))
        } else { Ok(Async::NotReady) }
    }
}

impl Drop for AMethodCall {
    fn drop(&mut self) {
        let mut map = self.callmap.borrow_mut();
        map.remove(&self.serial);
    }
}

#[derive(Debug)]
/// A Stream of incoming messages.
///
/// Messages already processed (method returns for AMethodCall, fd changes)
/// are already consumed and will not be present in the stream.
pub struct AMessageStream {
    inner: mpsc::UnboundedReceiver<Message>,
    stream: MStream,
}

impl Stream for AMessageStream {
    type Item = Message;
    type Error = ();
    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        // println!("Polling message stream");
        let r = self.inner.poll();
        // println!("msgstream {:?}", r);
        r
    }
}

impl Drop for AMessageStream {
    fn drop(&mut self) {
        *self.stream.borrow_mut() = None;
    }
}

#[test]
fn aconnection_test() {
    let conn = Rc::new(Connection::get_private(::dbus::BusType::Session).unwrap());
    let mut core = ::tokio_core::reactor::Core::new().unwrap();
    let aconn = AConnection::new(conn.clone(), core.handle()).unwrap();

    let m = ::dbus::Message::new_method_call("org.freedesktop.DBus", "/", "org.freedesktop.DBus", "ListNames").unwrap();
    let reply = core.run(aconn.method_call(m).unwrap()).unwrap();
    let z: Vec<&str> = reply.get1().unwrap();
    println!("got reply: {:?}", z);
    assert!(z.iter().any(|v| *v == "org.freedesktop.DBus"));
}

#[test]
fn astream_test() {
    let conn = Rc::new(Connection::get_private(::dbus::BusType::Session).unwrap());
    let mut core = ::tokio_core::reactor::Core::new().unwrap();
    let aconn = AConnection::new(conn.clone(), core.handle()).unwrap();

    let items: AMessageStream = aconn.messages().unwrap();
    let signals = items.filter_map(|m| if m.msg_type() == ::dbus::MessageType::Signal { Some(m) } else { None });
    let firstsig = core.run(signals.into_future()).map(|(x, _)| x).map_err(|(x, _)| x).unwrap();
    println!("first signal was: {:?}", firstsig);
    assert_eq!(firstsig.unwrap().msg_type(), ::dbus::MessageType::Signal);
}

<commit_msg>Fix AWatch poll mode changes<commit_after>// Third attempt.

use mio::{self, unix, Ready};
use mio::unix::UnixReady;
use std::io;
use dbus::{Connection, ConnectionItems, ConnectionItem, Watch, WatchEvent, Message, Error as DBusError};
use futures::{Async, Future, Stream, Poll};
use futures::sync::{oneshot, mpsc};
use tokio_core::reactor::{PollEvented, Handle as CoreHandle};
use std::rc::Rc;
use std::os::raw::c_uint;
use std::cell::RefCell;
use std::collections::HashMap;
use std::os::unix::io::RawFd;

type MCallMap = Rc<RefCell<HashMap<u32, oneshot::Sender<Message>>>>;

type MStream = Rc<RefCell<Option<mpsc::UnboundedSender<Message>>>>;

#[derive(Debug)]
/// A Tokio enabled D-Bus connection.
///
/// While an AConnection exists, it will consume all incoming messages.
/// Creating more than one AConnection for the same Connection is not recommended.
pub struct AConnection {
    conn: Rc<Connection>,
    quit: Option<oneshot::Sender<()>>,
    callmap: MCallMap,
    msgstream: MStream,
}

impl AConnection {
    /// Create an AConnection, which spawns a task on the core.
    ///
    /// The task handles incoming messages, and continues to do so until the
    /// AConnection is dropped.
    pub fn new(c: Rc<Connection>, h: CoreHandle) -> io::Result<AConnection> {
        let (tx, rx) = oneshot::channel();
        let map: MCallMap = Default::default();
        let istream: MStream = Default::default();
        let mut d = ADriver {
            conn: c.clone(),
            fds: HashMap::new(),
            core: h.clone(),
            quit: rx,
            callmap: map.clone(),
            msgstream: istream.clone(),
        };
        let i = AConnection {
            conn: c,
            quit: Some(tx),
            callmap: map,
            msgstream: istream,
        };
        for w in i.conn.watch_fds() { d.modify_watch(w)?; }
        h.spawn(d);
        Ok(i)
    }

    /// Sends a method call message, and returns a Future for the method return.
    pub fn method_call(&self, m: Message) -> Result<AMethodCall, &'static str> {
        let r = self.conn.send(m).map_err(|_| "D-Bus send error")?;
        let (tx, rx) = oneshot::channel();
        let mut map = self.callmap.borrow_mut();
        map.insert(r, tx); // TODO: error check for duplicate entries. Should not happen, but if it does...
        let mc = AMethodCall { serial: r, callmap: self.callmap.clone(), inner: rx };
        Ok(mc)
    }

    /// Returns a stream of incoming messages.
    ///
    /// Creating more than one stream for the same AConnection is not supported; this function will
    /// fail with an error if you try. Drop the first stream if you need to create a second one.
    pub fn messages(&self) -> Result<AMessageStream, &'static str> {
        let mut i = self.msgstream.borrow_mut();
        if i.is_some() { return Err("Another instance of AMessageStream already exists"); }
        let (tx, rx) = mpsc::unbounded();
        *i = Some(tx);
        Ok(AMessageStream { inner: rx, stream: self.msgstream.clone() })
    }
}

impl Drop for AConnection {
    fn drop(&mut self) { let _ = self.quit.take().unwrap().send(()); }
}

#[derive(Debug)]
// Internal struct; this is the future spawned on the core.
struct ADriver {
    conn: Rc<Connection>,
    fds: HashMap<RawFd, PollEvented<AWatch>>,
    core: CoreHandle,
    quit: oneshot::Receiver<()>,
    callmap: MCallMap,
    msgstream: MStream,
}

impl ADriver {
    fn modify_watch(&mut self, w: Watch) -> io::Result<()> {
        if !w.readable() && !w.writable() {
            self.fds.remove(&w.fd());
        } else {

            if let Some(evented) = self.fds.get(&w.fd()) {
                let ww = evented.get_ref().0;
                if ww.readable() == w.readable() && ww.writable() == w.writable() {
                    return Ok(())
                };
            }
            self.fds.remove(&w.fd());

            let z = PollEvented::new(AWatch(w), &self.core)?;

            self.fds.insert(w.fd(), z);
        }
        Ok(())
    }

    fn send_stream(&self, m: Message) {
        self.msgstream.borrow().as_ref().map(|z| { z.send(m).unwrap() });
    }

    fn handle_items(&mut self, items: ConnectionItems) {
        // TODO: What about all unwrapping in this function
        for i in items {
            // println!("Got: {:?}", i);
            match i {
                ConnectionItem::WatchFd(w) => { self.modify_watch(w).unwrap(); },
                ConnectionItem::MethodReturn(m) => {
                    let mut map = self.callmap.borrow_mut();
                    let serial = m.get_reply_serial().unwrap();
                    let r = map.remove(&serial);
                    if let Some(r) = r { r.send(m).unwrap(); }
                    else { self.send_stream(m) }
                }
                ConnectionItem::Nothing => return,
                ConnectionItem::Signal(m) => self.send_stream(m),
                ConnectionItem::MethodCall(m) => self.send_stream(m),
            }
        }
    }
}

impl Future for ADriver {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Result<Async<()>, ()> {
        let q = self.quit.poll();
        if q != Ok(Async::NotReady) { return Ok(Async::Ready(())); }

        let cc = self.conn.clone(); // Borrow checker made me do this
        let mut items = None;
        for w in self.fds.values() {
            let mut mask = UnixReady::hup() | UnixReady::error();
            if w.get_ref().0.readable() { mask = mask | Ready::readable().into(); }
            if w.get_ref().0.writable() { mask = mask | Ready::writable().into(); }
            let pr = w.poll_ready(*mask);
            // println!("{:?} is {:?}", w.get_ref().0.fd(), pr);
            let ur = if let Async::Ready(t) = pr { UnixReady::from(t) } else { continue };
            let flags =
                if ur.is_readable() { WatchEvent::Readable as c_uint } else { 0 } +
                if ur.is_writable() { WatchEvent::Writable as c_uint } else { 0 } +
                if ur.is_hup() { WatchEvent::Hangup as c_uint } else { 0 } +
                if ur.is_error() { WatchEvent::Error as c_uint } else { 0 };
            // println!("{:?} is {:?}", w.get_ref().0.fd(), ur);
            items = Some(cc.watch_handle(w.get_ref().0.fd(), flags));
            if ur.is_readable() { w.need_read() };
            if ur.is_writable() { w.need_write() };
        };
        self.handle_items(items.unwrap_or(cc.iter(0)));
        Ok(Async::NotReady)
    }
}

#[derive(Debug)]
struct AWatch(Watch);

impl mio::Evented for AWatch {
    fn register(&self,
                poll: &mio::Poll,
                token: mio::Token,
                mut interest: mio::Ready,
                mut opts: mio::PollOpt) -> io::Result<()>
    {
        if !self.0.readable() { interest.remove(mio::Ready::readable()) };
        if !self.0.writable() { interest.remove(mio::Ready::writable()) };
        opts.remove(mio::PollOpt::edge());
        opts.insert(mio::PollOpt::level());
        unix::EventedFd(&self.0.fd()).register(poll, token, interest, opts)
    }

    fn reregister(&self,
                  poll: &mio::Poll,
                  token: mio::Token,
                  mut interest: mio::Ready,
                  mut opts: mio::PollOpt) -> io::Result<()>
    {
        if !self.0.readable() { interest.remove(mio::Ready::readable()) };
        if !self.0.writable() { interest.remove(mio::Ready::writable()) };
        opts.remove(mio::PollOpt::edge());
        opts.insert(mio::PollOpt::level());
        unix::EventedFd(&self.0.fd()).reregister(poll, token, interest, opts)
    }

    fn deregister(&self, poll: &mio::Poll) -> io::Result<()> {
        unix::EventedFd(&self.0.fd()).deregister(poll)
    }
}

#[derive(Debug)]
/// A Future that resolves when a method call is replied to.
pub struct AMethodCall {
    serial: u32,
    callmap: MCallMap,
    inner: oneshot::Receiver<Message>,
}

impl Future for AMethodCall {
    type Item = Message;
    type Error = DBusError;

    fn poll(&mut self) -> Result<Async<Self::Item>, Self::Error> {
        let x = self.inner.poll().map_err(|_| DBusError::new_custom("org.freedesktop.DBus.Failed", "Tokio cancelled future"))?;
        if let Async::Ready(mut m) = x {
            m.as_result()?;
            Ok(Async::Ready(m))
        } else { Ok(Async::NotReady) }
    }
}

impl Drop for AMethodCall {
    fn drop(&mut self) {
        let mut map = self.callmap.borrow_mut();
        map.remove(&self.serial);
    }
}

#[derive(Debug)]
/// A Stream of incoming messages.
///
/// Messages already processed (method returns for AMethodCall, fd changes)
/// are already consumed and will not be present in the stream.
pub struct AMessageStream {
    inner: mpsc::UnboundedReceiver<Message>,
    stream: MStream,
}

impl Stream for AMessageStream {
    type Item = Message;
    type Error = ();
    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        // println!("Polling message stream");
        let r = self.inner.poll();
        // println!("msgstream {:?}", r);
        r
    }
}

impl Drop for AMessageStream {
    fn drop(&mut self) {
        *self.stream.borrow_mut() = None;
    }
}

#[test]
fn aconnection_test() {
    let conn = Rc::new(Connection::get_private(::dbus::BusType::Session).unwrap());
    let mut core = ::tokio_core::reactor::Core::new().unwrap();
    let aconn = AConnection::new(conn.clone(), core.handle()).unwrap();

    let m = ::dbus::Message::new_method_call("org.freedesktop.DBus", "/", "org.freedesktop.DBus", "ListNames").unwrap();
    let reply = core.run(aconn.method_call(m).unwrap()).unwrap();
    let z: Vec<&str> = reply.get1().unwrap();
    println!("got reply: {:?}", z);
    assert!(z.iter().any(|v| *v == "org.freedesktop.DBus"));
}

#[test]
fn astream_test() {
    let conn = Rc::new(Connection::get_private(::dbus::BusType::Session).unwrap());
    let mut core = ::tokio_core::reactor::Core::new().unwrap();
    let aconn = AConnection::new(conn.clone(), core.handle()).unwrap();

    let items: AMessageStream = aconn.messages().unwrap();
    let signals = items.filter_map(|m| if m.msg_type() == ::dbus::MessageType::Signal { Some(m) } else { None });
    let firstsig = core.run(signals.into_future()).map(|(x, _)| x).map_err(|(x, _)| x).unwrap();
    println!("first signal was: {:?}", firstsig);
    assert_eq!(firstsig.unwrap().msg_type(), ::dbus::MessageType::Signal);
}

<|endoftext|>