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

#include "generator.h"
#include "device.h"

#include <QDBusReply>
#include <QDBusMessage>
#include <QDBusConnection>

#include <kdebug.h>
#include <kscreen/config.h>

Generator* Generator::instance = 0;

Generator* Generator::self()
{
    if (!Generator::instance) {
        Generator::instance = new Generator();
    }
    return Generator::instance;
}

Generator::Generator()
 : QObject()
 , m_isReady(false)
 , m_forceLaptop(false)
 , m_forceLidClosed(false)
 , m_forceDocked(false)
{
    connect(Device::self(), SIGNAL(ready()), SIGNAL(ready()));
}

void Generator::destroy()
{
    delete Generator::instance;
    Generator::instance = 0;
}

Generator::~Generator()
{
}

KScreen::Config* Generator::idealConfig()
{
    KDebug::Block idealBlock("Ideal Config");
    KScreen::Config* config = KScreen::Config::current();
    if (!config) {
        kDebug() << "Unable get current config";
        return 0;
    }

    disableAllDisconnectedOutputs(config->outputs());

    KScreen::OutputList outputs = config->connectedOutputs();

    kDebug() << "Connected outputs: " << outputs.count();

    if (outputs.isEmpty()) {
        return config;
    }

    if (outputs.count() == 1) {
        singleOutput(outputs);
        return config;
    }

    if (isLaptop()) {
        laptop(outputs);
        return fallbackIfNeeded(config);
    }

    extendToRight(outputs);

    return fallbackIfNeeded(config);
}

KScreen::Config* Generator::fallbackIfNeeded(KScreen::Config* config)
{
    //If the ideal config can't be applied, try clonning
    if (!KScreen::Config::canBeApplied(config)) {
        delete config;
        config = displaySwitch(1);// Try to clone at our best
    }

    //If after trying to clone at our best, we fail... return current
    if (!KScreen::Config::canBeApplied(config)) {
        delete config;
        config = KScreen::Config::current();
    }

    return config;
}

KScreen::Config* Generator::displaySwitch(int iteration)
{
    KDebug::Block switchBlock("Display Switch");
    KScreen::Config* config = KScreen::Config::current();
    if (!config) {
        kDebug() << "Unable to get current config";
        return 0;
    }

    KScreen::OutputList outputs = config->connectedOutputs();

    if (outputs.count() < 2) {
        singleOutput(outputs);
        return config;
    }

    if (outputs.count() > 2) {
        extendToRight(outputs);
        return config;
    }

    KScreen::Output* embedded, *external;
    embedded = embeddedOutput(outputs);
    if (embedded) {
        outputs.remove(embedded->id());
    }
    external = outputs.value(outputs.keys().first());

    if (iteration == 1) {
        kDebug() << "Cloning";
        KScreen::ModeList embeddedModes = embedded->modes();
        QMap<QString, QSize> embeddedModeSize;
        Q_FOREACH(KScreen::Mode* mode, embeddedModes) {
            embeddedModeSize.insert(mode->id(), mode->size());
        }

        QList<QString> embeddedKeys;
        KScreen::ModeList externalCommon;
        KScreen::ModeList externalModes = external->modes();
        Q_FOREACH(KScreen::Mode* mode, externalModes) {
            if (!embeddedModeSize.keys(mode->size()).isEmpty()) {
                externalCommon.insert(mode->id(), mode);
                embeddedKeys.append(embeddedModeSize.keys(mode->size()));
            }
        }

        KScreen::ModeList embeddedCommon;
        Q_FOREACH(const QString& key, embeddedKeys) {
            embeddedCommon.insert(key, embeddedModes[key]);
        }

        KScreen::Mode* biggestEmbedded = !embeddedCommon.empty() ? biggestMode(embeddedCommon) : biggestMode(embeddedModes);
        KScreen::Mode* biggestExternal = !externalCommon.empty() ? biggestMode(externalCommon) : biggestMode(externalModes);

        embedded->setEnabled(true);
        embedded->setPos(QPoint(0,0));
        embedded->setCurrentModeId(biggestEmbedded->id());
        external->setEnabled(true);
        external->setPos(QPoint(0,0));
        external->setCurrentModeId(biggestExternal->id());

        return config;
    }

    if (iteration == 2) {
        kDebug() << "Extend to left";
        external->setEnabled(true);
        external->setPos(QPoint(0,0));
        external->setCurrentModeId(external->preferredModeId());

        QSize size = external->currentMode()->size();
        embedded->setPos(QPoint(size.width(), 0));
        embedded->setEnabled(true);
        embedded->setCurrentModeId(embedded->preferredModeId());
        embedded->setPrimary(true);
        return config;
    }

    if (iteration == 3) {
        kDebug() << "Turn of embedded (laptop)";
        embedded->setEnabled(false);
        embedded->setPrimary(false);

        external->setEnabled(true);
        external->setPrimary(true);
        external->setCurrentModeId(external->preferredModeId());
        return config;
    }

    if (iteration == 4) {
        kDebug() << "Turn off external screen";
        embedded->setEnabled(true);
        embedded->setPrimary(true);
        embedded->setPos(QPoint(0,0));
        embedded->setCurrentModeId(embedded->preferredModeId());

        external->setEnabled(false);
        external->setPrimary(false);
        return config;
    }

    if (iteration == 5) {
        kDebug() << "Extend to the right";
        embedded->setPos(QPoint(0,0));
        embedded->setCurrentModeId(embedded->preferredModeId());
        embedded->setPrimary(true);
        embedded->setEnabled(true);

        QSize size = embedded->currentMode()->size();
        external->setPos(QPoint(size.width(), 0));
        external->setEnabled(true);
        external->setCurrentModeId(external->preferredModeId());
        external->setPrimary(false);

        return config;
    }

    return config;
}

void Generator::singleOutput(KScreen::OutputList& outputs)
{
    Q_ASSERT(!outputs.isEmpty());

    KScreen::Output* output = outputs.take(outputs.keys().first());
    Q_ASSERT(output);

    output->setCurrentModeId(output->preferredModeId());
    output->setEnabled(true);
    output->setPrimary(true);
    output->setPos(QPoint(0,0));
}

void Generator::laptop(KScreen::OutputList& outputs)
{
    Q_ASSERT(!outputs.isEmpty());

    KDebug::Block laptopBlock("Laptop config");

    KScreen::Output* embedded = embeddedOutput(outputs);
    /* Apparently older laptops use "VGA-*" as embedded output ID, so embeddedOutput()
     * will fail, because it looks only for modern "LVDS", "EDP", etc. If we
     * fail to detect which output is embedded, just use the one  with the lowest
     * ID. It's a wild guess, but I think it's highly probable that it will work.
     * See bug #318907 for further reference. -- dvratil
     */
    if (!embedded) {
        QList<int> keys = outputs.keys();
        qSort(keys);
        embedded = outputs.value(keys.first());
    }
    outputs.remove(embedded->id());

    if (outputs.isEmpty()) {
        kWarning() << "No external outputs found, going for singleOutput()";
        outputs.insert(embedded->id(), embedded);
        return singleOutput(outputs);
    }

    if (isLidClosed() && outputs.count() == 1) {
        kDebug() << "With lid closed";
        embedded->setEnabled(false);
        embedded->setPrimary(false);

        KScreen::Output* external = outputs.value(outputs.keys().first());
        external->setEnabled(true);
        external->setPrimary(true);
        external->setCurrentModeId(external->preferredModeId());
        external->setPos(QPoint(0, 0));

        return;
    }

    if (isLidClosed() && outputs.count() > 1) {
        kDebug() << "Lid is closed, and more than one output";
        embedded->setEnabled(false);
        embedded->setPrimary(false);

        extendToRight(outputs);
        return;
    }

    kDebug() << "Lid is open";
    //If lid is open, laptop screen shuold be primary
    embedded->setPos(QPoint(0,0));
    embedded->setCurrentModeId(embedded->preferredModeId());
    embedded->setPrimary(true);
    embedded->setEnabled(true);

    int globalWidth;
    if (embedded->isHorizontal()) {
        globalWidth = embedded->preferredMode()->size().width();
    } else {
        globalWidth = embedded->preferredMode()->size().height();
    }
    KScreen::Output* biggest = biggestOutput(outputs);
    outputs.remove(biggest->id());

    biggest->setPos(QPoint(globalWidth, 0));
    biggest->setEnabled(true);
    biggest->setCurrentModeId(biggest->preferredModeId());
    biggest->setPrimary(false);

    if (biggest->isHorizontal()) {
        globalWidth += biggest->currentMode()->size().width();
    } else {
        globalWidth += biggest->currentMode()->size().height();
    }
    Q_FOREACH(KScreen::Output* output, outputs) {
        output->setEnabled(true);
        output->setCurrentModeId(output->preferredModeId());
        output->setPos(QPoint(globalWidth, 0));
        output->setPrimary(false);

        if (output->isHorizontal()) {
            globalWidth += output->currentMode()->size().width();
        } else {
            globalWidth += output->currentMode()->size().height();
        }
    }

    if (isDocked()) {
        kDebug() << "Docked";
        embedded->setPrimary(false);
        biggest->setPrimary(true);
    }
}

void Generator::extendToRight(KScreen::OutputList& outputs)
{
    Q_ASSERT(!outputs.isEmpty());

    kDebug() << "Extending to the right";
    KScreen::Output* biggest = biggestOutput(outputs);
    Q_ASSERT(biggest);

    outputs.remove(biggest->id());

    biggest->setEnabled(true);
    biggest->setPrimary(true);
    biggest->setCurrentModeId(biggest->preferredModeId());
    biggest->setPos(QPoint(0,0));

    int globalWidth;
    if (biggest->isHorizontal()) {
        globalWidth = biggest->currentMode()->size().width();
    } else {
        globalWidth = biggest->currentMode()->size().height();
    }

    Q_FOREACH(KScreen::Output* output, outputs) {
        output->setEnabled(true);
        output->setPrimary(false);
        output->setCurrentModeId(output->preferredModeId());
        output->setPos(QPoint(globalWidth, 0));

        if (output->isHorizontal()) {
            globalWidth += output->currentMode()->size().width();
        } else {
            globalWidth += output->currentMode()->size().height();
        }
    }
}

KScreen::Mode* Generator::biggestMode(const KScreen::ModeList& modes)
{
    int area, total = 0;
    KScreen::Mode* biggest = 0;
    Q_FOREACH(KScreen::Mode* mode, modes) {
        area = mode->size().width() * mode->size().height();
        if (area < total) {
            continue;
        }
        if (area == total && mode->refreshRate() < biggest->refreshRate()) {
            continue;
        }
        if (area == total && mode->refreshRate() > biggest->refreshRate()) {
            biggest = mode;
            continue;
        }

        total = area;
        biggest = mode;
    }

    return biggest;
}

KScreen::Output* Generator::biggestOutput(const KScreen::OutputList &outputs)
{
    int area, total = 0;
    KScreen::Output* biggest = 0;
    Q_FOREACH(KScreen::Output* output, outputs) {
        KScreen::Mode* mode = output->preferredMode();
        area = mode->size().width() * mode->size().height();
        if (area <= total) {
            continue;
        }

        total = area;
        biggest = output;
    }

    return biggest;
}

void Generator::disableAllDisconnectedOutputs(const KScreen::OutputList& outputs)
{
    KDebug::Block disableBlock("Disabling disconnected screens");
    Q_FOREACH(KScreen::Output* output, outputs) {
        if (!output->isConnected()) {
            kDebug() << output->name() << " Disabled";
            output->setEnabled(false);
            output->setPrimary(false);
        }
    }
}

KScreen::Output* Generator::embeddedOutput(const KScreen::OutputList& outputs)
{
    Q_FOREACH(KScreen::Output* output, outputs) {
        if (output->type() != KScreen::Output::Panel) {
            continue;
        }

        return output;
    }

    return 0;
}

bool Generator::isLaptop()
{
    if (m_forceLaptop) {
        return true;
    }

    return Device::self()->isLaptop();
}

bool Generator::isLidClosed()
{
    if (m_forceLidClosed) {
        return true;
    }

    return Device::self()->isLidClosed();
}

bool Generator::isDocked()
{
    if (m_forceDocked) {
        return true;
    }

    return Device::self()->isDocked();
}

void Generator::setForceLaptop(bool force)
{
    m_forceLaptop = force;
}

void Generator::setForceLidClosed(bool force)
{
    m_forceLidClosed = force;
}

void Generator::setForceDocked(bool force)
{
    m_forceDocked = force;
}

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

#include "generator.h"
#include "device.h"

#include <QDBusReply>
#include <QDBusMessage>
#include <QDBusConnection>

#include <kdebug.h>
#include <kscreen/config.h>

Generator* Generator::instance = 0;

Generator* Generator::self()
{
    if (!Generator::instance) {
        Generator::instance = new Generator();
    }
    return Generator::instance;
}

Generator::Generator()
 : QObject()
 , m_isReady(false)
 , m_forceLaptop(false)
 , m_forceLidClosed(false)
 , m_forceDocked(false)
{
    connect(Device::self(), SIGNAL(ready()), SIGNAL(ready()));
}

void Generator::destroy()
{
    delete Generator::instance;
    Generator::instance = 0;
}

Generator::~Generator()
{
}

KScreen::Config* Generator::idealConfig()
{
    KDebug::Block idealBlock("Ideal Config");
    KScreen::Config* config = KScreen::Config::current();
    if (!config) {
        kDebug() << "Unable get current config";
        return 0;
    }

    disableAllDisconnectedOutputs(config->outputs());

    KScreen::OutputList outputs = config->connectedOutputs();

    kDebug() << "Connected outputs: " << outputs.count();

    if (outputs.isEmpty()) {
        return config;
    }

    if (outputs.count() == 1) {
        singleOutput(outputs);
        return config;
    }

    if (isLaptop()) {
        laptop(outputs);
        return fallbackIfNeeded(config);
    }

    extendToRight(outputs);

    return fallbackIfNeeded(config);
}

KScreen::Config* Generator::fallbackIfNeeded(KScreen::Config* config)
{
    //If the ideal config can't be applied, try clonning
    if (!KScreen::Config::canBeApplied(config)) {
        delete config;
        config = displaySwitch(1);// Try to clone at our best
    }

    //If after trying to clone at our best, we fail... return current
    if (!KScreen::Config::canBeApplied(config)) {
        delete config;
        config = KScreen::Config::current();
    }

    return config;
}

KScreen::Config* Generator::displaySwitch(int iteration)
{
    KDebug::Block switchBlock("Display Switch");
    KScreen::Config* config = KScreen::Config::current();
    if (!config) {
        kDebug() << "Unable to get current config";
        return 0;
    }

    KScreen::OutputList outputs = config->connectedOutputs();

    if (outputs.count() < 2) {
        singleOutput(outputs);
        return config;
    }

    if (outputs.count() > 2) {
        extendToRight(outputs);
        return config;
    }

    KScreen::Output* embedded, *external;
    embedded = embeddedOutput(outputs);
    if (embedded) {
        outputs.remove(embedded->id());
    }
    external = outputs.value(outputs.keys().first());

    if (iteration == 1) {
        kDebug() << "Cloning";
        KScreen::ModeList embeddedModes = embedded->modes();
        QMap<QString, QSize> embeddedModeSize;
        Q_FOREACH(KScreen::Mode* mode, embeddedModes) {
            embeddedModeSize.insert(mode->id(), mode->size());
        }

        QList<QString> embeddedKeys;
        KScreen::ModeList externalCommon;
        KScreen::ModeList externalModes = external->modes();
        Q_FOREACH(KScreen::Mode* mode, externalModes) {
            if (!embeddedModeSize.keys(mode->size()).isEmpty()) {
                externalCommon.insert(mode->id(), mode);
                embeddedKeys.append(embeddedModeSize.keys(mode->size()));
            }
        }

        KScreen::ModeList embeddedCommon;
        Q_FOREACH(const QString& key, embeddedKeys) {
            embeddedCommon.insert(key, embeddedModes[key]);
        }

        KScreen::Mode* biggestEmbedded = !embeddedCommon.empty() ? biggestMode(embeddedCommon) : biggestMode(embeddedModes);
        KScreen::Mode* biggestExternal = !externalCommon.empty() ? biggestMode(externalCommon) : biggestMode(externalModes);

        embedded->setEnabled(true);
        embedded->setPos(QPoint(0,0));
        embedded->setCurrentModeId(biggestEmbedded->id());
        external->setEnabled(true);
        external->setPos(QPoint(0,0));
        external->setCurrentModeId(biggestExternal->id());

        return config;
    }

    if (iteration == 2) {
        kDebug() << "Extend to left";
        external->setEnabled(true);
        external->setPos(QPoint(0,0));
        external->setCurrentModeId(external->preferredModeId());

        QSize size = external->currentMode()->size();
        embedded->setPos(QPoint(size.width(), 0));
        embedded->setEnabled(true);
        embedded->setCurrentModeId(embedded->preferredModeId());
        embedded->setPrimary(true);
        return config;
    }

    if (iteration == 3) {
        kDebug() << "Turn of embedded (laptop)";
        embedded->setEnabled(false);
        embedded->setPrimary(false);

        external->setEnabled(true);
        external->setPrimary(true);
        external->setCurrentModeId(external->preferredModeId());
        return config;
    }

    if (iteration == 4) {
        kDebug() << "Turn off external screen";
        embedded->setEnabled(true);
        embedded->setPrimary(true);
        embedded->setPos(QPoint(0,0));
        embedded->setCurrentModeId(embedded->preferredModeId());

        external->setEnabled(false);
        external->setPrimary(false);
        return config;
    }

    if (iteration == 5) {
        kDebug() << "Extend to the right";
        embedded->setPos(QPoint(0,0));
        embedded->setCurrentModeId(embedded->preferredModeId());
        embedded->setPrimary(true);
        embedded->setEnabled(true);

        QSize size = embedded->currentMode()->size();
        external->setPos(QPoint(size.width(), 0));
        external->setEnabled(true);
        external->setCurrentModeId(external->preferredModeId());
        external->setPrimary(false);

        return config;
    }

    return config;
}

void Generator::singleOutput(KScreen::OutputList& outputs)
{
    Q_ASSERT(!outputs.isEmpty());

    KScreen::Output* output = outputs.take(outputs.keys().first());
    Q_ASSERT(output);

    output->setCurrentModeId(output->preferredModeId());
    output->setEnabled(true);
    output->setPrimary(true);
    output->setPos(QPoint(0,0));
}

void Generator::laptop(KScreen::OutputList& outputs)
{
    Q_ASSERT(!outputs.isEmpty());

    KDebug::Block laptopBlock("Laptop config");

    KScreen::Output* embedded = embeddedOutput(outputs);
    /* Apparently older laptops use "VGA-*" as embedded output ID, so embeddedOutput()
     * will fail, because it looks only for modern "LVDS", "EDP", etc. If we
     * fail to detect which output is embedded, just use the one  with the lowest
     * ID. It's a wild guess, but I think it's highly probable that it will work.
     * See bug #318907 for further reference. -- dvratil
     */
    if (!embedded) {
        QList<int> keys = outputs.keys();
        qSort(keys);
        embedded = outputs.value(keys.first());
    }
    outputs.remove(embedded->id());

    if (outputs.isEmpty()) {
        kWarning() << "No external outputs found, going for singleOutput()";
        outputs.insert(embedded->id(), embedded);
        return singleOutput(outputs);
    }

    if (isLidClosed() && outputs.count() == 1) {
        kDebug() << "With lid closed";
        embedded->setEnabled(false);
        embedded->setPrimary(false);

        KScreen::Output* external = outputs.value(outputs.keys().first());
        external->setEnabled(true);
        external->setPrimary(true);
        external->setCurrentModeId(external->preferredModeId());
        external->setPos(QPoint(0, 0));

        return;
    }

    if (isLidClosed() && outputs.count() > 1) {
        kDebug() << "Lid is closed, and more than one output";
        embedded->setEnabled(false);
        embedded->setPrimary(false);

        extendToRight(outputs);
        return;
    }

    kDebug() << "Lid is open";
    //If lid is open, laptop screen shuold be primary
    embedded->setPos(QPoint(0,0));
    embedded->setCurrentModeId(embedded->preferredModeId());
    embedded->setPrimary(true);
    embedded->setEnabled(true);

    int globalWidth;
    if (embedded->isHorizontal()) {
        globalWidth = embedded->preferredMode()->size().width();
    } else {
        globalWidth = embedded->preferredMode()->size().height();
    }
    KScreen::Output* biggest = biggestOutput(outputs);
    outputs.remove(biggest->id());

    biggest->setPos(QPoint(globalWidth, 0));
    biggest->setEnabled(true);
    biggest->setCurrentModeId(biggest->preferredModeId());
    biggest->setPrimary(false);

    if (biggest->isHorizontal()) {
        globalWidth += biggest->currentMode()->size().width();
    } else {
        globalWidth += biggest->currentMode()->size().height();
    }
    Q_FOREACH(KScreen::Output* output, outputs) {
        output->setEnabled(true);
        output->setCurrentModeId(output->preferredModeId());
        output->setPos(QPoint(globalWidth, 0));
        output->setPrimary(false);

        if (output->isHorizontal()) {
            globalWidth += output->currentMode()->size().width();
        } else {
            globalWidth += output->currentMode()->size().height();
        }
    }

    if (isDocked()) {
        kDebug() << "Docked";
        embedded->setPrimary(false);
        biggest->setPrimary(true);
    }
}

void Generator::extendToRight(KScreen::OutputList& outputs)
{
    Q_ASSERT(!outputs.isEmpty());

    kDebug() << "Extending to the right";
    KScreen::Output* biggest = biggestOutput(outputs);
    Q_ASSERT(biggest);

    outputs.remove(biggest->id());

    biggest->setEnabled(true);
    biggest->setPrimary(true);
    biggest->setCurrentModeId(biggest->preferredModeId());
    biggest->setPos(QPoint(0,0));

    int globalWidth;
    if (biggest->isHorizontal()) {
        globalWidth = biggest->currentMode()->size().width();
    } else {
        globalWidth = biggest->currentMode()->size().height();
    }

    Q_FOREACH(KScreen::Output* output, outputs) {
        output->setEnabled(true);
        output->setPrimary(false);
        output->setCurrentModeId(output->preferredModeId());
        output->setPos(QPoint(globalWidth, 0));

        if (output->isHorizontal()) {
            globalWidth += output->currentMode()->size().width();
        } else {
            globalWidth += output->currentMode()->size().height();
        }
    }
}

KScreen::Mode* Generator::biggestMode(const KScreen::ModeList& modes)
{
    int modeArea, biggestArea = 0;
    KScreen::Mode* biggestMode = 0;
    Q_FOREACH(KScreen::Mode* mode, modes) {
        modeArea = mode->size().width() * mode->size().height();
        if (modeArea < biggestArea) {
            continue;
        }
        if (modeArea == biggestArea && mode->refreshRate() < biggestMode->refreshRate()) {
            continue;
        }
        if (modeArea == biggestArea && mode->refreshRate() > biggestMode->refreshRate()) {
            biggestMode = mode;
            continue;
        }

        biggestArea = modeArea;
        biggestMode = mode;
    }

    return biggestMode;
}

KScreen::Output* Generator::biggestOutput(const KScreen::OutputList &outputs)
{
    int area, total = 0;
    KScreen::Output* biggest = 0;
    Q_FOREACH(KScreen::Output* output, outputs) {
        KScreen::Mode* mode = output->preferredMode();
        area = mode->size().width() * mode->size().height();
        if (area <= total) {
            continue;
        }

        total = area;
        biggest = output;
    }

    return biggest;
}

void Generator::disableAllDisconnectedOutputs(const KScreen::OutputList& outputs)
{
    KDebug::Block disableBlock("Disabling disconnected screens");
    Q_FOREACH(KScreen::Output* output, outputs) {
        if (!output->isConnected()) {
            kDebug() << output->name() << " Disabled";
            output->setEnabled(false);
            output->setPrimary(false);
        }
    }
}

KScreen::Output* Generator::embeddedOutput(const KScreen::OutputList& outputs)
{
    Q_FOREACH(KScreen::Output* output, outputs) {
        if (output->type() != KScreen::Output::Panel) {
            continue;
        }

        return output;
    }

    return 0;
}

bool Generator::isLaptop()
{
    if (m_forceLaptop) {
        return true;
    }

    return Device::self()->isLaptop();
}

bool Generator::isLidClosed()
{
    if (m_forceLidClosed) {
        return true;
    }

    return Device::self()->isLidClosed();
}

bool Generator::isDocked()
{
    if (m_forceDocked) {
        return true;
    }

    return Device::self()->isDocked();
}

void Generator::setForceLaptop(bool force)
{
    m_forceLaptop = force;
}

void Generator::setForceLidClosed(bool force)
{
    m_forceLidClosed = force;
}

void Generator::setForceDocked(bool force)
{
    m_forceDocked = force;
}

#include "generator.moc"
<|endoftext|>


<commit_before>/*
 * Copyright 2019 Google Inc.
 *
 * 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 "p2a.hpp"

#include "pci.hpp"

namespace host_tool
{

bool P2aDataHandler::sendContents(const std::string& input,
                                  std::uint16_t session)
{
    PciDevice result;
    PciUtilImpl pci;
    PciFilter filter;

    filter.vid = aspeedVendorId;
    filter.did = aspeedDeviceId;

    /* Find the ASPEED PCI device entry we want. */
    auto output = pci.getPciDevices(filter);
    for (const auto& d : output)
    {
        std::fprintf(stderr, "[0x%x 0x%x] ", d.vid, d.did);

        /* Verify it's a memory-based bar -- we want bar1. */
        pciaddr_t bar1 = d.bars[1];
        if ((bar1 & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
        {
            /* We want it to not be IO-based access. */
            continue;
        }

        result = d;
    }
    std::fprintf(stderr, "\n");

    /* We sent the open command before this, so the window should be open and
     * the bridge enabled.
     */
    std::uint32_t value;
    if (!io->read(result.bars[1] | aspeedP2aConfig, sizeof(value), &value))
    {
        if (0 == (value & p2ABridgeEnabled))
        {
            std::fprintf(stderr, "Bridge not enabled.\n");
            return false;
        }
    }

    std::fprintf(stderr, "The bridge is enabled!\n");

    /* Read the configuration via blobs metadata (stat). */

#if 0
    /* Configure the mmio to point there. */
    if (!io->IoWrite(bar | kAspeedP2aBridge, sizeof(phys), &phys)) {
        // Failed to set it up, so fall back.
        std::fprintf(stderr, "Failed to update the bridge address\n");
        return false;
    }
#endif

    return false;
}

} // namespace host_tool
<commit_msg>bugfix: result.bars[1] may be used uninitialized<commit_after>/*
 * Copyright 2019 Google Inc.
 *
 * 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 "p2a.hpp"

#include "pci.hpp"

namespace host_tool
{

bool P2aDataHandler::sendContents(const std::string& input,
                                  std::uint16_t session)
{
    PciDevice result;
    PciUtilImpl pci;
    PciFilter filter;
    bool found = false;

    filter.vid = aspeedVendorId;
    filter.did = aspeedDeviceId;

    /* Find the ASPEED PCI device entry we want. */
    auto output = pci.getPciDevices(filter);
    for (const auto& d : output)
    {
        std::fprintf(stderr, "[0x%x 0x%x] ", d.vid, d.did);

        /* Verify it's a memory-based bar -- we want bar1. */
        pciaddr_t bar1 = d.bars[1];
        if ((bar1 & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
        {
            /* We want it to not be IO-based access. */
            continue;
        }

        result = d;
        found = true;
        break;
    }

    if (!found)
    {
        return false;
    }

    std::fprintf(stderr, "\n");

    /* We sent the open command before this, so the window should be open and
     * the bridge enabled.
     */
    std::uint32_t value;
    if (!io->read(result.bars[1] | aspeedP2aConfig, sizeof(value), &value))
    {
        if (0 == (value & p2ABridgeEnabled))
        {
            std::fprintf(stderr, "Bridge not enabled.\n");
            return false;
        }
    }

    std::fprintf(stderr, "The bridge is enabled!\n");

    /* Read the configuration via blobs metadata (stat). */

#if 0
    /* Configure the mmio to point there. */
    if (!io->IoWrite(bar | kAspeedP2aBridge, sizeof(phys), &phys)) {
        // Failed to set it up, so fall back.
        std::fprintf(stderr, "Failed to update the bridge address\n");
        return false;
    }
#endif

    return false;
}

} // namespace host_tool
<|endoftext|>


<commit_before>/**
 *  @copyright Copyright 2016 The J-PET Framework Authors. All rights reserved.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may find a copy of the License in the LICENCE file.
 *
 *  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.
 *
 *  @file JPetCmdParser.cpp
 */

#include "JPetCmdParser.h"
#include <iostream>
#include "../JPetCommonTools/JPetCommonTools.h"
#include "../JPetLoggerInclude.h"
#include "../JPetScopeConfigParser/JPetScopeConfigParser.h"
#include <stdexcept>

JPetCmdParser::JPetCmdParser(): fOptionsDescriptions("Allowed options")
{
  fOptionsDescriptions.add_options()
  ("help,h", "Displays this help message.")
  ("type,t", po::value<std::string>()->required()->implicit_value(""), "Type of file: hld, zip, root or scope.")
  ("file,f", po::value< std::vector<std::string> >()->required()->multitoken(), "File(s) to open.")
  ("outputPath,o", po::value<std::string>(), "Location to which the outputFiles will be saved.")
  ("range,r", po::value< std::vector<int> >()->multitoken()->default_value({ -1, -1}, ""), "Range of events to process e.g. -r 1 1000 .")
  ("param,p", po::value<std::string>(), "xml file with TRB settings used by the unpacker program.")
  ("runId,i", po::value<int>(), "Run id.")
  ("progressBar,b", "Progress bar.")
  ("localDB,l", po::value<std::string>(), "The file to use as the parameter database.")
  ("localDBCreate,L", po::value<std::string>(), "File name to which the parameter database will be saved.");
}

JPetCmdParser::~JPetCmdParser()
{
  /**/
}

std::vector<JPetOptions> JPetCmdParser::parseAndGenerateOptions(int argc, const char** argv)
{
  po::variables_map variablesMap;
  if (argc == 1) {
    ERROR("No options provided.");
    std::cerr << getOptionsDescription() << "\n";
    throw std::invalid_argument("No options provided.");
  }

  po::store(po::parse_command_line(argc, argv, fOptionsDescriptions), variablesMap);

  /* print out help */
  if (variablesMap.count("help")) {
    std::cout << getOptionsDescription() << "\n";
    exit(0);
  }
  po::notify(variablesMap);
  if (!areCorrectOptions(variablesMap)) {
    throw std::invalid_argument("Wrong user options provided! Check the log!");
  }

  return generateOptions(variablesMap);
}

bool JPetCmdParser::areCorrectOptions(const po::variables_map& variablesMap) const
{
  /* Parse range of events */
  if (variablesMap.count("range")) {
    if (variablesMap["range"].as< std::vector<int> >().size() != 2) {
      ERROR("Wrong number of bounds in range.");
      std::cerr << "Wrong number of bounds in range: " << variablesMap["range"].as< std::vector<int> >().size() << std::endl;
      return false;
    }
    if (
      variablesMap["range"].as< std::vector<int> >()[0]
      > variablesMap["range"].as< std::vector<int> >()[1]) {
      ERROR("Wrong range of events.");
      std::cerr << "Wrong range of events." << std::endl;
      return false;
    }
  }

  if (!isCorrectFileType(getFileType(variablesMap))) {
    ERROR("Wrong type of file.");
    std::cerr << "Wrong type of file: " << getFileType(variablesMap) << std::endl;
    std::cerr << "Possible options: hld, root or scope" << std::endl;
    return false;
  }

  if (isRunNumberSet(variablesMap)) {
    int l_runId = variablesMap["runId"].as<int>();

    if (l_runId <= 0) {
      ERROR("Run id must be a number larger than 0.");
      std::cerr << "Run id must be a number larger than 0." << l_runId << std::endl;
      return false;
    }
  }

  if (isProgressBarSet(variablesMap)) {
    int l_progressBar = variablesMap["progressBar"].as<int>();

    if (l_progressBar != 0 && l_progressBar != 1) {
      ERROR("Wrong parameter of progressbar.");
      std::cerr << "Wrong parameter of progressbar: " << l_progressBar << std::endl;
      return false;
    }
  }

  if (isLocalDBSet(variablesMap)) {
    std::string localDBName = getLocalDBName(variablesMap);
    if ( !JPetCommonTools::ifFileExisting(localDBName) ) {
      ERROR("File : " + localDBName + " does not exist.");
      std::cerr << "File : " << localDBName << " does not exist" << std::endl;
      return false;
    }
  }

  std::vector<std::string> fileNames(variablesMap["file"].as< std::vector<std::string> >());
  for (unsigned int i = 0; i < fileNames.size(); i++) {
    if ( ! JPetCommonTools::ifFileExisting(fileNames[i]) ) {
      std::string fileName = fileNames[i];
      ERROR("File : " + fileName + " does not exist.");
      std::cerr << "File : " << fileNames[i] << " does not exist" << std::endl;
      return false;
    }
  }

  /// The run number option is neclegted if the input file is set as "scope"
  if (isRunNumberSet(variablesMap)) {
    if (getFileType(variablesMap) == "scope") {
      WARNING("Run number was specified but the input file type is a scope!\n The run number will be ignored!");
    }
  }

  /// Check if output path exists
  if (isOutputPath(variablesMap)) {
      auto dir = getOutputPath(variablesMap);
      if (!JPetCommonTools::isDirectory(dir)) {
        ERROR("Output directory : " + dir + " does not exist.");
        std::cerr << "Output directory: " << dir << " does not exist" << std::endl;
        return false;
      }
  }
  return true;
}

std::vector<JPetOptions> JPetCmdParser::generateOptions(const po::variables_map& optsMap) const
{
  std::map<std::string, std::string> options = JPetOptions::getDefaultOptions();
  auto fileType = getFileType(optsMap);
  if (isCorrectFileType(fileType)) {
    options.at("inputFileType") = fileType;
  }
  if (isOutputPath(optsMap)) {
    options.at("outputPath") = JPetCommonTools::appendSlashToPathIfAbsent(getOutputPath(optsMap));
  }
  if (isRunNumberSet(optsMap)) {
    options.at("runId") = std::to_string(getRunNumber(optsMap));
  }
  if (isProgressBarSet(optsMap)) {
    options.at("progressBar") = "true";
  }
  if (isLocalDBSet(optsMap)) {
    options["localDB"] = getLocalDBName(optsMap);
  }
  if (isLocalDBCreateSet(optsMap)) {
    options["localDBCreate"] = getLocalDBCreateName(optsMap);
  }
  auto firstEvent  = getLowerEventBound(optsMap);
  auto lastEvent  = getHigherEventBound(optsMap);
  if (firstEvent >= 0) options.at("firstEvent") = std::to_string(firstEvent);
  if (lastEvent >= 0) options.at("lastEvent") = std::to_string(lastEvent);

  auto files = getFileNames(optsMap);
  std::vector<JPetOptions>  optionContainer;
  /// In case of scope there is one special input file
  /// which is a json config file which must be parsed.
  /// Based on its content the set of input directories are generated.
  /// The input directories contain data files.
  /// The config input file name also should be stored in a special option field.
  if (fileType == "scope") {
    assert(files.size() == 1); /// there should be only file which is config.
    auto configFileName = files.front();
    options.at("scopeConfigFile") =  configFileName;
    JPetScopeConfigParser scopeConfigParser;
    /// The scope module must use a fake input file name which will be used to
    /// produce the correct output file names by the following modules.
    /// At the same time, the input directory with true input files must be
    /// also added. The container of pairs <directory, fileName> is generated
    /// based on the content of the configuration file.
    JPetScopeConfigParser::DirFileContainer dirsAndFiles = scopeConfigParser.getInputDirectoriesAndFakeInputFiles(configFileName);
    for (auto dirAndFile : dirsAndFiles) {
      options.at("scopeInputDirectory") = dirAndFile.first;
      options.at("inputFile") = dirAndFile.second;
      optionContainer.push_back(JPetOptions(options));
    }
  } else {
    /// for every single input file we create separate JPetOptions
    for (auto file : files) {
      options.at("inputFile") = file;
      optionContainer.push_back(JPetOptions(options));
    }
  }
  return optionContainer;
}

//#endif /* __CINT__ */
<commit_msg>Added zip phrase to function in JPetCmdParser<commit_after>/**
 *  @copyright Copyright 2016 The J-PET Framework Authors. All rights reserved.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may find a copy of the License in the LICENCE file.
 *
 *  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.
 *
 *  @file JPetCmdParser.cpp
 */

#include "JPetCmdParser.h"
#include <iostream>
#include "../JPetCommonTools/JPetCommonTools.h"
#include "../JPetLoggerInclude.h"
#include "../JPetScopeConfigParser/JPetScopeConfigParser.h"
#include <stdexcept>

JPetCmdParser::JPetCmdParser(): fOptionsDescriptions("Allowed options")
{
  fOptionsDescriptions.add_options()
  ("help,h", "Displays this help message.")
  ("type,t", po::value<std::string>()->required()->implicit_value(""), "Type of file: hld, zip, root or scope.")
  ("file,f", po::value< std::vector<std::string> >()->required()->multitoken(), "File(s) to open.")
  ("outputPath,o", po::value<std::string>(), "Location to which the outputFiles will be saved.")
  ("range,r", po::value< std::vector<int> >()->multitoken()->default_value({ -1, -1}, ""), "Range of events to process e.g. -r 1 1000 .")
  ("param,p", po::value<std::string>(), "xml file with TRB settings used by the unpacker program.")
  ("runId,i", po::value<int>(), "Run id.")
  ("progressBar,b", "Progress bar.")
  ("localDB,l", po::value<std::string>(), "The file to use as the parameter database.")
  ("localDBCreate,L", po::value<std::string>(), "File name to which the parameter database will be saved.");
}

JPetCmdParser::~JPetCmdParser()
{
  /**/
}

std::vector<JPetOptions> JPetCmdParser::parseAndGenerateOptions(int argc, const char** argv)
{
  po::variables_map variablesMap;
  if (argc == 1) {
    ERROR("No options provided.");
    std::cerr << getOptionsDescription() << "\n";
    throw std::invalid_argument("No options provided.");
  }

  po::store(po::parse_command_line(argc, argv, fOptionsDescriptions), variablesMap);

  /* print out help */
  if (variablesMap.count("help")) {
    std::cout << getOptionsDescription() << "\n";
    exit(0);
  }
  po::notify(variablesMap);
  if (!areCorrectOptions(variablesMap)) {
    throw std::invalid_argument("Wrong user options provided! Check the log!");
  }

  return generateOptions(variablesMap);
}

bool JPetCmdParser::areCorrectOptions(const po::variables_map& variablesMap) const
{
  /* Parse range of events */
  if (variablesMap.count("range")) {
    if (variablesMap["range"].as< std::vector<int> >().size() != 2) {
      ERROR("Wrong number of bounds in range.");
      std::cerr << "Wrong number of bounds in range: " << variablesMap["range"].as< std::vector<int> >().size() << std::endl;
      return false;
    }
    if (
      variablesMap["range"].as< std::vector<int> >()[0]
      > variablesMap["range"].as< std::vector<int> >()[1]) {
      ERROR("Wrong range of events.");
      std::cerr << "Wrong range of events." << std::endl;
      return false;
    }
  }

  if (!isCorrectFileType(getFileType(variablesMap))) {
    ERROR("Wrong type of file.");
    std::cerr << "Wrong type of file: " << getFileType(variablesMap) << std::endl;
    std::cerr << "Possible options: hld, zip, root or scope" << std::endl;
    return false;
  }

  if (isRunNumberSet(variablesMap)) {
    int l_runId = variablesMap["runId"].as<int>();

    if (l_runId <= 0) {
      ERROR("Run id must be a number larger than 0.");
      std::cerr << "Run id must be a number larger than 0." << l_runId << std::endl;
      return false;
    }
  }

  if (isProgressBarSet(variablesMap)) {
    int l_progressBar = variablesMap["progressBar"].as<int>();

    if (l_progressBar != 0 && l_progressBar != 1) {
      ERROR("Wrong parameter of progressbar.");
      std::cerr << "Wrong parameter of progressbar: " << l_progressBar << std::endl;
      return false;
    }
  }

  if (isLocalDBSet(variablesMap)) {
    std::string localDBName = getLocalDBName(variablesMap);
    if ( !JPetCommonTools::ifFileExisting(localDBName) ) {
      ERROR("File : " + localDBName + " does not exist.");
      std::cerr << "File : " << localDBName << " does not exist" << std::endl;
      return false;
    }
  }

  std::vector<std::string> fileNames(variablesMap["file"].as< std::vector<std::string> >());
  for (unsigned int i = 0; i < fileNames.size(); i++) {
    if ( ! JPetCommonTools::ifFileExisting(fileNames[i]) ) {
      std::string fileName = fileNames[i];
      ERROR("File : " + fileName + " does not exist.");
      std::cerr << "File : " << fileNames[i] << " does not exist" << std::endl;
      return false;
    }
  }

  /// The run number option is neclegted if the input file is set as "scope"
  if (isRunNumberSet(variablesMap)) {
    if (getFileType(variablesMap) == "scope") {
      WARNING("Run number was specified but the input file type is a scope!\n The run number will be ignored!");
    }
  }

  /// Check if output path exists
  if (isOutputPath(variablesMap)) {
      auto dir = getOutputPath(variablesMap);
      if (!JPetCommonTools::isDirectory(dir)) {
        ERROR("Output directory : " + dir + " does not exist.");
        std::cerr << "Output directory: " << dir << " does not exist" << std::endl;
        return false;
      }
  }
  return true;
}

std::vector<JPetOptions> JPetCmdParser::generateOptions(const po::variables_map& optsMap) const
{
  std::map<std::string, std::string> options = JPetOptions::getDefaultOptions();
  auto fileType = getFileType(optsMap);
  if (isCorrectFileType(fileType)) {
    options.at("inputFileType") = fileType;
  }
  if (isOutputPath(optsMap)) {
    options.at("outputPath") = JPetCommonTools::appendSlashToPathIfAbsent(getOutputPath(optsMap));
  }
  if (isRunNumberSet(optsMap)) {
    options.at("runId") = std::to_string(getRunNumber(optsMap));
  }
  if (isProgressBarSet(optsMap)) {
    options.at("progressBar") = "true";
  }
  if (isLocalDBSet(optsMap)) {
    options["localDB"] = getLocalDBName(optsMap);
  }
  if (isLocalDBCreateSet(optsMap)) {
    options["localDBCreate"] = getLocalDBCreateName(optsMap);
  }
  auto firstEvent  = getLowerEventBound(optsMap);
  auto lastEvent  = getHigherEventBound(optsMap);
  if (firstEvent >= 0) options.at("firstEvent") = std::to_string(firstEvent);
  if (lastEvent >= 0) options.at("lastEvent") = std::to_string(lastEvent);

  auto files = getFileNames(optsMap);
  std::vector<JPetOptions>  optionContainer;
  /// In case of scope there is one special input file
  /// which is a json config file which must be parsed.
  /// Based on its content the set of input directories are generated.
  /// The input directories contain data files.
  /// The config input file name also should be stored in a special option field.
  if (fileType == "scope") {
    assert(files.size() == 1); /// there should be only file which is config.
    auto configFileName = files.front();
    options.at("scopeConfigFile") =  configFileName;
    JPetScopeConfigParser scopeConfigParser;
    /// The scope module must use a fake input file name which will be used to
    /// produce the correct output file names by the following modules.
    /// At the same time, the input directory with true input files must be
    /// also added. The container of pairs <directory, fileName> is generated
    /// based on the content of the configuration file.
    JPetScopeConfigParser::DirFileContainer dirsAndFiles = scopeConfigParser.getInputDirectoriesAndFakeInputFiles(configFileName);
    for (auto dirAndFile : dirsAndFiles) {
      options.at("scopeInputDirectory") = dirAndFile.first;
      options.at("inputFile") = dirAndFile.second;
      optionContainer.push_back(JPetOptions(options));
    }
  } else {
    /// for every single input file we create separate JPetOptions
    for (auto file : files) {
      options.at("inputFile") = file;
      optionContainer.push_back(JPetOptions(options));
    }
  }
  return optionContainer;
}

//#endif /* __CINT__ */
<|endoftext|>


<commit_before>#include "ui_mainwindow.h"
#include "converter.h"
#include "utilities.h"
#include "window.h"
#include <QTime>

Converter::Converter(QObject *parent) : QObject(parent) {
}

void Converter::start() {
    utils.addToLog("Starting conversion.");
    utils.killProcesses();

    utils.currentDuration = 0;

    QStringList arguments;
    arguments << "-y" << "-hide_banner";
    arguments << "-i" << utils.getCurrentRawFilename();

    int bt = win.ui->bitrateValue->text().toInt() - 100;
    if (bt <= 0) bt = 1;
    QString bitrate = QString::number(bt);

    if (!bitrate.isEmpty()) {
        bitrate.append("K");
        arguments << "-b:v" << bitrate;
        utils.addToLog("Bitrate set to: " + bitrate);
    }

    if (!utils.configGetValue("ffmpeg_params").isEmpty()) {
        arguments << utils.configGetValue("ffmpeg_params").split(" ");
        utils.addToLog("Used custom parameters: " + utils.configGetValue("ffmpeg_params"));
    }

    if (!win.ui->cutFromEdit->text().trimmed().isEmpty() && !win.ui->cutToEdit->text().trimmed().isEmpty()) {
        arguments << "-ss" << win.ui->cutFromEdit->text().trimmed();
        arguments << "-to" << win.ui->cutToEdit->text().trimmed();
        utils.addToLog("Output video length: " + (QTime(0,0,0).addSecs(utils.getTrimmedVideoDuration())).toString("hh:mm:ss"));
        utils.currentDuration = utils.getTrimmedVideoDuration();
    }

    if (win.ui->menuRemoveAudio->isChecked())
        arguments << "-an";

    arguments << utils.getCurrentFilename();

    utils.conversionProcess = new QProcess;
    utils.conversionProcess->setProcessChannelMode(QProcess::MergedChannels);
    utils.conversionProcess->start(utils.ffmpegBinaryName(), arguments);

    connect(utils.conversionProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(read()));
    connect(utils.conversionProcess, SIGNAL(finished(int)), this, SLOT(complete(int)));
}

void Converter::read() {
    QString buffer = utils.conversionProcess->readAllStandardOutput();
    QString duration, progress;
    QTime durationTime, progressTime;
    QRegExp time("\\d\\d\\:\\d\\d\\:\\d\\d\\.\\d\\d");
    time.indexIn(buffer);
    if (buffer.contains("Duration: ") && utils.currentDuration == 0) {
        duration = time.capturedTexts()[0];
        durationTime = QTime::fromString(duration, "hh:mm:ss.z");
        utils.currentDuration = QTime(0,0).secsTo(durationTime);
    } else {
        if (buffer != "") {
            progress = time.capturedTexts()[0];
            if (progress != "") {
                progressTime = QTime::fromString(progress, "hh:mm:ss.z");
                int percent = double((QTime(0,0).msecsTo(progressTime)) / double(utils.currentDuration*1000))*100;
                win.ui->conversionProgressBar->setValue(percent);
            }
        }
    }
    if (win.ui->menuFfmpegOutput->isChecked())
        utils.addToLog(buffer);
    else
        utils.addToLog(buffer, false);
}

void Converter::complete(int code) {
    utils.conversionProcess->deleteLater();
    utils.conversionProcess = NULL;
    win.updateConversionButton();

    if (utils.killed) {
        utils.addToLog("Conversion canceled.");
        utils.killed = false;
        win.toggleConversionButton();
        return;
    }
    if (code != 0) {
        utils.addToLog("Error on conversion. Check logs.");
        win.toggleConversionButton();
        return;
    }

    // In case video is so short that ffmpeg do not display
    // conversion status
    win.ui->conversionProgressBar->setValue(100);

    win.toggleConversionButton();
    win.updateConversionButton();

    if (win.ui->menuRemoveRawVideo->isChecked())
        utils.removeRawVideo();

    utils.addToLog("Conversion complete.");
    utils.addToLog("Saved to: " + utils.getCurrentFilename());

    if (win.ui->menuShowFile->isChecked())
        utils.showFileInDirectory();
}
<commit_msg>bitrate calculating incldudes audio settings<commit_after>#include "ui_mainwindow.h"
#include "converter.h"
#include "utilities.h"
#include "window.h"
#include <QTime>

Converter::Converter(QObject *parent) : QObject(parent) {
}

void Converter::start() {
    utils.addToLog("Starting conversion.");
    utils.killProcesses();

    utils.currentDuration = 0;

    QStringList arguments;
    arguments << "-y" << "-hide_banner";
    arguments << "-i" << utils.getCurrentRawFilename();

    int bt = win.ui->bitrateValue->text().toInt();

    if (win.ui->menuRemoveAudio->isChecked())
        arguments << "-an";
    else
        bt -= 100;

    if (bt <= 0) bt = 1;
    QString bitrate = QString::number(bt);

    if (!bitrate.isEmpty()) {
        bitrate.append("K");
        arguments << "-b:v" << bitrate;
        utils.addToLog("Bitrate set to: " + bitrate);
    }

    if (!utils.configGetValue("ffmpeg_params").isEmpty()) {
        arguments << utils.configGetValue("ffmpeg_params").split(" ");
        utils.addToLog("Used custom parameters: " + utils.configGetValue("ffmpeg_params"));
    }

    if (!win.ui->cutFromEdit->text().trimmed().isEmpty() && !win.ui->cutToEdit->text().trimmed().isEmpty()) {
        arguments << "-ss" << win.ui->cutFromEdit->text().trimmed();
        arguments << "-to" << win.ui->cutToEdit->text().trimmed();
        utils.addToLog("Output video length: " + (QTime(0,0,0).addSecs(utils.getTrimmedVideoDuration())).toString("hh:mm:ss"));
        utils.currentDuration = utils.getTrimmedVideoDuration();
    }

    arguments << utils.getCurrentFilename();

    utils.conversionProcess = new QProcess;
    utils.conversionProcess->setProcessChannelMode(QProcess::MergedChannels);
    utils.conversionProcess->start(utils.ffmpegBinaryName(), arguments);

    connect(utils.conversionProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(read()));
    connect(utils.conversionProcess, SIGNAL(finished(int)), this, SLOT(complete(int)));
}

void Converter::read() {
    QString buffer = utils.conversionProcess->readAllStandardOutput();
    QString duration, progress;
    QTime durationTime, progressTime;
    QRegExp time("\\d\\d\\:\\d\\d\\:\\d\\d\\.\\d\\d");
    time.indexIn(buffer);
    if (buffer.contains("Duration: ") && utils.currentDuration == 0) {
        duration = time.capturedTexts()[0];
        durationTime = QTime::fromString(duration, "hh:mm:ss.z");
        utils.currentDuration = QTime(0,0).secsTo(durationTime);
    } else {
        if (buffer != "") {
            progress = time.capturedTexts()[0];
            if (progress != "") {
                progressTime = QTime::fromString(progress, "hh:mm:ss.z");
                int percent = double((QTime(0,0).msecsTo(progressTime)) / double(utils.currentDuration*1000))*100;
                win.ui->conversionProgressBar->setValue(percent);
            }
        }
    }
    if (win.ui->menuFfmpegOutput->isChecked())
        utils.addToLog(buffer);
    else
        utils.addToLog(buffer, false);
}

void Converter::complete(int code) {
    utils.conversionProcess->deleteLater();
    utils.conversionProcess = NULL;
    win.updateConversionButton();

    if (utils.killed) {
        utils.addToLog("Conversion canceled.");
        utils.killed = false;
        win.toggleConversionButton();
        return;
    }
    if (code != 0) {
        utils.addToLog("Error on conversion. Check logs.");
        win.toggleConversionButton();
        return;
    }

    // In case video is so short that ffmpeg do not display
    // conversion status
    win.ui->conversionProgressBar->setValue(100);

    win.toggleConversionButton();
    win.updateConversionButton();

    if (win.ui->menuRemoveRawVideo->isChecked())
        utils.removeRawVideo();

    utils.addToLog("Conversion complete.");
    utils.addToLog("Saved to: " + utils.getCurrentFilename());

    if (win.ui->menuShowFile->isChecked())
        utils.showFileInDirectory();
}
<|endoftext|>


<commit_before>/*
 * Copyright 2015 - 2021 gary@drinkingtea.net
 *
 * 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/.
 */

#pragma once

#include <ox/std/assert.hpp>
#include <ox/std/bit.hpp>
#include <ox/std/byteswap.hpp>
#include <ox/std/memops.hpp>

namespace ox::mc {

template<typename T>
static constexpr auto Bits = sizeof(T) << 3;

/**
 * Returns highest bit other than possible signed bit.
 * Bit numbering starts at 0.
 */
template<typename I>
[[nodiscard]] constexpr std::size_t highestBit(I val) noexcept {
	auto shiftStart = sizeof(I) * 8 - 1;
	// find most significant non-sign indicator bit
	std::size_t highestBit = 0;
	// start at one bit lower if signed
	if constexpr(ox::is_signed_v<I>) {
		--shiftStart;
	}
	for (int i = shiftStart; i > -1; --i) {
		const auto bitValue = (val >> i) & 1;
		if (bitValue) {
			highestBit = i;
			break;
		}
	}
	return highestBit;
}

static_assert(highestBit(int8_t(0b10000000)) == 0);
static_assert(highestBit(1) == 0);
static_assert(highestBit(2) == 1);
static_assert(highestBit(4) == 2);
static_assert(highestBit(8) == 3);
static_assert(highestBit(uint64_t(1) << 31) == 31);
static_assert(highestBit(uint64_t(1) << 63) == 63);

struct McInt {
	uint8_t data[9] = {0};
	// length of integer in bytes
	std::size_t length = 0;
};

template<typename I>
[[nodiscard]] constexpr McInt encodeInteger(I input) noexcept {
	McInt out;
	// move input to uint64_t to allow consistent bit manipulation, and to avoid
	// overflow concerns
	uint64_t val = 0;
	ox_memcpy(&val, &input, sizeof(I));
	if (val) {
		// bits needed to represent number factoring in space possibly
		// needed for signed bit
		const auto bits = highestBit(val) + 1 + (ox::is_signed_v<I> ? 1 : 0);
		// bytes needed to store value
		std::size_t bytes = bits / 8 + (bits % 8 != 0);
		const auto bitsAvailable = bytes * 8; // bits available to integer value
		const auto bitsNeeded = bits + bytes;
		// factor in bits needed for bytesIndicator (does not affect bytesIndicator)
		// bits for integer + bits neded to represent bytes > bits available
		if (bitsNeeded > bitsAvailable && bytes != 9) {
			++bytes;
		}
		const auto bytesIndicator = onMask<uint8_t>(bytes - 1);

		// ensure we are copying from little endian represenstation
		LittleEndian<I> leVal = val;
		if (bytes == 9) {
			out.data[0] = bytesIndicator;
			ox_memcpy(&out.data[1], &leVal, sizeof(I));
		} else {
			auto intermediate =
				static_cast<uint64_t>(leVal.raw()) << bytes |
				static_cast<uint64_t>(bytesIndicator);
			ox_memcpy(out.data, &intermediate, sizeof(intermediate));
		}
		out.length = bytes;
	}
	return out;
}

/**
 * Returns the number of bytes indicated by the bytes indicator of a variable
 * length integer.
 */
[[nodiscard]] static constexpr std::size_t countBytes(uint8_t b) noexcept {
	std::size_t i = 0;
	for (; (b >> i) & 1; i++);
	return i + 1;
}

static_assert(countBytes(0b00000000) == 1);
static_assert(countBytes(0b00000001) == 2);
static_assert(countBytes(0b00000011) == 3);
static_assert(countBytes(0b00000111) == 4);
static_assert(countBytes(0b00001111) == 5);
static_assert(countBytes(0b00011111) == 6);
static_assert(countBytes(0b00111111) == 7);
static_assert(countBytes(0b01111111) == 8);
static_assert(countBytes(0b11111111) == 9);

template<typename I>
Result<I> decodeInteger(uint8_t buff[9], std::size_t buffLen, std::size_t *bytesRead) noexcept {
	const auto bytes = countBytes(buff[0]);
	if (bytes == 9) {
		*bytesRead = bytes;
		I out = 0;
		memcpy(&out, &buff[1], sizeof(I));
		return {LittleEndian<I>(out), OxError(0)};
	} else if (buffLen >= bytes) {
		*bytesRead = bytes;
		uint64_t decoded = 0;
		memcpy(&decoded, &buff[0], bytes);
		decoded >>= bytes;
		auto out = static_cast<I>(decoded);
		// move sign bit
		if constexpr(ox::is_signed_v<I>) {
			const auto valBits = bytes << 3;
			// get sign
			uint64_t sign = decoded >> (valBits - 1);
			// remove sign
			decoded &= uint64_t(~0) ^ (uint64_t(1) << valBits);
			// set sign
			decoded |= sign << (Bits<I> - 1);
			memcpy(&out, &decoded, sizeof(out));
		}
		return {out, OxError(0)};
	}
	return {0, OxError(1)};
}

template<typename I>
Result<I> decodeInteger(McInt m) noexcept {
	std::size_t bytesRead;
	return decodeInteger<I>(m.data, 9, &bytesRead);
}

}
<commit_msg>[ox/mc] Removes some unnecessary type conversions<commit_after>/*
 * Copyright 2015 - 2021 gary@drinkingtea.net
 *
 * 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/.
 */

#pragma once

#include <ox/std/assert.hpp>
#include <ox/std/bit.hpp>
#include <ox/std/byteswap.hpp>
#include <ox/std/memops.hpp>

namespace ox::mc {

template<typename T>
static constexpr auto Bits = sizeof(T) << 3;

/**
 * Returns highest bit other than possible signed bit.
 * Bit numbering starts at 0.
 */
template<typename I>
[[nodiscard]] constexpr std::size_t highestBit(I val) noexcept {
	int shiftStart = sizeof(I) * 8 - 1;
	// find most significant non-sign indicator bit
	std::size_t highestBit = 0;
	// start at one bit lower if signed
	if constexpr(ox::is_signed_v<I>) {
		--shiftStart;
	}
	for (auto i = shiftStart; i > -1; --i) {
		const auto bitValue = (val >> i) & 1;
		if (bitValue) {
			highestBit = i;
			break;
		}
	}
	return highestBit;
}

static_assert(highestBit(int8_t(0b10000000)) == 0);
static_assert(highestBit(1) == 0);
static_assert(highestBit(2) == 1);
static_assert(highestBit(4) == 2);
static_assert(highestBit(8) == 3);
static_assert(highestBit(uint64_t(1) << 31) == 31);
static_assert(highestBit(uint64_t(1) << 63) == 63);

struct McInt {
	uint8_t data[9] = {0};
	// length of integer in bytes
	std::size_t length = 0;
};

template<typename I>
[[nodiscard]] constexpr McInt encodeInteger(I input) noexcept {
	McInt out;
	// move input to uint64_t to allow consistent bit manipulation, and to avoid
	// overflow concerns
	uint64_t val = 0;
	ox_memcpy(&val, &input, sizeof(I));
	if (val) {
		// bits needed to represent number factoring in space possibly
		// needed for signed bit
		const auto bits = highestBit(val) + 1 + (ox::is_signed_v<I> ? 1 : 0);
		// bytes needed to store value
		std::size_t bytes = bits / 8 + (bits % 8 != 0);
		const auto bitsAvailable = bytes * 8; // bits available to integer value
		const auto bitsNeeded = bits + bytes;
		// factor in bits needed for bytesIndicator (does not affect bytesIndicator)
		// bits for integer + bits neded to represent bytes > bits available
		if (bitsNeeded > bitsAvailable && bytes != 9) {
			++bytes;
		}
		const auto bytesIndicator = onMask<uint8_t>(bytes - 1);

		// ensure we are copying from little endian represenstation
		LittleEndian<I> leVal = val;
		if (bytes == 9) {
			out.data[0] = bytesIndicator;
			ox_memcpy(&out.data[1], &leVal, sizeof(I));
		} else {
			auto intermediate =
				static_cast<uint64_t>(leVal.raw()) << bytes |
				static_cast<uint64_t>(bytesIndicator);
			ox_memcpy(out.data, &intermediate, sizeof(intermediate));
		}
		out.length = bytes;
	}
	return out;
}

/**
 * Returns the number of bytes indicated by the bytes indicator of a variable
 * length integer.
 */
[[nodiscard]] static constexpr std::size_t countBytes(uint8_t b) noexcept {
	std::size_t i = 0;
	for (; (b >> i) & 1; i++);
	return i + 1;
}

static_assert(countBytes(0b00000000) == 1);
static_assert(countBytes(0b00000001) == 2);
static_assert(countBytes(0b00000011) == 3);
static_assert(countBytes(0b00000111) == 4);
static_assert(countBytes(0b00001111) == 5);
static_assert(countBytes(0b00011111) == 6);
static_assert(countBytes(0b00111111) == 7);
static_assert(countBytes(0b01111111) == 8);
static_assert(countBytes(0b11111111) == 9);

template<typename I>
Result<I> decodeInteger(uint8_t buff[9], std::size_t buffLen, std::size_t *bytesRead) noexcept {
	const auto bytes = countBytes(buff[0]);
	if (bytes == 9) {
		*bytesRead = bytes;
		I out = 0;
		memcpy(&out, &buff[1], sizeof(I));
		return {LittleEndian<I>(out), OxError(0)};
	} else if (buffLen >= bytes) {
		*bytesRead = bytes;
		uint64_t decoded = 0;
		memcpy(&decoded, &buff[0], bytes);
		decoded >>= bytes;
		auto out = static_cast<I>(decoded);
		// move sign bit
		if constexpr(ox::is_signed_v<I>) {
			const auto valBits = bytes << 3;
			// get sign
			uint64_t sign = decoded >> (valBits - 1);
			// remove sign
			decoded &= uint64_t(~0) ^ (uint64_t(1) << valBits);
			// set sign
			decoded |= sign << (Bits<I> - 1);
			memcpy(&out, &decoded, sizeof(out));
		}
		return {out, OxError(0)};
	}
	return {0, OxError(1)};
}

template<typename I>
Result<I> decodeInteger(McInt m) noexcept {
	std::size_t bytesRead;
	return decodeInteger<I>(m.data, 9, &bytesRead);
}

}
<|endoftext|>


<commit_before>/*
    main.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2001,2002,2004 Klar�vdalens Datakonsult AB

    Kleopatra is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    Kleopatra is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include <config-kleopatra.h>

#include "aboutdata.h"
#ifndef KLEO_ONLY_UISERVER
# include "certmanager.h"
#endif

#include "libkleo/kleo/cryptobackendfactory.h"

#ifdef HAVE_USABLE_ASSUAN
# include <uiserver/uiserver.h>
# include <uiserver/assuancommand.h>
# include <uiserver/echocommand.h>
# include <uiserver/decryptcommand.h>
# include <uiserver/verifycommand.h>
# include <uiserver/encryptcommand.h>
# include <uiserver/signcommand.h>
#endif

#include <kapplication.h>
#include <kcmdlineargs.h>
#include <kmessagebox.h>
#include <klocale.h>
#include <kglobal.h>
#include <kiconloader.h>

#include <QTextDocument> // for Qt::escape
#include <QSystemTrayIcon>
#include <QMenu>
#include <QAction>

#include <boost/shared_ptr.hpp>

namespace {
    template <typename T>
    boost::shared_ptr<T> make_shared_ptr( T * t ) {
        return t ? boost::shared_ptr<T>( t ) : boost::shared_ptr<T>() ;
    }
}

int main( int argc, char** argv )
{
  AboutData aboutData;

  KCmdLineArgs::init(argc, argv, &aboutData);

  KCmdLineOptions options;
#ifndef KLEO_ONLY_UISERVER
  options.add("external", ki18n("Search for external certificates initially"));
  options.add("query ", ki18n("Initial query string"));
#endif
  options.add("import-certificate ", ki18n("Name of certificate file to import"));
#ifdef HAVE_USABLE_ASSUAN
  options.add("uiserver-socket <argument>", ki18n("Location of the socket the ui server is listening on" ) );
#endif
  KCmdLineArgs::addCmdLineOptions( options );

  KApplication app;

  KCmdLineArgs *args = KCmdLineArgs::parsedArgs();

  KGlobal::locale()->insertCatalog( "libkleopatra" );
  KIconLoader::global()->addAppDir( "libkleopatra" );

  if( !Kleo::CryptoBackendFactory::instance()->smime() ) {
    KMessageBox::error(0,
			i18n( "<qt>The crypto plugin could not be initialized.
"
			      "Certificate Manager will terminate now.</qt>") );
    return -2;
  }

#ifndef KLEO_ONLY_UISERVER
  CertManager* manager = new CertManager( args->isSet("external"),
					  args->getOption("query"),
					  args->getOption("import-certificate") );
  manager->show();
#endif

  QSystemTrayIcon sysTray( KIcon( "gpg" ) );
  QMenu sysTrayMenu;
  QAction sysTrayQuitAction( i18n("&Quit"), &sysTray );
  app.connect( &sysTrayQuitAction, SIGNAL(triggered()), SLOT(quit()) );
  sysTrayMenu.addAction( &sysTrayQuitAction );
  sysTray.setContextMenu( &sysTrayMenu );
  sysTray.show();

  int rc;
#ifdef HAVE_USABLE_ASSUAN
  try {
      Kleo::UiServer server( args->getOption("uiserver-socket") );

      sysTray.setToolTip( i18n( "Kleopatra UI Server listening on %1", server.socketName() ) );

#define REGISTER( Command ) server.registerCommandFactory( boost::shared_ptr<Kleo::AssuanCommandFactory>( new Kleo::GenericAssuanCommandFactory<Kleo::Command> ) )
      REGISTER( DecryptCommand );
      REGISTER( EchoCommand );
      REGISTER( VerifyCommand );
      REGISTER( EncryptCommand );
      REGISTER( SignCommand );
#undef REGISTER

      server.start();
#endif

      args->clear();
      rc = app.exec();

#ifdef HAVE_USABLE_ASSUAN
      server.stop();
      server.waitForStopped();
  } catch ( const std::exception & e ) {
      QMessageBox::information( 0, i18n("GPG UI Server Error"),
                                i18n("<qt>The Kleopatra GPG UI Server Module couldn't be initialized.
"
                                     "The error given was: %1
"
                                     "You can use Kleopatra as a certificate manager, but cryptographic plugins that "
                                     "rely on a GPG UI Server being present might not work correctly, or at all.</qt>",
                                     Qt::escape( QString::fromUtf8( e.what() ) ) ));
      rc = app.exec();
  }
#endif

  return rc;
}
<commit_msg>Don't terminate the uiserver when closing the last dialog.<commit_after>/*
    main.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2001,2002,2004 Klar�vdalens Datakonsult AB

    Kleopatra is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    Kleopatra is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include <config-kleopatra.h>

#include "aboutdata.h"
#ifndef KLEO_ONLY_UISERVER
# include "certmanager.h"
#endif

#include "libkleo/kleo/cryptobackendfactory.h"

#ifdef HAVE_USABLE_ASSUAN
# include <uiserver/uiserver.h>
# include <uiserver/assuancommand.h>
# include <uiserver/echocommand.h>
# include <uiserver/decryptcommand.h>
# include <uiserver/verifycommand.h>
# include <uiserver/encryptcommand.h>
# include <uiserver/signcommand.h>
#endif

#include <kapplication.h>
#include <kcmdlineargs.h>
#include <kmessagebox.h>
#include <klocale.h>
#include <kglobal.h>
#include <kiconloader.h>

#include <QTextDocument> // for Qt::escape
#include <QSystemTrayIcon>
#include <QMenu>
#include <QAction>

#include <boost/shared_ptr.hpp>

namespace {
    template <typename T>
    boost::shared_ptr<T> make_shared_ptr( T * t ) {
        return t ? boost::shared_ptr<T>( t ) : boost::shared_ptr<T>() ;
    }
}

int main( int argc, char** argv )
{
  AboutData aboutData;

  KCmdLineArgs::init(argc, argv, &aboutData);

  KCmdLineOptions options;
#ifndef KLEO_ONLY_UISERVER
  options.add("external", ki18n("Search for external certificates initially"));
  options.add("query ", ki18n("Initial query string"));
#endif
  options.add("import-certificate ", ki18n("Name of certificate file to import"));
#ifdef HAVE_USABLE_ASSUAN
  options.add("uiserver-socket <argument>", ki18n("Location of the socket the ui server is listening on" ) );
#endif
  KCmdLineArgs::addCmdLineOptions( options );

  KApplication app;

  KCmdLineArgs *args = KCmdLineArgs::parsedArgs();

  KGlobal::locale()->insertCatalog( "libkleopatra" );
  KIconLoader::global()->addAppDir( "libkleopatra" );

  if( !Kleo::CryptoBackendFactory::instance()->smime() ) {
    KMessageBox::error(0,
			i18n( "<qt>The crypto plugin could not be initialized.
"
			      "Certificate Manager will terminate now.</qt>") );
    return -2;
  }

#ifndef KLEO_ONLY_UISERVER
  CertManager* manager = new CertManager( args->isSet("external"),
					  args->getOption("query"),
					  args->getOption("import-certificate") );
  manager->show();
#endif

  QSystemTrayIcon sysTray( KIcon( "gpg" ) );
  QMenu sysTrayMenu;
  QAction sysTrayQuitAction( i18n("&Quit"), &sysTray );
  app.connect( &sysTrayQuitAction, SIGNAL(triggered()), SLOT(quit()) );
  sysTrayMenu.addAction( &sysTrayQuitAction );
  sysTray.setContextMenu( &sysTrayMenu );
  sysTray.show();

  int rc;
#ifdef HAVE_USABLE_ASSUAN
  try {
      Kleo::UiServer server( args->getOption("uiserver-socket") );

      sysTray.setToolTip( i18n( "Kleopatra UI Server listening on %1", server.socketName() ) );

#define REGISTER( Command ) server.registerCommandFactory( boost::shared_ptr<Kleo::AssuanCommandFactory>( new Kleo::GenericAssuanCommandFactory<Kleo::Command> ) )
      REGISTER( DecryptCommand );
      REGISTER( EchoCommand );
      REGISTER( VerifyCommand );
      REGISTER( EncryptCommand );
      REGISTER( SignCommand );
#undef REGISTER

      server.start();
#endif

      args->clear();
      QApplication::setQuitOnLastWindowClosed( false );
      rc = app.exec();

#ifdef HAVE_USABLE_ASSUAN
      server.stop();
      server.waitForStopped();
  } catch ( const std::exception & e ) {
      QMessageBox::information( 0, i18n("GPG UI Server Error"),
                                i18n("<qt>The Kleopatra GPG UI Server Module couldn't be initialized.
"
                                     "The error given was: %1
"
                                     "You can use Kleopatra as a certificate manager, but cryptographic plugins that "
                                     "rely on a GPG UI Server being present might not work correctly, or at all.</qt>",
                                     Qt::escape( QString::fromUtf8( e.what() ) ) ));
      rc = app.exec();
  }
#endif

  return rc;
}
<|endoftext|>