<commit_before>//
// Created by salmon on 17-4-5.
//

#include "Domain.h"
#include "Attribute.h"
#include "MeshBase.h"
#include "Patch.h"

namespace simpla {
namespace engine {

struct Domain::pimpl_s {
    std::shared_ptr<geometry::GeoObject> m_geo_object_;
    std::shared_ptr<MeshBase> m_mesh_ = nullptr;
    Patch* m_patch_ = nullptr;
};
Domain::Domain(const std::shared_ptr<MeshBase>& m, const std::shared_ptr<geometry::GeoObject>& g)
    : SPObject(), m_pimpl_(new pimpl_s) {
    m_pimpl_->m_mesh_ = m;
    m_pimpl_->m_geo_object_ = g;
    Click();
}
Domain::~Domain() {}

std::shared_ptr<data::DataTable> Domain::Serialize() const {
    auto p = std::make_shared<data::DataTable>();
    p->SetValue("Type", GetRegisterName());
    p->SetValue("Name", GetName());
    return p;
}
void Domain::Deserialize(const std::shared_ptr<DataTable>& t) { UNIMPLEMENTED; };

void Domain::Update() {}
void Domain::TearDown() {}
void Domain::Initialize() {}
void Domain::Finalize() {}
MeshBase const* Domain::GetMesh() const { return m_pimpl_->m_mesh_.get(); }
MeshBase* Domain::GetMesh() { return m_pimpl_->m_mesh_.get(); }

void Domain::SetGeoObject(std::shared_ptr<geometry::GeoObject> const& g) {
    Click();
    m_pimpl_->m_geo_object_ = g;
}

std::shared_ptr<geometry::GeoObject> Domain::GetGeoObject() const { return m_pimpl_->m_geo_object_; }

void Domain::Push(Patch* p) {
    Click();
    m_pimpl_->m_patch_ = p;
    AttributeGroup::Push(p);

    DoUpdate();
}
void Domain::Pop(Patch* p) {
    auto res = m_pimpl_->m_patch_;
    m_pimpl_->m_patch_ = nullptr;
    AttributeGroup::Pop(p);
    Click();
    DoTearDown();
}

void Domain::DoInitialCondition(Patch* patch, Real time_now) {
    Push(patch);

    //    if (GetMesh() != nullptr) {
    //        GetMesh()->InitializeData(time_now);
    //        GetMesh()->RegisterRanges(m_pimpl_->m_patch_->m_ranges, m_pimpl_->m_geo_object_, GetName());
    //    }
    PreInitialCondition(this, time_now);
    InitialCondition(time_now);
    PostInitialCondition(this, time_now);
    Pop(patch);
}
void Domain::DoBoundaryCondition(Patch* patch, Real time_now, Real dt) {
    Push(patch);
    GetMesh()->SetBoundaryCondition(time_now, dt);
    PreBoundaryCondition(this, time_now, dt);
    BoundaryCondition(time_now, dt);
    PostBoundaryCondition(this, time_now, dt);
    Pop(patch);
}
void Domain::DoAdvance(Patch* patch, Real time_now, Real dt) {
    Push(patch);
    PreAdvance(this, time_now, dt);
    Advance(time_now, dt);
    PostAdvance(this, time_now, dt);
    Pop(patch);
}

}  // namespace engine{
}  // namespace simpla{<commit_msg>snapshot<commit_after>//
// Created by salmon on 17-4-5.
//

#include "Domain.h"
#include "Attribute.h"
#include "MeshBase.h"
#include "Patch.h"

namespace simpla {
namespace engine {

struct Domain::pimpl_s {
    std::shared_ptr<geometry::GeoObject> m_geo_object_;
    std::shared_ptr<MeshBase> m_mesh_ = nullptr;
    Patch* m_patch_ = nullptr;
};
Domain::Domain(const std::shared_ptr<MeshBase>& m, const std::shared_ptr<geometry::GeoObject>& g)
    : SPObject(), m_pimpl_(new pimpl_s) {
    m_pimpl_->m_mesh_ = m;
    m_pimpl_->m_geo_object_ = g;
    Click();
}
Domain::~Domain() {}

std::shared_ptr<data::DataTable> Domain::Serialize() const {
    auto p = std::make_shared<data::DataTable>();
    p->SetValue("Type", GetRegisterName());
    p->SetValue("Name", GetName());
    return p;
}
void Domain::Deserialize(const std::shared_ptr<DataTable>& t) { UNIMPLEMENTED; };

void Domain::Update() {}
void Domain::TearDown() {}
void Domain::Initialize() {}
void Domain::Finalize() {}
MeshBase const* Domain::GetMesh() const { return m_pimpl_->m_mesh_.get(); }
MeshBase* Domain::GetMesh() { return m_pimpl_->m_mesh_.get(); }

void Domain::SetGeoObject(std::shared_ptr<geometry::GeoObject> const& g) {
    Click();
    m_pimpl_->m_geo_object_ = g;
}

std::shared_ptr<geometry::GeoObject> Domain::GetGeoObject() const { return m_pimpl_->m_geo_object_; }

void Domain::Push(Patch* p) {
    Click();
    m_pimpl_->m_patch_ = p;
    m_pimpl_->m_mesh_->Push(p);
    AttributeGroup::Push(p);
    DoUpdate();
}
void Domain::Pop(Patch* p) {
    AttributeGroup::Pop(p);
    m_pimpl_->m_mesh_->Pop(p);
    m_pimpl_->m_patch_ = nullptr;
    Click();
    DoTearDown();
}

void Domain::DoInitialCondition(Patch* patch, Real time_now) {
    Push(patch);
    PreInitialCondition(this, time_now);
    InitialCondition(time_now);
    PostInitialCondition(this, time_now);
    Pop(patch);
}
void Domain::DoBoundaryCondition(Patch* patch, Real time_now, Real dt) {
    Push(patch);
    PreBoundaryCondition(this, time_now, dt);
    BoundaryCondition(time_now, dt);
    PostBoundaryCondition(this, time_now, dt);
    Pop(patch);
}
void Domain::DoAdvance(Patch* patch, Real time_now, Real dt) {
    Push(patch);
    PreAdvance(this, time_now, dt);
    Advance(time_now, dt);
    PostAdvance(this, time_now, dt);
    Pop(patch);
}

}  // namespace engine{
}  // namespace simpla{<|endoftext|>


<commit_before>#include "MeshUtils.hpp"

#include "libslic3r/Tesselate.hpp"
#include "libslic3r/TriangleMesh.hpp"
#include "libslic3r/TriangleMeshSlicer.hpp"
#include "libslic3r/ClipperUtils.hpp"

#include "slic3r/GUI/Camera.hpp"

#include <GL/glew.h>

#include <igl/unproject.h>

namespace Slic3r {
namespace GUI {

void MeshClipper::set_plane(const ClippingPlane& plane)
{
    if (m_plane != plane) {
        m_plane = plane;
        m_triangles_valid = false;
    }
}

void MeshClipper::set_limiting_plane(const ClippingPlane& plane)
{
    if (m_limiting_plane != plane) {
        m_limiting_plane = plane;
        m_triangles_valid = false;
    }
}

void MeshClipper::set_mesh(const TriangleMesh& mesh)
{
    if (m_mesh != &mesh) {
        m_mesh = &mesh;
        m_triangles_valid = false;
        m_triangles2d.resize(0);
    }
}

void MeshClipper::set_negative_mesh(const TriangleMesh& mesh)
{
    if (m_negative_mesh != &mesh) {
        m_negative_mesh = &mesh;
        m_triangles_valid = false;
        m_triangles2d.resize(0);
    }
}

void MeshClipper::set_transformation(const Geometry::Transformation& trafo)
{
    if (! m_trafo.get_matrix().isApprox(trafo.get_matrix())) {
        m_trafo = trafo;
        m_triangles_valid = false;
        m_triangles2d.resize(0);
    }
}

void MeshClipper::render_cut()
{
    if (! m_triangles_valid)
        recalculate_triangles();

    if (m_vertex_array.has_VBOs())
        m_vertex_array.render();
}

void MeshClipper::recalculate_triangles()
{
    const Transform3f& instance_matrix_no_translation_no_scaling = m_trafo.get_matrix(true,false,true).cast<float>();
    const Vec3f& scaling = m_trafo.get_scaling_factor().cast<float>();
    // Calculate clipping plane normal in mesh coordinates.
    Vec3f up_noscale = instance_matrix_no_translation_no_scaling.inverse() * m_plane.get_normal().cast<float>();
    Vec3d up (up_noscale(0)*scaling(0), up_noscale(1)*scaling(1), up_noscale(2)*scaling(2));
    // Calculate distance from mesh origin to the clipping plane (in mesh coordinates).
    float height_mesh = m_plane.distance(m_trafo.get_offset()) * (up_noscale.norm()/up.norm());

    // Now do the cutting
    MeshSlicingParams slicing_params;
    slicing_params.trafo.rotate(Eigen::Quaternion<double, Eigen::DontAlign>::FromTwoVectors(up, Vec3d::UnitZ()));

    assert(m_mesh->has_shared_vertices());
    ExPolygons expolys = union_ex(slice_mesh(m_mesh->its, height_mesh, slicing_params));

    if (m_negative_mesh && !m_negative_mesh->empty()) {
        assert(m_negative_mesh->has_shared_vertices());
        ExPolygons neg_expolys = union_ex(slice_mesh(m_negative_mesh->its, height_mesh, slicing_params));
        expolys = diff_ex(expolys, neg_expolys);
    }

    // Triangulate and rotate the cut into world coords:
    Eigen::Quaterniond q;
    q.setFromTwoVectors(Vec3d::UnitZ(), up);
    Transform3d tr = Transform3d::Identity();
    tr.rotate(q);
    tr = m_trafo.get_matrix() * tr;
    height_mesh += 0.001f; // to avoid z-fighting

    if (m_limiting_plane != ClippingPlane::ClipsNothing())
    {
        // Now remove whatever ended up below the limiting plane (e.g. sinking objects).
        // First transform the limiting plane from world to mesh coords.
        // Note that inverse of tr transforms the plane from world to horizontal.
        Vec3d normal_old = m_limiting_plane.get_normal().normalized();
        Vec3d normal_new = (tr.matrix().block<3,3>(0,0).transpose() * normal_old).normalized();

        // normal_new should now be the plane normal in mesh coords. To find the offset,
        // transform a point and set offset so it belongs to the transformed plane.
        Vec3d pt = Vec3d::Zero();
        double plane_offset = m_limiting_plane.get_data()[3];
        if (std::abs(normal_old.z()) > 0.5) // normal is normalized, at least one of the coords if larger than sqrt(3)/3 = 0.57
            pt.z() = - plane_offset / normal_old.z();
        else if (std::abs(normal_old.y()) > 0.5)
            pt.y() = - plane_offset / normal_old.y();
        else
            pt.x() = - plane_offset / normal_old.x();
        pt = tr.inverse() * pt;
        double offset = -(normal_new.dot(pt));

        if (std::abs(normal_old.dot(m_plane.get_normal().normalized())) > 0.99) {
            // The cuts are parallel, show all or nothing.
            if (offset < height_mesh)
                expolys.clear();
        } else {
            // The cut is a horizontal plane defined by z=height_mesh.
            // ax+by+e=0 is the line of intersection with the limiting plane.
            // Normalized so a^2 + b^2 = 1.
            double len = std::hypot(normal_new.x(), normal_new.y());
            if (len == 0.)
                return;
            double a = normal_new.x() / len;
            double b = normal_new.y() / len;
            double e = (normal_new.z() * height_mesh + offset) / len;
            if (b == 0.)
                return;

            // We need a half-plane to limit the cut. Get angle of the intersecting line.
            double angle = std::atan(-a/b);
            if (b > 0) // select correct half-plane
                angle += M_PI;

            // We'll take a big rectangle above x-axis and rotate and translate
            // it so it lies on our line. This will be the figure to subtract
            // from the cut. The coordinates must not overflow after the transform,
            // make the rectangle a bit smaller.
            coord_t size = (std::numeric_limits<coord_t>::max() - scale_(std::max(std::abs(e*a), std::abs(e*b)))) / 4;
            Polygons ep {Polygon({Point(-size, 0), Point(size, 0), Point(size, 2*size), Point(-size, 2*size)})};
            ep.front().rotate(angle);
            ep.front().translate(scale_(-e * a), scale_(-e * b));
            expolys = diff_ex(expolys, ep);
        }
    }

    m_triangles2d = triangulate_expolygons_2f(expolys, m_trafo.get_matrix().matrix().determinant() < 0.);

    m_vertex_array.release_geometry();
    for (auto it=m_triangles2d.cbegin(); it != m_triangles2d.cend(); it=it+3) {
        m_vertex_array.push_geometry(tr * Vec3d((*(it+0))(0), (*(it+0))(1), height_mesh), up);
        m_vertex_array.push_geometry(tr * Vec3d((*(it+1))(0), (*(it+1))(1), height_mesh), up);
        m_vertex_array.push_geometry(tr * Vec3d((*(it+2))(0), (*(it+2))(1), height_mesh), up);
        size_t idx = it - m_triangles2d.cbegin();
        m_vertex_array.push_triangle(idx, idx+1, idx+2);
    }
    m_vertex_array.finalize_geometry(true);

    m_triangles_valid = true;
}

Vec3f MeshRaycaster::get_triangle_normal(size_t facet_idx) const
{
    return m_normals[facet_idx];
}

void MeshRaycaster::line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
                                        Vec3d& point, Vec3d& direction) const
{
    Matrix4d modelview = camera.get_view_matrix().matrix();
    Matrix4d projection= camera.get_projection_matrix().matrix();
    Vec4i viewport(camera.get_viewport().data());

    Vec3d pt1;
    Vec3d pt2;
    igl::unproject(Vec3d(mouse_pos(0), viewport[3] - mouse_pos(1), 0.),
                   modelview, projection, viewport, pt1);
    igl::unproject(Vec3d(mouse_pos(0), viewport[3] - mouse_pos(1), 1.),
                   modelview, projection, viewport, pt2);

    Transform3d inv = trafo.inverse();
    pt1 = inv * pt1;
    pt2 = inv * pt2;

    point = pt1;
    direction = pt2-pt1;
}

bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
                                      Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane,
                                      size_t* facet_idx) const
{
    Vec3d point;
    Vec3d direction;
    line_from_mouse_pos(mouse_pos, trafo, camera, point, direction);

    std::vector<sla::IndexedMesh::hit_result> hits = m_emesh.query_ray_hits(point, direction);

    if (hits.empty())
        return false; // no intersection found

    unsigned i = 0;

    // Remove points that are obscured or cut by the clipping plane.
    // Also, remove anything below the bed (sinking objects).
    for (i=0; i<hits.size(); ++i) {
        Vec3d transformed_hit = trafo * hits[i].position();
        if (transformed_hit.z() >= 0. &&
            (! clipping_plane || ! clipping_plane->is_point_clipped(transformed_hit)))
            break;
    }

    if (i==hits.size() || (hits.size()-i) % 2 != 0) {
        // All hits are either clipped, or there is an odd number of unclipped
        // hits - meaning the nearest must be from inside the mesh.
        return false;
    }

    // Now stuff the points in the provided vector and calculate normals if asked about them:
    position = hits[i].position().cast<float>();
    normal = hits[i].normal().cast<float>();

    if (facet_idx)
        *facet_idx = hits[i].face();

    return true;
}

std::vector<unsigned> MeshRaycaster::get_unobscured_idxs(const Geometry::Transformation& trafo, const Camera& camera, const std::vector<Vec3f>& points,
                                                       const ClippingPlane* clipping_plane) const
{
    std::vector<unsigned> out;

    const Transform3d& instance_matrix_no_translation_no_scaling = trafo.get_matrix(true,false,true);
    Vec3f direction_to_camera = -camera.get_dir_forward().cast<float>();
    Vec3f direction_to_camera_mesh = (instance_matrix_no_translation_no_scaling.inverse().cast<float>() * direction_to_camera).normalized().eval();
    Vec3f scaling = trafo.get_scaling_factor().cast<float>();
    direction_to_camera_mesh = Vec3f(direction_to_camera_mesh(0)*scaling(0), direction_to_camera_mesh(1)*scaling(1), direction_to_camera_mesh(2)*scaling(2));
    const Transform3f inverse_trafo = trafo.get_matrix().inverse().cast<float>();

    for (size_t i=0; i<points.size(); ++i) {
        const Vec3f& pt = points[i];
        if (clipping_plane && clipping_plane->is_point_clipped(pt.cast<double>()))
            continue;

        bool is_obscured = false;
        // Cast a ray in the direction of the camera and look for intersection with the mesh:
        std::vector<sla::IndexedMesh::hit_result> hits;
        // Offset the start of the ray by EPSILON to account for numerical inaccuracies.
        hits = m_emesh.query_ray_hits((inverse_trafo * pt + direction_to_camera_mesh * EPSILON).cast<double>(),
                                      direction_to_camera.cast<double>());

        if (! hits.empty()) {
            // If the closest hit facet normal points in the same direction as the ray,
            // we are looking through the mesh and should therefore discard the point:
            if (hits.front().normal().dot(direction_to_camera_mesh.cast<double>()) > 0)
                is_obscured = true;

            // Eradicate all hits that the caller wants to ignore
            for (unsigned j=0; j<hits.size(); ++j) {
                if (clipping_plane && clipping_plane->is_point_clipped(trafo.get_matrix() * hits[j].position())) {
                    hits.erase(hits.begin()+j);
                    --j;
                }
            }

            // FIXME: the intersection could in theory be behind the camera, but as of now we only have camera direction.
            // Also, the threshold is in mesh coordinates, not in actual dimensions.
            if (! hits.empty())
                is_obscured = true;
        }
        if (! is_obscured)
            out.push_back(i);
    }
    return out;
}

Vec3f MeshRaycaster::get_closest_point(const Vec3f& point, Vec3f* normal) const
{
    int idx = 0;
    Vec3d closest_point;
    m_emesh.squared_distance(point.cast<double>(), idx, closest_point);
    if (normal)
        *normal = m_normals[idx];

    return closest_point.cast<float>();
}

} // namespace GUI
} // namespace Slic3r
<commit_msg>Fixed painting on surfaces close to the bed (broken since 1360446)<commit_after>#include "MeshUtils.hpp"

#include "libslic3r/Tesselate.hpp"
#include "libslic3r/TriangleMesh.hpp"
#include "libslic3r/TriangleMeshSlicer.hpp"
#include "libslic3r/ClipperUtils.hpp"
#include "libslic3r/Model.hpp"

#include "slic3r/GUI/Camera.hpp"

#include <GL/glew.h>

#include <igl/unproject.h>

namespace Slic3r {
namespace GUI {

void MeshClipper::set_plane(const ClippingPlane& plane)
{
    if (m_plane != plane) {
        m_plane = plane;
        m_triangles_valid = false;
    }
}

void MeshClipper::set_limiting_plane(const ClippingPlane& plane)
{
    if (m_limiting_plane != plane) {
        m_limiting_plane = plane;
        m_triangles_valid = false;
    }
}

void MeshClipper::set_mesh(const TriangleMesh& mesh)
{
    if (m_mesh != &mesh) {
        m_mesh = &mesh;
        m_triangles_valid = false;
        m_triangles2d.resize(0);
    }
}

void MeshClipper::set_negative_mesh(const TriangleMesh& mesh)
{
    if (m_negative_mesh != &mesh) {
        m_negative_mesh = &mesh;
        m_triangles_valid = false;
        m_triangles2d.resize(0);
    }
}

void MeshClipper::set_transformation(const Geometry::Transformation& trafo)
{
    if (! m_trafo.get_matrix().isApprox(trafo.get_matrix())) {
        m_trafo = trafo;
        m_triangles_valid = false;
        m_triangles2d.resize(0);
    }
}

void MeshClipper::render_cut()
{
    if (! m_triangles_valid)
        recalculate_triangles();

    if (m_vertex_array.has_VBOs())
        m_vertex_array.render();
}

void MeshClipper::recalculate_triangles()
{
    const Transform3f& instance_matrix_no_translation_no_scaling = m_trafo.get_matrix(true,false,true).cast<float>();
    const Vec3f& scaling = m_trafo.get_scaling_factor().cast<float>();
    // Calculate clipping plane normal in mesh coordinates.
    Vec3f up_noscale = instance_matrix_no_translation_no_scaling.inverse() * m_plane.get_normal().cast<float>();
    Vec3d up (up_noscale(0)*scaling(0), up_noscale(1)*scaling(1), up_noscale(2)*scaling(2));
    // Calculate distance from mesh origin to the clipping plane (in mesh coordinates).
    float height_mesh = m_plane.distance(m_trafo.get_offset()) * (up_noscale.norm()/up.norm());

    // Now do the cutting
    MeshSlicingParams slicing_params;
    slicing_params.trafo.rotate(Eigen::Quaternion<double, Eigen::DontAlign>::FromTwoVectors(up, Vec3d::UnitZ()));

    assert(m_mesh->has_shared_vertices());
    ExPolygons expolys = union_ex(slice_mesh(m_mesh->its, height_mesh, slicing_params));

    if (m_negative_mesh && !m_negative_mesh->empty()) {
        assert(m_negative_mesh->has_shared_vertices());
        ExPolygons neg_expolys = union_ex(slice_mesh(m_negative_mesh->its, height_mesh, slicing_params));
        expolys = diff_ex(expolys, neg_expolys);
    }

    // Triangulate and rotate the cut into world coords:
    Eigen::Quaterniond q;
    q.setFromTwoVectors(Vec3d::UnitZ(), up);
    Transform3d tr = Transform3d::Identity();
    tr.rotate(q);
    tr = m_trafo.get_matrix() * tr;
    height_mesh += 0.001f; // to avoid z-fighting

    if (m_limiting_plane != ClippingPlane::ClipsNothing())
    {
        // Now remove whatever ended up below the limiting plane (e.g. sinking objects).
        // First transform the limiting plane from world to mesh coords.
        // Note that inverse of tr transforms the plane from world to horizontal.
        Vec3d normal_old = m_limiting_plane.get_normal().normalized();
        Vec3d normal_new = (tr.matrix().block<3,3>(0,0).transpose() * normal_old).normalized();

        // normal_new should now be the plane normal in mesh coords. To find the offset,
        // transform a point and set offset so it belongs to the transformed plane.
        Vec3d pt = Vec3d::Zero();
        double plane_offset = m_limiting_plane.get_data()[3];
        if (std::abs(normal_old.z()) > 0.5) // normal is normalized, at least one of the coords if larger than sqrt(3)/3 = 0.57
            pt.z() = - plane_offset / normal_old.z();
        else if (std::abs(normal_old.y()) > 0.5)
            pt.y() = - plane_offset / normal_old.y();
        else
            pt.x() = - plane_offset / normal_old.x();
        pt = tr.inverse() * pt;
        double offset = -(normal_new.dot(pt));

        if (std::abs(normal_old.dot(m_plane.get_normal().normalized())) > 0.99) {
            // The cuts are parallel, show all or nothing.
            if (offset < height_mesh)
                expolys.clear();
        } else {
            // The cut is a horizontal plane defined by z=height_mesh.
            // ax+by+e=0 is the line of intersection with the limiting plane.
            // Normalized so a^2 + b^2 = 1.
            double len = std::hypot(normal_new.x(), normal_new.y());
            if (len == 0.)
                return;
            double a = normal_new.x() / len;
            double b = normal_new.y() / len;
            double e = (normal_new.z() * height_mesh + offset) / len;
            if (b == 0.)
                return;

            // We need a half-plane to limit the cut. Get angle of the intersecting line.
            double angle = std::atan(-a/b);
            if (b > 0) // select correct half-plane
                angle += M_PI;

            // We'll take a big rectangle above x-axis and rotate and translate
            // it so it lies on our line. This will be the figure to subtract
            // from the cut. The coordinates must not overflow after the transform,
            // make the rectangle a bit smaller.
            coord_t size = (std::numeric_limits<coord_t>::max() - scale_(std::max(std::abs(e*a), std::abs(e*b)))) / 4;
            Polygons ep {Polygon({Point(-size, 0), Point(size, 0), Point(size, 2*size), Point(-size, 2*size)})};
            ep.front().rotate(angle);
            ep.front().translate(scale_(-e * a), scale_(-e * b));
            expolys = diff_ex(expolys, ep);
        }
    }

    m_triangles2d = triangulate_expolygons_2f(expolys, m_trafo.get_matrix().matrix().determinant() < 0.);

    m_vertex_array.release_geometry();
    for (auto it=m_triangles2d.cbegin(); it != m_triangles2d.cend(); it=it+3) {
        m_vertex_array.push_geometry(tr * Vec3d((*(it+0))(0), (*(it+0))(1), height_mesh), up);
        m_vertex_array.push_geometry(tr * Vec3d((*(it+1))(0), (*(it+1))(1), height_mesh), up);
        m_vertex_array.push_geometry(tr * Vec3d((*(it+2))(0), (*(it+2))(1), height_mesh), up);
        size_t idx = it - m_triangles2d.cbegin();
        m_vertex_array.push_triangle(idx, idx+1, idx+2);
    }
    m_vertex_array.finalize_geometry(true);

    m_triangles_valid = true;
}

Vec3f MeshRaycaster::get_triangle_normal(size_t facet_idx) const
{
    return m_normals[facet_idx];
}

void MeshRaycaster::line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
                                        Vec3d& point, Vec3d& direction) const
{
    Matrix4d modelview = camera.get_view_matrix().matrix();
    Matrix4d projection= camera.get_projection_matrix().matrix();
    Vec4i viewport(camera.get_viewport().data());

    Vec3d pt1;
    Vec3d pt2;
    igl::unproject(Vec3d(mouse_pos(0), viewport[3] - mouse_pos(1), 0.),
                   modelview, projection, viewport, pt1);
    igl::unproject(Vec3d(mouse_pos(0), viewport[3] - mouse_pos(1), 1.),
                   modelview, projection, viewport, pt2);

    Transform3d inv = trafo.inverse();
    pt1 = inv * pt1;
    pt2 = inv * pt2;

    point = pt1;
    direction = pt2-pt1;
}

bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
                                      Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane,
                                      size_t* facet_idx) const
{
    Vec3d point;
    Vec3d direction;
    line_from_mouse_pos(mouse_pos, trafo, camera, point, direction);

    std::vector<sla::IndexedMesh::hit_result> hits = m_emesh.query_ray_hits(point, direction);

    if (hits.empty())
        return false; // no intersection found

    unsigned i = 0;

    // Remove points that are obscured or cut by the clipping plane.
    // Also, remove anything below the bed (sinking objects).
    for (i=0; i<hits.size(); ++i) {
        Vec3d transformed_hit = trafo * hits[i].position();
        if (transformed_hit.z() >= SINKING_Z_THRESHOLD &&
            (! clipping_plane || ! clipping_plane->is_point_clipped(transformed_hit)))
            break;
    }

    if (i==hits.size() || (hits.size()-i) % 2 != 0) {
        // All hits are either clipped, or there is an odd number of unclipped
        // hits - meaning the nearest must be from inside the mesh.
        return false;
    }

    // Now stuff the points in the provided vector and calculate normals if asked about them:
    position = hits[i].position().cast<float>();
    normal = hits[i].normal().cast<float>();

    if (facet_idx)
        *facet_idx = hits[i].face();

    return true;
}

std::vector<unsigned> MeshRaycaster::get_unobscured_idxs(const Geometry::Transformation& trafo, const Camera& camera, const std::vector<Vec3f>& points,
                                                       const ClippingPlane* clipping_plane) const
{
    std::vector<unsigned> out;

    const Transform3d& instance_matrix_no_translation_no_scaling = trafo.get_matrix(true,false,true);
    Vec3f direction_to_camera = -camera.get_dir_forward().cast<float>();
    Vec3f direction_to_camera_mesh = (instance_matrix_no_translation_no_scaling.inverse().cast<float>() * direction_to_camera).normalized().eval();
    Vec3f scaling = trafo.get_scaling_factor().cast<float>();
    direction_to_camera_mesh = Vec3f(direction_to_camera_mesh(0)*scaling(0), direction_to_camera_mesh(1)*scaling(1), direction_to_camera_mesh(2)*scaling(2));
    const Transform3f inverse_trafo = trafo.get_matrix().inverse().cast<float>();

    for (size_t i=0; i<points.size(); ++i) {
        const Vec3f& pt = points[i];
        if (clipping_plane && clipping_plane->is_point_clipped(pt.cast<double>()))
            continue;

        bool is_obscured = false;
        // Cast a ray in the direction of the camera and look for intersection with the mesh:
        std::vector<sla::IndexedMesh::hit_result> hits;
        // Offset the start of the ray by EPSILON to account for numerical inaccuracies.
        hits = m_emesh.query_ray_hits((inverse_trafo * pt + direction_to_camera_mesh * EPSILON).cast<double>(),
                                      direction_to_camera.cast<double>());

        if (! hits.empty()) {
            // If the closest hit facet normal points in the same direction as the ray,
            // we are looking through the mesh and should therefore discard the point:
            if (hits.front().normal().dot(direction_to_camera_mesh.cast<double>()) > 0)
                is_obscured = true;

            // Eradicate all hits that the caller wants to ignore
            for (unsigned j=0; j<hits.size(); ++j) {
                if (clipping_plane && clipping_plane->is_point_clipped(trafo.get_matrix() * hits[j].position())) {
                    hits.erase(hits.begin()+j);
                    --j;
                }
            }

            // FIXME: the intersection could in theory be behind the camera, but as of now we only have camera direction.
            // Also, the threshold is in mesh coordinates, not in actual dimensions.
            if (! hits.empty())
                is_obscured = true;
        }
        if (! is_obscured)
            out.push_back(i);
    }
    return out;
}

Vec3f MeshRaycaster::get_closest_point(const Vec3f& point, Vec3f* normal) const
{
    int idx = 0;
    Vec3d closest_point;
    m_emesh.squared_distance(point.cast<double>(), idx, closest_point);
    if (normal)
        *normal = m_normals[idx];

    return closest_point.cast<float>();
}

} // namespace GUI
} // namespace Slic3r
<|endoftext|>


<commit_before>/*************************************************************************************
 *  Copyright (C) 2012 by Alejandro Fiestas Olivares <afiestas@kde.org>              *
 *                                                                                *
 *  This program is free software; you can redistribute it and/or                    *
 *  modify it under the terms of the GNU General Public License                      *
 *  as published by the Free Software Foundation; either version 2                   *
 *  of the License, or (at your option) any later version.                           *
 *                                                                                *
 *  This program is distributed in the hope that it will be useful,                  *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of                   *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                    *
 *  GNU General Public License for more details.                                     *
 *                                                                                *
 *  You should have received a copy of the GNU General Public License                *
 *  along with this program; if not, write to the Free Software                      *
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA   *
 *************************************************************************************/

#include "daemon.h"
#include "serializer.h"
#include "generator.h"

#include <QtCore/QDebug>

#include <kdemacros.h>
#include <KPluginFactory>

#include <kscreen/config.h>
#include <kscreen/configmonitor.h>
#include <kaction.h>

K_PLUGIN_FACTORY(KScreenDaemonFactory, registerPlugin<KScreenDaemon>();)
K_EXPORT_PLUGIN(KScreenDaemonFactory("kscreen", "kscreen"))

KScreenDaemon::KScreenDaemon(QObject* parent, const QList< QVariant >& )
 : KDEDModule(parent)
 , m_iteration(0)
 , m_pendingSave(false)
{
    setenv("KSCREEN_BACKEND", "XRandR", 1);
    KAction* action = new KAction(this);
    action->setGlobalShortcut(KShortcut(Qt::Key_Display));

    connect(action, SIGNAL(triggered(bool)), SLOT(displayButton()));
    connect(Generator::self(), SIGNAL(ready()), SLOT(init()));
}

KScreenDaemon::~KScreenDaemon()
{
    Generator::destroy();
}

void KScreenDaemon::init()
{
    applyConfig();
    monitorForChanges();
}

void KScreenDaemon::applyConfig()
{
    qDebug() << "Applying config";
    KScreen::Config* config = 0;
    if (Serializer::configExists()) {
        config = Serializer::config(Serializer::currentId());
    } else {
        config = Generator::self()->idealConfig();
    }

    KScreen::Config::setConfig(config);
}

void KScreenDaemon::configChanged()
{
    qDebug() << "Change detected";
    if (m_pendingSave) {
        return;
    }

    qDebug() << "Scheduling screen save";
    m_pendingSave = true;
    QMetaObject::invokeMethod(this, "saveCurrentConfig", Qt::QueuedConnection);
}

void KScreenDaemon::saveCurrentConfig()
{
    qDebug() << "Saving current config";
    m_pendingSave = false;
    Serializer::saveConfig(KScreen::Config::current());
}

void KScreenDaemon::displayButton()
{
    if (m_iteration > 5) {
        m_iteration = 1;
    }

    Generator::displaySwitch(m_iteration);
}

void KScreenDaemon::monitorForChanges()
{
    KScreen::Config* config = KScreen::Config::current();
    KScreen::ConfigMonitor::instance()->addConfig(config);

    KScreen::OutputList outputs = config->outputs();
    Q_FOREACH(KScreen::Output* output, outputs) {
        connect(output, SIGNAL(isConnectedChanged()), SLOT(applyConfig()));

        connect(output, SIGNAL(currentModeChanged()), SLOT(configChanged()));
        connect(output, SIGNAL(isEnabledChanged()), SLOT(configChanged()));
        connect(output, SIGNAL(isPrimaryChanged()), SLOT(configChanged()));
        connect(output, SIGNAL(outputChanged()), SLOT(configChanged()));
        connect(output, SIGNAL(clonesChanged()), SLOT(configChanged()));
        connect(output, SIGNAL(posChanged()), SLOT(configChanged()));
        connect(output, SIGNAL(rotationChanged()), SLOT(configChanged()));
    }
}<commit_msg>Ups, displaySwitch is not static :p<commit_after>/*************************************************************************************
 *  Copyright (C) 2012 by Alejandro Fiestas Olivares <afiestas@kde.org>              *
 *                                                                                *
 *  This program is free software; you can redistribute it and/or                    *
 *  modify it under the terms of the GNU General Public License                      *
 *  as published by the Free Software Foundation; either version 2                   *
 *  of the License, or (at your option) any later version.                           *
 *                                                                                *
 *  This program is distributed in the hope that it will be useful,                  *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of                   *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                    *
 *  GNU General Public License for more details.                                     *
 *                                                                                *
 *  You should have received a copy of the GNU General Public License                *
 *  along with this program; if not, write to the Free Software                      *
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA   *
 *************************************************************************************/

#include "daemon.h"
#include "serializer.h"
#include "generator.h"

#include <QtCore/QDebug>

#include <kdemacros.h>
#include <KPluginFactory>

#include <kscreen/config.h>
#include <kscreen/configmonitor.h>
#include <kaction.h>

K_PLUGIN_FACTORY(KScreenDaemonFactory, registerPlugin<KScreenDaemon>();)
K_EXPORT_PLUGIN(KScreenDaemonFactory("kscreen", "kscreen"))

KScreenDaemon::KScreenDaemon(QObject* parent, const QList< QVariant >& )
 : KDEDModule(parent)
 , m_iteration(0)
 , m_pendingSave(false)
{
    setenv("KSCREEN_BACKEND", "XRandR", 1);
    KAction* action = new KAction(this);
    action->setGlobalShortcut(KShortcut(Qt::Key_Display));

    connect(action, SIGNAL(triggered(bool)), SLOT(displayButton()));
    connect(Generator::self(), SIGNAL(ready()), SLOT(init()));
}

KScreenDaemon::~KScreenDaemon()
{
    Generator::destroy();
}

void KScreenDaemon::init()
{
    applyConfig();
    monitorForChanges();
}

void KScreenDaemon::applyConfig()
{
    qDebug() << "Applying config";
    KScreen::Config* config = 0;
    if (Serializer::configExists()) {
        config = Serializer::config(Serializer::currentId());
    } else {
        config = Generator::self()->idealConfig();
    }

    KScreen::Config::setConfig(config);
}

void KScreenDaemon::configChanged()
{
    qDebug() << "Change detected";
    if (m_pendingSave) {
        return;
    }

    qDebug() << "Scheduling screen save";
    m_pendingSave = true;
    QMetaObject::invokeMethod(this, "saveCurrentConfig", Qt::QueuedConnection);
}

void KScreenDaemon::saveCurrentConfig()
{
    qDebug() << "Saving current config";
    m_pendingSave = false;
    Serializer::saveConfig(KScreen::Config::current());
}

void KScreenDaemon::displayButton()
{
    if (m_iteration > 5) {
        m_iteration = 1;
    }

    Generator::self()->displaySwitch(m_iteration);
}

void KScreenDaemon::monitorForChanges()
{
    KScreen::Config* config = KScreen::Config::current();
    KScreen::ConfigMonitor::instance()->addConfig(config);

    KScreen::OutputList outputs = config->outputs();
    Q_FOREACH(KScreen::Output* output, outputs) {
        connect(output, SIGNAL(isConnectedChanged()), SLOT(applyConfig()));

        connect(output, SIGNAL(currentModeChanged()), SLOT(configChanged()));
        connect(output, SIGNAL(isEnabledChanged()), SLOT(configChanged()));
        connect(output, SIGNAL(isPrimaryChanged()), SLOT(configChanged()));
        connect(output, SIGNAL(outputChanged()), SLOT(configChanged()));
        connect(output, SIGNAL(clonesChanged()), SLOT(configChanged()));
        connect(output, SIGNAL(posChanged()), SLOT(configChanged()));
        connect(output, SIGNAL(rotationChanged()), SLOT(configChanged()));
    }
}<|endoftext|>


<commit_before>#include "ros/ros.h"
#include <gtest/gtest.h>
#include <Eigen/Dense>
#include <eigen_conversions/eigen_msg.h>
#include "geometry_msgs/Wrench.h"
#include "geometry_msgs/Pose.h"
#include "uranus_dp/State.h"
#include "uranus_dp/ToggleControlMode.h"

class OpenLoopControllerTest : public ::testing::Test {
public:
    OpenLoopControllerTest()
    {
        pub      = nh.advertise<geometry_msgs::Wrench>("open_loop_setpoint", 1);
        sub        = nh.subscribe("control_input", 5, &OpenLoopControllerTest::Callback, this);
        // modeClient         = nh.serviceClient<uranus_dp::ToggleControlMode>("toggle_control_mode");

        message_received = false;
    }

    void SetUp()
    {
        while (!IsNodeReady())
        {
            ros::spinOnce();
        }
    }

    void PublishSetpoint(double X, double Y, double Z, double K, double M, double N)
    {
        geometry_msgs::Wrench msg;
        msg.force.x = X;
        msg.force.y = Y;
        msg.force.z = Z;
        msg.torque.x = K;
        msg.torque.y = M;
        msg.torque.z = N;
        pub.publish(msg);
    }

    void WaitForMessage()
    {
        while (!message_received)
        {
            ros::spinOnce();
        }
    }

    // ros::ServiceClient modeClient;
    Eigen::Matrix<double,6,1> tau;
    static const double EPSILON = 1e-6; // Max absolute error

 private:
    ros::NodeHandle nh;
    ros::Publisher  pub;
    ros::Subscriber sub;

    bool message_received;

    void Callback(const geometry_msgs::Wrench& msg)
    {
        tf::wrenchMsgToEigen(msg, tau);
        message_received = true;
    }

    bool IsNodeReady()
    {
        return (pub.getNumSubscribers() > 0) && (sub.getNumPublishers() > 0);
    }
};

 /*
  * Make sure we receive any messages at all.
  */
TEST_F(OpenLoopControllerTest, CheckResponsiveness)
{
    PublishSetpoint(1,2,3,4,5,6);
    WaitForMessage();
    EXPECT_TRUE(true);
}

 /*
  * Make sure open loop outputs the same as the input.
  */
TEST_F(OpenLoopControllerTest, DirectFeedthrough)
{
    PublishSetpoint(-9.966, -7.907, 7.626, -6.023, 1.506, 2.805);
    WaitForMessage();
    EXPECT_NEAR(tau(0), -9.966, EPSILON);
    EXPECT_NEAR(tau(1), -7.907, EPSILON);
    EXPECT_NEAR(tau(2),  7.626, EPSILON);
    EXPECT_NEAR(tau(3), -6.023, EPSILON);
    EXPECT_NEAR(tau(4),  1.506, EPSILON);
    EXPECT_NEAR(tau(5),  2.805, EPSILON);
}

 /*
  * Input zero speed and nonzero pose. Input same pose state and pose setpoint. Expect zero output.
  */
// TEST_F(OpenLoopControllerTest, ZeroErrorZeroOutput)
// {
//     uranus_dp::ToggleControlMode srv;
//     if (!modeClient.call(srv))
//     {
//         ROS_ERROR_STREAM("Failed to call service toggle_control_mode. New mode not activated.");
//     }

//     Eigen::Vector3d    p(1,2,3);
//     Eigen::Quaterniond q(4,5,6,7);
//     q.normalize();

//     Eigen::Vector3d v(0,0,0);
//     Eigen::Vector3d omega(0,0,0);

//     PublishState(p, q, v, omega);
//     PublishStationkeeperSetpoint(p, q);

//     WaitForMessage();

//     EXPECT_NEAR(tau(0), 0, EPSILON);
//     EXPECT_NEAR(tau(1), 0, EPSILON);
//     EXPECT_NEAR(tau(2), 0, EPSILON);
//     EXPECT_NEAR(tau(3), 0, EPSILON);
//     EXPECT_NEAR(tau(4), 0, EPSILON);
//     EXPECT_NEAR(tau(5), 0, EPSILON);
// }

int main(int argc, char **argv)
{
    testing::InitGoogleTest(&argc, argv);
    ros::init(argc, argv, "controller_test");
    ROS_INFO("Launching node controller_test.");

    int ret = RUN_ALL_TESTS();
    ros::shutdown();
    return ret;
}
<commit_msg>Update with new SetControlMode<commit_after>#include "ros/ros.h"
#include <gtest/gtest.h>
#include <Eigen/Dense>
#include <eigen_conversions/eigen_msg.h>
#include "geometry_msgs/Wrench.h"
#include "geometry_msgs/Pose.h"
#include "uranus_dp/State.h"
#include "uranus_dp/SetControlMode.h"
#include "../control_mode_enum.h"

class OpenLoopControllerTest : public ::testing::Test {
public:
    OpenLoopControllerTest()
    {
        pub    = nh.advertise<geometry_msgs::Wrench>("open_loop_setpoint", 1);
        sub    = nh.subscribe("control_input", 5, &OpenLoopControllerTest::Callback, this);
        client = nh.serviceClient<uranus_dp::SetControlMode>("set_control_mode");

        message_received = false;
    }

    void SetUp()
    {
        while (!IsNodeReady())
        {
            ros::spinOnce();
        }
    }

    void PublishSetpoint(double X, double Y, double Z, double K, double M, double N)
    {
        geometry_msgs::Wrench msg;
        msg.force.x = X;
        msg.force.y = Y;
        msg.force.z = Z;
        msg.torque.x = K;
        msg.torque.y = M;
        msg.torque.z = N;
        pub.publish(msg);
    }

    void WaitForMessage()
    {
        while (!message_received)
        {
            ros::spinOnce();
        }
    }

    ros::ServiceClient client; // Should be private?
    Eigen::Matrix<double,6,1> tau;
    static const double EPSILON = 1e-6; // Max absolute error

 private:
    ros::NodeHandle nh;
    ros::Publisher  pub;
    ros::Subscriber sub;

    bool message_received;

    void Callback(const geometry_msgs::Wrench& msg)
    {
        tf::wrenchMsgToEigen(msg, tau);
        message_received = true;
    }

    bool IsNodeReady()
    {
        return (pub.getNumSubscribers() > 0) && (sub.getNumPublishers() > 0);
    }
};

 /*
  * Make sure we receive any messages at all.
  */
TEST_F(OpenLoopControllerTest, CheckResponsiveness)
{
    uranus_dp::SetControlMode srv;
    srv.request.mode = ControlModes::OPEN_LOOP;
    if (!client.call(srv))
    {
        ROS_ERROR("Failed to call service toggle_control_mode. New mode open loop not activated.");
    }

    PublishSetpoint(1,2,3,4,5,6);
    WaitForMessage();
    EXPECT_TRUE(true);
}

 /*
  * Make sure open loop outputs the same as the input.
  */
TEST_F(OpenLoopControllerTest, DirectFeedthrough)
{
    PublishSetpoint(-9.966, -7.907, 7.626, -6.023, 1.506, 2.805);
    WaitForMessage();
    EXPECT_NEAR(tau(0), -9.966, EPSILON);
    EXPECT_NEAR(tau(1), -7.907, EPSILON);
    EXPECT_NEAR(tau(2),  7.626, EPSILON);
    EXPECT_NEAR(tau(3), -6.023, EPSILON);
    EXPECT_NEAR(tau(4),  1.506, EPSILON);
    EXPECT_NEAR(tau(5),  2.805, EPSILON);
}

 /*
  * Input zero speed and nonzero pose. Input same pose state and pose setpoint. Expect zero output.
  */
// TEST_F(OpenLoopControllerTest, ZeroErrorZeroOutput)
// {
//     uranus_dp::ToggleControlMode srv;
//     if (!modeClient.call(srv))
//     {
//         ROS_ERROR_STREAM("Failed to call service toggle_control_mode. New mode not activated.");
//     }

//     Eigen::Vector3d    p(1,2,3);
//     Eigen::Quaterniond q(4,5,6,7);
//     q.normalize();

//     Eigen::Vector3d v(0,0,0);
//     Eigen::Vector3d omega(0,0,0);

//     PublishState(p, q, v, omega);
//     PublishStationkeeperSetpoint(p, q);

//     WaitForMessage();

//     EXPECT_NEAR(tau(0), 0, EPSILON);
//     EXPECT_NEAR(tau(1), 0, EPSILON);
//     EXPECT_NEAR(tau(2), 0, EPSILON);
//     EXPECT_NEAR(tau(3), 0, EPSILON);
//     EXPECT_NEAR(tau(4), 0, EPSILON);
//     EXPECT_NEAR(tau(5), 0, EPSILON);
// }

int main(int argc, char **argv)
{
    testing::InitGoogleTest(&argc, argv);
    ros::init(argc, argv, "controller_test");
    ROS_INFO("Launching node controller_test.");

    int ret = RUN_ALL_TESTS();
    ros::shutdown();
    return ret;
}
<|endoftext|>


<commit_before>#include "../common/init.h"
#include "../common/timer.h"

#include <iostream>
#include <vector>

#include "character-select.h"
#include "util/debug.h"
#include "util/load_exception.h"
#include "util/token_exception.h"
#include "util/stretch-bitmap.h"
#include "util/input/input.h"
#include "util/input/input-manager.h"

enum Keys{
    Up=0,
    Down,
    Left,
    Right,
    Esc,
    Enter,
};

class Logic: public Util::Logic {
public:
    Logic(InputMap<Keys> & input, CharacterSelect & select):
    is_done(false),
    input(input),
    select(select){
    }

    bool is_done;
    InputMap<Keys> & input;
    CharacterSelect & select;

    bool done(){
        return is_done;
    }

    void run(){
        std::vector<InputMap<Keys>::InputEvent> out = InputManager::getEvents(input, InputSource());
        for (std::vector<InputMap<Keys>::InputEvent>::iterator it = out.begin(); it != out.end(); it++){
            const InputMap<Keys>::InputEvent & event = *it;
            if (event.enabled){
                if (event.out == Esc){
                    is_done = true;
                }
                /* NOTE Assumes only one cursor */
                if (event.out == Up){
                    select.getList()->up(0);
                }
                if (event.out == Down){
                    select.getList()->down(0);
                }
                if (event.out == Left){
                    select.getList()->left(0);
                }
                if (event.out == Right){
                    select.getList()->right(0);
                }
                if (event.out == Enter){
                }
            }
        }

        select.act();

    }

    double ticks(double system){
        return system;
    }
};

class Draw: public Util::Draw {
public:
    Draw(CharacterSelect & select):
    select(select){
    }

    CharacterSelect & select;

    void draw(const Graphics::Bitmap & buffer){
        buffer.clear();
        select.draw(buffer);
        buffer.BlitToScreen();
    }
};

int main(int argc, char ** argv){
    if (argc > 1){
        Screen::realInit();
        Common::startTimers();

        Global::setDebug(0);
        std::string file = argv[1];

        InputManager manager;
        Graphics::Bitmap screen(Graphics::getScreenBuffer());
        Util::Parameter<Graphics::Bitmap*> use(Graphics::screenParameter, &screen);
        Keyboard::pushRepeatState(true);

        InputMap<Keys> input;
        input.set(Keyboard::Key_ESC, 0, true, Esc);
        input.set(Keyboard::Key_ENTER, 0, true, Enter);
        input.set(Keyboard::Key_UP, 0, true, Up);
        input.set(Keyboard::Key_DOWN, 0, true, Down);
        input.set(Keyboard::Key_LEFT, 0, true, Left);
        input.set(Keyboard::Key_RIGHT, 0, true, Right);

        try {

            CharacterSelect select(file);

            Logic logic(input, select);
            Draw draw(select);

            Util::standardLoop(logic, draw);

        } catch (const LoadException & ex){
            Global::debug(0) << "Problem loading file [" << file << "]. Reason: " << ex.getTrace() << std::endl;
        } catch (const TokenException & ex){
            Global::debug(0) << "Problem parsing file [" << file << "]. Reason: " << ex.getTrace() << std::endl;
        }

        Screen::realFinish();
    } else {
        std::cout << "Usage: ./" << argv[0] << " select-screen.txt" << std::endl;
    }
    return 0;
}
#ifdef USE_ALLEGRO
END_OF_MAIN()
#endif<commit_msg>quit sdl in the atexit callback<commit_after>#include "../common/init.h"
#include "../common/timer.h"

#include <iostream>
#include <vector>

#include "character-select.h"
#include "util/debug.h"
#include "util/load_exception.h"
#include "util/token_exception.h"
#include "util/stretch-bitmap.h"
#include "util/input/input.h"
#include "util/input/input-manager.h"

enum Keys{
    Up=0,
    Down,
    Left,
    Right,
    Esc,
    Enter,
};

class Logic: public Util::Logic {
public:
    Logic(InputMap<Keys> & input, CharacterSelect & select):
    is_done(false),
    input(input),
    select(select){
    }

    bool is_done;
    InputMap<Keys> & input;
    CharacterSelect & select;

    bool done(){
        return is_done;
    }

    void run(){
        std::vector<InputMap<Keys>::InputEvent> out = InputManager::getEvents(input, InputSource());
        for (std::vector<InputMap<Keys>::InputEvent>::iterator it = out.begin(); it != out.end(); it++){
            const InputMap<Keys>::InputEvent & event = *it;
            if (event.enabled){
                if (event.out == Esc){
                    is_done = true;
                }
                /* NOTE Assumes only one cursor */
                if (event.out == Up){
                    select.getList()->up(0);
                }
                if (event.out == Down){
                    select.getList()->down(0);
                }
                if (event.out == Left){
                    select.getList()->left(0);
                }
                if (event.out == Right){
                    select.getList()->right(0);
                }
                if (event.out == Enter){
                }
            }
        }

        select.act();

    }

    double ticks(double system){
        return system;
    }
};

class Draw: public Util::Draw {
public:
    Draw(CharacterSelect & select):
    select(select){
    }

    CharacterSelect & select;

    void draw(const Graphics::Bitmap & buffer){
        buffer.clear();
        select.draw(buffer);
        buffer.BlitToScreen();
    }
};

int main(int argc, char ** argv){
    if (argc > 1){
        Screen::realInit();
        atexit(Screen::realFinish);
        Common::startTimers();

        Global::setDebug(0);
        std::string file = argv[1];

        InputManager manager;
        Graphics::Bitmap screen(Graphics::getScreenBuffer());
        Util::Parameter<Graphics::Bitmap*> use(Graphics::screenParameter, &screen);
        Keyboard::pushRepeatState(true);

        InputMap<Keys> input;
        input.set(Keyboard::Key_ESC, 0, true, Esc);
        input.set(Keyboard::Key_ENTER, 0, true, Enter);
        input.set(Keyboard::Key_UP, 0, true, Up);
        input.set(Keyboard::Key_DOWN, 0, true, Down);
        input.set(Keyboard::Key_LEFT, 0, true, Left);
        input.set(Keyboard::Key_RIGHT, 0, true, Right);

        try {

            CharacterSelect select(file);

            Logic logic(input, select);
            Draw draw(select);

            Util::standardLoop(logic, draw);

        } catch (const LoadException & ex){
            Global::debug(0) << "Problem loading file [" << file << "]. Reason: " << ex.getTrace() << std::endl;
        } catch (const TokenException & ex){
            Global::debug(0) << "Problem parsing file [" << file << "]. Reason: " << ex.getTrace() << std::endl;
        }

    } else {
        std::cout << "Usage: ./" << argv[0] << " select-screen.txt" << std::endl;
    }
    return 0;
}
#ifdef USE_ALLEGRO
END_OF_MAIN()
#endif
<|endoftext|>


<commit_before>#include "display.h"
#include "space.h"
#include "container.h"
#include "tree.h"
#include "application.h"
#include "window.h"
#include "helpers.h"

extern kwm_screen KWMScreen;
extern kwm_focus KWMFocus;
extern kwm_tiling KWMTiling;
extern kwm_thread KWMThread;
extern kwm_toggles KWMToggles;

void DisplayReconfigurationCallBack(CGDirectDisplayID Display, CGDisplayChangeSummaryFlags Flags, void *UserInfo)
{
    pthread_mutex_lock(&KWMThread.Lock);

    if (Flags & kCGDisplayAddFlag)
    {
        // Display has been added
        DEBUG("New display detected! DisplayID: " << Display << " Index: " << KWMScreen.ActiveCount)
        RefreshActiveDisplays();
    }
    else if (Flags & kCGDisplayRemoveFlag)
    {
        // Display has been removed
        if(CGDisplayIsAsleep(Display))
        {
            DEBUG("Display " << Display << " is asleep!")
        }
        else
        {
            DEBUG("Display has been removed! DisplayID: " << Display)
            std::map<int, space_info>::iterator It;
            for(It = KWMTiling.DisplayMap[Display].Space.begin(); It != KWMTiling.DisplayMap[Display].Space.end(); ++It)
                DestroyNodeTree(It->second.RootNode);

            if(KWMTiling.DisplayMap[Display].Identifier)
                CFRelease(KWMTiling.DisplayMap[Display].Identifier);

            KWMTiling.DisplayMap.erase(Display);
        }

        RefreshActiveDisplays();
    }

    pthread_mutex_unlock(&KWMThread.Lock);
}

screen_info CreateDefaultScreenInfo(int DisplayIndex, int ScreenIndex)
{
    CGRect DisplayRect = CGDisplayBounds(DisplayIndex);
    screen_info Screen;

    Screen.Identifier = NULL;
    Screen.ID = ScreenIndex;
    Screen.ActiveSpace = -1;
    Screen.OldWindowListCount = -1;

    Screen.X = DisplayRect.origin.x;
    Screen.Y = DisplayRect.origin.y;
    Screen.Width = DisplayRect.size.width;
    Screen.Height = DisplayRect.size.height;

    Screen.Settings.Offset = KWMScreen.DefaultOffset;
    Screen.Settings.Mode = SpaceModeDefault;
    return Screen;
}

void UpdateExistingScreenInfo(screen_info *Screen, int DisplayIndex, int ScreenIndex)
{
    CGRect DisplayRect = CGDisplayBounds(DisplayIndex);
    Screen->ID = ScreenIndex;

    Screen->X = DisplayRect.origin.x;
    Screen->Y = DisplayRect.origin.y;
    Screen->Width = DisplayRect.size.width;
    Screen->Height = DisplayRect.size.height;

    Screen->Settings.Offset = KWMScreen.DefaultOffset;
    Screen->Settings.Mode = SpaceModeDefault;
}

void GetActiveDisplays()
{
    KWMScreen.Displays = (CGDirectDisplayID*) malloc(sizeof(CGDirectDisplayID) * KWMScreen.MaxCount);
    CGGetActiveDisplayList(KWMScreen.MaxCount, KWMScreen.Displays, &KWMScreen.ActiveCount);
    for(std::size_t DisplayIndex = 0; DisplayIndex < KWMScreen.ActiveCount; ++DisplayIndex)
    {
        unsigned int DisplayID = KWMScreen.Displays[DisplayIndex];
        KWMTiling.DisplayMap[DisplayID] = CreateDefaultScreenInfo(DisplayID, DisplayIndex);;

        DEBUG("DisplayID " << DisplayID << " has index " << DisplayIndex)
    }

    KWMScreen.Current = GetDisplayOfMousePointer();
    KWMScreen.Current->ActiveSpace = GetActiveSpaceOfDisplay(KWMScreen.Current);
    ShouldActiveSpaceBeManaged();

    CGDisplayRegisterReconfigurationCallback(DisplayReconfigurationCallBack, NULL);
}

void RefreshActiveDisplays()
{
    if(KWMScreen.Displays)
        free(KWMScreen.Displays);

    KWMScreen.Displays = (CGDirectDisplayID*) malloc(sizeof(CGDirectDisplayID) * KWMScreen.MaxCount);
    CGGetActiveDisplayList(KWMScreen.MaxCount, KWMScreen.Displays, &KWMScreen.ActiveCount);
    for(std::size_t DisplayIndex = 0; DisplayIndex < KWMScreen.ActiveCount; ++DisplayIndex)
    {
        unsigned int DisplayID = KWMScreen.Displays[DisplayIndex];
        std::map<unsigned int, screen_info>::iterator It = KWMTiling.DisplayMap.find(DisplayID);

        if(It != KWMTiling.DisplayMap.end())
            UpdateExistingScreenInfo(&KWMTiling.DisplayMap[DisplayID], DisplayID, DisplayIndex);
        else
            KWMTiling.DisplayMap[DisplayID] = CreateDefaultScreenInfo(DisplayID, DisplayIndex);

        DEBUG("DisplayID " << DisplayID << " has index " << DisplayIndex)
    }

    screen_info *NewScreen = GetDisplayOfMousePointer();
    if(NewScreen)
        GiveFocusToScreen(NewScreen->ID, NULL, false, true);
}

screen_info *GetDisplayFromScreenID(unsigned int ID)
{
    std::map<unsigned int, screen_info>::iterator It;
    for(It = KWMTiling.DisplayMap.begin(); It != KWMTiling.DisplayMap.end(); ++It)
    {
        screen_info *Screen = &It->second;
        if(Screen->ID == ID)
            return Screen;
    }

    return NULL;
}

screen_info *GetDisplayOfMousePointer()
{
    std::map<unsigned int, screen_info>::iterator It;
    for(It = KWMTiling.DisplayMap.begin(); It != KWMTiling.DisplayMap.end(); ++It)
    {
        CGPoint Cursor = GetCursorPos();
        screen_info *Screen = &It->second;
        if(Cursor.x >= Screen->X && Cursor.x <= Screen->X + Screen->Width &&
           Cursor.y >= Screen->Y && Cursor.y <= Screen->Y + Screen->Height)
               return Screen;
    }

    return NULL;
}

screen_info *GetDisplayOfWindow(window_info *Window)
{
    if(Window)
    {
        std::map<unsigned int, screen_info>::iterator It;
        for(It = KWMTiling.DisplayMap.begin(); It != KWMTiling.DisplayMap.end(); ++It)
        {
            screen_info *Screen = &It->second;
            if(Window->X >= Screen->X && Window->X <= Screen->X + Screen->Width &&
               Window->Y >= Screen->Y && Window->Y <= Screen->Y + Screen->Height)
                return Screen;
        }

        return GetDisplayOfMousePointer();
    }

    return NULL;
}

std::vector<window_info*> GetAllWindowsOnDisplay(int ScreenIndex)
{
    screen_info *Screen = GetDisplayFromScreenID(ScreenIndex);
    std::vector<window_info*> ScreenWindowLst;
    for(std::size_t WindowIndex = 0; WindowIndex < KWMTiling.WindowLst.size(); ++WindowIndex)
    {
        window_info *Window = &KWMTiling.WindowLst[WindowIndex];
        if(!IsApplicationFloating(&KWMTiling.WindowLst[WindowIndex]) &&
           !IsWindowFloating(KWMTiling.WindowLst[WindowIndex].WID, NULL))
        {
            if(Screen == GetDisplayOfWindow(Window))
                ScreenWindowLst.push_back(Window);
        }
    }

    return ScreenWindowLst;
}

void SetDefaultPaddingOfDisplay(container_offset Offset)
{
    KWMScreen.DefaultOffset.PaddingTop = Offset.PaddingTop;
    KWMScreen.DefaultOffset.PaddingBottom = Offset.PaddingBottom;
    KWMScreen.DefaultOffset.PaddingLeft = Offset.PaddingLeft;
    KWMScreen.DefaultOffset.PaddingRight = Offset.PaddingRight;
}

void SetDefaultGapOfDisplay(container_offset Offset)
{
    KWMScreen.DefaultOffset.VerticalGap = Offset.VerticalGap;
    KWMScreen.DefaultOffset.HorizontalGap = Offset.HorizontalGap;
}

void ChangePaddingOfDisplay(const std::string &Side, int Offset)
{
    screen_info *Screen = GetDisplayOfMousePointer();
    space_info *Space = GetActiveSpaceOfScreen(Screen);

    if(Side == "all")
    {
        if(Space->Settings.Offset.PaddingLeft + Offset >= 0)
            Space->Settings.Offset.PaddingLeft += Offset;

        if(Space->Settings.Offset.PaddingRight + Offset >= 0)
            Space->Settings.Offset.PaddingRight += Offset;

        if(Space->Settings.Offset.PaddingTop + Offset >= 0)
            Space->Settings.Offset.PaddingTop += Offset;

        if(Space->Settings.Offset.PaddingBottom + Offset >= 0)
            Space->Settings.Offset.PaddingBottom += Offset;
    }
    else if(Side == "left")
    {
        if(Space->Settings.Offset.PaddingLeft + Offset >= 0)
            Space->Settings.Offset.PaddingLeft += Offset;
    }
    else if(Side == "right")
    {
        if(Space->Settings.Offset.PaddingRight + Offset >= 0)
            Space->Settings.Offset.PaddingRight += Offset;
    }
    else if(Side == "top")
    {
        if(Space->Settings.Offset.PaddingTop + Offset >= 0)
            Space->Settings.Offset.PaddingTop += Offset;
    }
    else if(Side == "bottom")
    {
        if(Space->Settings.Offset.PaddingBottom + Offset >= 0)
            Space->Settings.Offset.PaddingBottom += Offset;
    }

    if(Space->RootNode)
    {
        if(Space->Settings.Mode == SpaceModeBSP)
        {
            SetRootNodeContainer(Screen, Space->RootNode);
            CreateNodeContainers(Screen, Space->RootNode, true);
        }
        else if(Space->Settings.Mode == SpaceModeMonocle)
        {
            link_node *Link = Space->RootNode->List;
            while(Link)
            {
                SetLinkNodeContainer(Screen, Link);
                Link = Link->Next;
            }
        }

        ApplyTreeNodeContainer(Space->RootNode);
    }
}

void ChangeGapOfDisplay(const std::string &Side, int Offset)
{
    screen_info *Screen = GetDisplayOfMousePointer();
    space_info *Space = GetActiveSpaceOfScreen(Screen);

    if(Side == "all")
    {
        if(Space->Settings.Offset.VerticalGap + Offset >= 0)
            Space->Settings.Offset.VerticalGap += Offset;

        if(Space->Settings.Offset.HorizontalGap + Offset >= 0)
            Space->Settings.Offset.HorizontalGap += Offset;
    }
    else if(Side == "vertical")
    {
        if(Space->Settings.Offset.VerticalGap + Offset >= 0)
            Space->Settings.Offset.VerticalGap += Offset;
    }
    else if(Side == "horizontal")
    {
        if(Space->Settings.Offset.HorizontalGap + Offset >= 0)
            Space->Settings.Offset.HorizontalGap += Offset;
    }

    if(Space->RootNode && Space->Settings.Mode == SpaceModeBSP)
    {
        CreateNodeContainers(Screen, Space->RootNode, true);
        ApplyTreeNodeContainer(Space->RootNode);
    }
}

int GetIndexOfNextScreen()
{
    return KWMScreen.Current->ID + 1 >= KWMScreen.ActiveCount ? 0 : KWMScreen.Current->ID + 1;
}

int GetIndexOfPrevScreen()
{
    return KWMScreen.Current->ID == 0 ? KWMScreen.ActiveCount - 1 : KWMScreen.Current->ID - 1;
}

void GiveFocusToScreen(unsigned int ScreenIndex, tree_node *FocusNode, bool Mouse, bool UpdateFocus)
{
    screen_info *Screen = GetDisplayFromScreenID(ScreenIndex);
    if(Screen && Screen != KWMScreen.Current)
    {
        KWMScreen.PrevSpace = KWMScreen.Current->ActiveSpace;
        KWMScreen.Current = Screen;

        Screen->ActiveSpace = GetActiveSpaceOfDisplay(Screen);
        ShouldActiveSpaceBeManaged();
        space_info *Space = GetActiveSpaceOfScreen(Screen);

        DEBUG("GiveFocusToScreen() " << ScreenIndex << \
              ": Space transition ended " << KWMScreen.PrevSpace << \
              " -> " << Screen->ActiveSpace)

        if(UpdateFocus)
        {
            if(Space->Initialized && FocusNode)
            {
                DEBUG("Populated Screen 'Window -f Focus'")

                UpdateActiveWindowList(Screen);
                FilterWindowList(Screen);
                SetWindowFocusByNode(FocusNode);
                MoveCursorToCenterOfFocusedWindow();
            }
            else if(Space->Initialized && Space->RootNode)
            {
                DEBUG("Populated Screen Key/Mouse Focus")

                UpdateActiveWindowList(Screen);
                FilterWindowList(Screen);

                bool WindowBelowCursor = IsAnyWindowBelowCursor();
                if(Mouse && !WindowBelowCursor)
                    ClearFocusedWindow();
                else if(Mouse && WindowBelowCursor)
                    FocusWindowBelowCursor();

                if(!Mouse)
                {
                    if(Space->FocusedWindowID == 0)
                    {
                        void *FocusNode = NULL;
                        GetFirstLeafNode(Space->RootNode, (void**)&FocusNode);
                        if(Space->Settings.Mode == SpaceModeBSP)
                            Space->FocusedWindowID = ((tree_node*)FocusNode)->WindowID;
                        else if(Space->Settings.Mode == SpaceModeMonocle)
                            Space->FocusedWindowID = ((link_node*)FocusNode)->WindowID;
                    }

                    FocusWindowByID(Space->FocusedWindowID);
                    MoveCursorToCenterOfFocusedWindow();
                }
            }
            else
            {
                if(!Space->Initialized ||
                        Space->Settings.Mode == SpaceModeFloating ||
                        !Space->RootNode)
                {
                    DEBUG("Uninitialized Screen")
                    ClearFocusedWindow();

                    if(Space->Settings.Mode != SpaceModeFloating)
                    {
                        if(!Mouse)
                            CGWarpMouseCursorPosition(CGPointMake(Screen->X + (Screen->Width / 2),
                                        Screen->Y + (Screen->Height / 2)));

                        if(!Space->RootNode)
                        {
                            CGPoint ClickPos = GetCursorPos();
                            CGEventRef ClickEvent = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDown, ClickPos, kCGMouseButtonLeft);
                            CGEventSetFlags(ClickEvent, 0);
                            CGEventPost(kCGHIDEventTap, ClickEvent);
                            CFRelease(ClickEvent);

                            ClickEvent = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseUp, ClickPos, kCGMouseButtonLeft);
                            CGEventSetFlags(ClickEvent, 0);
                            CGEventPost(kCGHIDEventTap, ClickEvent);
                            CFRelease(ClickEvent);
                        }
                    }
                }
            }
        }
    }
}

void CaptureApplicationToScreen(int ScreenID, std::string Application)
{
    std::map<std::string, int>::iterator It = KWMTiling.CapturedAppLst.find(Application);
    if(It == KWMTiling.CapturedAppLst.end())
    {
        KWMTiling.CapturedAppLst[Application] = ScreenID;
        DEBUG("CaptureApplicationToScreen() " << ScreenID << " " << Application)
    }
}

void MoveWindowToDisplay(window_info *Window, int Shift, bool Relative, bool UpdateFocus)
{
    int NewScreenIndex = -1;

    if(Relative)
        NewScreenIndex = Shift == 1 ? GetIndexOfNextScreen() : GetIndexOfPrevScreen();
    else
        NewScreenIndex = Shift;

    screen_info *NewScreen = GetDisplayFromScreenID(NewScreenIndex);
    if(NewScreen)
        AddWindowToTreeOfUnfocusedMonitor(NewScreen, Window, UpdateFocus);
}

container_offset CreateDefaultScreenOffset()
{
    container_offset Offset = { 40, 20, 20, 20, 10, 10 };
    return Offset;
}

void UpdateActiveScreen()
{
    screen_info *Screen = GetDisplayOfMousePointer();
    if(KWMScreen.Current != Screen)
    {
        DEBUG("UpdateActiveScreen() Active Display Changed")

        ClearMarkedWindow();
        GiveFocusToScreen(Screen->ID, NULL, true, true);
    }
}

space_settings *GetSpaceSettingsForDisplay(unsigned int ScreenID)
{
    std::map<unsigned int, space_settings>::iterator It = KWMTiling.DisplaySettings.find(ScreenID);
    if(It != KWMTiling.DisplaySettings.end())
        return &It->second;
    else
        return NULL;
}
<commit_msg>fix indentation<commit_after>#include "display.h"
#include "space.h"
#include "container.h"
#include "tree.h"
#include "application.h"
#include "window.h"
#include "helpers.h"

extern kwm_screen KWMScreen;
extern kwm_focus KWMFocus;
extern kwm_tiling KWMTiling;
extern kwm_thread KWMThread;
extern kwm_toggles KWMToggles;

void DisplayReconfigurationCallBack(CGDirectDisplayID Display, CGDisplayChangeSummaryFlags Flags, void *UserInfo)
{
    pthread_mutex_lock(&KWMThread.Lock);

    if (Flags & kCGDisplayAddFlag)
    {
        // Display has been added
        DEBUG("New display detected! DisplayID: " << Display << " Index: " << KWMScreen.ActiveCount)
        RefreshActiveDisplays();
    }
    else if (Flags & kCGDisplayRemoveFlag)
    {
        // Display has been removed
        if(CGDisplayIsAsleep(Display))
        {
            DEBUG("Display " << Display << " is asleep!")
        }
        else
        {
            DEBUG("Display has been removed! DisplayID: " << Display)
            std::map<int, space_info>::iterator It;
            for(It = KWMTiling.DisplayMap[Display].Space.begin(); It != KWMTiling.DisplayMap[Display].Space.end(); ++It)
                DestroyNodeTree(It->second.RootNode);

            if(KWMTiling.DisplayMap[Display].Identifier)
                CFRelease(KWMTiling.DisplayMap[Display].Identifier);

            KWMTiling.DisplayMap.erase(Display);
        }

        RefreshActiveDisplays();
    }

    pthread_mutex_unlock(&KWMThread.Lock);
}

screen_info CreateDefaultScreenInfo(int DisplayIndex, int ScreenIndex)
{
    CGRect DisplayRect = CGDisplayBounds(DisplayIndex);
    screen_info Screen;

    Screen.Identifier = NULL;
    Screen.ID = ScreenIndex;
    Screen.ActiveSpace = -1;
    Screen.OldWindowListCount = -1;

    Screen.X = DisplayRect.origin.x;
    Screen.Y = DisplayRect.origin.y;
    Screen.Width = DisplayRect.size.width;
    Screen.Height = DisplayRect.size.height;

    Screen.Settings.Offset = KWMScreen.DefaultOffset;
    Screen.Settings.Mode = SpaceModeDefault;
    return Screen;
}

void UpdateExistingScreenInfo(screen_info *Screen, int DisplayIndex, int ScreenIndex)
{
    CGRect DisplayRect = CGDisplayBounds(DisplayIndex);
    Screen->ID = ScreenIndex;

    Screen->X = DisplayRect.origin.x;
    Screen->Y = DisplayRect.origin.y;
    Screen->Width = DisplayRect.size.width;
    Screen->Height = DisplayRect.size.height;

    Screen->Settings.Offset = KWMScreen.DefaultOffset;
    Screen->Settings.Mode = SpaceModeDefault;
}

void GetActiveDisplays()
{
    KWMScreen.Displays = (CGDirectDisplayID*) malloc(sizeof(CGDirectDisplayID) * KWMScreen.MaxCount);
    CGGetActiveDisplayList(KWMScreen.MaxCount, KWMScreen.Displays, &KWMScreen.ActiveCount);
    for(std::size_t DisplayIndex = 0; DisplayIndex < KWMScreen.ActiveCount; ++DisplayIndex)
    {
        unsigned int DisplayID = KWMScreen.Displays[DisplayIndex];
        KWMTiling.DisplayMap[DisplayID] = CreateDefaultScreenInfo(DisplayID, DisplayIndex);;

        DEBUG("DisplayID " << DisplayID << " has index " << DisplayIndex)
    }

    KWMScreen.Current = GetDisplayOfMousePointer();
    KWMScreen.Current->ActiveSpace = GetActiveSpaceOfDisplay(KWMScreen.Current);
    ShouldActiveSpaceBeManaged();

    CGDisplayRegisterReconfigurationCallback(DisplayReconfigurationCallBack, NULL);
}

void RefreshActiveDisplays()
{
    if(KWMScreen.Displays)
        free(KWMScreen.Displays);

    KWMScreen.Displays = (CGDirectDisplayID*) malloc(sizeof(CGDirectDisplayID) * KWMScreen.MaxCount);
    CGGetActiveDisplayList(KWMScreen.MaxCount, KWMScreen.Displays, &KWMScreen.ActiveCount);
    for(std::size_t DisplayIndex = 0; DisplayIndex < KWMScreen.ActiveCount; ++DisplayIndex)
    {
        unsigned int DisplayID = KWMScreen.Displays[DisplayIndex];
        std::map<unsigned int, screen_info>::iterator It = KWMTiling.DisplayMap.find(DisplayID);

        if(It != KWMTiling.DisplayMap.end())
            UpdateExistingScreenInfo(&KWMTiling.DisplayMap[DisplayID], DisplayID, DisplayIndex);
        else
            KWMTiling.DisplayMap[DisplayID] = CreateDefaultScreenInfo(DisplayID, DisplayIndex);

        DEBUG("DisplayID " << DisplayID << " has index " << DisplayIndex)
    }

    screen_info *NewScreen = GetDisplayOfMousePointer();
    if(NewScreen)
        GiveFocusToScreen(NewScreen->ID, NULL, false, true);
}

screen_info *GetDisplayFromScreenID(unsigned int ID)
{
    std::map<unsigned int, screen_info>::iterator It;
    for(It = KWMTiling.DisplayMap.begin(); It != KWMTiling.DisplayMap.end(); ++It)
    {
        screen_info *Screen = &It->second;
        if(Screen->ID == ID)
            return Screen;
    }

    return NULL;
}

screen_info *GetDisplayOfMousePointer()
{
    std::map<unsigned int, screen_info>::iterator It;
    for(It = KWMTiling.DisplayMap.begin(); It != KWMTiling.DisplayMap.end(); ++It)
    {
        CGPoint Cursor = GetCursorPos();
        screen_info *Screen = &It->second;
        if(Cursor.x >= Screen->X && Cursor.x <= Screen->X + Screen->Width &&
           Cursor.y >= Screen->Y && Cursor.y <= Screen->Y + Screen->Height)
               return Screen;
    }

    return NULL;
}

screen_info *GetDisplayOfWindow(window_info *Window)
{
    if(Window)
    {
        std::map<unsigned int, screen_info>::iterator It;
        for(It = KWMTiling.DisplayMap.begin(); It != KWMTiling.DisplayMap.end(); ++It)
        {
            screen_info *Screen = &It->second;
            if(Window->X >= Screen->X && Window->X <= Screen->X + Screen->Width &&
               Window->Y >= Screen->Y && Window->Y <= Screen->Y + Screen->Height)
                return Screen;
        }

        return GetDisplayOfMousePointer();
    }

    return NULL;
}

std::vector<window_info*> GetAllWindowsOnDisplay(int ScreenIndex)
{
    screen_info *Screen = GetDisplayFromScreenID(ScreenIndex);
    std::vector<window_info*> ScreenWindowLst;
    for(std::size_t WindowIndex = 0; WindowIndex < KWMTiling.WindowLst.size(); ++WindowIndex)
    {
        window_info *Window = &KWMTiling.WindowLst[WindowIndex];
        if(!IsApplicationFloating(&KWMTiling.WindowLst[WindowIndex]) &&
           !IsWindowFloating(KWMTiling.WindowLst[WindowIndex].WID, NULL))
        {
            if(Screen == GetDisplayOfWindow(Window))
                ScreenWindowLst.push_back(Window);
        }
    }

    return ScreenWindowLst;
}

void SetDefaultPaddingOfDisplay(container_offset Offset)
{
    KWMScreen.DefaultOffset.PaddingTop = Offset.PaddingTop;
    KWMScreen.DefaultOffset.PaddingBottom = Offset.PaddingBottom;
    KWMScreen.DefaultOffset.PaddingLeft = Offset.PaddingLeft;
    KWMScreen.DefaultOffset.PaddingRight = Offset.PaddingRight;
}

void SetDefaultGapOfDisplay(container_offset Offset)
{
    KWMScreen.DefaultOffset.VerticalGap = Offset.VerticalGap;
    KWMScreen.DefaultOffset.HorizontalGap = Offset.HorizontalGap;
}

void ChangePaddingOfDisplay(const std::string &Side, int Offset)
{
    screen_info *Screen = GetDisplayOfMousePointer();
    space_info *Space = GetActiveSpaceOfScreen(Screen);

    if(Side == "all")
    {
        if(Space->Settings.Offset.PaddingLeft + Offset >= 0)
            Space->Settings.Offset.PaddingLeft += Offset;

        if(Space->Settings.Offset.PaddingRight + Offset >= 0)
            Space->Settings.Offset.PaddingRight += Offset;

        if(Space->Settings.Offset.PaddingTop + Offset >= 0)
            Space->Settings.Offset.PaddingTop += Offset;

        if(Space->Settings.Offset.PaddingBottom + Offset >= 0)
            Space->Settings.Offset.PaddingBottom += Offset;
    }
    else if(Side == "left")
    {
        if(Space->Settings.Offset.PaddingLeft + Offset >= 0)
            Space->Settings.Offset.PaddingLeft += Offset;
    }
    else if(Side == "right")
    {
        if(Space->Settings.Offset.PaddingRight + Offset >= 0)
            Space->Settings.Offset.PaddingRight += Offset;
    }
    else if(Side == "top")
    {
        if(Space->Settings.Offset.PaddingTop + Offset >= 0)
            Space->Settings.Offset.PaddingTop += Offset;
    }
    else if(Side == "bottom")
    {
        if(Space->Settings.Offset.PaddingBottom + Offset >= 0)
            Space->Settings.Offset.PaddingBottom += Offset;
    }

    if(Space->RootNode)
    {
        if(Space->Settings.Mode == SpaceModeBSP)
        {
            SetRootNodeContainer(Screen, Space->RootNode);
            CreateNodeContainers(Screen, Space->RootNode, true);
        }
        else if(Space->Settings.Mode == SpaceModeMonocle)
        {
            link_node *Link = Space->RootNode->List;
            while(Link)
            {
                SetLinkNodeContainer(Screen, Link);
                Link = Link->Next;
            }
        }

        ApplyTreeNodeContainer(Space->RootNode);
    }
}

void ChangeGapOfDisplay(const std::string &Side, int Offset)
{
    screen_info *Screen = GetDisplayOfMousePointer();
    space_info *Space = GetActiveSpaceOfScreen(Screen);

    if(Side == "all")
    {
        if(Space->Settings.Offset.VerticalGap + Offset >= 0)
            Space->Settings.Offset.VerticalGap += Offset;

        if(Space->Settings.Offset.HorizontalGap + Offset >= 0)
            Space->Settings.Offset.HorizontalGap += Offset;
    }
    else if(Side == "vertical")
    {
        if(Space->Settings.Offset.VerticalGap + Offset >= 0)
            Space->Settings.Offset.VerticalGap += Offset;
    }
    else if(Side == "horizontal")
    {
        if(Space->Settings.Offset.HorizontalGap + Offset >= 0)
            Space->Settings.Offset.HorizontalGap += Offset;
    }

    if(Space->RootNode && Space->Settings.Mode == SpaceModeBSP)
    {
        CreateNodeContainers(Screen, Space->RootNode, true);
        ApplyTreeNodeContainer(Space->RootNode);
    }
}

int GetIndexOfNextScreen()
{
    return KWMScreen.Current->ID + 1 >= KWMScreen.ActiveCount ? 0 : KWMScreen.Current->ID + 1;
}

int GetIndexOfPrevScreen()
{
    return KWMScreen.Current->ID == 0 ? KWMScreen.ActiveCount - 1 : KWMScreen.Current->ID - 1;
}

void GiveFocusToScreen(unsigned int ScreenIndex, tree_node *FocusNode, bool Mouse, bool UpdateFocus)
{
    screen_info *Screen = GetDisplayFromScreenID(ScreenIndex);
    if(Screen && Screen != KWMScreen.Current)
    {
        KWMScreen.PrevSpace = KWMScreen.Current->ActiveSpace;
        KWMScreen.Current = Screen;

        Screen->ActiveSpace = GetActiveSpaceOfDisplay(Screen);
        ShouldActiveSpaceBeManaged();
        space_info *Space = GetActiveSpaceOfScreen(Screen);

        DEBUG("GiveFocusToScreen() " << ScreenIndex << \
              ": Space transition ended " << KWMScreen.PrevSpace << \
              " -> " << Screen->ActiveSpace)

        if(UpdateFocus)
        {
            if(Space->Initialized && FocusNode)
            {
                DEBUG("Populated Screen 'Window -f Focus'")

                UpdateActiveWindowList(Screen);
                FilterWindowList(Screen);
                SetWindowFocusByNode(FocusNode);
                MoveCursorToCenterOfFocusedWindow();
            }
            else if(Space->Initialized && Space->RootNode)
            {
                DEBUG("Populated Screen Key/Mouse Focus")

                UpdateActiveWindowList(Screen);
                FilterWindowList(Screen);

                bool WindowBelowCursor = IsAnyWindowBelowCursor();
                if(Mouse && !WindowBelowCursor)
                    ClearFocusedWindow();
                else if(Mouse && WindowBelowCursor)
                    FocusWindowBelowCursor();

                if(!Mouse)
                {
                    if(Space->FocusedWindowID == 0)
                    {
                        void *FocusNode = NULL;
                        GetFirstLeafNode(Space->RootNode, (void**)&FocusNode);
                        if(Space->Settings.Mode == SpaceModeBSP)
                            Space->FocusedWindowID = ((tree_node*)FocusNode)->WindowID;
                        else if(Space->Settings.Mode == SpaceModeMonocle)
                            Space->FocusedWindowID = ((link_node*)FocusNode)->WindowID;
                    }

                    FocusWindowByID(Space->FocusedWindowID);
                    MoveCursorToCenterOfFocusedWindow();
                }
            }
            else
            {
                if(!Space->Initialized ||
                   Space->Settings.Mode == SpaceModeFloating ||
                   !Space->RootNode)
                {
                    DEBUG("Uninitialized Screen")
                    ClearFocusedWindow();

                    if(!Mouse)
                        CGWarpMouseCursorPosition(CGPointMake(Screen->X + (Screen->Width / 2), Screen->Y + (Screen->Height / 2)));

                    if(Space->Settings.Mode != SpaceModeFloating && !Space->RootNode)
                    {
                        CGPoint ClickPos = GetCursorPos();
                        CGEventRef ClickEvent = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDown, ClickPos, kCGMouseButtonLeft);
                        CGEventSetFlags(ClickEvent, 0);
                        CGEventPost(kCGHIDEventTap, ClickEvent);
                        CFRelease(ClickEvent);

                        ClickEvent = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseUp, ClickPos, kCGMouseButtonLeft);
                        CGEventSetFlags(ClickEvent, 0);
                        CGEventPost(kCGHIDEventTap, ClickEvent);
                        CFRelease(ClickEvent);
                    }
                }
            }
        }
    }
}

void CaptureApplicationToScreen(int ScreenID, std::string Application)
{
    std::map<std::string, int>::iterator It = KWMTiling.CapturedAppLst.find(Application);
    if(It == KWMTiling.CapturedAppLst.end())
    {
        KWMTiling.CapturedAppLst[Application] = ScreenID;
        DEBUG("CaptureApplicationToScreen() " << ScreenID << " " << Application)
    }
}

void MoveWindowToDisplay(window_info *Window, int Shift, bool Relative, bool UpdateFocus)
{
    int NewScreenIndex = -1;

    if(Relative)
        NewScreenIndex = Shift == 1 ? GetIndexOfNextScreen() : GetIndexOfPrevScreen();
    else
        NewScreenIndex = Shift;

    screen_info *NewScreen = GetDisplayFromScreenID(NewScreenIndex);
    if(NewScreen)
        AddWindowToTreeOfUnfocusedMonitor(NewScreen, Window, UpdateFocus);
}

container_offset CreateDefaultScreenOffset()
{
    container_offset Offset = { 40, 20, 20, 20, 10, 10 };
    return Offset;
}

void UpdateActiveScreen()
{
    screen_info *Screen = GetDisplayOfMousePointer();
    if(KWMScreen.Current != Screen)
    {
        DEBUG("UpdateActiveScreen() Active Display Changed")

        ClearMarkedWindow();
        GiveFocusToScreen(Screen->ID, NULL, true, true);
    }
}

space_settings *GetSpaceSettingsForDisplay(unsigned int ScreenID)
{
    std::map<unsigned int, space_settings>::iterator It = KWMTiling.DisplaySettings.find(ScreenID);
    if(It != KWMTiling.DisplaySettings.end())
        return &It->second;
    else
        return NULL;
}
<|endoftext|>


<commit_before>#include "kwm.h"

extern uint32_t MaxDisplayCount;
extern uint32_t ActiveDisplaysCount;
extern CGDirectDisplayID ActiveDisplays[];

extern screen_info *Screen;
extern std::map<unsigned int, screen_info> DisplayMap;
extern std::vector<window_info> WindowLst;
extern window_info *FocusedWindow;

extern int DefaultPaddingLeft, DefaultPaddingRight;
extern int DefaultPaddingTop, DefaultPaddingBottom;
extern int DefaultGapVertical, DefaultGapHorizontal;

extern pthread_mutex_t BackgroundLock;

void DisplayReconfigurationCallBack(CGDirectDisplayID Display, CGDisplayChangeSummaryFlags Flags, void *UserInfo)
{
    pthread_mutex_lock(&BackgroundLock);

    if (Flags & kCGDisplayAddFlag)
    {
        // Display has been added
        DEBUG("New display detected! DisplayID: " << Display << " Index: " << ActiveDisplaysCount)
        RefreshActiveDisplays();
    }
    else if (Flags & kCGDisplayRemoveFlag)
    {
        // Display has been removed
        DEBUG("Display has been removed! DisplayID: " << Display)
        std::map<int, space_info>::iterator It;
        for(It = DisplayMap[Display].Space.begin(); It != DisplayMap[Display].Space.end(); ++It)
            DestroyNodeTree(It->second.RootNode);

        DisplayMap.erase(Display);
        RefreshActiveDisplays();
    }

    pthread_mutex_unlock(&BackgroundLock);
}

screen_info CreateDefaultScreenInfo(int DisplayIndex, int ScreenIndex)
{
    CGRect DisplayRect = CGDisplayBounds(DisplayIndex);
    screen_info Screen;

    Screen.ID = ScreenIndex;
    Screen.ForceContainerUpdate = false;
    Screen.ActiveSpace = 0;
    Screen.OldWindowListCount = -1;

    Screen.X = DisplayRect.origin.x;
    Screen.Y = DisplayRect.origin.y;
    Screen.Width = DisplayRect.size.width;
    Screen.Height = DisplayRect.size.height;

    Screen.PaddingTop = DefaultPaddingTop;
    Screen.PaddingLeft = DefaultPaddingLeft;
    Screen.PaddingRight = DefaultPaddingRight;
    Screen.PaddingBottom = DefaultPaddingBottom;

    Screen.VerticalGap = DefaultGapVertical;
    Screen.HorizontalGap = DefaultGapHorizontal;

    return Screen;
}

void UpdateExistingScreenInfo(screen_info *Screen, int DisplayIndex, int ScreenIndex)
{
    CGRect DisplayRect = CGDisplayBounds(DisplayIndex);
    Screen->ID = ScreenIndex;

    Screen->X = DisplayRect.origin.x;
    Screen->Y = DisplayRect.origin.y;
    Screen->Width = DisplayRect.size.width;
    Screen->Height = DisplayRect.size.height;

    Screen->PaddingTop = DefaultPaddingTop;
    Screen->PaddingLeft = DefaultPaddingLeft;
    Screen->PaddingRight = DefaultPaddingRight;
    Screen->PaddingBottom = DefaultPaddingBottom;

    Screen->VerticalGap = DefaultGapVertical;
    Screen->HorizontalGap = DefaultGapHorizontal;
    Screen->ForceContainerUpdate = true;
}

void GetActiveDisplays()
{
    CGGetActiveDisplayList(MaxDisplayCount, (CGDirectDisplayID*)&ActiveDisplays, &ActiveDisplaysCount);
    for(int DisplayIndex = 0; DisplayIndex < ActiveDisplaysCount; ++DisplayIndex)
    {
        unsigned int DisplayID = ActiveDisplays[DisplayIndex];
        DisplayMap[DisplayID] = CreateDefaultScreenInfo(DisplayID, DisplayIndex);;

        DEBUG("DisplayID " << DisplayID << " has index " << DisplayIndex)
    }

    Screen = GetDisplayOfMousePointer();
    CGDisplayRegisterReconfigurationCallback(DisplayReconfigurationCallBack, NULL);
}

void RefreshActiveDisplays()
{
    CGGetActiveDisplayList(MaxDisplayCount, (CGDirectDisplayID*)&ActiveDisplays, &ActiveDisplaysCount);
    for(int DisplayIndex = 0; DisplayIndex < ActiveDisplaysCount; ++DisplayIndex)
    {
        unsigned int DisplayID = ActiveDisplays[DisplayIndex];
        std::map<unsigned int, screen_info>::iterator It;

        if(It != DisplayMap.end())
            UpdateExistingScreenInfo(&DisplayMap[DisplayID], DisplayID, DisplayIndex);
        else
            DisplayMap[DisplayID] = CreateDefaultScreenInfo(DisplayID, DisplayIndex);

        DEBUG("DisplayID " << DisplayID << " has index " << DisplayIndex)
    }

    Screen = GetDisplayOfMousePointer();
}

screen_info *GetDisplayFromScreenID(int ID)
{
    std::map<unsigned int, screen_info>::iterator It;
    for(It = DisplayMap.begin(); It != DisplayMap.end(); ++It)
    {
        screen_info *Screen = &It->second;
        if(Screen->ID == ID)
            return Screen;
    }

    return NULL;
}

screen_info *GetDisplayOfMousePointer()
{
    std::map<unsigned int, screen_info>::iterator It;
    for(It = DisplayMap.begin(); It != DisplayMap.end(); ++It)
    {
        CGPoint Cursor = GetCursorPos();
        screen_info *Screen = &It->second;
        if(Cursor.x >= Screen->X && Cursor.x <= Screen->X + Screen->Width &&
           Cursor.y >= Screen->Y && Cursor.y <= Screen->Y + Screen->Height)
               return Screen;
    }

    return NULL;
}

screen_info *GetDisplayOfWindow(window_info *Window)
{
    if(Window)
    {
        std::map<unsigned int, screen_info>::iterator It;
        for(It = DisplayMap.begin(); It != DisplayMap.end(); ++It)
        {
            screen_info *Screen = &It->second;
            if(Window->X >= Screen->X && Window->X <= Screen->X + Screen->Width)
                return Screen;
        }
    }

    return NULL;
}

std::vector<window_info*> GetAllWindowsOnDisplay(int ScreenIndex)
{
    screen_info *Screen = GetDisplayFromScreenID(ScreenIndex);
    std::vector<window_info*> ScreenWindowLst;
    for(int WindowIndex = 0; WindowIndex < WindowLst.size(); ++WindowIndex)
    {
        window_info *Window = &WindowLst[WindowIndex];
        if(!IsApplicationFloating(&WindowLst[WindowIndex]))
        {
            if(Window->X >= Screen->X && Window->X <= Screen->X + Screen->Width)
                ScreenWindowLst.push_back(Window);
        }
    }

    return ScreenWindowLst;
}

std::vector<int> GetAllWindowIDsOnDisplay(int ScreenIndex)
{
    screen_info *Screen = GetDisplayFromScreenID(ScreenIndex);
    std::vector<int> ScreenWindowIDLst;
    for(int WindowIndex = 0; WindowIndex < WindowLst.size(); ++WindowIndex)
    {
        window_info *Window = &WindowLst[WindowIndex];
        if(!IsApplicationFloating(&WindowLst[WindowIndex]))
        {
            if(Window->X >= Screen->X && Window->X <= Screen->X + Screen->Width)
                ScreenWindowIDLst.push_back(Window->WID);
        }
    }

    return ScreenWindowIDLst;
}

void SetDefaultPaddingOfDisplay(const std::string &Side, int Offset)
{
    if(Side == "left")
        DefaultPaddingLeft = Offset;
    else if(Side == "right")
        DefaultPaddingRight = Offset;
    else if(Side == "top")
        DefaultPaddingTop = Offset;
    else if(Side == "bottom")
        DefaultPaddingBottom = Offset;
}

void SetDefaultGapOfDisplay(const std::string &Side, int Offset)
{
    if(Side == "vertical")
        DefaultGapVertical = Offset;
    else if(Side == "horizontal")
        DefaultGapHorizontal = Offset;
}

void ChangePaddingOfDisplay(const std::string &Side, int Offset)
{
    screen_info *Screen = GetDisplayOfMousePointer();
    space_info *Space = &Screen->Space[Screen->ActiveSpace];

    if(Side == "left")
    {
        if(Space->PaddingLeft + Offset >= 0)
            Space->PaddingLeft += Offset;
    }
    else if(Side == "right")
    {
        if(Space->PaddingRight + Offset >= 0)
            Space->PaddingRight += Offset;
    }
    else if(Side == "top")
    {
        if(Space->PaddingTop + Offset >= 0)
            Space->PaddingTop += Offset;
    }
    else if(Side == "bottom")
    {
        if(Space->PaddingBottom + Offset >= 0)
            Space->PaddingBottom += Offset;
    }

    SetRootNodeContainer(Screen, Space->RootNode);
    CreateNodeContainers(Screen, Space->RootNode, true);
    ApplyNodeContainer(Space->RootNode);
}

void ChangeGapOfDisplay(const std::string &Side, int Offset)
{
    screen_info *Screen = GetDisplayOfMousePointer();
    space_info *Space = &Screen->Space[Screen->ActiveSpace];

    if(Side == "vertical")
    {
        if(Space->VerticalGap + Offset >= 0)
            Space->VerticalGap += Offset;
    }
    else if(Side == "horizontal")
    {
        if(Space->HorizontalGap + Offset >= 0)
            Space->HorizontalGap += Offset;
    }

    CreateNodeContainers(Screen, Space->RootNode, true);
    ApplyNodeContainer(Space->RootNode);
}

void CycleFocusedWindowDisplay(int Shift, bool Relative)
{
    screen_info *Screen = GetDisplayOfWindow(FocusedWindow);
    int NewScreenIndex = -1;

    if(Relative)
    {
        if(Shift == 1)
            NewScreenIndex = (Screen->ID + 1 >= ActiveDisplaysCount) ? 0 : Screen->ID + 1;
        else if(Shift == -1)
            NewScreenIndex = (Screen->ID - 1 < 0) ? ActiveDisplaysCount - 1 : Screen->ID - 1;
    }
    else
    {
        NewScreenIndex = Shift;
    }

    if(NewScreenIndex != Screen->ID)
    {
        screen_info *NewScreen = GetDisplayFromScreenID(NewScreenIndex);
        AddWindowToTreeOfUnfocusedMonitor(NewScreen);
    }
}
<commit_msg>fixed #35 - trying to adjust padding/gaps of space with only floating windows<commit_after>#include "kwm.h"

extern uint32_t MaxDisplayCount;
extern uint32_t ActiveDisplaysCount;
extern CGDirectDisplayID ActiveDisplays[];

extern screen_info *Screen;
extern std::map<unsigned int, screen_info> DisplayMap;
extern std::vector<window_info> WindowLst;
extern window_info *FocusedWindow;

extern int DefaultPaddingLeft, DefaultPaddingRight;
extern int DefaultPaddingTop, DefaultPaddingBottom;
extern int DefaultGapVertical, DefaultGapHorizontal;

extern pthread_mutex_t BackgroundLock;

void DisplayReconfigurationCallBack(CGDirectDisplayID Display, CGDisplayChangeSummaryFlags Flags, void *UserInfo)
{
    pthread_mutex_lock(&BackgroundLock);

    if (Flags & kCGDisplayAddFlag)
    {
        // Display has been added
        DEBUG("New display detected! DisplayID: " << Display << " Index: " << ActiveDisplaysCount)
        RefreshActiveDisplays();
    }
    else if (Flags & kCGDisplayRemoveFlag)
    {
        // Display has been removed
        DEBUG("Display has been removed! DisplayID: " << Display)
        std::map<int, space_info>::iterator It;
        for(It = DisplayMap[Display].Space.begin(); It != DisplayMap[Display].Space.end(); ++It)
            DestroyNodeTree(It->second.RootNode);

        DisplayMap.erase(Display);
        RefreshActiveDisplays();
    }

    pthread_mutex_unlock(&BackgroundLock);
}

screen_info CreateDefaultScreenInfo(int DisplayIndex, int ScreenIndex)
{
    CGRect DisplayRect = CGDisplayBounds(DisplayIndex);
    screen_info Screen;

    Screen.ID = ScreenIndex;
    Screen.ForceContainerUpdate = false;
    Screen.ActiveSpace = 0;
    Screen.OldWindowListCount = -1;

    Screen.X = DisplayRect.origin.x;
    Screen.Y = DisplayRect.origin.y;
    Screen.Width = DisplayRect.size.width;
    Screen.Height = DisplayRect.size.height;

    Screen.PaddingTop = DefaultPaddingTop;
    Screen.PaddingLeft = DefaultPaddingLeft;
    Screen.PaddingRight = DefaultPaddingRight;
    Screen.PaddingBottom = DefaultPaddingBottom;

    Screen.VerticalGap = DefaultGapVertical;
    Screen.HorizontalGap = DefaultGapHorizontal;

    return Screen;
}

void UpdateExistingScreenInfo(screen_info *Screen, int DisplayIndex, int ScreenIndex)
{
    CGRect DisplayRect = CGDisplayBounds(DisplayIndex);
    Screen->ID = ScreenIndex;

    Screen->X = DisplayRect.origin.x;
    Screen->Y = DisplayRect.origin.y;
    Screen->Width = DisplayRect.size.width;
    Screen->Height = DisplayRect.size.height;

    Screen->PaddingTop = DefaultPaddingTop;
    Screen->PaddingLeft = DefaultPaddingLeft;
    Screen->PaddingRight = DefaultPaddingRight;
    Screen->PaddingBottom = DefaultPaddingBottom;

    Screen->VerticalGap = DefaultGapVertical;
    Screen->HorizontalGap = DefaultGapHorizontal;
    Screen->ForceContainerUpdate = true;
}

void GetActiveDisplays()
{
    CGGetActiveDisplayList(MaxDisplayCount, (CGDirectDisplayID*)&ActiveDisplays, &ActiveDisplaysCount);
    for(int DisplayIndex = 0; DisplayIndex < ActiveDisplaysCount; ++DisplayIndex)
    {
        unsigned int DisplayID = ActiveDisplays[DisplayIndex];
        DisplayMap[DisplayID] = CreateDefaultScreenInfo(DisplayID, DisplayIndex);;

        DEBUG("DisplayID " << DisplayID << " has index " << DisplayIndex)
    }

    Screen = GetDisplayOfMousePointer();
    CGDisplayRegisterReconfigurationCallback(DisplayReconfigurationCallBack, NULL);
}

void RefreshActiveDisplays()
{
    CGGetActiveDisplayList(MaxDisplayCount, (CGDirectDisplayID*)&ActiveDisplays, &ActiveDisplaysCount);
    for(int DisplayIndex = 0; DisplayIndex < ActiveDisplaysCount; ++DisplayIndex)
    {
        unsigned int DisplayID = ActiveDisplays[DisplayIndex];
        std::map<unsigned int, screen_info>::iterator It;

        if(It != DisplayMap.end())
            UpdateExistingScreenInfo(&DisplayMap[DisplayID], DisplayID, DisplayIndex);
        else
            DisplayMap[DisplayID] = CreateDefaultScreenInfo(DisplayID, DisplayIndex);

        DEBUG("DisplayID " << DisplayID << " has index " << DisplayIndex)
    }

    Screen = GetDisplayOfMousePointer();
}

screen_info *GetDisplayFromScreenID(int ID)
{
    std::map<unsigned int, screen_info>::iterator It;
    for(It = DisplayMap.begin(); It != DisplayMap.end(); ++It)
    {
        screen_info *Screen = &It->second;
        if(Screen->ID == ID)
            return Screen;
    }

    return NULL;
}

screen_info *GetDisplayOfMousePointer()
{
    std::map<unsigned int, screen_info>::iterator It;
    for(It = DisplayMap.begin(); It != DisplayMap.end(); ++It)
    {
        CGPoint Cursor = GetCursorPos();
        screen_info *Screen = &It->second;
        if(Cursor.x >= Screen->X && Cursor.x <= Screen->X + Screen->Width &&
           Cursor.y >= Screen->Y && Cursor.y <= Screen->Y + Screen->Height)
               return Screen;
    }

    return NULL;
}

screen_info *GetDisplayOfWindow(window_info *Window)
{
    if(Window)
    {
        std::map<unsigned int, screen_info>::iterator It;
        for(It = DisplayMap.begin(); It != DisplayMap.end(); ++It)
        {
            screen_info *Screen = &It->second;
            if(Window->X >= Screen->X && Window->X <= Screen->X + Screen->Width)
                return Screen;
        }
    }

    return NULL;
}

std::vector<window_info*> GetAllWindowsOnDisplay(int ScreenIndex)
{
    screen_info *Screen = GetDisplayFromScreenID(ScreenIndex);
    std::vector<window_info*> ScreenWindowLst;
    for(int WindowIndex = 0; WindowIndex < WindowLst.size(); ++WindowIndex)
    {
        window_info *Window = &WindowLst[WindowIndex];
        if(!IsApplicationFloating(&WindowLst[WindowIndex]))
        {
            if(Window->X >= Screen->X && Window->X <= Screen->X + Screen->Width)
                ScreenWindowLst.push_back(Window);
        }
    }

    return ScreenWindowLst;
}

std::vector<int> GetAllWindowIDsOnDisplay(int ScreenIndex)
{
    screen_info *Screen = GetDisplayFromScreenID(ScreenIndex);
    std::vector<int> ScreenWindowIDLst;
    for(int WindowIndex = 0; WindowIndex < WindowLst.size(); ++WindowIndex)
    {
        window_info *Window = &WindowLst[WindowIndex];
        if(!IsApplicationFloating(&WindowLst[WindowIndex]))
        {
            if(Window->X >= Screen->X && Window->X <= Screen->X + Screen->Width)
                ScreenWindowIDLst.push_back(Window->WID);
        }
    }

    return ScreenWindowIDLst;
}

void SetDefaultPaddingOfDisplay(const std::string &Side, int Offset)
{
    if(Side == "left")
        DefaultPaddingLeft = Offset;
    else if(Side == "right")
        DefaultPaddingRight = Offset;
    else if(Side == "top")
        DefaultPaddingTop = Offset;
    else if(Side == "bottom")
        DefaultPaddingBottom = Offset;
}

void SetDefaultGapOfDisplay(const std::string &Side, int Offset)
{
    if(Side == "vertical")
        DefaultGapVertical = Offset;
    else if(Side == "horizontal")
        DefaultGapHorizontal = Offset;
}

void ChangePaddingOfDisplay(const std::string &Side, int Offset)
{
    screen_info *Screen = GetDisplayOfMousePointer();
    space_info *Space = &Screen->Space[Screen->ActiveSpace];

    if(Side == "left")
    {
        if(Space->PaddingLeft + Offset >= 0)
            Space->PaddingLeft += Offset;
    }
    else if(Side == "right")
    {
        if(Space->PaddingRight + Offset >= 0)
            Space->PaddingRight += Offset;
    }
    else if(Side == "top")
    {
        if(Space->PaddingTop + Offset >= 0)
            Space->PaddingTop += Offset;
    }
    else if(Side == "bottom")
    {
        if(Space->PaddingBottom + Offset >= 0)
            Space->PaddingBottom += Offset;
    }

    if(Space->RootNode)
    {
        SetRootNodeContainer(Screen, Space->RootNode);
        CreateNodeContainers(Screen, Space->RootNode, true);
        ApplyNodeContainer(Space->RootNode);
    }
}

void ChangeGapOfDisplay(const std::string &Side, int Offset)
{
    screen_info *Screen = GetDisplayOfMousePointer();
    space_info *Space = &Screen->Space[Screen->ActiveSpace];

    if(Side == "vertical")
    {
        if(Space->VerticalGap + Offset >= 0)
            Space->VerticalGap += Offset;
    }
    else if(Side == "horizontal")
    {
        if(Space->HorizontalGap + Offset >= 0)
            Space->HorizontalGap += Offset;
    }

    if(Space->RootNode)
    {
        CreateNodeContainers(Screen, Space->RootNode, true);
        ApplyNodeContainer(Space->RootNode);
    }
}

void CycleFocusedWindowDisplay(int Shift, bool Relative)
{
    screen_info *Screen = GetDisplayOfWindow(FocusedWindow);
    int NewScreenIndex = -1;

    if(Relative)
    {
        if(Shift == 1)
            NewScreenIndex = (Screen->ID + 1 >= ActiveDisplaysCount) ? 0 : Screen->ID + 1;
        else if(Shift == -1)
            NewScreenIndex = (Screen->ID - 1 < 0) ? ActiveDisplaysCount - 1 : Screen->ID - 1;
    }
    else
    {
        NewScreenIndex = Shift;
    }

    if(NewScreenIndex != Screen->ID)
    {
        screen_info *NewScreen = GetDisplayFromScreenID(NewScreenIndex);
        AddWindowToTreeOfUnfocusedMonitor(NewScreen);
    }
}
<|endoftext|>