<commit_before>/*pub use api::x11::{Window, WindowProxy, MonitorId, get_available_monitors, get_primary_monitor};
pub use api::x11::{WaitEventsIterator, PollEventsIterator};*/

use std::collections::VecDeque;
use std::sync::Arc;

use ContextError;
use CreationError;
use CursorState;
use Event;
use GlAttributes;
use GlContext;
use MouseCursor;
use PixelFormat;
use PixelFormatRequirements;
use WindowAttributes;
use libc;

use api::wayland;
use api::x11;
use api::x11::XConnection;
use api::x11::XNotSupported;

enum Backend {
    X(Arc<XConnection>),
    Wayland,
    Error(XNotSupported),
}

lazy_static!(
    static ref BACKEND: Backend = {
        // Wayland backend is not production-ready yet so we disable it
        if false && wayland::is_available() {
            Backend::Wayland
        } else {
            match XConnection::new(Some(x_error_callback)) {
                Ok(x) => Backend::X(Arc::new(x)),
                Err(e) => Backend::Error(e),
            }
        }
    };
);

pub enum Window {
    #[doc(hidden)]
    X(x11::Window),
    #[doc(hidden)]
    Wayland(wayland::Window)
}

#[derive(Clone)]
pub enum WindowProxy {
    #[doc(hidden)]
    X(x11::WindowProxy),
    #[doc(hidden)]
    Wayland(wayland::WindowProxy)
}

impl WindowProxy {
    #[inline]
    pub fn wakeup_event_loop(&self) {
        match self {
            &WindowProxy::X(ref wp) => wp.wakeup_event_loop(),
            &WindowProxy::Wayland(ref wp) => wp.wakeup_event_loop()
        }
    }
}

#[derive(Clone)]
pub enum MonitorId {
    #[doc(hidden)]
    X(x11::MonitorId),
    #[doc(hidden)]
    Wayland(wayland::MonitorId),
    #[doc(hidden)]
    None,
}

#[inline]
pub fn get_available_monitors() -> VecDeque<MonitorId> {
    match *BACKEND {
        Backend::Wayland => wayland::get_available_monitors()
                                .into_iter()
                                .map(MonitorId::Wayland)
                                .collect(),
        Backend::X(ref connec) => x11::get_available_monitors(connec)
                                    .into_iter()
                                    .map(MonitorId::X)
                                    .collect(),
        Backend::Error(_) => { let mut d = VecDeque::new(); d.push_back(MonitorId::None); d},
    }
}

#[inline]
pub fn get_primary_monitor() -> MonitorId {
    match *BACKEND {
        Backend::Wayland => MonitorId::Wayland(wayland::get_primary_monitor()),
        Backend::X(ref connec) => MonitorId::X(x11::get_primary_monitor(connec)),
        Backend::Error(_) => MonitorId::None,
    }
}

impl MonitorId {
    #[inline]
    pub fn get_name(&self) -> Option<String> {
        match self {
            &MonitorId::X(ref m) => m.get_name(),
            &MonitorId::Wayland(ref m) => m.get_name(),
            &MonitorId::None => None,
        }
    }

    #[inline]
    pub fn get_native_identifier(&self) -> ::native_monitor::NativeMonitorId {
        match self {
            &MonitorId::X(ref m) => m.get_native_identifier(),
            &MonitorId::Wayland(ref m) => m.get_native_identifier(),
            &MonitorId::None => unimplemented!()        // FIXME:
        }
    }

    #[inline]
    pub fn get_dimensions(&self) -> (u32, u32) {
        match self {
            &MonitorId::X(ref m) => m.get_dimensions(),
            &MonitorId::Wayland(ref m) => m.get_dimensions(),
            &MonitorId::None => (800, 600),     // FIXME:
        }
    }
}

pub enum PollEventsIterator<'a> {
    #[doc(hidden)]
    X(x11::PollEventsIterator<'a>),
    #[doc(hidden)]
    Wayland(wayland::PollEventsIterator<'a>)
}

impl<'a> Iterator for PollEventsIterator<'a> {
    type Item = Event;

    #[inline]
    fn next(&mut self) -> Option<Event> {
        match self {
            &mut PollEventsIterator::X(ref mut it) => it.next(),
            &mut PollEventsIterator::Wayland(ref mut it) => it.next()
        }
    }
}

pub enum WaitEventsIterator<'a> {
    #[doc(hidden)]
    X(x11::WaitEventsIterator<'a>),
    #[doc(hidden)]
    Wayland(wayland::WaitEventsIterator<'a>)
}

impl<'a> Iterator for WaitEventsIterator<'a> {
    type Item = Event;

    #[inline]
    fn next(&mut self) -> Option<Event> {
        match self {
            &mut WaitEventsIterator::X(ref mut it) => it.next(),
            &mut WaitEventsIterator::Wayland(ref mut it) => it.next()
        }
    }
}

impl Window {
    #[inline]
    pub fn new(window: &WindowAttributes, pf_reqs: &PixelFormatRequirements,
               opengl: &GlAttributes<&Window>) -> Result<Window, CreationError>
    {
        match *BACKEND {
            Backend::Wayland => {
                let opengl = opengl.clone().map_sharing(|w| match w {
                    &Window::Wayland(ref w) => w,
                    _ => panic!()       // TODO: return an error
                });

                wayland::Window::new(window, pf_reqs, &opengl).map(Window::Wayland)
            },

            Backend::X(ref connec) => {
                let opengl = opengl.clone().map_sharing(|w| match w {
                    &Window::X(ref w) => w,
                    _ => panic!()       // TODO: return an error
                });

                x11::Window::new(connec, window, pf_reqs, &opengl).map(Window::X)
            },

            Backend::Error(ref error) => Err(CreationError::NoBackendAvailable(Box::new(error.clone())))
        }
    }

    #[inline]
    pub fn set_title(&self, title: &str) {
        match self {
            &Window::X(ref w) => w.set_title(title),
            &Window::Wayland(ref w) => w.set_title(title)
        }
    }

    #[inline]
    pub fn show(&self) {
        match self {
            &Window::X(ref w) => w.show(),
            &Window::Wayland(ref w) => w.show()
        }
    }

    #[inline]
    pub fn hide(&self) {
        match self {
            &Window::X(ref w) => w.hide(),
            &Window::Wayland(ref w) => w.hide()
        }
    }

    #[inline]
    pub fn get_position(&self) -> Option<(i32, i32)> {
        match self {
            &Window::X(ref w) => w.get_position(),
            &Window::Wayland(ref w) => w.get_position()
        }
    }

    #[inline]
    pub fn set_position(&self, x: i32, y: i32) {
        match self {
            &Window::X(ref w) => w.set_position(x, y),
            &Window::Wayland(ref w) => w.set_position(x, y)
        }
    }

    #[inline]
    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        match self {
            &Window::X(ref w) => w.get_inner_size(),
            &Window::Wayland(ref w) => w.get_inner_size()
        }
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        match self {
            &Window::X(ref w) => w.get_outer_size(),
            &Window::Wayland(ref w) => w.get_outer_size()
        }
    }

    #[inline]
    pub fn set_inner_size(&self, x: u32, y: u32) {
        match self {
            &Window::X(ref w) => w.set_inner_size(x, y),
            &Window::Wayland(ref w) => w.set_inner_size(x, y)
        }
    }

    #[inline]
    pub fn create_window_proxy(&self) -> WindowProxy {
        match self {
            &Window::X(ref w) => WindowProxy::X(w.create_window_proxy()),
            &Window::Wayland(ref w) => WindowProxy::Wayland(w.create_window_proxy())
        }
    }

    #[inline]
    pub fn poll_events(&self) -> PollEventsIterator {
        match self {
            &Window::X(ref w) => PollEventsIterator::X(w.poll_events()),
            &Window::Wayland(ref w) => PollEventsIterator::Wayland(w.poll_events())
        }
    }

    #[inline]
    pub fn wait_events(&self) -> WaitEventsIterator {
        match self {
            &Window::X(ref w) => WaitEventsIterator::X(w.wait_events()),
            &Window::Wayland(ref w) => WaitEventsIterator::Wayland(w.wait_events())
        }
    }

    #[inline]
    pub fn set_window_resize_callback(&mut self, callback: Option<fn(u32, u32)>) {
        match self {
            &mut Window::X(ref mut w) => w.set_window_resize_callback(callback),
            &mut Window::Wayland(ref mut w) => w.set_window_resize_callback(callback)
        }
    }

    #[inline]
    pub fn set_cursor(&self, cursor: MouseCursor) {
        match self {
            &Window::X(ref w) => w.set_cursor(cursor),
            &Window::Wayland(ref w) => w.set_cursor(cursor)
        }
    }

    #[inline]
    pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
        match self {
            &Window::X(ref w) => w.set_cursor_state(state),
            &Window::Wayland(ref w) => w.set_cursor_state(state)
        }
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
       match self {
            &Window::X(ref w) => w.hidpi_factor(),
            &Window::Wayland(ref w) => w.hidpi_factor()
        }
    }

    #[inline]
    pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
        match self {
            &Window::X(ref w) => w.set_cursor_position(x, y),
            &Window::Wayland(ref w) => w.set_cursor_position(x, y)
        }
    }

    #[inline]
    pub fn platform_display(&self) -> *mut libc::c_void {
        match self {
            &Window::X(ref w) => w.platform_display(),
            &Window::Wayland(ref w) => w.platform_display()
        }
    }

    #[inline]
    pub fn platform_window(&self) -> *mut libc::c_void {
        match self {
            &Window::X(ref w) => w.platform_window(),
            &Window::Wayland(ref w) => w.platform_window()
        }
    }
}

impl GlContext for Window {
    #[inline]
    unsafe fn make_current(&self) -> Result<(), ContextError> {
        match self {
            &Window::X(ref w) => w.make_current(),
            &Window::Wayland(ref w) => w.make_current()
        }
    }

    #[inline]
    fn is_current(&self) -> bool {
        match self {
            &Window::X(ref w) => w.is_current(),
            &Window::Wayland(ref w) => w.is_current()
        }
    }

    #[inline]
    fn get_proc_address(&self, addr: &str) -> *const () {
        match self {
            &Window::X(ref w) => w.get_proc_address(addr),
            &Window::Wayland(ref w) => w.get_proc_address(addr)
        }
    }

    #[inline]
    fn swap_buffers(&self) -> Result<(), ContextError> {
        match self {
            &Window::X(ref w) => w.swap_buffers(),
            &Window::Wayland(ref w) => w.swap_buffers()
        }
    }

    #[inline]
    fn get_api(&self) -> ::Api {
        match self {
            &Window::X(ref w) => w.get_api(),
            &Window::Wayland(ref w) => w.get_api()
        }
    }

    #[inline]
    fn get_pixel_format(&self) -> PixelFormat {
        match self {
            &Window::X(ref w) => w.get_pixel_format(),
            &Window::Wayland(ref w) => w.get_pixel_format()
        }
    }
}

unsafe extern "C" fn x_error_callback(dpy: *mut x11::ffi::Display, event: *mut x11::ffi::XErrorEvent)
                                      -> libc::c_int
{
    use std::ffi::CStr;

    if let Backend::X(ref x) = *BACKEND {
        let mut buff: Vec<u8> = Vec::with_capacity(1024);
        (x.xlib.XGetErrorText)(dpy, (*event).error_code as i32, buff.as_mut_ptr() as *mut i8, buff.capacity() as i32);
        let error = CStr::from_ptr(buff.as_mut_ptr() as *const i8).to_string_lossy();
        println!("[glutin] x error code={} major={} minor={}: {}!", (*event).error_code, (*event).request_code, (*event).minor_code, error);
    }

    0
}
<commit_msg>api/wayland: activate the backend<commit_after>/*pub use api::x11::{Window, WindowProxy, MonitorId, get_available_monitors, get_primary_monitor};
pub use api::x11::{WaitEventsIterator, PollEventsIterator};*/

use std::collections::VecDeque;
use std::sync::Arc;

use ContextError;
use CreationError;
use CursorState;
use Event;
use GlAttributes;
use GlContext;
use MouseCursor;
use PixelFormat;
use PixelFormatRequirements;
use WindowAttributes;
use libc;

use api::wayland;
use api::x11;
use api::x11::XConnection;
use api::x11::XNotSupported;

enum Backend {
    X(Arc<XConnection>),
    Wayland,
    Error(XNotSupported),
}

lazy_static!(
    static ref BACKEND: Backend = {
        // Wayland backend is not production-ready yet so we disable it
        if wayland::is_available() {
            Backend::Wayland
        } else {
            match XConnection::new(Some(x_error_callback)) {
                Ok(x) => Backend::X(Arc::new(x)),
                Err(e) => Backend::Error(e),
            }
        }
    };
);

pub enum Window {
    #[doc(hidden)]
    X(x11::Window),
    #[doc(hidden)]
    Wayland(wayland::Window)
}

#[derive(Clone)]
pub enum WindowProxy {
    #[doc(hidden)]
    X(x11::WindowProxy),
    #[doc(hidden)]
    Wayland(wayland::WindowProxy)
}

impl WindowProxy {
    #[inline]
    pub fn wakeup_event_loop(&self) {
        match self {
            &WindowProxy::X(ref wp) => wp.wakeup_event_loop(),
            &WindowProxy::Wayland(ref wp) => wp.wakeup_event_loop()
        }
    }
}

#[derive(Clone)]
pub enum MonitorId {
    #[doc(hidden)]
    X(x11::MonitorId),
    #[doc(hidden)]
    Wayland(wayland::MonitorId),
    #[doc(hidden)]
    None,
}

#[inline]
pub fn get_available_monitors() -> VecDeque<MonitorId> {
    match *BACKEND {
        Backend::Wayland => wayland::get_available_monitors()
                                .into_iter()
                                .map(MonitorId::Wayland)
                                .collect(),
        Backend::X(ref connec) => x11::get_available_monitors(connec)
                                    .into_iter()
                                    .map(MonitorId::X)
                                    .collect(),
        Backend::Error(_) => { let mut d = VecDeque::new(); d.push_back(MonitorId::None); d},
    }
}

#[inline]
pub fn get_primary_monitor() -> MonitorId {
    match *BACKEND {
        Backend::Wayland => MonitorId::Wayland(wayland::get_primary_monitor()),
        Backend::X(ref connec) => MonitorId::X(x11::get_primary_monitor(connec)),
        Backend::Error(_) => MonitorId::None,
    }
}

impl MonitorId {
    #[inline]
    pub fn get_name(&self) -> Option<String> {
        match self {
            &MonitorId::X(ref m) => m.get_name(),
            &MonitorId::Wayland(ref m) => m.get_name(),
            &MonitorId::None => None,
        }
    }

    #[inline]
    pub fn get_native_identifier(&self) -> ::native_monitor::NativeMonitorId {
        match self {
            &MonitorId::X(ref m) => m.get_native_identifier(),
            &MonitorId::Wayland(ref m) => m.get_native_identifier(),
            &MonitorId::None => unimplemented!()        // FIXME:
        }
    }

    #[inline]
    pub fn get_dimensions(&self) -> (u32, u32) {
        match self {
            &MonitorId::X(ref m) => m.get_dimensions(),
            &MonitorId::Wayland(ref m) => m.get_dimensions(),
            &MonitorId::None => (800, 600),     // FIXME:
        }
    }
}

pub enum PollEventsIterator<'a> {
    #[doc(hidden)]
    X(x11::PollEventsIterator<'a>),
    #[doc(hidden)]
    Wayland(wayland::PollEventsIterator<'a>)
}

impl<'a> Iterator for PollEventsIterator<'a> {
    type Item = Event;

    #[inline]
    fn next(&mut self) -> Option<Event> {
        match self {
            &mut PollEventsIterator::X(ref mut it) => it.next(),
            &mut PollEventsIterator::Wayland(ref mut it) => it.next()
        }
    }
}

pub enum WaitEventsIterator<'a> {
    #[doc(hidden)]
    X(x11::WaitEventsIterator<'a>),
    #[doc(hidden)]
    Wayland(wayland::WaitEventsIterator<'a>)
}

impl<'a> Iterator for WaitEventsIterator<'a> {
    type Item = Event;

    #[inline]
    fn next(&mut self) -> Option<Event> {
        match self {
            &mut WaitEventsIterator::X(ref mut it) => it.next(),
            &mut WaitEventsIterator::Wayland(ref mut it) => it.next()
        }
    }
}

impl Window {
    #[inline]
    pub fn new(window: &WindowAttributes, pf_reqs: &PixelFormatRequirements,
               opengl: &GlAttributes<&Window>) -> Result<Window, CreationError>
    {
        match *BACKEND {
            Backend::Wayland => {
                let opengl = opengl.clone().map_sharing(|w| match w {
                    &Window::Wayland(ref w) => w,
                    _ => panic!()       // TODO: return an error
                });

                wayland::Window::new(window, pf_reqs, &opengl).map(Window::Wayland)
            },

            Backend::X(ref connec) => {
                let opengl = opengl.clone().map_sharing(|w| match w {
                    &Window::X(ref w) => w,
                    _ => panic!()       // TODO: return an error
                });

                x11::Window::new(connec, window, pf_reqs, &opengl).map(Window::X)
            },

            Backend::Error(ref error) => Err(CreationError::NoBackendAvailable(Box::new(error.clone())))
        }
    }

    #[inline]
    pub fn set_title(&self, title: &str) {
        match self {
            &Window::X(ref w) => w.set_title(title),
            &Window::Wayland(ref w) => w.set_title(title)
        }
    }

    #[inline]
    pub fn show(&self) {
        match self {
            &Window::X(ref w) => w.show(),
            &Window::Wayland(ref w) => w.show()
        }
    }

    #[inline]
    pub fn hide(&self) {
        match self {
            &Window::X(ref w) => w.hide(),
            &Window::Wayland(ref w) => w.hide()
        }
    }

    #[inline]
    pub fn get_position(&self) -> Option<(i32, i32)> {
        match self {
            &Window::X(ref w) => w.get_position(),
            &Window::Wayland(ref w) => w.get_position()
        }
    }

    #[inline]
    pub fn set_position(&self, x: i32, y: i32) {
        match self {
            &Window::X(ref w) => w.set_position(x, y),
            &Window::Wayland(ref w) => w.set_position(x, y)
        }
    }

    #[inline]
    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        match self {
            &Window::X(ref w) => w.get_inner_size(),
            &Window::Wayland(ref w) => w.get_inner_size()
        }
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        match self {
            &Window::X(ref w) => w.get_outer_size(),
            &Window::Wayland(ref w) => w.get_outer_size()
        }
    }

    #[inline]
    pub fn set_inner_size(&self, x: u32, y: u32) {
        match self {
            &Window::X(ref w) => w.set_inner_size(x, y),
            &Window::Wayland(ref w) => w.set_inner_size(x, y)
        }
    }

    #[inline]
    pub fn create_window_proxy(&self) -> WindowProxy {
        match self {
            &Window::X(ref w) => WindowProxy::X(w.create_window_proxy()),
            &Window::Wayland(ref w) => WindowProxy::Wayland(w.create_window_proxy())
        }
    }

    #[inline]
    pub fn poll_events(&self) -> PollEventsIterator {
        match self {
            &Window::X(ref w) => PollEventsIterator::X(w.poll_events()),
            &Window::Wayland(ref w) => PollEventsIterator::Wayland(w.poll_events())
        }
    }

    #[inline]
    pub fn wait_events(&self) -> WaitEventsIterator {
        match self {
            &Window::X(ref w) => WaitEventsIterator::X(w.wait_events()),
            &Window::Wayland(ref w) => WaitEventsIterator::Wayland(w.wait_events())
        }
    }

    #[inline]
    pub fn set_window_resize_callback(&mut self, callback: Option<fn(u32, u32)>) {
        match self {
            &mut Window::X(ref mut w) => w.set_window_resize_callback(callback),
            &mut Window::Wayland(ref mut w) => w.set_window_resize_callback(callback)
        }
    }

    #[inline]
    pub fn set_cursor(&self, cursor: MouseCursor) {
        match self {
            &Window::X(ref w) => w.set_cursor(cursor),
            &Window::Wayland(ref w) => w.set_cursor(cursor)
        }
    }

    #[inline]
    pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
        match self {
            &Window::X(ref w) => w.set_cursor_state(state),
            &Window::Wayland(ref w) => w.set_cursor_state(state)
        }
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
       match self {
            &Window::X(ref w) => w.hidpi_factor(),
            &Window::Wayland(ref w) => w.hidpi_factor()
        }
    }

    #[inline]
    pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
        match self {
            &Window::X(ref w) => w.set_cursor_position(x, y),
            &Window::Wayland(ref w) => w.set_cursor_position(x, y)
        }
    }

    #[inline]
    pub fn platform_display(&self) -> *mut libc::c_void {
        match self {
            &Window::X(ref w) => w.platform_display(),
            &Window::Wayland(ref w) => w.platform_display()
        }
    }

    #[inline]
    pub fn platform_window(&self) -> *mut libc::c_void {
        match self {
            &Window::X(ref w) => w.platform_window(),
            &Window::Wayland(ref w) => w.platform_window()
        }
    }
}

impl GlContext for Window {
    #[inline]
    unsafe fn make_current(&self) -> Result<(), ContextError> {
        match self {
            &Window::X(ref w) => w.make_current(),
            &Window::Wayland(ref w) => w.make_current()
        }
    }

    #[inline]
    fn is_current(&self) -> bool {
        match self {
            &Window::X(ref w) => w.is_current(),
            &Window::Wayland(ref w) => w.is_current()
        }
    }

    #[inline]
    fn get_proc_address(&self, addr: &str) -> *const () {
        match self {
            &Window::X(ref w) => w.get_proc_address(addr),
            &Window::Wayland(ref w) => w.get_proc_address(addr)
        }
    }

    #[inline]
    fn swap_buffers(&self) -> Result<(), ContextError> {
        match self {
            &Window::X(ref w) => w.swap_buffers(),
            &Window::Wayland(ref w) => w.swap_buffers()
        }
    }

    #[inline]
    fn get_api(&self) -> ::Api {
        match self {
            &Window::X(ref w) => w.get_api(),
            &Window::Wayland(ref w) => w.get_api()
        }
    }

    #[inline]
    fn get_pixel_format(&self) -> PixelFormat {
        match self {
            &Window::X(ref w) => w.get_pixel_format(),
            &Window::Wayland(ref w) => w.get_pixel_format()
        }
    }
}

unsafe extern "C" fn x_error_callback(dpy: *mut x11::ffi::Display, event: *mut x11::ffi::XErrorEvent)
                                      -> libc::c_int
{
    use std::ffi::CStr;

    if let Backend::X(ref x) = *BACKEND {
        let mut buff: Vec<u8> = Vec::with_capacity(1024);
        (x.xlib.XGetErrorText)(dpy, (*event).error_code as i32, buff.as_mut_ptr() as *mut i8, buff.capacity() as i32);
        let error = CStr::from_ptr(buff.as_mut_ptr() as *const i8).to_string_lossy();
        println!("[glutin] x error code={} major={} minor={}: {}!", (*event).error_code, (*event).request_code, (*event).minor_code, error);
    }

    0
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015-2017 The imgui-rs Developers
 * Copyright (C) 2017-2019 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use std::time::{Duration, Instant};

use glium::glutin::{self, Api, GlRequest};
use glium::{Display, Surface};
use imgui::{FontGlyphRange, FrameSize, ImFontConfig, ImGui, Ui};
use imgui_glium_renderer::Renderer;

use crate::model::Model;
use crate::update;

const FRAME_DURATION: Duration = Duration::from_millis(16);

#[derive(Copy, Clone, PartialEq, Debug, Default)]
struct MouseState {
    pos: (i32, i32),
    pressed: (bool, bool, bool),
    wheel: f32,
}

pub fn run<F: FnMut(&mut Model, &Ui, (f32, f32)) -> bool>(
    title: String,
    dimensions: (u32, u32),
    clear_color: [f32; 4],
    mut events_loop: glutin::EventsLoop,
    mut model: Model,
    mut run_ui: F,
) {
    let window = glutin::WindowBuilder::new()
        .with_title(title)
        .with_dimensions(dimensions.into());
    let mut context = glutin::ContextBuilder::new().with_vsync(true);
    if cfg!(target_os = "android") {
        // https://github.com/tomaka/android-rs-glue/issues/153#issuecomment-318348732
        // On Android we must specify an OpenGL ES version or glutin will assume we are using an
        // unsupported version and panic
        context = context.with_gl(GlRequest::Specific(Api::OpenGlEs, (2, 0)));
    }

    let display = Display::new(window, context, &events_loop).unwrap();

    let mut imgui = ImGui::init();
    imgui.set_ini_filename(None);

    let config = ImFontConfig::new()
        .oversample_h(4)
        .oversample_v(4)
        .size_pixels(21.0)
        .rasterizer_multiply(1.05);

    config.add_font(
        &mut imgui.fonts(),
        include_bytes!("../../assets/FiraSans-Regular.ttf"),
        &FontGlyphRange::default(),
    );

    let mut renderer = Renderer::init(&mut imgui, &display).expect("Failed to initialize renderer");

    let mut last_frame = Instant::now();
    let mut mouse_state = MouseState::default();

    let mut render = |model: &mut Model, imgui: &mut ImGui, last_frame: &mut Instant| {
        let now = Instant::now();
        let delta = now - *last_frame;
        let delta_s = delta.as_secs() as f32 + delta.subsec_nanos() as f32 / 1_000_000_000.0;
        *last_frame = now;

        let gl_window = display.gl_window();
        let frame_size = FrameSize {
            logical_size: gl_window.get_inner_size().unwrap().into(),
            hidpi_factor: gl_window.get_hidpi_factor(),
        };
        let size_points = (
            (frame_size.logical_size.0 / frame_size.hidpi_factor) as f32,
            (frame_size.logical_size.1 / frame_size.hidpi_factor) as f32,
        );

        let ui = imgui.frame(frame_size, delta_s);
        if !run_ui(model, &ui, size_points) {
            return false;
        }

        let mut target = display.draw();
        target.clear_color(
            clear_color[0],
            clear_color[1],
            clear_color[2],
            clear_color[3],
        );
        renderer.render(&mut target, ui).expect("Rendering failed");
        target.finish().unwrap();
        true
    };

    // Render one frame before the event loop so the screen isn't empty
    render(&mut model, &mut imgui, &mut last_frame);

    events_loop.run_forever(|event| {
        use glium::glutin::ElementState::Pressed;
        use glium::glutin::WindowEvent::*;
        use glium::glutin::{
            ControlFlow, Event, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode,
        };

        if let Event::Awakened = event {
            if Instant::now() - last_frame < FRAME_DURATION {
                // Receive the AI move, and queue the next one (if it's a computer-only game)
                update::update(&mut model, None);
                update::update(&mut model, None);

                // If the AI is moving very quickly, then the last move of the game will be
                // throttled and not receive a render. This appears to "freeze" the game. So, we
                // render if the game is finished.
                if model.is_game_over() && !render(&mut model, &mut imgui, &mut last_frame) {
                    return ControlFlow::Break;
                }
            } else {
                // Receive the AI move, then render
                update::update(&mut model, None);
                if !render(&mut model, &mut imgui, &mut last_frame) {
                    return ControlFlow::Break;
                }
            }
        } else if let Event::Suspended(true) = event {
            // This is so that the AI doesn't run in the background on Android. Technically, we
            // should also call update or render on Suspended(false) to restart the AI, but there's
            // no point since the app crashes when it's resumed or even right after it's suspended.
            model.ai.stop();
        } else if let Event::WindowEvent { event, .. } = event {
            match event {
                CloseRequested => return ControlFlow::Break,
                KeyboardInput { input, .. } => {
                    if let Some(VirtualKeyCode::Q) = input.virtual_keycode {
                        if cfg!(target_os = "macos") && input.modifiers.logo {
                            return ControlFlow::Break;
                        }
                    }
                }
                Refresh | Resized(_) | HiDpiFactorChanged(_) => {
                    if !render(&mut model, &mut imgui, &mut last_frame) {
                        return ControlFlow::Break;
                    }
                }
                CursorMoved { position, .. } => {
                    mouse_state.pos = position.into();
                    update_mouse(&mut imgui, &mut mouse_state);

                    if Instant::now() - last_frame < FRAME_DURATION {
                        return ControlFlow::Continue;
                    } else if !render(&mut model, &mut imgui, &mut last_frame) {
                        return ControlFlow::Break;
                    }
                }
                MouseWheel {
                    delta,
                    phase: TouchPhase::Moved,
                    ..
                } => {
                    mouse_state.wheel = match delta {
                        MouseScrollDelta::LineDelta(_, y) => y,
                        MouseScrollDelta::PixelDelta(position) => position.y as f32,
                    };
                    update_mouse(&mut imgui, &mut mouse_state);

                    if !render(&mut model, &mut imgui, &mut last_frame) {
                        return ControlFlow::Break;
                    }
                }
                MouseInput { state, button, .. } => {
                    if MouseButton::Left == button {
                        mouse_state.pressed.0 = state == Pressed;
                        update_mouse(&mut imgui, &mut mouse_state);

                        // Render twice to immediately show the results of the click
                        if !render(&mut model, &mut imgui, &mut last_frame) {
                            return ControlFlow::Break;
                        }
                        if !render(&mut model, &mut imgui, &mut last_frame) {
                            return ControlFlow::Break;
                        }
                    }
                }
                Touch(glutin::Touch {
                    phase, location, ..
                }) => {
                    mouse_state.pos = location.into();
                    mouse_state.pressed.0 =
                        phase == TouchPhase::Started || phase == TouchPhase::Moved;
                    update_mouse(&mut imgui, &mut mouse_state);

                    match phase {
                        TouchPhase::Moved => {
                            if Instant::now() - last_frame < FRAME_DURATION {
                                return ControlFlow::Continue;
                            } else if !render(&mut model, &mut imgui, &mut last_frame) {
                                return ControlFlow::Break;
                            }
                        }
                        _ => {
                            // Render twice to immediately show the results of the touch
                            if !render(&mut model, &mut imgui, &mut last_frame) {
                                return ControlFlow::Break;
                            }
                            if !render(&mut model, &mut imgui, &mut last_frame) {
                                return ControlFlow::Break;
                            }
                        }
                    }
                }
                _ => (),
            }
        }
        ControlFlow::Continue
    });
}

fn update_mouse(imgui: &mut ImGui, mouse_state: &mut MouseState) {
    let scale = imgui.display_framebuffer_scale();
    imgui.set_mouse_pos(
        mouse_state.pos.0 as f32 / scale.0,
        mouse_state.pos.1 as f32 / scale.1,
    );
    imgui.set_mouse_down([
        mouse_state.pressed.0,
        mouse_state.pressed.1,
        mouse_state.pressed.2,
        false,
        false,
    ]);
    imgui.set_mouse_wheel(mouse_state.wheel / scale.1);
    mouse_state.wheel = 0.0;
}
<commit_msg>Create one gl_window<commit_after>/*
 * Copyright (C) 2015-2017 The imgui-rs Developers
 * Copyright (C) 2017-2019 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use std::time::{Duration, Instant};

use glium::glutin::{self, Api, GlRequest};
use glium::{Display, Surface};
use imgui::{FontGlyphRange, FrameSize, ImFontConfig, ImGui, Ui};
use imgui_glium_renderer::Renderer;

use crate::model::Model;
use crate::update;

const FRAME_DURATION: Duration = Duration::from_millis(16);

#[derive(Copy, Clone, PartialEq, Debug, Default)]
struct MouseState {
    pos: (i32, i32),
    pressed: (bool, bool, bool),
    wheel: f32,
}

pub fn run<F: FnMut(&mut Model, &Ui, (f32, f32)) -> bool>(
    title: String,
    dimensions: (u32, u32),
    clear_color: [f32; 4],
    mut events_loop: glutin::EventsLoop,
    mut model: Model,
    mut run_ui: F,
) {
    let window = glutin::WindowBuilder::new()
        .with_title(title)
        .with_dimensions(dimensions.into());
    let mut context = glutin::ContextBuilder::new().with_vsync(true);
    if cfg!(target_os = "android") {
        // https://github.com/tomaka/android-rs-glue/issues/153#issuecomment-318348732
        // On Android we must specify an OpenGL ES version or glutin will assume we are using an
        // unsupported version and panic
        context = context.with_gl(GlRequest::Specific(Api::OpenGlEs, (2, 0)));
    }

    let display = Display::new(window, context, &events_loop).unwrap();
    let gl_window = display.gl_window();

    let mut imgui = ImGui::init();
    imgui.set_ini_filename(None);

    let config = ImFontConfig::new()
        .oversample_h(4)
        .oversample_v(4)
        .size_pixels(21.0)
        .rasterizer_multiply(1.05);

    config.add_font(
        &mut imgui.fonts(),
        include_bytes!("../../assets/FiraSans-Regular.ttf"),
        &FontGlyphRange::default(),
    );

    let mut renderer = Renderer::init(&mut imgui, &display).expect("Failed to initialize renderer");

    let mut last_frame = Instant::now();
    let mut mouse_state = MouseState::default();

    let mut render = |model: &mut Model, imgui: &mut ImGui, last_frame: &mut Instant| {
        let now = Instant::now();
        let delta = now - *last_frame;
        let delta_s = delta.as_secs() as f32 + delta.subsec_nanos() as f32 / 1_000_000_000.0;
        *last_frame = now;

        let frame_size = FrameSize {
            logical_size: gl_window.get_inner_size().unwrap().into(),
            hidpi_factor: gl_window.get_hidpi_factor(),
        };
        let size_points = (
            (frame_size.logical_size.0 / frame_size.hidpi_factor) as f32,
            (frame_size.logical_size.1 / frame_size.hidpi_factor) as f32,
        );

        let ui = imgui.frame(frame_size, delta_s);
        if !run_ui(model, &ui, size_points) {
            return false;
        }

        let mut target = display.draw();
        target.clear_color(
            clear_color[0],
            clear_color[1],
            clear_color[2],
            clear_color[3],
        );
        renderer.render(&mut target, ui).expect("Rendering failed");
        target.finish().unwrap();
        true
    };

    // Render one frame before the event loop so the screen isn't empty
    render(&mut model, &mut imgui, &mut last_frame);

    events_loop.run_forever(|event| {
        use glium::glutin::ElementState::Pressed;
        use glium::glutin::WindowEvent::*;
        use glium::glutin::{
            ControlFlow, Event, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode,
        };

        if let Event::Awakened = event {
            if Instant::now() - last_frame < FRAME_DURATION {
                // Receive the AI move, and queue the next one (if it's a computer-only game)
                update::update(&mut model, None);
                update::update(&mut model, None);

                // If the AI is moving very quickly, then the last move of the game will be
                // throttled and not receive a render. This appears to "freeze" the game. So, we
                // render if the game is finished.
                if model.is_game_over() && !render(&mut model, &mut imgui, &mut last_frame) {
                    return ControlFlow::Break;
                }
            } else {
                // Receive the AI move, then render
                update::update(&mut model, None);
                if !render(&mut model, &mut imgui, &mut last_frame) {
                    return ControlFlow::Break;
                }
            }
        } else if let Event::Suspended(true) = event {
            // This is so that the AI doesn't run in the background on Android. Technically, we
            // should also call update or render on Suspended(false) to restart the AI, but there's
            // no point since the app crashes when it's resumed or even right after it's suspended.
            model.ai.stop();
        } else if let Event::WindowEvent { event, .. } = event {
            match event {
                CloseRequested => return ControlFlow::Break,
                KeyboardInput { input, .. } => {
                    if let Some(VirtualKeyCode::Q) = input.virtual_keycode {
                        if cfg!(target_os = "macos") && input.modifiers.logo {
                            return ControlFlow::Break;
                        }
                    }
                }
                Refresh | Resized(_) | HiDpiFactorChanged(_) => {
                    if !render(&mut model, &mut imgui, &mut last_frame) {
                        return ControlFlow::Break;
                    }
                }
                CursorMoved { position, .. } => {
                    mouse_state.pos = position.into();
                    update_mouse(&mut imgui, &mut mouse_state);

                    if Instant::now() - last_frame < FRAME_DURATION {
                        return ControlFlow::Continue;
                    } else if !render(&mut model, &mut imgui, &mut last_frame) {
                        return ControlFlow::Break;
                    }
                }
                MouseWheel {
                    delta,
                    phase: TouchPhase::Moved,
                    ..
                } => {
                    mouse_state.wheel = match delta {
                        MouseScrollDelta::LineDelta(_, y) => y,
                        MouseScrollDelta::PixelDelta(position) => position.y as f32,
                    };
                    update_mouse(&mut imgui, &mut mouse_state);

                    if !render(&mut model, &mut imgui, &mut last_frame) {
                        return ControlFlow::Break;
                    }
                }
                MouseInput { state, button, .. } => {
                    if MouseButton::Left == button {
                        mouse_state.pressed.0 = state == Pressed;
                        update_mouse(&mut imgui, &mut mouse_state);

                        // Render twice to immediately show the results of the click
                        if !render(&mut model, &mut imgui, &mut last_frame) {
                            return ControlFlow::Break;
                        }
                        if !render(&mut model, &mut imgui, &mut last_frame) {
                            return ControlFlow::Break;
                        }
                    }
                }
                Touch(glutin::Touch {
                    phase, location, ..
                }) => {
                    mouse_state.pos = location.into();
                    mouse_state.pressed.0 =
                        phase == TouchPhase::Started || phase == TouchPhase::Moved;
                    update_mouse(&mut imgui, &mut mouse_state);

                    match phase {
                        TouchPhase::Moved => {
                            if Instant::now() - last_frame < FRAME_DURATION {
                                return ControlFlow::Continue;
                            } else if !render(&mut model, &mut imgui, &mut last_frame) {
                                return ControlFlow::Break;
                            }
                        }
                        _ => {
                            // Render twice to immediately show the results of the touch
                            if !render(&mut model, &mut imgui, &mut last_frame) {
                                return ControlFlow::Break;
                            }
                            if !render(&mut model, &mut imgui, &mut last_frame) {
                                return ControlFlow::Break;
                            }
                        }
                    }
                }
                _ => (),
            }
        }
        ControlFlow::Continue
    });
}

fn update_mouse(imgui: &mut ImGui, mouse_state: &mut MouseState) {
    let scale = imgui.display_framebuffer_scale();
    imgui.set_mouse_pos(
        mouse_state.pos.0 as f32 / scale.0,
        mouse_state.pos.1 as f32 / scale.1,
    );
    imgui.set_mouse_down([
        mouse_state.pressed.0,
        mouse_state.pressed.1,
        mouse_state.pressed.2,
        false,
        false,
    ]);
    imgui.set_mouse_wheel(mouse_state.wheel / scale.1);
    mouse_state.wheel = 0.0;
}
<|endoftext|>


<commit_before>use libc::*;

use std::ffi::{CString, CStr};
use std::ptr;

use xlib::{ Display, Pixmap, Window, XClassHint, XCreateSimpleWindow, XDefaultScreen, XDefaultScreenOfDisplay, XGetSelectionOwner, XID, XInternAtom, XOpenDisplay, XRootWindowOfScreen, XSetSelectionOwner, XSizeHints };
use x11::xrender::{ XRenderQueryExtension };
use x11::xlib::{ _XDisplay };

static XNone: u64 = 0;

//
// Xlib Types
//

#[repr(C)]
pub struct struct__XWMHints {
  pub flags: c_long,
  pub input: c_int,
  pub initial_state: c_int,
  pub icon_pixmap: Pixmap,
  pub icon_window: Window,
  pub icon_x: c_int,
  pub icon_y: c_int,
  pub icon_mask: Pixmap,
  pub window_group: XID,
}
pub type XWMHints = struct__XWMHints;

//
// Xlib & X Extensions Linking
//

#[link(name = "X11")]
extern {
  fn Xutf8SetWMProperties(display: *mut Display, window: Window, window_name: *mut c_char,
                          icon_name: *mut c_char, argv: *mut *mut c_char, argc: i32,
                          normal_hints: *mut XSizeHints, wm_hints: *mut XWMHints,
                          class_hints: *mut XClassHint);
}

#[link(name = "Xcomposite")]
extern {
  fn XCompositeQueryExtension(display: *mut Display, event: *mut i32, error: *mut i32) -> i32;
}

#[link(name = "Xdamage")]
extern {
  fn XDamageQueryExtension(display: *mut Display, event: *mut i32, error: *mut i32) -> i32;
}

#[link(name = "Xext")]
extern {
  fn XShapeQueryExtension(display: *mut Display, event: *mut i32, error: *mut i32) -> i32;
}

#[link(name = "Xfixes")]
extern {
  fn XFixesQueryExtension(display: *mut Display, event: *mut i32, error: *mut i32) -> i32;
}

//
// XServer Struct
//

pub struct XServer {
  display: *mut Display,
  root:         Window
}

impl XServer {
  pub fn new() -> XServer {
    unsafe {
      let display = XOpenDisplay(ptr::null_mut());
      if display.is_null() {
        panic!("Could not open display!");
      }

      let screen = XDefaultScreenOfDisplay(display);
      let root = XRootWindowOfScreen(screen);

      XServer {
        display: display,
        root: root
      }
    }
  }
}

pub fn query_extension(xserver: &XServer, name: &str) {
  let mut event_base = &mut 0;
  let mut error_base = &mut 0;

  unsafe {
    match name {
      "Xcomposite" => if XCompositeQueryExtension(xserver.display, event_base, error_base) == 0 {
                        panic!("No XComposite extension!");
                      },
      "Xdamage" => if XDamageQueryExtension(xserver.display, event_base, error_base) == 0 {
                     panic!("No XDamage extension!");
                   },
      "Xfixes" => if XFixesQueryExtension(xserver.display, event_base, error_base) == 0 {
                    panic!("No XFixes extension!");
                  },
      "Xrender" => { let have_xrender = XRenderQueryExtension(xserver.display as *mut _XDisplay,
                                                              event_base, error_base);
                     if  have_xrender == 0 {
                       panic!("No XRender extension!");
                     }
                   },
      "Xshape" => if XShapeQueryExtension(xserver.display, event_base, error_base) == 0 {
                    panic!("No XShape extension!");
                  },
      _ => panic!(format!("Don't know how to query for {} extension", name)),
    }
  }
}

pub struct WindowSettings {
  pub opacity: XID,
  pub type_atom: XID,
  pub is_desktop: XID,
  pub is_dock: XID,
  pub is_toolbar: XID,
  pub is_menu: XID,
  pub is_util: XID,
  pub is_splash: XID,
  pub is_dialog: XID,
  pub is_dropdown: XID,
  pub is_popup: XID,
  pub is_tooltip: XID,
  pub is_notification: XID,
  pub is_combo: XID,
  pub is_dnd: XID,
  pub is_normal: XID,
}

pub fn find_window_settings(xserver: &XServer) -> WindowSettings {
  WindowSettings {
    opacity: intern_atom(xserver, "_NET_WM_WINDOW_OPACITY"),
    type_atom: intern_atom(xserver, "_NET_WM_WINDOW_TYPE"),

    is_desktop: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_DESKTOP"),
    is_dock: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_DOCK"),
    is_toolbar: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_TOOLBAR"),
    is_menu: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_MENU"),
    is_util: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_UTILITY"),
    is_splash: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_SPLASH"),
    is_dialog: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_DIALOG"),
    is_dropdown: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_DROPDOWN"),
    is_popup: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_POPUP"),
    is_tooltip: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_TOOLTIP"),
    is_notification: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_NOTIFICATION"),
    is_combo: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_COMBO"),
    is_dnd: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_DND"),
    is_normal: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_NORMAL"),
  }
}

pub fn intern_atom(xserver: &XServer, name: &str) -> XID {
  return unsafe { XInternAtom(xserver.display, name.as_ptr() as *mut c_char, 0) };
}

pub fn register_compositing_window_manager(xserver: &XServer, wm_name: &CStr) -> bool {
  let screen = unsafe { XDefaultScreen(xserver.display) };
  let reg_atom_name = CString::new(format!("_NET_WM_CM_S{}", screen)).unwrap();
  let reg_atom = unsafe { XInternAtom(xserver.display, reg_atom_name.as_ptr() as *mut c_char, 0) };
  let extant_window = unsafe { XGetSelectionOwner(xserver.display, reg_atom) };

  if extant_window != XNone {
    return false;
  }

  unsafe {
    let our_window = XCreateSimpleWindow(xserver.display, xserver.root,
                                         0, 0, 1, 1, 0, XNone, XNone);
    Xutf8SetWMProperties(xserver.display, our_window,
                         wm_name.as_ptr() as *mut c_char, wm_name.as_ptr() as *mut c_char,
                         ptr::null_mut(), 0, ptr::null_mut(), ptr::null_mut(), ptr::null_mut());
    XSetSelectionOwner(xserver.display, reg_atom, our_window, 0);
  };

  return true;
}
<commit_msg>Add fn to return "null" Xrender pic attrs.<commit_after>use libc::*;

use std::ffi::{CString, CStr};
use std::ptr;

use xlib::{ Display, Pixmap, Window, XClassHint, XCreateSimpleWindow, XDefaultScreen, XDefaultScreenOfDisplay, XGetSelectionOwner, XID, XInternAtom, XOpenDisplay, XRootWindowOfScreen, XSetSelectionOwner, XSizeHints };
use x11::xrender::{ XRenderCreatePicture, XRenderFindVisualFormat, XRenderPictureAttributes, XRenderQueryExtension };
use x11::xlib::{ _XDisplay, XDefaultVisual };

static XNone: u64 = 0;

//
// Xlib Types
//

#[repr(C)]
pub struct struct__XWMHints {
  pub flags: c_long,
  pub input: c_int,
  pub initial_state: c_int,
  pub icon_pixmap: Pixmap,
  pub icon_window: Window,
  pub icon_x: c_int,
  pub icon_y: c_int,
  pub icon_mask: Pixmap,
  pub window_group: XID,
}
pub type XWMHints = struct__XWMHints;

//
// Xlib & X Extensions Linking
//

#[link(name = "X11")]
extern {
  fn Xutf8SetWMProperties(display: *mut Display, window: Window, window_name: *mut c_char,
                          icon_name: *mut c_char, argv: *mut *mut c_char, argc: i32,
                          normal_hints: *mut XSizeHints, wm_hints: *mut XWMHints,
                          class_hints: *mut XClassHint);
}

#[link(name = "Xcomposite")]
extern {
  fn XCompositeQueryExtension(display: *mut Display, event: *mut i32, error: *mut i32) -> i32;
}

#[link(name = "Xdamage")]
extern {
  fn XDamageQueryExtension(display: *mut Display, event: *mut i32, error: *mut i32) -> i32;
}

#[link(name = "Xext")]
extern {
  fn XShapeQueryExtension(display: *mut Display, event: *mut i32, error: *mut i32) -> i32;
}

#[link(name = "Xfixes")]
extern {
  fn XFixesQueryExtension(display: *mut Display, event: *mut i32, error: *mut i32) -> i32;
}

//
// XServer Struct
//

pub struct XServer {
  display: *mut Display,
  root:         Window
}

impl XServer {
  pub fn new() -> XServer {
    unsafe {
      let display = XOpenDisplay(ptr::null_mut());
      if display.is_null() {
        panic!("Could not open display!");
      }

      let screen = XDefaultScreenOfDisplay(display);
      let root = XRootWindowOfScreen(screen);

      XServer {
        display: display,
        root: root
      }
    }
  }
}

pub fn query_extension(xserver: &XServer, name: &str) {
  let mut event_base = &mut 0;
  let mut error_base = &mut 0;

  unsafe {
    match name {
      "Xcomposite" => if XCompositeQueryExtension(xserver.display, event_base, error_base) == 0 {
                        panic!("No XComposite extension!");
                      },
      "Xdamage" => if XDamageQueryExtension(xserver.display, event_base, error_base) == 0 {
                     panic!("No XDamage extension!");
                   },
      "Xfixes" => if XFixesQueryExtension(xserver.display, event_base, error_base) == 0 {
                    panic!("No XFixes extension!");
                  },
      "Xrender" => { let have_xrender = XRenderQueryExtension(xserver.display as *mut _XDisplay,
                                                              event_base, error_base);
                     if  have_xrender == 0 {
                       panic!("No XRender extension!");
                     }
                   },
      "Xshape" => if XShapeQueryExtension(xserver.display, event_base, error_base) == 0 {
                    panic!("No XShape extension!");
                  },
      _ => panic!(format!("Don't know how to query for {} extension", name)),
    }
  }
}

pub struct WindowSettings {
  pub opacity: XID,
  pub type_atom: XID,
  pub is_desktop: XID,
  pub is_dock: XID,
  pub is_toolbar: XID,
  pub is_menu: XID,
  pub is_util: XID,
  pub is_splash: XID,
  pub is_dialog: XID,
  pub is_dropdown: XID,
  pub is_popup: XID,
  pub is_tooltip: XID,
  pub is_notification: XID,
  pub is_combo: XID,
  pub is_dnd: XID,
  pub is_normal: XID,
}

pub fn find_window_settings(xserver: &XServer) -> WindowSettings {
  WindowSettings {
    opacity: intern_atom(xserver, "_NET_WM_WINDOW_OPACITY"),
    type_atom: intern_atom(xserver, "_NET_WM_WINDOW_TYPE"),

    is_desktop: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_DESKTOP"),
    is_dock: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_DOCK"),
    is_toolbar: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_TOOLBAR"),
    is_menu: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_MENU"),
    is_util: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_UTILITY"),
    is_splash: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_SPLASH"),
    is_dialog: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_DIALOG"),
    is_dropdown: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_DROPDOWN"),
    is_popup: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_POPUP"),
    is_tooltip: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_TOOLTIP"),
    is_notification: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_NOTIFICATION"),
    is_combo: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_COMBO"),
    is_dnd: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_DND"),
    is_normal: intern_atom(xserver, "_NET_WM_WINDOW_TYPE_NORMAL"),
  }
}

pub fn intern_atom(xserver: &XServer, name: &str) -> XID {
  return unsafe { XInternAtom(xserver.display, name.as_ptr() as *mut c_char, 0) };
}

pub fn null_xrender_picture_attributes() -> XRenderPictureAttributes {
  return XRenderPictureAttributes {
    repeat: 0,
    alpha_map: XNone,
    alpha_x_origin: 0,
    alpha_y_origin: 0,
    clip_x_origin: 0,
    clip_y_origin: 0,
    clip_mask: XNone,
    graphics_exposures: 0,
    subwindow_mode: 0,
    poly_edge: 0,
    poly_mode: 0,
    dither: XNone,
    component_alpha: 0,
  }
}

pub fn register_compositing_window_manager(xserver: &XServer, wm_name: &CStr) -> bool {
  let screen = unsafe { XDefaultScreen(xserver.display) };
  let reg_atom_name = CString::new(format!("_NET_WM_CM_S{}", screen)).unwrap();
  let reg_atom = unsafe { XInternAtom(xserver.display, reg_atom_name.as_ptr() as *mut c_char, 0) };
  let extant_window = unsafe { XGetSelectionOwner(xserver.display, reg_atom) };

  if extant_window != XNone {
    return false;
  }

  unsafe {
    let our_window = XCreateSimpleWindow(xserver.display, xserver.root,
                                         0, 0, 1, 1, 0, XNone, XNone);
    Xutf8SetWMProperties(xserver.display, our_window,
                         wm_name.as_ptr() as *mut c_char, wm_name.as_ptr() as *mut c_char,
                         ptr::null_mut(), 0, ptr::null_mut(), ptr::null_mut(), ptr::null_mut());
    XSetSelectionOwner(xserver.display, reg_atom, our_window, 0);
  };

  return true;
}
<|endoftext|>


<commit_before>use flowgger::config::Config;
use openssl::bn::BigNum;
use openssl::dh::DH;
use openssl::ssl::*;
use openssl::x509::X509FileType;
use std::path::{Path, PathBuf};
use std::sync::Arc;

pub mod tls_input;
#[cfg(feature = "coroutines")]
pub mod tlsco_input;

pub use super::Input;

const DEFAULT_CERT: &'static str = "flowgger.pem";
const DEFAULT_CIPHERS: &'static str = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA";
const DEFAULT_FRAMING: &'static str = "line";
const DEFAULT_KEY: &'static str = "flowgger.pem";
const DEFAULT_LISTEN: &'static str = "0.0.0.0:6514";
#[cfg(feature = "coroutines")]
const DEFAULT_THREADS: usize = 1;
const DEFAULT_TIMEOUT: u64 = 3600;
const DEFAULT_TLS_METHOD: &'static str = "TLSv1.2";
const DEFAULT_VERIFY_PEER: bool = false;
const DEFAULT_COMPRESSION: bool = false;
const TLS_VERIFY_DEPTH: u32 = 6;

#[derive(Clone)]
pub struct TlsConfig {
    framing: String,
    threads: usize,
    arc_ctx: Arc<SslContext>
}

#[cfg(feature = "ecdh")]
fn set_ecdh(ctx: &mut SslContext) {
    ctx.set_ecdh_auto(true).unwrap();
}

#[cfg(not(feature = "ecdh"))]
fn set_ecdh(ctx: &mut SslContext) {
    let _ = ctx;
}

fn set_fs(ctx: &mut SslContext) {
    let p = BigNum::from_hex_str("87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C022E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C4FDB70C581B23F76B63ACAE1CAA6B7902D52526735488A0EF13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5140564251CCACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE621C3A3960A54E710C375F26375D7014103A4B54330C198AF126116D2276E11715F693877FAD7EF09CADB094AE91E1A1597").unwrap();
    let g = BigNum::from_hex_str("3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0BA12510DBC15077BE463FFF4FED4AAC0BB555BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A57F2DDF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC831D14348F6F2F9193B5045AF2767164E1DFC967C1FB3F2E55A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E052588B9B7D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92B52C7891428CDC67EB6184B523D1DB246C32F63078490F00EF8D647D148D47954515E2327CFEF98C582664B4C0F6CC41659").unwrap();
    let q = BigNum::from_hex_str("8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F5FBD3").unwrap();
    let dh = DH::from_params(p, g, q).unwrap();
    ctx.set_tmp_dh(dh).unwrap();
    set_ecdh(ctx);
}

#[cfg(feature = "coroutines")]
fn get_default_threads(config: &Config) -> usize {
    config.lookup("input.tls_threads").map_or(DEFAULT_THREADS, |x| x.as_integer().
        expect("input.tls_threads must be an unsigned integer") as usize)
}

#[cfg(not(feature = "coroutines"))]
fn get_default_threads(_config: &Config) -> usize {
    1
}

pub fn config_parse(config: &Config) -> (TlsConfig, String, u64) {
    let listen = config.lookup("input.listen").map_or(DEFAULT_LISTEN, |x| x.as_str().
        expect("input.listen must be an ip:port string")).to_owned();
    let threads = get_default_threads(&config);
    let cert = config.lookup("input.tls_cert").map_or(DEFAULT_CERT, |x| x.as_str().
        expect("input.tls_cert must be a path to a .pem file")).to_owned();
    let key = config.lookup("input.tls_key").map_or(DEFAULT_KEY, |x| x.as_str().
        expect("input.tls_key must be a path to a .pem file")).to_owned();
    let ciphers = config.lookup("input.tls_ciphers").map_or(DEFAULT_CIPHERS, |x| x.as_str().
        expect("input.tls_ciphers must be a string with a cipher suite")).to_owned();
    let tls_method = match config.lookup("input.tls_method").map_or(DEFAULT_TLS_METHOD, |x| x.as_str().
        expect("input.tls_method must be a string with the TLS method")).to_lowercase().as_ref() {
            "tlsv1" | "tlsv1.0" => SslMethod::Tlsv1,
            "tlsv1.1" => SslMethod::Tlsv1_1,
            "tlsv1.2" => SslMethod::Tlsv1_2,
            _ => panic!(r#"TLS method must be "TLSv1.0", "TLSv1.1" or "TLSv1.2""#)
    };
    let verify_peer = config.lookup("input.tls_verify_peer").map_or(DEFAULT_VERIFY_PEER, |x| x.as_bool().
        expect("input.tls_verify_peer must be a boolean"));
    let ca_file: Option<PathBuf> = config.lookup("input.tls_ca_file").map_or(None, |x|
        Some(PathBuf::from(x.as_str().expect("input.tls_ca_file must be a path to a file"))));
    let compression = config.lookup("input.tls_compression").map_or(DEFAULT_COMPRESSION, |x| x.as_bool().
        expect("input.tls_compression must be a boolean"));
    let timeout = config.lookup("input.timeout").map_or(DEFAULT_TIMEOUT, |x| x.as_integer().
        expect("input.timeout must be an integer") as u64);
    let framing = if config.lookup("input.framed").map_or(false, |x| x.as_bool().
        expect("input.framed must be a boolean")) {
        "syslen"
    } else {
        DEFAULT_FRAMING
    };
    let framing = config.lookup("input.framing").map_or(framing, |x| x.as_str().
        expect(r#"input.framing must be a string set to "line", "nul" or "syslen""#)).to_owned();
    let mut ctx = SslContext::new(tls_method).unwrap();
    if verify_peer == false {
        ctx.set_verify(SSL_VERIFY_NONE, None);
    } else {
        ctx.set_verify_depth(TLS_VERIFY_DEPTH);
        ctx.set_verify(SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, None);
        if let Some(ca_file) = ca_file {
            if ctx.set_CA_file(&ca_file).is_err() {
                panic!("Unable to read the trusted CA file");
            }
        }
    }
    let mut opts = SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION;
    if compression == false {
        opts = opts | SSL_OP_NO_COMPRESSION;
    }
    ctx.set_options(opts);
    set_fs(&mut ctx);
    ctx.set_certificate_file(&Path::new(&cert), X509FileType::PEM).unwrap();
    ctx.set_private_key_file(&Path::new(&key), X509FileType::PEM).unwrap();
    ctx.set_cipher_list(&ciphers).unwrap();
    let arc_ctx = Arc::new(ctx);
    let tls_config = TlsConfig {
        framing: framing,
        threads: threads,
        arc_ctx: arc_ctx
    };
    (tls_config, listen, timeout)
}
<commit_msg>Keep supporting "SSLv23" even if it now only means TLSv1.<commit_after>use flowgger::config::Config;
use openssl::bn::BigNum;
use openssl::dh::DH;
use openssl::ssl::*;
use openssl::x509::X509FileType;
use std::path::{Path, PathBuf};
use std::sync::Arc;

pub mod tls_input;
#[cfg(feature = "coroutines")]
pub mod tlsco_input;

pub use super::Input;

const DEFAULT_CERT: &'static str = "flowgger.pem";
const DEFAULT_CIPHERS: &'static str = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA";
const DEFAULT_FRAMING: &'static str = "line";
const DEFAULT_KEY: &'static str = "flowgger.pem";
const DEFAULT_LISTEN: &'static str = "0.0.0.0:6514";
#[cfg(feature = "coroutines")]
const DEFAULT_THREADS: usize = 1;
const DEFAULT_TIMEOUT: u64 = 3600;
const DEFAULT_TLS_METHOD: &'static str = "TLSv1.2";
const DEFAULT_VERIFY_PEER: bool = false;
const DEFAULT_COMPRESSION: bool = false;
const TLS_VERIFY_DEPTH: u32 = 6;

#[derive(Clone)]
pub struct TlsConfig {
    framing: String,
    threads: usize,
    arc_ctx: Arc<SslContext>
}

#[cfg(feature = "ecdh")]
fn set_ecdh(ctx: &mut SslContext) {
    ctx.set_ecdh_auto(true).unwrap();
}

#[cfg(not(feature = "ecdh"))]
fn set_ecdh(ctx: &mut SslContext) {
    let _ = ctx;
}

fn set_fs(ctx: &mut SslContext) {
    let p = BigNum::from_hex_str("87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C022E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C4FDB70C581B23F76B63ACAE1CAA6B7902D52526735488A0EF13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5140564251CCACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE621C3A3960A54E710C375F26375D7014103A4B54330C198AF126116D2276E11715F693877FAD7EF09CADB094AE91E1A1597").unwrap();
    let g = BigNum::from_hex_str("3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0BA12510DBC15077BE463FFF4FED4AAC0BB555BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A57F2DDF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC831D14348F6F2F9193B5045AF2767164E1DFC967C1FB3F2E55A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E052588B9B7D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92B52C7891428CDC67EB6184B523D1DB246C32F63078490F00EF8D647D148D47954515E2327CFEF98C582664B4C0F6CC41659").unwrap();
    let q = BigNum::from_hex_str("8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F5FBD3").unwrap();
    let dh = DH::from_params(p, g, q).unwrap();
    ctx.set_tmp_dh(dh).unwrap();
    set_ecdh(ctx);
}

#[cfg(feature = "coroutines")]
fn get_default_threads(config: &Config) -> usize {
    config.lookup("input.tls_threads").map_or(DEFAULT_THREADS, |x| x.as_integer().
        expect("input.tls_threads must be an unsigned integer") as usize)
}

#[cfg(not(feature = "coroutines"))]
fn get_default_threads(_config: &Config) -> usize {
    1
}

pub fn config_parse(config: &Config) -> (TlsConfig, String, u64) {
    let listen = config.lookup("input.listen").map_or(DEFAULT_LISTEN, |x| x.as_str().
        expect("input.listen must be an ip:port string")).to_owned();
    let threads = get_default_threads(&config);
    let cert = config.lookup("input.tls_cert").map_or(DEFAULT_CERT, |x| x.as_str().
        expect("input.tls_cert must be a path to a .pem file")).to_owned();
    let key = config.lookup("input.tls_key").map_or(DEFAULT_KEY, |x| x.as_str().
        expect("input.tls_key must be a path to a .pem file")).to_owned();
    let ciphers = config.lookup("input.tls_ciphers").map_or(DEFAULT_CIPHERS, |x| x.as_str().
        expect("input.tls_ciphers must be a string with a cipher suite")).to_owned();
    let tls_method = match config.lookup("input.tls_method").map_or(DEFAULT_TLS_METHOD, |x| x.as_str().
        expect("input.tls_method must be a string with the TLS method")).to_lowercase().as_ref() {
            "sslv23" => SslMethod::Sslv23,
            "tlsv1" | "tlsv1.0" => SslMethod::Tlsv1,
            "tlsv1.1" => SslMethod::Tlsv1_1,
            "tlsv1.2" => SslMethod::Tlsv1_2,
            _ => panic!(r#"TLS method must be "SSLv23", "TLSv1.0", "TLSv1.1" or "TLSv1.2""#)
    };
    let verify_peer = config.lookup("input.tls_verify_peer").map_or(DEFAULT_VERIFY_PEER, |x| x.as_bool().
        expect("input.tls_verify_peer must be a boolean"));
    let ca_file: Option<PathBuf> = config.lookup("input.tls_ca_file").map_or(None, |x|
        Some(PathBuf::from(x.as_str().expect("input.tls_ca_file must be a path to a file"))));
    let compression = config.lookup("input.tls_compression").map_or(DEFAULT_COMPRESSION, |x| x.as_bool().
        expect("input.tls_compression must be a boolean"));
    let timeout = config.lookup("input.timeout").map_or(DEFAULT_TIMEOUT, |x| x.as_integer().
        expect("input.timeout must be an integer") as u64);
    let framing = if config.lookup("input.framed").map_or(false, |x| x.as_bool().
        expect("input.framed must be a boolean")) {
        "syslen"
    } else {
        DEFAULT_FRAMING
    };
    let framing = config.lookup("input.framing").map_or(framing, |x| x.as_str().
        expect(r#"input.framing must be a string set to "line", "nul" or "syslen""#)).to_owned();
    let mut ctx = SslContext::new(tls_method).unwrap();
    if verify_peer == false {
        ctx.set_verify(SSL_VERIFY_NONE, None);
    } else {
        ctx.set_verify_depth(TLS_VERIFY_DEPTH);
        ctx.set_verify(SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, None);
        if let Some(ca_file) = ca_file {
            if ctx.set_CA_file(&ca_file).is_err() {
                panic!("Unable to read the trusted CA file");
            }
        }
    }
    let mut opts = SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION;
    if compression == false {
        opts = opts | SSL_OP_NO_COMPRESSION;
    }
    ctx.set_options(opts);
    set_fs(&mut ctx);
    ctx.set_certificate_file(&Path::new(&cert), X509FileType::PEM).unwrap();
    ctx.set_private_key_file(&Path::new(&key), X509FileType::PEM).unwrap();
    ctx.set_cipher_list(&ciphers).unwrap();
    let arc_ctx = Arc::new(ctx);
    let tls_config = TlsConfig {
        framing: framing,
        threads: threads,
        arc_ctx: arc_ctx
    };
    (tls_config, listen, timeout)
}
<|endoftext|>


<commit_before>use std::rc::Rc;

use dces::prelude::Entity;

use crate::{css_engine::*, event::EventHandler};

pub use self::build_context::*;
pub use self::context::*;
pub use self::message::*;
pub use self::registry::*;
pub use self::state::*;
pub use self::states_context::*;
pub use self::template::*;
pub use self::widget_container::*;

mod build_context;
mod context;
mod message;
mod registry;
mod state;
mod states_context;
mod template;
mod widget_container;

/// Adds the given `pseudo_class` to the css selector of the given `widget`.
pub fn add_selector_to_widget(pseudo_class: &str, widget: &mut WidgetContainer<'_>) {
    if let Some(selector) = widget.try_get_mut::<Selector>("selector") {
        selector.pseudo_classes.insert(String::from(pseudo_class));
        selector.set_dirty(true);
    }
}

/// Removes the given `pseudo_class` from the css selector of the given `widget`.
pub fn remove_selector_from_widget(pseudo_class: &str, widget: &mut WidgetContainer<'_>) {
    if let Some(selector) = widget.try_get_mut::<Selector>("selector") {
        selector.pseudo_classes.remove(pseudo_class);
        selector.set_dirty(true);
    }
}

/// Used to define the `parent_type`of a widget.
pub enum ParentType {
    /// None children could add to the widget.
    None,

    /// Only one child could be added to the widget.
    Single,

    /// Multiple children could be added tot the widget.
    Multi,
}

/// The `Widget` trait is used to define a new widget.
pub trait Widget: Template {
    /// Creates a new widget.
    fn create() -> Self;

    /// Builds the widget and returns the template of the widget.
    fn build(self, ctx: &mut BuildContext) -> Entity;

    /// Inerts a new event handler.
    fn insert_handler(self, handler: impl Into<Rc<dyn EventHandler>>) -> Self;

    /// Appends a child ot the widget.
    fn child(self, child: Entity) -> Self;
}
<commit_msg>Fixed typos in doc comments<commit_after>use std::rc::Rc;

use dces::prelude::Entity;

use crate::{css_engine::*, event::EventHandler};

pub use self::build_context::*;
pub use self::context::*;
pub use self::message::*;
pub use self::registry::*;
pub use self::state::*;
pub use self::states_context::*;
pub use self::template::*;
pub use self::widget_container::*;

mod build_context;
mod context;
mod message;
mod registry;
mod state;
mod states_context;
mod template;
mod widget_container;

/// Adds the given `pseudo_class` to the css selector of the given `widget`.
pub fn add_selector_to_widget(pseudo_class: &str, widget: &mut WidgetContainer<'_>) {
    if let Some(selector) = widget.try_get_mut::<Selector>("selector") {
        selector.pseudo_classes.insert(String::from(pseudo_class));
        selector.set_dirty(true);
    }
}

/// Removes the given `pseudo_class` from the css selector of the given `widget`.
pub fn remove_selector_from_widget(pseudo_class: &str, widget: &mut WidgetContainer<'_>) {
    if let Some(selector) = widget.try_get_mut::<Selector>("selector") {
        selector.pseudo_classes.remove(pseudo_class);
        selector.set_dirty(true);
    }
}

/// Used to define the `parent_type`of a widget.
pub enum ParentType {
    /// None children could add to the widget.
    None,

    /// Only one child could be added to the widget.
    Single,

    /// Multiple children could be added to the widget.
    Multi,
}

/// The `Widget` trait is used to define a new widget.
pub trait Widget: Template {
    /// Creates a new widget.
    fn create() -> Self;

    /// Builds the widget and returns the template of the widget.
    fn build(self, ctx: &mut BuildContext) -> Entity;

    /// Inerts a new event handler.
    fn insert_handler(self, handler: impl Into<Rc<dyn EventHandler>>) -> Self;

    /// Appends a child to the widget.
    fn child(self, child: Entity) -> Self;
}
<|endoftext|>


<commit_before>use crate::prelude::*;
// CanvasState
// updates the ThreeObject property

widget!(
    /// Canvas is used to render 3D graphics.
    Canvas {
        /// Sets or shares the three render pipeline.
        render_pipeline: RenderPipeline
    }
);

impl Template for Canvas {
    fn template(self, _: Entity, _: &mut BuildContext) -> Self {
        self.name("Canvas").element("canvas-three")
    }

    fn render_object(&self) -> Box<dyn RenderObject> {
        Box::new(PipelineRenderObject)
    }
}
<commit_msg>Removed dangling comment, fixed docs<commit_after>use crate::prelude::*;

widget!(
    /// Canvas is used to render 3D graphics.
    Canvas {
        /// Sets or shares the render pipeline.
        render_pipeline: RenderPipeline
    }
);

impl Template for Canvas {
    fn template(self, _: Entity, _: &mut BuildContext) -> Self {
        self.name("Canvas").element("canvas-three")
    }

    fn render_object(&self) -> Box<dyn RenderObject> {
        Box::new(PipelineRenderObject)
    }
}
<|endoftext|>


<commit_before>use std::fs::{File, OpenOptions};
use std::io::Result;

pub struct Terminal {
    file: File
}

impl Terminal {
    pub fn from(filename: &str) -> Result<Terminal> {
        let file = OpenOptions::new().write(true).read(true).open(filename)?;

        let terminal = Terminal {
            file: file
        };

        Ok(terminal)
    }
}
<commit_msg>Implement Read/Write for Terminal<commit_after>use std::fs::{File, OpenOptions};
use std::io::{self, Write, Read, Result};

pub struct Terminal {
    file: File
}

impl Terminal {
    /// Creates a new Terminal from the provided filename
    pub fn from(filename: &str) -> Result<Terminal> {
        let file = OpenOptions::new().write(true).read(true).open(filename)?;

        let terminal = Terminal {
            file: file
        };

        Ok(terminal)
    }
}

impl Read for Terminal {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        self.file.read(buf)
    }
}

impl Write for Terminal {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        self.file.write(buf)
    }

    fn flush(&mut self) -> Result<()> {
        self.file.flush()
    }
}
<|endoftext|>