<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "product.h"

void test_product_large()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( product(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
    CALL_SUBTEST_2( product(MatrixXd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
    CALL_SUBTEST_3( product(MatrixXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
    CALL_SUBTEST_4( product(MatrixXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2), internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2))) );
    CALL_SUBTEST_5( product(Matrix<float,Dynamic,Dynamic,RowMajor>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
  }

#if defined EIGEN_TEST_PART_6
  {
    // test a specific issue in DiagonalProduct
    int N = 1000000;
    VectorXf v = VectorXf::Ones(N);
    MatrixXf m = MatrixXf::Ones(N,3);
    m = (v+v).asDiagonal() * m;
    VERIFY_IS_APPROX(m, MatrixXf::Constant(N,3,2));
  }

  {
    // test deferred resizing in Matrix::operator=
    MatrixXf a = MatrixXf::Random(10,4), b = MatrixXf::Random(4,10), c = a;
    VERIFY_IS_APPROX((a = a * b), (c * b).eval());
  }

  {
    // check the functions to setup blocking sizes compile and do not segfault
    // FIXME check they do what they are supposed to do !!
    std::ptrdiff_t l1 = internal::random<int>(10000,20000);
    std::ptrdiff_t l2 = internal::random<int>(1000000,2000000);
    setCpuCacheSizes(l1,l2);
    VERIFY(l1==l1CacheSize());
    VERIFY(l2==l2CacheSize());
    std::ptrdiff_t k1 = internal::random<int>(10,100)*16;
    std::ptrdiff_t m1 = internal::random<int>(10,100)*16;
    std::ptrdiff_t n1 = internal::random<int>(10,100)*16;
    // only makes sure it compiles fine
    internal::computeProductBlockingSizes<float,float>(k1,m1,n1);
  }

  {
    // test regression in row-vector by matrix (bad Map type)
    MatrixXf mat1(10,32); mat1.setRandom();
    MatrixXf mat2(32,32); mat2.setRandom();
    MatrixXf r1 = mat1.row(2)*mat2.transpose();
    VERIFY_IS_APPROX(r1, (mat1.row(2)*mat2.transpose()).eval());

    MatrixXf r2 = mat1.row(2)*mat2;
    VERIFY_IS_APPROX(r2, (mat1.row(2)*mat2).eval());
  }
#endif
}
<commit_msg>Regression test for bug 714. Note that the bug only occurs on some compilers and is not fixed yet<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "product.h"

void test_product_large()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( product(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
    CALL_SUBTEST_2( product(MatrixXd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
    CALL_SUBTEST_3( product(MatrixXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
    CALL_SUBTEST_4( product(MatrixXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2), internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2))) );
    CALL_SUBTEST_5( product(Matrix<float,Dynamic,Dynamic,RowMajor>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
  }

#if defined EIGEN_TEST_PART_6
  {
    // test a specific issue in DiagonalProduct
    int N = 1000000;
    VectorXf v = VectorXf::Ones(N);
    MatrixXf m = MatrixXf::Ones(N,3);
    m = (v+v).asDiagonal() * m;
    VERIFY_IS_APPROX(m, MatrixXf::Constant(N,3,2));
  }

  {
    // test deferred resizing in Matrix::operator=
    MatrixXf a = MatrixXf::Random(10,4), b = MatrixXf::Random(4,10), c = a;
    VERIFY_IS_APPROX((a = a * b), (c * b).eval());
  }

  {
    // check the functions to setup blocking sizes compile and do not segfault
    // FIXME check they do what they are supposed to do !!
    std::ptrdiff_t l1 = internal::random<int>(10000,20000);
    std::ptrdiff_t l2 = internal::random<int>(1000000,2000000);
    setCpuCacheSizes(l1,l2);
    VERIFY(l1==l1CacheSize());
    VERIFY(l2==l2CacheSize());
    std::ptrdiff_t k1 = internal::random<int>(10,100)*16;
    std::ptrdiff_t m1 = internal::random<int>(10,100)*16;
    std::ptrdiff_t n1 = internal::random<int>(10,100)*16;
    // only makes sure it compiles fine
    internal::computeProductBlockingSizes<float,float>(k1,m1,n1);
  }

  {
    // test regression in row-vector by matrix (bad Map type)
    MatrixXf mat1(10,32); mat1.setRandom();
    MatrixXf mat2(32,32); mat2.setRandom();
    MatrixXf r1 = mat1.row(2)*mat2.transpose();
    VERIFY_IS_APPROX(r1, (mat1.row(2)*mat2.transpose()).eval());

    MatrixXf r2 = mat1.row(2)*mat2;
    VERIFY_IS_APPROX(r2, (mat1.row(2)*mat2).eval());
  }
#endif

  // Regression test for bug 714:
#ifdef EIGEN_HAS_OPENMP
  std::cout << "Testing omp_set_dynamic(1)\n";
  omp_set_dynamic(1);
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_6( product(Matrix<float,Dynamic,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
  }
#endif
}
<|endoftext|>


<commit_before>/*
 * This file is part of TelepathyQt4
 *
 * Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
 * Copyright (C) 2010 Nokia Corporation
 *
 * 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 <TelepathyQt4/ChannelClassSpec>

#include "TelepathyQt4/debug-internal.h"

namespace Tp
{

struct TELEPATHY_QT4_NO_EXPORT ChannelClassSpec::Private : public QSharedData
{
    Private(const QVariantMap &props = QVariantMap())
        : props(props) {}

    QVariantMap props;
};

ChannelClassSpec::ChannelClassSpec()
{
}

ChannelClassSpec::ChannelClassSpec(const ChannelClass &cc)
    : mPriv(new Private)
{
    foreach (QString key, cc.keys()) {
        setProperty(key, cc.value(key).variant());
    }
}

ChannelClassSpec::ChannelClassSpec(const QString &channelType, uint targetHandleType,
        const QVariantMap &otherProperties)
    : mPriv(new Private(otherProperties))
{
    setChannelType(channelType);
    setTargetHandleType(targetHandleType);
}

ChannelClassSpec::ChannelClassSpec(const QString &channelType, uint targetHandleType, bool requested,
        const QVariantMap &otherProperties)
    : mPriv(new Private(otherProperties))
{
    setChannelType(channelType);
    setTargetHandleType(targetHandleType);
    setRequested(requested);
}

ChannelClassSpec::ChannelClassSpec(const ChannelClassSpec &other,
        const QVariantMap &additionalProperties)
    : mPriv(other.mPriv)
{
    foreach (QString key, additionalProperties.keys()) {
        setProperty(key, additionalProperties.value(key));
    }
}

ChannelClassSpec::~ChannelClassSpec()
{
}

bool ChannelClassSpec::isValid() const
{
    return mPriv.constData() != 0 &&
        !(qdbus_cast<QString>(
                    mPriv->props.value(QLatin1String(TELEPATHY_INTERFACE_CHANNEL ".ChannelType")))
                .isEmpty()) &&
        mPriv->props.contains(QLatin1String(TELEPATHY_INTERFACE_CHANNEL ".TargetHandleType"));
}

ChannelClassSpec &ChannelClassSpec::operator=(const ChannelClassSpec &other)
{
    if (this == &other) {
        return *this;
    }

    this->mPriv = other.mPriv;
    return *this;
}

bool ChannelClassSpec::isSubsetOf(const ChannelClassSpec &other) const
{
    if (!isValid() || !other.isValid()) {
        warning() << "ChannelClassSpec comparison attempted for an invalid ChannelClassSpec";
        return false;
    }

    foreach (QString propName, mPriv->props.keys()) {
        if (!other.hasProperty(propName)) {
            return false;
        } else if (property(propName) != other.property(propName)) {
            return false;
        }
    }

    // other had all of the properties we have and they all had the same values

    return true;
}

bool ChannelClassSpec::matches(const QVariantMap &immutableProperties) const
{
    // We construct a ChannelClassSpec for comparison so the StreamedMedia props are normalized
    // consistently etc
    ChannelClassSpec other;
    foreach (QString propName, immutableProperties.keys()) {
        other.setProperty(propName, immutableProperties.value(propName));
    }
    return this->isSubsetOf(other);
}

bool ChannelClassSpec::hasProperty(const QString &qualifiedName) const
{
    return mPriv.constData() != 0 ? mPriv->props.contains(qualifiedName) : false;
}

QVariant ChannelClassSpec::property(const QString &qualifiedName) const
{
    return mPriv.constData() != 0 ? mPriv->props.value(qualifiedName) : QVariant();
}

void ChannelClassSpec::setProperty(const QString &qualifiedName, const QVariant &value)
{
    if (mPriv.constData() == 0) {
        mPriv = new Private;
    }

    // Flatten the InitialAudio/Video properties from the different media interfaces to one
    // namespace - we convert back to the correct interface when this is converted back to a
    // ChannelClass for use in e.g. client channel filters

    QString propName = qualifiedName;

    if (propName ==
            QLatin1String("org.freedesktop.Telepathy.Channel.Type.Call.DRAFT.InitialAudio")) {
        propName.replace(QLatin1String("Call.DRAFT"), QLatin1String("StreamedMedia"));
    } else if (propName ==
            QLatin1String("org.freedesktop.Telepathy.Channel.Type.Call.DRAFT.InitialVideo")) {
        propName.replace(QLatin1String("Call.DRAFT"), QLatin1String("StreamedMedia"));
    }
    // TODO add the corresponding non-draft Call properties when the interface is undrafted

    mPriv->props.insert(propName, value);
}

void ChannelClassSpec::unsetProperty(const QString &qualifiedName)
{
    if (mPriv.constData() == 0) {
        // No properties set for sure, so don't have to unset any
        return;
    }

    QString propName = qualifiedName;

    if (propName ==
            QLatin1String("org.freedesktop.Telepathy.Channel.Type.Call.DRAFT.InitialAudio")) {
        propName.replace(QLatin1String("Call.DRAFT"), QLatin1String("StreamedMedia"));
    } else if (propName ==
            QLatin1String("org.freedesktop.Telepathy.Channel.Type.Call.DRAFT.InitialVideo")) {
        propName.replace(QLatin1String("Call.DRAFT"), QLatin1String("StreamedMedia"));
    }
    // TODO add the corresponding non-draft Call properties when the interface is undrafted

    mPriv->props.remove(propName);
}

QVariantMap ChannelClassSpec::allProperties() const
{
    return mPriv.constData() != 0 ? mPriv->props : QVariantMap();
}

ChannelClass ChannelClassSpec::bareClass() const
{
    ChannelClass cc;

    if (!isValid()) {
        warning() << "Tried to convert an invalid ChannelClassSpec to a ChannelClass";
        return ChannelClass();
    }

    QVariantMap props = mPriv->props;
    foreach (QString propName, props.keys()) {
        QVariant value = props.value(propName);

        if (channelType() == QLatin1String("org.freedesktop.Telepathy.Channel.Type.Call.DRAFT")) {
            if (propName.endsWith(QLatin1String(".InitialAudio"))
                    || propName.endsWith(QLatin1String(".InitialVideo"))) {
                propName.replace(QLatin1String("StreamedMedia"), QLatin1String("Call.DRAFT"));
            }
        }
        // TODO add the corresponding non-draft Call properties when the interface is undrafted

        cc.insert(propName, QDBusVariant(value));
    }

    return cc;
}

ChannelClassSpec ChannelClassSpec::textChat(const QVariantMap &additionalProperties)
{
    static ChannelClassSpec spec;

    if (!spec.isValid()) {
        spec = ChannelClassSpec(QLatin1String(TELEPATHY_INTERFACE_CHANNEL_TYPE_TEXT),
                static_cast<uint>(HandleTypeContact));
    }

    if (additionalProperties.isEmpty()) {
        return spec;
    } else {
        return ChannelClassSpec(spec, additionalProperties);
    }
}

ChannelClassSpec ChannelClassSpec::textChatroom(const QVariantMap &additionalProperties)
{
    static ChannelClassSpec spec;

    if (!spec.isValid()) {
        spec = ChannelClassSpec(QLatin1String(TELEPATHY_INTERFACE_CHANNEL_TYPE_TEXT),
                static_cast<uint>(HandleTypeRoom));
    }

    if (additionalProperties.isEmpty()) {
        return spec;
    } else {
        return ChannelClassSpec(spec, additionalProperties);
    }
}

ChannelClassSpec ChannelClassSpec::mediaCall(const QVariantMap &additionalProperties)
{
    static ChannelClassSpec spec;

    if (!spec.isValid()) {
        spec = ChannelClassSpec(QLatin1String(TELEPATHY_INTERFACE_CHANNEL_TYPE_STREAMED_MEDIA),
                static_cast<uint>(HandleTypeContact));
    }

    if (additionalProperties.isEmpty()) {
        return spec;
    } else {
        return ChannelClassSpec(spec, additionalProperties);
    }
}

ChannelClassSpec ChannelClassSpec::mediaCallWithInitialAudio(const QVariantMap &additionalProperties)
{
    static ChannelClassSpec spec;

    if (!spec.isValid()) {
        spec = ChannelClassSpec(QLatin1String(TELEPATHY_INTERFACE_CHANNEL_TYPE_STREAMED_MEDIA),
                static_cast<uint>(HandleTypeContact));
        spec.setInitialAudio();
    }

    if (additionalProperties.isEmpty()) {
        return spec;
    } else {
        return ChannelClassSpec(spec, additionalProperties);
    }
}

ChannelClassSpec ChannelClassSpec::mediaCallWithInitialVideo(const QVariantMap &additionalProperties)
{
    static ChannelClassSpec spec;

    if (!spec.isValid()) {
        spec = ChannelClassSpec(QLatin1String(TELEPATHY_INTERFACE_CHANNEL_TYPE_STREAMED_MEDIA),
                static_cast<uint>(HandleTypeContact));
        spec.setInitialVideo();
    }

    if (additionalProperties.isEmpty()) {
        return spec;
    } else {
        return ChannelClassSpec(spec, additionalProperties);
    }
}

ChannelClassSpec ChannelClassSpec::roomList(const QVariantMap &additionalProperties)
{
    static ChannelClassSpec spec;

    if (!spec.isValid()) {
        spec = ChannelClassSpec(QLatin1String(TELEPATHY_INTERFACE_CHANNEL_TYPE_ROOM_LIST),
                static_cast<uint>(HandleTypeNone));
    }

    if (additionalProperties.isEmpty()) {
        return spec;
    } else {
        return ChannelClassSpec(spec, additionalProperties);
    }
}

ChannelClassSpec ChannelClassSpec::outgoingFileTransfer(const QVariantMap &additionalProperties)
{
    static ChannelClassSpec spec;

    if (!spec.isValid()) {
        spec = ChannelClassSpec(QLatin1String(TELEPATHY_INTERFACE_CHANNEL_TYPE_FILE_TRANSFER),
                static_cast<uint>(HandleTypeContact));
        spec.setRequested(true);
    }

    if (additionalProperties.isEmpty()) {
        return spec;
    } else {
        return ChannelClassSpec(spec, additionalProperties);
    }
}

ChannelClassSpec ChannelClassSpec::incomingFileTransfer(const QVariantMap &additionalProperties)
{
    static ChannelClassSpec spec;

    if (!spec.isValid()) {
        spec = ChannelClassSpec(QLatin1String(TELEPATHY_INTERFACE_CHANNEL_TYPE_FILE_TRANSFER),
                static_cast<uint>(HandleTypeContact));
        spec.setRequested(false);
    }

    if (additionalProperties.isEmpty()) {
        return spec;
    } else {
        return ChannelClassSpec(spec, additionalProperties);
    }
}

} // Tp
<commit_msg>Use setProperty for otherProperties too in ChannelClassSpec ctors<commit_after>/*
 * This file is part of TelepathyQt4
 *
 * Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
 * Copyright (C) 2010 Nokia Corporation
 *
 * 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 <TelepathyQt4/ChannelClassSpec>

#include "TelepathyQt4/debug-internal.h"

namespace Tp
{

struct TELEPATHY_QT4_NO_EXPORT ChannelClassSpec::Private : public QSharedData
{
    QVariantMap props;
};

ChannelClassSpec::ChannelClassSpec()
{
}

ChannelClassSpec::ChannelClassSpec(const ChannelClass &cc)
    : mPriv(new Private)
{
    foreach (QString key, cc.keys()) {
        setProperty(key, cc.value(key).variant());
    }
}

ChannelClassSpec::ChannelClassSpec(const QString &channelType, uint targetHandleType,
        const QVariantMap &otherProperties)
    : mPriv(new Private)
{
    setChannelType(channelType);
    setTargetHandleType(targetHandleType);
    foreach (QString key, otherProperties.keys()) {
        setProperty(key, otherProperties.value(key));
    }
}

ChannelClassSpec::ChannelClassSpec(const QString &channelType, uint targetHandleType, bool requested,
        const QVariantMap &otherProperties)
    : mPriv(new Private)
{
    setChannelType(channelType);
    setTargetHandleType(targetHandleType);
    setRequested(requested);
    foreach (QString key, otherProperties.keys()) {
        setProperty(key, otherProperties.value(key));
    }
}

ChannelClassSpec::ChannelClassSpec(const ChannelClassSpec &other,
        const QVariantMap &additionalProperties)
    : mPriv(other.mPriv)
{
    foreach (QString key, additionalProperties.keys()) {
        setProperty(key, additionalProperties.value(key));
    }
}

ChannelClassSpec::~ChannelClassSpec()
{
}

bool ChannelClassSpec::isValid() const
{
    return mPriv.constData() != 0 &&
        !(qdbus_cast<QString>(
                    mPriv->props.value(QLatin1String(TELEPATHY_INTERFACE_CHANNEL ".ChannelType")))
                .isEmpty()) &&
        mPriv->props.contains(QLatin1String(TELEPATHY_INTERFACE_CHANNEL ".TargetHandleType"));
}

ChannelClassSpec &ChannelClassSpec::operator=(const ChannelClassSpec &other)
{
    if (this == &other) {
        return *this;
    }

    this->mPriv = other.mPriv;
    return *this;
}

bool ChannelClassSpec::isSubsetOf(const ChannelClassSpec &other) const
{
    if (!isValid() || !other.isValid()) {
        warning() << "ChannelClassSpec comparison attempted for an invalid ChannelClassSpec";
        return false;
    }

    foreach (QString propName, mPriv->props.keys()) {
        if (!other.hasProperty(propName)) {
            return false;
        } else if (property(propName) != other.property(propName)) {
            return false;
        }
    }

    // other had all of the properties we have and they all had the same values

    return true;
}

bool ChannelClassSpec::matches(const QVariantMap &immutableProperties) const
{
    // We construct a ChannelClassSpec for comparison so the StreamedMedia props are normalized
    // consistently etc
    ChannelClassSpec other;
    foreach (QString propName, immutableProperties.keys()) {
        other.setProperty(propName, immutableProperties.value(propName));
    }
    return this->isSubsetOf(other);
}

bool ChannelClassSpec::hasProperty(const QString &qualifiedName) const
{
    return mPriv.constData() != 0 ? mPriv->props.contains(qualifiedName) : false;
}

QVariant ChannelClassSpec::property(const QString &qualifiedName) const
{
    return mPriv.constData() != 0 ? mPriv->props.value(qualifiedName) : QVariant();
}

void ChannelClassSpec::setProperty(const QString &qualifiedName, const QVariant &value)
{
    if (mPriv.constData() == 0) {
        mPriv = new Private;
    }

    // Flatten the InitialAudio/Video properties from the different media interfaces to one
    // namespace - we convert back to the correct interface when this is converted back to a
    // ChannelClass for use in e.g. client channel filters

    QString propName = qualifiedName;

    if (propName ==
            QLatin1String("org.freedesktop.Telepathy.Channel.Type.Call.DRAFT.InitialAudio")) {
        propName.replace(QLatin1String("Call.DRAFT"), QLatin1String("StreamedMedia"));
    } else if (propName ==
            QLatin1String("org.freedesktop.Telepathy.Channel.Type.Call.DRAFT.InitialVideo")) {
        propName.replace(QLatin1String("Call.DRAFT"), QLatin1String("StreamedMedia"));
    }
    // TODO add the corresponding non-draft Call properties when the interface is undrafted

    mPriv->props.insert(propName, value);
}

void ChannelClassSpec::unsetProperty(const QString &qualifiedName)
{
    if (mPriv.constData() == 0) {
        // No properties set for sure, so don't have to unset any
        return;
    }

    QString propName = qualifiedName;

    if (propName ==
            QLatin1String("org.freedesktop.Telepathy.Channel.Type.Call.DRAFT.InitialAudio")) {
        propName.replace(QLatin1String("Call.DRAFT"), QLatin1String("StreamedMedia"));
    } else if (propName ==
            QLatin1String("org.freedesktop.Telepathy.Channel.Type.Call.DRAFT.InitialVideo")) {
        propName.replace(QLatin1String("Call.DRAFT"), QLatin1String("StreamedMedia"));
    }
    // TODO add the corresponding non-draft Call properties when the interface is undrafted

    mPriv->props.remove(propName);
}

QVariantMap ChannelClassSpec::allProperties() const
{
    return mPriv.constData() != 0 ? mPriv->props : QVariantMap();
}

ChannelClass ChannelClassSpec::bareClass() const
{
    ChannelClass cc;

    if (!isValid()) {
        warning() << "Tried to convert an invalid ChannelClassSpec to a ChannelClass";
        return ChannelClass();
    }

    QVariantMap props = mPriv->props;
    foreach (QString propName, props.keys()) {
        QVariant value = props.value(propName);

        if (channelType() == QLatin1String("org.freedesktop.Telepathy.Channel.Type.Call.DRAFT")) {
            if (propName.endsWith(QLatin1String(".InitialAudio"))
                    || propName.endsWith(QLatin1String(".InitialVideo"))) {
                propName.replace(QLatin1String("StreamedMedia"), QLatin1String("Call.DRAFT"));
            }
        }
        // TODO add the corresponding non-draft Call properties when the interface is undrafted

        cc.insert(propName, QDBusVariant(value));
    }

    return cc;
}

ChannelClassSpec ChannelClassSpec::textChat(const QVariantMap &additionalProperties)
{
    static ChannelClassSpec spec;

    if (!spec.isValid()) {
        spec = ChannelClassSpec(QLatin1String(TELEPATHY_INTERFACE_CHANNEL_TYPE_TEXT),
                static_cast<uint>(HandleTypeContact));
    }

    if (additionalProperties.isEmpty()) {
        return spec;
    } else {
        return ChannelClassSpec(spec, additionalProperties);
    }
}

ChannelClassSpec ChannelClassSpec::textChatroom(const QVariantMap &additionalProperties)
{
    static ChannelClassSpec spec;

    if (!spec.isValid()) {
        spec = ChannelClassSpec(QLatin1String(TELEPATHY_INTERFACE_CHANNEL_TYPE_TEXT),
                static_cast<uint>(HandleTypeRoom));
    }

    if (additionalProperties.isEmpty()) {
        return spec;
    } else {
        return ChannelClassSpec(spec, additionalProperties);
    }
}

ChannelClassSpec ChannelClassSpec::mediaCall(const QVariantMap &additionalProperties)
{
    static ChannelClassSpec spec;

    if (!spec.isValid()) {
        spec = ChannelClassSpec(QLatin1String(TELEPATHY_INTERFACE_CHANNEL_TYPE_STREAMED_MEDIA),
                static_cast<uint>(HandleTypeContact));
    }

    if (additionalProperties.isEmpty()) {
        return spec;
    } else {
        return ChannelClassSpec(spec, additionalProperties);
    }
}

ChannelClassSpec ChannelClassSpec::mediaCallWithInitialAudio(const QVariantMap &additionalProperties)
{
    static ChannelClassSpec spec;

    if (!spec.isValid()) {
        spec = ChannelClassSpec(QLatin1String(TELEPATHY_INTERFACE_CHANNEL_TYPE_STREAMED_MEDIA),
                static_cast<uint>(HandleTypeContact));
        spec.setInitialAudio();
    }

    if (additionalProperties.isEmpty()) {
        return spec;
    } else {
        return ChannelClassSpec(spec, additionalProperties);
    }
}

ChannelClassSpec ChannelClassSpec::mediaCallWithInitialVideo(const QVariantMap &additionalProperties)
{
    static ChannelClassSpec spec;

    if (!spec.isValid()) {
        spec = ChannelClassSpec(QLatin1String(TELEPATHY_INTERFACE_CHANNEL_TYPE_STREAMED_MEDIA),
                static_cast<uint>(HandleTypeContact));
        spec.setInitialVideo();
    }

    if (additionalProperties.isEmpty()) {
        return spec;
    } else {
        return ChannelClassSpec(spec, additionalProperties);
    }
}

ChannelClassSpec ChannelClassSpec::roomList(const QVariantMap &additionalProperties)
{
    static ChannelClassSpec spec;

    if (!spec.isValid()) {
        spec = ChannelClassSpec(QLatin1String(TELEPATHY_INTERFACE_CHANNEL_TYPE_ROOM_LIST),
                static_cast<uint>(HandleTypeNone));
    }

    if (additionalProperties.isEmpty()) {
        return spec;
    } else {
        return ChannelClassSpec(spec, additionalProperties);
    }
}

ChannelClassSpec ChannelClassSpec::outgoingFileTransfer(const QVariantMap &additionalProperties)
{
    static ChannelClassSpec spec;

    if (!spec.isValid()) {
        spec = ChannelClassSpec(QLatin1String(TELEPATHY_INTERFACE_CHANNEL_TYPE_FILE_TRANSFER),
                static_cast<uint>(HandleTypeContact));
        spec.setRequested(true);
    }

    if (additionalProperties.isEmpty()) {
        return spec;
    } else {
        return ChannelClassSpec(spec, additionalProperties);
    }
}

ChannelClassSpec ChannelClassSpec::incomingFileTransfer(const QVariantMap &additionalProperties)
{
    static ChannelClassSpec spec;

    if (!spec.isValid()) {
        spec = ChannelClassSpec(QLatin1String(TELEPATHY_INTERFACE_CHANNEL_TYPE_FILE_TRANSFER),
                static_cast<uint>(HandleTypeContact));
        spec.setRequested(false);
    }

    if (additionalProperties.isEmpty()) {
        return spec;
    } else {
        return ChannelClassSpec(spec, additionalProperties);
    }
}

} // Tp
<|endoftext|>


<commit_before>/* Numenta Platform for Intelligent Computing (NuPIC)
 * Copyright (C) 2017, Numenta, Inc.  Unless you have an agreement
 * with Numenta, Inc., for a separate license for this software code, the
 * following terms and conditions apply:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero Public License for more details.
 *
 * You should have received a copy of the GNU Affero Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 *
 * http://numenta.org/licenses/
 * ---------------------------------------------------------------------
 */

#ifndef NUPIC_UTIL_SLIDING_WINDOW_HPP
#define NUPIC_UTIL_SLIDING_WINDOW_HPP

#include <vector>
#include <algorithm>

#include <nupic/types/Types.hpp>
#include <nupic/utils/Log.hpp>

namespace nupic {
  namespace util {

    template<class T>
    class SlidingWindow {
      public:
        SlidingWindow(UInt maxCapacity);
        SlidingWindow(UInt maxCapacity, std::vector<T> initialData);
        const UInt maxCapacity;
        size_t size() const;
        /** append new value to the end of the buffer and handle the "overflows"-may pop the first element if full.
        */
        void append(T newValue);

        /** like append, but return the dropped value. isValid indicates if the return value is valid (not while size()< maxCapacity)
          :param T newValue - new value to append to the sliding window
          :param bool isValid - a return pass-by-value that indicates validity of the return T value. for first maxCapacity items it is false, later always true.
          :return T dropped value (past oldest element) if isValid; if not valid, this field holds the oldest value (but still contained in the window!)
        */
        T append(T newValue, bool& isValid);

        /**
        * :return unordered content (data ) of this sl. window; call getLinearizedData() if you need them oredered from oldest->newest
        * This direct access method is fast.
        */
        const std::vector<T>& getData() const;

        /** linearize method for the internal buffer; this is slower than the pure getData() but ensures that the data are ordered (oldest at the
         * beginning, newest at the end of the vector
         * This handles case of |5,6;1,2,3,4| => |1,2,3,4,5,6|
         * :return new linearized vector
        */
        std::vector<T> getLinearizedData() const;

        bool operator==(const SlidingWindow& r2) const;
        bool operator!=(const SlidingWindow& r2) const;
        T& operator[](UInt index);
        const T& operator[](UInt index) const;

      private:
        std::vector<T> buffer_;
        UInt idxNext_;
        size_t size_;
};
}} //end ns

/// IMPLEMENTATION
#include <cmath>

using nupic::util::SlidingWindow;

template<class T>
SlidingWindow<T>::SlidingWindow(nupic::UInt maxCapacity) :
  maxCapacity(maxCapacity) {
  NTA_CHECK(maxCapacity > 0);
  buffer_.reserve(maxCapacity);
  buffer_.resize(maxCapacity);
  idxNext_ = 0;
  size_ = 0;
}

template<class T>
SlidingWindow<T>::SlidingWindow(nupic::UInt maxCapacity, std::vector<T> initialData)  :
  SlidingWindow(maxCapacity) {
  auto sz = std::min(initialData.size(), (size_t)maxCapacity);
  buffer_.insert(std::begin(buffer_), std::end(initialData) - sz, std::end(initialData));
  buffer_.resize(sz);
  idxNext_ = sz % maxCapacity;
  size_ = sz;
}

template<class T>
size_t SlidingWindow<T>::size() const {
  NTA_ASSERT(buffer_.size() <= maxCapacity);
  return std::min(size_, (size_t)maxCapacity);
}

template<class T>
void SlidingWindow<T>::append(T newValue) {
    buffer_[idxNext_] = newValue;
    idxNext_ = ++idxNext_ %maxCapacity;//the assignment must be out of the [] above -not [idxNext_++%maxCap]- because we want to store the value %maxCap, not only ++
  ++size_;
}

template<class T>
T SlidingWindow<T>::append(T newValue, bool& isValid) {
  T old = buffer_.empty() ? newValue : buffer_[idxNext_]; //handle case of empty buffer (access buff[0]), otherwise return oldest elem
  isValid = (buffer_.size()==maxCapacity); //only in this case we drop oldest; this happens always after first maxCap steps ; must be checked before append()
  append(newValue);
  return old;
}

template<class T>
const std::vector<T>& SlidingWindow<T>::getData() const {
  return buffer_; //may contain trailing "zeros"
}

template<class T>
std::vector<T> SlidingWindow<T>::getLinearizedData() const {
  std::vector<T> lin;
  lin.reserve(buffer_.size());

  lin.insert(std::begin(lin), std::begin(buffer_) + idxNext_, std::end(buffer_)); //insert the "older" part at the beginning
  lin.insert(std::end(lin), std::begin(buffer_), std::begin(buffer_) + idxNext_); //append the "newer" part to the end of the constructed vect
 return lin;
}

template<class T>
bool SlidingWindow<T>::operator==(const SlidingWindow& r2) const //FIXME review the ==, on my machine it randomly passes/fails the test!
{
  return ((this->size() == r2.size()) && (this->maxCapacity == r2.maxCapacity) &&
    (this->getData()== r2.getData()) );
}

template<class T>
bool SlidingWindow<T>::operator!=(const SlidingWindow& r2) const
{
  return !operator==(r2);
}

template<class T>
T& SlidingWindow<T>::operator[](nupic::UInt index) {
  NTA_ASSERT(index <= size());
  return &buffer_[index];
}

template<class T>
const T& SlidingWindow<T>::operator[](nupic::UInt index) const {
  return this->operator[](index); //call the overloaded operator[] above
}

#endif //header
<commit_msg>SlidingWindow: code fits 80-len lines<commit_after>/* Numenta Platform for Intelligent Computing (NuPIC)
 * Copyright (C) 2017, Numenta, Inc.  Unless you have an agreement
 * with Numenta, Inc., for a separate license for this software code, the
 * following terms and conditions apply:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero Public License for more details.
 *
 * You should have received a copy of the GNU Affero Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 *
 * http://numenta.org/licenses/
 * ---------------------------------------------------------------------
 */

#ifndef NUPIC_UTIL_SLIDING_WINDOW_HPP
#define NUPIC_UTIL_SLIDING_WINDOW_HPP

#include <vector>
#include <algorithm>

#include <nupic/types/Types.hpp>
#include <nupic/utils/Log.hpp>

namespace nupic {
  namespace util {

    template<class T>
    class SlidingWindow {
      public:
        SlidingWindow(UInt maxCapacity);
        SlidingWindow(UInt maxCapacity, std::vector<T> initialData);
        const UInt maxCapacity;
        size_t size() const;
        /** append new value to the end of the buffer and handle the
           "overflows"-may pop the first element if full.
        */
        void append(T newValue);

        /** like append, but return the dropped value. isValid indicates
            if the return value is valid (not while size()< maxCapacity)
          :param T newValue - new value to append to the sliding window
          :param bool isValid - a return pass-by-value that indicates validity
             of the return T value. for first maxCapacity items it is false,
             later always true.
          :return T dropped value (past oldest element) if isValid;
             if not valid, this field holds the oldest value
             (but still contained in the window!)
        */
        T append(T newValue, bool& isValid);

        /**
        * :return unordered content (data ) of this sl. window;
             call getLinearizedData() if you need them oredered from
             oldest->newest
        * This direct access method is fast.
        */
        const std::vector<T>& getData() const;

        /** linearize method for the internal buffer; this is slower than
            the pure getData() but ensures that the data are ordered (oldest at
             the beginning, newest at the end of the vector
         * This handles case of |5,6;1,2,3,4| => |1,2,3,4,5,6|
         * :return new linearized vector
        */
        std::vector<T> getLinearizedData() const;

        bool operator==(const SlidingWindow& r2) const;
        bool operator!=(const SlidingWindow& r2) const;
        T& operator[](UInt index);
        const T& operator[](UInt index) const;

      private:
        std::vector<T> buffer_;
        UInt idxNext_;
        size_t size_;
};
}} //end ns

/// IMPLEMENTATION
#include <cmath>

using nupic::util::SlidingWindow;

template<class T>
SlidingWindow<T>::SlidingWindow(nupic::UInt maxCapacity) :
  maxCapacity(maxCapacity) {
  NTA_CHECK(maxCapacity > 0);
  buffer_.reserve(maxCapacity);
  buffer_.resize(maxCapacity);
  idxNext_ = 0;
  size_ = 0;
}

template<class T>
SlidingWindow<T>::SlidingWindow(nupic::UInt maxCapacity, std::vector<T> initialData)  :
  SlidingWindow(maxCapacity) {
  auto sz = std::min(initialData.size(), (size_t)maxCapacity);
  buffer_.insert(std::begin(buffer_), std::end(initialData) - sz, std::end(initialData));
  buffer_.resize(sz);
  idxNext_ = sz % maxCapacity;
  size_ = sz;
}

template<class T>
size_t SlidingWindow<T>::size() const {
  NTA_ASSERT(buffer_.size() <= maxCapacity);
  return std::min(size_, (size_t)maxCapacity);
}

template<class T>
void SlidingWindow<T>::append(T newValue) {
  buffer_[idxNext_] = newValue;
  //the assignment must be out of the [] above, so not [idxNext_++%maxCap],
  // because we want to store the value %maxCap, not only ++
  idxNext_ = ++idxNext_ %maxCapacity;
  ++size_;
}

template<class T>
T SlidingWindow<T>::append(T newValue, bool& isValid) {
  //handle case of empty buffer (access buff[0]), otherwise return oldest elem
  T old = buffer_.empty() ? newValue : buffer_[idxNext_];
  //only in this case we drop oldest; this happens always after
  //first maxCap steps ; must be checked before append()
  isValid = (buffer_.size()==maxCapacity);
  append(newValue);
  return old;
}

template<class T>
const std::vector<T>& SlidingWindow<T>::getData() const {
  return buffer_; //may contain trailing "zeros"
}

template<class T>
std::vector<T> SlidingWindow<T>::getLinearizedData() const {
  std::vector<T> lin;
  lin.reserve(buffer_.size());

  //insert the "older" part at the beginning
  lin.insert(std::begin(lin), std::begin(buffer_) + idxNext_, std::end(buffer_));
  //append the "newer" part to the end of the constructed vect
  lin.insert(std::end(lin), std::begin(buffer_), std::begin(buffer_) + idxNext_);
 return lin;
}

template<class T>
bool SlidingWindow<T>::operator==(const SlidingWindow& r2) const {
  return ((this->size() == r2.size()) && (this->maxCapacity == r2.maxCapacity) &&
    (this->getData()== r2.getData()) );
  //FIXME review the ==, on my machine it randomly passes/fails the test!
}

template<class T>
bool SlidingWindow<T>::operator!=(const SlidingWindow& r2) const {
  return !operator==(r2);
}

template<class T>
T& SlidingWindow<T>::operator[](nupic::UInt index) {
  NTA_ASSERT(index <= size());
  return &buffer_[index];
}

template<class T>
const T& SlidingWindow<T>::operator[](nupic::UInt index) const {
  return this->operator[](index); //call the overloaded operator[] above
}

#endif //header
<|endoftext|>


<commit_before>
#include "CGUIManager.h"
#include <glad/glad.h>

namespace ion
{

	// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure)
	// If text or lines are blurry when integrating ImGui in your engine:
	// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f)
	void CGUIManager::DrawCallback(ImDrawData* draw_data)
	{
		Window->MakeContextCurrent();

		// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled
		GLint last_program, last_texture;
		glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
		glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
		glEnable(GL_BLEND);
		glBlendEquation(GL_FUNC_ADD);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glDisable(GL_CULL_FACE);
		glDisable(GL_DEPTH_TEST);
		glEnable(GL_SCISSOR_TEST);
		glActiveTexture(GL_TEXTURE0);

		// Setup orthographic projection matrix
		const float width = ImGui::GetIO().DisplaySize.x;
		const float height = ImGui::GetIO().DisplaySize.y;
		const float ortho_projection[4][4] =
		{
			{ 2.0f / width, 0.0f, 0.0f, 0.0f },
			{ 0.0f, 2.0f / -height, 0.0f, 0.0f },
			{ 0.0f, 0.0f, -1.0f, 0.0f },
			{ -1.0f, 1.0f, 0.0f, 1.0f },
		};
		glUseProgram(ShaderHandle);
		glUniform1i(AttribLocationTex, 0);
		glUniformMatrix4fv(AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
		glBindVertexArray(VaoHandle);

		for (int n = 0; n < draw_data->CmdListsCount; n++)
		{
			const ImDrawList* cmd_list = draw_data->CmdLists[n];
			const ImDrawIdx* idx_buffer = &cmd_list->IdxBuffer.front();

			glBindBuffer(GL_ARRAY_BUFFER, VboHandle);
			int needed_vtx_size = cmd_list->VtxBuffer.size() * sizeof(ImDrawVert);
			if (VboSize < needed_vtx_size)
			{
				// Grow our buffer if needed
				VboSize = needed_vtx_size + 2000 * sizeof(ImDrawVert);
				glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr) VboSize, NULL, GL_STREAM_DRAW);
			}

			unsigned char* vtx_data = (unsigned char*) glMapBufferRange(GL_ARRAY_BUFFER, 0, needed_vtx_size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
			if (!vtx_data)
				continue;
			memcpy(vtx_data, &cmd_list->VtxBuffer[0], cmd_list->VtxBuffer.size() * sizeof(ImDrawVert));
			glUnmapBuffer(GL_ARRAY_BUFFER);

			for (const ImDrawCmd* pcmd = cmd_list->CmdBuffer.begin(); pcmd != cmd_list->CmdBuffer.end(); pcmd++)
			{
				if (pcmd->UserCallback)
				{
					pcmd->UserCallback(cmd_list, pcmd);
				}
				else
				{
					glBindTexture(GL_TEXTURE_2D, (GLuint) (intptr_t) pcmd->TextureId);
					glScissor((int) pcmd->ClipRect.x, (int) (height - pcmd->ClipRect.w), (int) (pcmd->ClipRect.z - pcmd->ClipRect.x), (int) (pcmd->ClipRect.w - pcmd->ClipRect.y));
					glDrawElements(GL_TRIANGLES, (GLsizei) pcmd->ElemCount, GL_UNSIGNED_SHORT, idx_buffer);
				}
				idx_buffer += pcmd->ElemCount;
			}
		}

		// Restore modified state
		glBindVertexArray(0);
		glBindBuffer(GL_ARRAY_BUFFER, 0);
		glUseProgram(last_program);
		glDisable(GL_SCISSOR_TEST);
		glEnable(GL_DEPTH_TEST);
		glBindTexture(GL_TEXTURE_2D, last_texture);
	}

	void CGUIManager::OnEvent(IEvent & Event)
	{
		ImGuiIO& io = ImGui::GetIO();

		if (InstanceOf<SKeyboardEvent>(Event))
		{
			SKeyboardEvent KeyboardEvent = As<SKeyboardEvent>(Event);
			io.KeysDown[(int) KeyboardEvent.Key] = KeyboardEvent.Pressed;
			io.KeyCtrl = Window->IsKeyDown(EKey::LeftControl) || Window->IsKeyDown(EKey::RightControl);
			io.KeyShift = Window->IsKeyDown(EKey::LeftShift) || Window->IsKeyDown(EKey::RightShift);
			io.KeyAlt = Window->IsKeyDown(EKey::LeftAlt) || Window->IsKeyDown(EKey::RightAlt);
		}
		else if (InstanceOf<SMouseEvent>(Event))
		{
			SMouseEvent MouseEvent = As<SMouseEvent>(Event);
			switch (MouseEvent.Type)
			{
			case SMouseEvent::EType::Click:
				MousePressed[(int) MouseEvent.Button] = MouseEvent.Pressed;
				break;
			case SMouseEvent::EType::Move:
				break;
			case SMouseEvent::EType::Scroll:
				MouseWheel += MouseEvent.Movement.Y;
				break;
			}
		}
		else if (InstanceOf<SCharacterEvent>(Event))
		{
			SCharacterEvent CharacterEvent = As<SCharacterEvent>(Event);
			if (CharacterEvent.C > 0)
				io.AddInputCharacter(CharacterEvent.C);
		}
	}

	void CGUIManager::CreateFontsTexture()
	{
		ImGuiIO& io = ImGui::GetIO();

		unsigned char* pixels;
		int width, height;
		io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);   // Load as RGBA 32-bits for OpenGL3 demo because it is more likely to be compatible with user's existing shader.

		glGenTextures(1, &FontTexture);
		glBindTexture(GL_TEXTURE_2D, FontTexture);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);

		// Store our identifier
		io.Fonts->TexID = (void *) (intptr_t) FontTexture;
	}

	void CGUIManager::AddFontFromFile(string const & FileName, float const Size)
	{
		ImGuiIO& io = ImGui::GetIO();
		ImFont* my_font = io.Fonts->AddFontFromFileTTF(FileName.c_str(), Size);
	}

	bool CGUIManager::CreateDeviceObjects()
	{
		Window->MakeContextCurrent();

		const GLchar *vertex_shader =
			"#version 330\n"
			"uniform mat4 ProjMtx;\n"
			"in vec2 Position;\n"
			"in vec2 UV;\n"
			"in vec4 Color;\n"
			"out vec2 Frag_UV;\n"
			"out vec4 Frag_Color;\n"
			"void main()\n"
			"{\n"
			"	Frag_UV = UV;\n"
			"	Frag_Color = Color;\n"
			"	gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
			"}\n";

		const GLchar* fragment_shader =
			"#version 330\n"
			"uniform sampler2D Texture;\n"
			"in vec2 Frag_UV;\n"
			"in vec4 Frag_Color;\n"
			"out vec4 Out_Color;\n"
			"void main()\n"
			"{\n"
			"	Out_Color = Frag_Color * texture( Texture, Frag_UV.st);\n"
			"}\n";

		ShaderHandle = glCreateProgram();
		VertHandle = glCreateShader(GL_VERTEX_SHADER);
		FragHandle = glCreateShader(GL_FRAGMENT_SHADER);
		glShaderSource(VertHandle, 1, &vertex_shader, 0);
		glShaderSource(FragHandle, 1, &fragment_shader, 0);
		glCompileShader(VertHandle);
		glCompileShader(FragHandle);
		glAttachShader(ShaderHandle, VertHandle);
		glAttachShader(ShaderHandle, FragHandle);
		glLinkProgram(ShaderHandle);

		AttribLocationTex = glGetUniformLocation(ShaderHandle, "Texture");
		AttribLocationProjMtx = glGetUniformLocation(ShaderHandle, "ProjMtx");
		AttribLocationPosition = glGetAttribLocation(ShaderHandle, "Position");
		AttribLocationUV = glGetAttribLocation(ShaderHandle, "UV");
		AttribLocationColor = glGetAttribLocation(ShaderHandle, "Color");

		glGenBuffers(1, &VboHandle);
		glGenVertexArrays(1, &VaoHandle);
		glBindVertexArray(VaoHandle);
		glBindBuffer(GL_ARRAY_BUFFER, VboHandle);
		glEnableVertexAttribArray(AttribLocationPosition);
		glEnableVertexAttribArray(AttribLocationUV);
		glEnableVertexAttribArray(AttribLocationColor);

#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT))
		glVertexAttribPointer(AttribLocationPosition, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*) OFFSETOF(ImDrawVert, pos));
		glVertexAttribPointer(AttribLocationUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*) OFFSETOF(ImDrawVert, uv));
		glVertexAttribPointer(AttribLocationColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*) OFFSETOF(ImDrawVert, col));
#undef OFFSETOF
		glBindVertexArray(0);
		glBindBuffer(GL_ARRAY_BUFFER, 0);

		CreateFontsTexture();

		return true;
	}

	void ImGui_ImplGlfwGL3_RenderDrawLists(ImDrawData* draw_data)
	{
		SingletonPointer<CGUIManager> ImGUIManager;
		ImGUIManager->DrawCallback(draw_data);
	}

	char const * ImGui_ImplGlfwGL3_GetClipboardText()
	{
		SingletonPointer<CGUIManager> ImGUIManager;
		return ImGUIManager->Window->GetClipboardText().c_str();
	}

	void ImGui_ImplGlfwGL3_SetClipboardText(const char* text)
	{
		SingletonPointer<CGUIManager> ImGUIManager;
		ImGUIManager->Window->SetClipboardText(text);
	}

	bool CGUIManager::Init(CWindow* window)
	{
		Window = window;

		ImGuiIO& io = ImGui::GetIO();
		io.KeyMap[ImGuiKey_Tab] = (int) EKey::Tab;
		io.KeyMap[ImGuiKey_LeftArrow] = (int) EKey::Left;
		io.KeyMap[ImGuiKey_RightArrow] = (int) EKey::Right;
		io.KeyMap[ImGuiKey_UpArrow] = (int) EKey::Up;
		io.KeyMap[ImGuiKey_DownArrow] = (int) EKey::Down;
		io.KeyMap[ImGuiKey_Home] = (int) EKey::Home;
		io.KeyMap[ImGuiKey_End] = (int) EKey::End;
		io.KeyMap[ImGuiKey_Delete] = (int) EKey::Delete;
		io.KeyMap[ImGuiKey_Backspace] = (int) EKey::Backspace;
		io.KeyMap[ImGuiKey_Enter] = (int) EKey::Return;
		io.KeyMap[ImGuiKey_Escape] = (int) EKey::Escape;
		io.KeyMap[ImGuiKey_A] = (int) EKey::A;
		io.KeyMap[ImGuiKey_C] = (int) EKey::C;
		io.KeyMap[ImGuiKey_V] = (int) EKey::V;
		io.KeyMap[ImGuiKey_X] = (int) EKey::X;
		io.KeyMap[ImGuiKey_Y] = (int) EKey::Y;
		io.KeyMap[ImGuiKey_Z] = (int) EKey::Z;

		io.RenderDrawListsFn = ImGui_ImplGlfwGL3_RenderDrawLists;
		io.SetClipboardTextFn = ImGui_ImplGlfwGL3_SetClipboardText;
		io.GetClipboardTextFn = ImGui_ImplGlfwGL3_GetClipboardText;

		io.IniFilename = nullptr;

		return true;
	}

	void CGUIManager::Shutdown()
	{
		Window->MakeContextCurrent();

		if (VaoHandle) glDeleteVertexArrays(1, &VaoHandle);
		if (VboHandle) glDeleteBuffers(1, &VboHandle);
		VaoHandle = 0;
		VboHandle = 0;

		glDetachShader(ShaderHandle, VertHandle);
		glDeleteShader(VertHandle);
		VertHandle = 0;

		glDetachShader(ShaderHandle, FragHandle);
		glDeleteShader(FragHandle);
		FragHandle = 0;

		glDeleteProgram(ShaderHandle);
		ShaderHandle = 0;

		if (FontTexture)
		{
			glDeleteTextures(1, &FontTexture);
			ImGui::GetIO().Fonts->TexID = 0;
			FontTexture = 0;
		}
		ImGui::Shutdown();
	}

	void CGUIManager::NewFrame()
	{
		static int frame = 0;
		SingletonPointer<CTimeManager> TimeManager;

		if (! FontTexture)
			CreateDeviceObjects();

		ImGuiIO& io = ImGui::GetIO();

		// Setup display size (every frame to accommodate for window resizing)
		io.DisplaySize = ImVec2((float) Window->GetSize().X, (float) Window->GetSize().Y);

		// Setup time step
		double current_time = TimeManager->GetRunTime();
		io.DeltaTime = Time > 0.0 ? (float) (current_time - Time) : (float) (1.0f / 60.0f);
		Time = current_time;

		// Setup inputs
		// (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents())
		if (Window->IsFocused())
		{
			double mouse_x, mouse_y;
			mouse_x = Window->GetCursorLocation().X;
			mouse_y = Window->GetCursorLocation().Y;
			io.MousePos = ImVec2((float) mouse_x, (float) mouse_y);   // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.)
		}
		else
		{
			io.MousePos = ImVec2(-1, -1);
		}

		for (int i = 0; i < 3; i++)
		{
			io.MouseDown[i] = MousePressed[i] || Window->IsMouseDown((SMouseEvent::EButton) i);    // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
			MousePressed[i] = false;
		}

		io.MouseWheel = MouseWheel;
		MouseWheel = 0;

		// Start the frame
		ImGui::NewFrame();
	}

	CGUIManager::CGUIManager()
	{
		for (int i = 0; i < 3; ++ i)
			MousePressed[i] = false;
	}

}
<commit_msg>[ionGui] GUIManager blocks click events if mouse is over GUI<commit_after>
#include "CGUIManager.h"
#include <glad/glad.h>

namespace ion
{

	// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure)
	// If text or lines are blurry when integrating ImGui in your engine:
	// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f)
	void CGUIManager::DrawCallback(ImDrawData* draw_data)
	{
		Window->MakeContextCurrent();

		// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled
		GLint last_program, last_texture;
		glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
		glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
		glEnable(GL_BLEND);
		glBlendEquation(GL_FUNC_ADD);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glDisable(GL_CULL_FACE);
		glDisable(GL_DEPTH_TEST);
		glEnable(GL_SCISSOR_TEST);
		glActiveTexture(GL_TEXTURE0);

		// Setup orthographic projection matrix
		const float width = ImGui::GetIO().DisplaySize.x;
		const float height = ImGui::GetIO().DisplaySize.y;
		const float ortho_projection[4][4] =
		{
			{ 2.0f / width, 0.0f, 0.0f, 0.0f },
			{ 0.0f, 2.0f / -height, 0.0f, 0.0f },
			{ 0.0f, 0.0f, -1.0f, 0.0f },
			{ -1.0f, 1.0f, 0.0f, 1.0f },
		};
		glUseProgram(ShaderHandle);
		glUniform1i(AttribLocationTex, 0);
		glUniformMatrix4fv(AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
		glBindVertexArray(VaoHandle);

		for (int n = 0; n < draw_data->CmdListsCount; n++)
		{
			const ImDrawList* cmd_list = draw_data->CmdLists[n];
			const ImDrawIdx* idx_buffer = &cmd_list->IdxBuffer.front();

			glBindBuffer(GL_ARRAY_BUFFER, VboHandle);
			int needed_vtx_size = cmd_list->VtxBuffer.size() * sizeof(ImDrawVert);
			if (VboSize < needed_vtx_size)
			{
				// Grow our buffer if needed
				VboSize = needed_vtx_size + 2000 * sizeof(ImDrawVert);
				glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr) VboSize, NULL, GL_STREAM_DRAW);
			}

			unsigned char* vtx_data = (unsigned char*) glMapBufferRange(GL_ARRAY_BUFFER, 0, needed_vtx_size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
			if (!vtx_data)
				continue;
			memcpy(vtx_data, &cmd_list->VtxBuffer[0], cmd_list->VtxBuffer.size() * sizeof(ImDrawVert));
			glUnmapBuffer(GL_ARRAY_BUFFER);

			for (const ImDrawCmd* pcmd = cmd_list->CmdBuffer.begin(); pcmd != cmd_list->CmdBuffer.end(); pcmd++)
			{
				if (pcmd->UserCallback)
				{
					pcmd->UserCallback(cmd_list, pcmd);
				}
				else
				{
					glBindTexture(GL_TEXTURE_2D, (GLuint) (intptr_t) pcmd->TextureId);
					glScissor((int) pcmd->ClipRect.x, (int) (height - pcmd->ClipRect.w), (int) (pcmd->ClipRect.z - pcmd->ClipRect.x), (int) (pcmd->ClipRect.w - pcmd->ClipRect.y));
					glDrawElements(GL_TRIANGLES, (GLsizei) pcmd->ElemCount, GL_UNSIGNED_SHORT, idx_buffer);
				}
				idx_buffer += pcmd->ElemCount;
			}
		}

		// Restore modified state
		glBindVertexArray(0);
		glBindBuffer(GL_ARRAY_BUFFER, 0);
		glUseProgram(last_program);
		glDisable(GL_SCISSOR_TEST);
		glEnable(GL_DEPTH_TEST);
		glBindTexture(GL_TEXTURE_2D, last_texture);
	}

	void CGUIManager::OnEvent(IEvent & Event)
	{
		ImGuiIO& io = ImGui::GetIO();

		if (InstanceOf<SKeyboardEvent>(Event))
		{
			SKeyboardEvent KeyboardEvent = As<SKeyboardEvent>(Event);
			io.KeysDown[(int) KeyboardEvent.Key] = KeyboardEvent.Pressed;
			io.KeyCtrl = Window->IsKeyDown(EKey::LeftControl) || Window->IsKeyDown(EKey::RightControl);
			io.KeyShift = Window->IsKeyDown(EKey::LeftShift) || Window->IsKeyDown(EKey::RightShift);
			io.KeyAlt = Window->IsKeyDown(EKey::LeftAlt) || Window->IsKeyDown(EKey::RightAlt);
		}
		else if (InstanceOf<SMouseEvent>(Event))
		{
			SMouseEvent MouseEvent = As<SMouseEvent>(Event);
			switch (MouseEvent.Type)
			{
			case SMouseEvent::EType::Click:
				if (ImGui::IsMouseHoveringAnyWindow())
				{
					Event.Block();
				}
				MousePressed[(int) MouseEvent.Button] = MouseEvent.Pressed;
				break;
			case SMouseEvent::EType::Move:
				break;
			case SMouseEvent::EType::Scroll:
				MouseWheel += MouseEvent.Movement.Y;
				break;
			}
		}
		else if (InstanceOf<SCharacterEvent>(Event))
		{
			SCharacterEvent CharacterEvent = As<SCharacterEvent>(Event);
			if (CharacterEvent.C > 0)
				io.AddInputCharacter(CharacterEvent.C);
		}
	}

	void CGUIManager::CreateFontsTexture()
	{
		ImGuiIO& io = ImGui::GetIO();

		unsigned char* pixels;
		int width, height;
		io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);   // Load as RGBA 32-bits for OpenGL3 demo because it is more likely to be compatible with user's existing shader.

		glGenTextures(1, &FontTexture);
		glBindTexture(GL_TEXTURE_2D, FontTexture);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);

		// Store our identifier
		io.Fonts->TexID = (void *) (intptr_t) FontTexture;
	}

	void CGUIManager::AddFontFromFile(string const & FileName, float const Size)
	{
		ImGuiIO& io = ImGui::GetIO();
		ImFont* my_font = io.Fonts->AddFontFromFileTTF(FileName.c_str(), Size);
	}

	bool CGUIManager::CreateDeviceObjects()
	{
		Window->MakeContextCurrent();

		const GLchar *vertex_shader =
			"#version 330\n"
			"uniform mat4 ProjMtx;\n"
			"in vec2 Position;\n"
			"in vec2 UV;\n"
			"in vec4 Color;\n"
			"out vec2 Frag_UV;\n"
			"out vec4 Frag_Color;\n"
			"void main()\n"
			"{\n"
			"	Frag_UV = UV;\n"
			"	Frag_Color = Color;\n"
			"	gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
			"}\n";

		const GLchar* fragment_shader =
			"#version 330\n"
			"uniform sampler2D Texture;\n"
			"in vec2 Frag_UV;\n"
			"in vec4 Frag_Color;\n"
			"out vec4 Out_Color;\n"
			"void main()\n"
			"{\n"
			"	Out_Color = Frag_Color * texture( Texture, Frag_UV.st);\n"
			"}\n";

		ShaderHandle = glCreateProgram();
		VertHandle = glCreateShader(GL_VERTEX_SHADER);
		FragHandle = glCreateShader(GL_FRAGMENT_SHADER);
		glShaderSource(VertHandle, 1, &vertex_shader, 0);
		glShaderSource(FragHandle, 1, &fragment_shader, 0);
		glCompileShader(VertHandle);
		glCompileShader(FragHandle);
		glAttachShader(ShaderHandle, VertHandle);
		glAttachShader(ShaderHandle, FragHandle);
		glLinkProgram(ShaderHandle);

		AttribLocationTex = glGetUniformLocation(ShaderHandle, "Texture");
		AttribLocationProjMtx = glGetUniformLocation(ShaderHandle, "ProjMtx");
		AttribLocationPosition = glGetAttribLocation(ShaderHandle, "Position");
		AttribLocationUV = glGetAttribLocation(ShaderHandle, "UV");
		AttribLocationColor = glGetAttribLocation(ShaderHandle, "Color");

		glGenBuffers(1, &VboHandle);
		glGenVertexArrays(1, &VaoHandle);
		glBindVertexArray(VaoHandle);
		glBindBuffer(GL_ARRAY_BUFFER, VboHandle);
		glEnableVertexAttribArray(AttribLocationPosition);
		glEnableVertexAttribArray(AttribLocationUV);
		glEnableVertexAttribArray(AttribLocationColor);

#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT))
		glVertexAttribPointer(AttribLocationPosition, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*) OFFSETOF(ImDrawVert, pos));
		glVertexAttribPointer(AttribLocationUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*) OFFSETOF(ImDrawVert, uv));
		glVertexAttribPointer(AttribLocationColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*) OFFSETOF(ImDrawVert, col));
#undef OFFSETOF
		glBindVertexArray(0);
		glBindBuffer(GL_ARRAY_BUFFER, 0);

		CreateFontsTexture();

		return true;
	}

	void ImGui_ImplGlfwGL3_RenderDrawLists(ImDrawData* draw_data)
	{
		SingletonPointer<CGUIManager> ImGUIManager;
		ImGUIManager->DrawCallback(draw_data);
	}

	char const * ImGui_ImplGlfwGL3_GetClipboardText()
	{
		SingletonPointer<CGUIManager> ImGUIManager;
		return ImGUIManager->Window->GetClipboardText().c_str();
	}

	void ImGui_ImplGlfwGL3_SetClipboardText(const char* text)
	{
		SingletonPointer<CGUIManager> ImGUIManager;
		ImGUIManager->Window->SetClipboardText(text);
	}

	bool CGUIManager::Init(CWindow* window)
	{
		Window = window;

		ImGuiIO& io = ImGui::GetIO();
		io.KeyMap[ImGuiKey_Tab] = (int) EKey::Tab;
		io.KeyMap[ImGuiKey_LeftArrow] = (int) EKey::Left;
		io.KeyMap[ImGuiKey_RightArrow] = (int) EKey::Right;
		io.KeyMap[ImGuiKey_UpArrow] = (int) EKey::Up;
		io.KeyMap[ImGuiKey_DownArrow] = (int) EKey::Down;
		io.KeyMap[ImGuiKey_Home] = (int) EKey::Home;
		io.KeyMap[ImGuiKey_End] = (int) EKey::End;
		io.KeyMap[ImGuiKey_Delete] = (int) EKey::Delete;
		io.KeyMap[ImGuiKey_Backspace] = (int) EKey::Backspace;
		io.KeyMap[ImGuiKey_Enter] = (int) EKey::Return;
		io.KeyMap[ImGuiKey_Escape] = (int) EKey::Escape;
		io.KeyMap[ImGuiKey_A] = (int) EKey::A;
		io.KeyMap[ImGuiKey_C] = (int) EKey::C;
		io.KeyMap[ImGuiKey_V] = (int) EKey::V;
		io.KeyMap[ImGuiKey_X] = (int) EKey::X;
		io.KeyMap[ImGuiKey_Y] = (int) EKey::Y;
		io.KeyMap[ImGuiKey_Z] = (int) EKey::Z;

		io.RenderDrawListsFn = ImGui_ImplGlfwGL3_RenderDrawLists;
		io.SetClipboardTextFn = ImGui_ImplGlfwGL3_SetClipboardText;
		io.GetClipboardTextFn = ImGui_ImplGlfwGL3_GetClipboardText;

		io.IniFilename = nullptr;

		return true;
	}

	void CGUIManager::Shutdown()
	{
		Window->MakeContextCurrent();

		if (VaoHandle) glDeleteVertexArrays(1, &VaoHandle);
		if (VboHandle) glDeleteBuffers(1, &VboHandle);
		VaoHandle = 0;
		VboHandle = 0;

		glDetachShader(ShaderHandle, VertHandle);
		glDeleteShader(VertHandle);
		VertHandle = 0;

		glDetachShader(ShaderHandle, FragHandle);
		glDeleteShader(FragHandle);
		FragHandle = 0;

		glDeleteProgram(ShaderHandle);
		ShaderHandle = 0;

		if (FontTexture)
		{
			glDeleteTextures(1, &FontTexture);
			ImGui::GetIO().Fonts->TexID = 0;
			FontTexture = 0;
		}
		ImGui::Shutdown();
	}

	void CGUIManager::NewFrame()
	{
		static int frame = 0;
		SingletonPointer<CTimeManager> TimeManager;

		if (! FontTexture)
			CreateDeviceObjects();

		ImGuiIO& io = ImGui::GetIO();

		// Setup display size (every frame to accommodate for window resizing)
		io.DisplaySize = ImVec2((float) Window->GetSize().X, (float) Window->GetSize().Y);

		// Setup time step
		double current_time = TimeManager->GetRunTime();
		io.DeltaTime = Time > 0.0 ? (float) (current_time - Time) : (float) (1.0f / 60.0f);
		Time = current_time;

		// Setup inputs
		// (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents())
		if (Window->IsFocused())
		{
			double mouse_x, mouse_y;
			mouse_x = Window->GetCursorLocation().X;
			mouse_y = Window->GetCursorLocation().Y;
			io.MousePos = ImVec2((float) mouse_x, (float) mouse_y);   // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.)
		}
		else
		{
			io.MousePos = ImVec2(-1, -1);
		}

		for (int i = 0; i < 3; i++)
		{
			io.MouseDown[i] = MousePressed[i] || Window->IsMouseDown((SMouseEvent::EButton) i);    // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
			MousePressed[i] = false;
		}

		io.MouseWheel = MouseWheel;
		MouseWheel = 0;

		// Start the frame
		ImGui::NewFrame();
	}

	CGUIManager::CGUIManager()
	{
		for (int i = 0; i < 3; ++ i)
			MousePressed[i] = false;
	}

}
<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <chainparams.h>
#include <init.h>
#include <net.h>
#include <scheduler.h>
#include <outputtype.h>
#include <util/system.h>
#include <util/moneystr.h>
#include <validation.h>
#include <walletinitinterface.h>
#include <wallet/rpcwallet.h>
#include <wallet/wallet.h>
#include <wallet/walletutil.h>

class WalletInit : public WalletInitInterface {
public:

    //! Was the wallet component compiled in.
    bool HasWalletSupport() const override {return true;}

    //! Return the wallets help message.
    void AddWalletOptions() const override;

    //! Wallets parameter interaction
    bool ParameterInteraction() const override;

    //! Register wallet RPCs.
    void RegisterRPC(CRPCTable &tableRPC) const override;

    //! Responsible for reading and validating the -wallet arguments and verifying the wallet database.
    //  This function will perform salvage on the wallet if requested, as long as only one wallet is
    //  being loaded (WalletParameterInteraction forbids -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet).
    bool Verify() const override;

    //! Load wallet databases.
    bool Open() const override;

    //! Complete startup of wallets.
    void Start(CScheduler& scheduler) const override;

    //! Flush all wallets in preparation for shutdown.
    void Flush() const override;

    //! Stop all wallets. Wallets will be flushed first.
    void Stop() const override;

    //! Close all wallets.
    void Close() const override;
};

const WalletInitInterface& g_wallet_init_interface = WalletInit();

void WalletInit::AddWalletOptions() const
{
    gArgs.AddArg("-addresstype", strprintf("What type of addresses to use (\"legacy\", \"p2sh-segwit\", or \"bech32\", default: \"%s\")", FormatOutputType(DEFAULT_ADDRESS_TYPE)), false, OptionsCategory::WALLET);
    gArgs.AddArg("-avoidpartialspends", strprintf(_("Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)"), DEFAULT_AVOIDPARTIALSPENDS), false, OptionsCategory::WALLET);
    gArgs.AddArg("-changetype", "What type of change to use (\"legacy\", \"p2sh-segwit\", or \"bech32\"). Default is same as -addresstype, except when -addresstype=p2sh-segwit a native segwit output is used when sending to a native segwit address)", false, OptionsCategory::WALLET);
    gArgs.AddArg("-disablewallet", "Do not load the wallet and disable wallet RPC calls", false, OptionsCategory::WALLET);
    gArgs.AddArg("-discardfee=<amt>", strprintf("The fee rate (in %s/kB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). "
                                                                "Note: An output is discarded if it is dust at this rate, but we will always discard up to the dust relay fee and a discard fee above that is limited by the fee estimate for the longest target",
                                                              CURRENCY_UNIT, FormatMoney(DEFAULT_DISCARD_FEE)), false, OptionsCategory::WALLET);
    gArgs.AddArg("-fallbackfee=<amt>", strprintf("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)",
                                                               CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)), false, OptionsCategory::WALLET);
    gArgs.AddArg("-keypool=<n>", strprintf("Set key pool size to <n> (default: %u)", DEFAULT_KEYPOOL_SIZE), false, OptionsCategory::WALLET);
    gArgs.AddArg("-mintxfee=<amt>", strprintf("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)",
                                                            CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE)), false, OptionsCategory::WALLET);
    gArgs.AddArg("-paytxfee=<amt>", strprintf("Fee (in %s/kB) to add to transactions you send (default: %s)",
                                                            CURRENCY_UNIT, FormatMoney(CFeeRate{DEFAULT_PAY_TX_FEE}.GetFeePerK())), false, OptionsCategory::WALLET);
    gArgs.AddArg("-rescan", "Rescan the block chain for missing wallet transactions on startup", false, OptionsCategory::WALLET);
    gArgs.AddArg("-salvagewallet", "Attempt to recover private keys from a corrupt wallet on startup", false, OptionsCategory::WALLET);
    gArgs.AddArg("-spendzeroconfchange", strprintf("Spend unconfirmed change when sending transactions (default: %u)", DEFAULT_SPEND_ZEROCONF_CHANGE), false, OptionsCategory::WALLET);
    gArgs.AddArg("-txconfirmtarget=<n>", strprintf("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)", DEFAULT_TX_CONFIRM_TARGET), false, OptionsCategory::WALLET);
    gArgs.AddArg("-upgradewallet", "Upgrade wallet to latest format on startup", false, OptionsCategory::WALLET);
    gArgs.AddArg("-wallet=<path>", "Specify wallet database path. Can be specified multiple times to load multiple wallets. Path is interpreted relative to <walletdir> if it is not absolute, and will be created if it does not exist (as a directory containing a wallet.dat file and log files). For backwards compatibility this will also accept names of existing data files in <walletdir>.)", false, OptionsCategory::WALLET);
    gArgs.AddArg("-walletbroadcast",  strprintf("Make the wallet broadcast transactions (default: %u)", DEFAULT_WALLETBROADCAST), false, OptionsCategory::WALLET);
    gArgs.AddArg("-walletdir=<dir>", "Specify directory to hold wallets (default: <datadir>/wallets if it exists, otherwise <datadir>)", false, OptionsCategory::WALLET);
    gArgs.AddArg("-walletnotify=<cmd>", "Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)", false, OptionsCategory::WALLET);
    gArgs.AddArg("-walletrbf", strprintf("Send transactions with full-RBF opt-in enabled (RPC only, default: %u)", DEFAULT_WALLET_RBF), false, OptionsCategory::WALLET);
    gArgs.AddArg("-zapwallettxes=<mode>", "Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup"
                               " (1 = keep tx meta data e.g. payment request information, 2 = drop tx meta data)", false, OptionsCategory::WALLET);

    gArgs.AddArg("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE), true, OptionsCategory::WALLET_DEBUG_TEST);
    gArgs.AddArg("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET), true, OptionsCategory::WALLET_DEBUG_TEST);
    gArgs.AddArg("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB), true, OptionsCategory::WALLET_DEBUG_TEST);
    gArgs.AddArg("-walletrejectlongchains", strprintf("Wallet will not create transactions that violate mempool chain limits (default: %u)", DEFAULT_WALLET_REJECT_LONG_CHAINS), true, OptionsCategory::WALLET_DEBUG_TEST);
}

bool WalletInit::ParameterInteraction() const
{
    if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
        for (const std::string& wallet : gArgs.GetArgs("-wallet")) {
            LogPrintf("%s: parameter interaction: -disablewallet -> ignoring -wallet=%s\n", __func__, wallet);
        }

        return true;
    }

    gArgs.SoftSetArg("-wallet", "");
    const bool is_multiwallet = gArgs.GetArgs("-wallet").size() > 1;

    if (gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && gArgs.SoftSetBoolArg("-walletbroadcast", false)) {
        LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__);
    }

    if (gArgs.GetBoolArg("-salvagewallet", false)) {
        if (is_multiwallet) {
            return InitError(strprintf("%s is only allowed with a single wallet file", "-salvagewallet"));
        }
        // Rewrite just private keys: rescan to find transactions
        if (gArgs.SoftSetBoolArg("-rescan", true)) {
            LogPrintf("%s: parameter interaction: -salvagewallet=1 -> setting -rescan=1\n", __func__);
        }
    }

    bool zapwallettxes = gArgs.GetBoolArg("-zapwallettxes", false);
    // -zapwallettxes implies dropping the mempool on startup
    if (zapwallettxes && gArgs.SoftSetBoolArg("-persistmempool", false)) {
        LogPrintf("%s: parameter interaction: -zapwallettxes enabled -> setting -persistmempool=0\n", __func__);
    }

    // -zapwallettxes implies a rescan
    if (zapwallettxes) {
        if (is_multiwallet) {
            return InitError(strprintf("%s is only allowed with a single wallet file", "-zapwallettxes"));
        }
        if (gArgs.SoftSetBoolArg("-rescan", true)) {
            LogPrintf("%s: parameter interaction: -zapwallettxes enabled -> setting -rescan=1\n", __func__);
        }
    }

    if (is_multiwallet) {
        if (gArgs.GetBoolArg("-upgradewallet", false)) {
            return InitError(strprintf("%s is only allowed with a single wallet file", "-upgradewallet"));
        }
    }

    if (gArgs.GetBoolArg("-sysperms", false))
        return InitError("-sysperms is not allowed in combination with enabled wallet functionality");
    if (gArgs.GetArg("-prune", 0) && gArgs.GetBoolArg("-rescan", false))
        return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again."));

    if (::minRelayTxFee.GetFeePerK() > HIGH_TX_FEE_PER_KB)
        InitWarning(AmountHighWarn("-minrelaytxfee") + " " +
                    _("The wallet will avoid paying less than the minimum relay fee."));

    if (gArgs.IsArgSet("-maxtxfee"))
    {
        CAmount nMaxFee = 0;
        if (!ParseMoney(gArgs.GetArg("-maxtxfee", ""), nMaxFee))
            return InitError(AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", "")));
        if (nMaxFee > HIGH_MAX_TX_FEE)
            InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
        maxTxFee = nMaxFee;
        if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee)
        {
            return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
                                       gArgs.GetArg("-maxtxfee", ""), ::minRelayTxFee.ToString()));
        }
    }

    return true;
}

void WalletInit::RegisterRPC(CRPCTable &t) const
{
    if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
        return;
    }

    RegisterWalletRPCCommands(t);
}

bool WalletInit::Verify() const
{
    if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
        return true;
    }

    if (gArgs.IsArgSet("-walletdir")) {
        fs::path wallet_dir = gArgs.GetArg("-walletdir", "");
        boost::system::error_code error;
        // The canonical path cleans the path, preventing >1 Berkeley environment instances for the same directory
        fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error);
        if (error || !fs::exists(wallet_dir)) {
            return InitError(strprintf(_("Specified -walletdir \"%s\" does not exist"), wallet_dir.string()));
        } else if (!fs::is_directory(wallet_dir)) {
            return InitError(strprintf(_("Specified -walletdir \"%s\" is not a directory"), wallet_dir.string()));
        // The canonical path transforms relative paths into absolute ones, so we check the non-canonical version
        } else if (!wallet_dir.is_absolute()) {
            return InitError(strprintf(_("Specified -walletdir \"%s\" is a relative path"), wallet_dir.string()));
        }
        gArgs.ForceSetArg("-walletdir", canonical_wallet_dir.string());
    }

    LogPrintf("Using wallet directory %s\n", GetWalletDir().string());

    uiInterface.InitMessage(_("Verifying wallet(s)..."));

    std::vector<std::string> wallet_files = gArgs.GetArgs("-wallet");

    // Parameter interaction code should have thrown an error if -salvagewallet
    // was enabled with more than wallet file, so the wallet_files size check
    // here should have no effect.
    bool salvage_wallet = gArgs.GetBoolArg("-salvagewallet", false) && wallet_files.size() <= 1;

    // Keep track of each wallet absolute path to detect duplicates.
    std::set<fs::path> wallet_paths;

    for (const auto& wallet_file : wallet_files) {
        WalletLocation location(wallet_file);

        if (!wallet_paths.insert(location.GetPath()).second) {
            return InitError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified."), wallet_file));
        }

        std::string error_string;
        std::string warning_string;
        bool verify_success = CWallet::Verify(location, salvage_wallet, error_string, warning_string);
        if (!error_string.empty()) InitError(error_string);
        if (!warning_string.empty()) InitWarning(warning_string);
        if (!verify_success) return false;
    }

    return true;
}

bool WalletInit::Open() const
{
    if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
        LogPrintf("Wallet disabled!\n");
        return true;
    }

    for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
        std::shared_ptr<CWallet> pwallet = CWallet::CreateWalletFromFile(WalletLocation(walletFile));
        if (!pwallet) {
            return false;
        }
        AddWallet(pwallet);
    }

    return true;
}

void WalletInit::Start(CScheduler& scheduler) const
{
    for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
        pwallet->postInitProcess();
    }

    // Run a thread to flush wallet periodically
    scheduler.scheduleEvery(MaybeCompactWalletDB, 500);
}

void WalletInit::Flush() const
{
    for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
        pwallet->Flush(false);
    }
}

void WalletInit::Stop() const
{
    for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
        pwallet->Flush(true);
    }
}

void WalletInit::Close() const
{
    for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
        RemoveWallet(pwallet);
    }
}
<commit_msg>trivial: Don't translate in help text<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <chainparams.h>
#include <init.h>
#include <net.h>
#include <scheduler.h>
#include <outputtype.h>
#include <util/system.h>
#include <util/moneystr.h>
#include <validation.h>
#include <walletinitinterface.h>
#include <wallet/rpcwallet.h>
#include <wallet/wallet.h>
#include <wallet/walletutil.h>

class WalletInit : public WalletInitInterface {
public:

    //! Was the wallet component compiled in.
    bool HasWalletSupport() const override {return true;}

    //! Return the wallets help message.
    void AddWalletOptions() const override;

    //! Wallets parameter interaction
    bool ParameterInteraction() const override;

    //! Register wallet RPCs.
    void RegisterRPC(CRPCTable &tableRPC) const override;

    //! Responsible for reading and validating the -wallet arguments and verifying the wallet database.
    //  This function will perform salvage on the wallet if requested, as long as only one wallet is
    //  being loaded (WalletParameterInteraction forbids -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet).
    bool Verify() const override;

    //! Load wallet databases.
    bool Open() const override;

    //! Complete startup of wallets.
    void Start(CScheduler& scheduler) const override;

    //! Flush all wallets in preparation for shutdown.
    void Flush() const override;

    //! Stop all wallets. Wallets will be flushed first.
    void Stop() const override;

    //! Close all wallets.
    void Close() const override;
};

const WalletInitInterface& g_wallet_init_interface = WalletInit();

void WalletInit::AddWalletOptions() const
{
    gArgs.AddArg("-addresstype", strprintf("What type of addresses to use (\"legacy\", \"p2sh-segwit\", or \"bech32\", default: \"%s\")", FormatOutputType(DEFAULT_ADDRESS_TYPE)), false, OptionsCategory::WALLET);
    gArgs.AddArg("-avoidpartialspends", strprintf("Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)", DEFAULT_AVOIDPARTIALSPENDS), false, OptionsCategory::WALLET);
    gArgs.AddArg("-changetype", "What type of change to use (\"legacy\", \"p2sh-segwit\", or \"bech32\"). Default is same as -addresstype, except when -addresstype=p2sh-segwit a native segwit output is used when sending to a native segwit address)", false, OptionsCategory::WALLET);
    gArgs.AddArg("-disablewallet", "Do not load the wallet and disable wallet RPC calls", false, OptionsCategory::WALLET);
    gArgs.AddArg("-discardfee=<amt>", strprintf("The fee rate (in %s/kB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). "
                                                                "Note: An output is discarded if it is dust at this rate, but we will always discard up to the dust relay fee and a discard fee above that is limited by the fee estimate for the longest target",
                                                              CURRENCY_UNIT, FormatMoney(DEFAULT_DISCARD_FEE)), false, OptionsCategory::WALLET);
    gArgs.AddArg("-fallbackfee=<amt>", strprintf("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)",
                                                               CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)), false, OptionsCategory::WALLET);
    gArgs.AddArg("-keypool=<n>", strprintf("Set key pool size to <n> (default: %u)", DEFAULT_KEYPOOL_SIZE), false, OptionsCategory::WALLET);
    gArgs.AddArg("-mintxfee=<amt>", strprintf("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)",
                                                            CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE)), false, OptionsCategory::WALLET);
    gArgs.AddArg("-paytxfee=<amt>", strprintf("Fee (in %s/kB) to add to transactions you send (default: %s)",
                                                            CURRENCY_UNIT, FormatMoney(CFeeRate{DEFAULT_PAY_TX_FEE}.GetFeePerK())), false, OptionsCategory::WALLET);
    gArgs.AddArg("-rescan", "Rescan the block chain for missing wallet transactions on startup", false, OptionsCategory::WALLET);
    gArgs.AddArg("-salvagewallet", "Attempt to recover private keys from a corrupt wallet on startup", false, OptionsCategory::WALLET);
    gArgs.AddArg("-spendzeroconfchange", strprintf("Spend unconfirmed change when sending transactions (default: %u)", DEFAULT_SPEND_ZEROCONF_CHANGE), false, OptionsCategory::WALLET);
    gArgs.AddArg("-txconfirmtarget=<n>", strprintf("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)", DEFAULT_TX_CONFIRM_TARGET), false, OptionsCategory::WALLET);
    gArgs.AddArg("-upgradewallet", "Upgrade wallet to latest format on startup", false, OptionsCategory::WALLET);
    gArgs.AddArg("-wallet=<path>", "Specify wallet database path. Can be specified multiple times to load multiple wallets. Path is interpreted relative to <walletdir> if it is not absolute, and will be created if it does not exist (as a directory containing a wallet.dat file and log files). For backwards compatibility this will also accept names of existing data files in <walletdir>.)", false, OptionsCategory::WALLET);
    gArgs.AddArg("-walletbroadcast",  strprintf("Make the wallet broadcast transactions (default: %u)", DEFAULT_WALLETBROADCAST), false, OptionsCategory::WALLET);
    gArgs.AddArg("-walletdir=<dir>", "Specify directory to hold wallets (default: <datadir>/wallets if it exists, otherwise <datadir>)", false, OptionsCategory::WALLET);
    gArgs.AddArg("-walletnotify=<cmd>", "Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)", false, OptionsCategory::WALLET);
    gArgs.AddArg("-walletrbf", strprintf("Send transactions with full-RBF opt-in enabled (RPC only, default: %u)", DEFAULT_WALLET_RBF), false, OptionsCategory::WALLET);
    gArgs.AddArg("-zapwallettxes=<mode>", "Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup"
                               " (1 = keep tx meta data e.g. payment request information, 2 = drop tx meta data)", false, OptionsCategory::WALLET);

    gArgs.AddArg("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE), true, OptionsCategory::WALLET_DEBUG_TEST);
    gArgs.AddArg("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET), true, OptionsCategory::WALLET_DEBUG_TEST);
    gArgs.AddArg("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB), true, OptionsCategory::WALLET_DEBUG_TEST);
    gArgs.AddArg("-walletrejectlongchains", strprintf("Wallet will not create transactions that violate mempool chain limits (default: %u)", DEFAULT_WALLET_REJECT_LONG_CHAINS), true, OptionsCategory::WALLET_DEBUG_TEST);
}

bool WalletInit::ParameterInteraction() const
{
    if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
        for (const std::string& wallet : gArgs.GetArgs("-wallet")) {
            LogPrintf("%s: parameter interaction: -disablewallet -> ignoring -wallet=%s\n", __func__, wallet);
        }

        return true;
    }

    gArgs.SoftSetArg("-wallet", "");
    const bool is_multiwallet = gArgs.GetArgs("-wallet").size() > 1;

    if (gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && gArgs.SoftSetBoolArg("-walletbroadcast", false)) {
        LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__);
    }

    if (gArgs.GetBoolArg("-salvagewallet", false)) {
        if (is_multiwallet) {
            return InitError(strprintf("%s is only allowed with a single wallet file", "-salvagewallet"));
        }
        // Rewrite just private keys: rescan to find transactions
        if (gArgs.SoftSetBoolArg("-rescan", true)) {
            LogPrintf("%s: parameter interaction: -salvagewallet=1 -> setting -rescan=1\n", __func__);
        }
    }

    bool zapwallettxes = gArgs.GetBoolArg("-zapwallettxes", false);
    // -zapwallettxes implies dropping the mempool on startup
    if (zapwallettxes && gArgs.SoftSetBoolArg("-persistmempool", false)) {
        LogPrintf("%s: parameter interaction: -zapwallettxes enabled -> setting -persistmempool=0\n", __func__);
    }

    // -zapwallettxes implies a rescan
    if (zapwallettxes) {
        if (is_multiwallet) {
            return InitError(strprintf("%s is only allowed with a single wallet file", "-zapwallettxes"));
        }
        if (gArgs.SoftSetBoolArg("-rescan", true)) {
            LogPrintf("%s: parameter interaction: -zapwallettxes enabled -> setting -rescan=1\n", __func__);
        }
    }

    if (is_multiwallet) {
        if (gArgs.GetBoolArg("-upgradewallet", false)) {
            return InitError(strprintf("%s is only allowed with a single wallet file", "-upgradewallet"));
        }
    }

    if (gArgs.GetBoolArg("-sysperms", false))
        return InitError("-sysperms is not allowed in combination with enabled wallet functionality");
    if (gArgs.GetArg("-prune", 0) && gArgs.GetBoolArg("-rescan", false))
        return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again."));

    if (::minRelayTxFee.GetFeePerK() > HIGH_TX_FEE_PER_KB)
        InitWarning(AmountHighWarn("-minrelaytxfee") + " " +
                    _("The wallet will avoid paying less than the minimum relay fee."));

    if (gArgs.IsArgSet("-maxtxfee"))
    {
        CAmount nMaxFee = 0;
        if (!ParseMoney(gArgs.GetArg("-maxtxfee", ""), nMaxFee))
            return InitError(AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", "")));
        if (nMaxFee > HIGH_MAX_TX_FEE)
            InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
        maxTxFee = nMaxFee;
        if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee)
        {
            return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
                                       gArgs.GetArg("-maxtxfee", ""), ::minRelayTxFee.ToString()));
        }
    }

    return true;
}

void WalletInit::RegisterRPC(CRPCTable &t) const
{
    if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
        return;
    }

    RegisterWalletRPCCommands(t);
}

bool WalletInit::Verify() const
{
    if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
        return true;
    }

    if (gArgs.IsArgSet("-walletdir")) {
        fs::path wallet_dir = gArgs.GetArg("-walletdir", "");
        boost::system::error_code error;
        // The canonical path cleans the path, preventing >1 Berkeley environment instances for the same directory
        fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error);
        if (error || !fs::exists(wallet_dir)) {
            return InitError(strprintf(_("Specified -walletdir \"%s\" does not exist"), wallet_dir.string()));
        } else if (!fs::is_directory(wallet_dir)) {
            return InitError(strprintf(_("Specified -walletdir \"%s\" is not a directory"), wallet_dir.string()));
        // The canonical path transforms relative paths into absolute ones, so we check the non-canonical version
        } else if (!wallet_dir.is_absolute()) {
            return InitError(strprintf(_("Specified -walletdir \"%s\" is a relative path"), wallet_dir.string()));
        }
        gArgs.ForceSetArg("-walletdir", canonical_wallet_dir.string());
    }

    LogPrintf("Using wallet directory %s\n", GetWalletDir().string());

    uiInterface.InitMessage(_("Verifying wallet(s)..."));

    std::vector<std::string> wallet_files = gArgs.GetArgs("-wallet");

    // Parameter interaction code should have thrown an error if -salvagewallet
    // was enabled with more than wallet file, so the wallet_files size check
    // here should have no effect.
    bool salvage_wallet = gArgs.GetBoolArg("-salvagewallet", false) && wallet_files.size() <= 1;

    // Keep track of each wallet absolute path to detect duplicates.
    std::set<fs::path> wallet_paths;

    for (const auto& wallet_file : wallet_files) {
        WalletLocation location(wallet_file);

        if (!wallet_paths.insert(location.GetPath()).second) {
            return InitError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified."), wallet_file));
        }

        std::string error_string;
        std::string warning_string;
        bool verify_success = CWallet::Verify(location, salvage_wallet, error_string, warning_string);
        if (!error_string.empty()) InitError(error_string);
        if (!warning_string.empty()) InitWarning(warning_string);
        if (!verify_success) return false;
    }

    return true;
}

bool WalletInit::Open() const
{
    if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
        LogPrintf("Wallet disabled!\n");
        return true;
    }

    for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
        std::shared_ptr<CWallet> pwallet = CWallet::CreateWalletFromFile(WalletLocation(walletFile));
        if (!pwallet) {
            return false;
        }
        AddWallet(pwallet);
    }

    return true;
}

void WalletInit::Start(CScheduler& scheduler) const
{
    for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
        pwallet->postInitProcess();
    }

    // Run a thread to flush wallet periodically
    scheduler.scheduleEvery(MaybeCompactWalletDB, 500);
}

void WalletInit::Flush() const
{
    for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
        pwallet->Flush(false);
    }
}

void WalletInit::Stop() const
{
    for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
        pwallet->Flush(true);
    }
}

void WalletInit::Close() const
{
    for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
        RemoveWallet(pwallet);
    }
}
<|endoftext|>