<commit_before>use std::io::{Result, Write};

use analysis::rust_type::rust_type;
use codegen::general::{version_condition, version_condition_string};
use case::CaseExt;
use analysis;
use library;
use env::Env;
use nameutil;
use super::child_properties;
use super::function;
use super::general;
use super::properties;
use super::signal;
use super::trait_impls;
use super::trampoline;

pub fn generate(
    w: &mut Write,
    env: &Env,
    analysis: &analysis::object::Info,
    generate_display_trait: bool,
) -> Result<()> {
    try!(general::start_comments(w, &env.config));
    try!(general::uses(w, env, &analysis.imports));

    try!(general::define_object_type(
        w,
        env,
        &analysis.name,
        &analysis.c_type,
        &analysis.c_class_type.as_ref().map(|s| &s[..]),
        &analysis.rust_class_type.as_ref().map(|s| &s[..]),
        &analysis.get_type,
        analysis.is_interface,
        &analysis.supertypes,
    ));

    if need_generate_inherent(analysis) {
        try!(writeln!(w));
        try!(write!(w, "impl {} {{", analysis.name));
        for func_analysis in &analysis.constructors() {
            try!(function::generate(w, env, func_analysis, false, false, 1));
        }

        if !need_generate_trait(analysis) {
            for func_analysis in &analysis.methods() {
                try!(function::generate(w, env, func_analysis, false, false, 1));
            }

            for property in &analysis.properties {
                try!(properties::generate(w, env, property, false, false, 1));
            }

            for child_property in &analysis.child_properties {
                try!(child_properties::generate(
                    w,
                    env,
                    child_property,
                    false,
                    false,
                    1,
                ));
            }
        }

        for func_analysis in &analysis.functions() {
            try!(function::generate(w, env, func_analysis, false, false, 1));
        }

        if !need_generate_trait(analysis) {
            for signal_analysis in analysis
                .signals
                .iter()
                .chain(analysis.notify_signals.iter())
            {
                try!(signal::generate(
                    w,
                    env,
                    signal_analysis,
                    &analysis.trampolines,
                    false,
                    false,
                    1,
                ));
            }
        }

        try!(writeln!(w, "}}"));

        try!(general::declare_default_from_new(
            w,
            env,
            &analysis.name,
            &analysis.functions
        ));
    }

    try!(trait_impls::generate(
        w,
        &analysis.name,
        &analysis.functions,
        &analysis.specials,
        if need_generate_trait(analysis) {
            Some(&analysis.trait_name)
        } else {
            None
        },
    ));

    if analysis.concurrency != library::Concurrency::None {
        try!(writeln!(w));
    }

    // TODO: include parent and writable properties.
    if !analysis.builder_properties.is_empty() {
        let mut methods = vec![];
        let mut properties = vec![];
        writeln!(w, "#[cfg(any(feature = \"builders\", feature = \"dox\"))]
pub struct {}Builder {{", analysis.name)?;
        for property in &analysis.builder_properties {
            match rust_type(env, property.typ) {
                Ok(type_string) => {
                    let type_string =
                        match type_string.as_str() {
                            "GString" => "String",
                            "Vec<GString>" => "Vec<String>",
                            typ => typ,
                        };
                    let (param_type, conversion) =
                        match type_string {
                            "String" => ("&str", ".to_string()"),
                            typ => (typ, ""),
                        };
                    let name = nameutil::mangle_keywords(nameutil::signal_to_snake(&property.name));
                    version_condition(w, env, property.version, false, 1)?;
                    writeln!(w, "    {}: Option<{}>,", name, type_string)?;
                    let prefix = version_condition_string(env, property.version, false, 1).unwrap_or_default();
                    methods.push(format!("\n{prefix}    pub fn {name}(mut self, {name}: {param_type}) -> Self {{
        self.{name} = Some({name}{conversion});
        self
    }}", prefix=prefix, param_type=param_type, name=name, conversion=conversion));
                    properties.push(property);
                },
                Err(_) => writeln!(w, "    //{}: /*Unknown type*/,", property.name)?,
            }
        }
        writeln!(w, "}}\n

#[cfg(any(feature = \"builders\", feature = \"dox\"))]
impl {}Builder {{
    pub fn new() -> Self {{
        Self {{", analysis.name)?;
        for property in &properties {
            version_condition(w, env, property.version, false, 3)?;
            let name = nameutil::mangle_keywords(nameutil::signal_to_snake(&property.name));
            writeln!(w, "            {}: None,", name)?;
        }
        writeln!(w, "        }}
    }}

    pub fn build(self) -> {} {{
        let mut properties: Vec<(&str, &dyn ToValue)> = vec![];", analysis.name)?;
        for property in &properties {
            let name = nameutil::mangle_keywords(nameutil::signal_to_snake(&property.name));
            version_condition(w, env, property.version, false, 2)?;
            if property.version.is_some() {
                writeln!(w, "        {{")?;
            }
            writeln!(w,
"        if let Some(ref {property}) = self.{property} {{
            properties.push((\"{}\", {property}));
        }}", property = name)?;
            if property.version.is_some() {
                writeln!(w, "        }}")?;
            }
        }
        writeln!(w,
"        crate::Object::new({}::static_type(), &properties).expect(\"object new\").downcast().expect(\"downcast\")
    }}", analysis.name)?;
        for method in methods {
            writeln!(w, "{}", method)?;
        }
        writeln!(w, "}}")?;
    }

    match analysis.concurrency {
        library::Concurrency::Send | library::Concurrency::SendSync => {
            try!(writeln!(w, "unsafe impl Send for {} {{}}", analysis.name));
        }
        library::Concurrency::SendUnique => {
            if env.namespaces.is_glib_crate {
                try!(writeln!(w, "unsafe impl ::SendUnique for {} {{", analysis.name));
            } else {
                try!(writeln!(w, "unsafe impl glib::SendUnique for {} {{", analysis.name));
            }

            try!(writeln!(w, "    fn is_unique(&self) -> bool {{"));
            try!(writeln!(w, "        self.ref_count() == 1"));
            try!(writeln!(w, "    }}"));

            try!(writeln!(w, "}}"));
        },
        _ => (),
    }

    if let library::Concurrency::SendSync = analysis.concurrency {
        try!(writeln!(w, "unsafe impl Sync for {} {{}}", analysis.name));
    }

    if !analysis.final_type {
        try!(writeln!(w));
        try!(writeln!(w, "pub const NONE_{}: Option<&{}> = None;", analysis.name.to_snake().to_uppercase(), analysis.name));
    }

    if need_generate_trait(analysis) {
        try!(writeln!(w));
        try!(generate_trait(w, env, analysis));
    }

    if !analysis.trampolines.is_empty() {
        for trampoline in &analysis.trampolines {
            try!(trampoline::generate(
                w,
                env,
                trampoline,
                need_generate_trait(analysis),
                &analysis.name,
            ));
        }
    }

    if generate_display_trait {
        try!(writeln!(
            w,
            "\nimpl fmt::Display for {} {{",
            analysis.name,
        ));
        // Generate Display trait implementation.
        try!(writeln!(w, "\tfn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {{\n\
                            \t\twrite!(f, \"{}\")\n\
                          \t}}\n\
                        }}", analysis.name));
    }

    Ok(())
}

fn generate_trait(
    w: &mut Write,
    env: &Env,
    analysis: &analysis::object::Info,
) -> Result<()> {
    try!(write!(w, "pub trait {}: 'static {{", analysis.trait_name));

    for func_analysis in &analysis.methods() {
        try!(function::generate(w, env, func_analysis, true, true, 1));
    }
    for property in &analysis.properties {
        try!(properties::generate(w, env, property, true, true, 1));
    }
    for child_property in &analysis.child_properties {
        try!(child_properties::generate(
            w,
            env,
            child_property,
            true,
            true,
            1,
        ));
    }
    for signal_analysis in analysis
        .signals
        .iter()
        .chain(analysis.notify_signals.iter())
    {
        try!(signal::generate(
            w,
            env,
            signal_analysis,
            &analysis.trampolines,
            true,
            true,
            1,
        ));
    }
    try!(writeln!(w, "}}"));

    try!(writeln!(w));
    try!(write!(
        w,
        "impl<O: IsA<{}>> {} for O {{",
        analysis.name,
        analysis.trait_name,
    ));

    for func_analysis in &analysis.methods() {
        try!(function::generate(w, env, func_analysis, true, false, 1));
    }
    for property in &analysis.properties {
        try!(properties::generate(w, env, property, true, false, 1));
    }
    for child_property in &analysis.child_properties {
        try!(child_properties::generate(
            w,
            env,
            child_property,
            true,
            false,
            1,
        ));
    }
    for signal_analysis in analysis
        .signals
        .iter()
        .chain(analysis.notify_signals.iter())
    {
        try!(signal::generate(
            w,
            env,
            signal_analysis,
            &analysis.trampolines,
            true,
            false,
            1,
        ));
    }
    try!(writeln!(w, "}}"));

    Ok(())
}

fn need_generate_inherent(analysis: &analysis::object::Info) -> bool {
    analysis.has_constructors || analysis.has_functions || !need_generate_trait(analysis)
}

fn need_generate_trait(analysis: &analysis::object::Info) -> bool {
    analysis.generate_trait
}

pub fn generate_reexports(
    env: &Env,
    analysis: &analysis::object::Info,
    module_name: &str,
    contents: &mut Vec<String>,
    traits: &mut Vec<String>,
) {
    let mut cfgs: Vec<String> = Vec::new();
    if let Some(cfg) = general::cfg_condition_string(&analysis.cfg_condition, false, 0) {
        cfgs.push(cfg);
    }
    if let Some(cfg) = general::version_condition_string(env, analysis.version, false, 0) {
        cfgs.push(cfg);
    }
    contents.push("".to_owned());
    contents.extend_from_slice(&cfgs);
    contents.push(format!("mod {};", module_name));
    contents.extend_from_slice(&cfgs);

    let none_type = if !analysis.final_type {
        format!(", NONE_{}", analysis.name.to_snake().to_uppercase())
    } else {
        String::new()
    };

    if let Some(ref class_name) = analysis.rust_class_type {
        contents.push(format!("pub use self::{}::{{{}, {}{}}};", module_name, analysis.name, class_name, none_type));
    } else {
        contents.push(format!("pub use self::{}::{{{}{}}};", module_name, analysis.name, none_type));
    }
    if need_generate_trait(analysis) {
        contents.extend_from_slice(&cfgs);
        contents.push(format!(
            "pub use self::{}::{};",
            module_name,
            analysis.trait_name
        ));
        for cfg in &cfgs {
            traits.push(format!("\t{}", cfg));
        }
        traits.push(format!("\tpub use super::{};", analysis.trait_name));
    }

    if !analysis.builder_properties.is_empty() {
        contents.extend_from_slice(&cfgs);
        contents.push(format!("#[cfg(any(feature = \"builders\", feature = \"dox\"))]
pub use self::{}::{}Builder;", module_name, analysis.name));
    }
}
<commit_msg>Move to function<commit_after>use std::io::{Result, Write};

use analysis::rust_type::rust_type;
use codegen::general::{version_condition, version_condition_string};
use case::CaseExt;
use analysis;
use library;
use env::Env;
use nameutil;
use super::child_properties;
use super::function;
use super::general;
use super::properties;
use super::signal;
use super::trait_impls;
use super::trampoline;

pub fn generate(
    w: &mut Write,
    env: &Env,
    analysis: &analysis::object::Info,
    generate_display_trait: bool,
) -> Result<()> {
    try!(general::start_comments(w, &env.config));
    try!(general::uses(w, env, &analysis.imports));

    try!(general::define_object_type(
        w,
        env,
        &analysis.name,
        &analysis.c_type,
        &analysis.c_class_type.as_ref().map(|s| &s[..]),
        &analysis.rust_class_type.as_ref().map(|s| &s[..]),
        &analysis.get_type,
        analysis.is_interface,
        &analysis.supertypes,
    ));

    if need_generate_inherent(analysis) {
        try!(writeln!(w));
        try!(write!(w, "impl {} {{", analysis.name));
        for func_analysis in &analysis.constructors() {
            try!(function::generate(w, env, func_analysis, false, false, 1));
        }

        if !need_generate_trait(analysis) {
            for func_analysis in &analysis.methods() {
                try!(function::generate(w, env, func_analysis, false, false, 1));
            }

            for property in &analysis.properties {
                try!(properties::generate(w, env, property, false, false, 1));
            }

            for child_property in &analysis.child_properties {
                try!(child_properties::generate(
                    w,
                    env,
                    child_property,
                    false,
                    false,
                    1,
                ));
            }
        }

        for func_analysis in &analysis.functions() {
            try!(function::generate(w, env, func_analysis, false, false, 1));
        }

        if !need_generate_trait(analysis) {
            for signal_analysis in analysis
                .signals
                .iter()
                .chain(analysis.notify_signals.iter())
            {
                try!(signal::generate(
                    w,
                    env,
                    signal_analysis,
                    &analysis.trampolines,
                    false,
                    false,
                    1,
                ));
            }
        }

        try!(writeln!(w, "}}"));

        try!(general::declare_default_from_new(
            w,
            env,
            &analysis.name,
            &analysis.functions
        ));
    }

    try!(trait_impls::generate(
        w,
        &analysis.name,
        &analysis.functions,
        &analysis.specials,
        if need_generate_trait(analysis) {
            Some(&analysis.trait_name)
        } else {
            None
        },
    ));

    if analysis.concurrency != library::Concurrency::None {
        try!(writeln!(w));
    }

    // TODO: include parent properties.
    if !analysis.builder_properties.is_empty() {
        generate_builder(w, env, analysis)?;
    }

    match analysis.concurrency {
        library::Concurrency::Send | library::Concurrency::SendSync => {
            try!(writeln!(w, "unsafe impl Send for {} {{}}", analysis.name));
        }
        library::Concurrency::SendUnique => {
            if env.namespaces.is_glib_crate {
                try!(writeln!(w, "unsafe impl ::SendUnique for {} {{", analysis.name));
            } else {
                try!(writeln!(w, "unsafe impl glib::SendUnique for {} {{", analysis.name));
            }

            try!(writeln!(w, "    fn is_unique(&self) -> bool {{"));
            try!(writeln!(w, "        self.ref_count() == 1"));
            try!(writeln!(w, "    }}"));

            try!(writeln!(w, "}}"));
        },
        _ => (),
    }

    if let library::Concurrency::SendSync = analysis.concurrency {
        try!(writeln!(w, "unsafe impl Sync for {} {{}}", analysis.name));
    }

    if !analysis.final_type {
        try!(writeln!(w));
        try!(writeln!(w, "pub const NONE_{}: Option<&{}> = None;", analysis.name.to_snake().to_uppercase(), analysis.name));
    }

    if need_generate_trait(analysis) {
        try!(writeln!(w));
        try!(generate_trait(w, env, analysis));
    }

    if !analysis.trampolines.is_empty() {
        for trampoline in &analysis.trampolines {
            try!(trampoline::generate(
                w,
                env,
                trampoline,
                need_generate_trait(analysis),
                &analysis.name,
            ));
        }
    }

    if generate_display_trait {
        try!(writeln!(
            w,
            "\nimpl fmt::Display for {} {{",
            analysis.name,
        ));
        // Generate Display trait implementation.
        try!(writeln!(w, "\tfn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {{\n\
                            \t\twrite!(f, \"{}\")\n\
                          \t}}\n\
                        }}", analysis.name));
    }

    Ok(())
}

fn generate_builder(w: &mut Write, env: &Env, analysis: &analysis::object::Info) -> Result<()> {
    let mut methods = vec![];
    let mut properties = vec![];
    writeln!(w, "#[cfg(any(feature = \"builders\", feature = \"dox\"))]
pub struct {}Builder {{", analysis.name)?;
    for property in &analysis.builder_properties {
        match rust_type(env, property.typ) {
            Ok(type_string) => {
                let type_string =
                    match type_string.as_str() {
                        "GString" => "String",
                        "Vec<GString>" => "Vec<String>",
                        typ => typ,
                    };
                let (param_type, conversion) =
                    match type_string {
                        "String" => ("&str", ".to_string()"),
                        typ => (typ, ""),
                    };
                let name = nameutil::mangle_keywords(nameutil::signal_to_snake(&property.name));
                version_condition(w, env, property.version, false, 1)?;
                writeln!(w, "    {}: Option<{}>,", name, type_string)?;
                let prefix = version_condition_string(env, property.version, false, 1).unwrap_or_default();
                methods.push(format!("\n{prefix}    pub fn {name}(mut self, {name}: {param_type}) -> Self {{
        self.{name} = Some({name}{conversion});
        self
    }}", prefix=prefix, param_type=param_type, name=name, conversion=conversion));
                properties.push(property);
            },
            Err(_) => writeln!(w, "    //{}: /*Unknown type*/,", property.name)?,
        }
    }
    writeln!(w, "}}\n

#[cfg(any(feature = \"builders\", feature = \"dox\"))]
impl {}Builder {{
    pub fn new() -> Self {{
        Self {{", analysis.name)?;
    for property in &properties {
        version_condition(w, env, property.version, false, 3)?;
        let name = nameutil::mangle_keywords(nameutil::signal_to_snake(&property.name));
        writeln!(w, "            {}: None,", name)?;
    }
    writeln!(w, "        }}
    }}

    pub fn build(self) -> {} {{
        let mut properties: Vec<(&str, &dyn ToValue)> = vec![];", analysis.name)?;
    for property in &properties {
        let name = nameutil::mangle_keywords(nameutil::signal_to_snake(&property.name));
        version_condition(w, env, property.version, false, 2)?;
        if property.version.is_some() {
            writeln!(w, "        {{")?;
        }
        writeln!(w,
"        if let Some(ref {property}) = self.{property} {{
            properties.push((\"{}\", {property}));
        }}", property = name)?;
        if property.version.is_some() {
            writeln!(w, "        }}")?;
        }
    }
    writeln!(w,
"        crate::Object::new({}::static_type(), &properties).expect(\"object new\").downcast().expect(\"downcast\")
    }}", analysis.name)?;
    for method in methods {
        writeln!(w, "{}", method)?;
    }
    writeln!(w, "}}")
}

fn generate_trait(
    w: &mut Write,
    env: &Env,
    analysis: &analysis::object::Info,
) -> Result<()> {
    try!(write!(w, "pub trait {}: 'static {{", analysis.trait_name));

    for func_analysis in &analysis.methods() {
        try!(function::generate(w, env, func_analysis, true, true, 1));
    }
    for property in &analysis.properties {
        try!(properties::generate(w, env, property, true, true, 1));
    }
    for child_property in &analysis.child_properties {
        try!(child_properties::generate(
            w,
            env,
            child_property,
            true,
            true,
            1,
        ));
    }
    for signal_analysis in analysis
        .signals
        .iter()
        .chain(analysis.notify_signals.iter())
    {
        try!(signal::generate(
            w,
            env,
            signal_analysis,
            &analysis.trampolines,
            true,
            true,
            1,
        ));
    }
    try!(writeln!(w, "}}"));

    try!(writeln!(w));
    try!(write!(
        w,
        "impl<O: IsA<{}>> {} for O {{",
        analysis.name,
        analysis.trait_name,
    ));

    for func_analysis in &analysis.methods() {
        try!(function::generate(w, env, func_analysis, true, false, 1));
    }
    for property in &analysis.properties {
        try!(properties::generate(w, env, property, true, false, 1));
    }
    for child_property in &analysis.child_properties {
        try!(child_properties::generate(
            w,
            env,
            child_property,
            true,
            false,
            1,
        ));
    }
    for signal_analysis in analysis
        .signals
        .iter()
        .chain(analysis.notify_signals.iter())
    {
        try!(signal::generate(
            w,
            env,
            signal_analysis,
            &analysis.trampolines,
            true,
            false,
            1,
        ));
    }
    try!(writeln!(w, "}}"));

    Ok(())
}

fn need_generate_inherent(analysis: &analysis::object::Info) -> bool {
    analysis.has_constructors || analysis.has_functions || !need_generate_trait(analysis)
}

fn need_generate_trait(analysis: &analysis::object::Info) -> bool {
    analysis.generate_trait
}

pub fn generate_reexports(
    env: &Env,
    analysis: &analysis::object::Info,
    module_name: &str,
    contents: &mut Vec<String>,
    traits: &mut Vec<String>,
) {
    let mut cfgs: Vec<String> = Vec::new();
    if let Some(cfg) = general::cfg_condition_string(&analysis.cfg_condition, false, 0) {
        cfgs.push(cfg);
    }
    if let Some(cfg) = general::version_condition_string(env, analysis.version, false, 0) {
        cfgs.push(cfg);
    }
    contents.push("".to_owned());
    contents.extend_from_slice(&cfgs);
    contents.push(format!("mod {};", module_name));
    contents.extend_from_slice(&cfgs);

    let none_type = if !analysis.final_type {
        format!(", NONE_{}", analysis.name.to_snake().to_uppercase())
    } else {
        String::new()
    };

    if let Some(ref class_name) = analysis.rust_class_type {
        contents.push(format!("pub use self::{}::{{{}, {}{}}};", module_name, analysis.name, class_name, none_type));
    } else {
        contents.push(format!("pub use self::{}::{{{}{}}};", module_name, analysis.name, none_type));
    }
    if need_generate_trait(analysis) {
        contents.extend_from_slice(&cfgs);
        contents.push(format!(
            "pub use self::{}::{};",
            module_name,
            analysis.trait_name
        ));
        for cfg in &cfgs {
            traits.push(format!("\t{}", cfg));
        }
        traits.push(format!("\tpub use super::{};", analysis.trait_name));
    }

    if !analysis.builder_properties.is_empty() {
        contents.extend_from_slice(&cfgs);
        contents.push(format!("#[cfg(any(feature = \"builders\", feature = \"dox\"))]
pub use self::{}::{}Builder;", module_name, analysis.name));
    }
}
<|endoftext|>


<commit_before>use alloc::boxed::*;

use core::ptr;

use common::memory::*;
use common::paging::*;
use common::scheduler::*;
use common::vec::*;

pub const CONTEXT_STACK_SIZE: usize = 1024*1024;

pub static mut contexts_ptr: *mut Box<Vec<Context>> = 0 as *mut Box<Vec<Context>>;
pub static mut context_i: usize = 0;
pub static mut context_enabled: bool = false;

pub unsafe fn context_switch(interrupted: bool){
    let reenable = start_no_ints();

    let contexts = &*(*contexts_ptr);
    if context_enabled {
        let current_i = context_i;
        context_i += 1;
        if context_i >= contexts.len(){
            context_i -= contexts.len();
        }
        if context_i != current_i {
            match contexts.get(current_i){
                Option::Some(current) => match contexts.get(context_i) {
                    Option::Some(next) => {
                        current.interrupted = interrupted;
                        next.interrupted = false;
                        current.remap(next);
                        current.switch(next);
                    },
                    Option::None => ()
                },
                Option::None => ()
            }
        }
    }

    end_no_ints(reenable);
}

//TODO: To clean up memory leak, current must be destroyed!
pub unsafe extern "cdecl" fn context_exit() {
    let reenable = start_no_ints();

    let contexts = &mut *(*contexts_ptr);

    if contexts.len() > 1 && context_i > 1 {
        let current_option = contexts.remove(context_i);

        if context_i >= contexts.len() {
            context_i -= contexts.len();
        }
        match current_option {
            Option::Some(mut current) => match contexts.get(context_i) {
                Option::Some(next) => {
                    current.remap(next);
                    current.switch(next);
                },
                Option::None => ()
            },
            Option::None => ()
        }
    }

    end_no_ints(reenable);
}

pub unsafe extern "cdecl" fn context_box(box_fn_ptr: usize){
    let box_fn = ptr::read(box_fn_ptr as *mut Box<FnBox()>);
    unalloc(box_fn_ptr);
    box_fn();
}

pub struct ContextMemory {
    pub physical_address: usize,
    pub virtual_address: usize,
    pub virtual_size: usize,
    pub cleanup: bool
}

pub struct Context {
    pub stack: usize,
    pub stack_ptr: u32,
    pub fx: usize,
    pub memory: Vec<ContextMemory>,
    pub interrupted: bool
}

impl Context {
    pub unsafe fn root() -> Context {
        let ret = Context {
            stack: 0,
            stack_ptr: 0,
            fx: alloc(512),
            memory: Vec::new(),
            interrupted: false
        };

        for i in 0..512 {
            ptr::write((ret.fx + i) as *mut u8, 0);
        }

        return ret;
    }

    pub unsafe fn new(call: usize, args: &Vec<usize>) -> Context {
        let stack = alloc(CONTEXT_STACK_SIZE);

        let mut ret = Context {
            stack: stack,
            stack_ptr: (stack + CONTEXT_STACK_SIZE) as u32,
            fx: alloc(512),
            memory: Vec::new(),
            interrupted: false
        };

        let ebp = ret.stack_ptr;

        for arg in args.iter() {
            ret.push(*arg as u32);
        }

        ret.push(context_exit as u32); //If the function call returns, we will exit
        ret.push(call as u32); //We will ret into this function call

        ret.push(0); //ESI is a param used in the switch function

        ret.push(1 << 9); //Flags

        let esp = ret.stack_ptr;

        ret.push(0); //EAX
        ret.push(0); //ECX
        ret.push(0); //EDX
        ret.push(0); //EBX
        ret.push(esp); //ESP (ignored)
        ret.push(ebp); //EBP
        ret.push(0); //ESI
        ret.push(0); //EDI

        for i in 0..512 {
            ptr::write((ret.fx + i) as *mut u8, 0);
        }

        return ret;
    }

    pub fn spawn(box_fn: Box<FnBox()>) {
        unsafe{
            let box_fn_ptr: *mut Box<FnBox()> = alloc_type();
            ptr::write(box_fn_ptr, box_fn);

            let mut context_box_args: Vec<usize> = Vec::new();
            context_box_args.push(box_fn_ptr as usize);

            let reenable = start_no_ints();
            if contexts_ptr as usize > 0 {
                (*contexts_ptr).push(Context::new(context_box as usize, &context_box_args));
            }
            end_no_ints(reenable);
        }
    }

    pub unsafe fn push(&mut self, data: u32){
        self.stack_ptr -= 4;
        ptr::write(self.stack_ptr as *mut u32, data);
    }

    pub unsafe fn map(&mut self){
        for entry in self.memory.iter() {
            for i in 0..(entry.virtual_size + 4095)/4096 {
                set_page(entry.virtual_address + i*4096, entry.physical_address + i*4096);
            }
        }
    }

    pub unsafe fn unmap(&mut self){
        for entry in self.memory.iter() {
            for i in 0..(entry.virtual_size + 4095)/4096 {
                identity_page(entry.virtual_address + i*4096);
            }
        }
    }

    pub unsafe fn remap(&mut self, other: &mut Context){
        self.unmap();
        other.map();
    }

    //Warning: This function MUST be inspected in disassembly for correct push/pop
    //It should have exactly one extra push/pop of ESI
    #[cold]
    #[inline(never)]
    pub unsafe fn switch(&mut self, other: &mut Context){
        asm!("pushfd
            pushad
            mov [esi], esp"
            :
            : "{esi}"(&mut self.stack_ptr)
            : "memory"
            : "intel", "volatile");

        asm!("fxsave [esi]"
            :
            : "{esi}"(self.fx)
            : "memory"
            : "intel", "volatile");

        asm!("fxrstor [esi]"
            :
            : "{esi}"(other.fx)
            : "memory"
            : "intel", "volatile");

        asm!("mov esp, [esi]
            popad
            popfd"
            :
            : "{esi}"(&mut other.stack_ptr)
            : "memory"
            : "intel", "volatile");
    }
}

impl Drop for Context {
    fn drop(&mut self){
        /*
        while Option::Some(entry) = self.memory.pop() {
            if entry.cleanup {
                d("Application forgot to free ");
                dh(entry.physical_address);
                dl();
                unalloc(entry.physical_address);
            }
        }
        */

        if self.stack > 0 {
            unsafe {
                unalloc(self.stack);
            }
        }

        if self.fx > 0 {
            unsafe {
                unalloc(self.fx);
            }
        }
    }
}
<commit_msg>Fix memory leaks<commit_after>use alloc::boxed::*;

use core::ptr;

use common::memory::*;
use common::paging::*;
use common::scheduler::*;
use common::vec::*;

pub const CONTEXT_STACK_SIZE: usize = 1024*1024;

pub static mut contexts_ptr: *mut Box<Vec<Context>> = 0 as *mut Box<Vec<Context>>;
pub static mut context_i: usize = 0;
pub static mut context_enabled: bool = false;

pub unsafe fn context_switch(interrupted: bool){
    let reenable = start_no_ints();

    let contexts = &mut *(*contexts_ptr);
    if context_enabled {
        let current_i = context_i;
        //The only garbage collection in Redox
        loop {
            context_i += 1;
            if context_i >= contexts.len(){
                context_i -= contexts.len();
            }

            let mut remove = false;
            if let Option::Some(next) = contexts.get(context_i) {
                if next.exited {
                    remove = true;
                }
            }

            if remove {
                drop(contexts.remove(context_i));
            }else{
                break;
            }
        }

        if context_i != current_i {
            match contexts.get(current_i){
                Option::Some(current) => match contexts.get(context_i) {
                    Option::Some(next) => {
                        current.interrupted = interrupted;
                        next.interrupted = false;
                        current.remap(next);
                        current.switch(next);
                    },
                    Option::None => ()
                },
                Option::None => ()
            }
        }
    }

    end_no_ints(reenable);
}

//TODO: To clean up memory leak, current must be destroyed!
pub unsafe extern "cdecl" fn context_exit() {
    let reenable = start_no_ints();

    let contexts = &*(*contexts_ptr);
    if context_enabled && context_i > 1 {
        match contexts.get(context_i) {
            Option::Some(mut current) => current.exited = true,
            Option::None => ()
        }
        context_switch(false);
    }

    end_no_ints(reenable);
}

pub unsafe extern "cdecl" fn context_box(box_fn_ptr: usize){
    let box_fn = ptr::read(box_fn_ptr as *mut Box<FnBox()>);
    unalloc(box_fn_ptr);
    box_fn();
}

pub struct ContextMemory {
    pub physical_address: usize,
    pub virtual_address: usize,
    pub virtual_size: usize,
    pub cleanup: bool
}

pub struct Context {
    pub stack: usize,
    pub stack_ptr: u32,
    pub fx: usize,
    pub memory: Vec<ContextMemory>,
    pub interrupted: bool,
    pub exited: bool
}

impl Context {
    pub unsafe fn root() -> Context {
        let ret = Context {
            stack: 0,
            stack_ptr: 0,
            fx: alloc(512),
            memory: Vec::new(),
            interrupted: false,
            exited: false
        };

        for i in 0..512 {
            ptr::write((ret.fx + i) as *mut u8, 0);
        }

        return ret;
    }

    pub unsafe fn new(call: usize, args: &Vec<usize>) -> Context {
        let stack = alloc(CONTEXT_STACK_SIZE + 512);

        let mut ret = Context {
            stack: stack,
            stack_ptr: (stack + CONTEXT_STACK_SIZE) as u32,
            fx: stack + CONTEXT_STACK_SIZE,
            memory: Vec::new(),
            interrupted: false,
            exited: false
        };

        let ebp = ret.stack_ptr;

        for arg in args.iter() {
            ret.push(*arg as u32);
        }

        ret.push(context_exit as u32); //If the function call returns, we will exit
        ret.push(call as u32); //We will ret into this function call

        ret.push(0); //ESI is a param used in the switch function

        ret.push(1 << 9); //Flags

        let esp = ret.stack_ptr;

        ret.push(0); //EAX
        ret.push(0); //ECX
        ret.push(0); //EDX
        ret.push(0); //EBX
        ret.push(esp); //ESP (ignored)
        ret.push(ebp); //EBP
        ret.push(0); //ESI
        ret.push(0); //EDI

        for i in 0..512 {
            ptr::write((ret.fx + i) as *mut u8, 0);
        }

        return ret;
    }

    pub fn spawn(box_fn: Box<FnBox()>) {
        unsafe{
            let box_fn_ptr: *mut Box<FnBox()> = alloc_type();
            ptr::write(box_fn_ptr, box_fn);

            let mut context_box_args: Vec<usize> = Vec::new();
            context_box_args.push(box_fn_ptr as usize);

            let reenable = start_no_ints();
            if contexts_ptr as usize > 0 {
                (*contexts_ptr).push(Context::new(context_box as usize, &context_box_args));
            }
            end_no_ints(reenable);
        }
    }

    pub unsafe fn push(&mut self, data: u32){
        self.stack_ptr -= 4;
        ptr::write(self.stack_ptr as *mut u32, data);
    }

    pub unsafe fn map(&mut self){
        for entry in self.memory.iter() {
            for i in 0..(entry.virtual_size + 4095)/4096 {
                set_page(entry.virtual_address + i*4096, entry.physical_address + i*4096);
            }
        }
    }

    pub unsafe fn unmap(&mut self){
        for entry in self.memory.iter() {
            for i in 0..(entry.virtual_size + 4095)/4096 {
                identity_page(entry.virtual_address + i*4096);
            }
        }
    }

    pub unsafe fn remap(&mut self, other: &mut Context){
        self.unmap();
        other.map();
    }

    //Warning: This function MUST be inspected in disassembly for correct push/pop
    //It should have exactly one extra push/pop of ESI
    #[cold]
    #[inline(never)]
    pub unsafe fn switch(&mut self, other: &mut Context){
        asm!("pushfd
            pushad
            mov [esi], esp"
            :
            : "{esi}"(&mut self.stack_ptr)
            : "memory"
            : "intel", "volatile");

        asm!("fxsave [esi]"
            :
            : "{esi}"(self.fx)
            : "memory"
            : "intel", "volatile");

        asm!("fxrstor [esi]"
            :
            : "{esi}"(other.fx)
            : "memory"
            : "intel", "volatile");

        asm!("mov esp, [esi]
            popad
            popfd"
            :
            : "{esi}"(&mut other.stack_ptr)
            : "memory"
            : "intel", "volatile");
    }
}

impl Drop for Context {
    fn drop(&mut self){
        while let Option::Some(entry) = self.memory.remove(0) {
            if entry.cleanup {
                unsafe {
                    unalloc(entry.physical_address);
                }
            }
        }

        if self.stack > 0 {
            unsafe {
                unalloc(self.stack);
            }
            self.stack = 0;
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashSet;

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Set {
    pub data: HashSet<Vec<u8>>
}

/// An abstract set datatype
///
/// In order to avoid unnecessary copying, this implementation uses [impl
/// Trait](https://aturon.github.io/blog/2015/09/28/impl-trait/). Currently `impl Trait` is only
/// availible in nightly builds. Here's the implementation
/// [commit](https://github.com/rust-lang/rust/pull/35091).
impl Set {
    pub fn new() -> Set {
        Set {
            data: HashSet::new()
        }
    }

    pub fn with_capacity(size: usize) -> Set {
        Set {
            data: HashSet::with_capacity(size)
        }
    }

    pub fn fill(data: HashSet<Vec<u8>>) -> Set {
        Set {
            data: data
        }
    }

    /// Insert an element into the set.
    /// Returns `true` if the element was added, and `false` if it already existed in the set.
    pub fn insert(&mut self, element: Vec<u8>) -> bool {
        self.data.insert(element)
    }

    /// Remove the element from the set
    /// Returns `true` if the value was present in the set, `false` otherwise
    pub fn remove(&mut self, element: &Vec<u8>) -> bool {
        self.data.remove(element)
    }

    /// Returns `true` if the element is in the set
    pub fn contains(&self, element: &Vec<u8>) -> bool {
        self.data.contains(element)
    }

    /// Returns the union of two sets
    ///
    /// # Examples
    ///
    /// ```
    /// use vertree::containers::Set;
    ///
    /// let a = Set { data: vec![vec![1], vec![2], vec![3]].into_iter().collect() };
    /// let b = Set { data: vec![vec![1], vec![2], vec![3], vec![4]].into_iter().collect() };
    ///
    /// assert_eq!(Set { data: a.union(&b).cloned().collect() },
    ///            Set { data: vec![vec![1], vec![2], vec![3], vec![4]].into_iter().collect() });
    pub fn union<'a>(&'a self, other: &'a Set) -> impl Iterator<Item=&'a Vec<u8>> {
        self.data.union(&other.data)
    }

    /// Returns the intersection of two sets
    ///
    /// # Examples
    ///
    /// ```
    /// use vertree::containers::Set;
    ///
    /// let a = Set { data: vec![vec![1], vec![2], vec![3]].into_iter().collect() };
    /// let b = Set { data: vec![vec![2], vec![3], vec![4]].into_iter().collect() };
    ///
    /// let result = Set { data: a.intersection(&b).cloned().collect() };
    /// assert_eq!(result, Set { data: vec![vec![2], vec![3]].into_iter().collect() });
    pub fn intersection<'a>(&'a self, other: &'a Set) -> impl Iterator<Item=&'a Vec<u8>> {
        self.data.intersection(&other.data)
    }

    /// Returns the difference between two sets
    ///
    /// The difference is seen as `self - other`, which is all the keys in `self` that don't exist
    /// in `other`.
    ///
    /// # Examples
    ///
    /// ```
    /// use vertree::containers::Set;
    ///
    /// let a = Set { data: vec![vec![1], vec![2], vec![3]].into_iter().collect() };
    /// let b = Set { data: vec![vec![2], vec![3], vec![4]].into_iter().collect() };
    ///
    /// let result = Set { data: a.difference(&b).cloned().collect() };
    /// assert_eq!(result, Set { data: vec![vec![1]].into_iter().collect() });
    pub fn difference<'a>(&'a self, other: &'a Set) -> impl Iterator<Item=&'a Vec<u8>> {
        self.data.difference(&other.data)
    }

    /// Returns the symmetric difference between two sets
    ///
    /// The difference is seen as the union of `self - other`, and `other - self`, which is all the
    /// keys that don't exist in both sets.
    ///
    /// # Examples
    ///
    /// ```
    /// use vertree::containers::Set;
    ///
    /// let a = Set { data: vec![vec![1], vec![2], vec![3]].into_iter().collect() };
    /// let b = Set { data: vec![vec![2], vec![3], vec![4]].into_iter().collect() };
    ///
    /// let result_a = Set { data: a.symmetric_difference(&b).cloned().collect() };
    /// let result_b = Set { data: b.symmetric_difference(&a).cloned().collect() };
    /// assert_eq!(result_a, result_b);
    /// assert_eq!(result_a,
    ///            Set { data: vec![vec![1], vec![4]].into_iter().collect() });
    pub fn symmetric_difference<'a>(&'a self, other: &'a Set) -> impl Iterator<Item=&'a Vec<u8>> {
        self.data.symmetric_difference(&other.data)
    }

    /// Returns `true` if `self` is a subset of `other`
    pub fn is_subset(&self, other: &Set) -> bool {
        self.data.is_subset(&other.data)
    }

    /// Returns `true` if `self` is a subset of `other`
    pub fn is_superset(&self, other: &Set) -> bool {
        self.data.is_superset(&other.data)
    }
}
<commit_msg>add len() to set<commit_after>use std::collections::HashSet;

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Set {
    pub data: HashSet<Vec<u8>>
}

/// An abstract set datatype
///
/// In order to avoid unnecessary copying, this implementation uses [impl
/// Trait](https://aturon.github.io/blog/2015/09/28/impl-trait/). Currently `impl Trait` is only
/// availible in nightly builds. Here's the implementation
/// [commit](https://github.com/rust-lang/rust/pull/35091).
impl Set {
    pub fn new() -> Set {
        Set {
            data: HashSet::new()
        }
    }

    pub fn with_capacity(size: usize) -> Set {
        Set {
            data: HashSet::with_capacity(size)
        }
    }

    pub fn fill(data: HashSet<Vec<u8>>) -> Set {
        Set {
            data: data
        }
    }

    /// Insert an element into the set.
    /// Returns `true` if the element was added, and `false` if it already existed in the set.
    pub fn insert(&mut self, element: Vec<u8>) -> bool {
        self.data.insert(element)
    }

    /// Remove the element from the set
    /// Returns `true` if the value was present in the set, `false` otherwise
    pub fn remove(&mut self, element: &Vec<u8>) -> bool {
        self.data.remove(element)
    }

    /// Returns `true` if the element is in the set
    pub fn contains(&self, element: &Vec<u8>) -> bool {
        self.data.contains(element)
    }

     /// Returns the number of elements in the Set
     pub fn len(&self) -> usize {
       self.data.len()
     }

    /// Returns the union of two sets
    ///
    /// # Examples
    ///
    /// ```
    /// use vertree::containers::Set;
    ///
    /// let a = Set { data: vec![vec![1], vec![2], vec![3]].into_iter().collect() };
    /// let b = Set { data: vec![vec![1], vec![2], vec![3], vec![4]].into_iter().collect() };
    ///
    /// assert_eq!(Set { data: a.union(&b).cloned().collect() },
    ///            Set { data: vec![vec![1], vec![2], vec![3], vec![4]].into_iter().collect() });
    pub fn union<'a>(&'a self, other: &'a Set) -> impl Iterator<Item=&'a Vec<u8>> {
        self.data.union(&other.data)
    }

    /// Returns the intersection of two sets
    ///
    /// # Examples
    ///
    /// ```
    /// use vertree::containers::Set;
    ///
    /// let a = Set { data: vec![vec![1], vec![2], vec![3]].into_iter().collect() };
    /// let b = Set { data: vec![vec![2], vec![3], vec![4]].into_iter().collect() };
    ///
    /// let result = Set { data: a.intersection(&b).cloned().collect() };
    /// assert_eq!(result, Set { data: vec![vec![2], vec![3]].into_iter().collect() });
    pub fn intersection<'a>(&'a self, other: &'a Set) -> impl Iterator<Item=&'a Vec<u8>> {
        self.data.intersection(&other.data)
    }

    /// Returns the difference between two sets
    ///
    /// The difference is seen as `self - other`, which is all the keys in `self` that don't exist
    /// in `other`.
    ///
    /// # Examples
    ///
    /// ```
    /// use vertree::containers::Set;
    ///
    /// let a = Set { data: vec![vec![1], vec![2], vec![3]].into_iter().collect() };
    /// let b = Set { data: vec![vec![2], vec![3], vec![4]].into_iter().collect() };
    ///
    /// let result = Set { data: a.difference(&b).cloned().collect() };
    /// assert_eq!(result, Set { data: vec![vec![1]].into_iter().collect() });
    pub fn difference<'a>(&'a self, other: &'a Set) -> impl Iterator<Item=&'a Vec<u8>> {
        self.data.difference(&other.data)
    }

    /// Returns the symmetric difference between two sets
    ///
    /// The difference is seen as the union of `self - other`, and `other - self`, which is all the
    /// keys that don't exist in both sets.
    ///
    /// # Examples
    ///
    /// ```
    /// use vertree::containers::Set;
    ///
    /// let a = Set { data: vec![vec![1], vec![2], vec![3]].into_iter().collect() };
    /// let b = Set { data: vec![vec![2], vec![3], vec![4]].into_iter().collect() };
    ///
    /// let result_a = Set { data: a.symmetric_difference(&b).cloned().collect() };
    /// let result_b = Set { data: b.symmetric_difference(&a).cloned().collect() };
    /// assert_eq!(result_a, result_b);
    /// assert_eq!(result_a,
    ///            Set { data: vec![vec![1], vec![4]].into_iter().collect() });
    pub fn symmetric_difference<'a>(&'a self, other: &'a Set) -> impl Iterator<Item=&'a Vec<u8>> {
        self.data.symmetric_difference(&other.data)
    }

    /// Returns `true` if `self` is a subset of `other`
    pub fn is_subset(&self, other: &Set) -> bool {
        self.data.is_subset(&other.data)
    }

    /// Returns `true` if `self` is a subset of `other`
    pub fn is_superset(&self, other: &Set) -> bool {
        self.data.is_superset(&other.data)
    }
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate x11;

use x11::xlib;

use std::rc::{ Rc, Weak };
use std::cell::RefCell;
use std::boxed::Box;
use super::layout;
use super::super::libx;

pub const TITLE_HEIGHT: libc::c_int = 20;

pub enum Mode {
    Normal,
    Fullscreen,
}

pub struct Container {
    pub id: xlib::Window,
    pub visible: bool,
    pub titlebar_height: usize,
    pub pid: Option<xlib::Window>,
    pub clients: Vec<Container>,
    pub mode: Mode,
    pub context: libx::Context,
    layout: Box<layout::Layout>,
}

impl PartialEq for Container {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

impl Container {
    pub fn new(context: libx::Context, parent: Option<xlib::Window>) -> Container{
        let pid = match parent {
            Some(c) => {
                c
            }
            None => {
                context.root
            }
        };
        let attrs = libx::get_window_attributes(context, pid);

        let id = libx::create_window(context, pid,
                                     attrs.x, attrs.y,
                                     attrs.width as libc::c_uint,
                                     attrs.height as libc::c_uint);
        libx::select_input(context, id, xlib::SubstructureNotifyMask | xlib::SubstructureRedirectMask);
        let mut c = Container::from_id(context, id);
        c.pid = Some(pid);
        c
    }

    pub fn from_id(context: libx::Context, id: xlib::Window) -> Container {
        Container {
            context: context,
            clients: Vec::new(),
            pid: None,
            visible: false,
            id: id,
            mode: Mode::Normal,
            titlebar_height: 0,
            layout: Box::new(layout::TilingLayout::new(layout::Direction::Horizontal))
        }
    }

    pub fn print_tree(&self, indent: i32) {
        for i in 0..indent {
            print!(" ");
        }
        let attrs = libx::get_window_attributes(self.context, self.id);
        println!("C {} pid:{} x:{} y:{} w:{} h:{}", self.id, self.pid.unwrap_or(0), attrs.x, attrs.y, attrs.width, attrs.height);
        for client in self.clients.iter() {
            client.print_tree(indent+4);
        }
    }

    // pub fn is_top(&self) -> bool {
    //     let top = self.get_top();
    //     match top {
    //         Some(w) => {
    //             w.id == self.id
    //         }
    //         Noen => false
    //     }
    // }

    pub fn is_empty(&self) -> bool{
        self.clients.is_empty()
    }

    pub fn size(&self) -> usize {
        self.clients.len()
    }
    pub fn add(&mut self, mut client: Container) {
        if client.pid.is_none() || client.pid.unwrap() != self.id {
            libx::reparent(self.context, client.id, self.id, 0, 0);
            client.pid = Some(self.id);
        }
        self.clients.push(client);
    }

    pub fn remove(&mut self, id: xlib::Window) -> Option<Container>{
        let res = self.contain(id);
        match res {
            Some(index) => {
                let r = self.clients.remove(index);
                Some(r)
            }
            None => {
                for c in self.clients.iter_mut() {
                    let r = c.remove(id);
                    if r.is_some(){
                        return r;
                    }
                }
                None
            }
        }
    }

    pub fn get(&self, index: usize) -> Option<&Container> {
        self.clients.get(index)
    }
    pub fn contain(&self, id: xlib::Window) -> Option<usize>{
        self.clients.iter().position(|x| (*x).id == id)
    }

    pub fn configure(&self, x: i32, y: i32, width: usize, height: usize) {
        libx::resize_window(self.context, self.id, x, y, width, height);
        // layout for children clients
        self.update();
    }

    pub fn update(&self) {
        self.layout.configure(self);
    }

    pub fn map(&self) {
        // self.visible = true;
        libx::map_window(self.context, self.id);
        for client in self.clients.iter() {
            client.map();
        }
    }

    pub fn unmap(&self) {
        // self.visible = false;
        for client in self.clients.iter() {
            client.unmap();
        }
        libx::unmap_window(self.context, self.id);
    }

    pub fn destroy(&self) -> bool {
        // can distroy only if it has no clients
        if self.clients.is_empty() {
            unsafe{
                xlib::XDestroyWindow(self.context.display, self.id);
                true
            }
        }
        else {
            false
        }
    }

    pub fn next_client(&self, id: xlib::Window) -> Option<&Container>{
        match self.contain(id) {
            Some(i) => {
                let mut next = i+1;
                if next == self.size() {
                    next = 0;
                }
                self.get(next)
            }
            None => {
                None
            }
        }
    }

    pub fn last_client(&self, id: xlib::Window) -> Option<&Container>{
        match self.contain(id) {
            Some(i) => {
                let mut last = i-1;
                if last < 0 {
                    last = self.size() - 1
                }
                self.get(last)
            }
            None => {
                None
            }
        }
    }

    pub fn change_layout(&mut self, layout_type: layout::Type) {
        let t = self.layout.get_type();
        if t == layout_type {
            self.layout.toggle();
        }
        else{
            match layout_type {
                layout::Type::Tiling => {
                    let tmp = layout::TilingLayout::new(layout::Direction::Horizontal);
                    self.layout = Box::new(tmp);
                }
                layout::Type::Tab => {
                    let tmp = layout::TabLayout::new();
                    self.layout = Box::new(tmp);
                }
            }
        }
    }

    // pub fn split(&self, index: usize) -> bool {
    //     let res = self.remove(index);
    //     match res {
    //         Some(client) => {
    //             if client.is_empty() {
    //                 let container = Container::new(self.context, self);
    //                 container.add(client);
    //                 self.clients[index] = container;
    //                 true
    //             }
    //             else{
    //                 // client is not a leaf node, can't split
    //                 false
    //             }
    //         }
    //         None => { false }
    //     }
    // }

    pub fn focus(&self) {
        libx::set_input_focus(self.context, self.id);
        // match self.client {
        //     Some(id) => {
        //         libx::set_input_focus(self.context, id);
        //         self.draw_titlebar(true);
        //     }
        //     None => {
        //         libx::set_input_focus(self.context, self.id);
        //     }
        // }
    }

    pub fn unfocus(&self) {

    }

    pub fn switch_client(&self) {
        let (x, _) = libx::get_input_focus(self.context);

    }
}

// #[test]
// fn window_eq() {
//     use std::ptr;
//     let c1 = libx::Context {
//         display: ptr::null_mut()
//     };
//     let w1 = Window::new(c1, 1);
//     let c2 = libx::Context {
//         display: ptr::null_mut()
//     };
//     let w2 = Window::new(c2, 1);
//     assert_eq!(w1, w2);
// }
<commit_msg>split function<commit_after>extern crate libc;
extern crate x11;

use x11::xlib;

use std::rc::{ Rc, Weak };
use std::cell::RefCell;
use std::boxed::Box;
use super::layout;
use super::super::libx;

pub const TITLE_HEIGHT: libc::c_int = 20;

pub enum Mode {
    Normal,
    Fullscreen,
}

pub struct Container {
    pub id: xlib::Window,
    pub visible: bool,
    pub titlebar_height: usize,
    pub pid: Option<xlib::Window>,
    pub clients: Vec<Container>,
    pub mode: Mode,
    pub context: libx::Context,
    layout: Box<layout::Layout>,
}

impl PartialEq for Container {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

impl Container {
    pub fn new(context: libx::Context, parent: Option<xlib::Window>) -> Container{
        let pid = match parent {
            Some(c) => {
                c
            }
            None => {
                context.root
            }
        };
        let attrs = libx::get_window_attributes(context, pid);

        let id = libx::create_window(context, pid,
                                     attrs.x, attrs.y,
                                     attrs.width as libc::c_uint,
                                     attrs.height as libc::c_uint);
        libx::select_input(context, id, xlib::SubstructureNotifyMask | xlib::SubstructureRedirectMask);
        let mut c = Container::from_id(context, id);
        c.pid = Some(pid);
        c
    }

    pub fn from_id(context: libx::Context, id: xlib::Window) -> Container {
        Container {
            context: context,
            clients: Vec::new(),
            pid: None,
            visible: false,
            id: id,
            mode: Mode::Normal,
            titlebar_height: 0,
            layout: Box::new(layout::TilingLayout::new(layout::Direction::Horizontal))
        }
    }

    pub fn print_tree(&self, indent: i32) {
        for i in 0..indent {
            print!(" ");
        }
        let attrs = libx::get_window_attributes(self.context, self.id);
        println!("C {} pid:{} x:{} y:{} w:{} h:{}", self.id, self.pid.unwrap_or(0), attrs.x, attrs.y, attrs.width, attrs.height);
        for client in self.clients.iter() {
            client.print_tree(indent+4);
        }
    }

    // pub fn is_top(&self) -> bool {
    //     let top = self.get_top();
    //     match top {
    //         Some(w) => {
    //             w.id == self.id
    //         }
    //         Noen => false
    //     }
    // }

    pub fn is_empty(&self) -> bool{
        self.clients.is_empty()
    }

    pub fn size(&self) -> usize {
        self.clients.len()
    }
    pub fn add(&mut self, mut client: Container) {
        if client.pid.is_none() || client.pid.unwrap() != self.id {
            libx::reparent(self.context, client.id, self.id, 0, 0);
            client.pid = Some(self.id);
        }
        self.clients.push(client);
    }

    pub fn remove(&mut self, id: xlib::Window) -> Option<Container>{
        let res = self.contain(id);
        match res {
            Some(index) => {
                let r = self.clients.remove(index);
                Some(r)
            }
            None => {
                for c in self.clients.iter_mut() {
                    let r = c.remove(id);
                    if r.is_some(){
                        return r;
                    }
                }
                None
            }
        }
    }

    pub fn get(&self, index: usize) -> Option<&Container> {
        self.clients.get(index)
    }
    pub fn contain(&self, id: xlib::Window) -> Option<usize>{
        self.clients.iter().position(|x| (*x).id == id)
    }

    pub fn configure(&self, x: i32, y: i32, width: usize, height: usize) {
        libx::resize_window(self.context, self.id, x, y, width, height);
        // layout for children clients
        self.update();
    }

    pub fn update(&self) {
        self.layout.configure(self);
    }

    pub fn map(&self) {
        // self.visible = true;
        libx::map_window(self.context, self.id);
        for client in self.clients.iter() {
            client.map();
        }
    }

    pub fn unmap(&self) {
        // self.visible = false;
        for client in self.clients.iter() {
            client.unmap();
        }
        libx::unmap_window(self.context, self.id);
    }

    pub fn destroy(&self) -> bool {
        // can distroy only if it has no clients
        if self.clients.is_empty() {
            unsafe{
                xlib::XDestroyWindow(self.context.display, self.id);
                true
            }
        }
        else {
            false
        }
    }

    pub fn next_client(&self, id: xlib::Window) -> Option<&Container>{
        match self.contain(id) {
            Some(i) => {
                let mut next = i+1;
                if next == self.size() {
                    next = 0;
                }
                self.get(next)
            }
            None => {
                None
            }
        }
    }

    pub fn last_client(&self, id: xlib::Window) -> Option<&Container>{
        match self.contain(id) {
            Some(i) => {
                let mut last = i-1;
                if last < 0 {
                    last = self.size() - 1
                }
                self.get(last)
            }
            None => {
                None
            }
        }
    }

    pub fn change_layout(&mut self, layout_type: layout::Type) {
        let t = self.layout.get_type();
        if t == layout_type {
            self.layout.toggle();
        }
        else{
            match layout_type {
                layout::Type::Tiling => {
                    let tmp = layout::TilingLayout::new(layout::Direction::Horizontal);
                    self.layout = Box::new(tmp);
                }
                layout::Type::Tab => {
                    let tmp = layout::TabLayout::new();
                    self.layout = Box::new(tmp);
                }
            }
        }
    }

    pub fn split(&mut self) -> bool {
        if !self.is_empty() {
            return false;
        }

        let mut container = Container::new(self.context, None);
        let id = self.id;
        self.id = container.id;
        container.id = id;
        self.add(container);
        true
    }

    pub fn focus(&self) {
        libx::set_input_focus(self.context, self.id);
        // match self.client {
        //     Some(id) => {
        //         libx::set_input_focus(self.context, id);
        //         self.draw_titlebar(true);
        //     }
        //     None => {
        //         libx::set_input_focus(self.context, self.id);
        //     }
        // }
    }

    pub fn unfocus(&self) {

    }

    pub fn switch_client(&self) {
        let (x, _) = libx::get_input_focus(self.context);

    }
}

// #[test]
// fn window_eq() {
//     use std::ptr;
//     let c1 = libx::Context {
//         display: ptr::null_mut()
//     };
//     let w1 = Window::new(c1, 1);
//     let c2 = libx::Context {
//         display: ptr::null_mut()
//     };
//     let w2 = Window::new(c2, 1);
//     assert_eq!(w1, w2);
// }
<|endoftext|>


<commit_before>use crate::{
    backend::renderer::{utils::draw_surface_tree, Frame, ImportAll, Renderer, Texture},
    desktop::{utils::*, PopupManager, Space},
    utils::{Logical, Point, Rectangle},
    wayland::{
        compositor::with_states,
        output::Output,
        shell::xdg::{SurfaceCachedState, ToplevelSurface},
    },
};
use std::{
    cell::Cell,
    collections::HashSet,
    hash::{Hash, Hasher},
    rc::Rc,
    sync::{
        atomic::{AtomicUsize, Ordering},
        Mutex,
    },
};
use wayland_commons::user_data::UserDataMap;
use wayland_protocols::xdg_shell::server::xdg_toplevel;
use wayland_server::protocol::wl_surface;

static WINDOW_ID: AtomicUsize = AtomicUsize::new(0);
lazy_static::lazy_static! {
    static ref WINDOW_IDS: Mutex<HashSet<usize>> = Mutex::new(HashSet::new());
}

fn next_window_id() -> usize {
    let mut ids = WINDOW_IDS.lock().unwrap();
    if ids.len() == usize::MAX {
        // Theoretically the code below wraps around correctly,
        // but that is hard to detect and might deadlock.
        // Maybe make this a debug_assert instead?
        panic!("Out of window ids");
    }

    let mut id = WINDOW_ID.fetch_add(1, Ordering::SeqCst);
    while ids.iter().any(|k| *k == id) {
        id = WINDOW_ID.fetch_add(1, Ordering::SeqCst);
    }

    ids.insert(id);
    id
}

#[derive(Debug, Clone, PartialEq)]
pub enum Kind {
    Xdg(ToplevelSurface),
    #[cfg(feature = "xwayland")]
    X11(X11Surface),
}

// Big TODO
#[derive(Debug, Clone)]
pub struct X11Surface {
    surface: wl_surface::WlSurface,
}

impl std::cmp::PartialEq for X11Surface {
    fn eq(&self, other: &Self) -> bool {
        self.alive() && other.alive() && self.surface == other.surface
    }
}

impl X11Surface {
    pub fn alive(&self) -> bool {
        self.surface.as_ref().is_alive()
    }

    pub fn get_surface(&self) -> Option<&wl_surface::WlSurface> {
        if self.alive() {
            Some(&self.surface)
        } else {
            None
        }
    }
}

impl Kind {
    pub fn alive(&self) -> bool {
        match *self {
            Kind::Xdg(ref t) => t.alive(),
            #[cfg(feature = "xwayland")]
            Kind::X11(ref t) => t.alive(),
        }
    }

    pub fn get_surface(&self) -> Option<&wl_surface::WlSurface> {
        match *self {
            Kind::Xdg(ref t) => t.get_surface(),
            #[cfg(feature = "xwayland")]
            Kind::X11(ref t) => t.get_surface(),
        }
    }
}

#[derive(Debug)]
pub(super) struct WindowInner {
    pub(super) id: usize,
    toplevel: Kind,
    bbox: Cell<Rectangle<i32, Logical>>,
    user_data: UserDataMap,
}

impl Drop for WindowInner {
    fn drop(&mut self) {
        WINDOW_IDS.lock().unwrap().remove(&self.id);
    }
}

#[derive(Debug, Clone)]
pub struct Window(pub(super) Rc<WindowInner>);

impl PartialEq for Window {
    fn eq(&self, other: &Self) -> bool {
        self.0.id == other.0.id
    }
}

impl Eq for Window {}

impl Hash for Window {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.id.hash(state);
    }
}

impl Window {
    pub fn new(toplevel: Kind) -> Window {
        let id = next_window_id();

        // TODO: Do we want this? For new lets add Window::commit
        //add_commit_hook(toplevel.get_surface().unwrap(), surface_commit);

        Window(Rc::new(WindowInner {
            id,
            toplevel,
            bbox: Cell::new(Rectangle::from_loc_and_size((0, 0), (0, 0))),
            user_data: UserDataMap::new(),
        }))
    }

    /// Returns the geometry of this window.
    pub fn geometry(&self) -> Rectangle<i32, Logical> {
        // It's the set geometry with the full bounding box as the fallback.
        with_states(self.0.toplevel.get_surface().unwrap(), |states| {
            states.cached_state.current::<SurfaceCachedState>().geometry
        })
        .unwrap()
        .unwrap_or_else(|| self.bbox())
    }

    /// A bounding box over this window and its children.
    // TODO: Cache and document when to trigger updates. If possible let space do it
    pub fn bbox(&self) -> Rectangle<i32, Logical> {
        if let Some(surface) = self.0.toplevel.get_surface() {
            self.0.bbox.get()
        } else {
            Rectangle::from_loc_and_size((0, 0), (0, 0))
        }
    }

    pub fn bbox_with_popups(&self) -> Rectangle<i32, Logical> {
        let mut bounding_box = self.bbox();
        if let Some(surface) = self.0.toplevel.get_surface() {
            for (popup, location) in PopupManager::popups_for_surface(surface)
                .ok()
                .into_iter()
                .flatten()
            {
                if let Some(surface) = popup.get_surface() {
                    bounding_box = bounding_box.merge(bbox_from_surface_tree(surface, location));
                }
            }
        }
        bounding_box
    }

    /// Activate/Deactivate this window
    // TODO: Add more helpers for Maximize? Minimize? Fullscreen? I dunno
    pub fn set_activated(&self, active: bool) -> bool {
        match self.0.toplevel {
            Kind::Xdg(ref t) => t
                .with_pending_state(|state| {
                    if active {
                        state.states.set(xdg_toplevel::State::Activated)
                    } else {
                        state.states.unset(xdg_toplevel::State::Activated)
                    }
                })
                .unwrap_or(false),
            #[cfg(feature = "xwayland")]
            Kind::X11(ref t) => unimplemented!(),
        }
    }

    /// Commit any changes to this window
    pub fn configure(&self) {
        match self.0.toplevel {
            Kind::Xdg(ref t) => t.send_configure(),
            #[cfg(feature = "xwayland")]
            Kind::X11(ref t) => unimplemented!(),
        }
    }

    /// Sends the frame callback to all the subsurfaces in this
    /// window that requested it
    pub fn send_frame(&self, time: u32) {
        if let Some(surface) = self.0.toplevel.get_surface() {
            send_frames_surface_tree(surface, time);
            for (popup, _) in PopupManager::popups_for_surface(surface)
                .ok()
                .into_iter()
                .flatten()
            {
                if let Some(surface) = popup.get_surface() {
                    send_frames_surface_tree(surface, time);
                }
            }
        }
    }

    /// Updates internal values
    ///
    /// Needs to be called whenever the toplevel surface or any unsynchronized subsurfaces of this window are updated
    /// to correctly update the bounding box of this window.
    pub fn refresh(&self) {
        if let Some(surface) = self.0.toplevel.get_surface() {
            self.0.bbox.set(bbox_from_surface_tree(surface, (0, 0)));
        }
    }

    /// Finds the topmost surface under this point if any and returns it together with the location of this
    /// surface.
    pub fn surface_under<P: Into<Point<f64, Logical>>>(
        &self,
        point: P,
    ) -> Option<(wl_surface::WlSurface, Point<i32, Logical>)> {
        let point = point.into();
        if let Some(surface) = self.0.toplevel.get_surface() {
            for (popup, location) in PopupManager::popups_for_surface(surface)
                .ok()
                .into_iter()
                .flatten()
            {
                if let Some(result) = popup
                    .get_surface()
                    .and_then(|surface| under_from_surface_tree(surface, point, location))
                {
                    return Some(result);
                }
            }

            under_from_surface_tree(surface, point, (0, 0))
        } else {
            None
        }
    }

    /// Damage of all the surfaces of this window
    pub(super) fn accumulated_damage(
        &self,
        for_values: Option<(&Space, &Output)>,
    ) -> Vec<Rectangle<i32, Logical>> {
        let mut damage = Vec::new();
        if let Some(surface) = self.0.toplevel.get_surface() {
            damage.extend(
                damage_from_surface_tree(surface, (0, 0), for_values)
                    .into_iter()
                    .flat_map(|rect| rect.intersection(self.bbox())),
            );
            for (popup, location) in PopupManager::popups_for_surface(surface)
                .ok()
                .into_iter()
                .flatten()
            {
                if let Some(surface) = popup.get_surface() {
                    let bbox = bbox_from_surface_tree(surface, location);
                    let popup_damage = damage_from_surface_tree(surface, location, for_values);
                    damage.extend(popup_damage.into_iter().flat_map(|rect| rect.intersection(bbox)));
                }
            }
        }
        damage
    }

    pub fn toplevel(&self) -> &Kind {
        &self.0.toplevel
    }

    pub fn user_data(&self) -> &UserDataMap {
        &self.0.user_data
    }
}

pub fn draw_window<R, E, F, T, P>(
    renderer: &mut R,
    frame: &mut F,
    window: &Window,
    scale: f64,
    location: P,
    damage: &[Rectangle<i32, Logical>],
    log: &slog::Logger,
) -> Result<(), R::Error>
where
    R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll,
    F: Frame<Error = E, TextureId = T>,
    E: std::error::Error,
    T: Texture + 'static,
    P: Into<Point<i32, Logical>>,
{
    let location = location.into();
    if let Some(surface) = window.toplevel().get_surface() {
        draw_surface_tree(renderer, frame, surface, scale, location, damage, log)?;
        for (popup, p_location) in PopupManager::popups_for_surface(surface)
            .ok()
            .into_iter()
            .flatten()
        {
            if let Some(surface) = popup.get_surface() {
                let damage = damage
                    .iter()
                    .cloned()
                    .map(|mut geo| {
                        geo.loc -= p_location;
                        geo
                    })
                    .collect::<Vec<_>>();
                draw_surface_tree(
                    renderer,
                    frame,
                    surface,
                    scale,
                    location + p_location,
                    &damage,
                    log,
                )?;
            }
        }
    }
    Ok(())
}
<commit_msg>desktop: Make window damage public<commit_after>use crate::{
    backend::renderer::{utils::draw_surface_tree, Frame, ImportAll, Renderer, Texture},
    desktop::{utils::*, PopupManager, Space},
    utils::{Logical, Point, Rectangle},
    wayland::{
        compositor::with_states,
        output::Output,
        shell::xdg::{SurfaceCachedState, ToplevelSurface},
    },
};
use std::{
    cell::Cell,
    collections::HashSet,
    hash::{Hash, Hasher},
    rc::Rc,
    sync::{
        atomic::{AtomicUsize, Ordering},
        Mutex,
    },
};
use wayland_commons::user_data::UserDataMap;
use wayland_protocols::xdg_shell::server::xdg_toplevel;
use wayland_server::protocol::wl_surface;

static WINDOW_ID: AtomicUsize = AtomicUsize::new(0);
lazy_static::lazy_static! {
    static ref WINDOW_IDS: Mutex<HashSet<usize>> = Mutex::new(HashSet::new());
}

fn next_window_id() -> usize {
    let mut ids = WINDOW_IDS.lock().unwrap();
    if ids.len() == usize::MAX {
        // Theoretically the code below wraps around correctly,
        // but that is hard to detect and might deadlock.
        // Maybe make this a debug_assert instead?
        panic!("Out of window ids");
    }

    let mut id = WINDOW_ID.fetch_add(1, Ordering::SeqCst);
    while ids.iter().any(|k| *k == id) {
        id = WINDOW_ID.fetch_add(1, Ordering::SeqCst);
    }

    ids.insert(id);
    id
}

#[derive(Debug, Clone, PartialEq)]
pub enum Kind {
    Xdg(ToplevelSurface),
    #[cfg(feature = "xwayland")]
    X11(X11Surface),
}

// Big TODO
#[derive(Debug, Clone)]
pub struct X11Surface {
    surface: wl_surface::WlSurface,
}

impl std::cmp::PartialEq for X11Surface {
    fn eq(&self, other: &Self) -> bool {
        self.alive() && other.alive() && self.surface == other.surface
    }
}

impl X11Surface {
    pub fn alive(&self) -> bool {
        self.surface.as_ref().is_alive()
    }

    pub fn get_surface(&self) -> Option<&wl_surface::WlSurface> {
        if self.alive() {
            Some(&self.surface)
        } else {
            None
        }
    }
}

impl Kind {
    pub fn alive(&self) -> bool {
        match *self {
            Kind::Xdg(ref t) => t.alive(),
            #[cfg(feature = "xwayland")]
            Kind::X11(ref t) => t.alive(),
        }
    }

    pub fn get_surface(&self) -> Option<&wl_surface::WlSurface> {
        match *self {
            Kind::Xdg(ref t) => t.get_surface(),
            #[cfg(feature = "xwayland")]
            Kind::X11(ref t) => t.get_surface(),
        }
    }
}

#[derive(Debug)]
pub(super) struct WindowInner {
    pub(super) id: usize,
    toplevel: Kind,
    bbox: Cell<Rectangle<i32, Logical>>,
    user_data: UserDataMap,
}

impl Drop for WindowInner {
    fn drop(&mut self) {
        WINDOW_IDS.lock().unwrap().remove(&self.id);
    }
}

#[derive(Debug, Clone)]
pub struct Window(pub(super) Rc<WindowInner>);

impl PartialEq for Window {
    fn eq(&self, other: &Self) -> bool {
        self.0.id == other.0.id
    }
}

impl Eq for Window {}

impl Hash for Window {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.id.hash(state);
    }
}

impl Window {
    pub fn new(toplevel: Kind) -> Window {
        let id = next_window_id();

        // TODO: Do we want this? For new lets add Window::commit
        //add_commit_hook(toplevel.get_surface().unwrap(), surface_commit);

        Window(Rc::new(WindowInner {
            id,
            toplevel,
            bbox: Cell::new(Rectangle::from_loc_and_size((0, 0), (0, 0))),
            user_data: UserDataMap::new(),
        }))
    }

    /// Returns the geometry of this window.
    pub fn geometry(&self) -> Rectangle<i32, Logical> {
        // It's the set geometry with the full bounding box as the fallback.
        with_states(self.0.toplevel.get_surface().unwrap(), |states| {
            states.cached_state.current::<SurfaceCachedState>().geometry
        })
        .unwrap()
        .unwrap_or_else(|| self.bbox())
    }

    /// A bounding box over this window and its children.
    // TODO: Cache and document when to trigger updates. If possible let space do it
    pub fn bbox(&self) -> Rectangle<i32, Logical> {
        if let Some(surface) = self.0.toplevel.get_surface() {
            self.0.bbox.get()
        } else {
            Rectangle::from_loc_and_size((0, 0), (0, 0))
        }
    }

    pub fn bbox_with_popups(&self) -> Rectangle<i32, Logical> {
        let mut bounding_box = self.bbox();
        if let Some(surface) = self.0.toplevel.get_surface() {
            for (popup, location) in PopupManager::popups_for_surface(surface)
                .ok()
                .into_iter()
                .flatten()
            {
                if let Some(surface) = popup.get_surface() {
                    bounding_box = bounding_box.merge(bbox_from_surface_tree(surface, location));
                }
            }
        }
        bounding_box
    }

    /// Activate/Deactivate this window
    // TODO: Add more helpers for Maximize? Minimize? Fullscreen? I dunno
    pub fn set_activated(&self, active: bool) -> bool {
        match self.0.toplevel {
            Kind::Xdg(ref t) => t
                .with_pending_state(|state| {
                    if active {
                        state.states.set(xdg_toplevel::State::Activated)
                    } else {
                        state.states.unset(xdg_toplevel::State::Activated)
                    }
                })
                .unwrap_or(false),
            #[cfg(feature = "xwayland")]
            Kind::X11(ref t) => unimplemented!(),
        }
    }

    /// Commit any changes to this window
    pub fn configure(&self) {
        match self.0.toplevel {
            Kind::Xdg(ref t) => t.send_configure(),
            #[cfg(feature = "xwayland")]
            Kind::X11(ref t) => unimplemented!(),
        }
    }

    /// Sends the frame callback to all the subsurfaces in this
    /// window that requested it
    pub fn send_frame(&self, time: u32) {
        if let Some(surface) = self.0.toplevel.get_surface() {
            send_frames_surface_tree(surface, time);
            for (popup, _) in PopupManager::popups_for_surface(surface)
                .ok()
                .into_iter()
                .flatten()
            {
                if let Some(surface) = popup.get_surface() {
                    send_frames_surface_tree(surface, time);
                }
            }
        }
    }

    /// Updates internal values
    ///
    /// Needs to be called whenever the toplevel surface or any unsynchronized subsurfaces of this window are updated
    /// to correctly update the bounding box of this window.
    pub fn refresh(&self) {
        if let Some(surface) = self.0.toplevel.get_surface() {
            self.0.bbox.set(bbox_from_surface_tree(surface, (0, 0)));
        }
    }

    /// Finds the topmost surface under this point if any and returns it together with the location of this
    /// surface.
    pub fn surface_under<P: Into<Point<f64, Logical>>>(
        &self,
        point: P,
    ) -> Option<(wl_surface::WlSurface, Point<i32, Logical>)> {
        let point = point.into();
        if let Some(surface) = self.0.toplevel.get_surface() {
            for (popup, location) in PopupManager::popups_for_surface(surface)
                .ok()
                .into_iter()
                .flatten()
            {
                if let Some(result) = popup
                    .get_surface()
                    .and_then(|surface| under_from_surface_tree(surface, point, location))
                {
                    return Some(result);
                }
            }

            under_from_surface_tree(surface, point, (0, 0))
        } else {
            None
        }
    }

    /// Damage of all the surfaces of this window
    pub fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec<Rectangle<i32, Logical>> {
        let mut damage = Vec::new();
        if let Some(surface) = self.0.toplevel.get_surface() {
            damage.extend(
                damage_from_surface_tree(surface, (0, 0), for_values)
                    .into_iter()
                    .flat_map(|rect| rect.intersection(self.bbox())),
            );
            for (popup, location) in PopupManager::popups_for_surface(surface)
                .ok()
                .into_iter()
                .flatten()
            {
                if let Some(surface) = popup.get_surface() {
                    let bbox = bbox_from_surface_tree(surface, location);
                    let popup_damage = damage_from_surface_tree(surface, location, for_values);
                    damage.extend(popup_damage.into_iter().flat_map(|rect| rect.intersection(bbox)));
                }
            }
        }
        damage
    }

    pub fn toplevel(&self) -> &Kind {
        &self.0.toplevel
    }

    pub fn user_data(&self) -> &UserDataMap {
        &self.0.user_data
    }
}

pub fn draw_window<R, E, F, T, P>(
    renderer: &mut R,
    frame: &mut F,
    window: &Window,
    scale: f64,
    location: P,
    damage: &[Rectangle<i32, Logical>],
    log: &slog::Logger,
) -> Result<(), R::Error>
where
    R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll,
    F: Frame<Error = E, TextureId = T>,
    E: std::error::Error,
    T: Texture + 'static,
    P: Into<Point<i32, Logical>>,
{
    let location = location.into();
    if let Some(surface) = window.toplevel().get_surface() {
        draw_surface_tree(renderer, frame, surface, scale, location, damage, log)?;
        for (popup, p_location) in PopupManager::popups_for_surface(surface)
            .ok()
            .into_iter()
            .flatten()
        {
            if let Some(surface) = popup.get_surface() {
                let damage = damage
                    .iter()
                    .cloned()
                    .map(|mut geo| {
                        geo.loc -= p_location;
                        geo
                    })
                    .collect::<Vec<_>>();
                draw_surface_tree(
                    renderer,
                    frame,
                    surface,
                    scale,
                    location + p_location,
                    &damage,
                    log,
                )?;
            }
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate quickcheck;
extern crate rand;
extern crate tempfile;
extern crate positioned_io;

use std::cmp::{max, min};
use std::io::{Read, Write, Seek, SeekFrom};

use self::quickcheck::{Arbitrary, Gen};
use self::rand::Rng;
use positioned_io::{ReadAt, WriteAt};

#[derive(Clone, Debug)]
enum Op {
    WriteAll(Vec<u8>),
    WriteAllAt(u64, Vec<u8>),
    ReadExact(usize),
    ReadExactAt(u64, usize),
    Seek(u64),
    Flush,
}

impl Arbitrary for Op {
    fn arbitrary<G: Gen>(g: &mut G) -> Op {
        match g.gen_range(0, 6) {
            0 => Op::WriteAll(Vec::arbitrary(g)),
            1 => Op::WriteAllAt(g.gen_range(0, 123456), Vec::arbitrary(g)),
            2 => Op::ReadExact(usize::arbitrary(g)),
            3 => Op::ReadExactAt(u64::arbitrary(g), usize::arbitrary(g)),
            4 => Op::Seek(g.gen_range(0, 123456)),
            _ => Op::Flush,
        }
    }
}

struct Model {
    vec: Vec<u8>,
    pos: usize,
}

impl Model {
    fn new() -> Model {
        Model {
            vec: Vec::new(),
            pos: 0,
        }
    }

    fn write_all(&mut self, buf: &[u8]) {
        let len = max(self.vec.len(), self.pos + buf.len());
        self.vec.resize(len, 0);
        self.vec[self.pos..(self.pos + buf.len())].copy_from_slice(&buf);
        self.pos += buf.len();
    }

    fn read_exact(&mut self, buf: &mut[u8]) -> bool {
        if buf.is_empty() {
            return true;
        }

        let len = buf.len();

        if self.pos + len > self.vec.len() {
            self.pos = self.vec.len();
            return false;
        }

        buf.copy_from_slice(&self.vec[self.pos..(self.pos + len)]);
        self.pos += len;
        true
    }
}

quickcheck! {
    fn file_matches_model(ops: Vec<Op>) -> bool {
        let mut file = tempfile::tempfile().unwrap();
        let mut model = Model::new();

        for op in ops {
            match op {
                Op::WriteAll(ref buf) => {
                    model.write_all(buf);
                    file.write_all(buf).unwrap();
                },
                Op::WriteAllAt(at, ref buf) => {
                    assert_eq!(model.vec.write_all_at(at, buf).is_ok(), file.write_all_at(at, buf).is_ok());
                },
                Op::ReadExact(bytes) => {
                    let mut a = vec![0; bytes];
                    let mut b = vec![0; bytes];
                    assert_eq!(model.read_exact(&mut a), file.read_exact(&mut b).is_ok());
                    assert_eq!(a, b);
                },
                Op::ReadExactAt(at, bytes) => {
                    let mut a = vec![0; bytes];
                    let mut b = vec![0; bytes];
                    assert_eq!(model.vec.read_exact_at(at, &mut a).is_ok(),  file.read_exact_at(at, &mut b).is_ok());
                    assert_eq!(a, b);
                }
                Op::Seek(pos) => {
                    // seeking past eof is implementation defined, so avoid that
                    model.pos = min(pos as usize, model.vec.len());
                    assert!(file.seek(SeekFrom::Start(model.pos as u64)).is_ok());
                }
                Op::Flush => {
                    Write::flush(&mut file).unwrap();
                }
            }
        }

        true
    }
}
<commit_msg>test: only compare buffers after successful read<commit_after>#[macro_use]
extern crate quickcheck;
extern crate rand;
extern crate tempfile;
extern crate positioned_io;

use std::cmp::{max, min};
use std::io::{Read, Write, Seek, SeekFrom};

use self::quickcheck::{Arbitrary, Gen};
use self::rand::Rng;
use positioned_io::{ReadAt, WriteAt};

#[derive(Clone, Debug)]
enum Op {
    WriteAll(Vec<u8>),
    WriteAllAt(u64, Vec<u8>),
    ReadExact(usize),
    ReadExactAt(u64, usize),
    Seek(u64),
    Flush,
}

impl Arbitrary for Op {
    fn arbitrary<G: Gen>(g: &mut G) -> Op {
        match g.gen_range(0, 6) {
            0 => Op::WriteAll(Vec::arbitrary(g)),
            1 => Op::WriteAllAt(g.gen_range(0, 123456), Vec::arbitrary(g)),
            2 => Op::ReadExact(usize::arbitrary(g)),
            3 => Op::ReadExactAt(u64::arbitrary(g), usize::arbitrary(g)),
            4 => Op::Seek(g.gen_range(0, 123456)),
            _ => Op::Flush,
        }
    }
}

struct Model {
    vec: Vec<u8>,
    pos: usize,
}

impl Model {
    fn new() -> Model {
        Model {
            vec: Vec::new(),
            pos: 0,
        }
    }

    fn write_all(&mut self, buf: &[u8]) {
        let len = max(self.vec.len(), self.pos + buf.len());
        self.vec.resize(len, 0);
        self.vec[self.pos..(self.pos + buf.len())].copy_from_slice(&buf);
        self.pos += buf.len();
    }

    fn read_exact(&mut self, buf: &mut[u8]) -> bool {
        if buf.is_empty() {
            return true;
        }

        let len = buf.len();

        if self.pos + len > self.vec.len() {
            self.pos = self.vec.len();
            return false;
        }

        buf.copy_from_slice(&self.vec[self.pos..(self.pos + len)]);
        self.pos += len;
        true
    }
}

quickcheck! {
    fn file_matches_model(ops: Vec<Op>) -> bool {
        let mut file = tempfile::tempfile().unwrap();
        let mut model = Model::new();

        for op in ops {
            match op {
                Op::WriteAll(ref buf) => {
                    model.write_all(buf);
                    file.write_all(buf).unwrap();
                },
                Op::WriteAllAt(at, ref buf) => {
                    assert_eq!(model.vec.write_all_at(at, buf).is_ok(), file.write_all_at(at, buf).is_ok());
                },
                Op::ReadExact(bytes) => {
                    let mut a = vec![0; bytes];
                    let mut b = vec![0; bytes];

                    let success = model.read_exact(&mut a);
                    assert_eq!(success, file.read_exact(&mut b).is_ok());

                    if success {
                        assert_eq!(a, b);
                    }
                },
                Op::ReadExactAt(at, bytes) => {
                    let mut a = vec![0; bytes];
                    let mut b = vec![0; bytes];

                    let success = model.vec.read_exact_at(at, &mut a).is_ok();
                    assert_eq!(success, file.read_exact_at(at, &mut b).is_ok());

                    if success {
                        assert_eq!(a, b);
                    }
                }
                Op::Seek(pos) => {
                    // seeking past eof is implementation defined, so avoid that
                    model.pos = min(pos as usize, model.vec.len());
                    assert!(file.seek(SeekFrom::Start(model.pos as u64)).is_ok());
                }
                Op::Flush => {
                    Write::flush(&mut file).unwrap();
                }
            }
        }

        true
    }
}
<|endoftext|>


<commit_before>use cgmath::{Point2, Point3, Vector2};
use clap::value_t;
use collision::{Aabb, Aabb2, Aabb3};
use point_cloud_client::PointCloudClient;
use point_viewer::color::{Color, TRANSPARENT, WHITE};
use point_viewer::octree::OctreeFactory;
use point_viewer_grpc::octree_from_grpc_address;
use std::error::Error;
use std::path::Path;
use xray::generation::{
    xray_from_points, ColoringStrategyArgument, ColoringStrategyKind, TileBackgroundColorArgument,
};

fn parse_arguments() -> clap::ArgMatches<'static> {
    // TODO(sirver): pull out a function for common args.
    clap::App::new("build_xray_tile")
        .version("1.0")
        .author("Holger H. Rapp <hrapp@lyft.com>")
        .args(&[
            clap::Arg::with_name("output_filename")
                .help("Output filename to write into.")
                .default_value("output.png")
                .long("output_filename")
                .takes_value(true),
            clap::Arg::with_name("resolution")
                .help("Size of 1px in meters.")
                .long("resolution")
                .default_value("0.05"),
            clap::Arg::with_name("coloring_strategy")
                .long("coloring_strategy")
                .takes_value(true)
                .possible_values(&ColoringStrategyArgument::variants())
                .default_value("xray"),
            clap::Arg::with_name("min_intensity")
                .help(
                    "Minimum intensity of all points for color scaling. \
                     Only used for 'colored_with_intensity'.",
                )
                .long("min_intensity")
                .takes_value(true)
                .required_if("coloring_strategy", "colored_with_intensity"),
            clap::Arg::with_name("max_intensity")
                .help(
                    "Minimum intensity of all points for color scaling. \
                     Only used for 'colored_with_intensity'.",
                )
                .long("max_intensity")
                .takes_value(true)
                .required_if("coloring_strategy", "colored_with_intensity"),
            clap::Arg::with_name("max_stddev")
                .help(
                    "Maximum stddev for colored_with_height_stddev. Every stddev above this \
                     will be clamped to this value and appear saturated in the X-Rays. \
                     Only used for 'colored_with_height_stddev'.",
                )
                .long("max_stddev")
                .takes_value(true)
                .required_if("coloring_strategy", "colored_with_height_stddev"),
            clap::Arg::with_name("octree_locations")
                .help("Octree locations to turn into xrays.")
                .index(1)
                .multiple(true)
                .required(true),
            clap::Arg::with_name("min_x")
                .long("min_x")
                .takes_value(true)
                .help("Bounding box minimum x in meters.")
                .required(true),
            clap::Arg::with_name("min_y")
                .long("min_y")
                .takes_value(true)
                .help("Bounding box minimum y in meters.")
                .required(true),
            clap::Arg::with_name("max_x")
                .long("max_x")
                .takes_value(true)
                .help("Bounding box maximum x in meters.")
                .required(true),
            clap::Arg::with_name("max_y")
                .long("max_y")
                .takes_value(true)
                .help("Bounding box maximum y in meters.")
                .required(true),
            clap::Arg::with_name("tile_background_color")
                .long("tile_background_color")
                .takes_value(true)
                .possible_values(&TileBackgroundColorArgument::variants())
                .default_value("white"),
        ])
        .get_matches()
}

fn run(
    octree_locations: &[String],
    output_filename: &Path,
    resolution: f64,
    coloring_strategy_kind: &ColoringStrategyKind,
    tile_background_color: Color<u8>,
    bbox2: &Aabb2<f64>,
) -> Result<(), Box<dyn Error>> {
    let octree_factory = OctreeFactory::new().register("grpc://", octree_from_grpc_address);
    let point_cloud_client = PointCloudClient::new(octree_locations, octree_factory)?;
    let bbox3 = point_cloud_client.bounding_box();
    let bbox3 = Aabb3::new(
        Point3::new(
            bbox2.min().x.max(bbox3.min().x),
            bbox2.min().y.max(bbox3.min().y),
            bbox3.min().z,
        ),
        Point3::new(
            bbox2.max().x.min(bbox3.max().x),
            bbox2.max().y.min(bbox3.max().y),
            bbox3.max().z,
        ),
    );
    let image_width = (bbox2.dim().x / resolution).ceil() as u32;
    let image_height = (bbox2.dim().y / resolution).ceil() as u32;
    if !xray_from_points(
        &point_cloud_client,
        &None,
        &bbox3,
        output_filename,
        Vector2::new(image_width, image_height),
        coloring_strategy_kind.new_strategy(),
        tile_background_color,
    ) {
        println!("No points in bounding box. No output written.");
    }
    Ok(())
}

pub fn main() {
    let matches = parse_arguments();
    let resolution = value_t!(matches, "resolution", f64).expect("resolution could not be parsed.");
    let coloring_strategy_kind = {
        use crate::ColoringStrategyArgument::*;
        let arg = value_t!(matches, "coloring_strategy", ColoringStrategyArgument)
            .expect("coloring_strategy is invalid");
        match arg {
            xray => ColoringStrategyKind::XRay,
            colored => ColoringStrategyKind::Colored,
            colored_with_intensity => ColoringStrategyKind::ColoredWithIntensity(
                value_t!(matches, "min_intensity", f32).unwrap_or(1.),
                value_t!(matches, "max_intensity", f32).unwrap_or(1.),
            ),
            colored_with_height_stddev => ColoringStrategyKind::ColoredWithHeightStddev(
                value_t!(matches, "max_stddev", f32).unwrap_or(1.),
            ),
        }
    };
    let tile_background_color = {
        let arg = value_t!(
            matches,
            "tile_background_color",
            TileBackgroundColorArgument
        )
        .expect("tile_background_color is invalid");
        match arg {
            TileBackgroundColorArgument::white => WHITE.to_u8(),
            TileBackgroundColorArgument::transparent => TRANSPARENT.to_u8(),
        }
    };
    let octree_locations = matches
        .values_of("octree_locations")
        .unwrap()
        .map(String::from)
        .collect::<Vec<_>>();
    let output_filename = Path::new(matches.value_of("output_filename").unwrap());
    let min_x = value_t!(matches, "min_x", f64).expect("min_x could not be parsed.");
    let min_y = value_t!(matches, "min_y", f64).expect("min_y could not be parsed.");
    let max_x = value_t!(matches, "max_x", f64).expect("max_x could not be parsed.");
    let max_y = value_t!(matches, "max_y", f64).expect("max_y could not be parsed.");

    let bbox2 = Aabb2::new(Point2::new(min_x, min_y), Point2::new(max_x, max_y));
    run(
        &octree_locations,
        output_filename,
        resolution,
        &coloring_strategy_kind,
        tile_background_color,
        &bbox2,
    )
    .unwrap();
}
<commit_msg>Remove build_xray_tile which is no longer useful. (#319)<commit_after><|endoftext|>