<commit_before>// See LICENSE file for copyright and license details.

// Marauder is grid-less turn-based strategy game.

extern mod glfw;
extern mod gl;
extern mod cgmath;

use gl::types::{
  GLenum,
  GLuint,
  GLint,
  GLchar,
  GLfloat,
  GLsizeiptr,
  GLboolean
};
use cgmath::matrix::{Matrix, Mat4, Mat3, ToMat4};
use cgmath::projection;
use cgmath::angle;
use cgmath::vector::{Vec3, Vec2};

#[link(name = "glfw")]
#[link(name = "m")]
extern {}

/// usage: let s = mvp_matrix; println(type_of(&s));
fn type_of<T>(_: &T) -> &'static str {
  unsafe {
    (*std::unstable::intrinsics::get_tydesc::<T>()).name
  }
}

fn print_mat4(name: &str, mat: Mat4<f32>) {
  println!("{}:", name);
  for i in range(0u, 4) {
    for j in range(0u, 4) {
      print!("{} ", *mat.cr(i, j));
    }
    println("");
  }
  println("");
}

static mut MOUSE_POS: Vec2<f32> = Vec2{x: 0.0f32, y: 0.0};
static mut CAMERA_POS: Vec3<f32> = Vec3{x: 0.0f32, y: 0.0, z: 0.0};

static WIN_SIZE: Vec2<uint> = Vec2{x: 640, y: 480};
static VERTICES_COUNT: i32 = 3 * 2;

static VERTEX_DATA: [GLfloat, ..VERTICES_COUNT * 3] = [
   0.0,  1.0, 0.0,
   2.0, -1.0, 0.0,
  -2.0, -1.0, 0.0,

  0.0,  1.0,  0.0,
  0.0, -1.0,  2.0,
  0.0, -1.0, -2.0
];

static VERTEX_SHADER_SRC: &'static str = "
  #version 130
  in vec3 position;
  uniform mat4 model_view_proj_matrix;
  void main() {
    vec4 v = vec4(position, 1);
    gl_Position = model_view_proj_matrix * v;
  }
";

static FRAGMENT_SHADER_SRC: &'static str = "
  #version 130
  out vec4 out_color;
  void main() {
    out_color = vec4(1.0, 1.0, 1.0, 1.0);
  }
";

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
  let shader = gl::CreateShader(ty);
  unsafe {
    // Attempt to compile the shader
    gl::ShaderSource(shader, 1, &src.to_c_str().unwrap(), std::ptr::null());
    gl::CompileShader(shader);

    // Get the compile status
    let mut status = gl::FALSE as GLint;
    gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len = 0;
      gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
      // subtract 1 to skip the trailing null character
      let mut buf = std::vec::from_elem(len as uint - 1, 0u8);
      gl::GetShaderInfoLog(shader, len, std::ptr::mut_null(),
        std::vec::raw::to_mut_ptr(buf) as *mut GLchar
      );
      fail!("compile_shader(): " + std::str::raw::from_utf8(buf));
    }
  }
  shader
}

fn link_program(vertex_shader: GLuint, fragment_shader: GLuint) -> GLuint {
  let program = gl::CreateProgram();
  gl::AttachShader(program, vertex_shader);
  gl::AttachShader(program, fragment_shader);
  gl::LinkProgram(program);
  unsafe {
    // Get the link status
    let mut status = gl::FALSE as GLint;
    gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len: GLint = 0;
      gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
      // subtract 1 to skip the trailing null character
      let mut buf = std::vec::from_elem(len as uint - 1, 0u8);
      gl::GetProgramInfoLog(program, len, std::ptr::mut_null(),
        std::vec::raw::to_mut_ptr(buf) as *mut GLchar
      );
      fail!("link_program(): " + std::str::raw::from_utf8(buf));
    }
  }
  program
}

fn tr(m: Mat4<f32>, v: Vec3<f32>) -> Mat4<f32> {
  let mut t = Mat4::<f32>::identity();
  *t.mut_cr(3, 0) = v.x;
  *t.mut_cr(3, 1) = v.y;
  *t.mut_cr(3, 2) = v.z;
  m.mul_m(&t)
}

fn rot_x(m: Mat4<f32>, angle: f32) -> Mat4<f32> {
  let r = Mat3::from_angle_x(angle::rad(angle)).to_mat4();
  m.mul_m(&r)
}

fn rot_y(m: Mat4<f32>, angle: f32) -> Mat4<f32> {
  let r = Mat3::from_angle_y(angle::rad(angle)).to_mat4();
  m.mul_m(&r)
}

// change matrices
fn upd(programId: GLuint) {
  let fov = angle::deg(45.0f32);
  let ratio = 4.0 / 3.0;
  let display_range_min = 0.1;
  let display_range_max = 100.0;
  let projection_matrix = projection::perspective(
    fov, ratio, display_range_min, display_range_max
  );

  let mut mvp_matrix = projection_matrix;
  unsafe {
    mvp_matrix = tr(mvp_matrix, Vec3{x: 0.0f32, y: 0.0, z: -10.0f32});
    mvp_matrix = rot_x(mvp_matrix, MOUSE_POS.y / 100.0);
    mvp_matrix = rot_y(mvp_matrix, MOUSE_POS.x / 100.0);
    mvp_matrix = tr(mvp_matrix, CAMERA_POS);
  }

  unsafe {
    // Get a handle for our "model_view_proj_matrix" uniform.
    // Only at initialisation time.
    let matrixId = gl::GetUniformLocation(
      programId, "model_view_proj_matrix".to_c_str().unwrap());

    // Send our transformation to the currently bound shader,
    // in the "model_view_proj_matrix" uniform.
    // For each model you render, since the model_view_proj_matrix
    // will be different (at least the M part).
    gl::UniformMatrix4fv(matrixId, 1, gl::FALSE, mvp_matrix.cr(0, 0));
  }
}

struct Win {
  vertex_shader: GLuint,
  fragment_shader: GLuint,
  program: GLuint,
  vertex_array_obj: GLuint,
  vertex_buffer_obj: GLuint,
  window: glfw::Window
}

impl Win {
  fn new() -> Win {
    let mut win =  Win{
      vertex_shader: 0,
      fragment_shader: 0,
      program: 0,
      vertex_array_obj: 0,
      vertex_buffer_obj: 0,
      window: glfw::Window::create(
        WIN_SIZE.x,
        WIN_SIZE.y,
        "OpenGL",
        glfw::Windowed
      ).unwrap()
    };

    win.window.make_context_current();
    win.window.set_cursor_pos_callback(~CursorPosContext);
    win.window.set_key_callback(~KeyContext);

    // Load the OpenGL function pointers
    gl::load_with(glfw::get_proc_address);

    // Create GLSL shaders
    win.vertex_shader = compile_shader(
      VERTEX_SHADER_SRC, gl::VERTEX_SHADER);
    win.fragment_shader = compile_shader(
      FRAGMENT_SHADER_SRC, gl::FRAGMENT_SHADER);
    win.program = link_program(win.vertex_shader, win.fragment_shader);

    unsafe {
      // Create Vertex Array Object
      gl::GenVertexArrays(1, &mut win.vertex_array_obj);
      gl::BindVertexArray(win.vertex_array_obj);

      // Create a Vertex Buffer Object and copy the vertex data to it
      gl::GenBuffers(1, &mut win.vertex_buffer_obj);
      gl::BindBuffer(gl::ARRAY_BUFFER, win.vertex_buffer_obj);
      let float_size = std::mem::size_of::<GLfloat>();
      let vertices_ptr = (VERTEX_DATA.len() * float_size) as GLsizeiptr;
      gl::BufferData(
        gl::ARRAY_BUFFER,
        vertices_ptr,
        std::cast::transmute(&VERTEX_DATA[0]),
        gl::STATIC_DRAW
      );

      gl::UseProgram(win.program);
      gl::BindFragDataLocation(win.program, 0, "out_color".to_c_str().unwrap());

      // Specify the layout of the vertex data
      let pos_attr = gl::GetAttribLocation(
        win.program, "position".to_c_str().unwrap()) as GLuint;
      gl::EnableVertexAttribArray(pos_attr);
      let size = 3;
      let normalized = gl::FALSE as GLboolean;
      let stride = 0;
      gl::VertexAttribPointer(
        pos_attr,
        size,
        gl::FLOAT,
        normalized,
        stride,
        std::ptr::null()
      );
    }

    win
  }

  fn cleanup(&self) {
    // Cleanup
    gl::DeleteProgram(self.program);
    gl::DeleteShader(self.fragment_shader);
    gl::DeleteShader(self.vertex_shader);
    unsafe {
      gl::DeleteBuffers(1, &self.vertex_buffer_obj);
      gl::DeleteVertexArrays(1, &self.vertex_array_obj);
    }
  }

  fn draw(&self) {
    upd(self.program);

    // Clear the screen to black
    gl::ClearColor(0.3, 0.3, 0.3, 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT);

    // Draw a triangle from the 3 vertices
    gl::DrawArrays(gl::TRIANGLES, 0, VERTICES_COUNT);

    self.window.swap_buffers();
  }

  fn is_running(&self) -> bool {
    return !self.window.should_close()
  }

  fn process_events(&self) {
    glfw::poll_events();
  }
}

struct CursorPosContext;
impl glfw::CursorPosCallback for CursorPosContext {
  fn call(&self, w: &glfw::Window, xpos: f64, ypos: f64) {
    if w.get_mouse_button(glfw::MouseButtonRight) == glfw::Press {
      // println!("Cursor position: ({}, {})", xpos, ypos);
      unsafe {
        MOUSE_POS.x = xpos as f32;
        MOUSE_POS.y = ypos as f32;
      }
    }
  }
}

struct ErrorContext;
impl glfw::ErrorCallback for ErrorContext {
  fn call(&self, _: glfw::Error, description: ~str) {
    println!("GLFW Error: {:s}", description);
  }
}

struct KeyContext;
impl glfw::KeyCallback for KeyContext {
  fn call(
    &self,
    window: &glfw::Window,
    key:    glfw::Key,
    _:      std::libc::c_int,
    action: glfw::Action,
    _:      glfw::Modifiers
  ) {
    match (action, key) {
      (glfw::Press, glfw::KeyEscape) => {
        window.set_should_close(true)
      }
      (glfw::Press, glfw::KeySpace) => {
        println!("space")
      }
      (glfw::Press, glfw::KeyUp) => unsafe { CAMERA_POS.y -= 1.0f32 },
      (glfw::Press, glfw::KeyDown) => unsafe { CAMERA_POS.y += 1.0f32 },
      (glfw::Press, glfw::KeyRight) => unsafe { CAMERA_POS.x -= 1.0f32 },
      (glfw::Press, glfw::KeyLeft) => unsafe { CAMERA_POS.x += 1.0f32 },
      _ => {}
    }
  }
}

fn main() {
  glfw::set_error_callback(~ErrorContext);
  do glfw::start {
    // glfw::window_hint::context_version(3, 2);
    let win =  Win::new();
    while win.is_running() {
      win.process_events();
      win.draw();
    }
    win.cleanup();
  }
}

#[start]
fn start(argc: int, argv: **u8) -> int {
  std::rt::start_on_main_thread(argc, argv, main)
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<commit_msg>Moved commented-out context setting to ::new()<commit_after>// See LICENSE file for copyright and license details.

// Marauder is grid-less turn-based strategy game.

extern mod glfw;
extern mod gl;
extern mod cgmath;

use gl::types::{
  GLenum,
  GLuint,
  GLint,
  GLchar,
  GLfloat,
  GLsizeiptr,
  GLboolean
};
use cgmath::matrix::{Matrix, Mat4, Mat3, ToMat4};
use cgmath::projection;
use cgmath::angle;
use cgmath::vector::{Vec3, Vec2};

#[link(name = "glfw")]
#[link(name = "m")]
extern {}

/// usage: let s = mvp_matrix; println(type_of(&s));
fn type_of<T>(_: &T) -> &'static str {
  unsafe {
    (*std::unstable::intrinsics::get_tydesc::<T>()).name
  }
}

fn print_mat4(name: &str, mat: Mat4<f32>) {
  println!("{}:", name);
  for i in range(0u, 4) {
    for j in range(0u, 4) {
      print!("{} ", *mat.cr(i, j));
    }
    println("");
  }
  println("");
}

static mut MOUSE_POS: Vec2<f32> = Vec2{x: 0.0f32, y: 0.0};
static mut CAMERA_POS: Vec3<f32> = Vec3{x: 0.0f32, y: 0.0, z: 0.0};

static WIN_SIZE: Vec2<uint> = Vec2{x: 640, y: 480};
static VERTICES_COUNT: i32 = 3 * 2;

static VERTEX_DATA: [GLfloat, ..VERTICES_COUNT * 3] = [
   0.0,  1.0, 0.0,
   2.0, -1.0, 0.0,
  -2.0, -1.0, 0.0,

  0.0,  1.0,  0.0,
  0.0, -1.0,  2.0,
  0.0, -1.0, -2.0
];

static VERTEX_SHADER_SRC: &'static str = "
  #version 130
  in vec3 position;
  uniform mat4 model_view_proj_matrix;
  void main() {
    vec4 v = vec4(position, 1);
    gl_Position = model_view_proj_matrix * v;
  }
";

static FRAGMENT_SHADER_SRC: &'static str = "
  #version 130
  out vec4 out_color;
  void main() {
    out_color = vec4(1.0, 1.0, 1.0, 1.0);
  }
";

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
  let shader = gl::CreateShader(ty);
  unsafe {
    // Attempt to compile the shader
    gl::ShaderSource(shader, 1, &src.to_c_str().unwrap(), std::ptr::null());
    gl::CompileShader(shader);

    // Get the compile status
    let mut status = gl::FALSE as GLint;
    gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len = 0;
      gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
      // subtract 1 to skip the trailing null character
      let mut buf = std::vec::from_elem(len as uint - 1, 0u8);
      gl::GetShaderInfoLog(shader, len, std::ptr::mut_null(),
        std::vec::raw::to_mut_ptr(buf) as *mut GLchar
      );
      fail!("compile_shader(): " + std::str::raw::from_utf8(buf));
    }
  }
  shader
}

fn link_program(vertex_shader: GLuint, fragment_shader: GLuint) -> GLuint {
  let program = gl::CreateProgram();
  gl::AttachShader(program, vertex_shader);
  gl::AttachShader(program, fragment_shader);
  gl::LinkProgram(program);
  unsafe {
    // Get the link status
    let mut status = gl::FALSE as GLint;
    gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len: GLint = 0;
      gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
      // subtract 1 to skip the trailing null character
      let mut buf = std::vec::from_elem(len as uint - 1, 0u8);
      gl::GetProgramInfoLog(program, len, std::ptr::mut_null(),
        std::vec::raw::to_mut_ptr(buf) as *mut GLchar
      );
      fail!("link_program(): " + std::str::raw::from_utf8(buf));
    }
  }
  program
}

fn tr(m: Mat4<f32>, v: Vec3<f32>) -> Mat4<f32> {
  let mut t = Mat4::<f32>::identity();
  *t.mut_cr(3, 0) = v.x;
  *t.mut_cr(3, 1) = v.y;
  *t.mut_cr(3, 2) = v.z;
  m.mul_m(&t)
}

fn rot_x(m: Mat4<f32>, angle: f32) -> Mat4<f32> {
  let r = Mat3::from_angle_x(angle::rad(angle)).to_mat4();
  m.mul_m(&r)
}

fn rot_y(m: Mat4<f32>, angle: f32) -> Mat4<f32> {
  let r = Mat3::from_angle_y(angle::rad(angle)).to_mat4();
  m.mul_m(&r)
}

// change matrices
fn upd(programId: GLuint) {
  let fov = angle::deg(45.0f32);
  let ratio = 4.0 / 3.0;
  let display_range_min = 0.1;
  let display_range_max = 100.0;
  let projection_matrix = projection::perspective(
    fov, ratio, display_range_min, display_range_max
  );

  let mut mvp_matrix = projection_matrix;
  unsafe {
    mvp_matrix = tr(mvp_matrix, Vec3{x: 0.0f32, y: 0.0, z: -10.0f32});
    mvp_matrix = rot_x(mvp_matrix, MOUSE_POS.y / 100.0);
    mvp_matrix = rot_y(mvp_matrix, MOUSE_POS.x / 100.0);
    mvp_matrix = tr(mvp_matrix, CAMERA_POS);
  }

  unsafe {
    // Get a handle for our "model_view_proj_matrix" uniform.
    // Only at initialisation time.
    let matrixId = gl::GetUniformLocation(
      programId, "model_view_proj_matrix".to_c_str().unwrap());

    // Send our transformation to the currently bound shader,
    // in the "model_view_proj_matrix" uniform.
    // For each model you render, since the model_view_proj_matrix
    // will be different (at least the M part).
    gl::UniformMatrix4fv(matrixId, 1, gl::FALSE, mvp_matrix.cr(0, 0));
  }
}

struct Win {
  vertex_shader: GLuint,
  fragment_shader: GLuint,
  program: GLuint,
  vertex_array_obj: GLuint,
  vertex_buffer_obj: GLuint,
  window: glfw::Window
}

impl Win {
  fn new() -> Win {
    // TODO: Move to opengl_init method
    // glfw::window_hint::context_version(3, 2);

    let mut win =  Win{
      vertex_shader: 0,
      fragment_shader: 0,
      program: 0,
      vertex_array_obj: 0,
      vertex_buffer_obj: 0,
      window: glfw::Window::create(
        WIN_SIZE.x,
        WIN_SIZE.y,
        "OpenGL",
        glfw::Windowed
      ).unwrap()
    };

    win.window.make_context_current();
    win.window.set_cursor_pos_callback(~CursorPosContext);
    win.window.set_key_callback(~KeyContext);

    // Load the OpenGL function pointers
    gl::load_with(glfw::get_proc_address);

    // Create GLSL shaders
    win.vertex_shader = compile_shader(
      VERTEX_SHADER_SRC, gl::VERTEX_SHADER);
    win.fragment_shader = compile_shader(
      FRAGMENT_SHADER_SRC, gl::FRAGMENT_SHADER);
    win.program = link_program(win.vertex_shader, win.fragment_shader);

    unsafe {
      // Create Vertex Array Object
      gl::GenVertexArrays(1, &mut win.vertex_array_obj);
      gl::BindVertexArray(win.vertex_array_obj);

      // Create a Vertex Buffer Object and copy the vertex data to it
      gl::GenBuffers(1, &mut win.vertex_buffer_obj);
      gl::BindBuffer(gl::ARRAY_BUFFER, win.vertex_buffer_obj);
      let float_size = std::mem::size_of::<GLfloat>();
      let vertices_ptr = (VERTEX_DATA.len() * float_size) as GLsizeiptr;
      gl::BufferData(
        gl::ARRAY_BUFFER,
        vertices_ptr,
        std::cast::transmute(&VERTEX_DATA[0]),
        gl::STATIC_DRAW
      );

      gl::UseProgram(win.program);
      gl::BindFragDataLocation(win.program, 0, "out_color".to_c_str().unwrap());

      // Specify the layout of the vertex data
      let pos_attr = gl::GetAttribLocation(
        win.program, "position".to_c_str().unwrap()) as GLuint;
      gl::EnableVertexAttribArray(pos_attr);
      let size = 3;
      let normalized = gl::FALSE as GLboolean;
      let stride = 0;
      gl::VertexAttribPointer(
        pos_attr,
        size,
        gl::FLOAT,
        normalized,
        stride,
        std::ptr::null()
      );
    }

    win
  }

  fn cleanup(&self) {
    // Cleanup
    gl::DeleteProgram(self.program);
    gl::DeleteShader(self.fragment_shader);
    gl::DeleteShader(self.vertex_shader);
    unsafe {
      gl::DeleteBuffers(1, &self.vertex_buffer_obj);
      gl::DeleteVertexArrays(1, &self.vertex_array_obj);
    }
  }

  fn draw(&self) {
    upd(self.program);

    // Clear the screen to black
    gl::ClearColor(0.3, 0.3, 0.3, 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT);

    // Draw a triangle from the 3 vertices
    gl::DrawArrays(gl::TRIANGLES, 0, VERTICES_COUNT);

    self.window.swap_buffers();
  }

  fn is_running(&self) -> bool {
    return !self.window.should_close()
  }

  fn process_events(&self) {
    glfw::poll_events();
  }
}

struct CursorPosContext;
impl glfw::CursorPosCallback for CursorPosContext {
  fn call(&self, w: &glfw::Window, xpos: f64, ypos: f64) {
    if w.get_mouse_button(glfw::MouseButtonRight) == glfw::Press {
      // println!("Cursor position: ({}, {})", xpos, ypos);
      unsafe {
        MOUSE_POS.x = xpos as f32;
        MOUSE_POS.y = ypos as f32;
      }
    }
  }
}

struct ErrorContext;
impl glfw::ErrorCallback for ErrorContext {
  fn call(&self, _: glfw::Error, description: ~str) {
    println!("GLFW Error: {:s}", description);
  }
}

struct KeyContext;
impl glfw::KeyCallback for KeyContext {
  fn call(
    &self,
    window: &glfw::Window,
    key:    glfw::Key,
    _:      std::libc::c_int,
    action: glfw::Action,
    _:      glfw::Modifiers
  ) {
    match (action, key) {
      (glfw::Press, glfw::KeyEscape) => {
        window.set_should_close(true)
      }
      (glfw::Press, glfw::KeySpace) => {
        println!("space")
      }
      (glfw::Press, glfw::KeyUp) => unsafe { CAMERA_POS.y -= 1.0f32 },
      (glfw::Press, glfw::KeyDown) => unsafe { CAMERA_POS.y += 1.0f32 },
      (glfw::Press, glfw::KeyRight) => unsafe { CAMERA_POS.x -= 1.0f32 },
      (glfw::Press, glfw::KeyLeft) => unsafe { CAMERA_POS.x += 1.0f32 },
      _ => {}
    }
  }
}

fn main() {
  glfw::set_error_callback(~ErrorContext);
  do glfw::start {
    let win =  Win::new();
    while win.is_running() {
      win.process_events();
      win.draw();
    }
    win.cleanup();
  }
}

#[start]
fn start(argc: int, argv: **u8) -> int {
  std::rt::start_on_main_thread(argc, argv, main)
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<|endoftext|>


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

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("Color", inherited=True) %>

<% from data import to_rust_ident %>

${helpers.predefined_type(
    "color",
    "ColorPropertyValue",
    "::cssparser::RGBA::new(0, 0, 0, 255)",
    animation_value_type="AnimatedRGBA",
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
    ignored_when_colors_disabled="True",
    spec="https://drafts.csswg.org/css-color/#color"
)}

// FIXME(#15973): Add servo support for system colors
//
// FIXME(emilio): Move outside of mako.
% if product == "gecko":
pub mod system_colors {
    <%
        # These are actually parsed. See nsCSSProps::kColorKTable
        system_colors = """activeborder activecaption appworkspace background buttonface
                           buttonhighlight buttonshadow buttontext captiontext graytext highlight
                           highlighttext inactiveborder inactivecaption inactivecaptiontext
                           infobackground infotext menu menutext scrollbar threeddarkshadow
                           threedface threedhighlight threedlightshadow threedshadow window
                           windowframe windowtext -moz-buttondefault -moz-buttonhoverface
                           -moz-buttonhovertext -moz-cellhighlight -moz-cellhighlighttext
                           -moz-eventreerow -moz-field -moz-fieldtext -moz-dialog -moz-dialogtext
                           -moz-dragtargetzone -moz-gtk-info-bar-text -moz-html-cellhighlight
                           -moz-html-cellhighlighttext -moz-mac-buttonactivetext
                           -moz-mac-chrome-active -moz-mac-chrome-inactive
                           -moz-mac-defaultbuttontext -moz-mac-focusring -moz-mac-menuselect
                           -moz-mac-menushadow -moz-mac-menutextdisable -moz-mac-menutextselect
                           -moz-mac-disabledtoolbartext -moz-mac-secondaryhighlight
                           -moz-mac-vibrancy-light -moz-mac-vibrancy-dark -moz-mac-menupopup
                           -moz-mac-menuitem -moz-mac-active-menuitem -moz-mac-source-list
                           -moz-mac-source-list-selection -moz-mac-active-source-list-selection
                           -moz-mac-tooltip
                           -moz-menuhover -moz-menuhovertext -moz-menubartext -moz-menubarhovertext
                           -moz-oddtreerow -moz-win-mediatext -moz-win-communicationstext
                           -moz-win-accentcolor -moz-win-accentcolortext
                           -moz-nativehyperlinktext -moz-comboboxtext -moz-combobox""".split()

        # These are not parsed but must be serialized
        # They are only ever set directly by Gecko
        extra_colors = """WindowBackground WindowForeground WidgetBackground WidgetForeground
                          WidgetSelectBackground WidgetSelectForeground Widget3DHighlight Widget3DShadow
                          TextBackground TextForeground TextSelectBackground TextSelectForeground
                          TextSelectForegroundCustom TextSelectBackgroundDisabled TextSelectBackgroundAttention
                          TextHighlightBackground TextHighlightForeground IMERawInputBackground
                          IMERawInputForeground IMERawInputUnderline IMESelectedRawTextBackground
                          IMESelectedRawTextForeground IMESelectedRawTextUnderline
                          IMEConvertedTextBackground IMEConvertedTextForeground IMEConvertedTextUnderline
                          IMESelectedConvertedTextBackground IMESelectedConvertedTextForeground
                          IMESelectedConvertedTextUnderline SpellCheckerUnderline""".split()
    %>
    use cssparser::Parser;
    use gecko_bindings::bindings::Gecko_GetLookAndFeelSystemColor;
    use gecko_bindings::structs::root::mozilla::LookAndFeel_ColorID;
    use std::fmt;
    use style_traits::ToCss;
    use values::computed::{Context, ToComputedValue};

    pub type SystemColor = LookAndFeel_ColorID;

    // It's hard to implement MallocSizeOf for LookAndFeel_ColorID because it
    // is a bindgen type. So we implement it on the typedef instead.
    malloc_size_of_is_0!(SystemColor);

    impl ToCss for SystemColor {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let s = match *self {
                % for color in system_colors + extra_colors:
                    LookAndFeel_ColorID::eColorID_${to_rust_ident(color)} => "${color}",
                % endfor
                LookAndFeel_ColorID::eColorID_LAST_COLOR => unreachable!(),
            };
            dest.write_str(s)
        }
    }

    impl ToComputedValue for SystemColor {
        type ComputedValue = u32; // nscolor

        #[inline]
        fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
            unsafe {
                Gecko_GetLookAndFeelSystemColor(*self as i32,
                                                cx.device().pres_context())
            }
        }

        #[inline]
        fn from_computed_value(_: &Self::ComputedValue) -> Self {
            unreachable!()
        }
    }

    impl SystemColor {
        pub fn parse<'i, 't>(input: &mut Parser<'i, 't>,) -> Result<Self, ()> {
            ascii_case_insensitive_phf_map! {
                color_name -> SystemColor = {
                    % for color in system_colors:
                        "${color}" => LookAndFeel_ColorID::eColorID_${to_rust_ident(color)},
                    % endfor
                }
            }

            let ident = input.expect_ident().map_err(|_| ())?;
            color_name(ident).cloned().ok_or(())
        }
    }
}
% endif
<commit_msg>Servo changes for system colors-moz-mac-vibrant-titlebar-light/dark<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("Color", inherited=True) %>

<% from data import to_rust_ident %>

${helpers.predefined_type(
    "color",
    "ColorPropertyValue",
    "::cssparser::RGBA::new(0, 0, 0, 255)",
    animation_value_type="AnimatedRGBA",
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
    ignored_when_colors_disabled="True",
    spec="https://drafts.csswg.org/css-color/#color"
)}

// FIXME(#15973): Add servo support for system colors
//
// FIXME(emilio): Move outside of mako.
% if product == "gecko":
pub mod system_colors {
    <%
        # These are actually parsed. See nsCSSProps::kColorKTable
        system_colors = """activeborder activecaption appworkspace background buttonface
                           buttonhighlight buttonshadow buttontext captiontext graytext highlight
                           highlighttext inactiveborder inactivecaption inactivecaptiontext
                           infobackground infotext menu menutext scrollbar threeddarkshadow
                           threedface threedhighlight threedlightshadow threedshadow window
                           windowframe windowtext -moz-buttondefault -moz-buttonhoverface
                           -moz-buttonhovertext -moz-cellhighlight -moz-cellhighlighttext
                           -moz-eventreerow -moz-field -moz-fieldtext -moz-dialog -moz-dialogtext
                           -moz-dragtargetzone -moz-gtk-info-bar-text -moz-html-cellhighlight
                           -moz-html-cellhighlighttext -moz-mac-buttonactivetext
                           -moz-mac-chrome-active -moz-mac-chrome-inactive
                           -moz-mac-defaultbuttontext -moz-mac-focusring -moz-mac-menuselect
                           -moz-mac-menushadow -moz-mac-menutextdisable -moz-mac-menutextselect
                           -moz-mac-disabledtoolbartext -moz-mac-secondaryhighlight
                           -moz-mac-vibrancy-light -moz-mac-vibrancy-dark
                           -moz-mac-vibrant-titlebar-light -moz-mac-vibrant-titlebar-dark
                           -moz-mac-menupopup
                           -moz-mac-menuitem -moz-mac-active-menuitem -moz-mac-source-list
                           -moz-mac-source-list-selection -moz-mac-active-source-list-selection
                           -moz-mac-tooltip
                           -moz-menuhover -moz-menuhovertext -moz-menubartext -moz-menubarhovertext
                           -moz-oddtreerow -moz-win-mediatext -moz-win-communicationstext
                           -moz-win-accentcolor -moz-win-accentcolortext
                           -moz-nativehyperlinktext -moz-comboboxtext -moz-combobox""".split()

        # These are not parsed but must be serialized
        # They are only ever set directly by Gecko
        extra_colors = """WindowBackground WindowForeground WidgetBackground WidgetForeground
                          WidgetSelectBackground WidgetSelectForeground Widget3DHighlight Widget3DShadow
                          TextBackground TextForeground TextSelectBackground TextSelectForeground
                          TextSelectForegroundCustom TextSelectBackgroundDisabled TextSelectBackgroundAttention
                          TextHighlightBackground TextHighlightForeground IMERawInputBackground
                          IMERawInputForeground IMERawInputUnderline IMESelectedRawTextBackground
                          IMESelectedRawTextForeground IMESelectedRawTextUnderline
                          IMEConvertedTextBackground IMEConvertedTextForeground IMEConvertedTextUnderline
                          IMESelectedConvertedTextBackground IMESelectedConvertedTextForeground
                          IMESelectedConvertedTextUnderline SpellCheckerUnderline""".split()
    %>
    use cssparser::Parser;
    use gecko_bindings::bindings::Gecko_GetLookAndFeelSystemColor;
    use gecko_bindings::structs::root::mozilla::LookAndFeel_ColorID;
    use std::fmt;
    use style_traits::ToCss;
    use values::computed::{Context, ToComputedValue};

    pub type SystemColor = LookAndFeel_ColorID;

    // It's hard to implement MallocSizeOf for LookAndFeel_ColorID because it
    // is a bindgen type. So we implement it on the typedef instead.
    malloc_size_of_is_0!(SystemColor);

    impl ToCss for SystemColor {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let s = match *self {
                % for color in system_colors + extra_colors:
                    LookAndFeel_ColorID::eColorID_${to_rust_ident(color)} => "${color}",
                % endfor
                LookAndFeel_ColorID::eColorID_LAST_COLOR => unreachable!(),
            };
            dest.write_str(s)
        }
    }

    impl ToComputedValue for SystemColor {
        type ComputedValue = u32; // nscolor

        #[inline]
        fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
            unsafe {
                Gecko_GetLookAndFeelSystemColor(*self as i32,
                                                cx.device().pres_context())
            }
        }

        #[inline]
        fn from_computed_value(_: &Self::ComputedValue) -> Self {
            unreachable!()
        }
    }

    impl SystemColor {
        pub fn parse<'i, 't>(input: &mut Parser<'i, 't>,) -> Result<Self, ()> {
            ascii_case_insensitive_phf_map! {
                color_name -> SystemColor = {
                    % for color in system_colors:
                        "${color}" => LookAndFeel_ColorID::eColorID_${to_rust_ident(color)},
                    % endfor
                }
            }

            let ident = input.expect_ident().map_err(|_| ())?;
            color_name(ident).cloned().ok_or(())
        }
    }
}
% endif
<|endoftext|>


<commit_before>// Copyright (C) 2019 Guillaume Desmottes <guillaume.desmottes@collabora.com>
//
// 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 glib::subclass::prelude::*;
use gst::gst_debug;
use gst::subclass::prelude::*;
use gst_video::prelude::VideoDecoderExtManual;
use gst_video::prelude::*;
use gst_video::subclass::prelude::*;
use image::GenericImageView;
use once_cell::sync::Lazy;
use std::sync::Mutex;

use crate::constants::{CDG_HEIGHT, CDG_WIDTH};

static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
    gst::DebugCategory::new("cdgdec", gst::DebugColorFlags::empty(), Some("CDG decoder"))
});

#[derive(Default)]
pub struct CdgDec {
    cdg_inter: Mutex<Box<cdg_renderer::CdgInterpreter>>,
    output_info: Mutex<Option<gst_video::VideoInfo>>,
}

#[glib::object_subclass]
impl ObjectSubclass for CdgDec {
    const NAME: &'static str = "CdgDec";
    type Type = super::CdgDec;
    type ParentType = gst_video::VideoDecoder;
}

impl ObjectImpl for CdgDec {}

impl ElementImpl for CdgDec {
    fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
        static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
            gst::subclass::ElementMetadata::new(
                "CDG decoder",
                "Decoder/Video",
                "CDG decoder",
                "Guillaume Desmottes <guillaume.desmottes@collabora.com>",
            )
        });

        Some(&*ELEMENT_METADATA)
    }

    fn pad_templates() -> &'static [gst::PadTemplate] {
        static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
            let sink_caps = gst::Caps::new_simple("video/x-cdg", &[("parsed", &true)]);
            let sink_pad_template = gst::PadTemplate::new(
                "sink",
                gst::PadDirection::Sink,
                gst::PadPresence::Always,
                &sink_caps,
            )
            .unwrap();

            let src_caps = gst::Caps::new_simple(
                "video/x-raw",
                &[
                    ("format", &gst_video::VideoFormat::Rgba.to_str()),
                    ("width", &(CDG_WIDTH as i32)),
                    ("height", &(CDG_HEIGHT as i32)),
                    ("framerate", &gst::Fraction::new(0, 1)),
                ],
            );
            let src_pad_template = gst::PadTemplate::new(
                "src",
                gst::PadDirection::Src,
                gst::PadPresence::Always,
                &src_caps,
            )
            .unwrap();

            vec![src_pad_template, sink_pad_template]
        });

        PAD_TEMPLATES.as_ref()
    }
}

impl VideoDecoderImpl for CdgDec {
    fn start(&self, element: &Self::Type) -> Result<(), gst::ErrorMessage> {
        let mut out_info = self.output_info.lock().unwrap();
        *out_info = None;

        self.parent_start(element)
    }

    fn stop(&self, element: &Self::Type) -> Result<(), gst::ErrorMessage> {
        {
            let mut cdg_inter = self.cdg_inter.lock().unwrap();
            cdg_inter.reset(true);
        }
        self.parent_stop(element)
    }

    fn handle_frame(
        &self,
        element: &Self::Type,
        mut frame: gst_video::VideoCodecFrame,
    ) -> Result<gst::FlowSuccess, gst::FlowError> {
        {
            let mut out_info = self.output_info.lock().unwrap();
            if out_info.is_none() {
                let output_state = element.set_output_state(
                    gst_video::VideoFormat::Rgba,
                    CDG_WIDTH,
                    CDG_HEIGHT,
                    None,
                )?;

                element.negotiate(output_state)?;

                let out_state = element.output_state().unwrap();
                *out_info = Some(out_state.info());
            }
        }

        let cmd = {
            let input = frame.input_buffer().unwrap();
            let map = input.map_readable().map_err(|_| {
                gst::element_error!(
                    element,
                    gst::CoreError::Failed,
                    ["Failed to map input buffer readable"]
                );
                gst::FlowError::Error
            })?;
            let data = map.as_slice();

            cdg::decode_subchannel_cmd(&data)
        };

        let cmd = match cmd {
            Some(cmd) => cmd,
            None => {
                // Not a CDG command
                element.release_frame(frame);
                return Ok(gst::FlowSuccess::Ok);
            }
        };

        let mut cdg_inter = self.cdg_inter.lock().unwrap();
        cdg_inter.handle_cmd(cmd);

        element.allocate_output_frame(&mut frame, None)?;
        {
            let output = frame.output_buffer_mut().unwrap();
            let info = self.output_info.lock().unwrap();

            let mut out_frame =
                gst_video::VideoFrameRef::from_buffer_ref_writable(output, info.as_ref().unwrap())
                    .map_err(|_| {
                        gst::element_error!(
                            element,
                            gst::CoreError::Failed,
                            ["Failed to map output buffer writable"]
                        );
                        gst::FlowError::Error
                    })?;

            let out_stride = out_frame.plane_stride()[0] as usize;

            for (y, line) in out_frame
                .plane_data_mut(0)
                .unwrap()
                .chunks_exact_mut(out_stride)
                .take(CDG_HEIGHT as usize)
                .enumerate()
            {
                for (x, pixel) in line
                    .chunks_exact_mut(4)
                    .take(CDG_WIDTH as usize)
                    .enumerate()
                {
                    let p = cdg_inter.get_pixel(x as u32, y as u32);
                    pixel.copy_from_slice(&p.0);
                }
            }
        }

        gst_debug!(CAT, obj: element, "Finish frame pts={}", frame.pts());

        element.finish_frame(frame)
    }

    fn decide_allocation(
        &self,
        element: &Self::Type,
        query: &mut gst::QueryRef,
    ) -> Result<(), gst::ErrorMessage> {
        if let gst::query::QueryView::Allocation(allocation) = query.view() {
            if allocation
                .find_allocation_meta::<gst_video::VideoMeta>()
                .is_some()
            {
                let pools = allocation.allocation_pools();
                if let Some((Some(ref pool), _, _, _)) = pools.first() {
                    let mut config = pool.config();
                    config.add_option(&gst_video::BUFFER_POOL_OPTION_VIDEO_META);
                    pool.set_config(config)
                        .map_err(|e| gst::error_msg!(gst::CoreError::Negotiation, [&e.message]))?;
                }
            }
        }

        self.parent_decide_allocation(element, query)
    }

    fn flush(&self, element: &Self::Type) -> bool {
        gst_debug!(CAT, obj: element, "flushing, reset CDG interpreter");

        let mut cdg_inter = self.cdg_inter.lock().unwrap();
        cdg_inter.reset(false);
        true
    }
}
<commit_msg>cdgdec: Remove unneeded VideoDecoderExtManual import<commit_after>// Copyright (C) 2019 Guillaume Desmottes <guillaume.desmottes@collabora.com>
//
// 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 glib::subclass::prelude::*;
use gst::gst_debug;
use gst::subclass::prelude::*;
use gst_video::prelude::*;
use gst_video::subclass::prelude::*;
use image::GenericImageView;
use once_cell::sync::Lazy;
use std::sync::Mutex;

use crate::constants::{CDG_HEIGHT, CDG_WIDTH};

static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
    gst::DebugCategory::new("cdgdec", gst::DebugColorFlags::empty(), Some("CDG decoder"))
});

#[derive(Default)]
pub struct CdgDec {
    cdg_inter: Mutex<Box<cdg_renderer::CdgInterpreter>>,
    output_info: Mutex<Option<gst_video::VideoInfo>>,
}

#[glib::object_subclass]
impl ObjectSubclass for CdgDec {
    const NAME: &'static str = "CdgDec";
    type Type = super::CdgDec;
    type ParentType = gst_video::VideoDecoder;
}

impl ObjectImpl for CdgDec {}

impl ElementImpl for CdgDec {
    fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
        static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
            gst::subclass::ElementMetadata::new(
                "CDG decoder",
                "Decoder/Video",
                "CDG decoder",
                "Guillaume Desmottes <guillaume.desmottes@collabora.com>",
            )
        });

        Some(&*ELEMENT_METADATA)
    }

    fn pad_templates() -> &'static [gst::PadTemplate] {
        static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
            let sink_caps = gst::Caps::new_simple("video/x-cdg", &[("parsed", &true)]);
            let sink_pad_template = gst::PadTemplate::new(
                "sink",
                gst::PadDirection::Sink,
                gst::PadPresence::Always,
                &sink_caps,
            )
            .unwrap();

            let src_caps = gst::Caps::new_simple(
                "video/x-raw",
                &[
                    ("format", &gst_video::VideoFormat::Rgba.to_str()),
                    ("width", &(CDG_WIDTH as i32)),
                    ("height", &(CDG_HEIGHT as i32)),
                    ("framerate", &gst::Fraction::new(0, 1)),
                ],
            );
            let src_pad_template = gst::PadTemplate::new(
                "src",
                gst::PadDirection::Src,
                gst::PadPresence::Always,
                &src_caps,
            )
            .unwrap();

            vec![src_pad_template, sink_pad_template]
        });

        PAD_TEMPLATES.as_ref()
    }
}

impl VideoDecoderImpl for CdgDec {
    fn start(&self, element: &Self::Type) -> Result<(), gst::ErrorMessage> {
        let mut out_info = self.output_info.lock().unwrap();
        *out_info = None;

        self.parent_start(element)
    }

    fn stop(&self, element: &Self::Type) -> Result<(), gst::ErrorMessage> {
        {
            let mut cdg_inter = self.cdg_inter.lock().unwrap();
            cdg_inter.reset(true);
        }
        self.parent_stop(element)
    }

    fn handle_frame(
        &self,
        element: &Self::Type,
        mut frame: gst_video::VideoCodecFrame,
    ) -> Result<gst::FlowSuccess, gst::FlowError> {
        {
            let mut out_info = self.output_info.lock().unwrap();
            if out_info.is_none() {
                let output_state = element.set_output_state(
                    gst_video::VideoFormat::Rgba,
                    CDG_WIDTH,
                    CDG_HEIGHT,
                    None,
                )?;

                element.negotiate(output_state)?;

                let out_state = element.output_state().unwrap();
                *out_info = Some(out_state.info());
            }
        }

        let cmd = {
            let input = frame.input_buffer().unwrap();
            let map = input.map_readable().map_err(|_| {
                gst::element_error!(
                    element,
                    gst::CoreError::Failed,
                    ["Failed to map input buffer readable"]
                );
                gst::FlowError::Error
            })?;
            let data = map.as_slice();

            cdg::decode_subchannel_cmd(&data)
        };

        let cmd = match cmd {
            Some(cmd) => cmd,
            None => {
                // Not a CDG command
                element.release_frame(frame);
                return Ok(gst::FlowSuccess::Ok);
            }
        };

        let mut cdg_inter = self.cdg_inter.lock().unwrap();
        cdg_inter.handle_cmd(cmd);

        element.allocate_output_frame(&mut frame, None)?;
        {
            let output = frame.output_buffer_mut().unwrap();
            let info = self.output_info.lock().unwrap();

            let mut out_frame =
                gst_video::VideoFrameRef::from_buffer_ref_writable(output, info.as_ref().unwrap())
                    .map_err(|_| {
                        gst::element_error!(
                            element,
                            gst::CoreError::Failed,
                            ["Failed to map output buffer writable"]
                        );
                        gst::FlowError::Error
                    })?;

            let out_stride = out_frame.plane_stride()[0] as usize;

            for (y, line) in out_frame
                .plane_data_mut(0)
                .unwrap()
                .chunks_exact_mut(out_stride)
                .take(CDG_HEIGHT as usize)
                .enumerate()
            {
                for (x, pixel) in line
                    .chunks_exact_mut(4)
                    .take(CDG_WIDTH as usize)
                    .enumerate()
                {
                    let p = cdg_inter.get_pixel(x as u32, y as u32);
                    pixel.copy_from_slice(&p.0);
                }
            }
        }

        gst_debug!(CAT, obj: element, "Finish frame pts={}", frame.pts());

        element.finish_frame(frame)
    }

    fn decide_allocation(
        &self,
        element: &Self::Type,
        query: &mut gst::QueryRef,
    ) -> Result<(), gst::ErrorMessage> {
        if let gst::query::QueryView::Allocation(allocation) = query.view() {
            if allocation
                .find_allocation_meta::<gst_video::VideoMeta>()
                .is_some()
            {
                let pools = allocation.allocation_pools();
                if let Some((Some(ref pool), _, _, _)) = pools.first() {
                    let mut config = pool.config();
                    config.add_option(&gst_video::BUFFER_POOL_OPTION_VIDEO_META);
                    pool.set_config(config)
                        .map_err(|e| gst::error_msg!(gst::CoreError::Negotiation, [&e.message]))?;
                }
            }
        }

        self.parent_decide_allocation(element, query)
    }

    fn flush(&self, element: &Self::Type) -> bool {
        gst_debug!(CAT, obj: element, "flushing, reset CDG interpreter");

        let mut cdg_inter = self.cdg_inter.lock().unwrap();
        cdg_inter.reset(false);
        true
    }
}
<|endoftext|>


<commit_before>use super::package::*;
use super::executor::*;

use alloc::boxed::Box;

use core::{cmp, ptr, mem};

use common::event::{self, Event, EventOption, KeyEvent, MouseEvent};
use common::resource::{NoneResource, Resource, ResourceType, URL, VecResource};
use common::scheduler;
use common::string::{String, ToString};
use common::vec::Vec;

use graphics::bmp::*;
use graphics::color::Color;
use graphics::display::Display;
use graphics::point::Point;
use graphics::size::Size;
use graphics::window::Window;

#[allow(unused_variables)]
pub trait SessionItem {
    fn on_irq(&mut self, irq: u8) {

    }

    fn on_poll(&mut self) {

    }

    fn scheme(&self) -> String {
        String::new()
    }

    fn open(&mut self, url: &URL) -> Box<Resource> {
        box NoneResource
    }
}

pub struct Session {
    pub display: Display,
    pub background: BMPFile,
    pub cursor: BMPFile,
    pub mouse_point: Point,
    last_mouse_event: MouseEvent,
    pub items: Vec<Box<SessionItem>>,
    pub packages: Vec<Box<Package>>,
    pub windows: Vec<*mut Window>,
    pub windows_ordered: Vec<*mut Window>,
    pub redraw: usize,
}

impl Session {
    pub fn new() -> Self {
        unsafe {
            Session {
                display: Display::root(),
                background: BMPFile::new(),
                cursor: BMPFile::new(),
                mouse_point: Point::new(0, 0),
                last_mouse_event: MouseEvent {
                    x: 0,
                    y: 0,
                    left_button: false,
                    middle_button: false,
                    right_button: false,
                },
                items: Vec::new(),
                packages: Vec::new(),
                windows: Vec::new(),
                windows_ordered: Vec::new(),
                redraw: event::REDRAW_ALL,
            }
        }
    }

    pub unsafe fn add_window(&mut self, add_window_ptr: *mut Window) {
        self.windows.push(add_window_ptr);
        self.windows_ordered.push(add_window_ptr);
        self.redraw = cmp::max(self.redraw, event::REDRAW_ALL);
    }

    pub unsafe fn remove_window(&mut self, remove_window_ptr: *mut Window) {
        let mut i = 0;
        while i < self.windows.len() {
            let mut remove = false;

            match self.windows.get(i) {
                Option::Some(window_ptr) => if *window_ptr == remove_window_ptr {
                    remove = true;
                } else {
                    i += 1;
                },
                Option::None => break,
            }

            if remove {
                self.windows.remove(i);
            }
        }

        i = 0;
        while i < self.windows_ordered.len() {
            let mut remove = false;

            match self.windows_ordered.get(i) {
                Option::Some(window_ptr) => if *window_ptr == remove_window_ptr {
                    remove = true;
                } else {
                    i += 1;
                },
                Option::None => break,
            }

            if remove {
                self.windows_ordered.remove(i);
            }
        }

        self.redraw = cmp::max(self.redraw, event::REDRAW_ALL);
    }

    pub unsafe fn on_irq(&mut self, irq: u8) {
        for item in self.items.iter() {
            let reenable = scheduler::start_no_ints();
            item.on_irq(irq);
            scheduler::end_no_ints(reenable);
        }
    }

    pub unsafe fn on_poll(&mut self) {
        for item in self.items.iter() {
            let reenable = scheduler::start_no_ints();
            item.on_poll();
            scheduler::end_no_ints(reenable);
        }
    }

    pub fn open(&self, url: &URL) -> Box<Resource> {
        if url.scheme().len() == 0 {
            let mut list = String::new();

            for item in self.items.iter() {
                let scheme = item.scheme();
                if scheme.len() > 0 {
                    if list.len() > 0 {
                        list = list + "\n" + scheme;
                    } else {
                        list = scheme;
                    }
                }
            }

            box VecResource::new(URL::new(), ResourceType::Dir, list.to_utf8())
        } else {
            for item in self.items.iter() {
                if item.scheme() == url.scheme() {
                    return item.open(url);
                }
            }
            box NoneResource
        }
    }

    fn on_key(&mut self, key_event: KeyEvent) {
        if self.windows.len() > 0 {
            match self.windows.get(self.windows.len() - 1) {
                Option::Some(window_ptr) => {
                    unsafe {
                        (**window_ptr).on_key(key_event);
                        self.redraw = cmp::max(self.redraw, event::REDRAW_ALL);
                    }
                }
                Option::None => (),
            }
        }
    }

    fn on_mouse(&mut self, mouse_event: MouseEvent) {
        let mut catcher = -1;

        if mouse_event.y >= self.display.height as isize - 32 {
            if mouse_event.left_button && !self.last_mouse_event.left_button {
                let mut x = 0;
                for package in self.packages.iter() {
                    if package.icon.data.len() > 0 {
                        if mouse_event.x >= x &&
                           mouse_event.x < x + package.icon.size.width as isize {
                            execute(&package.binary, &package.url, &Vec::new());
                        }
                        x += package.icon.size.width as isize;
                    }
                }

                let mut chars = 32;
                while chars > 4 &&
                      (x as usize + (chars * 8 + 3 * 4) * self.windows.len()) >
                      self.display.width + 32 {
                    chars -= 1;
                }

                x += 4;
                for window_ptr in self.windows_ordered.iter() {
                    let w = (chars*8 + 2*4) as usize;
                    if mouse_event.x >= x && mouse_event.x < x + w as isize {
                        for j in 0..self.windows.len() {
                            match self.windows.get(j) {
                                Option::Some(catcher_window_ptr) =>
                                    if catcher_window_ptr == window_ptr {
                                    unsafe {
                                        if j == self.windows.len() - 1 {
                                            (**window_ptr).minimized = !(**window_ptr).minimized;
                                        } else {
                                            catcher = j as isize;
                                            (**window_ptr).minimized = false;
                                        }
                                    }
                                    break;
                                },
                                Option::None => break,
                            }
                        }
                        self.redraw = cmp::max(self.redraw, event::REDRAW_ALL);
                        break;
                    }
                    x += w as isize;
                }
            }
        } else {
            for reverse_i in 0..self.windows.len() {
                let i = self.windows.len() - 1 - reverse_i;
                match self.windows.get(i) {
                    Option::Some(window_ptr) => unsafe {
                        if (**window_ptr).on_mouse(mouse_event, catcher < 0) {
                            catcher = i as isize;

                            self.redraw = cmp::max(self.redraw, event::REDRAW_ALL);
                        }
                    },
                    Option::None => (),
                }
            }
        }

        if catcher >= 0 && catcher < self.windows.len() as isize - 1 {
            match self.windows.remove(catcher as usize) {
                Option::Some(window_ptr) => self.windows.push(window_ptr),
                Option::None => (),
            }
        }

        self.last_mouse_event = mouse_event;
    }

    pub unsafe fn redraw(&mut self) {
        if self.redraw > event::REDRAW_NONE {
            //if self.redraw >= REDRAW_ALL {
            self.display.set(Color::new(75, 163, 253));
            if self.background.data.len() > 0 {
                self.background.draw(&self.display,
                                     Point::new((self.display.width as isize -
                                                 self.background.size.width as isize) /
                                                2,
                                                (self.display.height as isize -
                                                 self.background.size.height as isize) /
                                                2));
            }

            for i in 0..self.windows.len() {
                match self.windows.get(i) {
                    Option::Some(window_ptr) => {
                        (**window_ptr).focused = i == self.windows.len() - 1;
                        (**window_ptr).draw(&self.display);
                    }
                    Option::None => (),
                }
            }

            self.display.rect(Point::new(0, self.display.height as isize - 32),
                              Size::new(self.display.width, 32),
                              Color::alpha(0, 0, 0, 128));

            let mut x = 0;
            for package in self.packages.iter() {
                if package.icon.data.len() > 0 {
                    let y = self.display.height as isize - package.icon.size.height as isize;
                    if self.mouse_point.y >= y && self.mouse_point.x >= x &&
                       self.mouse_point.x < x + package.icon.size.width as isize {
                        self.display.rect(Point::new(x, y),
                                          package.icon.size,
                                          Color::alpha(128, 128, 128, 128));

                        let mut c_x = x;
                        for c in package.name.chars() {
                            self.display
                                .char(Point::new(c_x, y - 16), c, Color::new(255, 255, 255));
                            c_x += 8;
                        }
                    }
                    package.icon.draw(&self.display, Point::new(x, y));
                    x += package.icon.size.width as isize;
                }
            }

            let mut chars = 32;
            while chars > 4 &&
                  (x as usize + (chars * 8 + 3 * 4) * self.windows.len()) >
                  self.display.width + 32 {
                chars -= 1;
            }

            x += 4;
            for window_ptr in self.windows_ordered.iter() {
                let w = (chars*8 + 2*4) as usize;
                self.display.rect(Point::new(x, self.display.height as isize - 32),
                                  Size::new(w, 32),
                                  (**window_ptr).border_color);
                x += 4;

                for i in 0..chars {
                    let c = (**window_ptr).title[i];
                    if c != '\0' {
                        self.display.char(Point::new(x, self.display.height as isize - 24),
                                          c,
                                          (**window_ptr).title_color);
                    }
                    x += 8;
                }
                x += 8;
            }

            if self.cursor.data.len() > 0 {
                self.display.image_alpha(self.mouse_point,
                                         self.cursor.data.as_ptr(),
                                         self.cursor.size);
            } else {
                self.display.char(Point::new(self.mouse_point.x - 3, self.mouse_point.y - 9),
                                  'X',
                                  Color::new(255, 255, 255));
            }
            //}

            let reenable = scheduler::start_no_ints();

            self.display.flip();

            /*
            if self.cursor.data.len() > 0 {
                self.display.image_alpha_onscreen(self.mouse_point, self.cursor.data.as_ptr(), self.cursor.size);
            } else {
                self.display.char_onscreen(Point::new(self.mouse_point.x - 3, self.mouse_point.y - 9), 'X', Color::new(255, 255, 255));
            }
            */

            self.redraw = event::REDRAW_NONE;

            scheduler::end_no_ints(reenable);
        }
    }

    pub fn event(&mut self, event: Event) {
        match event.to_option() {
            EventOption::Mouse(mouse_event) => self.on_mouse(mouse_event),
            EventOption::Key(key_event) => self.on_key(key_event),
            EventOption::Redraw(redraw_event) =>
                self.redraw = cmp::max(self.redraw, redraw_event.redraw),
            EventOption::Open(open_event) => {
                let url_string = open_event.url_string;

                if url_string.ends_with(".bin".to_string()) {
                    execute(&URL::from_string(&url_string),
                            &URL::new(),
                            &Vec::new());
                } else {
                    for package in self.packages.iter() {
                        let mut accepted = false;
                        for accept in package.accepts.iter() {
                            if url_string.ends_with(accept.substr(1, accept.len() - 1)) {
                                accepted = true;
                                break;
                            }
                        }
                        if accepted {
                            let mut args: Vec<String> = Vec::new();
                            args.push(url_string.clone());
                            execute(&package.binary, &package.url, &args);
                            break;
                        }
                    }
                }
            }
            _ => (),
        }
    }
}
<commit_msg>Opening Programs from the UI Bar Change<commit_after>use super::package::*;
use super::executor::*;

use alloc::boxed::Box;

use core::{cmp, ptr, mem};

use common::event::{self, Event, EventOption, KeyEvent, MouseEvent};
use common::resource::{NoneResource, Resource, ResourceType, URL, VecResource};
use common::scheduler;
use common::string::{String, ToString};
use common::vec::Vec;

use graphics::bmp::*;
use graphics::color::Color;
use graphics::display::Display;
use graphics::point::Point;
use graphics::size::Size;
use graphics::window::Window;

#[allow(unused_variables)]
pub trait SessionItem {
    fn on_irq(&mut self, irq: u8) {

    }

    fn on_poll(&mut self) {

    }

    fn scheme(&self) -> String {
        String::new()
    }

    fn open(&mut self, url: &URL) -> Box<Resource> {
        box NoneResource
    }
}

pub struct Session {
    pub display: Display,
    pub background: BMPFile,
    pub cursor: BMPFile,
    pub mouse_point: Point,
    last_mouse_event: MouseEvent,
    pub items: Vec<Box<SessionItem>>,
    pub packages: Vec<Box<Package>>,
    pub windows: Vec<*mut Window>,
    pub windows_ordered: Vec<*mut Window>,
    pub redraw: usize,
}

impl Session {
    pub fn new() -> Self {
        unsafe {
            Session {
                display: Display::root(),
                background: BMPFile::new(),
                cursor: BMPFile::new(),
                mouse_point: Point::new(0, 0),
                last_mouse_event: MouseEvent {
                    x: 0,
                    y: 0,
                    left_button: false,
                    middle_button: false,
                    right_button: false,
                },
                items: Vec::new(),
                packages: Vec::new(),
                windows: Vec::new(),
                windows_ordered: Vec::new(),
                redraw: event::REDRAW_ALL,
            }
        }
    }

    pub unsafe fn add_window(&mut self, add_window_ptr: *mut Window) {
        self.windows.push(add_window_ptr);
        self.windows_ordered.push(add_window_ptr);
        self.redraw = cmp::max(self.redraw, event::REDRAW_ALL);
    }

    pub unsafe fn remove_window(&mut self, remove_window_ptr: *mut Window) {
        let mut i = 0;
        while i < self.windows.len() {
            let mut remove = false;

            match self.windows.get(i) {
                Option::Some(window_ptr) => if *window_ptr == remove_window_ptr {
                    remove = true;
                } else {
                    i += 1;
                },
                Option::None => break,
            }

            if remove {
                self.windows.remove(i);
            }
        }

        i = 0;
        while i < self.windows_ordered.len() {
            let mut remove = false;

            match self.windows_ordered.get(i) {
                Option::Some(window_ptr) => if *window_ptr == remove_window_ptr {
                    remove = true;
                } else {
                    i += 1;
                },
                Option::None => break,
            }

            if remove {
                self.windows_ordered.remove(i);
            }
        }

        self.redraw = cmp::max(self.redraw, event::REDRAW_ALL);
    }

    pub unsafe fn on_irq(&mut self, irq: u8) {
        for item in self.items.iter() {
            let reenable = scheduler::start_no_ints();
            item.on_irq(irq);
            scheduler::end_no_ints(reenable);
        }
    }

    pub unsafe fn on_poll(&mut self) {
        for item in self.items.iter() {
            let reenable = scheduler::start_no_ints();
            item.on_poll();
            scheduler::end_no_ints(reenable);
        }
    }

    pub fn open(&self, url: &URL) -> Box<Resource> {
        if url.scheme().len() == 0 {
            let mut list = String::new();

            for item in self.items.iter() {
                let scheme = item.scheme();
                if scheme.len() > 0 {
                    if list.len() > 0 {
                        list = list + "\n" + scheme;
                    } else {
                        list = scheme;
                    }
                }
            }

            box VecResource::new(URL::new(), ResourceType::Dir, list.to_utf8())
        } else {
            for item in self.items.iter() {
                if item.scheme() == url.scheme() {
                    return item.open(url);
                }
            }
            box NoneResource
        }
    }

    fn on_key(&mut self, key_event: KeyEvent) {
        if self.windows.len() > 0 {
            match self.windows.get(self.windows.len() - 1) {
                Option::Some(window_ptr) => {
                    unsafe {
                        (**window_ptr).on_key(key_event);
                        self.redraw = cmp::max(self.redraw, event::REDRAW_ALL);
                    }
                }
                Option::None => (),
            }
        }
    }

    fn on_mouse(&mut self, mouse_event: MouseEvent) {
        let mut catcher = -1;

        if mouse_event.y >= self.display.height as isize - 32 {
            if !mouse_event.left_button && self.last_mouse_event.left_button {
                let mut x = 0;
                for package in self.packages.iter() {
                    if package.icon.data.len() > 0 {
                        if mouse_event.x >= x &&
                           mouse_event.x < x + package.icon.size.width as isize {
                            execute(&package.binary, &package.url, &Vec::new());
                        }
                        x += package.icon.size.width as isize;
                    }
                }

                let mut chars = 32;
                while chars > 4 &&
                      (x as usize + (chars * 8 + 3 * 4) * self.windows.len()) >
                      self.display.width + 32 {
                    chars -= 1;
                }

                x += 4;
                for window_ptr in self.windows_ordered.iter() {
                    let w = (chars*8 + 2*4) as usize;
                    if mouse_event.x >= x && mouse_event.x < x + w as isize {
                        for j in 0..self.windows.len() {
                            match self.windows.get(j) {
                                Option::Some(catcher_window_ptr) =>
                                    if catcher_window_ptr == window_ptr {
                                    unsafe {
                                        if j == self.windows.len() - 1 {
                                            (**window_ptr).minimized = !(**window_ptr).minimized;
                                        } else {
                                            catcher = j as isize;
                                            (**window_ptr).minimized = false;
                                        }
                                    }
                                    break;
                                },
                                Option::None => break,
                            }
                        }
                        self.redraw = cmp::max(self.redraw, event::REDRAW_ALL);
                        break;
                    }
                    x += w as isize;
                }
            }
        } else {
            for reverse_i in 0..self.windows.len() {
                let i = self.windows.len() - 1 - reverse_i;
                match self.windows.get(i) {
                    Option::Some(window_ptr) => unsafe {
                        if (**window_ptr).on_mouse(mouse_event, catcher < 0) {
                            catcher = i as isize;

                            self.redraw = cmp::max(self.redraw, event::REDRAW_ALL);
                        }
                    },
                    Option::None => (),
                }
            }
        }

        if catcher >= 0 && catcher < self.windows.len() as isize - 1 {
            match self.windows.remove(catcher as usize) {
                Option::Some(window_ptr) => self.windows.push(window_ptr),
                Option::None => (),
            }
        }

        self.last_mouse_event = mouse_event;
    }

    pub unsafe fn redraw(&mut self) {
        if self.redraw > event::REDRAW_NONE {
            //if self.redraw >= REDRAW_ALL {
            self.display.set(Color::new(75, 163, 253));
            if self.background.data.len() > 0 {
                self.background.draw(&self.display,
                                     Point::new((self.display.width as isize -
                                                 self.background.size.width as isize) /
                                                2,
                                                (self.display.height as isize -
                                                 self.background.size.height as isize) /
                                                2));
            }

            for i in 0..self.windows.len() {
                match self.windows.get(i) {
                    Option::Some(window_ptr) => {
                        (**window_ptr).focused = i == self.windows.len() - 1;
                        (**window_ptr).draw(&self.display);
                    }
                    Option::None => (),
                }
            }

            self.display.rect(Point::new(0, self.display.height as isize - 32),
                              Size::new(self.display.width, 32),
                              Color::alpha(0, 0, 0, 128));

            let mut x = 0;
            for package in self.packages.iter() {
                if package.icon.data.len() > 0 {
                    let y = self.display.height as isize - package.icon.size.height as isize;
                    if self.mouse_point.y >= y && self.mouse_point.x >= x &&
                       self.mouse_point.x < x + package.icon.size.width as isize {
                        self.display.rect(Point::new(x, y),
                                          package.icon.size,
                                          Color::alpha(128, 128, 128, 128));

                        let mut c_x = x;
                        for c in package.name.chars() {
                            self.display
                                .char(Point::new(c_x, y - 16), c, Color::new(255, 255, 255));
                            c_x += 8;
                        }
                    }
                    package.icon.draw(&self.display, Point::new(x, y));
                    x += package.icon.size.width as isize;
                }
            }

            let mut chars = 32;
            while chars > 4 &&
                  (x as usize + (chars * 8 + 3 * 4) * self.windows.len()) >
                  self.display.width + 32 {
                chars -= 1;
            }

            x += 4;
            for window_ptr in self.windows_ordered.iter() {
                let w = (chars*8 + 2*4) as usize;
                self.display.rect(Point::new(x, self.display.height as isize - 32),
                                  Size::new(w, 32),
                                  (**window_ptr).border_color);
                x += 4;

                for i in 0..chars {
                    let c = (**window_ptr).title[i];
                    if c != '\0' {
                        self.display.char(Point::new(x, self.display.height as isize - 24),
                                          c,
                                          (**window_ptr).title_color);
                    }
                    x += 8;
                }
                x += 8;
            }

            if self.cursor.data.len() > 0 {
                self.display.image_alpha(self.mouse_point,
                                         self.cursor.data.as_ptr(),
                                         self.cursor.size);
            } else {
                self.display.char(Point::new(self.mouse_point.x - 3, self.mouse_point.y - 9),
                                  'X',
                                  Color::new(255, 255, 255));
            }
            //}

            let reenable = scheduler::start_no_ints();

            self.display.flip();

            /*
            if self.cursor.data.len() > 0 {
                self.display.image_alpha_onscreen(self.mouse_point, self.cursor.data.as_ptr(), self.cursor.size);
            } else {
                self.display.char_onscreen(Point::new(self.mouse_point.x - 3, self.mouse_point.y - 9), 'X', Color::new(255, 255, 255));
            }
            */

            self.redraw = event::REDRAW_NONE;

            scheduler::end_no_ints(reenable);
        }
    }

    pub fn event(&mut self, event: Event) {
        match event.to_option() {
            EventOption::Mouse(mouse_event) => self.on_mouse(mouse_event),
            EventOption::Key(key_event) => self.on_key(key_event),
            EventOption::Redraw(redraw_event) =>
                self.redraw = cmp::max(self.redraw, redraw_event.redraw),
            EventOption::Open(open_event) => {
                let url_string = open_event.url_string;

                if url_string.ends_with(".bin".to_string()) {
                    execute(&URL::from_string(&url_string),
                            &URL::new(),
                            &Vec::new());
                } else {
                    for package in self.packages.iter() {
                        let mut accepted = false;
                        for accept in package.accepts.iter() {
                            if url_string.ends_with(accept.substr(1, accept.len() - 1)) {
                                accepted = true;
                                break;
                            }
                        }
                        if accepted {
                            let mut args: Vec<String> = Vec::new();
                            args.push(url_string.clone());
                            execute(&package.binary, &package.url, &args);
                            break;
                        }
                    }
                }
            }
            _ => (),
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::collections::{BTreeMap, HashMap};
use std::path::{Path, PathBuf};

use quire::{parse_config, parse_string, Options};
use quire::validate as V;

use config::Settings;
use path_util::Expand;

#[derive(PartialEq, RustcDecodable, Debug)]
struct SecureSettings {
    storage_dir: Option<PathBuf>,
    storage_subdir_from_env_var: Option<String>,
    cache_dir: Option<PathBuf>,
    version_check: Option<bool>,
    proxy_env_vars: Option<bool>,
    ubuntu_mirror: Option<String>,
    alpine_mirror: Option<String>,
    site_settings: BTreeMap<PathBuf, SecureSettings>,
    external_volumes: HashMap<String, PathBuf>,
    push_image_script: Option<String>,
    build_lock_wait: Option<bool>,
    auto_apply_sysctl: Option<bool>,
    index_all_images: Option<bool>,
    hard_link_identical_files: Option<bool>,
    run_symlinks_as_commands: Option<bool>,
    disable_auto_clean: Option<bool>,
    environ: BTreeMap<String, String>,
}

pub fn secure_settings_validator<'a>(has_children: bool)
    -> V::Structure<'a>
{
    let mut s = V::Structure::new()
        .member("storage_dir", V::Scalar::new().optional())
        .member("storage_subdir_from_env_var", V::Scalar::new().optional())
        .member("cache_dir", V::Scalar::new().optional())
        .member("version_check", V::Scalar::new().optional())
        .member("proxy_env_vars", V::Scalar::new().optional())
        .member("ubuntu_mirror", V::Scalar::new().optional())
        .member("alpine_mirror", V::Scalar::new().optional())
        .member("external_volumes", V::Mapping::new(
            V::Directory::new().absolute(false),
            V::Directory::new().absolute(true)))
        .member("push_image_script", V::Scalar::new().optional())
        .member("build_lock_wait", V::Scalar::new().optional())
        .member("auto_apply_sysctl", V::Scalar::new().optional())
        .member("index_all_images", V::Scalar::new().optional())
        .member("hard_link_identical_files", V::Scalar::new().optional())
        .member("run_symlinks_as_commands", V::Scalar::new().optional())
        .member("environ", V::Mapping::new(
            V::Scalar::new(), V::Scalar::new()));
    if has_children {
        s = s.member("site_settings", V::Mapping::new(
            V::Scalar::new(),
            secure_settings_validator(false)));
    }
    return s;
}

#[derive(PartialEq, RustcDecodable)]
struct InsecureSettings {
    version_check: Option<bool>,
    shared_cache: Option<bool>,
    ubuntu_mirror: Option<String>,
    alpine_mirror: Option<String>,
    build_lock_wait: Option<bool>,
    run_symlinks_as_commands: Option<bool>,
    disable_auto_clean: Option<bool>,
    environ: BTreeMap<String, String>,
}

pub fn insecure_settings_validator<'a>() -> Box<V::Validator + 'a> {
    Box::new(V::Structure::new()
    .member("version_check", V::Scalar::new().optional())
    .member("shared_cache", V::Scalar::new().optional())
    .member("ubuntu_mirror", V::Scalar::new().optional())
    .member("alpine_mirror", V::Scalar::new().optional())
    .member("run_symlinks_as_commands", V::Scalar::new().optional())
    .member("environ", V::Mapping::new(
        V::Scalar::new(), V::Scalar::new())))
}

#[derive(Debug)]
pub struct MergedSettings {
    pub external_volumes: HashMap<String, PathBuf>,
    pub push_image_script: Option<String>,
    pub storage_dir: Option<PathBuf>,
    pub storage_subdir_from_env_var: Option<String>,
    pub cache_dir: Option<PathBuf>,
    pub shared_cache: bool,
    pub disable_auto_clean: bool,
}

fn merge_settings(cfg: SecureSettings, project_root: &Path,
    ext_settings: &mut MergedSettings, int_settings: &mut Settings)
    -> Result<(), String>
{
    if let Some(dir) = cfg.storage_dir {
        ext_settings.storage_dir = Some(dir.expand_home()
            .map_err(|()| format!("Can't expand tilde `~` in storage dir \
                no HOME found"))?);
    }
    if let Some(name) = cfg.storage_subdir_from_env_var {
        ext_settings.storage_subdir_from_env_var = Some(name.clone());
        int_settings.storage_subdir_from_env_var = Some(name.clone());
    }
    if let Some(dir) = cfg.cache_dir {
        ext_settings.cache_dir = Some(dir.expand_home()
            .map_err(|()| format!("Can't expand tilde `~` in cache dir \
                no HOME found"))?);
        ext_settings.shared_cache = true;
    }
    if let Some(val) = cfg.version_check {
        int_settings.version_check = val;
    }
    if let Some(val) = cfg.proxy_env_vars {
        int_settings.proxy_env_vars = val;
    }
    if let Some(ref val) = cfg.ubuntu_mirror {
        int_settings.ubuntu_mirror = Some(val.clone());
    }
    if let Some(ref val) = cfg.alpine_mirror {
        int_settings.alpine_mirror = Some(val.clone());
    }
    for (k, v) in &cfg.external_volumes {
        ext_settings.external_volumes.insert(k.clone(), v.clone());
    }
    if let Some(ref val) = cfg.push_image_script {
        int_settings.push_image_script = Some(val.clone());
    }
    if let Some(val) = cfg.build_lock_wait {
        int_settings.build_lock_wait = val;
    }
    if let Some(val) = cfg.auto_apply_sysctl {
        int_settings.auto_apply_sysctl = val;
    }
    if let Some(val) = cfg.index_all_images {
        int_settings.index_all_images = val;
    }
    if let Some(val) = cfg.hard_link_identical_files {
        int_settings.hard_link_identical_files = val;
    }
    if let Some(val) = cfg.run_symlinks_as_commands {
        int_settings.run_symlinks_as_commands = val;
    }
    if let Some(val) = cfg.disable_auto_clean {
        int_settings.disable_auto_clean = val;
    }
    for (k, v) in &cfg.environ {
        int_settings.environ.insert(k.clone(), v.clone());
    }
    if let Some(cfg) = cfg.site_settings.get(project_root) {
        if let Some(ref dir) = cfg.storage_dir {
            ext_settings.storage_dir = Some(dir.clone());
        }
        if let Some(ref name) = cfg.storage_subdir_from_env_var {
            ext_settings.storage_subdir_from_env_var = Some(name.clone());
            int_settings.storage_subdir_from_env_var = Some(name.clone());
        }
        if let Some(ref dir) = cfg.cache_dir {
            ext_settings.cache_dir = Some(dir.clone());
            ext_settings.shared_cache = true;
        }
        if let Some(val) = cfg.version_check {
            int_settings.version_check = val;
        }
        if let Some(ref val) = cfg.ubuntu_mirror {
            int_settings.ubuntu_mirror = Some(val.clone());
        }
        if let Some(ref val) = cfg.alpine_mirror {
            int_settings.alpine_mirror = Some(val.clone());
        }
        for (k, v) in &cfg.external_volumes {
            ext_settings.external_volumes.insert(k.clone(), v.clone());
        }
        if let Some(ref val) = cfg.push_image_script {
            int_settings.push_image_script = Some(val.clone());
        }
        if let Some(val) = cfg.build_lock_wait {
            int_settings.build_lock_wait = val;
        }
        if let Some(val) = cfg.auto_apply_sysctl {
            int_settings.auto_apply_sysctl = val;
        }
        if let Some(val) = cfg.index_all_images {
            int_settings.index_all_images = val;
        }
        if let Some(val) = cfg.hard_link_identical_files {
            int_settings.hard_link_identical_files = val;
        }
        if let Some(val) = cfg.run_symlinks_as_commands {
            int_settings.run_symlinks_as_commands = val;
        }
        if let Some(val) = cfg.disable_auto_clean {
            int_settings.disable_auto_clean = val;
        }
        for (k, v) in &cfg.environ {
            int_settings.environ.insert(k.clone(), v.clone());
        }
    }
    Ok(())
}

pub fn read_settings(project_root: &Path)
    -> Result<(MergedSettings, Settings), String>
{
    let mut ext_settings = MergedSettings {
        external_volumes: HashMap::new(),
        push_image_script: None,
        storage_dir: None,
        storage_subdir_from_env_var: None,
        cache_dir: None,
        shared_cache: false,
        disable_auto_clean: false,
    };
    let mut int_settings = Settings {
        proxy_env_vars: true,
        version_check: true,
        uid_map: None,
        ubuntu_mirror: None,
        alpine_mirror: None,
        push_image_script: None,
        build_lock_wait: false,
        auto_apply_sysctl: false,
        index_all_images: false,
        hard_link_identical_files: false,
        run_symlinks_as_commands: true,
        disable_auto_clean: false,
        environ: BTreeMap::new(),
        storage_subdir_from_env_var: None,
    };
    let mut secure_files = vec!();
    if let Ok(home) = env::var("_VAGGA_HOME") {
        let home = Path::new(&home);
        secure_files.push(home.join(".config/vagga/settings.yaml"));
        secure_files.push(home.join(".vagga/settings.yaml"));
        secure_files.push(home.join(".vagga.yaml"));
    };
    for filename in secure_files.iter() {
        if !filename.exists() {
            continue;
        }
        let cfg: SecureSettings = parse_config(filename,
            &secure_settings_validator(true), &Options::default())
            .map_err(|e| format!("{}", e))?;
        merge_settings(cfg, &project_root,
            &mut ext_settings, &mut int_settings)?
    }
    if let Ok(settings) = env::var("VAGGA_SETTINGS") {
        let cfg: SecureSettings = parse_string("<env:VAGGA_SETTINGS>",
                &settings,
                &secure_settings_validator(true), &Options::default())
            .map_err(|e| format!("{}", e))?;
        merge_settings(cfg, &project_root,
            &mut ext_settings, &mut int_settings)?
    }
    let mut insecure_files = vec!();
    insecure_files.push(project_root.join(".vagga.settings.yaml"));
    insecure_files.push(project_root.join(".vagga/settings.yaml"));
    for filename in insecure_files.iter() {
        if !filename.exists() {
            continue;
        }
        let cfg: InsecureSettings = parse_config(filename,
            &*insecure_settings_validator(), &Options::default())
            .map_err(|e| format!("{}", e))?;
        if let Some(val) = cfg.version_check {
            int_settings.version_check = val;
        }
        if let Some(ref val) = cfg.ubuntu_mirror {
            int_settings.ubuntu_mirror = Some(val.clone());
        }
        if let Some(ref val) = cfg.alpine_mirror {
            int_settings.alpine_mirror = Some(val.clone());
        }
        if let Some(val) = cfg.shared_cache {
            ext_settings.shared_cache = val;
        }
        if let Some(val) = cfg.build_lock_wait {
            int_settings.build_lock_wait = val;
        }
        if let Some(val) = cfg.run_symlinks_as_commands {
            int_settings.run_symlinks_as_commands = val;
        }
        for (k, v) in &cfg.environ {
            int_settings.environ.insert(k.clone(), v.clone());
        }
    }
    return Ok((ext_settings, int_settings));
}
<commit_msg>Fixes validator for `disable-auto-clean`<commit_after>use std::env;
use std::collections::{BTreeMap, HashMap};
use std::path::{Path, PathBuf};

use quire::{parse_config, parse_string, Options};
use quire::validate as V;

use config::Settings;
use path_util::Expand;

#[derive(PartialEq, RustcDecodable, Debug)]
struct SecureSettings {
    storage_dir: Option<PathBuf>,
    storage_subdir_from_env_var: Option<String>,
    cache_dir: Option<PathBuf>,
    version_check: Option<bool>,
    proxy_env_vars: Option<bool>,
    ubuntu_mirror: Option<String>,
    alpine_mirror: Option<String>,
    site_settings: BTreeMap<PathBuf, SecureSettings>,
    external_volumes: HashMap<String, PathBuf>,
    push_image_script: Option<String>,
    build_lock_wait: Option<bool>,
    auto_apply_sysctl: Option<bool>,
    index_all_images: Option<bool>,
    hard_link_identical_files: Option<bool>,
    run_symlinks_as_commands: Option<bool>,
    disable_auto_clean: Option<bool>,
    environ: BTreeMap<String, String>,
}

pub fn secure_settings_validator<'a>(has_children: bool)
    -> V::Structure<'a>
{
    let mut s = V::Structure::new()
        .member("storage_dir", V::Scalar::new().optional())
        .member("storage_subdir_from_env_var", V::Scalar::new().optional())
        .member("cache_dir", V::Scalar::new().optional())
        .member("version_check", V::Scalar::new().optional())
        .member("proxy_env_vars", V::Scalar::new().optional())
        .member("ubuntu_mirror", V::Scalar::new().optional())
        .member("alpine_mirror", V::Scalar::new().optional())
        .member("external_volumes", V::Mapping::new(
            V::Directory::new().absolute(false),
            V::Directory::new().absolute(true)))
        .member("push_image_script", V::Scalar::new().optional())
        .member("build_lock_wait", V::Scalar::new().optional())
        .member("auto_apply_sysctl", V::Scalar::new().optional())
        .member("index_all_images", V::Scalar::new().optional())
        .member("hard_link_identical_files", V::Scalar::new().optional())
        .member("run_symlinks_as_commands", V::Scalar::new().optional())
        .member("disable_auto_clean", V::Scalar::new().optional())
        .member("environ", V::Mapping::new(
            V::Scalar::new(), V::Scalar::new()));
    if has_children {
        s = s.member("site_settings", V::Mapping::new(
            V::Scalar::new(),
            secure_settings_validator(false)));
    }
    return s;
}

#[derive(PartialEq, RustcDecodable)]
struct InsecureSettings {
    version_check: Option<bool>,
    shared_cache: Option<bool>,
    ubuntu_mirror: Option<String>,
    alpine_mirror: Option<String>,
    build_lock_wait: Option<bool>,
    run_symlinks_as_commands: Option<bool>,
    disable_auto_clean: Option<bool>,
    environ: BTreeMap<String, String>,
}

pub fn insecure_settings_validator<'a>() -> Box<V::Validator + 'a> {
    Box::new(V::Structure::new()
    .member("version_check", V::Scalar::new().optional())
    .member("shared_cache", V::Scalar::new().optional())
    .member("ubuntu_mirror", V::Scalar::new().optional())
    .member("alpine_mirror", V::Scalar::new().optional())
    .member("run_symlinks_as_commands", V::Scalar::new().optional())
    .member("disable_auto_clean", V::Scalar::new().optional())
    .member("environ", V::Mapping::new(
        V::Scalar::new(), V::Scalar::new())))
}

#[derive(Debug)]
pub struct MergedSettings {
    pub external_volumes: HashMap<String, PathBuf>,
    pub push_image_script: Option<String>,
    pub storage_dir: Option<PathBuf>,
    pub storage_subdir_from_env_var: Option<String>,
    pub cache_dir: Option<PathBuf>,
    pub shared_cache: bool,
    pub disable_auto_clean: bool,
}

fn merge_settings(cfg: SecureSettings, project_root: &Path,
    ext_settings: &mut MergedSettings, int_settings: &mut Settings)
    -> Result<(), String>
{
    if let Some(dir) = cfg.storage_dir {
        ext_settings.storage_dir = Some(dir.expand_home()
            .map_err(|()| format!("Can't expand tilde `~` in storage dir \
                no HOME found"))?);
    }
    if let Some(name) = cfg.storage_subdir_from_env_var {
        ext_settings.storage_subdir_from_env_var = Some(name.clone());
        int_settings.storage_subdir_from_env_var = Some(name.clone());
    }
    if let Some(dir) = cfg.cache_dir {
        ext_settings.cache_dir = Some(dir.expand_home()
            .map_err(|()| format!("Can't expand tilde `~` in cache dir \
                no HOME found"))?);
        ext_settings.shared_cache = true;
    }
    if let Some(val) = cfg.version_check {
        int_settings.version_check = val;
    }
    if let Some(val) = cfg.proxy_env_vars {
        int_settings.proxy_env_vars = val;
    }
    if let Some(ref val) = cfg.ubuntu_mirror {
        int_settings.ubuntu_mirror = Some(val.clone());
    }
    if let Some(ref val) = cfg.alpine_mirror {
        int_settings.alpine_mirror = Some(val.clone());
    }
    for (k, v) in &cfg.external_volumes {
        ext_settings.external_volumes.insert(k.clone(), v.clone());
    }
    if let Some(ref val) = cfg.push_image_script {
        int_settings.push_image_script = Some(val.clone());
    }
    if let Some(val) = cfg.build_lock_wait {
        int_settings.build_lock_wait = val;
    }
    if let Some(val) = cfg.auto_apply_sysctl {
        int_settings.auto_apply_sysctl = val;
    }
    if let Some(val) = cfg.index_all_images {
        int_settings.index_all_images = val;
    }
    if let Some(val) = cfg.hard_link_identical_files {
        int_settings.hard_link_identical_files = val;
    }
    if let Some(val) = cfg.run_symlinks_as_commands {
        int_settings.run_symlinks_as_commands = val;
    }
    if let Some(val) = cfg.disable_auto_clean {
        int_settings.disable_auto_clean = val;
    }
    for (k, v) in &cfg.environ {
        int_settings.environ.insert(k.clone(), v.clone());
    }
    if let Some(cfg) = cfg.site_settings.get(project_root) {
        if let Some(ref dir) = cfg.storage_dir {
            ext_settings.storage_dir = Some(dir.clone());
        }
        if let Some(ref name) = cfg.storage_subdir_from_env_var {
            ext_settings.storage_subdir_from_env_var = Some(name.clone());
            int_settings.storage_subdir_from_env_var = Some(name.clone());
        }
        if let Some(ref dir) = cfg.cache_dir {
            ext_settings.cache_dir = Some(dir.clone());
            ext_settings.shared_cache = true;
        }
        if let Some(val) = cfg.version_check {
            int_settings.version_check = val;
        }
        if let Some(ref val) = cfg.ubuntu_mirror {
            int_settings.ubuntu_mirror = Some(val.clone());
        }
        if let Some(ref val) = cfg.alpine_mirror {
            int_settings.alpine_mirror = Some(val.clone());
        }
        for (k, v) in &cfg.external_volumes {
            ext_settings.external_volumes.insert(k.clone(), v.clone());
        }
        if let Some(ref val) = cfg.push_image_script {
            int_settings.push_image_script = Some(val.clone());
        }
        if let Some(val) = cfg.build_lock_wait {
            int_settings.build_lock_wait = val;
        }
        if let Some(val) = cfg.auto_apply_sysctl {
            int_settings.auto_apply_sysctl = val;
        }
        if let Some(val) = cfg.index_all_images {
            int_settings.index_all_images = val;
        }
        if let Some(val) = cfg.hard_link_identical_files {
            int_settings.hard_link_identical_files = val;
        }
        if let Some(val) = cfg.run_symlinks_as_commands {
            int_settings.run_symlinks_as_commands = val;
        }
        if let Some(val) = cfg.disable_auto_clean {
            int_settings.disable_auto_clean = val;
        }
        for (k, v) in &cfg.environ {
            int_settings.environ.insert(k.clone(), v.clone());
        }
    }
    Ok(())
}

pub fn read_settings(project_root: &Path)
    -> Result<(MergedSettings, Settings), String>
{
    let mut ext_settings = MergedSettings {
        external_volumes: HashMap::new(),
        push_image_script: None,
        storage_dir: None,
        storage_subdir_from_env_var: None,
        cache_dir: None,
        shared_cache: false,
        disable_auto_clean: false,
    };
    let mut int_settings = Settings {
        proxy_env_vars: true,
        version_check: true,
        uid_map: None,
        ubuntu_mirror: None,
        alpine_mirror: None,
        push_image_script: None,
        build_lock_wait: false,
        auto_apply_sysctl: false,
        index_all_images: false,
        hard_link_identical_files: false,
        run_symlinks_as_commands: true,
        disable_auto_clean: false,
        environ: BTreeMap::new(),
        storage_subdir_from_env_var: None,
    };
    let mut secure_files = vec!();
    if let Ok(home) = env::var("_VAGGA_HOME") {
        let home = Path::new(&home);
        secure_files.push(home.join(".config/vagga/settings.yaml"));
        secure_files.push(home.join(".vagga/settings.yaml"));
        secure_files.push(home.join(".vagga.yaml"));
    };
    for filename in secure_files.iter() {
        if !filename.exists() {
            continue;
        }
        let cfg: SecureSettings = parse_config(filename,
            &secure_settings_validator(true), &Options::default())
            .map_err(|e| format!("{}", e))?;
        merge_settings(cfg, &project_root,
            &mut ext_settings, &mut int_settings)?
    }
    if let Ok(settings) = env::var("VAGGA_SETTINGS") {
        let cfg: SecureSettings = parse_string("<env:VAGGA_SETTINGS>",
                &settings,
                &secure_settings_validator(true), &Options::default())
            .map_err(|e| format!("{}", e))?;
        merge_settings(cfg, &project_root,
            &mut ext_settings, &mut int_settings)?
    }
    let mut insecure_files = vec!();
    insecure_files.push(project_root.join(".vagga.settings.yaml"));
    insecure_files.push(project_root.join(".vagga/settings.yaml"));
    for filename in insecure_files.iter() {
        if !filename.exists() {
            continue;
        }
        let cfg: InsecureSettings = parse_config(filename,
            &*insecure_settings_validator(), &Options::default())
            .map_err(|e| format!("{}", e))?;
        if let Some(val) = cfg.version_check {
            int_settings.version_check = val;
        }
        if let Some(ref val) = cfg.ubuntu_mirror {
            int_settings.ubuntu_mirror = Some(val.clone());
        }
        if let Some(ref val) = cfg.alpine_mirror {
            int_settings.alpine_mirror = Some(val.clone());
        }
        if let Some(val) = cfg.shared_cache {
            ext_settings.shared_cache = val;
        }
        if let Some(val) = cfg.build_lock_wait {
            int_settings.build_lock_wait = val;
        }
        if let Some(val) = cfg.run_symlinks_as_commands {
            int_settings.run_symlinks_as_commands = val;
        }
        for (k, v) in &cfg.environ {
            int_settings.environ.insert(k.clone(), v.clone());
        }
    }
    return Ok((ext_settings, int_settings));
}
<|endoftext|>