<commit_before>/*
 * This file is part of telepathy-accounts-kcm
 *
 * Copyright (C) 2009 Collabora Ltd. <http://www.collabora.co.uk/>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "accounts-list-model.h"

#include "account-item.h"

#include <KDebug>
#include <KIcon>

#include <TelepathyQt4/Account>

AccountsListModel::AccountsListModel(QObject *parent)
 : QAbstractListModel(parent)
{
    kDebug();

    m_accounts.clear();
}

AccountsListModel::~AccountsListModel()
{
    kDebug();

    // TODO: Implement me!
}

int AccountsListModel::rowCount(const QModelIndex &index) const
{
    // If the index is the root item, then return the row count.
    if (index == QModelIndex()) {
       return m_accounts.size();
    }

    // Otherwise, return 0 (as this is a list model, so all items
    // are children of the root item).
    return 0;
}

QVariant AccountsListModel::data(const QModelIndex &index, int role) const
{
    QVariant data;
    Tp::AccountPtr account = m_accounts.at(index.row())->account();

    switch(role)
    {
    case Qt::DisplayRole:
        data = QVariant(account->displayName());
        break;

    case Qt::DecorationRole:
        data = QVariant(m_accounts.at(index.row())->icon());
        break;

    case Qt::CheckStateRole:
        if(account->isEnabled()) {
            data = QVariant(Qt::Checked);
        }
        else {
            data = QVariant(Qt::Unchecked);
        }
        break;

    case AccountsListModel::ConnectionStateDisplayRole:
        data = QVariant(m_accounts.at(index.row())->connectionStateString());
        break;

    case AccountsListModel::ConnectionStateIconRole:
        data = QVariant(m_accounts.at(index.row())->connectionStateIcon());
        break;

    case AccountsListModel::ConnectionErrorMessageDisplayRole:
        data = QVariant(m_accounts.at(index.row())->connectionStatusReason());
        break;
    default:
        break;
    }

    return data;
}

bool AccountsListModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    kDebug();
    if(role == Qt::CheckStateRole) {
        m_accounts.at(index.row())->account()->setEnabled(value.toInt() == Qt::Checked);
        return true;
    }
    return false;
}

Qt::ItemFlags AccountsListModel::flags(const QModelIndex &index) const
{
    return QAbstractItemModel::flags(index) | Qt::ItemIsUserCheckable;
}

void AccountsListModel::addAccount(const Tp::AccountPtr &account)
{
    kDebug() << "Creating a new AccountItem from account:" << account.data();

    // Check if the account is already in the model.
    bool found = false;

    if (!found) {
        foreach (const AccountItem* ai, m_accounts) {
            if (ai->account() == account) {
                found = true;
                break;
            }
        }
    }

    if (found) {
       kWarning() << "Requested to add account"
                  << account.data()
                  << "to model, but it is already present. Doing nothing.";
   } else {
       kDebug() << "Account not already in model. Create new AccountItem from account:"
                << account.data();

       AccountItem *item = new AccountItem(account, this);

       beginInsertRows(QModelIndex(), m_accounts.size(), m_accounts.size());
       m_accounts.append(item);
       endInsertRows();

       connect(item, SIGNAL(removed()), SLOT(onAccountItemRemoved()));
       connect(item, SIGNAL(updated()), SLOT(onAccountItemUpdated()));
   }
}

void AccountsListModel::removeAccount(const QModelIndex &index)
{
    kDebug();

    if(!index.isValid()) {
        kDebug() << "Can't remove Account: Invalid index";
        return;
    }
    AccountItem *accountItem = m_accounts.at(index.row());

    Q_ASSERT(accountItem);

    accountItem->remove();
}

AccountItem* AccountsListModel::itemForIndex(const QModelIndex &index)
{
    kDebug();

    if(!index.isValid()) {
        kWarning() << "Invalid index" << index;
        return 0;
    }

    AccountItem *accountItem = m_accounts.at(index.row());
    return accountItem;
}

void AccountsListModel::onAccountItemRemoved()
{
    kDebug();

    AccountItem *item = qobject_cast<AccountItem*>(sender());

    Q_ASSERT(item);
    if (!item) {
        kWarning() << "Not an AccountItem pointer:" << sender();
        return;
    }

    beginRemoveRows(QModelIndex(), m_accounts.lastIndexOf(item),
                    m_accounts.lastIndexOf(item));
    m_accounts.removeAll(item);
    endRemoveRows();

    Q_ASSERT(!m_accounts.contains(item));
    if (m_accounts.contains(item)) {
        kWarning() << "Ready Accounts still contains Accout Item:" << item;
    }
}

void AccountsListModel::onAccountItemUpdated()
{
    kDebug();

    AccountItem *item = qobject_cast<AccountItem*>(sender());

    Q_ASSERT(item);
    if (!item) {
        kWarning() << "Not an AccountItem pointer:" << sender();
        return;
    }

    QModelIndex index = createIndex(m_accounts.lastIndexOf(item), 0);
    emit dataChanged(index, index);
}

void AccountsListModel::onTitleForCustomPages(QString mandatoryPage, QList<QString> optionalPage)
{
	kDebug();

	emit setTitleForCustomPages(mandatoryPage, optionalPage);
}

#include "accounts-list-model.moc"

<commit_msg>Fix some deletes Fix some TODOs that were not needed<commit_after>/*
 * This file is part of telepathy-accounts-kcm
 *
 * Copyright (C) 2009 Collabora Ltd. <http://www.collabora.co.uk/>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "accounts-list-model.h"

#include "account-item.h"

#include <KDebug>
#include <KIcon>

#include <TelepathyQt4/Account>

AccountsListModel::AccountsListModel(QObject *parent)
 : QAbstractListModel(parent)
{
    kDebug();

    m_accounts.clear();
}

AccountsListModel::~AccountsListModel()
{
    kDebug();
}

int AccountsListModel::rowCount(const QModelIndex &index) const
{
    // If the index is the root item, then return the row count.
    if (index == QModelIndex()) {
       return m_accounts.size();
    }

    // Otherwise, return 0 (as this is a list model, so all items
    // are children of the root item).
    return 0;
}

QVariant AccountsListModel::data(const QModelIndex &index, int role) const
{
    QVariant data;
    Tp::AccountPtr account = m_accounts.at(index.row())->account();

    switch(role)
    {
    case Qt::DisplayRole:
        data = QVariant(account->displayName());
        break;

    case Qt::DecorationRole:
        data = QVariant(m_accounts.at(index.row())->icon());
        break;

    case Qt::CheckStateRole:
        if(account->isEnabled()) {
            data = QVariant(Qt::Checked);
        }
        else {
            data = QVariant(Qt::Unchecked);
        }
        break;

    case AccountsListModel::ConnectionStateDisplayRole:
        data = QVariant(m_accounts.at(index.row())->connectionStateString());
        break;

    case AccountsListModel::ConnectionStateIconRole:
        data = QVariant(m_accounts.at(index.row())->connectionStateIcon());
        break;

    case AccountsListModel::ConnectionErrorMessageDisplayRole:
        data = QVariant(m_accounts.at(index.row())->connectionStatusReason());
        break;
    default:
        break;
    }

    return data;
}

bool AccountsListModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    kDebug();
    if(role == Qt::CheckStateRole) {
        m_accounts.at(index.row())->account()->setEnabled(value.toInt() == Qt::Checked);
        return true;
    }
    return false;
}

Qt::ItemFlags AccountsListModel::flags(const QModelIndex &index) const
{
    return QAbstractItemModel::flags(index) | Qt::ItemIsUserCheckable;
}

void AccountsListModel::addAccount(const Tp::AccountPtr &account)
{
    kDebug() << "Creating a new AccountItem from account:" << account.data();

    // Check if the account is already in the model.
    bool found = false;

    if (!found) {
        foreach (const AccountItem* ai, m_accounts) {
            if (ai->account() == account) {
                found = true;
                break;
            }
        }
    }

    if (found) {
       kWarning() << "Requested to add account"
                  << account.data()
                  << "to model, but it is already present. Doing nothing.";
   } else {
       kDebug() << "Account not already in model. Create new AccountItem from account:"
                << account.data();

       AccountItem *item = new AccountItem(account, this);

       beginInsertRows(QModelIndex(), m_accounts.size(), m_accounts.size());
       m_accounts.append(item);
       endInsertRows();

       connect(item, SIGNAL(removed()), SLOT(onAccountItemRemoved()));
       connect(item, SIGNAL(updated()), SLOT(onAccountItemUpdated()));
   }
}

void AccountsListModel::removeAccount(const QModelIndex &index)
{
    kDebug();

    if(!index.isValid()) {
        kDebug() << "Can't remove Account: Invalid index";
        return;
    }
    AccountItem *accountItem = m_accounts.at(index.row());

    Q_ASSERT(accountItem);

    accountItem->remove();
}

AccountItem* AccountsListModel::itemForIndex(const QModelIndex &index)
{
    kDebug();

    if(!index.isValid()) {
        kWarning() << "Invalid index" << index;
        return 0;
    }

    AccountItem *accountItem = m_accounts.at(index.row());
    return accountItem;
}

void AccountsListModel::onAccountItemRemoved()
{
    kDebug();

    AccountItem *item = qobject_cast<AccountItem*>(sender());

    Q_ASSERT(item);
    if (!item) {
        kWarning() << "Not an AccountItem pointer:" << sender();
        return;
    }

    beginRemoveRows(QModelIndex(), m_accounts.indexOf(item),
                    m_accounts.lastIndexOf(item));
    m_accounts.removeAll(item);
    endRemoveRows();

    delete item;
}

void AccountsListModel::onAccountItemUpdated()
{
    kDebug();

    AccountItem *item = qobject_cast<AccountItem*>(sender());

    Q_ASSERT(item);
    if (!item) {
        kWarning() << "Not an AccountItem pointer:" << sender();
        return;
    }

    QModelIndex index = createIndex(m_accounts.lastIndexOf(item), 0);
    emit dataChanged(index, index);
}

void AccountsListModel::onTitleForCustomPages(QString mandatoryPage, QList<QString> optionalPage)
{
	kDebug();

	emit setTitleForCustomPages(mandatoryPage, optionalPage);
}

#include "accounts-list-model.moc"

<|endoftext|>


<commit_before>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "Material.h"
#include "SubProblem.h"
#include "MaterialData.h"

// system includes
#include <iostream>

template<>
InputParameters validParams<Material>()
{
  InputParameters params = validParams<MooseObject>();
  params.addParam<std::vector<SubdomainName> >("block", "The id or name of the block (subdomain) that this material represents.");
  params.addParam<std::vector<BoundaryName> >("boundary", "The id or name of the boundary that this material represents.");

  params.addPrivateParam<std::string>("built_by_action", "add_material");
  return params;
}

Material::Material(const std::string & name, InputParameters parameters) :
    MooseObject(name, parameters),
    SetupInterface(parameters),
    Coupleable(parameters, false),
    ScalarCoupleable(parameters),
    FunctionInterface(parameters),
    UserObjectInterface(parameters),
    TransientInterface(parameters),
    MaterialPropertyInterface(parameters),
    PostprocessorInterface(parameters),
    _problem(*parameters.get<Problem *>("_problem")),
    _subproblem(*parameters.get<SubProblem *>("_subproblem")),
    _displaced_subproblem(parameters.get<SubProblem *>("_subproblem_displaced")),
    _tid(parameters.get<THREAD_ID>("_tid")),
    _bnd(parameters.get<bool>("_bnd")),
    _material_data(*parameters.get<MaterialData *>("_material_data")),
    _qrule(_bnd ? _subproblem.qRuleFace(_tid) : _subproblem.qRule(_tid)),
    _JxW(_bnd ? _subproblem.JxWFace(_tid) : _subproblem.JxW(_tid)),
    _coord(_subproblem.coords(_tid)),
    _q_point(_bnd ? _subproblem.pointsFace(_tid) : _subproblem.points(_tid)),
    _normals(_subproblem.assembly(_tid).normals()),
    _current_elem(_subproblem.elem(_tid)),
    _mesh(_subproblem.mesh()),
    _dim(_mesh.dimension()),
    _coord_sys(_subproblem.coordSystem()),
    _block_id(_mesh.getSubdomainIDs(parameters.get<std::vector<SubdomainName> >("block"))),
    _real_zero(_problem._real_zero[_tid]),
    _zero(_problem._zero[_tid]),
    _grad_zero(_problem._grad_zero[_tid]),
    _second_zero(_problem._second_zero[_tid]),
    _has_stateful_property(false)
{
/*
  for (unsigned int i = 0; i < _coupled_to.size(); i++)
  {
    std::string coupled_var_name = _coupled_to[i];

    //Is it in the nonlinear system or the aux system?
    if (_moose_system.hasVariable(coupled_var_name))
    {
      unsigned int coupled_var_num = _moose_system.getVariableNumber(coupled_var_name);
      _data._var_nums.insert(coupled_var_num);
    }
    //Look for it in the Aux system
    else if (_moose_system.hasAuxVariable(coupled_var_name))
    {
      unsigned int coupled_var_num = _moose_system.getAuxVariableNumber(coupled_var_name);
      _data._aux_var_nums.insert(coupled_var_num);
    }
    else
      mooseError("Coupled variable '" + coupled_var_name + "' not found.");
  }
  */
}

Material::~Material()
{
  // TODO: Implement destructor to clean up after the _qp_prev and _qp_curr data objects

  //std::for_each(_qp_prev.begin(), _qp_prev.end(), DeleteFunctor());
  //std::for_each(_qp_curr.begin(), _qp_curr.end(), DeleteFunctor());
}

void
Material::computeProperties()
{
  for (_qp = 0; _qp < _qrule->n_points(); ++_qp)
    computeQpProperties();
}

void
Material::initStatefulProperties(unsigned int n_points)
{
  if (_has_stateful_property)
    for (_qp = 0; _qp < n_points; ++_qp)
      initQpStatefulProperties();
}

void
Material::initQpStatefulProperties()
{
  libmesh_do_once(mooseWarning(std::string("Material \"") + _name + "\" declares one or more stateful properties but initQpStatefulProperties() was not overridden in the derived class."));
}

void
Material::computeQpProperties()
{
}

void
Material::timeStepSetup()
{}

QpData *
Material::createData()
{
  return NULL;
}

<commit_msg>Calling ComputeQpProperties during initializaing for materials without stateful properties - closes #1208<commit_after>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "Material.h"
#include "SubProblem.h"
#include "MaterialData.h"

// system includes
#include <iostream>

template<>
InputParameters validParams<Material>()
{
  InputParameters params = validParams<MooseObject>();
  params.addParam<std::vector<SubdomainName> >("block", "The id or name of the block (subdomain) that this material represents.");
  params.addParam<std::vector<BoundaryName> >("boundary", "The id or name of the boundary that this material represents.");

  params.addPrivateParam<std::string>("built_by_action", "add_material");
  return params;
}

Material::Material(const std::string & name, InputParameters parameters) :
    MooseObject(name, parameters),
    SetupInterface(parameters),
    Coupleable(parameters, false),
    ScalarCoupleable(parameters),
    FunctionInterface(parameters),
    UserObjectInterface(parameters),
    TransientInterface(parameters),
    MaterialPropertyInterface(parameters),
    PostprocessorInterface(parameters),
    _problem(*parameters.get<Problem *>("_problem")),
    _subproblem(*parameters.get<SubProblem *>("_subproblem")),
    _displaced_subproblem(parameters.get<SubProblem *>("_subproblem_displaced")),
    _tid(parameters.get<THREAD_ID>("_tid")),
    _bnd(parameters.get<bool>("_bnd")),
    _material_data(*parameters.get<MaterialData *>("_material_data")),
    _qrule(_bnd ? _subproblem.qRuleFace(_tid) : _subproblem.qRule(_tid)),
    _JxW(_bnd ? _subproblem.JxWFace(_tid) : _subproblem.JxW(_tid)),
    _coord(_subproblem.coords(_tid)),
    _q_point(_bnd ? _subproblem.pointsFace(_tid) : _subproblem.points(_tid)),
    _normals(_subproblem.assembly(_tid).normals()),
    _current_elem(_subproblem.elem(_tid)),
    _mesh(_subproblem.mesh()),
    _dim(_mesh.dimension()),
    _coord_sys(_subproblem.coordSystem()),
    _block_id(_mesh.getSubdomainIDs(parameters.get<std::vector<SubdomainName> >("block"))),
    _real_zero(_problem._real_zero[_tid]),
    _zero(_problem._zero[_tid]),
    _grad_zero(_problem._grad_zero[_tid]),
    _second_zero(_problem._second_zero[_tid]),
    _has_stateful_property(false)
{
/*
  for (unsigned int i = 0; i < _coupled_to.size(); i++)
  {
    std::string coupled_var_name = _coupled_to[i];

    //Is it in the nonlinear system or the aux system?
    if (_moose_system.hasVariable(coupled_var_name))
    {
      unsigned int coupled_var_num = _moose_system.getVariableNumber(coupled_var_name);
      _data._var_nums.insert(coupled_var_num);
    }
    //Look for it in the Aux system
    else if (_moose_system.hasAuxVariable(coupled_var_name))
    {
      unsigned int coupled_var_num = _moose_system.getAuxVariableNumber(coupled_var_name);
      _data._aux_var_nums.insert(coupled_var_num);
    }
    else
      mooseError("Coupled variable '" + coupled_var_name + "' not found.");
  }
  */
}

Material::~Material()
{
  // TODO: Implement destructor to clean up after the _qp_prev and _qp_curr data objects

  //std::for_each(_qp_prev.begin(), _qp_prev.end(), DeleteFunctor());
  //std::for_each(_qp_curr.begin(), _qp_curr.end(), DeleteFunctor());
}

void
Material::computeProperties()
{
  for (_qp = 0; _qp < _qrule->n_points(); ++_qp)
    computeQpProperties();
}

void
Material::initStatefulProperties(unsigned int n_points)
{
  if (_has_stateful_property)
    for (_qp = 0; _qp < n_points; ++_qp)
      initQpStatefulProperties();
  else
    for (_qp = 0; _qp < n_points; ++_qp)
      computeQpProperties();
}

void
Material::initQpStatefulProperties()
{
  libmesh_do_once(mooseWarning(std::string("Material \"") + _name + "\" declares one or more stateful properties but initQpStatefulProperties() was not overridden in the derived class."));
}

void
Material::computeQpProperties()
{
}

void
Material::timeStepSetup()
{}

QpData *
Material::createData()
{
  return NULL;
}

<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2016.  All rights reserved
 */
#include    "../StroikaPreComp.h"

#if     qPlatform_Linux
#include    <execinfo.h>
#include    <unistd.h>
#if     defined (__GNUC__)
#include    <cxxabi.h>
#endif
#elif   qPlatform_Windows
#include    <Windows.h>
#endif

#include    "../Characters/LineEndings.h"
#include    "../Characters/StringBuilder.h"
#include    "../Execution/Finally.h"

#include    "BackTrace.h"

using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Characters;

/*
 ********************************************************************************
 ********************************* Debug::BackTrace *****************************
 ********************************************************************************
 */
wstring    Debug::BackTrace (unsigned int maxFrames)
{
#if     qPlatform_Linux
    // @see http://man7.org/linux/man-pages/man3/backtrace.3.html
    constexpr   size_t  kMaxStackSize_  =   100;        // could look at return size and re-run if equals exactly...
    // @todo combine maxFrames with trial and error on backtrace() calls
    void* stackTraceBuf[kMaxStackSize_] {};
    int nptrs = ::backtrace (stackTraceBuf, NEltsOf (stackTraceBuf));
    char**   syms = ::backtrace_symbols (stackTraceBuf, nptrs);
    if (syms == NULL) {
        //DbgTrace ("%d errno", errno); // perror("backtrace_symbols");
        return wstring {};
    }
    auto narrow2Wide = [] (const char* s) -> wstring {
        wstring symStr;
        for (const char* p = s; *p != '\0'; ++p)
        {
            symStr += *p;
        }
        return symStr;
    };
    auto&&      cleanup =   Execution::Finally ([syms] () noexcept { if (syms != nullptr) ::free (syms); });
    wstring     out;
    for (int j = 0; j < nptrs; j++) {
        wstring symStr  =    narrow2Wide (syms[j]);
#if     defined (__GNUC__)
        int status = -1;
        char* realname = abi::__cxa_demangle (syms[j], 0, 0, &status);
        if  (status == 0) {
            symStr = narrow2Wide (realname);
        }
        if (realname != nullptr) {
            ::free (realname);
        }
#endif
        out += symStr + L";" + Characters::GetEOL<wchar_t> ();
    }
    return out;
#else
    return wstring {};
#endif
}
<commit_msg>improved formatting of backtrace output on gcc/unix (hopefully fixed demangle)<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2016.  All rights reserved
 */
#include    "../StroikaPreComp.h"

#if     qPlatform_Linux
#include    <execinfo.h>
#include    <unistd.h>
#if     defined (__GNUC__)
#include    <cxxabi.h>
#endif
#elif   qPlatform_Windows
#include    <Windows.h>
#endif

#include    "../Characters/LineEndings.h"
#include    "../Characters/StringBuilder.h"
#include    "../Execution/Finally.h"

#include    "BackTrace.h"

using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Characters;

/*
 ********************************************************************************
 ********************************* Debug::BackTrace *****************************
 ********************************************************************************
 */
wstring    Debug::BackTrace (unsigned int maxFrames)
{
#if     qPlatform_Linux
    // @see http://man7.org/linux/man-pages/man3/backtrace.3.html
    constexpr   size_t  kMaxStackSize_  =   100;        // could look at return size and re-run if equals exactly...
    // @todo combine maxFrames with trial and error on backtrace() calls
    void* stackTraceBuf[kMaxStackSize_] {};
    int nptrs = ::backtrace (stackTraceBuf, NEltsOf (stackTraceBuf));
    char**   syms = ::backtrace_symbols (stackTraceBuf, nptrs);
    if (syms == NULL) {
        //DbgTrace ("%d errno", errno); // perror("backtrace_symbols");
        return wstring {};
    }
    auto narrow2Wide = [] (const char* s) -> wstring {
        wstring symStr;
        for (const char* p = s; *p != '\0'; ++p)
        {
            symStr += *p;
        }
        return symStr;
    };
    auto&&      cleanup =   Execution::Finally ([syms] () noexcept { if (syms != nullptr) ::free (syms); });
    wstring     out;
    for (int j = 0; j < nptrs; j++) {
        wstring symStr  =    narrow2Wide (syms[j]);
#if     defined (__GNUC__)
        //
        // Example output from backtrace_symbols:
        //      /media/Sandbox/lewis-Sandbox/Stroika-DevRoot/Builds/Debug/Samples_SimpleService(_ZN7Stroika10Foundation9Execution8Private_8GetBT_wsEv+0x21) [0x7fc677]
        //
        //  abi::__cxa_demangle requires just the _ZN7Stroika10Foundation9Execution8Private_8GetBT_wsEv part, so extract it.
        //
        const char* beginOfName = ::strchr (syms[j], '(');
        if (beginOfName != nullptr) {
            beginOfName++;
        }
        const char* endOfName = (beginOfName == nullptr) ? nullptr : ::strchr (beginOfName, '+');
        //if (endOfName == nullptr and beginOfName != nullptr) {
        //  endOfName = ::strchr (beginOfName, ')');    // maybe no + sometimes?
        //}
        if (beginOfName != nullptr and endOfName != nullptr) {
            int status = -1;
            string tmp { beginOfName, endOfName };
            char* realname = abi::__cxa_demangle (tmp.c_str (), 0, 0, &status);
            if  (status == 0) {
                symStr = narrow2Wide (string {syms[j], beginOfName} + realname + endOfName);
            }
            if (realname != nullptr) {
                ::free (realname);
            }
        }
#endif
        out += symStr + L";" + Characters::GetEOL<wchar_t> ();
    }
    return out;
#else
    return wstring {};
#endif
}
<|endoftext|>


<commit_before>/*
 * AccountManager.cpp
 *
 *  Created on: Oct 13, 2010
 *      Author: crush
 */

#include "engine/engine.h"

#include "Account.h"
#include "AccountManager.h"
#include "server/login/LoginClient.h"
#include "server/login/LoginServer.h"
#include "server/login/objects/CharacterList.h"
#include "server/login/packets/AccountVersionMessage.h"
#include "server/login/packets/EnumerateCharacterId.h"
#include "server/login/packets/LoginClientToken.h"
#include "server/login/packets/LoginClusterStatus.h"
#include "server/login/packets/LoginEnumCluster.h"
#include "server/ServerCore.h"

AccountManager::AccountManager(LoginServer* loginserv) : Logger("AccountManager") {
	loginServer = loginserv;

	autoRegistration = true;
	requiredVersion = "";
	maxOnlineCharacters = 1;

	setLogging(false);
	setGlobalLogging(false);

	if (ServerCore::truncateDatabases()) {
		try {
			String query = "TRUNCATE TABLE characters";

			Reference<ResultSet*> res = ServerDatabase::instance()->executeQuery(query);

			info("characters table truncated", true);
		} catch (Exception& e) {
			error(e.getMessage());
		}
	}
}

AccountManager::~AccountManager() {

}

void AccountManager::loginAccount(LoginClient* client, Message* packet) {
	String username, password, version;
	AccountVersionMessage::parse(packet, username, password, version);

	Database::escapeString(username);
	Database::escapeString(password);

	if (!isRequiredVersion(version)) {
		client->sendErrorMessage("Login Error", "The client you are attempting to connect with does not match that required by the server.");
		return;
	}

	ManagedReference<Account*> account = validateAccountCredentials(client, username, password);

	if (account == NULL)
		return;

	//TODO: This should probably be refactored at some point.
	uint32 sessionID = System::random();

	Message* lct = new LoginClientToken(account, sessionID);
	client->sendMessage(lct);

	uint32 accountID = account->getAccountID();

	client->setAccountID(accountID);

	String ip = client->getSession()->getAddress().getIPAddress();

	StringBuffer sessionQuery;
	sessionQuery << "REPLACE INTO sessions (account_id, session_id, ip, expires) VALUES (";
	sessionQuery << accountID << ", " << sessionID << ", '" << ip << "' , ADDTIME(NOW(), '00:15'));";

	StringBuffer logQuery;
	logQuery << "INSERT INTO account_log (account_id, ip_address, timestamp) VALUES (" << accountID << ", '" << ip << "', NOW());";

	try {
		ServerDatabase::instance()->executeStatement(sessionQuery);
		ServerDatabase::instance()->executeStatement(logQuery);
	} catch (DatabaseException& e) {
		client->info(e.getMessage(), true);
	}

	client->sendMessage(loginServer->getLoginEnumClusterMessage());
	client->sendMessage(loginServer->getLoginClusterStatusMessage());

	Message* eci = new EnumerateCharacterID(account->getCharacterList());
	client->sendMessage(eci);
}

Account* AccountManager::validateAccountCredentials(LoginClient* client, const String& username, const String& password) {

	StringBuffer query;
	query << "SELECT a.account_id, a.username, a.password, a.salt, IFNULL((SELECT b.expires FROM account_bans b WHERE b.account_id = a.account_id AND b.expires > UNIX_TIMESTAMP() ORDER BY b.expires DESC LIMIT 1), 0), IFNULL((SELECT b.reason FROM account_bans b WHERE b.account_id = a.account_id AND b.expires > UNIX_TIMESTAMP() ORDER BY b.expires DESC LIMIT 1), ''), a.account_id, a.station_id, UNIX_TIMESTAMP(a.created), a.admin_level FROM accounts a WHERE a.username = '" << username << "' LIMIT 1;";

	String passwordStored;
	Account* account = getAccount(query.toString(), passwordStored);

	if(account == NULL) {

		//The user name didn't exist, so we check if auto registration is enabled and create a new account
		if (isAutoRegistrationEnabled() && client != NULL) {
			account = createAccount(username, password, passwordStored);
		} else {
			if(client != NULL)
				client->sendErrorMessage("Login Error", "Automatic registration is currently disabled. Please contact the administrators of the server in order to get an authorized account.");
			return NULL;
		}
	}

	if(!account->isActive()) {

		if(client != NULL)
			client->sendErrorMessage("Account Disabled", "The server administrators have disabled your account.");

		return NULL;
	}

	//Check hash version
	String passwordHashed;
	if(account->getSalt() == "") {
		passwordHashed = Crypto::SHA1Hash(password);
	} else {
		passwordHashed = Crypto::SHA256Hash(dbSecret + password + account->getSalt());
	}

	if (passwordStored != passwordHashed) {

		if(client != NULL)
			client->sendErrorMessage("Wrong Password", "The password you entered was incorrect.");

		return NULL;
	}
	//update hash if unsalted
	if(account->getSalt() == "")
		updateHash(username, password);

	//Check if they are banned
	if(account->isBanned()) {

		StringBuffer reason;
		reason << "Your account has been banned from the server by the administrators.\n\n";
		reason << "Time remaining: " << round(((account->getBanExpires() - time(0)) / 60.0f) / 60.f) << " Minutes\n";
		reason << "Reason: " << account->getBanReason();

		if(client != NULL)
			client->sendErrorMessage("Account Banned", reason.toString());

		return NULL;
	}

	return account;
}

void AccountManager::updateHash(const String& username, const String& password) {
	String salt = Crypto::randomSalt();
	String hash = Crypto::SHA256Hash(dbSecret + password + salt);

	StringBuffer query;
	query << "UPDATE accounts SET password = '" << hash << "', ";
	query << "salt = '" << salt << "' ";
	query << "WHERE username = '" << username << "';";

	try {
		ServerDatabase::instance()->executeStatement(query);
	} catch (DatabaseException& e) {
		error(e.getMessage());
	}
}

Account* AccountManager::createAccount(const String& username, const String& password, String& passwordStored) {

	uint32 stationID = System::random();

	String salt = Crypto::randomSalt();
	String hash = Crypto::SHA256Hash(dbSecret + password + salt);

	StringBuffer query;
	query << "INSERT INTO accounts (username, password, station_id, salt) VALUES (";
	query << "'" << username << "',";
	query << "'" << hash << "',";
	query << stationID << ",";
	query << "'" << salt << "');";

	ResultSet* result = ServerDatabase::instance()->executeQuery(query.toString());

	if (result == NULL)
		return NULL;

	uint32 accountID = result->getLastAffectedRow();

	return getAccount(accountID, passwordStored);
}

Account* AccountManager::getAccount(uint32 accountID) {
	StringBuffer query;
	query << "SELECT a.active, a.username, a.password, a.salt, IFNULL((SELECT b.expires FROM account_bans b WHERE b.account_id = a.account_id AND b.expires > UNIX_TIMESTAMP() ORDER BY b.expires DESC LIMIT 1), 0), IFNULL((SELECT b.reason FROM account_bans b WHERE b.account_id = a.account_id AND b.expires > UNIX_TIMESTAMP() ORDER BY b.expires DESC LIMIT 1), ''), a.account_id, a.station_id, UNIX_TIMESTAMP(a.created), a.admin_level FROM accounts a WHERE a.account_id = '" << accountID << "' LIMIT 1;";

	String passwordStored;
	return getAccount(query.toString(), passwordStored);
}

Account* AccountManager::getAccount(uint32 accountID, String& passwordStored) {
	StringBuffer query;
	query << "SELECT a.active, a.username, a.password, a.salt, IFNULL((SELECT b.expires FROM account_bans b WHERE b.account_id = a.account_id AND b.expires > UNIX_TIMESTAMP() ORDER BY b.expires DESC LIMIT 1), 0), IFNULL((SELECT b.reason FROM account_bans b WHERE b.account_id = a.account_id AND b.expires > UNIX_TIMESTAMP() ORDER BY b.expires DESC LIMIT 1), ''), a.account_id, a.station_id, UNIX_TIMESTAMP(a.created), a.admin_level FROM accounts a WHERE a.account_id = '" << accountID << "' LIMIT 1;";

	return getAccount(query.toString(), passwordStored);
}

Account* AccountManager::getAccount(String query, String& passwordStored) {

	Account* account = NULL;

	ResultSet* result = ServerDatabase::instance()->executeQuery(query);

	if (result->next()) {

		account = new Account(this);

		account->setActive(result->getBoolean(0));
		account->setUsername(result->getString(1));
		passwordStored = result->getString(2);
		account->setSalt(result->getString(3));

		account->setBanExpires(result->getUnsignedInt(4));
		account->setBanReason(result->getString(5));

		account->setAccountID(result->getUnsignedInt(6));
		account->setStationID(result->getUnsignedInt(7));

		account->setTimeCreated(result->getUnsignedInt(8));
		account->setAdminLevel(result->getInt(9));
	}
	delete result;
	result = NULL;

	return account;
}
<commit_msg>[Fixed] Small typo<commit_after>/*
 * AccountManager.cpp
 *
 *  Created on: Oct 13, 2010
 *      Author: crush
 */

#include "engine/engine.h"

#include "Account.h"
#include "AccountManager.h"
#include "server/login/LoginClient.h"
#include "server/login/LoginServer.h"
#include "server/login/objects/CharacterList.h"
#include "server/login/packets/AccountVersionMessage.h"
#include "server/login/packets/EnumerateCharacterId.h"
#include "server/login/packets/LoginClientToken.h"
#include "server/login/packets/LoginClusterStatus.h"
#include "server/login/packets/LoginEnumCluster.h"
#include "server/ServerCore.h"

AccountManager::AccountManager(LoginServer* loginserv) : Logger("AccountManager") {
	loginServer = loginserv;

	autoRegistration = true;
	requiredVersion = "";
	maxOnlineCharacters = 1;

	setLogging(false);
	setGlobalLogging(false);

	if (ServerCore::truncateDatabases()) {
		try {
			String query = "TRUNCATE TABLE characters";

			Reference<ResultSet*> res = ServerDatabase::instance()->executeQuery(query);

			info("characters table truncated", true);
		} catch (Exception& e) {
			error(e.getMessage());
		}
	}
}

AccountManager::~AccountManager() {

}

void AccountManager::loginAccount(LoginClient* client, Message* packet) {
	String username, password, version;
	AccountVersionMessage::parse(packet, username, password, version);

	Database::escapeString(username);
	Database::escapeString(password);

	if (!isRequiredVersion(version)) {
		client->sendErrorMessage("Login Error", "The client you are attempting to connect with does not match that required by the server.");
		return;
	}

	ManagedReference<Account*> account = validateAccountCredentials(client, username, password);

	if (account == NULL)
		return;

	//TODO: This should probably be refactored at some point.
	uint32 sessionID = System::random();

	Message* lct = new LoginClientToken(account, sessionID);
	client->sendMessage(lct);

	uint32 accountID = account->getAccountID();

	client->setAccountID(accountID);

	String ip = client->getSession()->getAddress().getIPAddress();

	StringBuffer sessionQuery;
	sessionQuery << "REPLACE INTO sessions (account_id, session_id, ip, expires) VALUES (";
	sessionQuery << accountID << ", " << sessionID << ", '" << ip << "' , ADDTIME(NOW(), '00:15'));";

	StringBuffer logQuery;
	logQuery << "INSERT INTO account_log (account_id, ip_address, timestamp) VALUES (" << accountID << ", '" << ip << "', NOW());";

	try {
		ServerDatabase::instance()->executeStatement(sessionQuery);
		ServerDatabase::instance()->executeStatement(logQuery);
	} catch (DatabaseException& e) {
		client->info(e.getMessage(), true);
	}

	client->sendMessage(loginServer->getLoginEnumClusterMessage());
	client->sendMessage(loginServer->getLoginClusterStatusMessage());

	Message* eci = new EnumerateCharacterID(account->getCharacterList());
	client->sendMessage(eci);
}

Account* AccountManager::validateAccountCredentials(LoginClient* client, const String& username, const String& password) {

	StringBuffer query;
	query << "SELECT a.account_id, a.username, a.password, a.salt, IFNULL((SELECT b.expires FROM account_bans b WHERE b.account_id = a.account_id AND b.expires > UNIX_TIMESTAMP() ORDER BY b.expires DESC LIMIT 1), 0), IFNULL((SELECT b.reason FROM account_bans b WHERE b.account_id = a.account_id AND b.expires > UNIX_TIMESTAMP() ORDER BY b.expires DESC LIMIT 1), ''), a.account_id, a.station_id, UNIX_TIMESTAMP(a.created), a.admin_level FROM accounts a WHERE a.username = '" << username << "' LIMIT 1;";

	String passwordStored;
	Account* account = getAccount(query.toString(), passwordStored);

	if(account == NULL) {

		//The user name didn't exist, so we check if auto registration is enabled and create a new account
		if (isAutoRegistrationEnabled() && client != NULL) {
			account = createAccount(username, password, passwordStored);
		} else {
			if(client != NULL)
				client->sendErrorMessage("Login Error", "Automatic registration is currently disabled. Please contact the administrators of the server in order to get an authorized account.");
			return NULL;
		}
	}

	if(!account->isActive()) {

		if(client != NULL)
			client->sendErrorMessage("Account Disabled", "The server administrators have disabled your account.");

		return NULL;
	}

	//Check hash version
	String passwordHashed;
	if(account->getSalt() == "") {
		passwordHashed = Crypto::SHA1Hash(password);
	} else {
		passwordHashed = Crypto::SHA256Hash(dbSecret + password + account->getSalt());
	}

	if (passwordStored != passwordHashed) {

		if(client != NULL)
			client->sendErrorMessage("Wrong Password", "The password you entered was incorrect.");

		return NULL;
	}
	//update hash if unsalted
	if(account->getSalt() == "")
		updateHash(username, password);

	//Check if they are banned
	if(account->isBanned()) {

		StringBuffer reason;
		reason << "Your account has been banned from the server by the administrators.\n\n";
		reason << "Time remaining: " << round(((account->getBanExpires() - time(0)) / 60.0f) / 60.f) << " Minutes\n";
		reason << "Reason: " << account->getBanReason();

		if(client != NULL)
			client->sendErrorMessage("Account Banned", reason.toString());

		return NULL;
	}

	return account;
}

void AccountManager::updateHash(const String& username, const String& password) {
	String salt = Crypto::randomSalt();
	String hash = Crypto::SHA256Hash(dbSecret + password + salt);

	StringBuffer query;
	query << "UPDATE accounts SET password = '" << hash << "', ";
	query << "salt = '" << salt << "' ";
	query << "WHERE username = '" << username << "';";

	try {
		ServerDatabase::instance()->executeStatement(query);
	} catch (DatabaseException& e) {
		error(e.getMessage());
	}
}

Account* AccountManager::createAccount(const String& username, const String& password, String& passwordStored) {

	uint32 stationID = System::random();

	String salt = Crypto::randomSalt();
	String hash = Crypto::SHA256Hash(dbSecret + password + salt);

	StringBuffer query;
	query << "INSERT INTO accounts (username, password, station_id, salt) VALUES (";
	query << "'" << username << "',";
	query << "'" << hash << "',";
	query << stationID << ",";
	query << "'" << salt << "');";

	ResultSet* result = ServerDatabase::instance()->executeQuery(query.toString());

	if (result == NULL)
		return NULL;

	uint32 accountID = result->getLastAffectedRow();

	return getAccount(accountID, passwordStored);
}

Account* AccountManager::getAccount(uint32 accountID) {

	String passwordStored;
	return getAccount(accountID, passwordStored);
}

Account* AccountManager::getAccount(uint32 accountID, String& passwordStored) {
	StringBuffer query;
	query << "SELECT a.active, a.username, a.password, a.salt, IFNULL((SELECT b.expires FROM account_bans b WHERE b.account_id = a.account_id AND b.expires > UNIX_TIMESTAMP() ORDER BY b.expires DESC LIMIT 1), 0), IFNULL((SELECT b.reason FROM account_bans b WHERE b.account_id = a.account_id AND b.expires > UNIX_TIMESTAMP() ORDER BY b.expires DESC LIMIT 1), ''), a.account_id, a.station_id, UNIX_TIMESTAMP(a.created), a.admin_level FROM accounts a WHERE a.account_id = '" << accountID << "' LIMIT 1;";

	return getAccount(query.toString(), passwordStored);
}

Account* AccountManager::getAccount(String query, String& passwordStored) {

	Account* account = NULL;

	ResultSet* result = ServerDatabase::instance()->executeQuery(query);

	if (result->next()) {

		account = new Account(this);

		account->setActive(result->getBoolean(0));
		account->setUsername(result->getString(1));
		passwordStored = result->getString(2);
		account->setSalt(result->getString(3));

		account->setBanExpires(result->getUnsignedInt(4));
		account->setBanReason(result->getString(5));

		account->setAccountID(result->getUnsignedInt(6));
		account->setStationID(result->getUnsignedInt(7));

		account->setTimeCreated(result->getUnsignedInt(8));
		account->setAdminLevel(result->getInt(9));
	}
	delete result;
	result = NULL;

	return account;
}
<|endoftext|>


<commit_before>/*************************************************************************/
/*  editor_about.cpp                                                     */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md)    */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/
#include "editor_about.h"

#include "authors.gen.h"
#include "donors.gen.h"
#include "license.gen.h"
#include "version.h"
#include "version_hash.gen.h"

void EditorAbout::_license_tree_selected() {

	TreeItem *selected = _tpl_tree->get_selected();
	_tpl_text->select(0, 0, 0, 0);
	_tpl_text->set_text(selected->get_metadata(0));
}

void EditorAbout::_bind_methods() {

	ClassDB::bind_method(D_METHOD("_license_tree_selected"), &EditorAbout::_license_tree_selected);
}

TextureRect *EditorAbout::get_logo() const {

	return _logo;
}

ScrollContainer *EditorAbout::_populate_list(const String &p_name, const List<String> &p_sections, const char **p_src[]) {

	ScrollContainer *sc = memnew(ScrollContainer);
	sc->set_name(p_name);
	sc->set_v_size_flags(Control::SIZE_EXPAND);

	VBoxContainer *vbc = memnew(VBoxContainer);
	vbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
	sc->add_child(vbc);

	for (int i = 0; i < p_sections.size(); i++) {

		const char **names_ptr = p_src[i];
		if (*names_ptr) {

			Label *lbl = memnew(Label);
			lbl->set_text(p_sections[i]);
			vbc->add_child(lbl);

			ItemList *il = memnew(ItemList);
			il->set_max_columns(16);
			il->set_h_size_flags(Control::SIZE_EXPAND_FILL);
			il->set_same_column_width(true);
			il->set_auto_height(true);
			while (*names_ptr) {
				il->add_item(String::utf8(*names_ptr++), NULL, false);
			}
			vbc->add_child(il);
			if (il->get_item_count() == 2) {
				il->set_fixed_column_width(200 * EDSCALE);
			}

			HSeparator *hs = memnew(HSeparator);
			hs->set_modulate(Color(0, 0, 0, 0));
			vbc->add_child(hs);
		}
	}

	return sc;
}

EditorAbout::EditorAbout() {

	set_title(TTR("Thanks from the Godot community!"));
	get_ok()->set_text(TTR("Thanks!"));
	set_hide_on_ok(true);
	set_resizable(true);

	VBoxContainer *vbc = memnew(VBoxContainer);
	HBoxContainer *hbc = memnew(HBoxContainer);
	hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
	hbc->set_alignment(BoxContainer::ALIGN_CENTER);
	hbc->add_constant_override("separation", 30 * EDSCALE);
	add_child(vbc);
	vbc->add_child(hbc);

	_logo = memnew(TextureRect);
	hbc->add_child(_logo);

	String hash = String(VERSION_HASH);
	if (hash.length() != 0)
		hash = "." + hash.left(7);

	Label *about_text = memnew(Label);
	about_text->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
	about_text->set_text(VERSION_FULL_NAME + hash + String::utf8("\n\u00A9 2007-2017 Juan Linietsky, Ariel Manzur.\n\u00A9 2014-2017 ") +
						 TTR("Godot Engine contributors") + "\n");
	hbc->add_child(about_text);

	TabContainer *tc = memnew(TabContainer);
	tc->set_custom_minimum_size(Size2(630, 240) * EDSCALE);
	tc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
	vbc->add_child(tc);

	// Authors

	List<String> dev_sections;
	dev_sections.push_back(TTR("Project Founders"));
	dev_sections.push_back(TTR("Lead Developer"));
	dev_sections.push_back(TTR("Project Manager"));
	dev_sections.push_back(TTR("Developers"));
	const char **dev_src[] = { dev_founders, dev_lead, dev_manager, dev_names };
	tc->add_child(_populate_list(TTR("Authors"), dev_sections, dev_src));

	// Donors

	List<String> donor_sections;
	donor_sections.push_back(TTR("Platinum Sponsors"));
	donor_sections.push_back(TTR("Gold Sponsors"));
	donor_sections.push_back(TTR("Mini Sponsors"));
	donor_sections.push_back(TTR("Gold Donors"));
	donor_sections.push_back(TTR("Silver Donors"));
	donor_sections.push_back(TTR("Bronze Donors"));
	const char **donor_src[] = { donor_s_plat, donor_s_gold, donor_s_mini, donor_gold, donor_silver, donor_bronze };
	tc->add_child(_populate_list(TTR("Donors"), donor_sections, donor_src));

	// License

	TextEdit *license = memnew(TextEdit);
	license->set_name(TTR("License"));
	license->set_h_size_flags(Control::SIZE_EXPAND_FILL);
	license->set_v_size_flags(Control::SIZE_EXPAND_FILL);
	license->set_wrap(true);
	license->set_readonly(true);
	license->set_text(String::utf8(about_license));
	tc->add_child(license);

	// Thirdparty License

	VBoxContainer *license_thirdparty = memnew(VBoxContainer);
	license_thirdparty->set_name(TTR("Thirdparty License"));
	license_thirdparty->set_h_size_flags(Control::SIZE_EXPAND_FILL);
	tc->add_child(license_thirdparty);

	Label *tpl_label = memnew(Label);
	tpl_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
	tpl_label->set_autowrap(true);
	tpl_label->set_text(TTR("Godot Engine relies on a number of thirdparty free and open source libraries, all compatible with the terms of its MIT license. The following is an exhaustive list of all such thirdparty components with their respective copyright statements and license terms."));
	license_thirdparty->add_child(tpl_label);

	HSplitContainer *tpl_hbc = memnew(HSplitContainer);
	tpl_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
	tpl_hbc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
	tpl_hbc->set_split_offset(240 * EDSCALE);
	license_thirdparty->add_child(tpl_hbc);

	_tpl_tree = memnew(Tree);
	_tpl_tree->set_hide_root(true);
	TreeItem *root = _tpl_tree->create_item();
	TreeItem *tpl_ti_all = _tpl_tree->create_item(root);
	tpl_ti_all->set_text(0, TTR("All Components"));
	TreeItem *tpl_ti_tp = _tpl_tree->create_item(root);
	tpl_ti_tp->set_text(0, TTR("Components"));
	tpl_ti_tp->set_selectable(0, false);
	TreeItem *tpl_ti_lc = _tpl_tree->create_item(root);
	tpl_ti_lc->set_text(0, TTR("Licenses"));
	tpl_ti_lc->set_selectable(0, false);
	int read_idx = 0;
	String long_text = "";
	for (int i = 0; i < THIRDPARTY_COUNT; i++) {

		TreeItem *ti = _tpl_tree->create_item(tpl_ti_tp);
		String thirdparty = String(about_thirdparty[i]);
		ti->set_text(0, thirdparty);
		String text = thirdparty + "\n";
		long_text += "- " + thirdparty + "\n\n";
		for (int j = 0; j < about_tp_copyright_count[i]; j++) {

			text += "\n    Files:\n        " + String(about_tp_file[read_idx]).replace("\n", "\n        ") + "\n";
			String copyright = String::utf8("    \u00A9 ") + String::utf8(about_tp_copyright[read_idx]).replace("\n", String::utf8("\n    \u00A9 "));
			text += copyright;
			long_text += copyright;
			String license = "\n    License: " + String(about_tp_license[read_idx]) + "\n";
			text += license;
			long_text += license + "\n";
			read_idx++;
		}
		ti->set_metadata(0, text);
	}
	for (int i = 0; i < LICENSE_COUNT; i++) {

		TreeItem *ti = _tpl_tree->create_item(tpl_ti_lc);
		String licensename = String(about_license_name[i]);
		ti->set_text(0, licensename);
		long_text += "- " + licensename + "\n\n";
		String licensebody = String(about_license_body[i]);
		ti->set_metadata(0, licensebody);
		long_text += "    " + licensebody.replace("\n", "\n    ") + "\n\n";
	}
	tpl_ti_all->set_metadata(0, long_text);
	tpl_hbc->add_child(_tpl_tree);

	_tpl_text = memnew(TextEdit);
	_tpl_text->set_h_size_flags(Control::SIZE_EXPAND_FILL);
	_tpl_text->set_v_size_flags(Control::SIZE_EXPAND_FILL);
	_tpl_text->set_wrap(true);
	_tpl_text->set_readonly(true);
	tpl_hbc->add_child(_tpl_text);

	_tpl_tree->connect("item_selected", this, "_license_tree_selected");
	tpl_ti_all->select(0);
	_tpl_text->set_text(tpl_ti_all->get_metadata(0));
}

EditorAbout::~EditorAbout() {}
<commit_msg>Fixed invalid license symbol<commit_after>/*************************************************************************/
/*  editor_about.cpp                                                     */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md)    */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/
#include "editor_about.h"

#include "authors.gen.h"
#include "donors.gen.h"
#include "license.gen.h"
#include "version.h"
#include "version_hash.gen.h"

void EditorAbout::_license_tree_selected() {

	TreeItem *selected = _tpl_tree->get_selected();
	_tpl_text->select(0, 0, 0, 0);
	_tpl_text->set_text(selected->get_metadata(0));
}

void EditorAbout::_bind_methods() {

	ClassDB::bind_method(D_METHOD("_license_tree_selected"), &EditorAbout::_license_tree_selected);
}

TextureRect *EditorAbout::get_logo() const {

	return _logo;
}

ScrollContainer *EditorAbout::_populate_list(const String &p_name, const List<String> &p_sections, const char **p_src[]) {

	ScrollContainer *sc = memnew(ScrollContainer);
	sc->set_name(p_name);
	sc->set_v_size_flags(Control::SIZE_EXPAND);

	VBoxContainer *vbc = memnew(VBoxContainer);
	vbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
	sc->add_child(vbc);

	for (int i = 0; i < p_sections.size(); i++) {

		const char **names_ptr = p_src[i];
		if (*names_ptr) {

			Label *lbl = memnew(Label);
			lbl->set_text(p_sections[i]);
			vbc->add_child(lbl);

			ItemList *il = memnew(ItemList);
			il->set_max_columns(16);
			il->set_h_size_flags(Control::SIZE_EXPAND_FILL);
			il->set_same_column_width(true);
			il->set_auto_height(true);
			while (*names_ptr) {
				il->add_item(String::utf8(*names_ptr++), NULL, false);
			}
			vbc->add_child(il);
			if (il->get_item_count() == 2) {
				il->set_fixed_column_width(200 * EDSCALE);
			}

			HSeparator *hs = memnew(HSeparator);
			hs->set_modulate(Color(0, 0, 0, 0));
			vbc->add_child(hs);
		}
	}

	return sc;
}

EditorAbout::EditorAbout() {

	set_title(TTR("Thanks from the Godot community!"));
	get_ok()->set_text(TTR("Thanks!"));
	set_hide_on_ok(true);
	set_resizable(true);

	VBoxContainer *vbc = memnew(VBoxContainer);
	HBoxContainer *hbc = memnew(HBoxContainer);
	hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
	hbc->set_alignment(BoxContainer::ALIGN_CENTER);
	hbc->add_constant_override("separation", 30 * EDSCALE);
	add_child(vbc);
	vbc->add_child(hbc);

	_logo = memnew(TextureRect);
	hbc->add_child(_logo);

	String hash = String(VERSION_HASH);
	if (hash.length() != 0)
		hash = "." + hash.left(7);

	Label *about_text = memnew(Label);
	about_text->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
	about_text->set_text(VERSION_FULL_NAME + hash + String::utf8("\n\xc2\xa9 2007-2017 Juan Linietsky, Ariel Manzur.\n\xc2\xa9 2014-2017 ") +
						 TTR("Godot Engine contributors") + "\n");
	hbc->add_child(about_text);

	TabContainer *tc = memnew(TabContainer);
	tc->set_custom_minimum_size(Size2(630, 240) * EDSCALE);
	tc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
	vbc->add_child(tc);

	// Authors

	List<String> dev_sections;
	dev_sections.push_back(TTR("Project Founders"));
	dev_sections.push_back(TTR("Lead Developer"));
	dev_sections.push_back(TTR("Project Manager"));
	dev_sections.push_back(TTR("Developers"));
	const char **dev_src[] = { dev_founders, dev_lead, dev_manager, dev_names };
	tc->add_child(_populate_list(TTR("Authors"), dev_sections, dev_src));

	// Donors

	List<String> donor_sections;
	donor_sections.push_back(TTR("Platinum Sponsors"));
	donor_sections.push_back(TTR("Gold Sponsors"));
	donor_sections.push_back(TTR("Mini Sponsors"));
	donor_sections.push_back(TTR("Gold Donors"));
	donor_sections.push_back(TTR("Silver Donors"));
	donor_sections.push_back(TTR("Bronze Donors"));
	const char **donor_src[] = { donor_s_plat, donor_s_gold, donor_s_mini, donor_gold, donor_silver, donor_bronze };
	tc->add_child(_populate_list(TTR("Donors"), donor_sections, donor_src));

	// License

	TextEdit *license = memnew(TextEdit);
	license->set_name(TTR("License"));
	license->set_h_size_flags(Control::SIZE_EXPAND_FILL);
	license->set_v_size_flags(Control::SIZE_EXPAND_FILL);
	license->set_wrap(true);
	license->set_readonly(true);
	license->set_text(String::utf8(about_license));
	tc->add_child(license);

	// Thirdparty License

	VBoxContainer *license_thirdparty = memnew(VBoxContainer);
	license_thirdparty->set_name(TTR("Thirdparty License"));
	license_thirdparty->set_h_size_flags(Control::SIZE_EXPAND_FILL);
	tc->add_child(license_thirdparty);

	Label *tpl_label = memnew(Label);
	tpl_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
	tpl_label->set_autowrap(true);
	tpl_label->set_text(TTR("Godot Engine relies on a number of thirdparty free and open source libraries, all compatible with the terms of its MIT license. The following is an exhaustive list of all such thirdparty components with their respective copyright statements and license terms."));
	license_thirdparty->add_child(tpl_label);

	HSplitContainer *tpl_hbc = memnew(HSplitContainer);
	tpl_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
	tpl_hbc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
	tpl_hbc->set_split_offset(240 * EDSCALE);
	license_thirdparty->add_child(tpl_hbc);

	_tpl_tree = memnew(Tree);
	_tpl_tree->set_hide_root(true);
	TreeItem *root = _tpl_tree->create_item();
	TreeItem *tpl_ti_all = _tpl_tree->create_item(root);
	tpl_ti_all->set_text(0, TTR("All Components"));
	TreeItem *tpl_ti_tp = _tpl_tree->create_item(root);
	tpl_ti_tp->set_text(0, TTR("Components"));
	tpl_ti_tp->set_selectable(0, false);
	TreeItem *tpl_ti_lc = _tpl_tree->create_item(root);
	tpl_ti_lc->set_text(0, TTR("Licenses"));
	tpl_ti_lc->set_selectable(0, false);
	int read_idx = 0;
	String long_text = "";
	for (int i = 0; i < THIRDPARTY_COUNT; i++) {

		TreeItem *ti = _tpl_tree->create_item(tpl_ti_tp);
		String thirdparty = String(about_thirdparty[i]);
		ti->set_text(0, thirdparty);
		String text = thirdparty + "\n";
		long_text += "- " + thirdparty + "\n\n";
		for (int j = 0; j < about_tp_copyright_count[i]; j++) {

			text += "\n    Files:\n        " + String(about_tp_file[read_idx]).replace("\n", "\n        ") + "\n";
			String copyright = String::utf8("    \xc2\xa9 ") + String::utf8(about_tp_copyright[read_idx]).replace("\n", String::utf8("\n    \xc2\xa9 "));
			text += copyright;
			long_text += copyright;
			String license = "\n    License: " + String(about_tp_license[read_idx]) + "\n";
			text += license;
			long_text += license + "\n";
			read_idx++;
		}
		ti->set_metadata(0, text);
	}
	for (int i = 0; i < LICENSE_COUNT; i++) {

		TreeItem *ti = _tpl_tree->create_item(tpl_ti_lc);
		String licensename = String(about_license_name[i]);
		ti->set_text(0, licensename);
		long_text += "- " + licensename + "\n\n";
		String licensebody = String(about_license_body[i]);
		ti->set_metadata(0, licensebody);
		long_text += "    " + licensebody.replace("\n", "\n    ") + "\n\n";
	}
	tpl_ti_all->set_metadata(0, long_text);
	tpl_hbc->add_child(_tpl_tree);

	_tpl_text = memnew(TextEdit);
	_tpl_text->set_h_size_flags(Control::SIZE_EXPAND_FILL);
	_tpl_text->set_v_size_flags(Control::SIZE_EXPAND_FILL);
	_tpl_text->set_wrap(true);
	_tpl_text->set_readonly(true);
	tpl_hbc->add_child(_tpl_text);

	_tpl_tree->connect("item_selected", this, "_license_tree_selected");
	tpl_ti_all->select(0);
	_tpl_text->set_text(tpl_ti_all->get_metadata(0));
}

EditorAbout::~EditorAbout() {}
<|endoftext|>


<commit_before>// This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
#include "clientapi.hh"
#include "internal.hh"
#include "config/config.h" // RAPICORN_GETTEXT_DOMAIN
#include <stdlib.h>

#define SDEBUG(...)     RAPICORN_KEY_DEBUG ("StartUp", __VA_ARGS__)

namespace Rapicorn {

static struct __StaticCTorTest { int v; __StaticCTorTest() : v (0x120caca0) { v += 0x300000; } } __staticctortest;

struct AppData {
  ApplicationH          app;
  Aida::BaseConnectionP connection;
};
static DurableInstance<AppData> static_appdata; // use DurableInstance to ensure app stays around for static dtors

/** Initialize Rapicorn and the main Application object.
 *
 * This funciton initializes the Rapicorn toolkit and starts an asynchronously
 * running UI thread. The UI thread creates the main Application object,
 * manages all UI related components and processes UI events.
 * .
 * The arguments passed in @a argcp and @a argv are parsed and any Rapicorn
 * specific arguments are stripped. Note that Rapicorn requires the exact argv0
 * as provided by main(). If @a argv[0] as passed into this function is empty or
 * otherwise altered, the correct value needs to be supplied previously by a
 * call to program_argv0_init().
 * If 'testing=1' is passed in @a args, these command line arguments are supported:
 * - @c --test-verbose - Execute test cases with verbose message generation.
 * - @c --test-slow - Execute only test cases excercising slow code paths or loops.
 * .
 * The initialization arguments currenlty supported for @a args are as follows:
 * - @c autonomous - Avoid loading external rc-files or other configurations that could affect test runs.
 * - @c cpu-affinity - The CPU# to bind the Rapicorn UI thread to.
 * - @c testing - Enable testing framework, used by init_core_test(), see also #$RAPICORN_TEST.
 * - @c test-verbose - acts like --test-verbose.
 * - @c test-slow - acts like --test-slow.
 * .
 * Additionally, the @c $RAPICORN environment variable affects toolkit behaviour. It supports
 * multiple colon (':') separated options (options can be prfixed with 'no-' to disable):
 * - @c debug - Enables verbose debugging output (default=off).
 * - @c fatal-syslog - Fatal program conditions that lead to aborting are recorded via syslog (default=on).
 * - @c syslog - Critical and warning conditions are recorded via syslog (default=off).
 * - @c fatal-warnings - Critical and warning conditions are treated as fatal conditions (default=off).
 * - @c logfile=FILENAME - Record all messages and conditions into FILENAME.
 * .
 * @param application_name Possibly localized string useful to display the application name in user interfaces.
 * @param argcp         Location of the 'argc' argument to main()
 * @param argv          Location of the 'argv' arguments to main()
 * @param args          Rapicorn initialization arguments.
 */
ApplicationH
init_app (const String &application_name, int *argcp, char **argv, const StringVector &args)
{
  return_unless (static_appdata->app == NULL, static_appdata->app);
  // assert global_ctors work
  if (__staticctortest.v != 0x123caca0)
    fatal ("%s: link error: C++ constructors have not been executed", __func__);
  // full locale initialization is needed by X11, etc
  if (!setlocale (LC_ALL,""))
    {
      auto sgetenv = [] (const char *var)  {
        const char *str = getenv (var);
        return str ? str : "";
      };
      String lv = string_format ("LANGUAGE=%s;LC_ALL=%s;LC_MONETARY=%s;LC_MESSAGES=%s;LC_COLLATE=%s;LC_CTYPE=%s;LC_TIME=%s;LANG=%s",
                                 sgetenv ("LANGUAGE"), sgetenv ("LC_ALL"), sgetenv ("LC_MONETARY"), sgetenv ("LC_MESSAGES"),
                                 sgetenv ("LC_COLLATE"), sgetenv ("LC_CTYPE"), sgetenv ("LC_TIME"), sgetenv ("LANG"));
      SDEBUG ("environment: %s", lv.c_str());
      setlocale (LC_ALL, "C");
      SDEBUG ("failed to initialize locale, falling back to \"C\"");
    }
  // initialize i18n functions
  RapicornInternal::init_rapicorn_gettext (RAPICORN_GETTEXT_DOMAIN);
  // miscellaneous sub systems
  {
    const String ci = cpu_info(); // initialize cpu info
    (void) ci;
  }
  // initialize core
  parse_init_args (argcp, argv, args);
  // boot up UI thread
  const bool boot_ok = RapicornInternal::uithread_bootup (argcp, argv, args);
  if (!boot_ok)
    fatal ("%s: failed to start Rapicorn UI thread: %s", __func__, strerror (errno));
  // connect to remote UIThread and fetch main handle
  static_appdata->connection = Aida::ClientConnection::connect ("inproc://Rapicorn-" RAPICORN_VERSION);
  if (!static_appdata->connection)
    fatal ("%s: failed to connect to Rapicorn UI thread: %s", __func__, strerror (errno));
  static_appdata->app = static_appdata->connection->remote_origin<ApplicationHandle>();
  if (!static_appdata->app)
    fatal ("%s: failed to retrieve Rapicorn::Application object: %s", __func__, strerror (errno));
  if (!application_name.empty())
    static_appdata->app.setup (application_name, "");
  return static_appdata->app;
}

ApplicationH
ApplicationH::the ()
{
  return static_appdata->app;
}

class AppSource;
typedef std::shared_ptr<AppSource> AppSourceP;

class AppSource : public EventSource {
  Rapicorn::Aida::BaseConnection &connection_;
  PollFD pfd_;
  bool   last_seen_primary, need_check_primary;
  void
  check_primaries()
  {
    // seen_primary is merely a hint, need to check local and remote states
    if (main_loop() && main_loop()->finishable() &&     // local
        ApplicationH::the().finishable() &&             // remote
        main_loop()->finishable())                      // still finishable after remote call
      main_loop()->quit();
  }
  AppSource (Rapicorn::Aida::BaseConnection &connection) :
    connection_ (connection), last_seen_primary (false), need_check_primary (false)
  {
    pfd_.fd = connection_.notify_fd();
    pfd_.events = PollFD::IN;
    pfd_.revents = 0;
    add_poll (&pfd_);
    primary (false);
    ApplicationH::the().sig_missing_primary() += [this]() { queue_check_primaries(); };
  }
  virtual bool
  prepare (const LoopState &state, int64 *timeout_usecs_p)
  {
    return need_check_primary || connection_.pending();
  }
  virtual bool
  check (const LoopState &state)
  {
    if (UNLIKELY (last_seen_primary && !state.seen_primary && !need_check_primary))
      need_check_primary = true;
    last_seen_primary = state.seen_primary;
    return need_check_primary || connection_.pending();
  }
  virtual bool
  dispatch (const LoopState &state)
  {
    connection_.dispatch();
    if (need_check_primary)
      {
        need_check_primary = false;
        queue_check_primaries();
      }
    return true;
  }
  friend class FriendAllocator<AppSource>;
public:
  static AppSourceP create (Rapicorn::Aida::BaseConnection &connection)
  { return FriendAllocator<AppSource>::make_shared (connection); }
  void
  queue_check_primaries()
  {
    if (loop_)
      loop_->exec_idle (Aida::slot (*this, &AppSource::check_primaries));
  }
};

} // Rapicorn

// compile client-side API
#include "clientapi.cc"

#include <rcore/testutils.hh>
namespace Rapicorn {
MainLoopP
ApplicationH::main_loop()
{
  ApplicationH the_app = the();
  assert_return (the_app != NULL, NULL);
  static MainLoopP app_loop = NULL;
  do_once
    {
      app_loop = MainLoop::create();
      AppSourceP source = AppSource::create (*the_app.__aida_connection__());
      app_loop->add (source);
      source->queue_check_primaries();
    }
  return app_loop;
}

/**
 * Initialize Rapicorn like init_app(), and boots up the test suite framework.
 * Normally, Test::run() should be called next to execute all unit tests.
 */
ApplicationH
init_test_app (const String &application_name, int *argcp, char **argv, const StringVector &args)
{
  RapicornInternal::inject_init_args (":autonomous:testing:fatal-warnings:");
  ApplicationH app = init_app (application_name, argcp, argv, args);
  return app;
}

/**
 * Cause the application's main loop to quit, and run() to return @a quit_code.
 */
void
ApplicationH::quit (int quit_code)
{
  main_loop()->quit (quit_code);
}

/**
 * Run the main event loop until all primary sources ceased to exist
 * (see MainLoop::finishable()) or until the loop is quit.
 * @returns the @a quit_code passed in to loop_quit() or 0.
 */
int
ApplicationH::run ()
{
  return main_loop()->run();
}

/**
 * This function runs the Application main loop via loop_run(), and exits
 * the running process once the loop has quit. The loop_quit() status is
 * passed on to exit() and thus to the parent process.
 */
int
ApplicationH::run_and_exit ()
{
  int status = run();
  shutdown();
  ::exit (status);
}

/// Perform one loop iteration and return whether more iterations are needed.
bool
ApplicationH::iterate (bool block)
{
  return main_loop()->iterate (block);
}

/**
 * This function causes proper termination of Rapicorn's concurrently running
 * ui-thread and needs to be called before exit(3posix), to avoid parallel
 * execution of the ui-thread while atexit(3posix) handlers or while global
 * destructors are releasing process resources.
 */
void
ApplicationH::shutdown()
{
  RapicornInternal::uithread_shutdown();
}

} // Rapicorn

namespace RapicornInternal {

// internal function for tests
int64
client_app_test_hook ()
{
  return ApplicationH::the().test_hook();
}

} // RapicornInternal
<commit_msg>UI: clientglue: rely on C++11 exclusive local static variable initialization<commit_after>// This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
#include "clientapi.hh"
#include "internal.hh"
#include "config/config.h" // RAPICORN_GETTEXT_DOMAIN
#include <stdlib.h>

#define SDEBUG(...)     RAPICORN_KEY_DEBUG ("StartUp", __VA_ARGS__)

namespace Rapicorn {

static struct __StaticCTorTest { int v; __StaticCTorTest() : v (0x120caca0) { v += 0x300000; } } __staticctortest;

struct AppData {
  ApplicationH          app;
  Aida::BaseConnectionP connection;
};
static DurableInstance<AppData> static_appdata; // use DurableInstance to ensure app stays around for static dtors

/** Initialize Rapicorn and the main Application object.
 *
 * This funciton initializes the Rapicorn toolkit and starts an asynchronously
 * running UI thread. The UI thread creates the main Application object,
 * manages all UI related components and processes UI events.
 * .
 * The arguments passed in @a argcp and @a argv are parsed and any Rapicorn
 * specific arguments are stripped. Note that Rapicorn requires the exact argv0
 * as provided by main(). If @a argv[0] as passed into this function is empty or
 * otherwise altered, the correct value needs to be supplied previously by a
 * call to program_argv0_init().
 * If 'testing=1' is passed in @a args, these command line arguments are supported:
 * - @c --test-verbose - Execute test cases with verbose message generation.
 * - @c --test-slow - Execute only test cases excercising slow code paths or loops.
 * .
 * The initialization arguments currenlty supported for @a args are as follows:
 * - @c autonomous - Avoid loading external rc-files or other configurations that could affect test runs.
 * - @c cpu-affinity - The CPU# to bind the Rapicorn UI thread to.
 * - @c testing - Enable testing framework, used by init_core_test(), see also #$RAPICORN_TEST.
 * - @c test-verbose - acts like --test-verbose.
 * - @c test-slow - acts like --test-slow.
 * .
 * Additionally, the @c $RAPICORN environment variable affects toolkit behaviour. It supports
 * multiple colon (':') separated options (options can be prfixed with 'no-' to disable):
 * - @c debug - Enables verbose debugging output (default=off).
 * - @c fatal-syslog - Fatal program conditions that lead to aborting are recorded via syslog (default=on).
 * - @c syslog - Critical and warning conditions are recorded via syslog (default=off).
 * - @c fatal-warnings - Critical and warning conditions are treated as fatal conditions (default=off).
 * - @c logfile=FILENAME - Record all messages and conditions into FILENAME.
 * .
 * @param application_name Possibly localized string useful to display the application name in user interfaces.
 * @param argcp         Location of the 'argc' argument to main()
 * @param argv          Location of the 'argv' arguments to main()
 * @param args          Rapicorn initialization arguments.
 */
ApplicationH
init_app (const String &application_name, int *argcp, char **argv, const StringVector &args)
{
  return_unless (static_appdata->app == NULL, static_appdata->app);
  // assert global_ctors work
  if (__staticctortest.v != 0x123caca0)
    fatal ("%s: link error: C++ constructors have not been executed", __func__);
  // full locale initialization is needed by X11, etc
  if (!setlocale (LC_ALL,""))
    {
      const auto sgetenv = [] (const char *var)  {
        const char *str = getenv (var);
        return str ? str : "";
      };
      String lv = string_format ("LANGUAGE=%s;LC_ALL=%s;LC_MONETARY=%s;LC_MESSAGES=%s;LC_COLLATE=%s;LC_CTYPE=%s;LC_TIME=%s;LANG=%s",
                                 sgetenv ("LANGUAGE"), sgetenv ("LC_ALL"), sgetenv ("LC_MONETARY"), sgetenv ("LC_MESSAGES"),
                                 sgetenv ("LC_COLLATE"), sgetenv ("LC_CTYPE"), sgetenv ("LC_TIME"), sgetenv ("LANG"));
      SDEBUG ("environment: %s", lv.c_str());
      setlocale (LC_ALL, "C");
      SDEBUG ("failed to initialize locale, falling back to \"C\"");
    }
  // initialize i18n functions
  RapicornInternal::init_rapicorn_gettext (RAPICORN_GETTEXT_DOMAIN);
  // miscellaneous sub systems
  {
    const String ci = cpu_info(); // initialize cpu info
    (void) ci;
  }
  // initialize core
  parse_init_args (argcp, argv, args);
  // boot up UI thread
  const bool boot_ok = RapicornInternal::uithread_bootup (argcp, argv, args);
  if (!boot_ok)
    fatal ("%s: failed to start Rapicorn UI thread: %s", __func__, strerror (errno));
  // connect to remote UIThread and fetch main handle
  static_appdata->connection = Aida::ClientConnection::connect ("inproc://Rapicorn-" RAPICORN_VERSION);
  if (!static_appdata->connection)
    fatal ("%s: failed to connect to Rapicorn UI thread: %s", __func__, strerror (errno));
  static_appdata->app = static_appdata->connection->remote_origin<ApplicationHandle>();
  if (!static_appdata->app)
    fatal ("%s: failed to retrieve Rapicorn::Application object: %s", __func__, strerror (errno));
  if (!application_name.empty())
    static_appdata->app.setup (application_name, "");
  return static_appdata->app;
}

ApplicationH
ApplicationH::the ()
{
  return static_appdata->app;
}

class AppSource;
typedef std::shared_ptr<AppSource> AppSourceP;

class AppSource : public EventSource {
  Rapicorn::Aida::BaseConnection &connection_;
  PollFD pfd_;
  bool   last_seen_primary, need_check_primary;
  void
  check_primaries()
  {
    // seen_primary is merely a hint, need to check local and remote states
    if (main_loop() && main_loop()->finishable() &&     // local
        ApplicationH::the().finishable() &&             // remote
        main_loop()->finishable())                      // still finishable after remote call
      main_loop()->quit();
  }
  AppSource (Rapicorn::Aida::BaseConnection &connection) :
    connection_ (connection), last_seen_primary (false), need_check_primary (false)
  {
    pfd_.fd = connection_.notify_fd();
    pfd_.events = PollFD::IN;
    pfd_.revents = 0;
    add_poll (&pfd_);
    primary (false);
    ApplicationH::the().sig_missing_primary() += [this]() { queue_check_primaries(); };
  }
  virtual bool
  prepare (const LoopState &state, int64 *timeout_usecs_p)
  {
    return need_check_primary || connection_.pending();
  }
  virtual bool
  check (const LoopState &state)
  {
    if (UNLIKELY (last_seen_primary && !state.seen_primary && !need_check_primary))
      need_check_primary = true;
    last_seen_primary = state.seen_primary;
    return need_check_primary || connection_.pending();
  }
  virtual bool
  dispatch (const LoopState &state)
  {
    connection_.dispatch();
    if (need_check_primary)
      {
        need_check_primary = false;
        queue_check_primaries();
      }
    return true;
  }
  friend class FriendAllocator<AppSource>;
public:
  static AppSourceP create (Rapicorn::Aida::BaseConnection &connection)
  { return FriendAllocator<AppSource>::make_shared (connection); }
  void
  queue_check_primaries()
  {
    if (loop_)
      loop_->exec_idle (Aida::slot (*this, &AppSource::check_primaries));
  }
};

} // Rapicorn

// compile client-side API
#include "clientapi.cc"

#include <rcore/testutils.hh>
namespace Rapicorn {
MainLoopP
ApplicationH::main_loop()
{
  static const MainLoopP app_loop = [] () {
    ApplicationH the_app = the();
    assert (the_app != NULL);
    MainLoopP main_loop = MainLoop::create();
    AppSourceP source = AppSource::create (*the_app.__aida_connection__());
    main_loop->add (source);
    source->queue_check_primaries();
    return main_loop;
  } ();
  return app_loop;
}

/**
 * Initialize Rapicorn like init_app(), and boots up the test suite framework.
 * Normally, Test::run() should be called next to execute all unit tests.
 */
ApplicationH
init_test_app (const String &application_name, int *argcp, char **argv, const StringVector &args)
{
  RapicornInternal::inject_init_args (":autonomous:testing:fatal-warnings:");
  ApplicationH app = init_app (application_name, argcp, argv, args);
  return app;
}

/**
 * Cause the application's main loop to quit, and run() to return @a quit_code.
 */
void
ApplicationH::quit (int quit_code)
{
  main_loop()->quit (quit_code);
}

/**
 * Run the main event loop until all primary sources ceased to exist
 * (see MainLoop::finishable()) or until the loop is quit.
 * @returns the @a quit_code passed in to loop_quit() or 0.
 */
int
ApplicationH::run ()
{
  return main_loop()->run();
}

/**
 * This function runs the Application main loop via loop_run(), and exits
 * the running process once the loop has quit. The loop_quit() status is
 * passed on to exit() and thus to the parent process.
 */
int
ApplicationH::run_and_exit ()
{
  int status = run();
  shutdown();
  ::exit (status);
}

/// Perform one loop iteration and return whether more iterations are needed.
bool
ApplicationH::iterate (bool block)
{
  return main_loop()->iterate (block);
}

/**
 * This function causes proper termination of Rapicorn's concurrently running
 * ui-thread and needs to be called before exit(3posix), to avoid parallel
 * execution of the ui-thread while atexit(3posix) handlers or while global
 * destructors are releasing process resources.
 */
void
ApplicationH::shutdown()
{
  RapicornInternal::uithread_shutdown();
}

} // Rapicorn

namespace RapicornInternal {

// internal function for tests
int64
client_app_test_hook ()
{
  return ApplicationH::the().test_hook();
}

} // RapicornInternal
<|endoftext|>