<commit_before>// Copyright (c) 2019 The Gulden developers
// Authored by: Malcolm MacLeod (mmacleod@gmx.com)
// Distributed under the GULDEN software license, see the accompanying file COPYING

#if defined(HAVE_CONFIG_H)
#include "config/gulden-config.h"
#endif

#include "miningaccountdialog.h"
#include <qt/_Gulden/forms/ui_miningaccountdialog.h>

#include "addressbookpage.h"
#include "addresstablemodel.h"
#include "units.h"
#include "guiutil.h"
#include "guiconstants.h"
#include "optionsmodel.h"
#include "receiverequestdialog.h"
#include "recentrequeststablemodel.h"
#include "walletmodel.h"
#include "wallet/wallet.h"

#include <QAction>
#include <QCursor>
#include <QItemSelection>
#include <QMessageBox>
#include <QScrollBar>
#include <QTextDocument>
#include <QDesktopWidget>
#include <QDesktopServices>
#include <QToolTip>

#include "clientmodel.h"
#include "editaddressdialog.h"

#include "GuldenGUI.h"
#include <generation/miner.h>

#include <crypto/hash/sigma/sigma.h>
#include <compat/sys.h>
#include "alert.h"

#ifdef USE_QRCODE
#include <qrencode.h>
#endif

MiningAccountDialog::MiningAccountDialog(const QStyle *_platformStyle, QWidget *parent)
: QDialog( parent )
, ui( new Ui::MiningAccountDialog )
, model( 0 )
, platformStyle( _platformStyle )
, buyReceiveAddress( NULL )
, currentAccount( NULL )
{
    ui->setupUi(this);

    ui->miningStartminingButton->setCursor(Qt::PointingHandCursor);
    ui->miningStopminingButton->setCursor(Qt::PointingHandCursor);
    ui->miningCopyToClipboardButton->setCursor(Qt::PointingHandCursor);
    ui->miningCopyToClipboardButton->setTextFormat( Qt::RichText );
    ui->miningCopyToClipboardButton->setText( GUIUtil::fontAwesomeRegular("\uf0c5") );
    ui->miningCopyToClipboardButton->setContentsMargins(0, 0, 0, 0);
    ui->miningEditAddressButton->setCursor(Qt::PointingHandCursor);
    ui->miningEditAddressButton->setTextFormat( Qt::RichText );
    ui->miningEditAddressButton->setText( GUIUtil::fontAwesomeRegular("\uf044") );
    ui->miningEditAddressButton->setContentsMargins(0, 0, 0, 0);
    ui->miningResetAddressButton->setCursor(Qt::PointingHandCursor);
    ui->miningResetAddressButton->setTextFormat( Qt::RichText );
    ui->miningResetAddressButton->setText( GUIUtil::fontAwesomeRegular("\uf12d") );
    ui->miningResetAddressButton->setContentsMargins(0, 0, 0, 0);

    ui->miningThreadSlider->setCursor(Qt::PointingHandCursor);
    ui->miningThreadSlider->setContentsMargins(0, 0, 0, 0);
    ui->miningThreadSlider->setToolTip(tr("Increasing the number of threads will increase your mining speed, but will also increase your energy usage and slow down other appliations that might be running."));

    ui->miningMemorySlider->setCursor(Qt::PointingHandCursor);
    ui->miningMemorySlider->setContentsMargins(0, 0, 0, 0);
    ui->miningMemorySlider->setToolTip(tr("Reducing memory usage is not recommended. It will slow down your mining while using the same amount of processor power and energy as before. Only use this as a last resort on machines that have low memory availability."));

    ui->miningStopminingButton->setVisible(false);

    uint32_t nThreadMax = std::max((uint32_t)2, (uint32_t)std::thread::hardware_concurrency());
    uint32_t nThreadSel = std::max((uint32_t)2, nThreadMax-2);
    ui->miningThreadSlider->setMinimum(1);
    ui->miningThreadSlider->setMaximum(nThreadMax);
    ui->miningThreadSlider->setTickInterval(1);
    ui->miningThreadSlider->setPageStep(1);
    ui->miningThreadSlider->setSingleStep(1);
    ui->miningThreadSlider->setTickPosition(QSlider::TicksBelow);
    ui->miningThreadSlider->setValue(nThreadSel);
    ui->miningThreadSlider->setTracking(false);

    uint64_t systemMemoryInMb = systemPhysicalMemoryInBytes()/1024/1024;
    uint64_t nMaxMemoryInMb = std::min(systemMemoryInMb, defaultSigmaSettings.arenaSizeKb/1024);
    ui->miningMemorySlider->setMinimum(128);
    ui->miningMemorySlider->setMaximum(nMaxMemoryInMb);
    ui->miningMemorySlider->setTickInterval(16);
    ui->miningMemorySlider->setSingleStep(16);
    ui->miningMemorySlider->setPageStep(1024);
    //fixme: (SIGMA) - Try pick a reasonable default for lower memory (e.g. 3gb) machines.
    ui->miningMemorySlider->setValue(ui->miningMemorySlider->maximum());
    ui->miningMemorySlider->setTracking(false);

    updateSliderLabels();

    ui->miningResetAddressButton->setVisible(false);
    updateAddress("");

    if (PoWGenerationIsActive())
    {
        slotUpdateMiningStats();
    }
}

void MiningAccountDialog::updateSliderLabels()
{
    ui->miningMemorySliderLabel->setText(tr("%1 MB").arg(ui->miningMemorySlider->value()));
    ui->miningThreadSliderLabel->setText(tr("%1 threads").arg(ui->miningThreadSlider->value()));
}

void MiningAccountDialog::startMining()
{
    LogPrintf("MiningAccountDialog::startMining\n");

    uint64_t nGenProcLimit = ui->miningThreadSlider->value();
    uint64_t nGenMemoryLimitKilobytes = ((uint64_t)ui->miningMemorySlider->value())*1024;

    if(clientModel && clientModel->getOptionsModel())
    {
        clientModel->getOptionsModel()->setMineThreadCount(nGenProcLimit);
        clientModel->getOptionsModel()->setMineMemory(nGenMemoryLimitKilobytes);
    }

    startMining(currentAccount, nGenProcLimit, nGenMemoryLimitKilobytes, overrideAddress.size() > 0 ? overrideAddress.toStdString() : accountAddress.toStdString());

    ui->miningStopminingButton->setVisible(true);
    ui->miningStartminingButton->setVisible(false);

    slotUpdateMiningStats();
}

void MiningAccountDialog::startMining(CAccount* forAccount, uint64_t numThreads, uint64_t mineMemoryKb, std::string overrideAddress)
{
    std::thread([=]
    {
        try
        {
            PoWGenerateGulden(true, numThreads, mineMemoryKb, Params(), forAccount, overrideAddress);
        }
        catch(...)
        {
            CAlert::Notify("Error in mining loop.", true, true);
        }
    }).detach();
}

//fixme: (SIGMA) Fire from timer instead of immediately
void MiningAccountDialog::restartMiningIfNeeded()
{
    if (PoWGenerationIsActive())
    {
        startMining();
    }
}

void MiningAccountDialog::updateAddress(const QString& address)
{
    accountAddress = address;

    if (overrideAddress.size() > 0)
    {
        ui->miningEditAddressButton->setVisible(false);
        ui->miningResetAddressButton->setVisible(true);
        ui->accountAddress->setText(overrideAddress);
    }
    else
    {
        ui->miningEditAddressButton->setVisible(true);
        ui->miningResetAddressButton->setVisible(false);
        ui->accountAddress->setText(accountAddress);
    }

    if (PoWGenerationIsActive())
    {
        ui->miningStopminingButton->setVisible(true);
        ui->miningStartminingButton->setVisible(false);
    }
    else
    {
        ui->miningStopminingButton->setVisible(false);
        ui->miningStartminingButton->setVisible(true);
    }
}

void MiningAccountDialog::setActiveAccount(CAccount* account)
{
    currentAccount = account;
}

void MiningAccountDialog::activeAccountChanged(CAccount* activeAccount)
{
    LogPrintf("MiningAccountDialog::activeAccountChanged\n");

    setActiveAccount(activeAccount);
}

void MiningAccountDialog::setModel(WalletModel *_model)
{
    this->model = _model;

    connect(model, SIGNAL(activeAccountChanged(CAccount*)), this, SLOT(activeAccountChanged(CAccount*)));
    activeAccountChanged(model->getActiveAccount());

    std::string readOverrideAddress;
    CWalletDB(*pactiveWallet->dbw).ReadMiningAddressString(readOverrideAddress);
    overrideAddress = QString::fromStdString(readOverrideAddress);
    updateAddress(accountAddress);

    static bool init=true;
    if (init)
    {
        init=false;
        connect(ui->miningCopyToClipboardButton, SIGNAL(clicked()),         this, SLOT(slotCopyAddressToClipboard()));
        connect(ui->miningEditAddressButton,     SIGNAL(clicked()),         this, SLOT(slotEditMiningAddress()));
        connect(ui->miningResetAddressButton,    SIGNAL(clicked()),         this, SLOT(slotResetMiningAddress()));
        connect(ui->miningStartminingButton,     SIGNAL(clicked()),         this, SLOT(slotStartMining()));
        connect(ui->miningStopminingButton,      SIGNAL(clicked()),         this, SLOT(slotStopMining()));
        connect(ui->miningCheckBoxKeepOpen,      SIGNAL(clicked()),         this, SLOT(slotKeepOpenWhenMining()));
        connect(ui->miningCheckBoxMineAtStartup, SIGNAL(clicked()),         this, SLOT(slotMineAtStartup()));
        connect(ui->miningMemorySlider,          SIGNAL(sliderMoved(int)),  this, SLOT(slotMiningMemorySettingChanging(int)));
        connect(ui->miningThreadSlider,          SIGNAL(sliderMoved(int)),  this, SLOT(slotMiningThreadSettingChanging(int)));
        connect(ui->miningMemorySlider,          SIGNAL(valueChanged(int)), this, SLOT(slotMiningMemorySettingChanged())); //Emitted only when user releases mouse at end of slider movement, not for every change
        connect(ui->miningThreadSlider,          SIGNAL(valueChanged(int)), this, SLOT(slotMiningThreadSettingChanged())); //Emitted only when user releases mouse at end of slider movement, not for every change
    }
}

void MiningAccountDialog::setClientModel(ClientModel* clientModel_)
{
    LogPrint(BCLog::QT, "MiningAccountDialog::setClientModel\n");
    clientModel = clientModel_;

    if(clientModel->getOptionsModel())
    {
        ui->miningCheckBoxKeepOpen->setChecked(clientModel->getOptionsModel()->getKeepOpenWhenMining());
        ui->miningCheckBoxMineAtStartup->setChecked(clientModel->getOptionsModel()->getMineAtStartup());

        uint64_t nGenProcLimit = clientModel->getOptionsModel()->getMineThreadCount();
        uint64_t nGenMemoryLimitKilobytes = clientModel->getOptionsModel()->getMineMemory();
        if (nGenProcLimit > 0)
            ui->miningThreadSlider->setValue(nGenProcLimit);
        if (nGenMemoryLimitKilobytes > 0)
            ui->miningMemorySlider->setValue(nGenMemoryLimitKilobytes/1024);
    }
    updateSliderLabels();
}

MiningAccountDialog::~MiningAccountDialog()
{
    delete ui;
}

void MiningAccountDialog::slotCopyAddressToClipboard()
{
    GUIUtil::setClipboard(accountAddress);
    QToolTip::showText(ui->miningCopyToClipboardButton->mapToGlobal(QPoint(0,0)), tr("Address copied to clipboard"),ui->miningCopyToClipboardButton);
}

void MiningAccountDialog::slotEditMiningAddress()
{
    LogPrintf("MiningAccountDialog::slotEditMiningAddress\n");
    if (model)
    {
        EditAddressDialog dlg(EditAddressDialog::NewMiningAddress, this, tr("Mining address"));
        dlg.setModel(model->getAddressTableModel());
        if(dlg.exec())
        {
            overrideAddress = dlg.getAddress();
            std::string strWriteOverrideAddress = overrideAddress.toStdString();
            CWalletDB(*pactiveWallet->dbw).WriteMiningAddressString(strWriteOverrideAddress);
            updateAddress(accountAddress);
            restartMiningIfNeeded();
        }
    }
}

void MiningAccountDialog::slotResetMiningAddress()
{
    LogPrintf("MiningAccountDialog::slotResetMiningAddress\n");

    if(pactiveWallet)
    {
        overrideAddress = "";
        CWalletDB(*pactiveWallet->dbw).WriteMiningAddressString("");
        updateAddress(accountAddress);
        restartMiningIfNeeded();
    }
}

void MiningAccountDialog::slotStartMining()
{
    LogPrintf("MiningAccountDialog::slotStartMining\n");
    startMining();
}

void MiningAccountDialog::slotStopMining()
{
    LogPrintf("MiningAccountDialog::slotStopMining\n");
    std::thread([=]
    {
        PoWStopGeneration();
    }).detach();

    ui->miningStopminingButton->setVisible(false);
    ui->miningStartminingButton->setVisible(true);
}

void MiningAccountDialog::slotKeepOpenWhenMining()
{
    if(clientModel && clientModel->getOptionsModel())
    {
        clientModel->getOptionsModel()->setKeepOpenWhenMining(ui->miningCheckBoxKeepOpen->isChecked());
    }
}

void MiningAccountDialog::slotMineAtStartup()
{
    if(clientModel && clientModel->getOptionsModel())
    {
        clientModel->getOptionsModel()->setMineAtStartup(ui->miningCheckBoxMineAtStartup->isChecked());
    }
}

void MiningAccountDialog::slotMiningMemorySettingChanged()
{
    updateSliderLabels();
    restartMiningIfNeeded();
}

void MiningAccountDialog::slotMiningThreadSettingChanged()
{
    updateSliderLabels();
    restartMiningIfNeeded();
}

void MiningAccountDialog::slotMiningMemorySettingChanging(int val)
{
    ui->miningMemorySliderLabel->setText(tr("%1 MB").arg(val));
}

void MiningAccountDialog::slotMiningThreadSettingChanging(int val)
{
    ui->miningThreadSliderLabel->setText(tr("%1 threads").arg(val));
}

void MiningAccountDialog::slotUpdateMiningStats()
{
    //fixme: (SIGMA) (DEDUP) - Share this code with RPC if possible
    double dHashPerSecLog = dHashesPerSec;
    std::string sHashPerSecLogLabel = " h";
    selectLargesHashUnit(dHashPerSecLog, sHashPerSecLogLabel);
    double dRollingHashPerSecLog = dRollingHashesPerSec;
    std::string sRollingHashPerSecLogLabel = " h";
    selectLargesHashUnit(dRollingHashPerSecLog, sRollingHashPerSecLogLabel);
    double dBestHashPerSecLog = dBestHashesPerSec;
    std::string sBestHashPerSecLogLabel = " h";
    selectLargesHashUnit(dBestHashPerSecLog, sBestHashPerSecLogLabel);

    ui->labelLastMiningSpeed->setText(QString::fromStdString(strprintf("%.2lf %s/s", dHashPerSecLog, sHashPerSecLogLabel)));
    ui->labelAverageMiningSpeed->setText(QString::fromStdString(strprintf("%.2lf %s/s", dRollingHashPerSecLog, sRollingHashPerSecLogLabel)));
    ui->labelBestMiningSpeed->setText(QString::fromStdString(strprintf("%.2lf %s/s", dBestHashPerSecLog, sBestHashPerSecLogLabel)));

    if (PoWGenerationIsActive())
    {
        // Call again every 5 seconds as long as mining is active
        QTimer::singleShot( 5000, this, SLOT(slotUpdateMiningStats()) );
    }
}
<commit_msg>UI: SIGMA: Specify lower memory defaults for 32 bit systems.<commit_after>// Copyright (c) 2019 The Gulden developers
// Authored by: Malcolm MacLeod (mmacleod@gmx.com)
// Distributed under the GULDEN software license, see the accompanying file COPYING

#if defined(HAVE_CONFIG_H)
#include "config/gulden-config.h"
#endif

#include "miningaccountdialog.h"
#include <qt/_Gulden/forms/ui_miningaccountdialog.h>

#include "addressbookpage.h"
#include "addresstablemodel.h"
#include "units.h"
#include "guiutil.h"
#include "guiconstants.h"
#include "optionsmodel.h"
#include "receiverequestdialog.h"
#include "recentrequeststablemodel.h"
#include "walletmodel.h"
#include "wallet/wallet.h"

#include <QAction>
#include <QCursor>
#include <QItemSelection>
#include <QMessageBox>
#include <QScrollBar>
#include <QTextDocument>
#include <QDesktopWidget>
#include <QDesktopServices>
#include <QToolTip>

#include "clientmodel.h"
#include "editaddressdialog.h"

#include "GuldenGUI.h"
#include <generation/miner.h>

#include <crypto/hash/sigma/sigma.h>
#include <compat/sys.h>
#include "alert.h"

#ifdef USE_QRCODE
#include <qrencode.h>
#endif

MiningAccountDialog::MiningAccountDialog(const QStyle *_platformStyle, QWidget *parent)
: QDialog( parent )
, ui( new Ui::MiningAccountDialog )
, model( 0 )
, platformStyle( _platformStyle )
, buyReceiveAddress( NULL )
, currentAccount( NULL )
{
    ui->setupUi(this);

    ui->miningStartminingButton->setCursor(Qt::PointingHandCursor);
    ui->miningStopminingButton->setCursor(Qt::PointingHandCursor);
    ui->miningCopyToClipboardButton->setCursor(Qt::PointingHandCursor);
    ui->miningCopyToClipboardButton->setTextFormat( Qt::RichText );
    ui->miningCopyToClipboardButton->setText( GUIUtil::fontAwesomeRegular("\uf0c5") );
    ui->miningCopyToClipboardButton->setContentsMargins(0, 0, 0, 0);
    ui->miningEditAddressButton->setCursor(Qt::PointingHandCursor);
    ui->miningEditAddressButton->setTextFormat( Qt::RichText );
    ui->miningEditAddressButton->setText( GUIUtil::fontAwesomeRegular("\uf044") );
    ui->miningEditAddressButton->setContentsMargins(0, 0, 0, 0);
    ui->miningResetAddressButton->setCursor(Qt::PointingHandCursor);
    ui->miningResetAddressButton->setTextFormat( Qt::RichText );
    ui->miningResetAddressButton->setText( GUIUtil::fontAwesomeRegular("\uf12d") );
    ui->miningResetAddressButton->setContentsMargins(0, 0, 0, 0);

    ui->miningThreadSlider->setCursor(Qt::PointingHandCursor);
    ui->miningThreadSlider->setContentsMargins(0, 0, 0, 0);
    ui->miningThreadSlider->setToolTip(tr("Increasing the number of threads will increase your mining speed, but will also increase your energy usage and slow down other appliations that might be running."));

    ui->miningMemorySlider->setCursor(Qt::PointingHandCursor);
    ui->miningMemorySlider->setContentsMargins(0, 0, 0, 0);
    ui->miningMemorySlider->setToolTip(tr("Reducing memory usage is not recommended. It will slow down your mining while using the same amount of processor power and energy as before. Only use this as a last resort on machines that have low memory availability."));

    ui->miningStopminingButton->setVisible(false);

    uint32_t nThreadMax = std::max((uint32_t)2, (uint32_t)std::thread::hardware_concurrency());
    uint32_t nThreadSel = std::max((uint32_t)2, nThreadMax-2);
    ui->miningThreadSlider->setMinimum(1);
    ui->miningThreadSlider->setMaximum(nThreadMax);
    ui->miningThreadSlider->setTickInterval(1);
    ui->miningThreadSlider->setPageStep(1);
    ui->miningThreadSlider->setSingleStep(1);
    ui->miningThreadSlider->setTickPosition(QSlider::TicksBelow);
    ui->miningThreadSlider->setValue(nThreadSel);
    ui->miningThreadSlider->setTracking(false);

    uint64_t systemMemoryInMb = systemPhysicalMemoryInBytes()/1024/1024;
    uint64_t nMaxMemoryInMb = std::min(systemMemoryInMb, defaultSigmaSettings.arenaSizeKb/1024);
    // 32 bit windows can only address 2gb of memory per process (3gb if /largeaddressaware)
    // 32 bit linux is 4gb per process.
    // Limit both accordingly
    #ifdef ARCH_X86
        #ifdef WIN32
            nMaxMemoryInMb = std::min(nMaxMemoryInMb, 1*1024);
        #else
            nMaxMemoryInMb = std::min(nMaxMemoryInMb, 2*1024);
        #endif
    #endif

    ui->miningMemorySlider->setMinimum(128);
    ui->miningMemorySlider->setMaximum(nMaxMemoryInMb);
    ui->miningMemorySlider->setTickInterval(16);
    ui->miningMemorySlider->setSingleStep(16);
    ui->miningMemorySlider->setPageStep(1024);
    //fixme: (SIGMA) - Try pick a reasonable default for lower memory (e.g. 3gb) machines.
    ui->miningMemorySlider->setValue(ui->miningMemorySlider->maximum());
    ui->miningMemorySlider->setTracking(false);

    updateSliderLabels();

    ui->miningResetAddressButton->setVisible(false);
    updateAddress("");

    if (PoWGenerationIsActive())
    {
        slotUpdateMiningStats();
    }
}

void MiningAccountDialog::updateSliderLabels()
{
    ui->miningMemorySliderLabel->setText(tr("%1 MB").arg(ui->miningMemorySlider->value()));
    ui->miningThreadSliderLabel->setText(tr("%1 threads").arg(ui->miningThreadSlider->value()));
}

void MiningAccountDialog::startMining()
{
    LogPrintf("MiningAccountDialog::startMining\n");

    uint64_t nGenProcLimit = ui->miningThreadSlider->value();
    uint64_t nGenMemoryLimitKilobytes = ((uint64_t)ui->miningMemorySlider->value())*1024;

    if(clientModel && clientModel->getOptionsModel())
    {
        clientModel->getOptionsModel()->setMineThreadCount(nGenProcLimit);
        clientModel->getOptionsModel()->setMineMemory(nGenMemoryLimitKilobytes);
    }

    startMining(currentAccount, nGenProcLimit, nGenMemoryLimitKilobytes, overrideAddress.size() > 0 ? overrideAddress.toStdString() : accountAddress.toStdString());

    ui->miningStopminingButton->setVisible(true);
    ui->miningStartminingButton->setVisible(false);

    slotUpdateMiningStats();
}

void MiningAccountDialog::startMining(CAccount* forAccount, uint64_t numThreads, uint64_t mineMemoryKb, std::string overrideAddress)
{
    std::thread([=]
    {
        try
        {
            PoWGenerateGulden(true, numThreads, mineMemoryKb, Params(), forAccount, overrideAddress);
        }
        catch(...)
        {
            CAlert::Notify("Error in mining loop.", true, true);
        }
    }).detach();
}

//fixme: (SIGMA) Fire from timer instead of immediately
void MiningAccountDialog::restartMiningIfNeeded()
{
    if (PoWGenerationIsActive())
    {
        startMining();
    }
}

void MiningAccountDialog::updateAddress(const QString& address)
{
    accountAddress = address;

    if (overrideAddress.size() > 0)
    {
        ui->miningEditAddressButton->setVisible(false);
        ui->miningResetAddressButton->setVisible(true);
        ui->accountAddress->setText(overrideAddress);
    }
    else
    {
        ui->miningEditAddressButton->setVisible(true);
        ui->miningResetAddressButton->setVisible(false);
        ui->accountAddress->setText(accountAddress);
    }

    if (PoWGenerationIsActive())
    {
        ui->miningStopminingButton->setVisible(true);
        ui->miningStartminingButton->setVisible(false);
    }
    else
    {
        ui->miningStopminingButton->setVisible(false);
        ui->miningStartminingButton->setVisible(true);
    }
}

void MiningAccountDialog::setActiveAccount(CAccount* account)
{
    currentAccount = account;
}

void MiningAccountDialog::activeAccountChanged(CAccount* activeAccount)
{
    LogPrintf("MiningAccountDialog::activeAccountChanged\n");

    setActiveAccount(activeAccount);
}

void MiningAccountDialog::setModel(WalletModel *_model)
{
    this->model = _model;

    connect(model, SIGNAL(activeAccountChanged(CAccount*)), this, SLOT(activeAccountChanged(CAccount*)));
    activeAccountChanged(model->getActiveAccount());

    std::string readOverrideAddress;
    CWalletDB(*pactiveWallet->dbw).ReadMiningAddressString(readOverrideAddress);
    overrideAddress = QString::fromStdString(readOverrideAddress);
    updateAddress(accountAddress);

    static bool init=true;
    if (init)
    {
        init=false;
        connect(ui->miningCopyToClipboardButton, SIGNAL(clicked()),         this, SLOT(slotCopyAddressToClipboard()));
        connect(ui->miningEditAddressButton,     SIGNAL(clicked()),         this, SLOT(slotEditMiningAddress()));
        connect(ui->miningResetAddressButton,    SIGNAL(clicked()),         this, SLOT(slotResetMiningAddress()));
        connect(ui->miningStartminingButton,     SIGNAL(clicked()),         this, SLOT(slotStartMining()));
        connect(ui->miningStopminingButton,      SIGNAL(clicked()),         this, SLOT(slotStopMining()));
        connect(ui->miningCheckBoxKeepOpen,      SIGNAL(clicked()),         this, SLOT(slotKeepOpenWhenMining()));
        connect(ui->miningCheckBoxMineAtStartup, SIGNAL(clicked()),         this, SLOT(slotMineAtStartup()));
        connect(ui->miningMemorySlider,          SIGNAL(sliderMoved(int)),  this, SLOT(slotMiningMemorySettingChanging(int)));
        connect(ui->miningThreadSlider,          SIGNAL(sliderMoved(int)),  this, SLOT(slotMiningThreadSettingChanging(int)));
        connect(ui->miningMemorySlider,          SIGNAL(valueChanged(int)), this, SLOT(slotMiningMemorySettingChanged())); //Emitted only when user releases mouse at end of slider movement, not for every change
        connect(ui->miningThreadSlider,          SIGNAL(valueChanged(int)), this, SLOT(slotMiningThreadSettingChanged())); //Emitted only when user releases mouse at end of slider movement, not for every change
    }
}

void MiningAccountDialog::setClientModel(ClientModel* clientModel_)
{
    LogPrint(BCLog::QT, "MiningAccountDialog::setClientModel\n");
    clientModel = clientModel_;

    if(clientModel->getOptionsModel())
    {
        ui->miningCheckBoxKeepOpen->setChecked(clientModel->getOptionsModel()->getKeepOpenWhenMining());
        ui->miningCheckBoxMineAtStartup->setChecked(clientModel->getOptionsModel()->getMineAtStartup());

        uint64_t nGenProcLimit = clientModel->getOptionsModel()->getMineThreadCount();
        uint64_t nGenMemoryLimitKilobytes = clientModel->getOptionsModel()->getMineMemory();
        if (nGenProcLimit > 0)
            ui->miningThreadSlider->setValue(nGenProcLimit);
        if (nGenMemoryLimitKilobytes > 0)
            ui->miningMemorySlider->setValue(nGenMemoryLimitKilobytes/1024);
    }
    updateSliderLabels();
}

MiningAccountDialog::~MiningAccountDialog()
{
    delete ui;
}

void MiningAccountDialog::slotCopyAddressToClipboard()
{
    GUIUtil::setClipboard(accountAddress);
    QToolTip::showText(ui->miningCopyToClipboardButton->mapToGlobal(QPoint(0,0)), tr("Address copied to clipboard"),ui->miningCopyToClipboardButton);
}

void MiningAccountDialog::slotEditMiningAddress()
{
    LogPrintf("MiningAccountDialog::slotEditMiningAddress\n");
    if (model)
    {
        EditAddressDialog dlg(EditAddressDialog::NewMiningAddress, this, tr("Mining address"));
        dlg.setModel(model->getAddressTableModel());
        if(dlg.exec())
        {
            overrideAddress = dlg.getAddress();
            std::string strWriteOverrideAddress = overrideAddress.toStdString();
            CWalletDB(*pactiveWallet->dbw).WriteMiningAddressString(strWriteOverrideAddress);
            updateAddress(accountAddress);
            restartMiningIfNeeded();
        }
    }
}

void MiningAccountDialog::slotResetMiningAddress()
{
    LogPrintf("MiningAccountDialog::slotResetMiningAddress\n");

    if(pactiveWallet)
    {
        overrideAddress = "";
        CWalletDB(*pactiveWallet->dbw).WriteMiningAddressString("");
        updateAddress(accountAddress);
        restartMiningIfNeeded();
    }
}

void MiningAccountDialog::slotStartMining()
{
    LogPrintf("MiningAccountDialog::slotStartMining\n");
    startMining();
}

void MiningAccountDialog::slotStopMining()
{
    LogPrintf("MiningAccountDialog::slotStopMining\n");
    std::thread([=]
    {
        PoWStopGeneration();
    }).detach();

    ui->miningStopminingButton->setVisible(false);
    ui->miningStartminingButton->setVisible(true);
}

void MiningAccountDialog::slotKeepOpenWhenMining()
{
    if(clientModel && clientModel->getOptionsModel())
    {
        clientModel->getOptionsModel()->setKeepOpenWhenMining(ui->miningCheckBoxKeepOpen->isChecked());
    }
}

void MiningAccountDialog::slotMineAtStartup()
{
    if(clientModel && clientModel->getOptionsModel())
    {
        clientModel->getOptionsModel()->setMineAtStartup(ui->miningCheckBoxMineAtStartup->isChecked());
    }
}

void MiningAccountDialog::slotMiningMemorySettingChanged()
{
    updateSliderLabels();
    restartMiningIfNeeded();
}

void MiningAccountDialog::slotMiningThreadSettingChanged()
{
    updateSliderLabels();
    restartMiningIfNeeded();
}

void MiningAccountDialog::slotMiningMemorySettingChanging(int val)
{
    ui->miningMemorySliderLabel->setText(tr("%1 MB").arg(val));
}

void MiningAccountDialog::slotMiningThreadSettingChanging(int val)
{
    ui->miningThreadSliderLabel->setText(tr("%1 threads").arg(val));
}

void MiningAccountDialog::slotUpdateMiningStats()
{
    //fixme: (SIGMA) (DEDUP) - Share this code with RPC if possible
    double dHashPerSecLog = dHashesPerSec;
    std::string sHashPerSecLogLabel = " h";
    selectLargesHashUnit(dHashPerSecLog, sHashPerSecLogLabel);
    double dRollingHashPerSecLog = dRollingHashesPerSec;
    std::string sRollingHashPerSecLogLabel = " h";
    selectLargesHashUnit(dRollingHashPerSecLog, sRollingHashPerSecLogLabel);
    double dBestHashPerSecLog = dBestHashesPerSec;
    std::string sBestHashPerSecLogLabel = " h";
    selectLargesHashUnit(dBestHashPerSecLog, sBestHashPerSecLogLabel);

    ui->labelLastMiningSpeed->setText(QString::fromStdString(strprintf("%.2lf %s/s", dHashPerSecLog, sHashPerSecLogLabel)));
    ui->labelAverageMiningSpeed->setText(QString::fromStdString(strprintf("%.2lf %s/s", dRollingHashPerSecLog, sRollingHashPerSecLogLabel)));
    ui->labelBestMiningSpeed->setText(QString::fromStdString(strprintf("%.2lf %s/s", dBestHashPerSecLog, sBestHashPerSecLogLabel)));

    if (PoWGenerationIsActive())
    {
        // Call again every 5 seconds as long as mining is active
        QTimer::singleShot( 5000, this, SLOT(slotUpdateMiningStats()) );
    }
}
<|endoftext|>


<commit_before>/*Copyright 2010-2015 George Karagoulis

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.*/

#include "progressbarcontrol.h"
#include <gutil/macros.h>
#include <QStackedLayout>
#include <QVBoxLayout>

NAMESPACE_GUTIL1(Qt);

ProgressBarControl::ProgressBarControl(bool be, QWidget *parent)
    :QWidget(parent),
      _p_AutoShow(true),
      m_isCancellable(true)
{
    _button.setStyleSheet("background-color: rgba(0,0,0,0);");

    _progressBar.setTextVisible(false);

    setLayout(new QVBoxLayout(this));
    layout()->setContentsMargins(0, 0, 0, 0);
    layout()->addWidget(&_progressBar);

    _label.setAlignment(::Qt::AlignCenter);
    QFont f;  f.setBold(true);
    _label.setFont(f);

    _progressBar.setLayout(new QStackedLayout(&_progressBar));
    _progressBar.layout()->setContentsMargins(0, 0, 0, 0);
    ((QStackedLayout*)_progressBar.layout())->setStackingMode(QStackedLayout::StackAll);
    _progressBar.layout()->addWidget(&_label);

    _progressBar.layout()->addWidget(&_button);

    connect(&_button, SIGNAL(clicked()), this, SIGNAL(Clicked()));

    setButtonEnabled(be);

    if(GetAutoShow())
        hide();
}

void ProgressBarControl::SetIsCancellable(bool c)
{
    m_isCancellable = c;
    _button.setVisible(c);
}

void ProgressBarControl::setButtonEnabled(bool which)
{
    if(which)
    {
        _button.show();
        ((QStackedLayout *)_progressBar.layout())->setCurrentWidget(&_button);
    }
    else
    {
        _button.hide();
    }
}

void ProgressBarControl::SetProgress(int p, const QString &s)
{
    if(GetAutoShow())
    {
        if(p == _progressBar.minimum() && !isVisible())
            show();
        else if(p == _progressBar.maximum() && isVisible())
            hide();
    }

    _progressBar.setValue(p);
    if(_button.isVisible())
        _label.setText(QString(tr("%1%2"))
                       .arg(s)
                       .arg(m_isCancellable ? tr(" (Click to cancel)") : QString::null));
    else
        _label.setText(s);
}

END_NAMESPACE_GUTIL1;
<commit_msg>The progress bar control should show any time the progress value is less than the max. Sometimes the progress reporter doesn't report the starting 0 value, so we have to account for that in the auto-show logic.<commit_after>/*Copyright 2010-2015 George Karagoulis

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.*/

#include "progressbarcontrol.h"
#include <gutil/macros.h>
#include <QStackedLayout>
#include <QVBoxLayout>

NAMESPACE_GUTIL1(Qt);

ProgressBarControl::ProgressBarControl(bool be, QWidget *parent)
    :QWidget(parent),
      _p_AutoShow(true),
      m_isCancellable(true)
{
    _button.setStyleSheet("background-color: rgba(0,0,0,0);");

    _progressBar.setTextVisible(false);

    setLayout(new QVBoxLayout(this));
    layout()->setContentsMargins(0, 0, 0, 0);
    layout()->addWidget(&_progressBar);

    _label.setAlignment(::Qt::AlignCenter);
    QFont f;  f.setBold(true);
    _label.setFont(f);

    _progressBar.setLayout(new QStackedLayout(&_progressBar));
    _progressBar.layout()->setContentsMargins(0, 0, 0, 0);
    ((QStackedLayout*)_progressBar.layout())->setStackingMode(QStackedLayout::StackAll);
    _progressBar.layout()->addWidget(&_label);

    _progressBar.layout()->addWidget(&_button);

    connect(&_button, SIGNAL(clicked()), this, SIGNAL(Clicked()));

    setButtonEnabled(be);

    if(GetAutoShow())
        hide();
}

void ProgressBarControl::SetIsCancellable(bool c)
{
    m_isCancellable = c;
    _button.setVisible(c);
}

void ProgressBarControl::setButtonEnabled(bool which)
{
    if(which)
    {
        _button.show();
        ((QStackedLayout *)_progressBar.layout())->setCurrentWidget(&_button);
    }
    else
    {
        _button.hide();
    }
}

void ProgressBarControl::SetProgress(int p, const QString &s)
{
    if(GetAutoShow())
    {
        if(p == _progressBar.maximum() && isVisible())
            hide();
        else if(p < _progressBar.maximum() && !isVisible())
            show();
    }

    _progressBar.setValue(p);
    if(_button.isVisible())
        _label.setText(QString(tr("%1%2"))
                       .arg(s)
                       .arg(m_isCancellable ? tr(" (Click to cancel)") : QString::null));
    else
        _label.setText(s);
}

END_NAMESPACE_GUTIL1;
<|endoftext|>


<commit_before>#include "connection.hpp"
#include "server.hpp"

using namespace server;

Connection::Connection(Server& serv, Connection_ptr conn, size_t idx)
  : server_(serv), conn_(conn), idx_(idx)
{
  conn_->read(BUFSIZE, OnData::from<Connection, &Connection::on_data>(this));
  conn_->onDisconnect(OnDisconnect::from<Connection, &Connection::on_disconnect>(this));
}

void Connection::on_data(buffer_t buf, size_t n) {
  printf("<Connection> @on_data, size=%u\n", n);
  // if it's a new request
  if(!request_) {
    request_ = std::make_shared<Request>(buf, n);
    // return early to read payload
    if((request_->method() == http::POST or request_->method() == http::PUT)
      and request_->content_length() > request_->get_body().size())
      return;
  }
  // else we assume it's payload
  else {
    request_->add_body(request_->get_body() + std::string((const char*)buf.get(), n));
    // if we haven't received all data promised
    if(request_->content_length() > request_->get_body().size())
      return;
  }

  printf("<Connection:[%s]> Incoming Request [@%s:%s]\n",
    conn_->remote().to_string().c_str(),
    http::method::str(request_->method()).c_str(),
    request_->uri().path().c_str());

  response_ = std::make_shared<Response>(conn_);

  //std::cout << "Raw data: " << buf << " <<< End raw data.\n";

  server_.process(request_, response_);
  request_ = nullptr;

}

void Connection::on_disconnect(Connection_ptr, Disconnect) {
  close();
}

void Connection::close() {
  conn_->close();
  server_.close(idx_);
}
<commit_msg>Close connection if invalid HTTP<commit_after>#include "connection.hpp"
#include "server.hpp"

using namespace server;

Connection::Connection(Server& serv, Connection_ptr conn, size_t idx)
  : server_(serv), conn_(conn), idx_(idx)
{
  conn_->read(BUFSIZE, OnData::from<Connection, &Connection::on_data>(this));
  conn_->onDisconnect(OnDisconnect::from<Connection, &Connection::on_disconnect>(this));
}

void Connection::on_data(buffer_t buf, size_t n) {
  printf("<Connection> @on_data, size=%u\n", n);
  // if it's a new request
  if(!request_) {
    try {
      request_ = std::make_shared<Request>(buf, n);
      // return early to read payload
      if((request_->method() == http::POST or request_->method() == http::PUT)
        and request_->content_length() > request_->get_body().size())
        return;
    } catch(...) {
      printf("<Connection> Error - exception thrown when creating Request???\n");
      close();
      return;
    }
  }
  // else we assume it's payload
  else {
    request_->add_body(request_->get_body() + std::string((const char*)buf.get(), n));
    // if we haven't received all data promised
    if(request_->content_length() > request_->get_body().size())
      return;
  }

  printf("<Connection:[%s]> Incoming Request [@%s:%s]\n",
    conn_->remote().to_string().c_str(),
    http::method::str(request_->method()).c_str(),
    request_->uri().path().c_str());

  response_ = std::make_shared<Response>(conn_);

  //std::cout << "Raw data: " << buf << " <<< End raw data.\n";

  server_.process(request_, response_);
  request_ = nullptr;

}

void Connection::on_disconnect(Connection_ptr, Disconnect) {
  close();
}

void Connection::close() {
  conn_->close();
  server_.close(idx_);
}
<|endoftext|>


<commit_before>// The libMesh Finite Element Library.
// Copyright (C) 2002-2012 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// Local includes
#include "libmesh/quadrature_simpson.h"

namespace libMesh
{

void QSimpson::init_3D(const ElemType _type,
                       unsigned int)
{
#if LIBMESH_DIM == 3

  //-----------------------------------------------------------------------
  // 3D quadrature rules
  switch (_type)
    {
      //---------------------------------------------
      // Hex quadrature rules
    case HEX8:
    case HEX20:
    case HEX27:
      {
	// We compute the 3D quadrature rule as a tensor
	// product of the 1D quadrature rule.
	QSimpson q1D(1);
	q1D.init(EDGE2);

	tensor_product_hex( q1D );

	return;
      }

      //---------------------------------------------
      // Tetrahedral quadrature rules
    case TET4:
    case TET10:
      {
	// This rule is created by combining 8 subtets
	// which use the trapezoidal rule.  The weights
	// may seem a bit odd, but they are correct,
	// and should add up to 1/6, the volume of the
	// reference tet.  The points of this rule are
	// at the nodal points of the TET10, allowing
	// you to generate diagonal element stiffness
	// matrices when using quadratic elements.
	// It should be able to integrate something
	// better than linears, but I'm not sure how
	// high.

	_points.resize(10);
	_weights.resize(10);

	_points[0](0) = 0.;   _points[5](0) = .5;
	_points[0](1) = 0.;   _points[5](1) = .5;
	_points[0](2) = 0.;   _points[5](2) = 0.;

	_points[1](0) = 1.;   _points[6](0) = 0.;
	_points[1](1) = 0.;   _points[6](1) = .5;
	_points[1](2) = 0.;   _points[6](2) = 0.;

	_points[2](0) = 0.;   _points[7](0) = 0.;
	_points[2](1) = 1.;   _points[7](1) = 0.;
	_points[2](2) = 0.;   _points[7](2) = .5;

	_points[3](0) = 0.;   _points[8](0) = .5;
	_points[3](1) = 0.;   _points[8](1) = 0.;
	_points[3](2) = 1.;   _points[8](2) = .5;

	_points[4](0) = .5;   _points[9](0) = 0.;
	_points[4](1) = 0.;   _points[9](1) = .5;
	_points[4](2) = 0.;   _points[9](2) = .5;

	_weights[0] = .0052083333333333333333333333333333333333333333; // 1./192.
	_weights[1] = _weights[0];
	_weights[2] = _weights[0];
	_weights[3] = _weights[0];

	_weights[4] = .0243055555555555555555555555555555555555555555; // 14./576.
	_weights[5] = _weights[4];
	_weights[6] = _weights[4];
	_weights[7] = _weights[4];
	_weights[8] = _weights[4];
	_weights[9] = _weights[4];

	return;
      }

      //---------------------------------------------
      // Prism quadrature rules
    case PRISM6:
    case PRISM15:
    case PRISM18:
      {
	// We compute the 3D quadrature rule as a tensor
	// product of the 1D quadrature rule and a 2D
	// triangle quadrature rule

 	QSimpson q1D(1);
 	QSimpson q2D(2);

 	// Initialize
 	q1D.init(EDGE2);
 	q2D.init(TRI3);

	tensor_product_prism(q1D, q2D);

	return;
      }

      //---------------------------------------------
      // Unsupported type
    default:
      {
	libMesh::err << "ERROR: Unsupported type: " << _type << std::endl;
	libmesh_error();
      }
    }

  libmesh_error();

  return;

#endif
}

} // namespace libMesh
<commit_msg>Changes in quadrature_simpson_3D.C for -Wshadow.<commit_after>// The libMesh Finite Element Library.
// Copyright (C) 2002-2012 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// Local includes
#include "libmesh/quadrature_simpson.h"

namespace libMesh
{

void QSimpson::init_3D(const ElemType type_in,
                       unsigned int)
{
#if LIBMESH_DIM == 3

  //-----------------------------------------------------------------------
  // 3D quadrature rules
  switch (type_in)
    {
      //---------------------------------------------
      // Hex quadrature rules
    case HEX8:
    case HEX20:
    case HEX27:
      {
	// We compute the 3D quadrature rule as a tensor
	// product of the 1D quadrature rule.
	QSimpson q1D(1);
	q1D.init(EDGE2);

	tensor_product_hex( q1D );

	return;
      }

      //---------------------------------------------
      // Tetrahedral quadrature rules
    case TET4:
    case TET10:
      {
	// This rule is created by combining 8 subtets
	// which use the trapezoidal rule.  The weights
	// may seem a bit odd, but they are correct,
	// and should add up to 1/6, the volume of the
	// reference tet.  The points of this rule are
	// at the nodal points of the TET10, allowing
	// you to generate diagonal element stiffness
	// matrices when using quadratic elements.
	// It should be able to integrate something
	// better than linears, but I'm not sure how
	// high.

	_points.resize(10);
	_weights.resize(10);

	_points[0](0) = 0.;   _points[5](0) = .5;
	_points[0](1) = 0.;   _points[5](1) = .5;
	_points[0](2) = 0.;   _points[5](2) = 0.;

	_points[1](0) = 1.;   _points[6](0) = 0.;
	_points[1](1) = 0.;   _points[6](1) = .5;
	_points[1](2) = 0.;   _points[6](2) = 0.;

	_points[2](0) = 0.;   _points[7](0) = 0.;
	_points[2](1) = 1.;   _points[7](1) = 0.;
	_points[2](2) = 0.;   _points[7](2) = .5;

	_points[3](0) = 0.;   _points[8](0) = .5;
	_points[3](1) = 0.;   _points[8](1) = 0.;
	_points[3](2) = 1.;   _points[8](2) = .5;

	_points[4](0) = .5;   _points[9](0) = 0.;
	_points[4](1) = 0.;   _points[9](1) = .5;
	_points[4](2) = 0.;   _points[9](2) = .5;

	_weights[0] = .0052083333333333333333333333333333333333333333; // 1./192.
	_weights[1] = _weights[0];
	_weights[2] = _weights[0];
	_weights[3] = _weights[0];

	_weights[4] = .0243055555555555555555555555555555555555555555; // 14./576.
	_weights[5] = _weights[4];
	_weights[6] = _weights[4];
	_weights[7] = _weights[4];
	_weights[8] = _weights[4];
	_weights[9] = _weights[4];

	return;
      }

      //---------------------------------------------
      // Prism quadrature rules
    case PRISM6:
    case PRISM15:
    case PRISM18:
      {
	// We compute the 3D quadrature rule as a tensor
	// product of the 1D quadrature rule and a 2D
	// triangle quadrature rule

 	QSimpson q1D(1);
 	QSimpson q2D(2);

 	// Initialize
 	q1D.init(EDGE2);
 	q2D.init(TRI3);

	tensor_product_prism(q1D, q2D);

	return;
      }

      //---------------------------------------------
      // Unsupported type
    default:
      {
	libMesh::err << "ERROR: Unsupported type: " << type_in << std::endl;
	libmesh_error();
      }
    }

  libmesh_error();

  return;

#endif
}

} // namespace libMesh
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qsgrenderloop_p.h"
#include "qsgthreadedrenderloop_p.h"
#include "qsgwindowsrenderloop_p.h"

#include <QtCore/QCoreApplication>
#include <QtCore/QTime>
#include <QtCore/QLibraryInfo>
#include <QtCore/private/qabstractanimation_p.h>

#include <QtGui/QOpenGLContext>
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>

#include <QtQml/private/qqmlglobal_p.h>

#include <QtQuick/QQuickWindow>
#include <QtQuick/private/qquickwindow_p.h>
#include <QtQuick/private/qsgcontext_p.h>
#include <private/qquickprofiler_p.h>

#ifdef Q_OS_WIN
#  include <QtCore/qt_windows.h>
#endif

QT_BEGIN_NAMESPACE

DEFINE_BOOL_CONFIG_OPTION(qsg_render_timing, QSG_RENDER_TIMING)

extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);

/*!
    expectations for this manager to work:
     - one opengl context to render multiple windows
     - OpenGL pipeline will not block for vsync in swap
     - OpenGL pipeline will block based on a full buffer queue.
     - Multiple screens can share the OpenGL context
     - Animations are advanced for all windows once per swap
 */

DEFINE_BOOL_CONFIG_OPTION(qmlNoThreadedRenderer, QML_BAD_GUI_RENDER_LOOP);
DEFINE_BOOL_CONFIG_OPTION(qmlForceThreadedRenderer, QML_FORCE_THREADED_RENDERER); // Might trigger graphics driver threading bugs, use at own risk

QSGRenderLoop *QSGRenderLoop::s_instance = 0;

QSGRenderLoop::~QSGRenderLoop()
{
}

void QSGRenderLoop::cleanup()
{
    if (!s_instance)
        return;
    foreach (QQuickWindow *w, s_instance->windows()) {
        QQuickWindowPrivate *wd = QQuickWindowPrivate::get(w);
        if (wd->windowManager == s_instance) {
           s_instance->windowDestroyed(w);
           wd->windowManager = 0;
        }
    }
    delete s_instance;
    s_instance = 0;
}

class QSGGuiThreadRenderLoop : public QSGRenderLoop
{
    Q_OBJECT
public:
    QSGGuiThreadRenderLoop();
    ~QSGGuiThreadRenderLoop();

    void show(QQuickWindow *window);
    void hide(QQuickWindow *window);

    void windowDestroyed(QQuickWindow *window);

    void renderWindow(QQuickWindow *window);
    void exposureChanged(QQuickWindow *window);
    QImage grab(QQuickWindow *window);

    void maybeUpdate(QQuickWindow *window);
    void update(QQuickWindow *window) { maybeUpdate(window); } // identical for this implementation.

    void releaseResources(QQuickWindow *) { }

    QAnimationDriver *animationDriver() const { return 0; }

    QSGContext *sceneGraphContext() const;
    QSGRenderContext *createRenderContext(QSGContext *) const { return rc; }

    bool event(QEvent *);

    struct WindowData {
        bool updatePending : 1;
        bool grabOnly : 1;
    };

    QHash<QQuickWindow *, WindowData> m_windows;

    QOpenGLContext *gl;
    QSGContext *sg;
    QSGRenderContext *rc;

    QImage grabContent;
    int m_update_timer;

    bool eventPending;
};

bool QSGRenderLoop::useConsistentTiming()
{
    bool bufferQueuing = QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::BufferQueueingOpenGL);
    // Enable fixed animation steps...
    QByteArray fixed = qgetenv("QSG_FIXED_ANIMATION_STEP");
    bool fixedAnimationSteps = bufferQueuing;
    if (fixed == "no")
        fixedAnimationSteps = false;
    else if (fixed.length())
        fixedAnimationSteps = true;
    return fixedAnimationSteps;
}

QSGRenderLoop *QSGRenderLoop::instance()
{
    if (!s_instance) {
        s_instance = QSGContext::createWindowManager();

        bool info = qEnvironmentVariableIsSet("QSG_INFO");

        if (useConsistentTiming()) {
            QUnifiedTimer::instance(true)->setConsistentTiming(true);
            if (info)
                qDebug() << "QSG: using fixed animation steps";
        }

        if (!s_instance) {

            enum RenderLoopType {
                BasicRenderLoop,
                ThreadedRenderLoop,
                WindowsRenderLoop
            };

            RenderLoopType loopType = BasicRenderLoop;

#ifdef Q_OS_WIN
            loopType = WindowsRenderLoop;
#else
            if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL))
                loopType = ThreadedRenderLoop;
#endif
            if (qmlNoThreadedRenderer())
                loopType = BasicRenderLoop;
            else if (qmlForceThreadedRenderer())
                loopType = ThreadedRenderLoop;

            const QByteArray loopName = qgetenv("QSG_RENDER_LOOP");
            if (loopName == QByteArrayLiteral("windows"))
                loopType = WindowsRenderLoop;
            else if (loopName == QByteArrayLiteral("basic"))
                loopType = BasicRenderLoop;
            else if (loopName == QByteArrayLiteral("threaded"))
                loopType = ThreadedRenderLoop;

            switch (loopType) {
            case ThreadedRenderLoop:
                if (info) qDebug() << "QSG: threaded render loop";
                s_instance = new QSGThreadedRenderLoop();
                break;
            case WindowsRenderLoop:
                if (info) qDebug() << "QSG: windows render loop";
                s_instance = new QSGWindowsRenderLoop();
                break;
            default:
                if (info) qDebug() << "QSG: basic render loop";
                s_instance = new QSGGuiThreadRenderLoop();
                break;
            }
        }

        qAddPostRoutine(QSGRenderLoop::cleanup);
    }
    return s_instance;
}

void QSGRenderLoop::setInstance(QSGRenderLoop *instance)
{
    Q_ASSERT(!s_instance);
    s_instance = instance;
}

void QSGRenderLoop::handleContextCreationFailure(QQuickWindow *window,
                                                 bool isEs)
{
    QString translatedMessage;
    QString untranslatedMessage;
    QQuickWindowPrivate::contextCreationFailureMessage(window->requestedFormat(),
                                                       &translatedMessage,
                                                       &untranslatedMessage,
                                                       isEs);
    // If there is a slot connected to the error signal, emit it and leave it to
    // the application to do something with the message. If nothing is connected,
    // show a message on our own and terminate.
    const bool signalEmitted =
        QQuickWindowPrivate::get(window)->emitError(QQuickWindow::ContextNotAvailable,
                                                    translatedMessage);
#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
    if (!signalEmitted && !QLibraryInfo::isDebugBuild() && !GetConsoleWindow()) {
        MessageBox(0, (LPCTSTR) translatedMessage.utf16(),
                   (LPCTSTR)(QCoreApplication::applicationName().utf16()),
                   MB_OK | MB_ICONERROR);
    }
#endif // Q_OS_WIN && !Q_OS_WINCE && !Q_OS_WINRT
    if (!signalEmitted)
        qFatal("%s", qPrintable(untranslatedMessage));
}

QSGGuiThreadRenderLoop::QSGGuiThreadRenderLoop()
    : gl(0)
    , eventPending(false)
{
    sg = QSGContext::createDefaultContext();
    rc = sg->createRenderContext();
}

QSGGuiThreadRenderLoop::~QSGGuiThreadRenderLoop()
{
    delete rc;
    delete sg;
}

void QSGGuiThreadRenderLoop::show(QQuickWindow *window)
{
    WindowData data;
    data.updatePending = false;
    data.grabOnly = false;
    m_windows[window] = data;

    maybeUpdate(window);
}

void QSGGuiThreadRenderLoop::hide(QQuickWindow *window)
{
    if (!m_windows.contains(window))
        return;

    m_windows.remove(window);
    QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
    if (gl)
        gl->makeCurrent(window);
    cd->fireAboutToStop();
    cd->cleanupNodesOnShutdown();

    if (m_windows.size() == 0) {
        if (!cd->persistentSceneGraph) {
            rc->invalidate();
            QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
            if (!cd->persistentGLContext) {
                delete gl;
                gl = 0;
            }
        }
    }
}

void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window)
{
    hide(window);
    if (m_windows.size() == 0) {
        rc->invalidate();
        QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
        delete gl;
        gl = 0;
    } else if (window == gl->surface()) {
        gl->doneCurrent();
    }
}

void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
{
    QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
    if (!cd->isRenderable() || !m_windows.contains(window))
        return;

    WindowData &data = const_cast<WindowData &>(m_windows[window]);

    bool current = false;

    if (!gl) {
        gl = new QOpenGLContext();
        gl->setFormat(window->requestedFormat());
        if (QOpenGLContextPrivate::globalShareContext())
            gl->setShareContext(QOpenGLContextPrivate::globalShareContext());
        if (!gl->create()) {
            const bool isEs = gl->isOpenGLES();
            delete gl;
            gl = 0;
            handleContextCreationFailure(window, isEs);
        } else {
            cd->fireOpenGLContextCreated(gl);
            current = gl->makeCurrent(window);
        }
        if (current)
            cd->context->initialize(gl);
    } else {
        current = gl->makeCurrent(window);
    }

    bool alsoSwap = data.updatePending;
    data.updatePending = false;

    if (!current)
        return;

    cd->polishItems();

    emit window->afterAnimating();

    qint64 renderTime = 0, syncTime = 0;
    QElapsedTimer renderTimer;
    bool profileFrames = qsg_render_timing()  || QQuickProfiler::enabled;
    if (profileFrames)
        renderTimer.start();

    cd->syncSceneGraph();

    if (profileFrames)
        syncTime = renderTimer.nsecsElapsed();

    cd->renderSceneGraph(window->size());

    if (profileFrames)
        renderTime = renderTimer.nsecsElapsed() - syncTime;

    if (data.grabOnly) {
        grabContent = qt_gl_read_framebuffer(window->size() * window->devicePixelRatio(), false, false);
        data.grabOnly = false;
    }

    if (alsoSwap && window->isVisible()) {
        gl->swapBuffers(window);
        cd->fireFrameSwapped();
    }

    qint64 swapTime = 0;
    if (profileFrames) {
        swapTime = renderTimer.nsecsElapsed() - renderTime - syncTime;
    }

    if (qsg_render_timing()) {
        static QTime lastFrameTime = QTime::currentTime();
        qDebug() << "- Breakdown of frame time; sync:" << syncTime/1000000
                 << "ms render:" << renderTime/1000000 << "ms swap:" << swapTime/1000000
                 << "ms total:" << (swapTime + renderTime + syncTime)/1000000
                 << "ms time since last frame:" << (lastFrameTime.msecsTo(QTime::currentTime()))
                 << "ms";
        lastFrameTime = QTime::currentTime();
    }

    Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphRenderLoopFrame, (
            syncTime,
            renderTime,
            swapTime));

    // Might have been set during syncSceneGraph()
    if (data.updatePending)
        maybeUpdate(window);
}

void QSGGuiThreadRenderLoop::exposureChanged(QQuickWindow *window)
{
    if (window->isExposed()) {
        m_windows[window].updatePending = true;
        renderWindow(window);
    }
}

QImage QSGGuiThreadRenderLoop::grab(QQuickWindow *window)
{
    if (!m_windows.contains(window))
        return QImage();

    m_windows[window].grabOnly = true;

    renderWindow(window);

    QImage grabbed = grabContent;
    grabContent = QImage();
    return grabbed;
}

void QSGGuiThreadRenderLoop::maybeUpdate(QQuickWindow *window)
{
    if (!m_windows.contains(window))
        return;

    m_windows[window].updatePending = true;

    if (!eventPending) {
        const int exhaust_delay = 5;
        m_update_timer = startTimer(exhaust_delay, Qt::PreciseTimer);
        eventPending = true;
    }
}

QSGContext *QSGGuiThreadRenderLoop::sceneGraphContext() const
{
    return sg;
}

bool QSGGuiThreadRenderLoop::event(QEvent *e)
{
    if (e->type() == QEvent::Timer) {
        eventPending = false;
        killTimer(m_update_timer);
        m_update_timer = 0;
        for (QHash<QQuickWindow *, WindowData>::const_iterator it = m_windows.constBegin();
             it != m_windows.constEnd(); ++it) {
            const WindowData &data = it.value();
            if (data.updatePending)
                renderWindow(it.key());
        }
        return true;
    }
    return QObject::event(e);
}

#include "qsgrenderloop.moc"

QT_END_NAMESPACE
<commit_msg>Don't dereference null QQuickWindowPrivate.<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qsgrenderloop_p.h"
#include "qsgthreadedrenderloop_p.h"
#include "qsgwindowsrenderloop_p.h"

#include <QtCore/QCoreApplication>
#include <QtCore/QTime>
#include <QtCore/QLibraryInfo>
#include <QtCore/private/qabstractanimation_p.h>

#include <QtGui/QOpenGLContext>
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>

#include <QtQml/private/qqmlglobal_p.h>

#include <QtQuick/QQuickWindow>
#include <QtQuick/private/qquickwindow_p.h>
#include <QtQuick/private/qsgcontext_p.h>
#include <private/qquickprofiler_p.h>

#ifdef Q_OS_WIN
#  include <QtCore/qt_windows.h>
#endif

QT_BEGIN_NAMESPACE

DEFINE_BOOL_CONFIG_OPTION(qsg_render_timing, QSG_RENDER_TIMING)

extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);

/*!
    expectations for this manager to work:
     - one opengl context to render multiple windows
     - OpenGL pipeline will not block for vsync in swap
     - OpenGL pipeline will block based on a full buffer queue.
     - Multiple screens can share the OpenGL context
     - Animations are advanced for all windows once per swap
 */

DEFINE_BOOL_CONFIG_OPTION(qmlNoThreadedRenderer, QML_BAD_GUI_RENDER_LOOP);
DEFINE_BOOL_CONFIG_OPTION(qmlForceThreadedRenderer, QML_FORCE_THREADED_RENDERER); // Might trigger graphics driver threading bugs, use at own risk

QSGRenderLoop *QSGRenderLoop::s_instance = 0;

QSGRenderLoop::~QSGRenderLoop()
{
}

void QSGRenderLoop::cleanup()
{
    if (!s_instance)
        return;
    foreach (QQuickWindow *w, s_instance->windows()) {
        QQuickWindowPrivate *wd = QQuickWindowPrivate::get(w);
        if (wd->windowManager == s_instance) {
           // windowDestroyed() triggers a sendPostedEvent(DeferredDelete),
           // so wd will be null if the window was deleteLater()'ed
           bool wasDeleted = wd->wasDeleted;
           s_instance->windowDestroyed(w);
           if (!wasDeleted)
               wd->windowManager = 0;
        }
    }
    delete s_instance;
    s_instance = 0;
}

class QSGGuiThreadRenderLoop : public QSGRenderLoop
{
    Q_OBJECT
public:
    QSGGuiThreadRenderLoop();
    ~QSGGuiThreadRenderLoop();

    void show(QQuickWindow *window);
    void hide(QQuickWindow *window);

    void windowDestroyed(QQuickWindow *window);

    void renderWindow(QQuickWindow *window);
    void exposureChanged(QQuickWindow *window);
    QImage grab(QQuickWindow *window);

    void maybeUpdate(QQuickWindow *window);
    void update(QQuickWindow *window) { maybeUpdate(window); } // identical for this implementation.

    void releaseResources(QQuickWindow *) { }

    QAnimationDriver *animationDriver() const { return 0; }

    QSGContext *sceneGraphContext() const;
    QSGRenderContext *createRenderContext(QSGContext *) const { return rc; }

    bool event(QEvent *);

    struct WindowData {
        bool updatePending : 1;
        bool grabOnly : 1;
    };

    QHash<QQuickWindow *, WindowData> m_windows;

    QOpenGLContext *gl;
    QSGContext *sg;
    QSGRenderContext *rc;

    QImage grabContent;
    int m_update_timer;

    bool eventPending;
};

bool QSGRenderLoop::useConsistentTiming()
{
    bool bufferQueuing = QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::BufferQueueingOpenGL);
    // Enable fixed animation steps...
    QByteArray fixed = qgetenv("QSG_FIXED_ANIMATION_STEP");
    bool fixedAnimationSteps = bufferQueuing;
    if (fixed == "no")
        fixedAnimationSteps = false;
    else if (fixed.length())
        fixedAnimationSteps = true;
    return fixedAnimationSteps;
}

QSGRenderLoop *QSGRenderLoop::instance()
{
    if (!s_instance) {
        s_instance = QSGContext::createWindowManager();

        bool info = qEnvironmentVariableIsSet("QSG_INFO");

        if (useConsistentTiming()) {
            QUnifiedTimer::instance(true)->setConsistentTiming(true);
            if (info)
                qDebug() << "QSG: using fixed animation steps";
        }

        if (!s_instance) {

            enum RenderLoopType {
                BasicRenderLoop,
                ThreadedRenderLoop,
                WindowsRenderLoop
            };

            RenderLoopType loopType = BasicRenderLoop;

#ifdef Q_OS_WIN
            loopType = WindowsRenderLoop;
#else
            if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL))
                loopType = ThreadedRenderLoop;
#endif
            if (qmlNoThreadedRenderer())
                loopType = BasicRenderLoop;
            else if (qmlForceThreadedRenderer())
                loopType = ThreadedRenderLoop;

            const QByteArray loopName = qgetenv("QSG_RENDER_LOOP");
            if (loopName == QByteArrayLiteral("windows"))
                loopType = WindowsRenderLoop;
            else if (loopName == QByteArrayLiteral("basic"))
                loopType = BasicRenderLoop;
            else if (loopName == QByteArrayLiteral("threaded"))
                loopType = ThreadedRenderLoop;

            switch (loopType) {
            case ThreadedRenderLoop:
                if (info) qDebug() << "QSG: threaded render loop";
                s_instance = new QSGThreadedRenderLoop();
                break;
            case WindowsRenderLoop:
                if (info) qDebug() << "QSG: windows render loop";
                s_instance = new QSGWindowsRenderLoop();
                break;
            default:
                if (info) qDebug() << "QSG: basic render loop";
                s_instance = new QSGGuiThreadRenderLoop();
                break;
            }
        }

        qAddPostRoutine(QSGRenderLoop::cleanup);
    }
    return s_instance;
}

void QSGRenderLoop::setInstance(QSGRenderLoop *instance)
{
    Q_ASSERT(!s_instance);
    s_instance = instance;
}

void QSGRenderLoop::handleContextCreationFailure(QQuickWindow *window,
                                                 bool isEs)
{
    QString translatedMessage;
    QString untranslatedMessage;
    QQuickWindowPrivate::contextCreationFailureMessage(window->requestedFormat(),
                                                       &translatedMessage,
                                                       &untranslatedMessage,
                                                       isEs);
    // If there is a slot connected to the error signal, emit it and leave it to
    // the application to do something with the message. If nothing is connected,
    // show a message on our own and terminate.
    const bool signalEmitted =
        QQuickWindowPrivate::get(window)->emitError(QQuickWindow::ContextNotAvailable,
                                                    translatedMessage);
#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
    if (!signalEmitted && !QLibraryInfo::isDebugBuild() && !GetConsoleWindow()) {
        MessageBox(0, (LPCTSTR) translatedMessage.utf16(),
                   (LPCTSTR)(QCoreApplication::applicationName().utf16()),
                   MB_OK | MB_ICONERROR);
    }
#endif // Q_OS_WIN && !Q_OS_WINCE && !Q_OS_WINRT
    if (!signalEmitted)
        qFatal("%s", qPrintable(untranslatedMessage));
}

QSGGuiThreadRenderLoop::QSGGuiThreadRenderLoop()
    : gl(0)
    , eventPending(false)
{
    sg = QSGContext::createDefaultContext();
    rc = sg->createRenderContext();
}

QSGGuiThreadRenderLoop::~QSGGuiThreadRenderLoop()
{
    delete rc;
    delete sg;
}

void QSGGuiThreadRenderLoop::show(QQuickWindow *window)
{
    WindowData data;
    data.updatePending = false;
    data.grabOnly = false;
    m_windows[window] = data;

    maybeUpdate(window);
}

void QSGGuiThreadRenderLoop::hide(QQuickWindow *window)
{
    if (!m_windows.contains(window))
        return;

    m_windows.remove(window);
    QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
    if (gl)
        gl->makeCurrent(window);
    cd->fireAboutToStop();
    cd->cleanupNodesOnShutdown();

    if (m_windows.size() == 0) {
        if (!cd->persistentSceneGraph) {
            rc->invalidate();
            QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
            if (!cd->persistentGLContext) {
                delete gl;
                gl = 0;
            }
        }
    }
}

void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window)
{
    hide(window);
    if (m_windows.size() == 0) {
        rc->invalidate();
        QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
        delete gl;
        gl = 0;
    } else if (window == gl->surface()) {
        gl->doneCurrent();
    }
}

void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
{
    QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
    if (!cd->isRenderable() || !m_windows.contains(window))
        return;

    WindowData &data = const_cast<WindowData &>(m_windows[window]);

    bool current = false;

    if (!gl) {
        gl = new QOpenGLContext();
        gl->setFormat(window->requestedFormat());
        if (QOpenGLContextPrivate::globalShareContext())
            gl->setShareContext(QOpenGLContextPrivate::globalShareContext());
        if (!gl->create()) {
            const bool isEs = gl->isOpenGLES();
            delete gl;
            gl = 0;
            handleContextCreationFailure(window, isEs);
        } else {
            cd->fireOpenGLContextCreated(gl);
            current = gl->makeCurrent(window);
        }
        if (current)
            cd->context->initialize(gl);
    } else {
        current = gl->makeCurrent(window);
    }

    bool alsoSwap = data.updatePending;
    data.updatePending = false;

    if (!current)
        return;

    cd->polishItems();

    emit window->afterAnimating();

    qint64 renderTime = 0, syncTime = 0;
    QElapsedTimer renderTimer;
    bool profileFrames = qsg_render_timing()  || QQuickProfiler::enabled;
    if (profileFrames)
        renderTimer.start();

    cd->syncSceneGraph();

    if (profileFrames)
        syncTime = renderTimer.nsecsElapsed();

    cd->renderSceneGraph(window->size());

    if (profileFrames)
        renderTime = renderTimer.nsecsElapsed() - syncTime;

    if (data.grabOnly) {
        grabContent = qt_gl_read_framebuffer(window->size() * window->devicePixelRatio(), false, false);
        data.grabOnly = false;
    }

    if (alsoSwap && window->isVisible()) {
        gl->swapBuffers(window);
        cd->fireFrameSwapped();
    }

    qint64 swapTime = 0;
    if (profileFrames) {
        swapTime = renderTimer.nsecsElapsed() - renderTime - syncTime;
    }

    if (qsg_render_timing()) {
        static QTime lastFrameTime = QTime::currentTime();
        qDebug() << "- Breakdown of frame time; sync:" << syncTime/1000000
                 << "ms render:" << renderTime/1000000 << "ms swap:" << swapTime/1000000
                 << "ms total:" << (swapTime + renderTime + syncTime)/1000000
                 << "ms time since last frame:" << (lastFrameTime.msecsTo(QTime::currentTime()))
                 << "ms";
        lastFrameTime = QTime::currentTime();
    }

    Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphRenderLoopFrame, (
            syncTime,
            renderTime,
            swapTime));

    // Might have been set during syncSceneGraph()
    if (data.updatePending)
        maybeUpdate(window);
}

void QSGGuiThreadRenderLoop::exposureChanged(QQuickWindow *window)
{
    if (window->isExposed()) {
        m_windows[window].updatePending = true;
        renderWindow(window);
    }
}

QImage QSGGuiThreadRenderLoop::grab(QQuickWindow *window)
{
    if (!m_windows.contains(window))
        return QImage();

    m_windows[window].grabOnly = true;

    renderWindow(window);

    QImage grabbed = grabContent;
    grabContent = QImage();
    return grabbed;
}

void QSGGuiThreadRenderLoop::maybeUpdate(QQuickWindow *window)
{
    if (!m_windows.contains(window))
        return;

    m_windows[window].updatePending = true;

    if (!eventPending) {
        const int exhaust_delay = 5;
        m_update_timer = startTimer(exhaust_delay, Qt::PreciseTimer);
        eventPending = true;
    }
}

QSGContext *QSGGuiThreadRenderLoop::sceneGraphContext() const
{
    return sg;
}

bool QSGGuiThreadRenderLoop::event(QEvent *e)
{
    if (e->type() == QEvent::Timer) {
        eventPending = false;
        killTimer(m_update_timer);
        m_update_timer = 0;
        for (QHash<QQuickWindow *, WindowData>::const_iterator it = m_windows.constBegin();
             it != m_windows.constEnd(); ++it) {
            const WindowData &data = it.value();
            if (data.updatePending)
                renderWindow(it.key());
        }
        return true;
    }
    return QObject::event(e);
}

#include "qsgrenderloop.moc"

QT_END_NAMESPACE
<|endoftext|>


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

#include <mavsdk/mavsdk.h>
#include <mavsdk/plugins/action/action.h>
#include <mavsdk/plugins/telemetry/telemetry.h>
#include <iostream>
#include <string>
#include "autopilot_tester.h"

TEST_CASE("Offboard takeoff and land", "[multicopter][offboard][nogps]")
{
	AutopilotTester tester;
	Offboard::PositionNedYaw takeoff_position {0.0f, 0.0f, -2.0f, 0.0f};
	tester.connect(connection_url);
	tester.wait_until_ready_local_position_only();
	tester.store_home();
	tester.arm();
	std::chrono::seconds goto_timeout = std::chrono::seconds(20);
	tester.offboard_goto(takeoff_position, 0.1f, goto_timeout);
	tester.offboard_land();
	tester.wait_until_disarmed(goto_timeout);
	tester.check_home_within(1.0f);
}

TEST_CASE("Offboard position control", "[multicopter][offboard][nogps]")
{
	AutopilotTester tester;
	Offboard::PositionNedYaw takeoff_position {0.0f, 0.0f, -2.0f, 0.0f};
	Offboard::PositionNedYaw setpoint_1 {0.0f, 5.0f, -2.0f, 180.0f};
	Offboard::PositionNedYaw setpoint_2 {5.0f, 5.0f, -4.0f, 180.0f};
	Offboard::PositionNedYaw setpoint_3 {5.0f, 0.0f, -4.0f, 90.0f};
	tester.connect(connection_url);
	tester.wait_until_ready_local_position_only();
	tester.store_home();
	tester.arm();
	std::chrono::seconds goto_timeout = std::chrono::seconds(20);
	tester.offboard_goto(takeoff_position, 0.1f, goto_timeout);
	tester.offboard_goto(setpoint_1, 0.1f, goto_timeout);
	tester.offboard_goto(setpoint_2, 0.1f, goto_timeout);
	tester.offboard_goto(setpoint_3, 0.1f, goto_timeout);
	tester.offboard_goto(takeoff_position, 0.1f, goto_timeout);
	tester.offboard_land();
	tester.wait_until_disarmed(goto_timeout);
	tester.check_home_within(1.0f);
}
<commit_msg>mavsdk_tests: temporarily disable offboard position control test<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2020 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

#include <mavsdk/mavsdk.h>
#include <mavsdk/plugins/action/action.h>
#include <mavsdk/plugins/telemetry/telemetry.h>
#include <iostream>
#include <string>
#include "autopilot_tester.h"

TEST_CASE("Offboard takeoff and land", "[multicopter][offboard][nogps]")
{
	AutopilotTester tester;
	Offboard::PositionNedYaw takeoff_position {0.0f, 0.0f, -2.0f, 0.0f};
	tester.connect(connection_url);
	tester.wait_until_ready_local_position_only();
	tester.store_home();
	tester.arm();
	std::chrono::seconds goto_timeout = std::chrono::seconds(20);
	tester.offboard_goto(takeoff_position, 0.1f, goto_timeout);
	tester.offboard_land();
	tester.wait_until_disarmed(goto_timeout);
	tester.check_home_within(1.0f);
}

// TEST_CASE("Offboard position control", "[multicopter][offboard][nogps]")
// {
// 	AutopilotTester tester;
// 	Offboard::PositionNedYaw takeoff_position {0.0f, 0.0f, -2.0f, 0.0f};
// 	Offboard::PositionNedYaw setpoint_1 {0.0f, 5.0f, -2.0f, 180.0f};
// 	Offboard::PositionNedYaw setpoint_2 {5.0f, 5.0f, -4.0f, 180.0f};
// 	Offboard::PositionNedYaw setpoint_3 {5.0f, 0.0f, -4.0f, 90.0f};
// 	tester.connect(connection_url);
// 	tester.wait_until_ready_local_position_only();
// 	tester.store_home();
// 	tester.arm();
// 	std::chrono::seconds goto_timeout = std::chrono::seconds(20);
// 	tester.offboard_goto(takeoff_position, 0.1f, goto_timeout);
// 	tester.offboard_goto(setpoint_1, 0.1f, goto_timeout);
// 	tester.offboard_goto(setpoint_2, 0.1f, goto_timeout);
// 	tester.offboard_goto(setpoint_3, 0.1f, goto_timeout);
// 	tester.offboard_goto(takeoff_position, 0.1f, goto_timeout);
// 	tester.offboard_land();
// 	tester.wait_until_disarmed(goto_timeout);
// 	tester.check_home_within(1.0f);
// }
<|endoftext|>