<commit_before>use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::{walk_item, walk_path, walk_ty, NestedVisitorMap, Visitor};
use rustc_hir::{
    def, FnDecl, FnRetTy, FnSig, GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind, Path, PathSegment, QPath,
    TyKind,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::map::Map;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
use rustc_middle::ty::{DefIdTree, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::kw;

use crate::utils::{differing_macro_contexts, span_lint_and_sugg};

declare_clippy_lint! {
    /// **What it does:** Checks for unnecessary repetition of structure name when a
    /// replacement with `Self` is applicable.
    ///
    /// **Why is this bad?** Unnecessary repetition. Mixed use of `Self` and struct
    /// name
    /// feels inconsistent.
    ///
    /// **Known problems:**
    /// - False positive when using associated types (#2843)
    /// - False positives in some situations when using generics (#3410)
    ///
    /// **Example:**
    /// ```rust
    /// struct Foo {}
    /// impl Foo {
    ///     fn new() -> Foo {
    ///         Foo {}
    ///     }
    /// }
    /// ```
    /// could be
    /// ```rust
    /// struct Foo {}
    /// impl Foo {
    ///     fn new() -> Self {
    ///         Self {}
    ///     }
    /// }
    /// ```
    pub USE_SELF,
    nursery,
    "Unnecessary structure name repetition whereas `Self` is applicable"
}

declare_lint_pass!(UseSelf => [USE_SELF]);

const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element";

fn span_use_self_lint(cx: &LateContext<'_, '_>, path: &Path<'_>, last_segment: Option<&PathSegment<'_>>) {
    let last_segment = last_segment.unwrap_or_else(|| path.segments.last().expect(SEGMENTS_MSG));

    // Path segments only include actual path, no methods or fields.
    let last_path_span = last_segment.ident.span;

    if differing_macro_contexts(path.span, last_path_span) {
        return;
    }

    // Only take path up to the end of last_path_span.
    let span = path.span.with_hi(last_path_span.hi());

    span_lint_and_sugg(
        cx,
        USE_SELF,
        span,
        "unnecessary structure name repetition",
        "use the applicable keyword",
        "Self".to_owned(),
        Applicability::MachineApplicable,
    );
}

struct TraitImplTyVisitor<'a, 'tcx> {
    item_type: Ty<'tcx>,
    cx: &'a LateContext<'a, 'tcx>,
    trait_type_walker: ty::walk::TypeWalker<'tcx>,
    impl_type_walker: ty::walk::TypeWalker<'tcx>,
}

impl<'a, 'tcx> Visitor<'tcx> for TraitImplTyVisitor<'a, 'tcx> {
    type Map = Map<'tcx>;

    fn visit_ty(&mut self, t: &'tcx hir::Ty<'_>) {
        let trait_ty = self.trait_type_walker.next();
        let impl_ty = self.impl_type_walker.next();

        if_chain! {
            if let TyKind::Path(QPath::Resolved(_, path)) = &t.kind;

            // The implementation and trait types don't match which means that
            // the concrete type was specified by the implementation
            if impl_ty != trait_ty;
            if let Some(impl_ty) = impl_ty;
            if self.item_type == impl_ty;
            then {
                match path.res {
                    def::Res::SelfTy(..) => {},
                    _ => span_use_self_lint(self.cx, path, None)
                }
            }
        }

        walk_ty(self, t)
    }

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::None
    }
}

fn check_trait_method_impl_decl<'a, 'tcx>(
    cx: &'a LateContext<'a, 'tcx>,
    item_type: Ty<'tcx>,
    impl_item: &ImplItem<'_>,
    impl_decl: &'tcx FnDecl<'_>,
    impl_trait_ref: &ty::TraitRef<'_>,
) {
    let trait_method = cx
        .tcx
        .associated_items(impl_trait_ref.def_id)
        .find_by_name_and_kind(cx.tcx, impl_item.ident, ty::AssocKind::Method, impl_trait_ref.def_id)
        .expect("impl method matches a trait method");

    let trait_method_sig = cx.tcx.fn_sig(trait_method.def_id);
    let trait_method_sig = cx.tcx.erase_late_bound_regions(&trait_method_sig);

    let impl_method_def_id = cx.tcx.hir().local_def_id(impl_item.hir_id);
    let impl_method_sig = cx.tcx.fn_sig(impl_method_def_id);
    let impl_method_sig = cx.tcx.erase_late_bound_regions(&impl_method_sig);

    let output_ty = if let FnRetTy::Return(ty) = &impl_decl.output {
        Some(&**ty)
    } else {
        None
    };

    // `impl_decl_ty` (of type `hir::Ty`) represents the type declared in the signature.
    // `impl_ty` (of type `ty:TyS`) is the concrete type that the compiler has determined for
    // that declaration. We use `impl_decl_ty` to see if the type was declared as `Self`
    // and use `impl_ty` to check its concrete type.
    for (impl_decl_ty, (impl_ty, trait_ty)) in impl_decl.inputs.iter().chain(output_ty).zip(
        impl_method_sig
            .inputs_and_output
            .iter()
            .zip(trait_method_sig.inputs_and_output),
    ) {
        let mut visitor = TraitImplTyVisitor {
            cx,
            item_type,
            trait_type_walker: trait_ty.walk(),
            impl_type_walker: impl_ty.walk(),
        };

        visitor.visit_ty(&impl_decl_ty);
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UseSelf {
    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item<'_>) {
        if in_external_macro(cx.sess(), item.span) {
            return;
        }
        if_chain! {
            if let ItemKind::Impl{ self_ty: ref item_type, items: refs, .. } = item.kind;
            if let TyKind::Path(QPath::Resolved(_, ref item_path)) = item_type.kind;
            then {
                let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args;
                let should_check = if let Some(ref params) = *parameters {
                    !params.parenthesized && !params.args.iter().any(|arg| match arg {
                        GenericArg::Lifetime(_) => true,
                        _ => false,
                    })
                } else {
                    true
                };

                if should_check {
                    let visitor = &mut UseSelfVisitor {
                        item_path,
                        cx,
                    };
                    let impl_def_id = cx.tcx.hir().local_def_id(item.hir_id);
                    let impl_trait_ref = cx.tcx.impl_trait_ref(impl_def_id);

                    if let Some(impl_trait_ref) = impl_trait_ref {
                        for impl_item_ref in refs {
                            let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
                            if let ImplItemKind::Fn(FnSig{ decl: impl_decl, .. }, impl_body_id)
                                    = &impl_item.kind {
                                let item_type = cx.tcx.type_of(impl_def_id);
                                check_trait_method_impl_decl(cx, item_type, impl_item, impl_decl, &impl_trait_ref);

                                let body = cx.tcx.hir().body(*impl_body_id);
                                visitor.visit_body(body);
                            } else {
                                visitor.visit_impl_item(impl_item);
                            }
                        }
                    } else {
                        for impl_item_ref in refs {
                            let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
                            visitor.visit_impl_item(impl_item);
                        }
                    }
                }
            }
        }
    }
}

struct UseSelfVisitor<'a, 'tcx> {
    item_path: &'a Path<'a>,
    cx: &'a LateContext<'a, 'tcx>,
}

impl<'a, 'tcx> Visitor<'tcx> for UseSelfVisitor<'a, 'tcx> {
    type Map = Map<'tcx>;

    fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) {
        if !path.segments.iter().any(|p| p.ident.span.is_dummy()) {
            if path.segments.len() >= 2 {
                let last_but_one = &path.segments[path.segments.len() - 2];
                if last_but_one.ident.name != kw::SelfUpper {
                    let enum_def_id = match path.res {
                        Res::Def(DefKind::Variant, variant_def_id) => self.cx.tcx.parent(variant_def_id),
                        Res::Def(DefKind::Ctor(def::CtorOf::Variant, _), ctor_def_id) => {
                            let variant_def_id = self.cx.tcx.parent(ctor_def_id);
                            variant_def_id.and_then(|def_id| self.cx.tcx.parent(def_id))
                        },
                        _ => None,
                    };

                    if self.item_path.res.opt_def_id() == enum_def_id {
                        span_use_self_lint(self.cx, path, Some(last_but_one));
                    }
                }
            }

            if path.segments.last().expect(SEGMENTS_MSG).ident.name != kw::SelfUpper {
                if self.item_path.res == path.res {
                    span_use_self_lint(self.cx, path, None);
                } else if let Res::Def(DefKind::Ctor(def::CtorOf::Struct, _), ctor_def_id) = path.res {
                    if self.item_path.res.opt_def_id() == self.cx.tcx.parent(ctor_def_id) {
                        span_use_self_lint(self.cx, path, None);
                    }
                }
            }
        }

        walk_path(self, path);
    }

    fn visit_item(&mut self, item: &'tcx Item<'_>) {
        match item.kind {
            ItemKind::Use(..)
            | ItemKind::Static(..)
            | ItemKind::Enum(..)
            | ItemKind::Struct(..)
            | ItemKind::Union(..)
            | ItemKind::Impl { .. }
            | ItemKind::Fn(..) => {
                // Don't check statements that shadow `Self` or where `Self` can't be used
            },
            _ => walk_item(self, item),
        }
    }

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::All(self.cx.tcx.hir())
    }
}
<commit_msg>use_self: switch to hir_ty_to_ty.<commit_after>use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::{walk_item, walk_path, walk_ty, NestedVisitorMap, Visitor};
use rustc_hir::{
    def, FnDecl, FnRetTy, FnSig, GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind, Path, PathSegment, QPath,
    TyKind,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::map::Map;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
use rustc_middle::ty::{DefIdTree, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::kw;
use rustc_typeck::hir_ty_to_ty;

use crate::utils::{differing_macro_contexts, span_lint_and_sugg};

declare_clippy_lint! {
    /// **What it does:** Checks for unnecessary repetition of structure name when a
    /// replacement with `Self` is applicable.
    ///
    /// **Why is this bad?** Unnecessary repetition. Mixed use of `Self` and struct
    /// name
    /// feels inconsistent.
    ///
    /// **Known problems:**
    /// - False positive when using associated types (#2843)
    /// - False positives in some situations when using generics (#3410)
    ///
    /// **Example:**
    /// ```rust
    /// struct Foo {}
    /// impl Foo {
    ///     fn new() -> Foo {
    ///         Foo {}
    ///     }
    /// }
    /// ```
    /// could be
    /// ```rust
    /// struct Foo {}
    /// impl Foo {
    ///     fn new() -> Self {
    ///         Self {}
    ///     }
    /// }
    /// ```
    pub USE_SELF,
    nursery,
    "Unnecessary structure name repetition whereas `Self` is applicable"
}

declare_lint_pass!(UseSelf => [USE_SELF]);

const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element";

fn span_use_self_lint(cx: &LateContext<'_, '_>, path: &Path<'_>, last_segment: Option<&PathSegment<'_>>) {
    let last_segment = last_segment.unwrap_or_else(|| path.segments.last().expect(SEGMENTS_MSG));

    // Path segments only include actual path, no methods or fields.
    let last_path_span = last_segment.ident.span;

    if differing_macro_contexts(path.span, last_path_span) {
        return;
    }

    // Only take path up to the end of last_path_span.
    let span = path.span.with_hi(last_path_span.hi());

    span_lint_and_sugg(
        cx,
        USE_SELF,
        span,
        "unnecessary structure name repetition",
        "use the applicable keyword",
        "Self".to_owned(),
        Applicability::MachineApplicable,
    );
}

// FIXME: always use this (more correct) visitor, not just in method signatures.
struct SemanticUseSelfVisitor<'a, 'tcx> {
    cx: &'a LateContext<'a, 'tcx>,
    self_ty: Ty<'tcx>,
}

impl<'a, 'tcx> Visitor<'tcx> for SemanticUseSelfVisitor<'a, 'tcx> {
    type Map = Map<'tcx>;

    fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'_>) {
        if let TyKind::Path(QPath::Resolved(_, path)) = &hir_ty.kind {
            match path.res {
                def::Res::SelfTy(..) => {},
                _ => {
                    if hir_ty_to_ty(self.cx.tcx, hir_ty) == self.self_ty {
                        span_use_self_lint(self.cx, path, None);
                    }
                },
            }
        }

        walk_ty(self, hir_ty)
    }

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::None
    }
}

fn check_trait_method_impl_decl<'a, 'tcx>(
    cx: &'a LateContext<'a, 'tcx>,
    impl_item: &ImplItem<'_>,
    impl_decl: &'tcx FnDecl<'_>,
    impl_trait_ref: ty::TraitRef<'tcx>,
) {
    let trait_method = cx
        .tcx
        .associated_items(impl_trait_ref.def_id)
        .find_by_name_and_kind(cx.tcx, impl_item.ident, ty::AssocKind::Method, impl_trait_ref.def_id)
        .expect("impl method matches a trait method");

    let trait_method_sig = cx.tcx.fn_sig(trait_method.def_id);
    let trait_method_sig = cx.tcx.erase_late_bound_regions(&trait_method_sig);

    let output_hir_ty = if let FnRetTy::Return(ty) = &impl_decl.output {
        Some(&**ty)
    } else {
        None
    };

    // `impl_hir_ty` (of type `hir::Ty`) represents the type written in the signature.
    // `trait_ty` (of type `ty::Ty`) is the semantic type for the signature in the trait.
    // We use `impl_hir_ty` to see if the type was written as `Self`,
    // `hir_ty_to_ty(...)` to check semantic types of paths, and
    // `trait_ty` to determine which parts of the signature in the trait, mention
    // the type being implemented verbatim (as opposed to `Self`).
    for (impl_hir_ty, trait_ty) in impl_decl
        .inputs
        .iter()
        .chain(output_hir_ty)
        .zip(trait_method_sig.inputs_and_output)
    {
        // Check if the input/output type in the trait method specifies the implemented
        // type verbatim, and only suggest `Self` if that isn't the case.
        // This avoids suggestions to e.g. replace `Vec<u8>` with `Vec<Self>`,
        // in an `impl Trait for u8`, when the trait always uses `Vec<u8>`.
        // See also https://github.com/rust-lang/rust-clippy/issues/2894.
        let self_ty = impl_trait_ref.self_ty();
        if !trait_ty.walk().any(|inner| inner == self_ty.into()) {
            let mut visitor = SemanticUseSelfVisitor { cx, self_ty };

            visitor.visit_ty(&impl_hir_ty);
        }
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UseSelf {
    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item<'_>) {
        if in_external_macro(cx.sess(), item.span) {
            return;
        }
        if_chain! {
            if let ItemKind::Impl{ self_ty: ref item_type, items: refs, .. } = item.kind;
            if let TyKind::Path(QPath::Resolved(_, ref item_path)) = item_type.kind;
            then {
                let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args;
                let should_check = if let Some(ref params) = *parameters {
                    !params.parenthesized && !params.args.iter().any(|arg| match arg {
                        GenericArg::Lifetime(_) => true,
                        _ => false,
                    })
                } else {
                    true
                };

                if should_check {
                    let visitor = &mut UseSelfVisitor {
                        item_path,
                        cx,
                    };
                    let impl_def_id = cx.tcx.hir().local_def_id(item.hir_id);
                    let impl_trait_ref = cx.tcx.impl_trait_ref(impl_def_id);

                    if let Some(impl_trait_ref) = impl_trait_ref {
                        for impl_item_ref in refs {
                            let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
                            if let ImplItemKind::Fn(FnSig{ decl: impl_decl, .. }, impl_body_id)
                                    = &impl_item.kind {
                                check_trait_method_impl_decl(cx, impl_item, impl_decl, impl_trait_ref);

                                let body = cx.tcx.hir().body(*impl_body_id);
                                visitor.visit_body(body);
                            } else {
                                visitor.visit_impl_item(impl_item);
                            }
                        }
                    } else {
                        for impl_item_ref in refs {
                            let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
                            visitor.visit_impl_item(impl_item);
                        }
                    }
                }
            }
        }
    }
}

struct UseSelfVisitor<'a, 'tcx> {
    item_path: &'a Path<'a>,
    cx: &'a LateContext<'a, 'tcx>,
}

impl<'a, 'tcx> Visitor<'tcx> for UseSelfVisitor<'a, 'tcx> {
    type Map = Map<'tcx>;

    fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) {
        if !path.segments.iter().any(|p| p.ident.span.is_dummy()) {
            if path.segments.len() >= 2 {
                let last_but_one = &path.segments[path.segments.len() - 2];
                if last_but_one.ident.name != kw::SelfUpper {
                    let enum_def_id = match path.res {
                        Res::Def(DefKind::Variant, variant_def_id) => self.cx.tcx.parent(variant_def_id),
                        Res::Def(DefKind::Ctor(def::CtorOf::Variant, _), ctor_def_id) => {
                            let variant_def_id = self.cx.tcx.parent(ctor_def_id);
                            variant_def_id.and_then(|def_id| self.cx.tcx.parent(def_id))
                        },
                        _ => None,
                    };

                    if self.item_path.res.opt_def_id() == enum_def_id {
                        span_use_self_lint(self.cx, path, Some(last_but_one));
                    }
                }
            }

            if path.segments.last().expect(SEGMENTS_MSG).ident.name != kw::SelfUpper {
                if self.item_path.res == path.res {
                    span_use_self_lint(self.cx, path, None);
                } else if let Res::Def(DefKind::Ctor(def::CtorOf::Struct, _), ctor_def_id) = path.res {
                    if self.item_path.res.opt_def_id() == self.cx.tcx.parent(ctor_def_id) {
                        span_use_self_lint(self.cx, path, None);
                    }
                }
            }
        }

        walk_path(self, path);
    }

    fn visit_item(&mut self, item: &'tcx Item<'_>) {
        match item.kind {
            ItemKind::Use(..)
            | ItemKind::Static(..)
            | ItemKind::Enum(..)
            | ItemKind::Struct(..)
            | ItemKind::Union(..)
            | ItemKind::Impl { .. }
            | ItemKind::Fn(..) => {
                // Don't check statements that shadow `Self` or where `Self` can't be used
            },
            _ => walk_item(self, item),
        }
    }

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::All(self.cx.tcx.hir())
    }
}
<|endoftext|>


<commit_before><commit_msg>Catch call to module.require<commit_after><|endoftext|>


<commit_before>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

// FIXME: Missings methods

use libc::{c_int, c_uint};

use {PositionType};
use cast::GTK_GRID;
use ffi;
use glib::{to_bool, to_gboolean};

struct_Widget!(Grid);

impl Grid {
    pub fn new() -> Option<Grid> {
        assert_initialized_main_thread!();
        let tmp_pointer = unsafe { ffi::gtk_grid_new() };
        check_pointer!(tmp_pointer, Grid)
    }

    pub fn attach<T: ::WidgetTrait>(&self,
                                child: &T,
                                left: i32,
                                top: i32,
                                width: i32,
                                height: i32) -> () {
        unsafe {
            ffi::gtk_grid_attach(GTK_GRID(self.pointer),
                                 child.unwrap_widget(),
                                 left as c_int,
                                 top as c_int,
                                 width as c_int,
                                 height as c_int);
        }
    }

    pub fn attach_next_to<T: ::WidgetTrait, T2: ::WidgetTrait>(&self,
                                        child: &T,
                                        sibling: &T2,
                                        side: PositionType,
                                        width: i32,
                                        height: i32) -> () {
        unsafe {
            ffi::gtk_grid_attach_next_to(GTK_GRID(self.pointer),
                                         child.unwrap_widget(),
                                         sibling.unwrap_widget(),
                                         side,
                                         width as c_int,
                                         height as c_int);
        }
    }

    pub unsafe fn get_child_at<T: ::WidgetTrait>(&self, left: i32, top: i32) -> Option<T> {
        let tmp_pointer = unsafe {
            ffi::gtk_grid_get_child_at(GTK_GRID(self.pointer), left, top)
        };

        if tmp_pointer.is_null() {
            None
        } else {
            Some(::FFIWidget::wrap_widget(tmp_pointer))
        }
    }

    pub fn insert_row(&self, position: i32) -> () {
        unsafe {
            ffi::gtk_grid_insert_row(GTK_GRID(self.pointer), position as c_int);
        }
    }

     pub fn insert_column(&self, position: i32) -> () {
        unsafe {
            ffi::gtk_grid_insert_column(GTK_GRID(self.pointer), position as c_int);
        }
    }

    #[cfg(gtk_3_10)]
     pub fn remove_row(&self, position: i32) -> () {
        unsafe {
            ffi::gtk_grid_remove_row(GTK_GRID(self.pointer), position as c_int);
        }
    }

    #[cfg(gtk_3_10)]
     pub fn remove_column(&self, position: i32) -> () {
        unsafe {
            ffi::gtk_grid_remove_column(GTK_GRID(self.pointer), position as c_int);
        }
    }

    pub fn insert_next_to<T: ::WidgetTrait>(&self, sibling: &T, side: PositionType) -> () {
        unsafe {
            ffi::gtk_grid_insert_next_to(GTK_GRID(self.pointer), sibling.unwrap_widget(), side);
        }
    }

    pub fn set_row_homogeneous(&self, homogeneous: bool) -> () {
        unsafe { ffi::gtk_grid_set_row_homogeneous(GTK_GRID(self.pointer), to_gboolean(homogeneous)); }
    }

    pub fn get_row_homogeneous(&self) -> bool {
        unsafe { to_bool(ffi::gtk_grid_get_row_homogeneous(GTK_GRID(self.pointer))) }
    }

    pub fn set_row_spacing(&self, spacing: u32) -> () {
        unsafe {
            ffi::gtk_grid_set_row_spacing(GTK_GRID(self.pointer), spacing as c_uint);
        }
    }

    pub fn get_row_spacing(&self) -> u32 {
        unsafe {
            ffi::gtk_grid_get_row_spacing(GTK_GRID(self.pointer)) as u32
        }
    }

    pub fn set_column_homogeneous(&self, homogeneous: bool) -> () {
        unsafe { ffi::gtk_grid_set_column_homogeneous(GTK_GRID(self.pointer), to_gboolean(homogeneous)); }
    }

    pub fn get_column_homogeneous(&self) -> bool {
        unsafe { to_bool(ffi::gtk_grid_get_column_homogeneous(GTK_GRID(self.pointer))) }
    }

    pub fn set_column_spacing(&self, spacing: u32) -> () {
        unsafe {
            ffi::gtk_grid_set_column_spacing(GTK_GRID(self.pointer), spacing as c_uint);
        }
    }

    pub fn get_column_spacing(&self) -> u32 {
        unsafe {
            ffi::gtk_grid_get_column_spacing(GTK_GRID(self.pointer)) as u32
        }
    }

    #[cfg(gtk_3_10)]
    pub fn get_baseline_row(&self) -> i32 {
        unsafe {
            ffi::gtk_grid_get_baseline_row(GTK_GRID(self.pointer)) as i32
        }
    }

    #[cfg(gtk_3_10)]
    pub fn set_baseline_row(&self, row: i32) -> () {
        unsafe {
            ffi::gtk_grid_set_baseline_row(GTK_GRID(self.pointer), row as c_int);
        }
    }
}

impl_drop!(Grid);
impl_TraitWidget!(Grid);

impl ::ContainerTrait for Grid {}
impl ::OrientableTrait for Grid {}
<commit_msg>Remove redundant unsafe block<commit_after>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

// FIXME: Missings methods

use libc::{c_int, c_uint};

use {PositionType};
use cast::GTK_GRID;
use ffi;
use glib::{to_bool, to_gboolean};

struct_Widget!(Grid);

impl Grid {
    pub fn new() -> Option<Grid> {
        assert_initialized_main_thread!();
        let tmp_pointer = unsafe { ffi::gtk_grid_new() };
        check_pointer!(tmp_pointer, Grid)
    }

    pub fn attach<T: ::WidgetTrait>(&self,
                                child: &T,
                                left: i32,
                                top: i32,
                                width: i32,
                                height: i32) -> () {
        unsafe {
            ffi::gtk_grid_attach(GTK_GRID(self.pointer),
                                 child.unwrap_widget(),
                                 left as c_int,
                                 top as c_int,
                                 width as c_int,
                                 height as c_int);
        }
    }

    pub fn attach_next_to<T: ::WidgetTrait, T2: ::WidgetTrait>(&self,
                                        child: &T,
                                        sibling: &T2,
                                        side: PositionType,
                                        width: i32,
                                        height: i32) -> () {
        unsafe {
            ffi::gtk_grid_attach_next_to(GTK_GRID(self.pointer),
                                         child.unwrap_widget(),
                                         sibling.unwrap_widget(),
                                         side,
                                         width as c_int,
                                         height as c_int);
        }
    }

    pub unsafe fn get_child_at<T: ::WidgetTrait>(&self, left: i32, top: i32) -> Option<T> {
        let tmp_pointer = ffi::gtk_grid_get_child_at(GTK_GRID(self.pointer), left, top);

        if tmp_pointer.is_null() {
            None
        } else {
            Some(::FFIWidget::wrap_widget(tmp_pointer))
        }
    }

    pub fn insert_row(&self, position: i32) -> () {
        unsafe {
            ffi::gtk_grid_insert_row(GTK_GRID(self.pointer), position as c_int);
        }
    }

     pub fn insert_column(&self, position: i32) -> () {
        unsafe {
            ffi::gtk_grid_insert_column(GTK_GRID(self.pointer), position as c_int);
        }
    }

    #[cfg(gtk_3_10)]
     pub fn remove_row(&self, position: i32) -> () {
        unsafe {
            ffi::gtk_grid_remove_row(GTK_GRID(self.pointer), position as c_int);
        }
    }

    #[cfg(gtk_3_10)]
     pub fn remove_column(&self, position: i32) -> () {
        unsafe {
            ffi::gtk_grid_remove_column(GTK_GRID(self.pointer), position as c_int);
        }
    }

    pub fn insert_next_to<T: ::WidgetTrait>(&self, sibling: &T, side: PositionType) -> () {
        unsafe {
            ffi::gtk_grid_insert_next_to(GTK_GRID(self.pointer), sibling.unwrap_widget(), side);
        }
    }

    pub fn set_row_homogeneous(&self, homogeneous: bool) -> () {
        unsafe { ffi::gtk_grid_set_row_homogeneous(GTK_GRID(self.pointer), to_gboolean(homogeneous)); }
    }

    pub fn get_row_homogeneous(&self) -> bool {
        unsafe { to_bool(ffi::gtk_grid_get_row_homogeneous(GTK_GRID(self.pointer))) }
    }

    pub fn set_row_spacing(&self, spacing: u32) -> () {
        unsafe {
            ffi::gtk_grid_set_row_spacing(GTK_GRID(self.pointer), spacing as c_uint);
        }
    }

    pub fn get_row_spacing(&self) -> u32 {
        unsafe {
            ffi::gtk_grid_get_row_spacing(GTK_GRID(self.pointer)) as u32
        }
    }

    pub fn set_column_homogeneous(&self, homogeneous: bool) -> () {
        unsafe { ffi::gtk_grid_set_column_homogeneous(GTK_GRID(self.pointer), to_gboolean(homogeneous)); }
    }

    pub fn get_column_homogeneous(&self) -> bool {
        unsafe { to_bool(ffi::gtk_grid_get_column_homogeneous(GTK_GRID(self.pointer))) }
    }

    pub fn set_column_spacing(&self, spacing: u32) -> () {
        unsafe {
            ffi::gtk_grid_set_column_spacing(GTK_GRID(self.pointer), spacing as c_uint);
        }
    }

    pub fn get_column_spacing(&self) -> u32 {
        unsafe {
            ffi::gtk_grid_get_column_spacing(GTK_GRID(self.pointer)) as u32
        }
    }

    #[cfg(gtk_3_10)]
    pub fn get_baseline_row(&self) -> i32 {
        unsafe {
            ffi::gtk_grid_get_baseline_row(GTK_GRID(self.pointer)) as i32
        }
    }

    #[cfg(gtk_3_10)]
    pub fn set_baseline_row(&self, row: i32) -> () {
        unsafe {
            ffi::gtk_grid_set_baseline_row(GTK_GRID(self.pointer), row as c_int);
        }
    }
}

impl_drop!(Grid);
impl_TraitWidget!(Grid);

impl ::ContainerTrait for Grid {}
impl ::OrientableTrait for Grid {}
<|endoftext|>


<commit_before>use core::cell::Cell;
use hil::{Callback, Driver, NUM_PROCS};
use hil::alarm::{Alarm, AlarmClient};
use hil::timer::{Timer, TimerClient};

#[derive(Copy, Clone)]
enum Schedule {
    Oneshot,
    Repeating { interval: u32 }
}

pub struct AlarmToTimer<'a, Alrm: Alarm + 'a> {
    schedule: Cell<Schedule>,
    alarm: &'a Alrm,
    client: Cell<Option<&'a TimerClient>>
}

impl<'a, Alrm: Alarm> AlarmToTimer<'a, Alrm> {
    pub const fn new(alarm: &'a Alrm) -> AlarmToTimer<'a, Alrm> {
        AlarmToTimer {
            schedule: Cell::new(Schedule::Oneshot),
            alarm: alarm,
            client: Cell::new(None)
        }
    }

    pub fn set_client(&self, client: &'a TimerClient) {
        self.client.set(Some(client));
    }
}

impl<'a, Alrm: Alarm> Timer for AlarmToTimer<'a, Alrm> {
    fn now(&self) -> u32 {
        self.alarm.now()
    }

    fn oneshot(&self, interval: u32) {
        self.schedule.set(Schedule::Oneshot);

        let when = interval.wrapping_add(self.alarm.now());
        self.alarm.set_alarm(when);
    }

    fn repeat(&self, interval: u32) {
        self.schedule.set(Schedule::Repeating {interval: interval});

        let when = interval.wrapping_add(self.alarm.now());
        self.alarm.set_alarm(when);
    }
}

impl<'a, Alrm: Alarm> AlarmClient for AlarmToTimer<'a, Alrm> {
    fn fired(&self) {
        let now = self.now();

        match self.schedule.get() {
            Schedule::Oneshot => self.alarm.disable_alarm(),

            Schedule::Repeating { interval } => {
                let when = interval.wrapping_add(now);
                self.alarm.set_alarm(when);
            }
        }

        self.client.get().map(|client| client.fired(now) );
    }
}

#[derive(Copy, Clone)]
struct TimerData {
    t0: u32,
    interval: u32,
    repeating: bool,
    callback: Callback
}

pub struct TimerDriver<'a, T: Timer + 'a> {
    timer: &'a T,
    app_timers: [Cell<Option<TimerData>>; NUM_PROCS]
}

impl<'a, T: Timer> Driver for TimerDriver<'a, T> {
    fn subscribe(&self, subscribe_type: usize, callback: Callback) -> isize {
        let interval = 115000;
        match subscribe_type {
            0 /* Oneshot */ => {
                self.app_timers[callback.app_id().idx()].set(Some(TimerData {
                    t0: self.timer.now(),
                    interval: interval,
                    repeating: false,
                    callback: callback
                }));
                self.timer.oneshot(interval);
                0
            },
            _ => -1
        }
    }
}

impl<'a, T: Timer> TimerClient for TimerDriver<'a, T> {
    fn fired(&self, now: u32) {
        for mtimer in self.app_timers.iter() {
            mtimer.get().map(|timer| {
                let elapsed = now.wrapping_sub(timer.t0);
                if elapsed >= timer.interval {
                    let mut cb = timer.callback;
                    cb.schedule(now as usize, 0, 0);
                }
            });
        }
    }
}

<commit_msg>Add repeating subscription to timer driver<commit_after>use core::cell::Cell;
use hil::{Callback, Driver, NUM_PROCS};
use hil::alarm::{Alarm, AlarmClient};
use hil::timer::{Timer, TimerClient};

#[derive(Copy, Clone)]
enum Schedule {
    Oneshot,
    Repeating { interval: u32 }
}

pub struct AlarmToTimer<'a, Alrm: Alarm + 'a> {
    schedule: Cell<Schedule>,
    alarm: &'a Alrm,
    client: Cell<Option<&'a TimerClient>>
}

impl<'a, Alrm: Alarm> AlarmToTimer<'a, Alrm> {
    pub const fn new(alarm: &'a Alrm) -> AlarmToTimer<'a, Alrm> {
        AlarmToTimer {
            schedule: Cell::new(Schedule::Oneshot),
            alarm: alarm,
            client: Cell::new(None)
        }
    }

    pub fn set_client(&self, client: &'a TimerClient) {
        self.client.set(Some(client));
    }
}

impl<'a, Alrm: Alarm> Timer for AlarmToTimer<'a, Alrm> {
    fn now(&self) -> u32 {
        self.alarm.now()
    }

    fn oneshot(&self, interval: u32) {
        self.schedule.set(Schedule::Oneshot);

        let when = interval.wrapping_add(self.alarm.now());
        self.alarm.set_alarm(when);
    }

    fn repeat(&self, interval: u32) {
        self.schedule.set(Schedule::Repeating {interval: interval});

        let when = interval.wrapping_add(self.alarm.now());
        self.alarm.set_alarm(when);
    }
}

impl<'a, Alrm: Alarm> AlarmClient for AlarmToTimer<'a, Alrm> {
    fn fired(&self) {
        let now = self.now();

        match self.schedule.get() {
            Schedule::Oneshot => self.alarm.disable_alarm(),

            Schedule::Repeating { interval } => {
                let when = interval.wrapping_add(now);
                self.alarm.set_alarm(when);
            }
        }

        self.client.get().map(|client| client.fired(now) );
    }
}

#[derive(Copy, Clone)]
struct TimerData {
    t0: u32,
    interval: u32,
    repeating: bool,
    callback: Callback
}

pub struct TimerDriver<'a, T: Timer + 'a> {
    timer: &'a T,
    app_timers: [Cell<Option<TimerData>>; NUM_PROCS]
}

impl<'a, T: Timer> TimerDriver<'a, T> {
    pub const fn new(timer: &'a T) -> TimerDriver<'a, T> {
        TimerDriver {
            timer: timer,
            app_timers: [Cell::new(None); NUM_PROCS]
        }
    }
}

impl<'a, T: Timer> Driver for TimerDriver<'a, T> {
    fn subscribe(&self, subscribe_type: usize, callback: Callback) -> isize {
        let interval = 115000;
        match subscribe_type {
            0 /* Oneshot */ => {
                self.app_timers[callback.app_id().idx()].set(Some(TimerData {
                    t0: self.timer.now(),
                    interval: interval,
                    repeating: false,
                    callback: callback
                }));
                self.timer.oneshot(interval);
                0
            },
            1 /* Repeating */ => {
                self.app_timers[callback.app_id().idx()].set(Some(TimerData {
                    t0: self.timer.now(),
                    interval: interval,
                    repeating: true,
                    callback: callback
                }));
                self.timer.repeat(interval);
                0
            },
            _ => -1
        }
    }
}

impl<'a, T: Timer> TimerClient for TimerDriver<'a, T> {
    fn fired(&self, now: u32) {
        for mtimer in self.app_timers.iter() {
            mtimer.get().map(|timer| {
                let elapsed = now.wrapping_sub(timer.t0);
                if elapsed >= timer.interval {
                    let mut cb = timer.callback;
                    cb.schedule(now as usize, 0, 0);
                }
            });
        }
    }
}

<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::env;
use std::fs;
use std::path::Path;
use std::process::Command;

use core::{Package, PackageIdSpec};
use ops;
use util::CargoResult;

pub struct DocOptions<'a> {
    pub open_result: bool,
    pub compile_opts: ops::CompileOptions<'a>,
}

pub fn doc(manifest_path: &Path,
           options: &DocOptions) -> CargoResult<()> {
    let package = try!(Package::for_path(manifest_path, options.compile_opts.config));

    let mut lib_names = HashSet::new();
    let mut bin_names = HashSet::new();
    if options.compile_opts.spec.is_empty() {
        for target in package.targets().iter().filter(|t| t.documented()) {
            if target.is_lib() {
                assert!(lib_names.insert(target.crate_name()));
            } else {
                assert!(bin_names.insert(target.crate_name()));
            }
        }
        for bin in bin_names.iter() {
            if lib_names.contains(bin) {
                bail!("cannot document a package where a library and a binary \
                       have the same name. Consider renaming one or marking \
                       the target as `doc = false`")
            }
        }
    }

    try!(ops::compile(manifest_path, &options.compile_opts));

    if options.open_result {
        let name = if options.compile_opts.spec.len() > 1 {
            bail!("Passing multiple packages and `open` is not supported")
        } else if options.compile_opts.spec.len() == 1 {
            try!(PackageIdSpec::parse(&options.compile_opts.spec[0]))
                                             .name().replace("-", "_")
        } else {
            match lib_names.iter().chain(bin_names.iter()).nth(0) {
                Some(s) => s.to_string(),
                None => return Ok(())
            }
        };

        let target_dir = options.compile_opts.config.target_dir(&package);
        let path = target_dir.join("doc").join(&name).join("index.html");
        if fs::metadata(&path).is_ok() {
            let mut shell = options.compile_opts.config.shell();
            match open_docs(&path) {
                Ok(m) => try!(shell.status("Opening with", m)),
                Err(e) => {
                    try!(shell.warn(
                            "warning: could not determine a browser to open docs with, tried:"));
                    for method in e {
                        try!(shell.warn(format!("\t{}", method)));
                    }
                }
            }
        }
    }

    Ok(())
}

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
fn open_docs(path: &Path) -> Result<&'static str, Vec<&'static str>> {
    let mut methods = Vec::new();
    // trying $BROWSER
    match env::var("BROWSER").map(|name| Command::new(name).arg(path).status()) {
        Ok(_) => return Ok("$BROWSER"),
        Err(_) => methods.push("$BROWSER")
    }

    for m in ["xdg-open", "gnome-open", "kde-open"].iter() {
        match Command::new(m).arg(path).status() {
            Ok(_) => return Ok(m),
            Err(_) => methods.push(m)
        }
    }

    Err(methods)
}

#[cfg(target_os = "windows")]
fn open_docs(path: &Path) -> Result<&'static str, Vec<&'static str>> {
    match Command::new("cmd").arg("/C").arg("start").arg("").arg(path).status() {
        Ok(_) => return Ok("cmd /C start"),
        Err(_) => return Err(vec!["cmd /C start"])
    };
}

#[cfg(target_os = "macos")]
fn open_docs(path: &Path) -> Result<&'static str, Vec<&'static str>> {
    match Command::new("open").arg(path).status() {
        Ok(_) => return Ok("open"),
        Err(_) => return Err(vec!["open"])
    };
}
<commit_msg>Ignore $BROWSER if not set<commit_after>use std::collections::HashSet;
use std::env;
use std::fs;
use std::path::Path;
use std::process::Command;

use core::{Package, PackageIdSpec};
use ops;
use util::CargoResult;

pub struct DocOptions<'a> {
    pub open_result: bool,
    pub compile_opts: ops::CompileOptions<'a>,
}

pub fn doc(manifest_path: &Path,
           options: &DocOptions) -> CargoResult<()> {
    let package = try!(Package::for_path(manifest_path, options.compile_opts.config));

    let mut lib_names = HashSet::new();
    let mut bin_names = HashSet::new();
    if options.compile_opts.spec.is_empty() {
        for target in package.targets().iter().filter(|t| t.documented()) {
            if target.is_lib() {
                assert!(lib_names.insert(target.crate_name()));
            } else {
                assert!(bin_names.insert(target.crate_name()));
            }
        }
        for bin in bin_names.iter() {
            if lib_names.contains(bin) {
                bail!("cannot document a package where a library and a binary \
                       have the same name. Consider renaming one or marking \
                       the target as `doc = false`")
            }
        }
    }

    try!(ops::compile(manifest_path, &options.compile_opts));

    if options.open_result {
        let name = if options.compile_opts.spec.len() > 1 {
            bail!("Passing multiple packages and `open` is not supported")
        } else if options.compile_opts.spec.len() == 1 {
            try!(PackageIdSpec::parse(&options.compile_opts.spec[0]))
                                             .name().replace("-", "_")
        } else {
            match lib_names.iter().chain(bin_names.iter()).nth(0) {
                Some(s) => s.to_string(),
                None => return Ok(())
            }
        };

        let target_dir = options.compile_opts.config.target_dir(&package);
        let path = target_dir.join("doc").join(&name).join("index.html");
        if fs::metadata(&path).is_ok() {
            let mut shell = options.compile_opts.config.shell();
            match open_docs(&path) {
                Ok(m) => try!(shell.status("Launching", m)),
                Err(e) => {
                    try!(shell.warn(
                            "warning: could not determine a browser to open docs with, tried:"));
                    for method in e {
                        try!(shell.warn(format!("\t{}", method)));
                    }
                }
            }
        }
    }

    Ok(())
}

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
fn open_docs(path: &Path) -> Result<&'static str, Vec<&'static str>> {
    let mut methods = Vec::new();
    // trying $BROWSER
    match env::var("BROWSER"){
        Ok(name) => match Command::new(name).arg(path).status() {
            Ok(_) => return Ok("$BROWSER"),
            Err(_) => methods.push("$BROWSER")
        },
        Err(_) => () // Do nothing here if $BROWSER is not found
    }

    for m in ["xdg-open", "gnome-open", "kde-open"].iter() {
        match Command::new(m).arg(path).status() {
            Ok(_) => return Ok(m),
            Err(_) => methods.push(m)
        }
    }

    Err(methods)
}

#[cfg(target_os = "windows")]
fn open_docs(path: &Path) -> Result<&'static str, Vec<&'static str>> {
    match Command::new("cmd").arg("/C").arg("start").arg("").arg(path).status() {
        Ok(_) => return Ok("cmd /C start"),
        Err(_) => return Err(vec!["cmd /C start"])
    };
}

#[cfg(target_os = "macos")]
fn open_docs(path: &Path) -> Result<&'static str, Vec<&'static str>> {
    match Command::new("open").arg(path).status() {
        Ok(_) => return Ok("open"),
        Err(_) => return Err(vec!["open"])
    };
}
<|endoftext|>


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

//! Traversing the DOM tree; the bloom filter.

use animation;
use context::{LocalStyleContext, SharedStyleContext, StyleContext};
use dom::{OpaqueNode, TNode, TRestyleDamage, UnsafeNode};
use matching::{ApplicableDeclarations, ElementMatchMethods, MatchMethods, StyleSharingResult};
use selectors::bloom::BloomFilter;
use selectors::matching::StyleRelations;
use std::cell::RefCell;
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use tid::tid;
use util::opts;

/// Every time we do another layout, the old bloom filters are invalid. This is
/// detected by ticking a generation number every layout.
pub type Generation = u32;

/// This enum tells us about whether we can stop restyling or not after styling
/// an element.
///
/// So far this only happens where a display: none node is found.
pub enum RestyleResult {
    Continue,
    Stop,
}

/// Style sharing candidate cache stats. These are only used when
/// `-Z style-sharing-stats` is given.
pub static STYLE_SHARING_CACHE_HITS: AtomicUsize = ATOMIC_USIZE_INIT;
pub static STYLE_SHARING_CACHE_MISSES: AtomicUsize = ATOMIC_USIZE_INIT;

/// A pair of the bloom filter used for css selector matching, and the node to
/// which it applies. This is used to efficiently do `Descendant` selector
/// matches. Thanks to the bloom filter, we can avoid walking up the tree
/// looking for ancestors that aren't there in the majority of cases.
///
/// As we walk down the DOM tree a thread-local bloom filter is built of all the
/// CSS `SimpleSelector`s which are part of a `Descendant` compound selector
/// (i.e. paired with a `Descendant` combinator, in the `next` field of a
/// `CompoundSelector`.
///
/// Before a `Descendant` selector match is tried, it's compared against the
/// bloom filter. If the bloom filter can exclude it, the selector is quickly
/// rejected.
///
/// When done styling a node, all selectors previously inserted into the filter
/// are removed.
///
/// Since a work-stealing queue is used for styling, sometimes, the bloom filter
/// will no longer be the for the parent of the node we're currently on. When
/// this happens, the thread local bloom filter will be thrown away and rebuilt.
thread_local!(
    static STYLE_BLOOM: RefCell<Option<(Box<BloomFilter>, UnsafeNode, Generation)>> = RefCell::new(None));

/// Returns the thread local bloom filter.
///
/// If one does not exist, a new one will be made for you. If it is out of date,
/// it will be cleared and reused.
fn take_thread_local_bloom_filter<N>(parent_node: Option<N>,
                                     root: OpaqueNode,
                                     context: &SharedStyleContext)
                                     -> Box<BloomFilter>
                                     where N: TNode {
    STYLE_BLOOM.with(|style_bloom| {
        match (parent_node, style_bloom.borrow_mut().take()) {
            // Root node. Needs new bloom filter.
            (None,     _  ) => {
                debug!("[{}] No parent, but new bloom filter!", tid());
                Box::new(BloomFilter::new())
            }
            // No bloom filter for this thread yet.
            (Some(parent), None) => {
                let mut bloom_filter = Box::new(BloomFilter::new());
                insert_ancestors_into_bloom_filter(&mut bloom_filter, parent, root);
                bloom_filter
            }
            // Found cached bloom filter.
            (Some(parent), Some((mut bloom_filter, old_node, old_generation))) => {
                if old_node == parent.to_unsafe() &&
                    old_generation == context.generation {
                    // Hey, the cached parent is our parent! We can reuse the bloom filter.
                    debug!("[{}] Parent matches (={}). Reusing bloom filter.", tid(), old_node.0);
                } else {
                    // Oh no. the cached parent is stale. I guess we need a new one. Reuse the existing
                    // allocation to avoid malloc churn.
                    bloom_filter.clear();
                    insert_ancestors_into_bloom_filter(&mut bloom_filter, parent, root);
                }
                bloom_filter
            },
        }
    })
}

fn put_thread_local_bloom_filter(bf: Box<BloomFilter>, unsafe_node: &UnsafeNode,
                                 context: &SharedStyleContext) {
    STYLE_BLOOM.with(move |style_bloom| {
        assert!(style_bloom.borrow().is_none(),
                "Putting into a never-taken thread-local bloom filter");
        *style_bloom.borrow_mut() = Some((bf, *unsafe_node, context.generation));
    })
}

/// "Ancestors" in this context is inclusive of ourselves.
fn insert_ancestors_into_bloom_filter<N>(bf: &mut Box<BloomFilter>,
                                         mut n: N,
                                         root: OpaqueNode)
                                         where N: TNode {
    debug!("[{}] Inserting ancestors.", tid());
    let mut ancestors = 0;
    loop {
        ancestors += 1;

        n.insert_into_bloom_filter(&mut **bf);
        n = match n.layout_parent_node(root) {
            None => break,
            Some(p) => p,
        };
    }
    debug!("[{}] Inserted {} ancestors.", tid(), ancestors);
}

pub fn remove_from_bloom_filter<'a, N, C>(context: &C, root: OpaqueNode, node: N)
    where N: TNode,
          C: StyleContext<'a>
{
    let unsafe_layout_node = node.to_unsafe();

    let (mut bf, old_node, old_generation) =
        STYLE_BLOOM.with(|style_bloom| {
            style_bloom.borrow_mut()
                       .take()
                       .expect("The bloom filter should have been set by style recalc.")
        });

    assert_eq!(old_node, unsafe_layout_node);
    assert_eq!(old_generation, context.shared_context().generation);

    match node.layout_parent_node(root) {
        None => {
            debug!("[{}] - {:X}, and deleting BF.", tid(), unsafe_layout_node.0);
            // If this is the reflow root, eat the thread-local bloom filter.
        }
        Some(parent) => {
            // Otherwise, put it back, but remove this node.
            node.remove_from_bloom_filter(&mut *bf);
            let unsafe_parent = parent.to_unsafe();
            put_thread_local_bloom_filter(bf, &unsafe_parent, &context.shared_context());
        },
    };
}

pub trait DomTraversalContext<N: TNode> {
    type SharedContext: Sync + 'static;

    fn new<'a>(&'a Self::SharedContext, OpaqueNode) -> Self;

    /// Process `node` on the way down, before its children have been processed.
    fn process_preorder(&self, node: N) -> RestyleResult;

    /// Process `node` on the way up, after its children have been processed.
    ///
    /// This is only executed if `needs_postorder_traversal` returns true.
    fn process_postorder(&self, node: N);

    /// Boolean that specifies whether a bottom up traversal should be
    /// performed.
    ///
    /// If it's false, then process_postorder has no effect at all.
    fn needs_postorder_traversal(&self) -> bool { true }

    /// Returns if the node should be processed by the preorder traversal (and
    /// then by the post-order one).
    ///
    /// Note that this is true unconditionally for servo, since it requires to
    /// bubble the widths bottom-up for all the DOM.
    fn should_process(&self, node: N) -> bool {
        node.is_dirty() || node.has_dirty_descendants()
    }

    /// Do an action over the child before pushing him to the work queue.
    ///
    /// By default, propagate the IS_DIRTY flag down the tree.
    #[allow(unsafe_code)]
    fn pre_process_child_hook(&self, parent: N, kid: N) {
        // NOTE: At this point is completely safe to modify either the parent or
        // the child, since we have exclusive access to both of them.
        if parent.is_dirty() {
            unsafe {
                kid.set_dirty(true);
                parent.set_dirty_descendants(true);
            }
        }
    }

    fn local_context(&self) -> &LocalStyleContext;
}

/// Determines the amount of relations where we're going to share style.
#[inline]
pub fn relations_are_shareable(relations: &StyleRelations) -> bool {
    use selectors::matching::*;
    !relations.intersects(AFFECTED_BY_ID_SELECTOR |
                          AFFECTED_BY_PSEUDO_ELEMENTS | AFFECTED_BY_STATE |
                          AFFECTED_BY_NON_COMMON_STYLE_AFFECTING_ATTRIBUTE_SELECTOR |
                          AFFECTED_BY_STYLE_ATTRIBUTE |
                          AFFECTED_BY_PRESENTATIONAL_HINTS)
}

pub fn ensure_node_styled<'a, N, C>(node: N,
                                    context: &'a C)
    where N: TNode,
          C: StyleContext<'a>
{
    let mut display_none = false;
    ensure_node_styled_internal(node, context, &mut display_none);
}

#[allow(unsafe_code)]
fn ensure_node_styled_internal<'a, N, C>(node: N,
                                         context: &'a C,
                                         parents_had_display_none: &mut bool)
    where N: TNode,
          C: StyleContext<'a>
{
    use properties::longhands::display::computed_value as display;

    // Ensure we have style data available. This must be done externally because
    // there's no way to initialize the style data from the style system
    // (because in Servo it's coupled with the layout data too).
    //
    // Ideally we'd have an initialize_data() or something similar but just for
    // style data.
    debug_assert!(node.borrow_data().is_some(),
                  "Need to initialize the data before calling ensure_node_styled");

    // We need to go to the root and ensure their style is up to date.
    //
    // This means potentially a bit of wasted work (usually not much). We could
    // add a flag at the node at which point we stopped the traversal to know
    // where should we stop, but let's not add that complication unless needed.
    let parent = match node.parent_node() {
        Some(parent) if parent.is_element() => Some(parent),
        _ => None,
    };

    if let Some(parent) = parent {
        ensure_node_styled_internal(parent, context, parents_had_display_none);
    }

    // Common case: our style is already resolved and none of our ancestors had
    // display: none.
    //
    // We only need to mark whether we have display none, and forget about it,
    // our style is up to date.
    if let Some(ref style) = node.borrow_data().unwrap().style {
        if !*parents_had_display_none {
            *parents_had_display_none = style.get_box().clone_display() == display::T::none;
            return;
        }
    }

    // Otherwise, our style might be out of date. Time to do selector matching
    // if appropriate and cascade the node.
    //
    // Note that we could add the bloom filter's complexity here, but that's
    // probably not necessary since we're likely to be matching only a few
    // nodes, at best.
    let mut applicable_declarations = ApplicableDeclarations::new();
    if let Some(element) = node.as_element() {
        let stylist = &context.shared_context().stylist;

        element.match_element(&**stylist,
                              None,
                              &mut applicable_declarations);
    }

    unsafe {
        node.cascade_node(context, parent, &applicable_declarations);
    }
}

/// Calculates the style for a single node.
#[inline]
#[allow(unsafe_code)]
pub fn recalc_style_at<'a, N, C>(context: &'a C,
                                 root: OpaqueNode,
                                 node: N) -> RestyleResult
    where N: TNode,
          C: StyleContext<'a>
{
    // Get the parent node.
    let parent_opt = match node.parent_node() {
        Some(parent) if parent.is_element() => Some(parent),
        _ => None,
    };

    // Get the style bloom filter.
    let mut bf = take_thread_local_bloom_filter(parent_opt, root, context.shared_context());

    let nonincremental_layout = opts::get().nonincremental_layout;
    let mut restyle_result = RestyleResult::Continue;
    if nonincremental_layout || node.is_dirty() {
        // Remove existing CSS styles from nodes whose content has changed (e.g. text changed),
        // to force non-incremental reflow.
        if node.has_changed() {
            node.unstyle();
        }

        // Check to see whether we can share a style with someone.
        let style_sharing_candidate_cache =
            &mut context.local_context().style_sharing_candidate_cache.borrow_mut();

        let sharing_result = match node.as_element() {
            Some(element) => {
                unsafe {
                    element.share_style_if_possible(style_sharing_candidate_cache,
                                                    context.shared_context(),
                                                    parent_opt.clone())
                }
            },
            None => StyleSharingResult::CannotShare,
        };

        // Otherwise, match and cascade selectors.
        match sharing_result {
            StyleSharingResult::CannotShare => {
                let mut applicable_declarations = ApplicableDeclarations::new();

                let relations;
                let shareable_element = match node.as_element() {
                    Some(element) => {
                        if opts::get().style_sharing_stats {
                            STYLE_SHARING_CACHE_MISSES.fetch_add(1, Ordering::Relaxed);
                        }

                        // Perform the CSS selector matching.
                        let stylist = &context.shared_context().stylist;

                        relations = element.match_element(&**stylist,
                                                          Some(&*bf),
                                                          &mut applicable_declarations);

                        debug!("Result of selector matching: {:?}", relations);

                        if relations_are_shareable(&relations) {
                            Some(element)
                        } else {
                            None
                        }
                    },
                    None => {
                        relations = StyleRelations::empty();
                        if node.has_changed() {
                            node.set_restyle_damage(N::ConcreteRestyleDamage::rebuild_and_reflow())
                        }
                        None
                    },
                };

                // Perform the CSS cascade.
                unsafe {
                    restyle_result = node.cascade_node(context,
                                                       parent_opt,
                                                       &applicable_declarations);
                }

                // Add ourselves to the LRU cache.
                if let Some(element) = shareable_element {
                    style_sharing_candidate_cache.insert_if_possible(&element, relations);
                }
            }
            StyleSharingResult::StyleWasShared(index, damage, cached_restyle_result) => {
                restyle_result = cached_restyle_result;
                if opts::get().style_sharing_stats {
                    STYLE_SHARING_CACHE_HITS.fetch_add(1, Ordering::Relaxed);
                }
                style_sharing_candidate_cache.touch(index);
                node.set_restyle_damage(damage);
            }
        }
    } else {
        // Finish any expired transitions.
        animation::complete_expired_transitions(
            node.opaque(),
            node.mutate_data().unwrap().style.as_mut().unwrap(),
            context.shared_context()
        );
    }

    let unsafe_layout_node = node.to_unsafe();

    // Before running the children, we need to insert our nodes into the bloom
    // filter.
    debug!("[{}] + {:X}", tid(), unsafe_layout_node.0);
    node.insert_into_bloom_filter(&mut *bf);

    // NB: flow construction updates the bloom filter on the way up.
    put_thread_local_bloom_filter(bf, &unsafe_layout_node, context.shared_context());

    if nonincremental_layout {
        RestyleResult::Continue
    } else {
        restyle_result
    }
}
<commit_msg>force style calculation/element construction for non-incremental mode<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Traversing the DOM tree; the bloom filter.

use animation;
use context::{LocalStyleContext, SharedStyleContext, StyleContext};
use dom::{OpaqueNode, TNode, TRestyleDamage, UnsafeNode};
use matching::{ApplicableDeclarations, ElementMatchMethods, MatchMethods, StyleSharingResult};
use selectors::bloom::BloomFilter;
use selectors::matching::StyleRelations;
use std::cell::RefCell;
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use tid::tid;
use util::opts;

/// Every time we do another layout, the old bloom filters are invalid. This is
/// detected by ticking a generation number every layout.
pub type Generation = u32;

/// This enum tells us about whether we can stop restyling or not after styling
/// an element.
///
/// So far this only happens where a display: none node is found.
pub enum RestyleResult {
    Continue,
    Stop,
}

/// Style sharing candidate cache stats. These are only used when
/// `-Z style-sharing-stats` is given.
pub static STYLE_SHARING_CACHE_HITS: AtomicUsize = ATOMIC_USIZE_INIT;
pub static STYLE_SHARING_CACHE_MISSES: AtomicUsize = ATOMIC_USIZE_INIT;

/// A pair of the bloom filter used for css selector matching, and the node to
/// which it applies. This is used to efficiently do `Descendant` selector
/// matches. Thanks to the bloom filter, we can avoid walking up the tree
/// looking for ancestors that aren't there in the majority of cases.
///
/// As we walk down the DOM tree a thread-local bloom filter is built of all the
/// CSS `SimpleSelector`s which are part of a `Descendant` compound selector
/// (i.e. paired with a `Descendant` combinator, in the `next` field of a
/// `CompoundSelector`.
///
/// Before a `Descendant` selector match is tried, it's compared against the
/// bloom filter. If the bloom filter can exclude it, the selector is quickly
/// rejected.
///
/// When done styling a node, all selectors previously inserted into the filter
/// are removed.
///
/// Since a work-stealing queue is used for styling, sometimes, the bloom filter
/// will no longer be the for the parent of the node we're currently on. When
/// this happens, the thread local bloom filter will be thrown away and rebuilt.
thread_local!(
    static STYLE_BLOOM: RefCell<Option<(Box<BloomFilter>, UnsafeNode, Generation)>> = RefCell::new(None));

/// Returns the thread local bloom filter.
///
/// If one does not exist, a new one will be made for you. If it is out of date,
/// it will be cleared and reused.
fn take_thread_local_bloom_filter<N>(parent_node: Option<N>,
                                     root: OpaqueNode,
                                     context: &SharedStyleContext)
                                     -> Box<BloomFilter>
                                     where N: TNode {
    STYLE_BLOOM.with(|style_bloom| {
        match (parent_node, style_bloom.borrow_mut().take()) {
            // Root node. Needs new bloom filter.
            (None,     _  ) => {
                debug!("[{}] No parent, but new bloom filter!", tid());
                Box::new(BloomFilter::new())
            }
            // No bloom filter for this thread yet.
            (Some(parent), None) => {
                let mut bloom_filter = Box::new(BloomFilter::new());
                insert_ancestors_into_bloom_filter(&mut bloom_filter, parent, root);
                bloom_filter
            }
            // Found cached bloom filter.
            (Some(parent), Some((mut bloom_filter, old_node, old_generation))) => {
                if old_node == parent.to_unsafe() &&
                    old_generation == context.generation {
                    // Hey, the cached parent is our parent! We can reuse the bloom filter.
                    debug!("[{}] Parent matches (={}). Reusing bloom filter.", tid(), old_node.0);
                } else {
                    // Oh no. the cached parent is stale. I guess we need a new one. Reuse the existing
                    // allocation to avoid malloc churn.
                    bloom_filter.clear();
                    insert_ancestors_into_bloom_filter(&mut bloom_filter, parent, root);
                }
                bloom_filter
            },
        }
    })
}

fn put_thread_local_bloom_filter(bf: Box<BloomFilter>, unsafe_node: &UnsafeNode,
                                 context: &SharedStyleContext) {
    STYLE_BLOOM.with(move |style_bloom| {
        assert!(style_bloom.borrow().is_none(),
                "Putting into a never-taken thread-local bloom filter");
        *style_bloom.borrow_mut() = Some((bf, *unsafe_node, context.generation));
    })
}

/// "Ancestors" in this context is inclusive of ourselves.
fn insert_ancestors_into_bloom_filter<N>(bf: &mut Box<BloomFilter>,
                                         mut n: N,
                                         root: OpaqueNode)
                                         where N: TNode {
    debug!("[{}] Inserting ancestors.", tid());
    let mut ancestors = 0;
    loop {
        ancestors += 1;

        n.insert_into_bloom_filter(&mut **bf);
        n = match n.layout_parent_node(root) {
            None => break,
            Some(p) => p,
        };
    }
    debug!("[{}] Inserted {} ancestors.", tid(), ancestors);
}

pub fn remove_from_bloom_filter<'a, N, C>(context: &C, root: OpaqueNode, node: N)
    where N: TNode,
          C: StyleContext<'a>
{
    let unsafe_layout_node = node.to_unsafe();

    let (mut bf, old_node, old_generation) =
        STYLE_BLOOM.with(|style_bloom| {
            style_bloom.borrow_mut()
                       .take()
                       .expect("The bloom filter should have been set by style recalc.")
        });

    assert_eq!(old_node, unsafe_layout_node);
    assert_eq!(old_generation, context.shared_context().generation);

    match node.layout_parent_node(root) {
        None => {
            debug!("[{}] - {:X}, and deleting BF.", tid(), unsafe_layout_node.0);
            // If this is the reflow root, eat the thread-local bloom filter.
        }
        Some(parent) => {
            // Otherwise, put it back, but remove this node.
            node.remove_from_bloom_filter(&mut *bf);
            let unsafe_parent = parent.to_unsafe();
            put_thread_local_bloom_filter(bf, &unsafe_parent, &context.shared_context());
        },
    };
}

pub trait DomTraversalContext<N: TNode> {
    type SharedContext: Sync + 'static;

    fn new<'a>(&'a Self::SharedContext, OpaqueNode) -> Self;

    /// Process `node` on the way down, before its children have been processed.
    fn process_preorder(&self, node: N) -> RestyleResult;

    /// Process `node` on the way up, after its children have been processed.
    ///
    /// This is only executed if `needs_postorder_traversal` returns true.
    fn process_postorder(&self, node: N);

    /// Boolean that specifies whether a bottom up traversal should be
    /// performed.
    ///
    /// If it's false, then process_postorder has no effect at all.
    fn needs_postorder_traversal(&self) -> bool { true }

    /// Returns if the node should be processed by the preorder traversal (and
    /// then by the post-order one).
    ///
    /// Note that this is true unconditionally for servo, since it requires to
    /// bubble the widths bottom-up for all the DOM.
    fn should_process(&self, node: N) -> bool {
        opts::get().nonincremental_layout || node.is_dirty() || node.has_dirty_descendants()
    }

    /// Do an action over the child before pushing him to the work queue.
    ///
    /// By default, propagate the IS_DIRTY flag down the tree.
    #[allow(unsafe_code)]
    fn pre_process_child_hook(&self, parent: N, kid: N) {
        // NOTE: At this point is completely safe to modify either the parent or
        // the child, since we have exclusive access to both of them.
        if parent.is_dirty() {
            unsafe {
                kid.set_dirty(true);
                parent.set_dirty_descendants(true);
            }
        }
    }

    fn local_context(&self) -> &LocalStyleContext;
}

/// Determines the amount of relations where we're going to share style.
#[inline]
pub fn relations_are_shareable(relations: &StyleRelations) -> bool {
    use selectors::matching::*;
    !relations.intersects(AFFECTED_BY_ID_SELECTOR |
                          AFFECTED_BY_PSEUDO_ELEMENTS | AFFECTED_BY_STATE |
                          AFFECTED_BY_NON_COMMON_STYLE_AFFECTING_ATTRIBUTE_SELECTOR |
                          AFFECTED_BY_STYLE_ATTRIBUTE |
                          AFFECTED_BY_PRESENTATIONAL_HINTS)
}

pub fn ensure_node_styled<'a, N, C>(node: N,
                                    context: &'a C)
    where N: TNode,
          C: StyleContext<'a>
{
    let mut display_none = false;
    ensure_node_styled_internal(node, context, &mut display_none);
}

#[allow(unsafe_code)]
fn ensure_node_styled_internal<'a, N, C>(node: N,
                                         context: &'a C,
                                         parents_had_display_none: &mut bool)
    where N: TNode,
          C: StyleContext<'a>
{
    use properties::longhands::display::computed_value as display;

    // Ensure we have style data available. This must be done externally because
    // there's no way to initialize the style data from the style system
    // (because in Servo it's coupled with the layout data too).
    //
    // Ideally we'd have an initialize_data() or something similar but just for
    // style data.
    debug_assert!(node.borrow_data().is_some(),
                  "Need to initialize the data before calling ensure_node_styled");

    // We need to go to the root and ensure their style is up to date.
    //
    // This means potentially a bit of wasted work (usually not much). We could
    // add a flag at the node at which point we stopped the traversal to know
    // where should we stop, but let's not add that complication unless needed.
    let parent = match node.parent_node() {
        Some(parent) if parent.is_element() => Some(parent),
        _ => None,
    };

    if let Some(parent) = parent {
        ensure_node_styled_internal(parent, context, parents_had_display_none);
    }

    // Common case: our style is already resolved and none of our ancestors had
    // display: none.
    //
    // We only need to mark whether we have display none, and forget about it,
    // our style is up to date.
    if let Some(ref style) = node.borrow_data().unwrap().style {
        if !*parents_had_display_none {
            *parents_had_display_none = style.get_box().clone_display() == display::T::none;
            return;
        }
    }

    // Otherwise, our style might be out of date. Time to do selector matching
    // if appropriate and cascade the node.
    //
    // Note that we could add the bloom filter's complexity here, but that's
    // probably not necessary since we're likely to be matching only a few
    // nodes, at best.
    let mut applicable_declarations = ApplicableDeclarations::new();
    if let Some(element) = node.as_element() {
        let stylist = &context.shared_context().stylist;

        element.match_element(&**stylist,
                              None,
                              &mut applicable_declarations);
    }

    unsafe {
        node.cascade_node(context, parent, &applicable_declarations);
    }
}

/// Calculates the style for a single node.
#[inline]
#[allow(unsafe_code)]
pub fn recalc_style_at<'a, N, C>(context: &'a C,
                                 root: OpaqueNode,
                                 node: N) -> RestyleResult
    where N: TNode,
          C: StyleContext<'a>
{
    // Get the parent node.
    let parent_opt = match node.parent_node() {
        Some(parent) if parent.is_element() => Some(parent),
        _ => None,
    };

    // Get the style bloom filter.
    let mut bf = take_thread_local_bloom_filter(parent_opt, root, context.shared_context());

    let nonincremental_layout = opts::get().nonincremental_layout;
    let mut restyle_result = RestyleResult::Continue;
    if nonincremental_layout || node.is_dirty() {
        // Remove existing CSS styles from nodes whose content has changed (e.g. text changed),
        // to force non-incremental reflow.
        if node.has_changed() {
            node.unstyle();
        }

        // Check to see whether we can share a style with someone.
        let style_sharing_candidate_cache =
            &mut context.local_context().style_sharing_candidate_cache.borrow_mut();

        let sharing_result = match node.as_element() {
            Some(element) => {
                unsafe {
                    element.share_style_if_possible(style_sharing_candidate_cache,
                                                    context.shared_context(),
                                                    parent_opt.clone())
                }
            },
            None => StyleSharingResult::CannotShare,
        };

        // Otherwise, match and cascade selectors.
        match sharing_result {
            StyleSharingResult::CannotShare => {
                let mut applicable_declarations = ApplicableDeclarations::new();

                let relations;
                let shareable_element = match node.as_element() {
                    Some(element) => {
                        if opts::get().style_sharing_stats {
                            STYLE_SHARING_CACHE_MISSES.fetch_add(1, Ordering::Relaxed);
                        }

                        // Perform the CSS selector matching.
                        let stylist = &context.shared_context().stylist;

                        relations = element.match_element(&**stylist,
                                                          Some(&*bf),
                                                          &mut applicable_declarations);

                        debug!("Result of selector matching: {:?}", relations);

                        if relations_are_shareable(&relations) {
                            Some(element)
                        } else {
                            None
                        }
                    },
                    None => {
                        relations = StyleRelations::empty();
                        if node.has_changed() {
                            node.set_restyle_damage(N::ConcreteRestyleDamage::rebuild_and_reflow())
                        }
                        None
                    },
                };

                // Perform the CSS cascade.
                unsafe {
                    restyle_result = node.cascade_node(context,
                                                       parent_opt,
                                                       &applicable_declarations);
                }

                // Add ourselves to the LRU cache.
                if let Some(element) = shareable_element {
                    style_sharing_candidate_cache.insert_if_possible(&element, relations);
                }
            }
            StyleSharingResult::StyleWasShared(index, damage, cached_restyle_result) => {
                restyle_result = cached_restyle_result;
                if opts::get().style_sharing_stats {
                    STYLE_SHARING_CACHE_HITS.fetch_add(1, Ordering::Relaxed);
                }
                style_sharing_candidate_cache.touch(index);
                node.set_restyle_damage(damage);
            }
        }
    } else {
        // Finish any expired transitions.
        animation::complete_expired_transitions(
            node.opaque(),
            node.mutate_data().unwrap().style.as_mut().unwrap(),
            context.shared_context()
        );
    }

    let unsafe_layout_node = node.to_unsafe();

    // Before running the children, we need to insert our nodes into the bloom
    // filter.
    debug!("[{}] + {:X}", tid(), unsafe_layout_node.0);
    node.insert_into_bloom_filter(&mut *bf);

    // NB: flow construction updates the bloom filter on the way up.
    put_thread_local_bloom_filter(bf, &unsafe_layout_node, context.shared_context());

    if nonincremental_layout {
        RestyleResult::Continue
    } else {
        restyle_result
    }
}
<|endoftext|>


<commit_before>extern crate x11;
extern crate libc;

use std::collections::HashMap;
// use super::Window;
use x11::xlib::{Window};
use super::Container;
use super::super::libx;
use super::super::libx::{ Context };

pub struct Workspaces {
    current: char,
    context: Context,
    pub spaces: HashMap<char, Container>,
}

impl Workspaces {
    pub fn new(context: Context) -> Workspaces {
        Workspaces {
            current: '0',
            context: context,
            spaces: HashMap::new(),
        }
    }

    pub fn contain(&self, key: char) -> bool {
        self.spaces.contains_key(&key)
    }

    pub fn create(&mut self, key: char) {
        let space = Container::from_id(self.context, self.context.root);
        self.spaces.insert(key, space);
    }

    pub fn delete(&mut self, key: char) {
        self.spaces.remove(&key);
    }

    pub fn get(&mut self, key: char) -> Option<&mut Container>{
        self.spaces.get_mut(&key)
    }

    pub fn current(&mut self) -> &mut Container {
        self.spaces.get_mut(&self.current).unwrap()
    }

    pub fn current_name(&self) -> char {
        self.current
    }

    pub fn switch_workspace(&mut self, new: char, context: Context){
        if new == self.current {
            return
        }

        if !self.contain(new) {
            // let s = libx::default_screen(context);
            self.create(new);
        }

        let old = self.current;
        match self.get(old) {
            Some(v) => {
                v.unmap();
                v.update_layout();
            }
            None => {}
        }

        self.current = new;
        match self.get(new) {
            Some(v) => {
                println!("workspace {}", v.id);
                v.map();
                v.focus();
                v.update_layout();
            }
            None => {}
        }
    }

    pub fn can_manage(context: libx::Context, id: Window) -> bool {
        let attrs = libx::get_window_attributes(context, id);
        let transientfor_hint = libx::get_transient_for_hint(context, id);
        attrs.override_redirect == 0 && transientfor_hint == 0
    }

    pub fn move_window(&mut self, window: Window, from: char, to: char){
        if from == to {
            return
        }

        if !self.contain(from) {
            self.create(from);
        }
        if !self.contain(to) {
            self.create(to);
        }

        let res = match self.get(from) {
            Some(w) => { w.remove(window) }
            None => { None }
        };

        match self.get(to) {
            Some(w) => {
                if res.is_some(){
                    w.add(res.unwrap());
                }
            }
            None => {}
        }
    }

    pub fn add_window(&mut self, container: Container, workspace: Option<char>) {
        let w = match workspace {
            Some(k) => {
                match self.get(k) {
                    Some(v) => {
                        v
                    }
                    None => {
                        return
                    }
                }
            }
            None => {
                self.current()
            }
        };
        w.add(container);
        w.update_layout();
        w.print_tree(0);
    }

    // insert window just next to old focus
    pub fn insert_window(&mut self, container: Container) {
        match self.get_focus() {
            Some(c) => {
                match c.get_parent(){
                    Some(p) => {
                        let index = p.contain(c.id).unwrap();
                        p.insert(index+1, container);
                        p.update_layout();
                        p.print_tree(0);
                        return
                    }
                    None => {}
                }
            }
            None => {}
        }
        self.add_window(container, None);
    }

    pub fn remove_window(&mut self, window: Window) -> Option<Container>{
        for (k, workspace) in self.spaces.iter_mut() {
            let res =  workspace.remove(window);
            match res {
                Some(w) => {
                    if w.pid.is_some() {
                        let res = workspace.remove(w.pid.unwrap());
                        if res.is_some(){
                            res.unwrap().destroy();
                        };
                    }

                    workspace.update_layout();
                    workspace.print_tree(0);
                    return Some(w)
                }
                None => {

                }
            }
        }
        None
    }

    pub fn set_focus(&mut self, window: Window) {
        match self.get_focus() {
            Some(w) => {
                w.unfocus();
            }
            None => {}
        }

        match self.get_container(window) {
            Some((_, c)) => {
                c.focus()
            }
            None => {}
        }
    }

    pub fn get_focus(&mut self) -> Option<&mut Container> {
        let (w, _) = libx::get_input_focus(self.context);
        let res = self.get_container(w);
        match res {
            Some((k, c)) => {
                Some(c)
            }
            None => { None }
        }
    }

    pub fn get_container(&mut self, id: Window) -> Option<(char, &mut Container)>{
        for (k, w) in self.spaces.iter_mut() {
            let r = w.tree_search(id);
            if r.is_some(){
                return Some((*k, r.unwrap()))
            }
        }
        None
    }

    // pub fn find_window(&self, window: Window) -> Option<(char, usize)> {
    //     for (k, w) in self.spaces.iter() {
    //         let index = w.contain(window);
    //         match index {
    //             Some(i) => {
    //                 return Some((*k, i))
    //             }
    //             None => {}
    //         }
    //     }
    //     None
    // }
}
<commit_msg>create a sub-root window for every workspace<commit_after>extern crate x11;
extern crate libc;

use std::collections::HashMap;
// use super::Window;
use x11::xlib::{Window};
use super::Container;
use super::super::libx;
use super::super::libx::{ Context };

pub struct Workspaces {
    current: char,
    context: Context,
    pub spaces: HashMap<char, Container>,
}

impl Workspaces {
    pub fn new(context: Context) -> Workspaces {
        Workspaces {
            current: '0',
            context: context,
            spaces: HashMap::new(),
        }
    }

    pub fn contain(&self, key: char) -> bool {
        self.spaces.contains_key(&key)
    }

    pub fn create(&mut self, key: char) {
        let mut space = Container::new(self.context);
        self.spaces.insert(key, space);
    }

    pub fn delete(&mut self, key: char) {
        self.spaces.remove(&key);
    }

    pub fn get(&mut self, key: char) -> Option<&mut Container>{
        self.spaces.get_mut(&key)
    }

    pub fn current(&mut self) -> &mut Container {
        self.spaces.get_mut(&self.current).unwrap()
    }

    pub fn current_name(&self) -> char {
        self.current
    }

    pub fn switch_workspace(&mut self, new: char, context: Context){
        if new == self.current {
            return
        }

        if !self.contain(new) {
            // let s = libx::default_screen(context);
            self.create(new);
        }

        let old = self.current;
        match self.get(old) {
            Some(v) => {
                v.unmap();
                v.update_layout();
            }
            None => {}
        }

        self.current = new;
        match self.get(new) {
            Some(v) => {
                println!("workspace {}", v.id);
                v.map();
                v.focus();
                v.update_layout();
            }
            None => {}
        }
    }

    pub fn can_manage(context: libx::Context, id: Window) -> bool {
        let attrs = libx::get_window_attributes(context, id);
        let transientfor_hint = libx::get_transient_for_hint(context, id);
        attrs.override_redirect == 0 && transientfor_hint == 0
    }

    pub fn move_window(&mut self, window: Window, from: char, to: char){
        if from == to {
            return
        }

        if !self.contain(from) {
            self.create(from);
        }
        if !self.contain(to) {
            self.create(to);
        }

        let res = match self.get(from) {
            Some(w) => { w.remove(window) }
            None => { None }
        };

        match self.get(to) {
            Some(w) => {
                if res.is_some(){
                    w.add(res.unwrap());
                }
            }
            None => {}
        }
    }

    pub fn add_window(&mut self, container: Container, workspace: Option<char>) {
        let w = match workspace {
            Some(k) => {
                match self.get(k) {
                    Some(v) => {
                        v
                    }
                    None => {
                        return
                    }
                }
            }
            None => {
                self.current()
            }
        };
        w.add(container);
        w.update_layout();
        w.print_tree(0);
    }

    // insert window just next to old focus
    pub fn insert_window(&mut self, container: Container) {
        match self.get_focus() {
            Some(c) => {
                match c.get_parent(){
                    Some(p) => {
                        let index = p.contain(c.id).unwrap();
                        p.insert(index+1, container);
                        p.update_layout();
                        p.print_tree(0);
                        return
                    }
                    None => {}
                }
            }
            None => {}
        }
        self.add_window(container, None);
    }

    pub fn remove_window(&mut self, window: Window) -> Option<Container>{
        for (k, workspace) in self.spaces.iter_mut() {
            let res =  workspace.remove(window);
            match res {
                Some(w) => {
                    if w.pid.is_some() {
                        let res = workspace.remove(w.pid.unwrap());
                        if res.is_some(){
                            res.unwrap().destroy();
                        };
                    }

                    workspace.update_layout();
                    workspace.print_tree(0);
                    return Some(w)
                }
                None => {

                }
            }
        }
        None
    }

    pub fn set_focus(&mut self, window: Window) {
        match self.get_focus() {
            Some(w) => {
                w.unfocus();
            }
            None => {}
        }

        match self.get_container(window) {
            Some((_, c)) => {
                c.focus()
            }
            None => {}
        }
    }

    pub fn get_focus(&mut self) -> Option<&mut Container> {
        let (w, _) = libx::get_input_focus(self.context);
        let res = self.get_container(w);
        match res {
            Some((k, c)) => {
                Some(c)
            }
            None => { None }
        }
    }

    pub fn get_container(&mut self, id: Window) -> Option<(char, &mut Container)>{
        for (k, w) in self.spaces.iter_mut() {
            let r = w.tree_search(id);
            if r.is_some(){
                return Some((*k, r.unwrap()))
            }
        }
        None
    }

    // pub fn find_window(&self, window: Window) -> Option<(char, usize)> {
    //     for (k, w) in self.spaces.iter() {
    //         let index = w.contain(window);
    //         match index {
    //             Some(i) => {
    //                 return Some((*k, i))
    //             }
    //             None => {}
    //         }
    //     }
    //     None
    // }
}
<|endoftext|>