<commit_before>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2016 ETH Zurich
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
** following conditions are met:
**
** * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
** disclaimer.
** * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
** following disclaimer in the documentation and/or other materials provided with the distribution.
** * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
***********************************************************************************************************************/

#include "UseAnalysisGroupings.h"

#include "ModelBase/src/nodes/Reference.h"

namespace CodeReview
{

bool const UseAnalysisGroupings::ONLY_CONSIDER_CHANGES = true;

UseAnalysisGroupings::DiffFrameInfo UseAnalysisGroupings::computeDiffFrameDependenciesAndPresentations
		(VersionControlUI::DiffFrame* diffFrame)
{
	auto oldNode = diffFrame->oldVersionNode();
	auto newNode = diffFrame->newVersionNode();

	if (!oldNode && !newNode)
		return {};

	QList<Model::Node*> stack;
	if (oldNode)
		stack << oldNode;
	if (newNode)
		stack << newNode;

	DiffFrameInfo diffFrameInfo;

	while (!stack.isEmpty())
	{
		auto top = stack.takeLast();
		if (top)
		{

			if (auto referenceNode = DCast<Model::Reference>(top))
			{
				if (referenceNode->isResolved())
					diffFrameInfo.refersTo_.insert(referenceNode->target());

			}
			else
			{
				stack.append(top->children());
				diffFrameInfo.shows_.insert(top);
			}
		}
	}

	// remove ids which are shown by this DiffFrame from the dependencies
	diffFrameInfo.refersTo_.subtract(diffFrameInfo.shows_);

	return diffFrameInfo;
}

QList<QList<VersionControlUI::DiffFrame*>> UseAnalysisGroupings::useAnalysisGrouping(QList<VersionControlUI::DiffFrame*>
																												 diffFrames)
{
	QList<QList<VersionControlUI::DiffFrame*>> result;

	QHash<VersionControlUI::DiffFrame*, DiffFrameInfo> diffFrameToInfo;
	QHash<VersionControlUI::DiffFrame*, QList<VersionControlUI::DiffFrame*>*> groupLists;

	for (auto diffFrame : diffFrames)
	{
		auto info = computeDiffFrameDependenciesAndPresentations(diffFrame);

		diffFrameToInfo.insert(diffFrame, info);
	}

	for (auto diffFrame : diffFrames)
	{
		bool dependsOnOther = false;

		for (auto otherDiffFrame : diffFrames)
		{
			if (diffFrame == otherDiffFrame) continue;

			if (dependsOn(diffFrameToInfo.value(diffFrame), otherDiffFrame, diffFrameToInfo.value(otherDiffFrame)))
			{
				dependsOnOther = true;
				auto iter = groupLists.find(otherDiffFrame);
				if (iter != groupLists.end())
				{
					iter.value()->append(diffFrame);
					groupLists.insert(diffFrame, iter.value());
				} else
				{
					result.append(QList<VersionControlUI::DiffFrame*>{});
					result.last().append(diffFrame);
					result.last().append(otherDiffFrame);
					groupLists.insert(diffFrame, &result.last());
					groupLists.insert(otherDiffFrame, &result.last());
				}
			}
		}

		if (!dependsOnOther && !groupLists.contains(diffFrame))
		{
			result.append(QList<VersionControlUI::DiffFrame*>{});
			result.last().append(diffFrame);
			groupLists.insert(diffFrame, &result.last());
		}
	}
	return result;
}

bool UseAnalysisGroupings::dependsOn(DiffFrameInfo infoA,
												VersionControlUI::DiffFrame* frameB, DiffFrameInfo infoB)
{
	if (ONLY_CONSIDER_CHANGES)
	{
		for (auto referal : infoA.refersTo_)
		{
			for (auto changesOld : frameB->oldChangedNodes())
				if (changesOld->isSameOrAncestorOf(referal))
					return true;
			for (auto changesNew : frameB->newChangedNodes())
				if (changesNew->isSameOrAncestorOf(referal))
					return true;
		}
		return false;
	}
	else
	{
		auto refers = infoA.refersTo_;
		auto shows = infoB.shows_;
		return !refers.intersect(shows).isEmpty();
	}
}

}
<commit_msg>Fix condition for dependsOn function<commit_after>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2016 ETH Zurich
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
** following conditions are met:
**
** * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
** disclaimer.
** * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
** following disclaimer in the documentation and/or other materials provided with the distribution.
** * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
***********************************************************************************************************************/

#include "UseAnalysisGroupings.h"

#include "ModelBase/src/nodes/Reference.h"

namespace CodeReview
{

bool const UseAnalysisGroupings::ONLY_CONSIDER_CHANGES = true;

UseAnalysisGroupings::DiffFrameInfo UseAnalysisGroupings::computeDiffFrameDependenciesAndPresentations
		(VersionControlUI::DiffFrame* diffFrame)
{
	auto oldNode = diffFrame->oldVersionNode();
	auto newNode = diffFrame->newVersionNode();

	if (!oldNode && !newNode)
		return {};

	QList<Model::Node*> stack;
	if (oldNode)
		stack << oldNode;
	if (newNode)
		stack << newNode;

	DiffFrameInfo diffFrameInfo;

	while (!stack.isEmpty())
	{
		auto top = stack.takeLast();
		if (top)
		{

			if (auto referenceNode = DCast<Model::Reference>(top))
			{
				if (referenceNode->isResolved())
					diffFrameInfo.refersTo_.insert(referenceNode->target());

			}
			else
			{
				stack.append(top->children());
				diffFrameInfo.shows_.insert(top);
			}
		}
	}

	// remove ids which are shown by this DiffFrame from the dependencies
	diffFrameInfo.refersTo_.subtract(diffFrameInfo.shows_);

	return diffFrameInfo;
}

QList<QList<VersionControlUI::DiffFrame*>> UseAnalysisGroupings::useAnalysisGrouping(QList<VersionControlUI::DiffFrame*>
																												 diffFrames)
{
	QList<QList<VersionControlUI::DiffFrame*>> result;

	QHash<VersionControlUI::DiffFrame*, DiffFrameInfo> diffFrameToInfo;
	QHash<VersionControlUI::DiffFrame*, QList<VersionControlUI::DiffFrame*>*> groupLists;

	for (auto diffFrame : diffFrames)
	{
		auto info = computeDiffFrameDependenciesAndPresentations(diffFrame);

		diffFrameToInfo.insert(diffFrame, info);
	}

	for (auto diffFrame : diffFrames)
	{
		bool dependsOnOther = false;

		for (auto otherDiffFrame : diffFrames)
		{
			if (diffFrame == otherDiffFrame) continue;

			if (dependsOn(diffFrameToInfo.value(diffFrame), otherDiffFrame, diffFrameToInfo.value(otherDiffFrame)))
			{
				dependsOnOther = true;
				auto iter = groupLists.find(otherDiffFrame);
				if (iter != groupLists.end())
				{
					iter.value()->append(diffFrame);
					groupLists.insert(diffFrame, iter.value());
				} else
				{
					result.append(QList<VersionControlUI::DiffFrame*>{});
					result.last().append(diffFrame);
					result.last().append(otherDiffFrame);
					groupLists.insert(diffFrame, &result.last());
					groupLists.insert(otherDiffFrame, &result.last());
				}
			}
		}

		if (!dependsOnOther && !groupLists.contains(diffFrame))
		{
			result.append(QList<VersionControlUI::DiffFrame*>{});
			result.last().append(diffFrame);
			groupLists.insert(diffFrame, &result.last());
		}
	}
	return result;
}

bool UseAnalysisGroupings::dependsOn(DiffFrameInfo infoA,
												VersionControlUI::DiffFrame* frameB, DiffFrameInfo infoB)
{
	if (ONLY_CONSIDER_CHANGES)
	{
		for (auto referal : infoA.refersTo_)
		{
			for (auto changesOld : frameB->oldChangedNodes())
				if (changesOld->isSameOrAncestorOf(referal) || referal->isSameOrAncestorOf(changesOld))
					return true;
			for (auto changesNew : frameB->newChangedNodes())
				if (changesNew->isSameOrAncestorOf(referal) || referal->isSameOrAncestorOf(changesNew))
					return true;
		}
		return false;
	}
	else
	{
		auto refers = infoA.refersTo_;
		auto shows = infoB.shows_;
		return !refers.intersect(shows).isEmpty();
	}
}

}
<|endoftext|>


<commit_before>/*
* This is an open source non-commercial project. Dear PVS-Studio, please check it.
* PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
*/
// Google Test library
#include <gtest/gtest.h>

// uArchSim modules
#include "../cow_string.h"

TEST( Cow_String, Copy_Check)
{
    CowString a {"Hello"};
    CowString b = a;
    ASSERT_EQ( a, b);
    ASSERT_EQ( static_cast<std::string_view>(a).data(), static_cast<std::string_view>(b).data());

    b += " World!";
    ASSERT_EQ( a, "Hello");
    ASSERT_EQ( b, "Hello World!");
    ASSERT_NE( a, b);
    ASSERT_NE( static_cast<std::string_view>(a).data(), static_cast<std::string_view>(b).data());
}

TEST( Cow_String, Assignment_Check)
{
    CowString a {"Hello"};
    CowString b = a;
    ASSERT_EQ( a, b);
    ASSERT_EQ( static_cast<std::string_view>(a).data(), static_cast<std::string_view>(b).data());

    a = "Goodbye!";
    ASSERT_EQ( a, "Goodbye!");
    ASSERT_EQ( b, "Hello");
    ASSERT_NE( a, b);
    ASSERT_NE( static_cast<std::string_view>(a).data(), static_cast<std::string_view>(b).data());
}

TEST( Cow_String, Empty_String)
{
    CowString a;
    ASSERT_EQ( a, "");
    CowString b = a;
    ASSERT_EQ( b, "");

    a = "Hello!";
    ASSERT_EQ( a, "Hello!");
    ASSERT_EQ( b, "");
    ASSERT_NE( a, b);

    b = "Goodbye!";
    ASSERT_EQ( b, "Goodbye!");
    ASSERT_NE( a, b);

    CowString c;
    ASSERT_EQ( c, "");
    c += "World!";
    ASSERT_EQ( c, "World!");
}

int main( int argc, char* argv[])
{
    ::testing::InitGoogleTest( &argc, argv);
    ::testing::FLAGS_gtest_death_test_style = "threadsafe";
    return RUN_ALL_TESTS();
}
<commit_msg>Update unit_test.cpp<commit_after>/*
* This is an open source non-commercial project. Dear PVS-Studio, please check it.
* PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
*/
// Google Test library
#include <gtest/gtest.h>

// uArchSim modules
#include "../cow_string.h"

TEST( Cow_String, Copy_Check)
{
    CowString a {"Hello"};
    CowString b = a;
    ASSERT_EQ( a, b);
    ASSERT_EQ( static_cast<std::string_view>(a).data(), static_cast<std::string_view>(b).data());

    b += " World!";
    ASSERT_EQ( a, "Hello");
    ASSERT_EQ( b, "Hello World!");
    ASSERT_NE( a, b);
    ASSERT_NE( static_cast<std::string_view>(a).data(), static_cast<std::string_view>(b).data());
}

TEST( Cow_String, Assignment_Check)
{
    CowString a {"Hello"};
    CowString b = a;
    ASSERT_EQ( a, b);
    ASSERT_EQ( static_cast<std::string_view>(a).data(), static_cast<std::string_view>(b).data());

    a = "Goodbye!";
    ASSERT_EQ( a, "Goodbye!");
    ASSERT_EQ( b, "Hello");
    ASSERT_NE( a, b);
    ASSERT_NE( static_cast<std::string_view>(a).data(), static_cast<std::string_view>(b).data());
}

TEST( Cow_String, Empty_String)
{
    CowString a;
    ASSERT_EQ( a, "");
    CowString b = a;
    ASSERT_EQ( b, "");

    a = "Hello!";
    ASSERT_EQ( a, "Hello!");
    ASSERT_EQ( b, "");
    ASSERT_NE( a, b);

    b = "Goodbye!";
    ASSERT_EQ( b, "Goodbye!");
    ASSERT_NE( a, b);

    CowString c;
    CowString d = c;
    ASSERT_EQ( c, "");
    c += "World!";
    ASSERT_EQ( c, "World!");
    ASSERT_EQ( d, "");
}

int main( int argc, char* argv[])
{
    ::testing::InitGoogleTest( &argc, argv);
    ::testing::FLAGS_gtest_death_test_style = "threadsafe";
    return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>#include "ConfigTypes.h"

/*
void ConfigSet::set(string name, string value){
    Strings[name] = value;
}

void ConfigSet::set( string name, std::map <string, std::pair <int, int> > value ){
	Pairs[name] = value;
}

void ConfigSet::set( string name, std::vector < int > value ){
	Vectors[name] = value;
}

string ConfigSet::get(string name){
    std::map < string, string>::iterator iter = Strings.find( name );
    if( iter != Strings.end() )
        return iter->second;
    return "";
}
*/
<commit_msg>Cleanup<commit_after><|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkTreeDifferenceFilter.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

#include "vtkTreeDifferenceFilter.h"

#include "vtkDataSetAttributes.h"
#include "vtkDoubleArray.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkMath.h"
#include "vtkNew.h"
#include "vtkObjectFactory.h"
#include "vtkStringArray.h"
#include "vtkTree.h"

vtkStandardNewMacro(vtkTreeDifferenceFilter);

//---------------------------------------------------------------------------
vtkTreeDifferenceFilter::vtkTreeDifferenceFilter()
{
  this->SetNumberOfInputPorts(2);
  this->SetNumberOfOutputPorts(1);

  this->IdArrayName = 0;
  this->ComparisonArrayName = 0;
  this->OutputArrayName = 0;
  this->ComparisonArrayIsVertexData = false;
}

//---------------------------------------------------------------------------
vtkTreeDifferenceFilter::~vtkTreeDifferenceFilter()
{
  // release memory
  this->SetIdArrayName(0);
  this->SetComparisonArrayName(0);
  this->SetOutputArrayName(0);
}

//---------------------------------------------------------------------------
int vtkTreeDifferenceFilter::FillInputPortInformation(int port, vtkInformation *info)
{
  if(port == 0)
    {
    info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkTree");
    }
  else if(port == 1)
    {
    info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkTree");
    info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(), 1);
    }

  return 1;
}

//---------------------------------------------------------------------------
int vtkTreeDifferenceFilter::RequestData(
  vtkInformation*,
  vtkInformationVector** inputVector,
  vtkInformationVector* outputVector)
{
  vtkInformation* tree1_info = inputVector[0]->GetInformationObject(0);
  vtkTree* tree1 = vtkTree::SafeDownCast(
    tree1_info->Get(vtkDataObject::DATA_OBJECT()));

  // Copy the structure into the output.
  vtkTree* outputTree = vtkTree::GetData(outputVector);

  vtkInformation* tree2_info = inputVector[1]->GetInformationObject(0);
  if(!tree2_info)
    {
    // If no second tree provided, we're done
    outputTree->CheckedShallowCopy(tree1);
    return 0;
    }

  vtkTree* tree2 = vtkTree::SafeDownCast(
    tree2_info->Get(vtkDataObject::DATA_OBJECT()));

  if (this->IdArrayName != 0)
    {
    if (!this->GenerateMapping(tree1, tree2))
      {
      return 0;
      }
    }
  else
    {
    this->VertexMap.clear();
    for (vtkIdType vertex = 0; vertex < tree1->GetNumberOfVertices(); ++vertex)
      {
      this->VertexMap[vertex] = vertex;
      }

    this->EdgeMap.clear();
    for (vtkIdType edge = 0; edge < tree1->GetNumberOfEdges(); ++edge)
      {
      this->VertexMap[edge] = edge;
      }
    }

  this->ComputeDifference(tree1, tree2);

  if (!outputTree->CheckedShallowCopy(tree1))
    {
    vtkErrorMacro(<<"Invalid tree structure.");
    return 0;
    }
  return 1;
}

//---------------------------------------------------------------------------
bool vtkTreeDifferenceFilter::GenerateMapping(vtkTree *tree1, vtkTree *tree2)
{
  this->VertexMap.clear();
  this->VertexMap.assign(tree1->GetNumberOfVertices(), -1);

  this->EdgeMap.clear();
  this->EdgeMap.assign(tree1->GetNumberOfEdges(), -1);

  vtkStringArray *nodeNames1 = vtkStringArray::SafeDownCast(
    tree1->GetVertexData()->GetAbstractArray(this->IdArrayName));
  if (nodeNames1 == NULL)
    {
    vtkErrorMacro("tree #1's VertexData does not have a vtkStringArray named "
      << this->IdArrayName);
    return false;
    }

  vtkStringArray *nodeNames2 = vtkStringArray::SafeDownCast(
    tree2->GetVertexData()->GetAbstractArray(this->IdArrayName));
  if (nodeNames2 == NULL)
    {
    vtkErrorMacro("tree #2's VertexData does not have a vtkStringArray named "
      << this->IdArrayName);
    return false;
    }

  vtkIdType root1 = tree1->GetRoot();
  vtkIdType root2 = tree2->GetRoot();

  vtkIdType edgeId1 = -1;
  vtkIdType edgeId2 = -1;

  // iterate over the vertex names for tree #1, finding the corresponding
  // vertex in tree #2.
  for (vtkIdType vertexItr = 0; vertexItr < nodeNames1->GetNumberOfTuples();
       ++vertexItr)
    {
    vtkIdType vertexId1 = vertexItr;
    std::string nodeName = nodeNames1->GetValue(vertexId1);
    if (nodeName.compare("") == 0)
      {
      continue;
      }

    // record this correspondence in the maps
    vtkIdType vertexId2 = nodeNames2->LookupValue(nodeName);
    if (vertexId2 == -1)
      {
      vtkWarningMacro("tree #2 does not contain a vertex named " << nodeName);
      continue;
      }
    this->VertexMap[vertexId1] = vertexId2;

    if (vertexId1 == root1 || vertexId2 == root2)
      {
      continue;
      }

    edgeId1 = tree1->GetEdgeId(tree1->GetParent(vertexId1), vertexId1);
    edgeId2 = tree2->GetEdgeId(tree2->GetParent(vertexId2), vertexId2);
    this->EdgeMap[edgeId1] = edgeId2;

    // descend the tree until we reach the root, mapping parent vertices to
    // each other along the way.
    while (tree1->GetParent(vertexId1) != root1 &&
           tree2->GetParent(vertexId2) != root2)
      {
      vertexId1 = tree1->GetParent(vertexId1);
      vertexId2 = tree2->GetParent(vertexId2);
      if (this->VertexMap[vertexId1] == -1)
        {
        this->VertexMap[vertexId1] = vertexId2;
        edgeId1 = tree1->GetEdgeId(tree1->GetParent(vertexId1), vertexId1);
        edgeId2 = tree2->GetEdgeId(tree2->GetParent(vertexId2), vertexId2);
        this->EdgeMap[edgeId1] = edgeId2;
        }
      }
    }

  return true;
}

//---------------------------------------------------------------------------
void vtkTreeDifferenceFilter::ComputeDifference(vtkTree *tree1, vtkTree *tree2)
{
  if (this->ComparisonArrayName == 0)
    {
    vtkErrorMacro("ComparisonArrayName has not been set.");
    return;
    }

  vtkDataSetAttributes *treeData1, *treeData2;
  const char *dataName;
  if (this->ComparisonArrayIsVertexData)
    {
    treeData1 = tree1->GetVertexData();
    treeData2 = tree2->GetVertexData();
    dataName = "VertexData";
    }
  else
    {
    treeData1 = tree1->GetEdgeData();
    treeData2 = tree2->GetEdgeData();
    dataName = "EdgeData";
    }

  vtkDoubleArray *arrayToCompare1 = vtkDoubleArray::SafeDownCast(
    treeData1->GetAbstractArray(this->ComparisonArrayName));
  if (arrayToCompare1 == NULL)
    {
    vtkErrorMacro("tree #1's " << dataName <<
      " does not have a vtkDoubleArray named " << this->IdArrayName);
    return;
    }

  vtkDoubleArray *arrayToCompare2 = vtkDoubleArray::SafeDownCast(
    treeData2->GetAbstractArray(this->ComparisonArrayName));
  if (arrayToCompare2 == NULL)
    {
    vtkErrorMacro("tree #2's " << dataName <<
      " does not have a vtkDoubleArray named " << this->IdArrayName);
    return;
    }

  vtkNew<vtkDoubleArray> resultArray;
  resultArray->SetNumberOfValues(arrayToCompare1->GetNumberOfTuples());
  resultArray->FillComponent(0, vtkMath::Nan());

  if (this->OutputArrayName == 0)
    {
    resultArray->SetName("difference");
    }
  else
    {
    resultArray->SetName(this->OutputArrayName);
    }

  vtkIdType treeId2;
  for (vtkIdType treeId1 = 0; treeId1 < arrayToCompare1->GetNumberOfTuples();
       ++treeId1)
    {
    treeId2 = this->EdgeMap[treeId1];
    double result =
      arrayToCompare1->GetValue(treeId1) - arrayToCompare2->GetValue(treeId2);
    resultArray->SetValue(treeId1, result);
    }

  treeData1->AddArray(resultArray.GetPointer());
}

//---------------------------------------------------------------------------
void vtkTreeDifferenceFilter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}
<commit_msg>Fix some logic errors<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkTreeDifferenceFilter.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

#include "vtkTreeDifferenceFilter.h"

#include "vtkDataSetAttributes.h"
#include "vtkDoubleArray.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkMath.h"
#include "vtkNew.h"
#include "vtkObjectFactory.h"
#include "vtkStringArray.h"
#include "vtkTree.h"

vtkStandardNewMacro(vtkTreeDifferenceFilter);

//---------------------------------------------------------------------------
vtkTreeDifferenceFilter::vtkTreeDifferenceFilter()
{
  this->SetNumberOfInputPorts(2);
  this->SetNumberOfOutputPorts(1);

  this->IdArrayName = 0;
  this->ComparisonArrayName = 0;
  this->OutputArrayName = 0;
  this->ComparisonArrayIsVertexData = false;
}

//---------------------------------------------------------------------------
vtkTreeDifferenceFilter::~vtkTreeDifferenceFilter()
{
  // release memory
  this->SetIdArrayName(0);
  this->SetComparisonArrayName(0);
  this->SetOutputArrayName(0);
}

//---------------------------------------------------------------------------
int vtkTreeDifferenceFilter::FillInputPortInformation(int port, vtkInformation *info)
{
  if(port == 0)
    {
    info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkTree");
    }
  else if(port == 1)
    {
    info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkTree");
    info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(), 1);
    }

  return 1;
}

//---------------------------------------------------------------------------
int vtkTreeDifferenceFilter::RequestData(
  vtkInformation*,
  vtkInformationVector** inputVector,
  vtkInformationVector* outputVector)
{
  vtkInformation* tree1_info = inputVector[0]->GetInformationObject(0);
  vtkTree* tree1 = vtkTree::SafeDownCast(
    tree1_info->Get(vtkDataObject::DATA_OBJECT()));

  // Copy the structure into the output.
  vtkTree* outputTree = vtkTree::GetData(outputVector);

  vtkInformation* tree2_info = inputVector[1]->GetInformationObject(0);
  if(!tree2_info)
    {
    // If no second tree provided, we're done
    outputTree->CheckedShallowCopy(tree1);
    return 0;
    }

  vtkTree* tree2 = vtkTree::SafeDownCast(
    tree2_info->Get(vtkDataObject::DATA_OBJECT()));

  if (this->IdArrayName != 0)
    {
    if (!this->GenerateMapping(tree1, tree2))
      {
      return 0;
      }
    }
  else
    {
    this->VertexMap.clear();
    for (vtkIdType vertex = 0; vertex < tree1->GetNumberOfVertices(); ++vertex)
      {
      this->VertexMap[vertex] = vertex;
      }

    this->EdgeMap.clear();
    for (vtkIdType edge = 0; edge < tree1->GetNumberOfEdges(); ++edge)
      {
      this->EdgeMap[edge] = edge;
      }
    }

  this->ComputeDifference(tree1, tree2);

  if (!outputTree->CheckedShallowCopy(tree1))
    {
    vtkErrorMacro(<<"Invalid tree structure.");
    return 0;
    }
  return 1;
}

//---------------------------------------------------------------------------
bool vtkTreeDifferenceFilter::GenerateMapping(vtkTree *tree1, vtkTree *tree2)
{
  this->VertexMap.clear();
  this->VertexMap.assign(tree1->GetNumberOfVertices(), -1);

  this->EdgeMap.clear();
  this->EdgeMap.assign(tree1->GetNumberOfEdges(), -1);

  vtkStringArray *nodeNames1 = vtkStringArray::SafeDownCast(
    tree1->GetVertexData()->GetAbstractArray(this->IdArrayName));
  if (nodeNames1 == NULL)
    {
    vtkErrorMacro("tree #1's VertexData does not have a vtkStringArray named "
      << this->IdArrayName);
    return false;
    }

  vtkStringArray *nodeNames2 = vtkStringArray::SafeDownCast(
    tree2->GetVertexData()->GetAbstractArray(this->IdArrayName));
  if (nodeNames2 == NULL)
    {
    vtkErrorMacro("tree #2's VertexData does not have a vtkStringArray named "
      << this->IdArrayName);
    return false;
    }

  vtkIdType root1 = tree1->GetRoot();
  vtkIdType root2 = tree2->GetRoot();

  vtkIdType edgeId1 = -1;
  vtkIdType edgeId2 = -1;

  // iterate over the vertex names for tree #1, finding the corresponding
  // vertex in tree #2.
  for (vtkIdType vertexItr = 0; vertexItr < nodeNames1->GetNumberOfTuples();
       ++vertexItr)
    {
    vtkIdType vertexId1 = vertexItr;
    std::string nodeName = nodeNames1->GetValue(vertexId1);
    if (nodeName.compare("") == 0)
      {
      continue;
      }

    // record this correspondence in the maps
    vtkIdType vertexId2 = nodeNames2->LookupValue(nodeName);
    if (vertexId2 == -1)
      {
      vtkWarningMacro("tree #2 does not contain a vertex named " << nodeName);
      continue;
      }
    this->VertexMap[vertexId1] = vertexId2;

    if (vertexId1 == root1 || vertexId2 == root2)
      {
      continue;
      }

    edgeId1 = tree1->GetEdgeId(tree1->GetParent(vertexId1), vertexId1);
    edgeId2 = tree2->GetEdgeId(tree2->GetParent(vertexId2), vertexId2);
    this->EdgeMap[edgeId1] = edgeId2;

    // descend the tree until we reach the root, mapping parent vertices to
    // each other along the way.
    while (tree1->GetParent(vertexId1) != root1 &&
           tree2->GetParent(vertexId2) != root2)
      {
      vertexId1 = tree1->GetParent(vertexId1);
      vertexId2 = tree2->GetParent(vertexId2);
      if (this->VertexMap[vertexId1] == -1)
        {
        this->VertexMap[vertexId1] = vertexId2;
        edgeId1 = tree1->GetEdgeId(tree1->GetParent(vertexId1), vertexId1);
        edgeId2 = tree2->GetEdgeId(tree2->GetParent(vertexId2), vertexId2);
        this->EdgeMap[edgeId1] = edgeId2;
        }
      }
    }

  return true;
}

//---------------------------------------------------------------------------
void vtkTreeDifferenceFilter::ComputeDifference(vtkTree *tree1, vtkTree *tree2)
{
  if (this->ComparisonArrayName == 0)
    {
    vtkErrorMacro("ComparisonArrayName has not been set.");
    return;
    }

  vtkDataSetAttributes *treeData1, *treeData2;
  const char *dataName;
  if (this->ComparisonArrayIsVertexData)
    {
    treeData1 = tree1->GetVertexData();
    treeData2 = tree2->GetVertexData();
    dataName = "VertexData";
    }
  else
    {
    treeData1 = tree1->GetEdgeData();
    treeData2 = tree2->GetEdgeData();
    dataName = "EdgeData";
    }

  vtkDoubleArray *arrayToCompare1 = vtkDoubleArray::SafeDownCast(
    treeData1->GetAbstractArray(this->ComparisonArrayName));
  if (arrayToCompare1 == NULL)
    {
    vtkErrorMacro("tree #1's " << dataName <<
      " does not have a vtkDoubleArray named " << this->IdArrayName);
    return;
    }

  vtkDoubleArray *arrayToCompare2 = vtkDoubleArray::SafeDownCast(
    treeData2->GetAbstractArray(this->ComparisonArrayName));
  if (arrayToCompare2 == NULL)
    {
    vtkErrorMacro("tree #2's " << dataName <<
      " does not have a vtkDoubleArray named " << this->IdArrayName);
    return;
    }

  vtkNew<vtkDoubleArray> resultArray;
  resultArray->SetNumberOfValues(arrayToCompare1->GetNumberOfTuples());
  resultArray->FillComponent(0, vtkMath::Nan());

  if (this->OutputArrayName == 0)
    {
    resultArray->SetName("difference");
    }
  else
    {
    resultArray->SetName(this->OutputArrayName);
    }

  vtkIdType treeId2;
  for (vtkIdType treeId1 = 0; treeId1 < arrayToCompare1->GetNumberOfTuples();
       ++treeId1)
    {
    if (this->ComparisonArrayIsVertexData)
      {
      treeId2 = this->VertexMap[treeId1];
      }
    else
      {
      treeId2 = this->EdgeMap[treeId1];
      }
    double result =
      arrayToCompare1->GetValue(treeId1) - arrayToCompare2->GetValue(treeId2);
    resultArray->SetValue(treeId1, result);
    }

  treeData1->AddArray(resultArray.GetPointer());
}

//---------------------------------------------------------------------------
void vtkTreeDifferenceFilter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}
<|endoftext|>


<commit_before>#include <sys/types.h>
#include <sys/epoll.h>
#include <sys/errno.h>
#include <sys/time.h>
#include <unistd.h>

#include <common/buffer.h>

#include <event/event_callback.h>
#include <event/event_poll.h>

#define	EPOLL_EVENT_COUNT	128

struct EventPollState {
	int ep_;
};

EventPoll::EventPoll(void)
: log_("/event/poll"),
  read_poll_(),
  write_poll_(),
  state_(new EventPollState())
{
	state_->ep_ = epoll_create(EPOLL_EVENT_COUNT);
	ASSERT(state_->ep_ != -1);
}

EventPoll::~EventPoll()
{
	ASSERT(read_poll_.empty());
	ASSERT(write_poll_.empty());

	if (state_ != NULL) {
		if (state_->ep_ != -1) {
			close(state_->ep_);
			state_->ep_ = -1;
		}
		delete state_;
		state_ = NULL;
	}
}

Action *
EventPoll::poll(const Type& type, int fd, EventCallback *cb)
{
	ASSERT(fd != -1);

	EventPoll::PollHandler *poll_handler;
	struct epoll_event eev;
	bool unique = true;
	eev.data.fd = fd;
	switch (type) {
	case EventPoll::Readable:
		ASSERT(read_poll_.find(fd) == read_poll_.end());
		unique = write_poll_.find(fd) == write_poll_.end();
		poll_handler = &read_poll_[fd];
		eev.events = EPOLLIN | (unique ? 0 : EPOLLOUT);
		break;
	case EventPoll::Writable:
		ASSERT(write_poll_.find(fd) == write_poll_.end());
		unique = read_poll_.find(fd) == read_poll_.end();
		poll_handler = &write_poll_[fd];
		eev.events = EPOLLOUT | (unique ? 0 : EPOLLIN);
		break;
	default:
		NOTREACHED();
	}
	int rv = ::epoll_ctl(state_->ep_, unique ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, fd, &eev);
	if (rv == -1)
		HALT(log_) << "Could not add event to epoll.";
	ASSERT(rv == 0);
	ASSERT(poll_handler->action_ == NULL);
	poll_handler->callback_ = cb;
	Action *a = new EventPoll::PollAction(this, type, fd);
	return (a);
}

void
EventPoll::cancel(const Type& type, int fd)
{
	EventPoll::PollHandler *poll_handler;

	struct epoll_event eev;
	bool unique = true;
	eev.data.fd = fd;
	switch (type) {
	case EventPoll::Readable:
		ASSERT(read_poll_.find(fd) != read_poll_.end());
		unique = write_poll_.find(fd) == write_poll_.end();
		poll_handler = &read_poll_[fd];
		poll_handler->cancel();
		read_poll_.erase(fd);
		eev.events = unique ? 0 : EPOLLOUT;
		break;
	case EventPoll::Writable:
		ASSERT(write_poll_.find(fd) != write_poll_.end());
		unique = read_poll_.find(fd) == read_poll_.end();
		poll_handler = &write_poll_[fd];
		poll_handler->cancel();
		write_poll_.erase(fd);
		eev.events = unique ? 0 : EPOLLIN;
		break;
	}
	int rv = ::epoll_ctl(state_->ep_, unique ? EPOLL_CTL_DEL : EPOLL_CTL_MOD, fd, &eev);
	if (rv == -1)
		HALT(log_) << "Could not delete event from epoll.";
	ASSERT(rv == 0);
}

void
EventPoll::wait(int ms)
{
	struct timespec ts;

	ts.tv_sec = ms / 1000;
	ts.tv_nsec = (ms % 1000) * 1000000;

	if (idle()) {
		if (ms != -1) {
			int rv;

			rv = nanosleep(&ts, NULL);
			ASSERT(rv != -1);
		}
		return;
	}

	struct epoll_event eev[EPOLL_EVENT_COUNT];
	int evcnt = ::epoll_wait(state_->ep_, eev, EPOLL_EVENT_COUNT, ms);
	if (evcnt == -1) {
		if (errno == EINTR) {
			INFO(log_) << "Received interrupt, ceasing polling until stop handlers have run.";
			return;
		}
		HALT(log_) << "Could not poll epoll.";
	}

	int i;
	for (i = 0; i < evcnt; i++) {
		struct epoll_event *ev = &eev[i];
		EventPoll::PollHandler *poll_handler;
		if ((ev->events & EPOLLIN) != 0) {
			ASSERT(read_poll_.find(ev->data.fd) != read_poll_.end());
			poll_handler = &read_poll_[ev->data.fd];
			poll_handler->callback(Event::Done);
		}

		if ((ev->events & EPOLLOUT) != 0) {
			ASSERT(write_poll_.find(ev->data.fd) != write_poll_.end());
			poll_handler = &write_poll_[ev->data.fd];
			poll_handler->callback(Event::Done);
		}

		if ((ev->events & EPOLLIN) == 0 && (ev->events & EPOLLOUT) == 0) {
			if (read_poll_.find(ev->data.fd) != read_poll_.end()) {
				poll_handler = &read_poll_[ev->data.fd];
			} else if (write_poll_.find(ev->data.fd) != write_poll_.end()) {
				poll_handler = &write_poll_[ev->data.fd];
			} else {
				HALT(log_) << "Unexpected poll fd.";
				continue;
			}

			if ((ev->events & EPOLLERR) != 0) {
				poll_handler->callback(Event::Error);
				continue;
			}

			if ((ev->events & EPOLLHUP) != 0) {
				poll_handler->callback(Event::EOS);
				continue;
			}

			HALT(log_) << "Unexpected poll events: " << ev->events;
		}
	}
}
<commit_msg>Ignore hangup on write polls.<commit_after>#include <sys/types.h>
#include <sys/epoll.h>
#include <sys/errno.h>
#include <sys/time.h>
#include <unistd.h>

#include <common/buffer.h>

#include <event/event_callback.h>
#include <event/event_poll.h>

#define	EPOLL_EVENT_COUNT	128

struct EventPollState {
	int ep_;
};

EventPoll::EventPoll(void)
: log_("/event/poll"),
  read_poll_(),
  write_poll_(),
  state_(new EventPollState())
{
	state_->ep_ = epoll_create(EPOLL_EVENT_COUNT);
	ASSERT(state_->ep_ != -1);
}

EventPoll::~EventPoll()
{
	ASSERT(read_poll_.empty());
	ASSERT(write_poll_.empty());

	if (state_ != NULL) {
		if (state_->ep_ != -1) {
			close(state_->ep_);
			state_->ep_ = -1;
		}
		delete state_;
		state_ = NULL;
	}
}

Action *
EventPoll::poll(const Type& type, int fd, EventCallback *cb)
{
	ASSERT(fd != -1);

	EventPoll::PollHandler *poll_handler;
	struct epoll_event eev;
	bool unique = true;
	eev.data.fd = fd;
	switch (type) {
	case EventPoll::Readable:
		ASSERT(read_poll_.find(fd) == read_poll_.end());
		unique = write_poll_.find(fd) == write_poll_.end();
		poll_handler = &read_poll_[fd];
		eev.events = EPOLLIN | (unique ? 0 : EPOLLOUT);
		break;
	case EventPoll::Writable:
		ASSERT(write_poll_.find(fd) == write_poll_.end());
		unique = read_poll_.find(fd) == read_poll_.end();
		poll_handler = &write_poll_[fd];
		eev.events = EPOLLOUT | (unique ? 0 : EPOLLIN);
		break;
	default:
		NOTREACHED();
	}
	int rv = ::epoll_ctl(state_->ep_, unique ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, fd, &eev);
	if (rv == -1)
		HALT(log_) << "Could not add event to epoll.";
	ASSERT(rv == 0);
	ASSERT(poll_handler->action_ == NULL);
	poll_handler->callback_ = cb;
	Action *a = new EventPoll::PollAction(this, type, fd);
	return (a);
}

void
EventPoll::cancel(const Type& type, int fd)
{
	EventPoll::PollHandler *poll_handler;

	struct epoll_event eev;
	bool unique = true;
	eev.data.fd = fd;
	switch (type) {
	case EventPoll::Readable:
		ASSERT(read_poll_.find(fd) != read_poll_.end());
		unique = write_poll_.find(fd) == write_poll_.end();
		poll_handler = &read_poll_[fd];
		poll_handler->cancel();
		read_poll_.erase(fd);
		eev.events = unique ? 0 : EPOLLOUT;
		break;
	case EventPoll::Writable:
		ASSERT(write_poll_.find(fd) != write_poll_.end());
		unique = read_poll_.find(fd) == read_poll_.end();
		poll_handler = &write_poll_[fd];
		poll_handler->cancel();
		write_poll_.erase(fd);
		eev.events = unique ? 0 : EPOLLIN;
		break;
	}
	int rv = ::epoll_ctl(state_->ep_, unique ? EPOLL_CTL_DEL : EPOLL_CTL_MOD, fd, &eev);
	if (rv == -1)
		HALT(log_) << "Could not delete event from epoll.";
	ASSERT(rv == 0);
}

void
EventPoll::wait(int ms)
{
	struct timespec ts;

	ts.tv_sec = ms / 1000;
	ts.tv_nsec = (ms % 1000) * 1000000;

	if (idle()) {
		if (ms != -1) {
			int rv;

			rv = nanosleep(&ts, NULL);
			ASSERT(rv != -1);
		}
		return;
	}

	struct epoll_event eev[EPOLL_EVENT_COUNT];
	int evcnt = ::epoll_wait(state_->ep_, eev, EPOLL_EVENT_COUNT, ms);
	if (evcnt == -1) {
		if (errno == EINTR) {
			INFO(log_) << "Received interrupt, ceasing polling until stop handlers have run.";
			return;
		}
		HALT(log_) << "Could not poll epoll.";
	}

	int i;
	for (i = 0; i < evcnt; i++) {
		struct epoll_event *ev = &eev[i];
		EventPoll::PollHandler *poll_handler;
		if ((ev->events & EPOLLIN) != 0) {
			ASSERT(read_poll_.find(ev->data.fd) != read_poll_.end());
			poll_handler = &read_poll_[ev->data.fd];
			poll_handler->callback(Event::Done);
		}

		if ((ev->events & EPOLLOUT) != 0) {
			ASSERT(write_poll_.find(ev->data.fd) != write_poll_.end());
			poll_handler = &write_poll_[ev->data.fd];
			poll_handler->callback(Event::Done);
		}

		if ((ev->events & EPOLLIN) == 0 && (ev->events & EPOLLOUT) == 0) {
			if (read_poll_.find(ev->data.fd) != read_poll_.end()) {
				poll_handler = &read_poll_[ev->data.fd];
			} else if (write_poll_.find(ev->data.fd) != write_poll_.end()) {
				poll_handler = &write_poll_[ev->data.fd];

				if ((ev->events & (EPOLLERR | EPOLLHUP)) == EPOLLHUP) {
					DEBUG(log_) << "Got EPOLLHUP on write poll.";
					continue;
				}
			} else {
				HALT(log_) << "Unexpected poll fd.";
				continue;
			}

			if ((ev->events & EPOLLERR) != 0) {
				poll_handler->callback(Event::Error);
				continue;
			}

			if ((ev->events & EPOLLHUP) != 0) {
				poll_handler->callback(Event::EOS);
				continue;
			}

			HALT(log_) << "Unexpected poll events: " << ev->events;
		}
	}
}
<|endoftext|>


<commit_before>//===========================================
//  Lumina-DE source code
//  Copyright (c) 2016, Ken Moore
//  Available under the 3-clause BSD license
//  See the LICENSE file for full details
//===========================================
#include "session.h"

#include <QObject>
#include <QProcess>
#include <QProcessEnvironment>
#include <QDebug>
#include <QSettings>
#include <QDir>

#include <LUtils.h>
#include <LuminaOS.h>
#include <LDesktopUtils.h>

void LSession::stopall(){
  stopping = true;
  for(int i=0; i<PROCS.length(); i++){
    if(PROCS[i]->state()!=QProcess::NotRunning){ PROCS[i]->kill(); }
  }
  QCoreApplication::processEvents();
  for(int i=0; i<PROCS.length(); i++){
    if(PROCS[i]->state()!=QProcess::NotRunning){ PROCS[i]->terminate(); }
  }
  QCoreApplication::exit(0);
}

void LSession::procFinished(){
  //Go through and check the status on all the procs to determine which one finished
  int stopped = 0;
  //qDebug() << "Got Process Stopped Signal:";
  for(int i=0; i<PROCS.length(); i++){
    if(PROCS[i]->state()==QProcess::NotRunning){
      //qDebug() << " - Stopped:" << PROCS[i]->objectName();
      stopped++;
      if(!stopping){
        //See if this process is the main desktop binary
        if(PROCS[i]->objectName()=="runtime"){
          qDebug() << "Got Desktop Process Finished:" << PROCS[i]->exitCode();
          //if(PROCS[i]->exitCode()==787){ PROCS[i]->start(QIODevice::ReadOnly); } //special internal restart code
          //else{
          stopall(); //}
        }else if(PROCS[i]->objectName()=="wm" && wmfails<2){ wmfails++; PROCS[i]->start(QIODevice::ReadOnly); wmTimer->start(); } //restart the WM
        //if(PROCS[i]->program().section("/",-1) == "lumina-desktop"){ stopall();  } //start closing down everything
        //else{ PROCS[i]->start(QIODevice::ReadOnly); } //restart the process
        //break;
      }
    }
  }
  //qDebug() << " - Final Count:" << stopped << stopping;
  if(stopping || stopped==PROCS.length()){
    //Note about compton: It does not like running multiple sessions under the *same user*
    // (even on different displays). Run a blanket killall on it when closing down so that
    // any other Lumina sessions will automatically restart compton on that specific display
    QProcess::execute("killall compton");
    QCoreApplication::exit(0);
  }else{
    //Make sure we restart the process as needed
    for(int i=0; i<PROCS.length(); i++){
      if(PROCS[i]->state()==QProcess::NotRunning){
        //runtime/wm processes have special restart rules above
        if(PROCS[i]->objectName()!="runtime" && PROCS[i]->objectName()!="wm"){
          PROCS[i]->start(QIODevice::ReadOnly);
        }
      }
    }
  }
}

void LSession::startProcess(QString ID, QString command, QStringList watchfiles){
  QString dir = QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/logs";
  QString display = QString(getenv("DISPLAY")).section(":",1,1);
  if(!QFile::exists(dir)){ QDir tmp(dir); tmp.mkpath(dir); }
  QString logfile = dir+"/"+ID+"_"+display+".log";
  if(QFile::exists(logfile+".old")){ QFile::remove(logfile+".old"); }
  if(QFile::exists(logfile)){ QFile::rename(logfile,logfile+".old"); }

  LProcess *proc = new LProcess(ID, watchfiles);
  proc->setProcessChannelMode(QProcess::MergedChannels);
  proc->setProcessEnvironment( QProcessEnvironment::systemEnvironment() );
  proc->setStandardOutputFile(logfile);
  proc->setObjectName(ID);
  if(ID=="runtime"){
    //Bypass for a hidden dbus file requirement for Qt itself (Qt 5.5.1+?)
    if(!QFile::exists("/etc/machine-id") && !QFile::exists("/var/db/dbus/machine-id")){
      if(LUtils::isValidBinary("dbus-uuidgen") && LUtils::runCmd("dbus-uuidgen --ensure") ){ } //good - the UUID was created successfully
      else if(LUtils::isValidBinary("dbus-launch")){ command.prepend("dbus-launch --exit-with-session "); }
      else{
        //create a simple DBUS UUID and put it in the universal-fallback location (OS-independent)
        // TO-DO - root vs user level permissions issue?
        qDebug() << "Could not find '/etc/machine-id' or '/var/db/dbus/machine-id': Qt will most likely crash. \nPlease run 'dbus-uuidgen --ensure' with root permissions to generate this file if Lumina does not start properly.";
      }
   }
  }
  proc->start(command, QIODevice::ReadOnly);
  connect(proc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(procFinished()) );
  PROCS << proc;
}

void LSession::setupCompositor(bool force){
  //Compositing manager
  QSettings settings("lumina-desktop","sessionsettings");
  if(settings.value("enableCompositing",false).toBool() || force){
    if(LUtils::isValidBinary("compton")){
      //Compton available - check the config file
      QString set = QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/compton.conf";
      if(!QFile::exists(set)){
	  if(QFile::exists(LOS::LuminaShare()+"/compton.conf")){
	    QFile::copy(LOS::LuminaShare()+"/compton.conf", set);
	  }
      }
	//Auto-detect if GLX is available on the system and turn it on/off as needed
       bool startcompton = true;
       if(LUtils::isValidBinary("glxinfo")){
	 bool hasAccel =! LUtils::getCmdOutput("glxinfo -B").filter("direct rendering:").filter("Yes").isEmpty();
	 qDebug() << "Detected GPU Acceleration:" << hasAccel;
	 QStringList info = LUtils::readFile(set);
	 for(int i=0; i<info.length(); i++){
	   if(info[i].section("=",0,0).simplified()=="backend"){ info[i] = QString("backend = \"")+ (hasAccel ? "glx" : "xrender")+"\""; break; } //replace this line
	 }
	 LUtils::writeFile(set, info, true);
	 if( !hasAccel && settings.value("compositingWithGpuAccelOnly",true).toBool() ){ startcompton = false; }
       }
       QString disp = getenv("DISPLAY");
	if(startcompton || force){ startProcess("compositing","compton --backend xr_glx_hybrid -d "+disp); }
    }else if(LUtils::isValidBinary("xcompmgr") && !settings.value("compositingWithGpuAccelOnly",true).toBool() ){ startProcess("compositing","xcompmgr"); }
  }
}

void LSession::start(bool unified){
  //First check for a valid installation
  if(!LUtils::isValidBinary("lumina-desktop") ){
    exit(1);
  }
  setenv("DESKTOP_SESSION","Lumina",1);
  setenv("XDG_CURRENT_DESKTOP","Lumina",1);
  setenv("QT_QPA_PLATFORMTHEME","lthemeengine", true);
  setenv("QT_NO_GLIB", "1", 1); //Disable the glib event loop within Qt at runtime (performance hit + bugs)
  unsetenv("QT_AUTO_SCREEN_SCALE_FACTOR"); //need exact-pixel measurements (no fake scaling)
  if(LUtils::isValidBinary("xdg-user-dirs-update")){
    //Make sure the XDG user directories are created as needed first
    QProcess::execute("xdg-user-dirs-update");
  }

 if(!unified){
  QSettings sessionsettings("lumina-desktop","sessionsettings");
  QString WM = sessionsettings.value("WindowManager", "fluxbox").toString();
  //Window Manager First
  if(WM=="fluxbox" || WM.endsWith("/fluxbox") || WM.simplified().isEmpty() ){
	  // FLUXBOX BUG BYPASS: if the ~/.fluxbox dir does not exist, it will ignore the given config file
	  if( !LUtils::isValidBinary("fluxbox") ){
	    qDebug() << "[INCOMPLETE LUMINA INSTALLATION] fluxbox binary is missing - cannot continue";
	  }else{
	    QString confDir = QString( getenv("XDG_CONFIG_HOME"))+"/lumina-desktop";
	    if(!QFile::exists(confDir)){ QDir dir(confDir); dir.mkpath(confDir); }
	    if(!QFile::exists(confDir+"/fluxbox-init")){
	      QStringList keys = LUtils::readFile(LOS::LuminaShare()+"/fluxbox-init-rc");
	       keys = keys.replaceInStrings("${XDG_CONFIG_HOME}", QString( getenv("XDG_CONFIG_HOME")));
	       LUtils::writeFile(confDir+"/fluxbox-init", keys, true);
	      QFile::setPermissions(confDir+"/fluxbox-init", QFile::ReadOwner | QFile::WriteOwner | QFile::ReadUser | QFile::ReadOther | QFile::ReadGroup);
	    }
	    if(!QFile::exists(confDir+"/fluxbox-keys")){
	      QStringList keys = LUtils::readFile(LOS::LuminaShare()+"/fluxbox-keys");
	       keys = keys.replaceInStrings("${XDG_CONFIG_HOME}", QString( getenv("XDG_CONFIG_HOME")));
	       LUtils::writeFile(confDir+"/fluxbox-keys", keys, true);
	      QFile::setPermissions(confDir+"/fluxbox-keys", QFile::ReadOwner | QFile::WriteOwner | QFile::ReadUser | QFile::ReadOther | QFile::ReadGroup);
	    }
	    // FLUXBOX BUG BYPASS: if the ~/.fluxbox dir does not exist, it will ignore the given config file
	    if(!QFile::exists(QDir::homePath()+"/.fluxbox")){
	      QDir dir; dir.mkpath(QDir::homePath()+"/.fluxbox");
	    }
	    QString cmd = "fluxbox -rc "+confDir+"/fluxbox-init -no-slit -no-toolbar";
	    startProcess("wm", cmd, QStringList() << confDir+"/fluxbox-init" << confDir+"/fluxbox-keys");
	  }
	  //Compositing manager
	  setupCompositor();
  } else {
	if(!LUtils::isValidBinary(WM)){
	  exit(1);
	}
	startProcess("wm", WM);
  }
  //Desktop Next
  startProcess("runtime","lumina-desktop -new-instance");
  //ScreenSaver
  if(LUtils::isValidBinary("xscreensaver")){ startProcess("screensaver","xscreensaver -no-splash"); }
 }else{
  //unified process
  setupCompositor(true); //required for Lumina 2
  startProcess("runtime","lumina-desktop-unified -new-instance");
 }
}

void LSession::checkFiles(){
//internal version conversion examples:
  //  [1.0.0 -> 1000000], [1.2.3 -> 1002003], [0.6.1 -> 6001]
  qDebug() << "[Lumina] Checking User Files";
  QSettings sset("lumina-desktop", "sessionsettings");
  QString OVS = sset.value("DesktopVersion","0").toString(); //Old Version String
  qDebug() << " - Old Version:" << OVS;
  qDebug() << " - Current Version:" << LDesktopUtils::LuminaDesktopVersion();
  bool changed = LDesktopUtils::checkUserFiles(OVS, LDesktopUtils::LuminaDesktopVersion());
  qDebug() << " - Made Changes:" << changed;
  if(changed){
    //Save the current version of the session to the settings file (for next time)
    sset.setValue("DesktopVersion", LDesktopUtils::LuminaDesktopVersion());
  }
  qDebug() << "Finished with user files check";
}
<commit_msg>Ensure that the Fluxbox background/wallpaper setter is disabled before Lumina starts it up<commit_after>//===========================================
//  Lumina-DE source code
//  Copyright (c) 2016, Ken Moore
//  Available under the 3-clause BSD license
//  See the LICENSE file for full details
//===========================================
#include "session.h"

#include <QObject>
#include <QProcess>
#include <QProcessEnvironment>
#include <QDebug>
#include <QSettings>
#include <QDir>

#include <LUtils.h>
#include <LuminaOS.h>
#include <LDesktopUtils.h>

void LSession::stopall(){
  stopping = true;
  for(int i=0; i<PROCS.length(); i++){
    if(PROCS[i]->state()!=QProcess::NotRunning){ PROCS[i]->kill(); }
  }
  QCoreApplication::processEvents();
  for(int i=0; i<PROCS.length(); i++){
    if(PROCS[i]->state()!=QProcess::NotRunning){ PROCS[i]->terminate(); }
  }
  QCoreApplication::exit(0);
}

void LSession::procFinished(){
  //Go through and check the status on all the procs to determine which one finished
  int stopped = 0;
  //qDebug() << "Got Process Stopped Signal:";
  for(int i=0; i<PROCS.length(); i++){
    if(PROCS[i]->state()==QProcess::NotRunning){
      //qDebug() << " - Stopped:" << PROCS[i]->objectName();
      stopped++;
      if(!stopping){
        //See if this process is the main desktop binary
        if(PROCS[i]->objectName()=="runtime"){
          qDebug() << "Got Desktop Process Finished:" << PROCS[i]->exitCode();
          //if(PROCS[i]->exitCode()==787){ PROCS[i]->start(QIODevice::ReadOnly); } //special internal restart code
          //else{
          stopall(); //}
        }else if(PROCS[i]->objectName()=="wm" && wmfails<2){ wmfails++; PROCS[i]->start(QIODevice::ReadOnly); wmTimer->start(); } //restart the WM
        //if(PROCS[i]->program().section("/",-1) == "lumina-desktop"){ stopall();  } //start closing down everything
        //else{ PROCS[i]->start(QIODevice::ReadOnly); } //restart the process
        //break;
      }
    }
  }
  //qDebug() << " - Final Count:" << stopped << stopping;
  if(stopping || stopped==PROCS.length()){
    //Note about compton: It does not like running multiple sessions under the *same user*
    // (even on different displays). Run a blanket killall on it when closing down so that
    // any other Lumina sessions will automatically restart compton on that specific display
    QProcess::execute("killall compton");
    QCoreApplication::exit(0);
  }else{
    //Make sure we restart the process as needed
    for(int i=0; i<PROCS.length(); i++){
      if(PROCS[i]->state()==QProcess::NotRunning){
        //runtime/wm processes have special restart rules above
        if(PROCS[i]->objectName()!="runtime" && PROCS[i]->objectName()!="wm"){
          PROCS[i]->start(QIODevice::ReadOnly);
        }
      }
    }
  }
}

void LSession::startProcess(QString ID, QString command, QStringList watchfiles){
  QString dir = QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/logs";
  QString display = QString(getenv("DISPLAY")).section(":",1,1);
  if(!QFile::exists(dir)){ QDir tmp(dir); tmp.mkpath(dir); }
  QString logfile = dir+"/"+ID+"_"+display+".log";
  if(QFile::exists(logfile+".old")){ QFile::remove(logfile+".old"); }
  if(QFile::exists(logfile)){ QFile::rename(logfile,logfile+".old"); }

  LProcess *proc = new LProcess(ID, watchfiles);
  proc->setProcessChannelMode(QProcess::MergedChannels);
  proc->setProcessEnvironment( QProcessEnvironment::systemEnvironment() );
  proc->setStandardOutputFile(logfile);
  proc->setObjectName(ID);
  if(ID=="runtime"){
    //Bypass for a hidden dbus file requirement for Qt itself (Qt 5.5.1+?)
    if(!QFile::exists("/etc/machine-id") && !QFile::exists("/var/db/dbus/machine-id")){
      if(LUtils::isValidBinary("dbus-uuidgen") && LUtils::runCmd("dbus-uuidgen --ensure") ){ } //good - the UUID was created successfully
      else if(LUtils::isValidBinary("dbus-launch")){ command.prepend("dbus-launch --exit-with-session "); }
      else{
        //create a simple DBUS UUID and put it in the universal-fallback location (OS-independent)
        // TO-DO - root vs user level permissions issue?
        qDebug() << "Could not find '/etc/machine-id' or '/var/db/dbus/machine-id': Qt will most likely crash. \nPlease run 'dbus-uuidgen --ensure' with root permissions to generate this file if Lumina does not start properly.";
      }
   }
  }
  proc->start(command, QIODevice::ReadOnly);
  connect(proc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(procFinished()) );
  PROCS << proc;
}

void LSession::setupCompositor(bool force){
  //Compositing manager
  QSettings settings("lumina-desktop","sessionsettings");
  if(settings.value("enableCompositing",false).toBool() || force){
    if(LUtils::isValidBinary("compton")){
      //Compton available - check the config file
      QString set = QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/compton.conf";
      if(!QFile::exists(set)){
	  if(QFile::exists(LOS::LuminaShare()+"/compton.conf")){
	    QFile::copy(LOS::LuminaShare()+"/compton.conf", set);
	  }
      }
	//Auto-detect if GLX is available on the system and turn it on/off as needed
       bool startcompton = true;
       if(LUtils::isValidBinary("glxinfo")){
	 bool hasAccel =! LUtils::getCmdOutput("glxinfo -B").filter("direct rendering:").filter("Yes").isEmpty();
	 qDebug() << "Detected GPU Acceleration:" << hasAccel;
	 QStringList info = LUtils::readFile(set);
	 for(int i=0; i<info.length(); i++){
	   if(info[i].section("=",0,0).simplified()=="backend"){ info[i] = QString("backend = \"")+ (hasAccel ? "glx" : "xrender")+"\""; break; } //replace this line
	 }
	 LUtils::writeFile(set, info, true);
	 if( !hasAccel && settings.value("compositingWithGpuAccelOnly",true).toBool() ){ startcompton = false; }
       }
       QString disp = getenv("DISPLAY");
	if(startcompton || force){ startProcess("compositing","compton --backend xr_glx_hybrid -d "+disp); }
    }else if(LUtils::isValidBinary("xcompmgr") && !settings.value("compositingWithGpuAccelOnly",true).toBool() ){ startProcess("compositing","xcompmgr"); }
  }
}

void LSession::start(bool unified){
  //First check for a valid installation
  if(!LUtils::isValidBinary("lumina-desktop") ){
    exit(1);
  }
  setenv("DESKTOP_SESSION","Lumina",1);
  setenv("XDG_CURRENT_DESKTOP","Lumina",1);
  setenv("QT_QPA_PLATFORMTHEME","lthemeengine", true);
  setenv("QT_NO_GLIB", "1", 1); //Disable the glib event loop within Qt at runtime (performance hit + bugs)
  unsetenv("QT_AUTO_SCREEN_SCALE_FACTOR"); //need exact-pixel measurements (no fake scaling)
  if(LUtils::isValidBinary("xdg-user-dirs-update")){
    //Make sure the XDG user directories are created as needed first
    QProcess::execute("xdg-user-dirs-update");
  }

 if(!unified){
  QSettings sessionsettings("lumina-desktop","sessionsettings");
  QString WM = sessionsettings.value("WindowManager", "fluxbox").toString();
  //Window Manager First
  if(WM=="fluxbox" || WM.endsWith("/fluxbox") || WM.simplified().isEmpty() ){
	  // FLUXBOX BUG BYPASS: if the ~/.fluxbox dir does not exist, it will ignore the given config file
	  if( !LUtils::isValidBinary("fluxbox") ){
	    qDebug() << "[INCOMPLETE LUMINA INSTALLATION] fluxbox binary is missing - cannot continue";
	  }else{
	    QString confDir = QString( getenv("XDG_CONFIG_HOME"))+"/lumina-desktop";
	    if(!QFile::exists(confDir)){ QDir dir(confDir); dir.mkpath(confDir); }
	    if(!QFile::exists(confDir+"/fluxbox-init")){
	      QStringList keys = LUtils::readFile(LOS::LuminaShare()+"/fluxbox-init-rc");
	       keys = keys.replaceInStrings("${XDG_CONFIG_HOME}", QString( getenv("XDG_CONFIG_HOME")));
	       LUtils::writeFile(confDir+"/fluxbox-init", keys, true);
	      QFile::setPermissions(confDir+"/fluxbox-init", QFile::ReadOwner | QFile::WriteOwner | QFile::ReadUser | QFile::ReadOther | QFile::ReadGroup);
	    }
	    if(!QFile::exists(confDir+"/fluxbox-keys")){
	      QStringList keys = LUtils::readFile(LOS::LuminaShare()+"/fluxbox-keys");
	       keys = keys.replaceInStrings("${XDG_CONFIG_HOME}", QString( getenv("XDG_CONFIG_HOME")));
	       LUtils::writeFile(confDir+"/fluxbox-keys", keys, true);
	      QFile::setPermissions(confDir+"/fluxbox-keys", QFile::ReadOwner | QFile::WriteOwner | QFile::ReadUser | QFile::ReadOther | QFile::ReadGroup);
	    }
            if(!QFile::exists(confDir+"/fluxbox-overlay")){
              QStringList contents; contents << "background: unset";
              LUtils::writeFile(confDir+"/fluxbox-overlay", contents, true);
              //Now make sure this overlay file is set within the init file
              contents = LUtils::readFile(confDir+"/fluxbox-init");
              contents << "session.styleOverlay:	"+confDir+"/fluxbox-overlay";
              LUtils::writeFile(confDir+"/fluxbox-init", contents, true);
            }
	    // FLUXBOX BUG BYPASS: if the ~/.fluxbox dir does not exist, it will ignore the given config file
	    if(!QFile::exists(QDir::homePath()+"/.fluxbox")){
	      QDir dir; dir.mkpath(QDir::homePath()+"/.fluxbox");
	    }
	    QString cmd = "fluxbox -rc "+confDir+"/fluxbox-init -no-slit -no-toolbar";
	    startProcess("wm", cmd, QStringList() << confDir+"/fluxbox-init" << confDir+"/fluxbox-keys");
	  }
	  //Compositing manager
	  setupCompositor();
  } else {
	if(!LUtils::isValidBinary(WM)){
	  exit(1);
	}
	startProcess("wm", WM);
  }
  //Desktop Next
  startProcess("runtime","lumina-desktop -new-instance");
  //ScreenSaver
  if(LUtils::isValidBinary("xscreensaver")){ startProcess("screensaver","xscreensaver -no-splash"); }
 }else{
  //unified process
  setupCompositor(true); //required for Lumina 2
  startProcess("runtime","lumina-desktop-unified -new-instance");
 }
}

void LSession::checkFiles(){
//internal version conversion examples:
  //  [1.0.0 -> 1000000], [1.2.3 -> 1002003], [0.6.1 -> 6001]
  qDebug() << "[Lumina] Checking User Files";
  QSettings sset("lumina-desktop", "sessionsettings");
  QString OVS = sset.value("DesktopVersion","0").toString(); //Old Version String
  qDebug() << " - Old Version:" << OVS;
  qDebug() << " - Current Version:" << LDesktopUtils::LuminaDesktopVersion();
  bool changed = LDesktopUtils::checkUserFiles(OVS, LDesktopUtils::LuminaDesktopVersion());
  qDebug() << " - Made Changes:" << changed;
  if(changed){
    //Save the current version of the session to the settings file (for next time)
    sset.setValue("DesktopVersion", LDesktopUtils::LuminaDesktopVersion());
  }
  qDebug() << "Finished with user files check";
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: waitsymbol.cxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: obo $ $Date: 2007-07-17 14:43:26 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_slideshow.hxx"

#include <boost/current_function.hpp>
#include <canvas/canvastools.hxx>

#include <comphelper/anytostring.hxx>
#include <cppuhelper/exc_hlp.hxx>

#include <basegfx/point/b2dpoint.hxx>
#include <basegfx/vector/b2dvector.hxx>

#include "waitsymbol.hxx"
#include "eventmultiplexer.hxx"

#include <algorithm>

using namespace com::sun::star;

namespace slideshow {
namespace internal {

const sal_Int32 LEFT_BORDER_SPACE  = 10;
const sal_Int32 LOWER_BORDER_SPACE = 10;

WaitSymbolSharedPtr WaitSymbol::create( const uno::Reference<rendering::XBitmap>& xBitmap,
                                        ScreenUpdater&                            rScreenUpdater,
                                        EventMultiplexer&                         rEventMultiplexer,
                                        const UnoViewContainer&                   rViewContainer )
{
    WaitSymbolSharedPtr pRet(
        new WaitSymbol( xBitmap,
                        rScreenUpdater,
                        rViewContainer ));

    rEventMultiplexer.addViewHandler( pRet );

    return pRet;
}

WaitSymbol::WaitSymbol( uno::Reference<rendering::XBitmap> const &   xBitmap,
                        ScreenUpdater&                               rScreenUpdater,
                        const UnoViewContainer&                      rViewContainer ) :
    mxBitmap(xBitmap),
    maViews(),
    mrScreenUpdater( rScreenUpdater ),
    mbVisible(false)
{
    std::for_each( rViewContainer.begin(),
                   rViewContainer.end(),
                   boost::bind( &WaitSymbol::viewAdded,
                                this,
                                _1 ));
}

void WaitSymbol::setVisible( const bool bVisible )
{
    if( mbVisible != bVisible )
    {
        mbVisible = bVisible;

        ViewsVecT::const_iterator       aIter( maViews.begin() );
        ViewsVecT::const_iterator const aEnd ( maViews.end() );
        while( aIter != aEnd )
        {
            if( aIter->second )
            {
                if( bVisible )
                    aIter->second->show();
                else
                    aIter->second->hide();
            }

            ++aIter;
        }

        // sprites changed, need a screen update for this frame.
        mrScreenUpdater.requestImmediateUpdate();
    }
}

basegfx::B2DPoint WaitSymbol::calcSpritePos(
    UnoViewSharedPtr const & rView ) const
{
    const uno::Reference<rendering::XBitmap> xBitmap( rView->getCanvas()->getUNOCanvas(),
                                                      uno::UNO_QUERY_THROW );
    const geometry::IntegerSize2D realSize( xBitmap->getSize() );
    return basegfx::B2DPoint(
        std::min<sal_Int32>( realSize.Width, LEFT_BORDER_SPACE ),
        std::max<sal_Int32>( 0, realSize.Height - mxBitmap->getSize().Height
                                                - LOWER_BORDER_SPACE ) );
}

void WaitSymbol::viewAdded( const UnoViewSharedPtr& rView )
{
    cppcanvas::CustomSpriteSharedPtr sprite;

    try
    {
        const geometry::IntegerSize2D spriteSize( mxBitmap->getSize() );
        sprite = rView->createSprite( basegfx::B2DVector( spriteSize.Width,
                                                          spriteSize.Height ),
                                      1000.0 ); // sprite should be in front of all
                                                // other sprites
        rendering::ViewState viewState;
        canvas::tools::initViewState( viewState );
        rendering::RenderState renderState;
        canvas::tools::initRenderState( renderState );
        sprite->getContentCanvas()->getUNOCanvas()->drawBitmap(
            mxBitmap, viewState, renderState );

        sprite->setAlpha( 0.9 );
        sprite->movePixel( calcSpritePos( rView ) );
        if( mbVisible )
            sprite->show();
    }
    catch( uno::Exception& )
    {
        OSL_ENSURE( false,
                    rtl::OUStringToOString(
                        comphelper::anyToString( cppu::getCaughtException() ),
                        RTL_TEXTENCODING_UTF8 ).getStr() );
    }

    maViews.push_back( ViewsVecT::value_type( rView, sprite ) );
}

void WaitSymbol::viewRemoved( const UnoViewSharedPtr& rView )
{
    maViews.erase(
        std::remove_if(
            maViews.begin(), maViews.end(),
            boost::bind(
                std::equal_to<UnoViewSharedPtr>(),
                rView,
                // select view:
                boost::bind( std::select1st<ViewsVecT::value_type>(), _1 ) ) ),
        maViews.end() );
}

void WaitSymbol::viewChanged( const UnoViewSharedPtr& rView )
{
    // find entry corresponding to modified view
    ViewsVecT::iterator aModifiedEntry(
        std::find_if(
            maViews.begin(),
            maViews.end(),
            boost::bind(
                std::equal_to<UnoViewSharedPtr>(),
                rView,
                // select view:
                boost::bind( std::select1st<ViewsVecT::value_type>(), _1 ))));

    OSL_ASSERT( aModifiedEntry != maViews.end() );
    if( aModifiedEntry == maViews.end() )
        return;

    if( aModifiedEntry->second )
        aModifiedEntry->second->movePixel(
            calcSpritePos(aModifiedEntry->first) );
}

void WaitSymbol::viewsChanged()
{
    // reposition sprites on all views
    ViewsVecT::const_iterator       aIter( maViews.begin() );
    ViewsVecT::const_iterator const aEnd ( maViews.end() );
    while( aIter != aEnd )
    {
        if( aIter->second )
            aIter->second->movePixel(
                calcSpritePos( aIter->first ));
        ++aIter;
    }
}

} // namespace internal
} // namespace presentation
<commit_msg>INTEGRATION: CWS changefileheader (1.10.46); FILE MERGED 2008/03/31 14:00:15 rt 1.10.46.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: waitsymbol.cxx,v $
 * $Revision: 1.11 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_slideshow.hxx"

#include <boost/current_function.hpp>
#include <canvas/canvastools.hxx>

#include <comphelper/anytostring.hxx>
#include <cppuhelper/exc_hlp.hxx>

#include <basegfx/point/b2dpoint.hxx>
#include <basegfx/vector/b2dvector.hxx>

#include "waitsymbol.hxx"
#include "eventmultiplexer.hxx"

#include <algorithm>

using namespace com::sun::star;

namespace slideshow {
namespace internal {

const sal_Int32 LEFT_BORDER_SPACE  = 10;
const sal_Int32 LOWER_BORDER_SPACE = 10;

WaitSymbolSharedPtr WaitSymbol::create( const uno::Reference<rendering::XBitmap>& xBitmap,
                                        ScreenUpdater&                            rScreenUpdater,
                                        EventMultiplexer&                         rEventMultiplexer,
                                        const UnoViewContainer&                   rViewContainer )
{
    WaitSymbolSharedPtr pRet(
        new WaitSymbol( xBitmap,
                        rScreenUpdater,
                        rViewContainer ));

    rEventMultiplexer.addViewHandler( pRet );

    return pRet;
}

WaitSymbol::WaitSymbol( uno::Reference<rendering::XBitmap> const &   xBitmap,
                        ScreenUpdater&                               rScreenUpdater,
                        const UnoViewContainer&                      rViewContainer ) :
    mxBitmap(xBitmap),
    maViews(),
    mrScreenUpdater( rScreenUpdater ),
    mbVisible(false)
{
    std::for_each( rViewContainer.begin(),
                   rViewContainer.end(),
                   boost::bind( &WaitSymbol::viewAdded,
                                this,
                                _1 ));
}

void WaitSymbol::setVisible( const bool bVisible )
{
    if( mbVisible != bVisible )
    {
        mbVisible = bVisible;

        ViewsVecT::const_iterator       aIter( maViews.begin() );
        ViewsVecT::const_iterator const aEnd ( maViews.end() );
        while( aIter != aEnd )
        {
            if( aIter->second )
            {
                if( bVisible )
                    aIter->second->show();
                else
                    aIter->second->hide();
            }

            ++aIter;
        }

        // sprites changed, need a screen update for this frame.
        mrScreenUpdater.requestImmediateUpdate();
    }
}

basegfx::B2DPoint WaitSymbol::calcSpritePos(
    UnoViewSharedPtr const & rView ) const
{
    const uno::Reference<rendering::XBitmap> xBitmap( rView->getCanvas()->getUNOCanvas(),
                                                      uno::UNO_QUERY_THROW );
    const geometry::IntegerSize2D realSize( xBitmap->getSize() );
    return basegfx::B2DPoint(
        std::min<sal_Int32>( realSize.Width, LEFT_BORDER_SPACE ),
        std::max<sal_Int32>( 0, realSize.Height - mxBitmap->getSize().Height
                                                - LOWER_BORDER_SPACE ) );
}

void WaitSymbol::viewAdded( const UnoViewSharedPtr& rView )
{
    cppcanvas::CustomSpriteSharedPtr sprite;

    try
    {
        const geometry::IntegerSize2D spriteSize( mxBitmap->getSize() );
        sprite = rView->createSprite( basegfx::B2DVector( spriteSize.Width,
                                                          spriteSize.Height ),
                                      1000.0 ); // sprite should be in front of all
                                                // other sprites
        rendering::ViewState viewState;
        canvas::tools::initViewState( viewState );
        rendering::RenderState renderState;
        canvas::tools::initRenderState( renderState );
        sprite->getContentCanvas()->getUNOCanvas()->drawBitmap(
            mxBitmap, viewState, renderState );

        sprite->setAlpha( 0.9 );
        sprite->movePixel( calcSpritePos( rView ) );
        if( mbVisible )
            sprite->show();
    }
    catch( uno::Exception& )
    {
        OSL_ENSURE( false,
                    rtl::OUStringToOString(
                        comphelper::anyToString( cppu::getCaughtException() ),
                        RTL_TEXTENCODING_UTF8 ).getStr() );
    }

    maViews.push_back( ViewsVecT::value_type( rView, sprite ) );
}

void WaitSymbol::viewRemoved( const UnoViewSharedPtr& rView )
{
    maViews.erase(
        std::remove_if(
            maViews.begin(), maViews.end(),
            boost::bind(
                std::equal_to<UnoViewSharedPtr>(),
                rView,
                // select view:
                boost::bind( std::select1st<ViewsVecT::value_type>(), _1 ) ) ),
        maViews.end() );
}

void WaitSymbol::viewChanged( const UnoViewSharedPtr& rView )
{
    // find entry corresponding to modified view
    ViewsVecT::iterator aModifiedEntry(
        std::find_if(
            maViews.begin(),
            maViews.end(),
            boost::bind(
                std::equal_to<UnoViewSharedPtr>(),
                rView,
                // select view:
                boost::bind( std::select1st<ViewsVecT::value_type>(), _1 ))));

    OSL_ASSERT( aModifiedEntry != maViews.end() );
    if( aModifiedEntry == maViews.end() )
        return;

    if( aModifiedEntry->second )
        aModifiedEntry->second->movePixel(
            calcSpritePos(aModifiedEntry->first) );
}

void WaitSymbol::viewsChanged()
{
    // reposition sprites on all views
    ViewsVecT::const_iterator       aIter( maViews.begin() );
    ViewsVecT::const_iterator const aEnd ( maViews.end() );
    while( aIter != aEnd )
    {
        if( aIter->second )
            aIter->second->movePixel(
                calcSpritePos( aIter->first ));
        ++aIter;
    }
}

} // namespace internal
} // namespace presentation
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "views/controls/tabbed_pane/native_tabbed_pane_win.h"

#include <vssym32.h>

#include "app/l10n_util_win.h"
#include "app/resource_bundle.h"
#include "base/logging.h"
#include "base/stl_util-inl.h"
#include "gfx/canvas.h"
#include "gfx/font.h"
#include "gfx/native_theme_win.h"
#include "views/controls/tabbed_pane/tabbed_pane.h"
#include "views/fill_layout.h"
#include "views/widget/root_view.h"
#include "views/widget/widget_win.h"

namespace views {

// A background object that paints the tab panel background which may be
// rendered by the system visual styles system.
class TabBackground : public Background {
 public:
  explicit TabBackground() {
    // TMT_FILLCOLORHINT returns a color value that supposedly
    // approximates the texture drawn by PaintTabPanelBackground.
    SkColor tab_page_color =
        gfx::NativeTheme::instance()->GetThemeColorWithDefault(
            gfx::NativeTheme::TAB, TABP_BODY, 0, TMT_FILLCOLORHINT,
            COLOR_3DFACE);
    SetNativeControlColor(tab_page_color);
  }
  virtual ~TabBackground() {}

  virtual void Paint(gfx::Canvas* canvas, View* view) const {
    HDC dc = canvas->beginPlatformPaint();
    RECT r = {0, 0, view->width(), view->height()};
    gfx::NativeTheme::instance()->PaintTabPanelBackground(dc, &r);
    canvas->endPlatformPaint();
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(TabBackground);
};

////////////////////////////////////////////////////////////////////////////////
// NativeTabbedPaneWin, public:

NativeTabbedPaneWin::NativeTabbedPaneWin(TabbedPane* tabbed_pane)
    : NativeControlWin(),
      tabbed_pane_(tabbed_pane),
      content_window_(NULL),
      selected_index_(-1) {
  // Associates the actual HWND with the tabbed-pane so the tabbed-pane is
  // the one considered as having the focus (not the wrapper) when the HWND is
  // focused directly (with a click for example).
  set_focus_view(tabbed_pane);
}

NativeTabbedPaneWin::~NativeTabbedPaneWin() {
  // We own the tab views, let's delete them.
  STLDeleteContainerPointers(tab_views_.begin(), tab_views_.end());
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabbedPaneWin, NativeTabbedPaneWrapper implementation:

void NativeTabbedPaneWin::AddTab(const std::wstring& title, View* contents) {
  AddTabAtIndex(static_cast<int>(tab_views_.size()), title, contents, true);
}

void NativeTabbedPaneWin::AddTabAtIndex(int index, const std::wstring& title,
                                        View* contents,
                                        bool select_if_first_tab) {
  DCHECK(index <= static_cast<int>(tab_views_.size()));
  contents->set_parent_owned(false);
  tab_views_.insert(tab_views_.begin() + index, contents);
  tab_titles_.insert(tab_titles_.begin() + index, title);

  if (!contents->background())
    contents->set_background(new TabBackground);

  if (tab_views_.size() == 1 && select_if_first_tab) {
    // If this is the only tab displayed, make sure the contents is set.
    selected_index_ = 0;
    if (content_window_)
      content_window_->GetRootView()->AddChildView(contents);
  }

  // Add native tab only if the native control is alreay created.
  if (content_window_) {
    AddNativeTab(index, title, contents);

    // The newly added tab may have made the contents window smaller.
    ResizeContents();
  }
}

void NativeTabbedPaneWin::AddNativeTab(int index,
                                       const std::wstring &title,
                                       views::View* contents) {
  TCITEM tcitem;
  tcitem.mask = TCIF_TEXT;

  // If the locale is RTL, we set the TCIF_RTLREADING so that BiDi text is
  // rendered properly on the tabs.
  if (UILayoutIsRightToLeft()) {
    tcitem.mask |= TCIF_RTLREADING;
  }

  tcitem.pszText = const_cast<wchar_t*>(title.c_str());
  int result = TabCtrl_InsertItem(native_view(), index, &tcitem);
  DCHECK(result != -1);
}

View* NativeTabbedPaneWin::RemoveTabAtIndex(int index) {
  int tab_count = static_cast<int>(tab_views_.size());
  DCHECK(index >= 0 && index < tab_count);

  if (index < (tab_count - 1)) {
    // Select the next tab.
    SelectTabAt(index + 1);
  } else {
    // We are the last tab, select the previous one.
    if (index > 0) {
      SelectTabAt(index - 1);
    } else if (content_window_) {
      // That was the last tab. Remove the contents.
      content_window_->GetRootView()->RemoveAllChildViews(false);
    }
  }
  TabCtrl_DeleteItem(native_view(), index);

  // The removed tab may have made the contents window bigger.
  if (content_window_)
    ResizeContents();

  std::vector<View*>::iterator iter = tab_views_.begin() + index;
  View* removed_tab = *iter;
  tab_views_.erase(iter);
  tab_titles_.erase(tab_titles_.begin() + index);

  return removed_tab;
}

void NativeTabbedPaneWin::SelectTabAt(int index) {
  DCHECK((index >= 0) && (index < static_cast<int>(tab_views_.size())));
  if (native_view())
    TabCtrl_SetCurSel(native_view(), index);
  DoSelectTabAt(index, true);
}

int NativeTabbedPaneWin::GetTabCount() {
  return TabCtrl_GetItemCount(native_view());
}

int NativeTabbedPaneWin::GetSelectedTabIndex() {
  return TabCtrl_GetCurSel(native_view());
}

View* NativeTabbedPaneWin::GetSelectedTab() {
  if (selected_index_ < 0)
    return NULL;
  return tab_views_[selected_index_];
}

View* NativeTabbedPaneWin::GetView() {
  return this;
}

void NativeTabbedPaneWin::SetFocus() {
  // Focus the associated HWND.
  Focus();
}

gfx::NativeView NativeTabbedPaneWin::GetTestingHandle() const {
  return native_view();
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabbedPaneWin, NativeControlWin override:

void NativeTabbedPaneWin::CreateNativeControl() {
  // Create the tab control.
  //
  // Note that we don't follow the common convention for NativeControl
  // subclasses and we don't pass the value returned from
  // NativeControl::GetAdditionalExStyle() as the dwExStyle parameter. Here is
  // why: on RTL locales, if we pass NativeControl::GetAdditionalExStyle() when
  // we basically tell Windows to create our HWND with the WS_EX_LAYOUTRTL. If
  // we do that, then the HWND we create for |content_window_| below will
  // inherit the WS_EX_LAYOUTRTL property and this will result in the contents
  // being flipped, which is not what we want (because we handle mirroring in
  // views without the use of Windows' support for mirroring). Therefore,
  // we initially create our HWND without the aforementioned property and we
  // explicitly set this property our child is created. This way, on RTL
  // locales, our tabs will be nicely rendered from right to left (by virtue of
  // Windows doing the right thing with the TabbedPane HWND) and each tab
  // contents will use an RTL layout correctly (by virtue of the mirroring
  // infrastructure in views doing the right thing with each View we put
  // in the tab).
  HWND tab_control = ::CreateWindowEx(0,
                                      WC_TABCONTROL,
                                      L"",
                                      WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,
                                      0, 0, width(), height(),
                                      GetWidget()->GetNativeView(), NULL, NULL,
                                      NULL);

  HFONT font = ResourceBundle::GetSharedInstance().
      GetFont(ResourceBundle::BaseFont).hfont();
  SendMessage(tab_control, WM_SETFONT, reinterpret_cast<WPARAM>(font), FALSE);

  // Create the view container which is a child of the TabControl.
  content_window_ = new WidgetWin();
  content_window_->Init(tab_control, gfx::Rect());

  // Explicitly setting the WS_EX_LAYOUTRTL property for the HWND (see above
  // for a thorough explanation regarding why we waited until |content_window_|
  // if created before we set this property for the tabbed pane's HWND).
  if (UILayoutIsRightToLeft())
    l10n_util::HWNDSetRTLLayout(tab_control);

  RootView* root_view = content_window_->GetRootView();
  root_view->SetLayoutManager(new FillLayout());
  DWORD sys_color = ::GetSysColor(COLOR_3DHILIGHT);
  SkColor color = SkColorSetRGB(GetRValue(sys_color), GetGValue(sys_color),
                                GetBValue(sys_color));
  root_view->set_background(Background::CreateSolidBackground(color));

  content_window_->SetFocusTraversableParentView(this);

  NativeControlCreated(tab_control);

  // Add tabs that are already added if any.
  if (tab_views_.size() > 0) {
    InitializeTabs();
    if (selected_index_ >= 0)
      DoSelectTabAt(selected_index_, false);
  }

  ResizeContents();
}

bool NativeTabbedPaneWin::ProcessMessage(UINT message,
                                         WPARAM w_param,
                                         LPARAM l_param,
                                         LRESULT* result) {
  if (message == WM_NOTIFY &&
      reinterpret_cast<LPNMHDR>(l_param)->code == TCN_SELCHANGE) {
    int selected_tab = TabCtrl_GetCurSel(native_view());
    DCHECK(selected_tab != -1);
    DoSelectTabAt(selected_tab, true);
    return TRUE;
  }
  return NativeControlWin::ProcessMessage(message, w_param, l_param, result);
}

////////////////////////////////////////////////////////////////////////////////
// View override:

void NativeTabbedPaneWin::Layout() {
  NativeControlWin::Layout();
  ResizeContents();
}

FocusTraversable* NativeTabbedPaneWin::GetFocusTraversable() {
  return content_window_;
}

void NativeTabbedPaneWin::ViewHierarchyChanged(bool is_add,
                                               View *parent,
                                               View *child) {
  NativeControlWin::ViewHierarchyChanged(is_add, parent, child);

  if (is_add && (child == this) && content_window_) {
    // We have been added to a view hierarchy, update the FocusTraversable
    // parent.
    content_window_->SetFocusTraversableParent(GetRootView());
  }
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabbedPaneWin, private:

void NativeTabbedPaneWin::InitializeTabs() {
  for (size_t i = 0; i < tab_views_.size(); ++i) {
    AddNativeTab(i, tab_titles_[i], tab_views_[i]);
  }
}

void NativeTabbedPaneWin::DoSelectTabAt(int index, boolean invoke_listener) {
  selected_index_ = index;
  if (content_window_) {
    RootView* content_root = content_window_->GetRootView();

    // Clear the focus if the focused view was on the tab.
    FocusManager* focus_manager = GetFocusManager();
    DCHECK(focus_manager);
    View* focused_view = focus_manager->GetFocusedView();
    if (focused_view && content_root->IsParentOf(focused_view))
      focus_manager->ClearFocus();

    content_root->RemoveAllChildViews(false);
    content_root->AddChildView(tab_views_[index]);
    content_root->Layout();
  }
  if (invoke_listener && tabbed_pane_->listener())
    tabbed_pane_->listener()->TabSelectedAt(index);
}

void NativeTabbedPaneWin::ResizeContents() {
  CRect content_bounds;
  if (!GetClientRect(native_view(), &content_bounds))
    return;
  TabCtrl_AdjustRect(native_view(), FALSE, &content_bounds);
  content_window_->MoveWindow(content_bounds.left, content_bounds.top,
                              content_bounds.Width(), content_bounds.Height(),
                              TRUE);
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabbedPaneWrapper, public:

// static
NativeTabbedPaneWrapper* NativeTabbedPaneWrapper::CreateNativeWrapper(
    TabbedPane* tabbed_pane) {
  return new NativeTabbedPaneWin(tabbed_pane);
}

}  // namespace views
<commit_msg>Add style to clip children which reduces flashing when the tab control is resized. The tab control still flashes a little bit but it is only the outer area and not the large content area/child controls. Fixing that probably requires drawing the tab control on our own which is perhaps overkill. BUG=28383 TEST=follow steps given in the bug and resize password manager window, tab should not flicker as much as it did earlier. <commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "views/controls/tabbed_pane/native_tabbed_pane_win.h"

#include <vssym32.h>

#include "app/l10n_util_win.h"
#include "app/resource_bundle.h"
#include "base/logging.h"
#include "base/stl_util-inl.h"
#include "gfx/canvas.h"
#include "gfx/font.h"
#include "gfx/native_theme_win.h"
#include "views/controls/tabbed_pane/tabbed_pane.h"
#include "views/fill_layout.h"
#include "views/widget/root_view.h"
#include "views/widget/widget_win.h"

namespace views {

// A background object that paints the tab panel background which may be
// rendered by the system visual styles system.
class TabBackground : public Background {
 public:
  explicit TabBackground() {
    // TMT_FILLCOLORHINT returns a color value that supposedly
    // approximates the texture drawn by PaintTabPanelBackground.
    SkColor tab_page_color =
        gfx::NativeTheme::instance()->GetThemeColorWithDefault(
            gfx::NativeTheme::TAB, TABP_BODY, 0, TMT_FILLCOLORHINT,
            COLOR_3DFACE);
    SetNativeControlColor(tab_page_color);
  }
  virtual ~TabBackground() {}

  virtual void Paint(gfx::Canvas* canvas, View* view) const {
    HDC dc = canvas->beginPlatformPaint();
    RECT r = {0, 0, view->width(), view->height()};
    gfx::NativeTheme::instance()->PaintTabPanelBackground(dc, &r);
    canvas->endPlatformPaint();
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(TabBackground);
};

////////////////////////////////////////////////////////////////////////////////
// NativeTabbedPaneWin, public:

NativeTabbedPaneWin::NativeTabbedPaneWin(TabbedPane* tabbed_pane)
    : NativeControlWin(),
      tabbed_pane_(tabbed_pane),
      content_window_(NULL),
      selected_index_(-1) {
  // Associates the actual HWND with the tabbed-pane so the tabbed-pane is
  // the one considered as having the focus (not the wrapper) when the HWND is
  // focused directly (with a click for example).
  set_focus_view(tabbed_pane);
}

NativeTabbedPaneWin::~NativeTabbedPaneWin() {
  // We own the tab views, let's delete them.
  STLDeleteContainerPointers(tab_views_.begin(), tab_views_.end());
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabbedPaneWin, NativeTabbedPaneWrapper implementation:

void NativeTabbedPaneWin::AddTab(const std::wstring& title, View* contents) {
  AddTabAtIndex(static_cast<int>(tab_views_.size()), title, contents, true);
}

void NativeTabbedPaneWin::AddTabAtIndex(int index, const std::wstring& title,
                                        View* contents,
                                        bool select_if_first_tab) {
  DCHECK(index <= static_cast<int>(tab_views_.size()));
  contents->set_parent_owned(false);
  tab_views_.insert(tab_views_.begin() + index, contents);
  tab_titles_.insert(tab_titles_.begin() + index, title);

  if (!contents->background())
    contents->set_background(new TabBackground);

  if (tab_views_.size() == 1 && select_if_first_tab) {
    // If this is the only tab displayed, make sure the contents is set.
    selected_index_ = 0;
    if (content_window_)
      content_window_->GetRootView()->AddChildView(contents);
  }

  // Add native tab only if the native control is alreay created.
  if (content_window_) {
    AddNativeTab(index, title, contents);

    // The newly added tab may have made the contents window smaller.
    ResizeContents();
  }
}

void NativeTabbedPaneWin::AddNativeTab(int index,
                                       const std::wstring &title,
                                       views::View* contents) {
  TCITEM tcitem;
  tcitem.mask = TCIF_TEXT;

  // If the locale is RTL, we set the TCIF_RTLREADING so that BiDi text is
  // rendered properly on the tabs.
  if (UILayoutIsRightToLeft()) {
    tcitem.mask |= TCIF_RTLREADING;
  }

  tcitem.pszText = const_cast<wchar_t*>(title.c_str());
  int result = TabCtrl_InsertItem(native_view(), index, &tcitem);
  DCHECK(result != -1);
}

View* NativeTabbedPaneWin::RemoveTabAtIndex(int index) {
  int tab_count = static_cast<int>(tab_views_.size());
  DCHECK(index >= 0 && index < tab_count);

  if (index < (tab_count - 1)) {
    // Select the next tab.
    SelectTabAt(index + 1);
  } else {
    // We are the last tab, select the previous one.
    if (index > 0) {
      SelectTabAt(index - 1);
    } else if (content_window_) {
      // That was the last tab. Remove the contents.
      content_window_->GetRootView()->RemoveAllChildViews(false);
    }
  }
  TabCtrl_DeleteItem(native_view(), index);

  // The removed tab may have made the contents window bigger.
  if (content_window_)
    ResizeContents();

  std::vector<View*>::iterator iter = tab_views_.begin() + index;
  View* removed_tab = *iter;
  tab_views_.erase(iter);
  tab_titles_.erase(tab_titles_.begin() + index);

  return removed_tab;
}

void NativeTabbedPaneWin::SelectTabAt(int index) {
  DCHECK((index >= 0) && (index < static_cast<int>(tab_views_.size())));
  if (native_view())
    TabCtrl_SetCurSel(native_view(), index);
  DoSelectTabAt(index, true);
}

int NativeTabbedPaneWin::GetTabCount() {
  return TabCtrl_GetItemCount(native_view());
}

int NativeTabbedPaneWin::GetSelectedTabIndex() {
  return TabCtrl_GetCurSel(native_view());
}

View* NativeTabbedPaneWin::GetSelectedTab() {
  if (selected_index_ < 0)
    return NULL;
  return tab_views_[selected_index_];
}

View* NativeTabbedPaneWin::GetView() {
  return this;
}

void NativeTabbedPaneWin::SetFocus() {
  // Focus the associated HWND.
  Focus();
}

gfx::NativeView NativeTabbedPaneWin::GetTestingHandle() const {
  return native_view();
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabbedPaneWin, NativeControlWin override:

void NativeTabbedPaneWin::CreateNativeControl() {
  // Create the tab control.
  //
  // Note that we don't follow the common convention for NativeControl
  // subclasses and we don't pass the value returned from
  // NativeControl::GetAdditionalExStyle() as the dwExStyle parameter. Here is
  // why: on RTL locales, if we pass NativeControl::GetAdditionalExStyle() when
  // we basically tell Windows to create our HWND with the WS_EX_LAYOUTRTL. If
  // we do that, then the HWND we create for |content_window_| below will
  // inherit the WS_EX_LAYOUTRTL property and this will result in the contents
  // being flipped, which is not what we want (because we handle mirroring in
  // views without the use of Windows' support for mirroring). Therefore,
  // we initially create our HWND without the aforementioned property and we
  // explicitly set this property our child is created. This way, on RTL
  // locales, our tabs will be nicely rendered from right to left (by virtue of
  // Windows doing the right thing with the TabbedPane HWND) and each tab
  // contents will use an RTL layout correctly (by virtue of the mirroring
  // infrastructure in views doing the right thing with each View we put
  // in the tab).
  DWORD style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | WS_CLIPCHILDREN;
  HWND tab_control = ::CreateWindowEx(0,
                                      WC_TABCONTROL,
                                      L"",
                                      style,
                                      0, 0, width(), height(),
                                      GetWidget()->GetNativeView(), NULL, NULL,
                                      NULL);

  HFONT font = ResourceBundle::GetSharedInstance().
      GetFont(ResourceBundle::BaseFont).hfont();
  SendMessage(tab_control, WM_SETFONT, reinterpret_cast<WPARAM>(font), FALSE);

  // Create the view container which is a child of the TabControl.
  content_window_ = new WidgetWin();
  content_window_->Init(tab_control, gfx::Rect());

  // Explicitly setting the WS_EX_LAYOUTRTL property for the HWND (see above
  // for a thorough explanation regarding why we waited until |content_window_|
  // if created before we set this property for the tabbed pane's HWND).
  if (UILayoutIsRightToLeft())
    l10n_util::HWNDSetRTLLayout(tab_control);

  RootView* root_view = content_window_->GetRootView();
  root_view->SetLayoutManager(new FillLayout());
  DWORD sys_color = ::GetSysColor(COLOR_3DHILIGHT);
  SkColor color = SkColorSetRGB(GetRValue(sys_color), GetGValue(sys_color),
                                GetBValue(sys_color));
  root_view->set_background(Background::CreateSolidBackground(color));

  content_window_->SetFocusTraversableParentView(this);

  NativeControlCreated(tab_control);

  // Add tabs that are already added if any.
  if (tab_views_.size() > 0) {
    InitializeTabs();
    if (selected_index_ >= 0)
      DoSelectTabAt(selected_index_, false);
  }

  ResizeContents();
}

bool NativeTabbedPaneWin::ProcessMessage(UINT message,
                                         WPARAM w_param,
                                         LPARAM l_param,
                                         LRESULT* result) {
  if (message == WM_NOTIFY &&
      reinterpret_cast<LPNMHDR>(l_param)->code == TCN_SELCHANGE) {
    int selected_tab = TabCtrl_GetCurSel(native_view());
    DCHECK(selected_tab != -1);
    DoSelectTabAt(selected_tab, true);
    return TRUE;
  }
  return NativeControlWin::ProcessMessage(message, w_param, l_param, result);
}

////////////////////////////////////////////////////////////////////////////////
// View override:

void NativeTabbedPaneWin::Layout() {
  NativeControlWin::Layout();
  ResizeContents();
}

FocusTraversable* NativeTabbedPaneWin::GetFocusTraversable() {
  return content_window_;
}

void NativeTabbedPaneWin::ViewHierarchyChanged(bool is_add,
                                               View *parent,
                                               View *child) {
  NativeControlWin::ViewHierarchyChanged(is_add, parent, child);

  if (is_add && (child == this) && content_window_) {
    // We have been added to a view hierarchy, update the FocusTraversable
    // parent.
    content_window_->SetFocusTraversableParent(GetRootView());
  }
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabbedPaneWin, private:

void NativeTabbedPaneWin::InitializeTabs() {
  for (size_t i = 0; i < tab_views_.size(); ++i) {
    AddNativeTab(i, tab_titles_[i], tab_views_[i]);
  }
}

void NativeTabbedPaneWin::DoSelectTabAt(int index, boolean invoke_listener) {
  selected_index_ = index;
  if (content_window_) {
    RootView* content_root = content_window_->GetRootView();

    // Clear the focus if the focused view was on the tab.
    FocusManager* focus_manager = GetFocusManager();
    DCHECK(focus_manager);
    View* focused_view = focus_manager->GetFocusedView();
    if (focused_view && content_root->IsParentOf(focused_view))
      focus_manager->ClearFocus();

    content_root->RemoveAllChildViews(false);
    content_root->AddChildView(tab_views_[index]);
    content_root->Layout();
  }
  if (invoke_listener && tabbed_pane_->listener())
    tabbed_pane_->listener()->TabSelectedAt(index);
}

void NativeTabbedPaneWin::ResizeContents() {
  CRect content_bounds;
  if (!GetClientRect(native_view(), &content_bounds))
    return;
  TabCtrl_AdjustRect(native_view(), FALSE, &content_bounds);
  content_window_->MoveWindow(content_bounds.left, content_bounds.top,
                              content_bounds.Width(), content_bounds.Height(),
                              TRUE);
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabbedPaneWrapper, public:

// static
NativeTabbedPaneWrapper* NativeTabbedPaneWrapper::CreateNativeWrapper(
    TabbedPane* tabbed_pane) {
  return new NativeTabbedPaneWin(tabbed_pane);
}

}  // namespace views
<|endoftext|>