<commit_before>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrDrawState.h"

#include "GrBlend.h"
#include "GrOptDrawState.h"
#include "GrPaint.h"
#include "GrProcOptInfo.h"
#include "GrXferProcessor.h"
#include "effects/GrPorterDuffXferProcessor.h"

bool GrDrawState::isEqual(const GrDrawState& that) const {
    if (this->getRenderTarget() != that.getRenderTarget() ||
        this->fColorStages.count() != that.fColorStages.count() ||
        this->fCoverageStages.count() != that.fCoverageStages.count() ||
        !this->fViewMatrix.cheapEqualTo(that.fViewMatrix) ||
        this->fFlagBits != that.fFlagBits ||
        this->fStencilSettings != that.fStencilSettings ||
        this->fDrawFace != that.fDrawFace) {
        return false;
    }

    bool explicitLocalCoords = this->hasLocalCoordAttribute();
    if (this->hasGeometryProcessor()) {
        if (!that.hasGeometryProcessor()) {
            return false;
        } else if (!this->getGeometryProcessor()->isEqual(*that.getGeometryProcessor())) {
            return false;
        }
    } else if (that.hasGeometryProcessor()) {
        return false;
    }

    if (!this->getXPFactory()->isEqual(*that.getXPFactory())) {
        return false;
    }

    for (int i = 0; i < this->numColorStages(); i++) {
        if (!GrFragmentStage::AreCompatible(this->getColorStage(i), that.getColorStage(i),
                                             explicitLocalCoords)) {
            return false;
        }
    }
    for (int i = 0; i < this->numCoverageStages(); i++) {
        if (!GrFragmentStage::AreCompatible(this->getCoverageStage(i), that.getCoverageStage(i),
                                             explicitLocalCoords)) {
            return false;
        }
    }

    return true;
}

//////////////////////////////////////////////////////////////////////////////s

GrDrawState::GrDrawState(const GrDrawState& state, const SkMatrix& preConcatMatrix) {
    SkDEBUGCODE(fBlockEffectRemovalCnt = 0;)
    *this = state;
    if (!preConcatMatrix.isIdentity()) {
        for (int i = 0; i < this->numColorStages(); ++i) {
            fColorStages[i].localCoordChange(preConcatMatrix);
        }
        for (int i = 0; i < this->numCoverageStages(); ++i) {
            fCoverageStages[i].localCoordChange(preConcatMatrix);
        }
    }
}

GrDrawState& GrDrawState::operator=(const GrDrawState& that) {
    fRenderTarget.reset(SkSafeRef(that.fRenderTarget.get()));
    fViewMatrix = that.fViewMatrix;
    fFlagBits = that.fFlagBits;
    fStencilSettings = that.fStencilSettings;
    fDrawFace = that.fDrawFace;
    fGeometryProcessor.reset(SkSafeRef(that.fGeometryProcessor.get()));
    fXPFactory.reset(SkRef(that.getXPFactory()));
    fColorStages = that.fColorStages;
    fCoverageStages = that.fCoverageStages;

    fHints = that.fHints;

    fColorProcInfoValid = that.fColorProcInfoValid;
    fCoverageProcInfoValid = that.fCoverageProcInfoValid;
    if (fColorProcInfoValid) {
        fColorProcInfo = that.fColorProcInfo;
    }
    if (fCoverageProcInfoValid) {
        fCoverageProcInfo = that.fCoverageProcInfo;
    }
    return *this;
}

void GrDrawState::onReset(const SkMatrix* initialViewMatrix) {
    SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
    fRenderTarget.reset(NULL);

    fGeometryProcessor.reset(NULL);
    fXPFactory.reset(GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode));
    fColorStages.reset();
    fCoverageStages.reset();

    if (NULL == initialViewMatrix) {
        fViewMatrix.reset();
    } else {
        fViewMatrix = *initialViewMatrix;
    }
    fFlagBits = 0x0;
    fStencilSettings.setDisabled();
    fDrawFace = kBoth_DrawFace;

    fHints = 0;

    fColorProcInfoValid = false;
    fCoverageProcInfoValid = false;
}

bool GrDrawState::setIdentityViewMatrix()  {
    if (this->numFragmentStages()) {
        SkMatrix invVM;
        if (!fViewMatrix.invert(&invVM)) {
            // sad trombone sound
            return false;
        }
        for (int s = 0; s < this->numColorStages(); ++s) {
            fColorStages[s].localCoordChange(invVM);
        }
        for (int s = 0; s < this->numCoverageStages(); ++s) {
            fCoverageStages[s].localCoordChange(invVM);
        }
    }
    fViewMatrix.reset();
    return true;
}

void GrDrawState::setFromPaint(const GrPaint& paint, const SkMatrix& vm, GrRenderTarget* rt) {
    SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());

    fGeometryProcessor.reset(NULL);
    fColorStages.reset();
    fCoverageStages.reset();

    for (int i = 0; i < paint.numColorStages(); ++i) {
        fColorStages.push_back(paint.getColorStage(i));
    }

    for (int i = 0; i < paint.numCoverageStages(); ++i) {
        fCoverageStages.push_back(paint.getCoverageStage(i));
    }

    fXPFactory.reset(SkRef(paint.getXPFactory()));

    this->setRenderTarget(rt);

    fViewMatrix = vm;

    // These have no equivalent in GrPaint, set them to defaults
    fDrawFace = kBoth_DrawFace;
    fStencilSettings.setDisabled();
    fFlagBits = 0;
    fHints = 0;

    // Enable the clip bit
    this->enableState(GrDrawState::kClip_StateBit);

    this->setState(GrDrawState::kDither_StateBit, paint.isDither());
    this->setState(GrDrawState::kHWAntialias_StateBit, paint.isAntiAlias());

    fColorProcInfoValid = false;
    fCoverageProcInfoValid = false;

    fColorCache = GrColor_ILLEGAL;
    fCoverageCache = GrColor_ILLEGAL;
}

////////////////////////////////////////////////////////////////////////////////

bool GrDrawState::canUseFracCoveragePrimProc(GrColor color, const GrDrawTargetCaps& caps) const {
    if (caps.dualSourceBlendingSupport()) {
        return true;
    }

    this->calcColorInvariantOutput(color);

    // The coverage isn't actually white, its unknown, but this will produce the same effect
    // TODO we want to cache the result of this call, but we can probably clean up the interface
    // so we don't have to pass in a seemingly known coverage
    this->calcCoverageInvariantOutput(GrColor_WHITE);
    return fXPFactory->canApplyCoverage(fColorProcInfo, fCoverageProcInfo,
                                        this->isCoverageDrawing(), this->isColorWriteDisabled());
}

bool GrDrawState::hasSolidCoverage(GrColor coverage) const {
    // If we're drawing coverage directly then coverage is effectively treated as color.
    if (this->isCoverageDrawing()) {
        return true;
    }

    if (this->numCoverageStages() > 0) {
        return false;
    }

    this->calcCoverageInvariantOutput(coverage);
    return fCoverageProcInfo.isSolidWhite();
}

//////////////////////////////////////////////////////////////////////////////s

bool GrDrawState::willEffectReadDstColor(GrColor color, GrColor coverage) const {
    this->calcColorInvariantOutput(color);
    this->calcCoverageInvariantOutput(coverage);
    // TODO: Remove need to create the XP here.
    //       Also once all custom blends are turned into XPs we can remove the need
    //       to check other stages since only xp's will be able to read dst
    SkAutoTUnref<GrXferProcessor> xferProcessor(fXPFactory->createXferProcessor(fColorProcInfo,
                                                                                fCoverageProcInfo));
    if (xferProcessor && xferProcessor->willReadDstColor()) {
        return true;
    }

    if (!this->isColorWriteDisabled()) {
        if (fColorProcInfo.readsDst()) {
            return true;
        }
    }
    return fCoverageProcInfo.readsDst();
}

void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) {
    if (fDrawState) {
        // See the big comment on the class definition about GPs.
        if (SK_InvalidUniqueID == fOriginalGPID) {
            fDrawState->fGeometryProcessor.reset(NULL);
        } else {
            SkASSERT(fDrawState->getGeometryProcessor()->getUniqueID() ==
                     fOriginalGPID);
            fOriginalGPID = SK_InvalidUniqueID;
        }

        int m = fDrawState->numColorStages() - fColorEffectCnt;
        SkASSERT(m >= 0);
        fDrawState->fColorStages.pop_back_n(m);

        int n = fDrawState->numCoverageStages() - fCoverageEffectCnt;
        SkASSERT(n >= 0);
        fDrawState->fCoverageStages.pop_back_n(n);
        if (m + n > 0) {
            fDrawState->fColorProcInfoValid = false;
            fDrawState->fCoverageProcInfoValid = false;
        }
        SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
    }
    fDrawState = ds;
    if (NULL != ds) {
        SkASSERT(SK_InvalidUniqueID == fOriginalGPID);
        if (NULL != ds->getGeometryProcessor()) {
            fOriginalGPID = ds->getGeometryProcessor()->getUniqueID();
        }
        fColorEffectCnt = ds->numColorStages();
        fCoverageEffectCnt = ds->numCoverageStages();
        SkDEBUGCODE(++ds->fBlockEffectRemovalCnt;)
    }
}

////////////////////////////////////////////////////////////////////////////////

// Some blend modes allow folding a fractional coverage value into the color's alpha channel, while
// others will blend incorrectly.
bool GrDrawState::canTweakAlphaForCoverage() const {
    return fXPFactory->canTweakAlphaForCoverage(this->isCoverageDrawing());
}

////////////////////////////////////////////////////////////////////////////////

void GrDrawState::AutoViewMatrixRestore::restore() {
    if (fDrawState) {
        SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
        fDrawState->fViewMatrix = fViewMatrix;
        SkASSERT(fDrawState->numColorStages() >= fNumColorStages);
        int numCoverageStages = fSavedCoordChanges.count() - fNumColorStages;
        SkASSERT(fDrawState->numCoverageStages() >= numCoverageStages);

        int i = 0;
        for (int s = 0; s < fNumColorStages; ++s, ++i) {
            fDrawState->fColorStages[s].restoreCoordChange(fSavedCoordChanges[i]);
        }
        for (int s = 0; s < numCoverageStages; ++s, ++i) {
            fDrawState->fCoverageStages[s].restoreCoordChange(fSavedCoordChanges[i]);
        }
        fDrawState = NULL;
    }
}

void GrDrawState::AutoViewMatrixRestore::set(GrDrawState* drawState,
                                             const SkMatrix& preconcatMatrix) {
    this->restore();

    SkASSERT(NULL == fDrawState);
    if (NULL == drawState || preconcatMatrix.isIdentity()) {
        return;
    }
    fDrawState = drawState;

    fViewMatrix = drawState->getViewMatrix();
    drawState->fViewMatrix.preConcat(preconcatMatrix);

    this->doEffectCoordChanges(preconcatMatrix);
    SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
}

bool GrDrawState::AutoViewMatrixRestore::setIdentity(GrDrawState* drawState) {
    this->restore();

    if (NULL == drawState) {
        return false;
    }

    if (drawState->getViewMatrix().isIdentity()) {
        return true;
    }

    fViewMatrix = drawState->getViewMatrix();
    if (0 == drawState->numFragmentStages()) {
        drawState->fViewMatrix.reset();
        fDrawState = drawState;
        fNumColorStages = 0;
        fSavedCoordChanges.reset(0);
        SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
        return true;
    } else {
        SkMatrix inv;
        if (!fViewMatrix.invert(&inv)) {
            return false;
        }
        drawState->fViewMatrix.reset();
        fDrawState = drawState;
        this->doEffectCoordChanges(inv);
        SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
        return true;
    }
}

void GrDrawState::AutoViewMatrixRestore::doEffectCoordChanges(const SkMatrix& coordChangeMatrix) {
    fSavedCoordChanges.reset(fDrawState->numFragmentStages());
    int i = 0;

    fNumColorStages = fDrawState->numColorStages();
    for (int s = 0; s < fNumColorStages; ++s, ++i) {
        fDrawState->getColorStage(s).saveCoordChange(&fSavedCoordChanges[i]);
        fDrawState->fColorStages[s].localCoordChange(coordChangeMatrix);
    }

    int numCoverageStages = fDrawState->numCoverageStages();
    for (int s = 0; s < numCoverageStages; ++s, ++i) {
        fDrawState->getCoverageStage(s).saveCoordChange(&fSavedCoordChanges[i]);
        fDrawState->fCoverageStages[s].localCoordChange(coordChangeMatrix);
    }
}

////////////////////////////////////////////////////////////////////////////////

GrDrawState::~GrDrawState() {
    SkASSERT(0 == fBlockEffectRemovalCnt);
}

////////////////////////////////////////////////////////////////////////////////

bool GrDrawState::srcAlphaWillBeOne(GrColor color, GrColor coverage) const {
    this->calcColorInvariantOutput(color);
    if (this->isCoverageDrawing()) {
        this->calcCoverageInvariantOutput(coverage);
        return (fColorProcInfo.isOpaque() && fCoverageProcInfo.isOpaque());
    }
    return fColorProcInfo.isOpaque();
}

bool GrDrawState::willBlendWithDst(GrColor color, GrColor coverage) const {
    this->calcColorInvariantOutput(color);
    this->calcCoverageInvariantOutput(coverage);
    return fXPFactory->willBlendWithDst(fColorProcInfo, fCoverageProcInfo,
                                        this->isCoverageDrawing(), this->isColorWriteDisabled());
}

void GrDrawState::calcColorInvariantOutput(GrColor color) const {
    if (!fColorProcInfoValid || color != fColorCache) {
        GrColorComponentFlags flags;
        if (this->hasColorVertexAttribute()) {
            if (fHints & kVertexColorsAreOpaque_Hint) {
                flags = kA_GrColorComponentFlag;
                color = 0xFF << GrColor_SHIFT_A;
            } else {
                flags = static_cast<GrColorComponentFlags>(0);
                color = 0;
            }
        } else {
            flags = kRGBA_GrColorComponentFlags;
        }
        fColorProcInfo.calcWithInitialValues(fColorStages.begin(), this->numColorStages(),
                                             color, flags, false);
        fColorProcInfoValid = true;
        fColorCache = color;
    }
}

void GrDrawState::calcCoverageInvariantOutput(GrColor coverage) const {
    if (!fCoverageProcInfoValid || coverage != fCoverageCache) {
        GrColorComponentFlags flags;
        // Check if per-vertex or constant color may have partial alpha
        if (this->hasCoverageVertexAttribute()) {
            flags = static_cast<GrColorComponentFlags>(0);
            coverage = 0;
        } else {
            flags = kRGBA_GrColorComponentFlags;
        }
        fCoverageProcInfo.calcWithInitialValues(fCoverageStages.begin(), this->numCoverageStages(),
                                                coverage, flags, true, fGeometryProcessor.get());
        fCoverageProcInfoValid = true;
        fCoverageCache = coverage;
    }
}
<commit_msg>fix for valgrind uninit variables<commit_after>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrDrawState.h"

#include "GrBlend.h"
#include "GrOptDrawState.h"
#include "GrPaint.h"
#include "GrProcOptInfo.h"
#include "GrXferProcessor.h"
#include "effects/GrPorterDuffXferProcessor.h"

bool GrDrawState::isEqual(const GrDrawState& that) const {
    if (this->getRenderTarget() != that.getRenderTarget() ||
        this->fColorStages.count() != that.fColorStages.count() ||
        this->fCoverageStages.count() != that.fCoverageStages.count() ||
        !this->fViewMatrix.cheapEqualTo(that.fViewMatrix) ||
        this->fFlagBits != that.fFlagBits ||
        this->fStencilSettings != that.fStencilSettings ||
        this->fDrawFace != that.fDrawFace) {
        return false;
    }

    bool explicitLocalCoords = this->hasLocalCoordAttribute();
    if (this->hasGeometryProcessor()) {
        if (!that.hasGeometryProcessor()) {
            return false;
        } else if (!this->getGeometryProcessor()->isEqual(*that.getGeometryProcessor())) {
            return false;
        }
    } else if (that.hasGeometryProcessor()) {
        return false;
    }

    if (!this->getXPFactory()->isEqual(*that.getXPFactory())) {
        return false;
    }

    for (int i = 0; i < this->numColorStages(); i++) {
        if (!GrFragmentStage::AreCompatible(this->getColorStage(i), that.getColorStage(i),
                                             explicitLocalCoords)) {
            return false;
        }
    }
    for (int i = 0; i < this->numCoverageStages(); i++) {
        if (!GrFragmentStage::AreCompatible(this->getCoverageStage(i), that.getCoverageStage(i),
                                             explicitLocalCoords)) {
            return false;
        }
    }

    return true;
}

//////////////////////////////////////////////////////////////////////////////s

GrDrawState::GrDrawState(const GrDrawState& state, const SkMatrix& preConcatMatrix) {
    SkDEBUGCODE(fBlockEffectRemovalCnt = 0;)
    *this = state;
    if (!preConcatMatrix.isIdentity()) {
        for (int i = 0; i < this->numColorStages(); ++i) {
            fColorStages[i].localCoordChange(preConcatMatrix);
        }
        for (int i = 0; i < this->numCoverageStages(); ++i) {
            fCoverageStages[i].localCoordChange(preConcatMatrix);
        }
    }
}

GrDrawState& GrDrawState::operator=(const GrDrawState& that) {
    fRenderTarget.reset(SkSafeRef(that.fRenderTarget.get()));
    fViewMatrix = that.fViewMatrix;
    fFlagBits = that.fFlagBits;
    fStencilSettings = that.fStencilSettings;
    fDrawFace = that.fDrawFace;
    fGeometryProcessor.reset(SkSafeRef(that.fGeometryProcessor.get()));
    fXPFactory.reset(SkRef(that.getXPFactory()));
    fColorStages = that.fColorStages;
    fCoverageStages = that.fCoverageStages;

    fHints = that.fHints;

    fColorProcInfoValid = that.fColorProcInfoValid;
    fCoverageProcInfoValid = that.fCoverageProcInfoValid;
    if (fColorProcInfoValid) {
        fColorProcInfo = that.fColorProcInfo;
    }
    if (fCoverageProcInfoValid) {
        fCoverageProcInfo = that.fCoverageProcInfo;
    }
    return *this;
}

void GrDrawState::onReset(const SkMatrix* initialViewMatrix) {
    SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
    fRenderTarget.reset(NULL);

    fGeometryProcessor.reset(NULL);
    fXPFactory.reset(GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode));
    fColorStages.reset();
    fCoverageStages.reset();

    if (NULL == initialViewMatrix) {
        fViewMatrix.reset();
    } else {
        fViewMatrix = *initialViewMatrix;
    }
    fFlagBits = 0x0;
    fStencilSettings.setDisabled();
    fDrawFace = kBoth_DrawFace;

    fHints = 0;

    fColorProcInfoValid = false;
    fCoverageProcInfoValid = false;

    fColorCache = GrColor_ILLEGAL;
    fCoverageCache = GrColor_ILLEGAL;
}

bool GrDrawState::setIdentityViewMatrix()  {
    if (this->numFragmentStages()) {
        SkMatrix invVM;
        if (!fViewMatrix.invert(&invVM)) {
            // sad trombone sound
            return false;
        }
        for (int s = 0; s < this->numColorStages(); ++s) {
            fColorStages[s].localCoordChange(invVM);
        }
        for (int s = 0; s < this->numCoverageStages(); ++s) {
            fCoverageStages[s].localCoordChange(invVM);
        }
    }
    fViewMatrix.reset();
    return true;
}

void GrDrawState::setFromPaint(const GrPaint& paint, const SkMatrix& vm, GrRenderTarget* rt) {
    SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());

    fGeometryProcessor.reset(NULL);
    fColorStages.reset();
    fCoverageStages.reset();

    for (int i = 0; i < paint.numColorStages(); ++i) {
        fColorStages.push_back(paint.getColorStage(i));
    }

    for (int i = 0; i < paint.numCoverageStages(); ++i) {
        fCoverageStages.push_back(paint.getCoverageStage(i));
    }

    fXPFactory.reset(SkRef(paint.getXPFactory()));

    this->setRenderTarget(rt);

    fViewMatrix = vm;

    // These have no equivalent in GrPaint, set them to defaults
    fDrawFace = kBoth_DrawFace;
    fStencilSettings.setDisabled();
    fFlagBits = 0;
    fHints = 0;

    // Enable the clip bit
    this->enableState(GrDrawState::kClip_StateBit);

    this->setState(GrDrawState::kDither_StateBit, paint.isDither());
    this->setState(GrDrawState::kHWAntialias_StateBit, paint.isAntiAlias());

    fColorProcInfoValid = false;
    fCoverageProcInfoValid = false;

    fColorCache = GrColor_ILLEGAL;
    fCoverageCache = GrColor_ILLEGAL;
}

////////////////////////////////////////////////////////////////////////////////

bool GrDrawState::canUseFracCoveragePrimProc(GrColor color, const GrDrawTargetCaps& caps) const {
    if (caps.dualSourceBlendingSupport()) {
        return true;
    }

    this->calcColorInvariantOutput(color);

    // The coverage isn't actually white, its unknown, but this will produce the same effect
    // TODO we want to cache the result of this call, but we can probably clean up the interface
    // so we don't have to pass in a seemingly known coverage
    this->calcCoverageInvariantOutput(GrColor_WHITE);
    return fXPFactory->canApplyCoverage(fColorProcInfo, fCoverageProcInfo,
                                        this->isCoverageDrawing(), this->isColorWriteDisabled());
}

bool GrDrawState::hasSolidCoverage(GrColor coverage) const {
    // If we're drawing coverage directly then coverage is effectively treated as color.
    if (this->isCoverageDrawing()) {
        return true;
    }

    if (this->numCoverageStages() > 0) {
        return false;
    }

    this->calcCoverageInvariantOutput(coverage);
    return fCoverageProcInfo.isSolidWhite();
}

//////////////////////////////////////////////////////////////////////////////s

bool GrDrawState::willEffectReadDstColor(GrColor color, GrColor coverage) const {
    this->calcColorInvariantOutput(color);
    this->calcCoverageInvariantOutput(coverage);
    // TODO: Remove need to create the XP here.
    //       Also once all custom blends are turned into XPs we can remove the need
    //       to check other stages since only xp's will be able to read dst
    SkAutoTUnref<GrXferProcessor> xferProcessor(fXPFactory->createXferProcessor(fColorProcInfo,
                                                                                fCoverageProcInfo));
    if (xferProcessor && xferProcessor->willReadDstColor()) {
        return true;
    }

    if (!this->isColorWriteDisabled()) {
        if (fColorProcInfo.readsDst()) {
            return true;
        }
    }
    return fCoverageProcInfo.readsDst();
}

void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) {
    if (fDrawState) {
        // See the big comment on the class definition about GPs.
        if (SK_InvalidUniqueID == fOriginalGPID) {
            fDrawState->fGeometryProcessor.reset(NULL);
        } else {
            SkASSERT(fDrawState->getGeometryProcessor()->getUniqueID() ==
                     fOriginalGPID);
            fOriginalGPID = SK_InvalidUniqueID;
        }

        int m = fDrawState->numColorStages() - fColorEffectCnt;
        SkASSERT(m >= 0);
        fDrawState->fColorStages.pop_back_n(m);

        int n = fDrawState->numCoverageStages() - fCoverageEffectCnt;
        SkASSERT(n >= 0);
        fDrawState->fCoverageStages.pop_back_n(n);
        if (m + n > 0) {
            fDrawState->fColorProcInfoValid = false;
            fDrawState->fCoverageProcInfoValid = false;
        }
        SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
    }
    fDrawState = ds;
    if (NULL != ds) {
        SkASSERT(SK_InvalidUniqueID == fOriginalGPID);
        if (NULL != ds->getGeometryProcessor()) {
            fOriginalGPID = ds->getGeometryProcessor()->getUniqueID();
        }
        fColorEffectCnt = ds->numColorStages();
        fCoverageEffectCnt = ds->numCoverageStages();
        SkDEBUGCODE(++ds->fBlockEffectRemovalCnt;)
    }
}

////////////////////////////////////////////////////////////////////////////////

// Some blend modes allow folding a fractional coverage value into the color's alpha channel, while
// others will blend incorrectly.
bool GrDrawState::canTweakAlphaForCoverage() const {
    return fXPFactory->canTweakAlphaForCoverage(this->isCoverageDrawing());
}

////////////////////////////////////////////////////////////////////////////////

void GrDrawState::AutoViewMatrixRestore::restore() {
    if (fDrawState) {
        SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
        fDrawState->fViewMatrix = fViewMatrix;
        SkASSERT(fDrawState->numColorStages() >= fNumColorStages);
        int numCoverageStages = fSavedCoordChanges.count() - fNumColorStages;
        SkASSERT(fDrawState->numCoverageStages() >= numCoverageStages);

        int i = 0;
        for (int s = 0; s < fNumColorStages; ++s, ++i) {
            fDrawState->fColorStages[s].restoreCoordChange(fSavedCoordChanges[i]);
        }
        for (int s = 0; s < numCoverageStages; ++s, ++i) {
            fDrawState->fCoverageStages[s].restoreCoordChange(fSavedCoordChanges[i]);
        }
        fDrawState = NULL;
    }
}

void GrDrawState::AutoViewMatrixRestore::set(GrDrawState* drawState,
                                             const SkMatrix& preconcatMatrix) {
    this->restore();

    SkASSERT(NULL == fDrawState);
    if (NULL == drawState || preconcatMatrix.isIdentity()) {
        return;
    }
    fDrawState = drawState;

    fViewMatrix = drawState->getViewMatrix();
    drawState->fViewMatrix.preConcat(preconcatMatrix);

    this->doEffectCoordChanges(preconcatMatrix);
    SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
}

bool GrDrawState::AutoViewMatrixRestore::setIdentity(GrDrawState* drawState) {
    this->restore();

    if (NULL == drawState) {
        return false;
    }

    if (drawState->getViewMatrix().isIdentity()) {
        return true;
    }

    fViewMatrix = drawState->getViewMatrix();
    if (0 == drawState->numFragmentStages()) {
        drawState->fViewMatrix.reset();
        fDrawState = drawState;
        fNumColorStages = 0;
        fSavedCoordChanges.reset(0);
        SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
        return true;
    } else {
        SkMatrix inv;
        if (!fViewMatrix.invert(&inv)) {
            return false;
        }
        drawState->fViewMatrix.reset();
        fDrawState = drawState;
        this->doEffectCoordChanges(inv);
        SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
        return true;
    }
}

void GrDrawState::AutoViewMatrixRestore::doEffectCoordChanges(const SkMatrix& coordChangeMatrix) {
    fSavedCoordChanges.reset(fDrawState->numFragmentStages());
    int i = 0;

    fNumColorStages = fDrawState->numColorStages();
    for (int s = 0; s < fNumColorStages; ++s, ++i) {
        fDrawState->getColorStage(s).saveCoordChange(&fSavedCoordChanges[i]);
        fDrawState->fColorStages[s].localCoordChange(coordChangeMatrix);
    }

    int numCoverageStages = fDrawState->numCoverageStages();
    for (int s = 0; s < numCoverageStages; ++s, ++i) {
        fDrawState->getCoverageStage(s).saveCoordChange(&fSavedCoordChanges[i]);
        fDrawState->fCoverageStages[s].localCoordChange(coordChangeMatrix);
    }
}

////////////////////////////////////////////////////////////////////////////////

GrDrawState::~GrDrawState() {
    SkASSERT(0 == fBlockEffectRemovalCnt);
}

////////////////////////////////////////////////////////////////////////////////

bool GrDrawState::srcAlphaWillBeOne(GrColor color, GrColor coverage) const {
    this->calcColorInvariantOutput(color);
    if (this->isCoverageDrawing()) {
        this->calcCoverageInvariantOutput(coverage);
        return (fColorProcInfo.isOpaque() && fCoverageProcInfo.isOpaque());
    }
    return fColorProcInfo.isOpaque();
}

bool GrDrawState::willBlendWithDst(GrColor color, GrColor coverage) const {
    this->calcColorInvariantOutput(color);
    this->calcCoverageInvariantOutput(coverage);
    return fXPFactory->willBlendWithDst(fColorProcInfo, fCoverageProcInfo,
                                        this->isCoverageDrawing(), this->isColorWriteDisabled());
}

void GrDrawState::calcColorInvariantOutput(GrColor color) const {
    if (!fColorProcInfoValid || color != fColorCache) {
        GrColorComponentFlags flags;
        if (this->hasColorVertexAttribute()) {
            if (fHints & kVertexColorsAreOpaque_Hint) {
                flags = kA_GrColorComponentFlag;
                color = 0xFF << GrColor_SHIFT_A;
            } else {
                flags = static_cast<GrColorComponentFlags>(0);
                color = 0;
            }
        } else {
            flags = kRGBA_GrColorComponentFlags;
        }
        fColorProcInfo.calcWithInitialValues(fColorStages.begin(), this->numColorStages(),
                                             color, flags, false);
        fColorProcInfoValid = true;
        fColorCache = color;
    }
}

void GrDrawState::calcCoverageInvariantOutput(GrColor coverage) const {
    if (!fCoverageProcInfoValid || coverage != fCoverageCache) {
        GrColorComponentFlags flags;
        // Check if per-vertex or constant color may have partial alpha
        if (this->hasCoverageVertexAttribute()) {
            flags = static_cast<GrColorComponentFlags>(0);
            coverage = 0;
        } else {
            flags = kRGBA_GrColorComponentFlags;
        }
        fCoverageProcInfo.calcWithInitialValues(fCoverageStages.begin(), this->numCoverageStages(),
                                                coverage, flags, true, fGeometryProcessor.get());
        fCoverageProcInfoValid = true;
        fCoverageCache = coverage;
    }
}
<|endoftext|>


<commit_before><?hh //strict

/**
 * This file is part of hhpack\performance.
 *
 * (c) Noritaka Horio <holy.shared.design@gmail.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace hhpack\performance\reporter;

use hhpack\performance\Writer;
use hhpack\performance\WatchedResult;
use hhpack\performance\ResultReporter;
use hhpack\performance\result\BenchmarkedResult;
use hhpack\performance\writer\StdoutWriter;

final class TextReporter implements ResultReporter
{

    private Vector<ImmMap<string, string>> $results;
    private Map<string, int> $paddingLength;

    public function __construct(
        private Writer<void> $writer = new StdoutWriter()
    )
    {
        $this->results = Vector {};
        $this->paddingLength = Map {};
    }

    public function onStop(BenchmarkedResult $result) : void
    {
        $watchedResult = $result->map(($value) ==> (string) $value);

        foreach ($watchedResult as $key => $value) {
            $length = strlen((string) $value);
            $paddingLength = $this->paddingLength->get($key);
            $paddingLength = ($paddingLength === null) ? 0 : $paddingLength;
            $this->paddingLength->set($key, ($length > $paddingLength) ? $length : $paddingLength);
        }

        $this->results->add($watchedResult);
    }

    public function onFinish() : void
    {
        $this->writeHeader();
        $this->writeBody();
        $this->writeFooter();
    }

    <<__Memoize>>
    private function header() : string
    {
        $columns = $this->paddingLength->mapWithKey(($key, $value) ==> {
            return str_pad($key, $value, ' ', STR_PAD_RIGHT);
        })->values()->toArray();

        return '| ' . implode(' | ', $columns) . ' |';
    }

    private function writeHeader() : void
    {
        $headerLength = strlen($this->header());
        $headerSeparator = str_pad('', $headerLength, '-');

        $this->writer->writeln($headerSeparator);
        $this->writer->writeln($this->header());
        $this->writer->writeln($headerSeparator);
    }

    private function writeBody() : void
    {
        foreach ($this->results as $result) {
            $columns = $result->mapWithKey(($key, $value) ==> {
                $max = $this->paddingLength->at($key);
                return str_pad($value, $max, ' ', STR_PAD_LEFT);
            })->values()->toArray();
            $this->writer->writeln('| ' . implode(' | ', $columns) . ' |');
        }
    }

    private function writeFooter() : void
    {
        $headerLength = strlen($this->header());
        $headerSeparator = str_pad('', $headerLength, '-');
        $this->writer->writeln(str_pad('', $headerLength, '-'));
    }

}
<commit_msg>add order number to report<commit_after><?hh //strict

/**
 * This file is part of hhpack\performance.
 *
 * (c) Noritaka Horio <holy.shared.design@gmail.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace hhpack\performance\reporter;

use hhpack\performance\Writer;
use hhpack\performance\WatchedResult;
use hhpack\performance\ResultReporter;
use hhpack\performance\result\BenchmarkedResult;
use hhpack\performance\writer\StdoutWriter;

final class TextReporter implements ResultReporter
{

    private Vector<ImmMap<string, string>> $results;
    private Map<string, int> $paddingLength;

    public function __construct(
        private Writer<void> $writer = new StdoutWriter()
    )
    {
        $this->results = Vector {};
        $this->paddingLength = Map {};
    }

    public function onStop(BenchmarkedResult $result) : void
    {
        $orderedResult = Map { 'order' => (string) $result->orderNumber() };

        $watchedResult = $result->map(($value) ==> (string) $value);
        $watchedResult = $orderedResult->addAll( $watchedResult->items() )->toImmMap();

        foreach ($watchedResult as $key => $value) {
            $length = strlen((string) $value);
            $paddingLength = $this->paddingLength->get($key);
            $paddingLength = ($paddingLength === null) ? 0 : $paddingLength;
            $this->paddingLength->set($key, ($length > $paddingLength) ? $length : $paddingLength);
        }

        $this->results->add($watchedResult);
    }

    public function onFinish() : void
    {
        $this->writeHeader();
        $this->writeBody();
        $this->writeFooter();
    }

    <<__Memoize>>
    private function header() : string
    {
        $this->paddingLength = $this->paddingLength->mapWithKey(($key, $value) ==> {
            return strlen($key) <= $value ? $value : strlen($key);
        });

        $columns = $this->paddingLength->mapWithKey(($key, $value) ==> {
            return str_pad($key, $value, ' ', STR_PAD_RIGHT);
        })->values()->toArray();

        return '| ' . implode(' | ', $columns) . ' |';
    }

    private function writeHeader() : void
    {
        $headerLength = strlen($this->header());
        $headerSeparator = str_pad('', $headerLength, '-');

        $this->writer->writeln($headerSeparator);
        $this->writer->writeln($this->header());
        $this->writer->writeln($headerSeparator);
    }

    private function writeBody() : void
    {
        foreach ($this->results as $result) {
            $columns = $result->mapWithKey(($key, $value) ==> {
                $max = $this->paddingLength->at($key);
                return str_pad($value, $max, ' ', STR_PAD_LEFT);
            })->values()->toArray();
            $this->writer->writeln('| ' . implode(' | ', $columns) . ' |');
        }
    }

    private function writeFooter() : void
    {
        $headerLength = strlen($this->header());
        $headerSeparator = str_pad('', $headerLength, '-');
        $this->writer->writeln(str_pad('', $headerLength, '-'));
    }

}
<|endoftext|>


<commit_before>#include <unistd.h>

#include <event2/event.h>
#include <event2/thread.h>

#include <process/logging.hpp>

#include "event_loop.hpp"
#include "libevent.hpp"
#include "synchronized.hpp"

namespace process {

struct event_base* base = NULL;

void* EventLoop::run(void*)
{
  do {
    int result = event_base_loop(base, EVLOOP_ONCE);
    if (result < 0) {
      LOG(FATAL) << "Failed to run event loop";
    } else if (result == 1) {
      VLOG(1) << "All events handled, continuing event loop";
      continue;
    } else if (event_base_got_break(base)) {
      break;
    } else if (event_base_got_exit(base)) {
      break;
    }
  } while (true);
  return NULL;
}

namespace internal {

struct Delay
{
  lambda::function<void(void)> function;
  event* timer;
};

void handle_delay(int, short, void* arg)
{
  Delay* delay = reinterpret_cast<Delay*>(arg);
  delay->function();
  delete delay;
}

}  // namespace internal {

void EventLoop::delay(
    const Duration& duration,
    const lambda::function<void(void)>& function)
{
  internal::Delay* delay = new internal::Delay();
  delay->timer = evtimer_new(base, &internal::handle_delay, delay);
  if (delay->timer == NULL) {
    LOG(FATAL) << "Failed to delay, evtimer_new";
  }

  delay->function = function;

  timeval t{0, 0};
  if (duration > Seconds(0)) {
    t = duration.timeval();
  }

  evtimer_add(delay->timer, &t);
}

double EventLoop::time()
{
  // Get the cached time if running the event loop, or call
  // gettimeofday() to get the current time. Since a lot of logic in
  // libprocess depends on time math, we want to log fatal rather than
  // cause logic errors if the time fails.
  timeval t;
  if (event_base_gettimeofday_cached(base, &t) < 0) {
    LOG(FATAL) << "Failed to get time, event_base_gettimeofday_cached";
  }

  return Duration(t).secs();
}

void EventLoop::initialize()
{
  if (evthread_use_pthreads() < 0) {
    LOG(FATAL) << "Failed to initialize, evthread_use_pthreads";
  }

  // This enables debugging of libevent calls. We can remove this
  // when the implementation settles and after we gain confidence.
  event_enable_debug_mode();

  base = event_base_new();
  if (base == NULL) {
    LOG(FATAL) << "Failed to initialize, event_base_new";
  }
}

} // namespace process {
<commit_msg>MESOS-2377: Fix leak in libevent EventLoop::handle_delay.<commit_after>#include <unistd.h>

#include <event2/event.h>
#include <event2/thread.h>

#include <process/logging.hpp>

#include "event_loop.hpp"
#include "libevent.hpp"
#include "synchronized.hpp"

namespace process {

struct event_base* base = NULL;

void* EventLoop::run(void*)
{
  do {
    int result = event_base_loop(base, EVLOOP_ONCE);
    if (result < 0) {
      LOG(FATAL) << "Failed to run event loop";
    } else if (result == 1) {
      VLOG(1) << "All events handled, continuing event loop";
      continue;
    } else if (event_base_got_break(base)) {
      break;
    } else if (event_base_got_exit(base)) {
      break;
    }
  } while (true);
  return NULL;
}

namespace internal {

struct Delay
{
  lambda::function<void(void)> function;
  event* timer;
};

void handle_delay(int, short, void* arg)
{
  Delay* delay = reinterpret_cast<Delay*>(arg);
  delay->function();
  event_free(delay->timer);
  delete delay;
}

}  // namespace internal {

void EventLoop::delay(
    const Duration& duration,
    const lambda::function<void(void)>& function)
{
  internal::Delay* delay = new internal::Delay();
  delay->timer = evtimer_new(base, &internal::handle_delay, delay);
  if (delay->timer == NULL) {
    LOG(FATAL) << "Failed to delay, evtimer_new";
  }

  delay->function = function;

  timeval t{0, 0};
  if (duration > Seconds(0)) {
    t = duration.timeval();
  }

  evtimer_add(delay->timer, &t);
}

double EventLoop::time()
{
  // Get the cached time if running the event loop, or call
  // gettimeofday() to get the current time. Since a lot of logic in
  // libprocess depends on time math, we want to log fatal rather than
  // cause logic errors if the time fails.
  timeval t;
  if (event_base_gettimeofday_cached(base, &t) < 0) {
    LOG(FATAL) << "Failed to get time, event_base_gettimeofday_cached";
  }

  return Duration(t).secs();
}

void EventLoop::initialize()
{
  if (evthread_use_pthreads() < 0) {
    LOG(FATAL) << "Failed to initialize, evthread_use_pthreads";
  }

  // This enables debugging of libevent calls. We can remove this
  // when the implementation settles and after we gain confidence.
  event_enable_debug_mode();

  base = event_base_new();
  if (base == NULL) {
    LOG(FATAL) << "Failed to initialize, event_base_new";
  }
}

} // namespace process {
<|endoftext|>


<commit_before>#include "ROOT/TDataFrame.hxx"
#include "TRandom.h"
#include "gtest/gtest.h"
#include <limits>
using namespace ROOT::Experimental;
using namespace ROOT::Experimental::TDF;
using namespace ROOT::Detail::TDF;

/********* FIXTURES *********/
// fixture that provides a TDF with no data-source and a single column "x" containing normal-distributed doubles
class TDFCallbacks : public ::testing::Test {
protected:
   const ULong64_t nEvents = 8ull; // must be initialized before fLoopManager

private:
   TDataFrame fLoopManager;
   TInterface<TLoopManager> DefineRandomCol()
   {
      TRandom r;
      return fLoopManager.Define("x", [r]() mutable { return r.Gaus(); });
   }

protected:
   TDFCallbacks() : fLoopManager(nEvents), tdf(DefineRandomCol()) {}
   TInterface<TLoopManager> tdf;
};

/********* TESTS *********/
TEST_F(TDFCallbacks, Histo1DWithFillTOHelper)
{
   // Histo1D<double> + OnPartialResult + FillTOHelper
   auto h = tdf.Histo1D<double>({"", "", 128, -2., 2.}, "x");
   using value_t = typename decltype(h)::Value_t;
   ULong64_t i = 0ull;
   ULong64_t everyN = 1ull;
   h.OnPartialResult(everyN, [&i, &everyN](value_t &h_) {
      i += everyN;
      EXPECT_EQ(h_.GetEntries(), everyN * i);
   });
   *h;
   EXPECT_EQ(nEvents, everyN * i);
}

TEST_F(TDFCallbacks, JittedHisto1DWithFillTOHelper)
{
   // Histo1D + Jitting + OnPartialResult + FillTOHelper
   auto h = tdf.Histo1D({"", "", 128, -2., 2.}, "x");
   using value_t = typename decltype(h)::Value_t;
   ULong64_t i = 0ull;
   ULong64_t everyN = 1ull;
   h.OnPartialResult(everyN, [&i, &everyN](value_t &h_) {
      i += everyN;
      EXPECT_EQ(h_.GetEntries(), everyN * i);
   });
   *h;
   EXPECT_EQ(nEvents, everyN * i);
}

TEST_F(TDFCallbacks, Histo1DWithFillHelper)
{
   // Histo1D<double> + OnPartialResult + FillHelper
   auto h = tdf.Histo1D<double>("x");
   using value_t = typename decltype(h)::Value_t;
   ULong64_t i = 0ull;
   ULong64_t everyN = 1ull;
   h.OnPartialResult(everyN, [&i, &everyN](value_t &h_) {
      i += everyN;
      EXPECT_EQ(h_.GetEntries(), everyN * i);
   });
   *h;
   EXPECT_EQ(nEvents, everyN * i);
}

TEST_F(TDFCallbacks, JittedHisto1DWithFillHelper)
{
   // Histo1D + Jitting + OnPartialResult + FillHelper
   auto h = tdf.Histo1D("x");
   using value_t = typename decltype(h)::Value_t;
   ULong64_t i = 0ull;
   ULong64_t everyN = 1ull;
   h.OnPartialResult(everyN, [&i, &everyN](value_t &h_) {
      i += everyN;
      EXPECT_EQ(h_.GetEntries(), everyN * i);
   });
   *h;
   EXPECT_EQ(nEvents, everyN * i);
}

TEST_F(TDFCallbacks, Min)
{
   // Min + OnPartialResult
   auto m = tdf.Min<double>("x");
   double runningMin = std::numeric_limits<double>::max();
   m.OnPartialResult(2, [&runningMin](double x) {
      EXPECT_LE(x, runningMin);
      runningMin = x;
   });
   EXPECT_DOUBLE_EQ(runningMin, *m);
}

TEST_F(TDFCallbacks, JittedMin)
{
   // Min + Jitting + OnPartialResult
   auto m = tdf.Min("x");
   double runningMin = std::numeric_limits<double>::max();
   m.OnPartialResult(2, [&runningMin](double x) {
      EXPECT_LE(x, runningMin);
      runningMin = x;
   });
   EXPECT_DOUBLE_EQ(runningMin, *m);
}

TEST_F(TDFCallbacks, Max)
{
   // Max + OnPartialResult
   auto m = tdf.Max<double>("x");
   double runningMax = std::numeric_limits<double>::lowest();
   m.OnPartialResult(2, [&runningMax](double x) {
      EXPECT_GE(x, runningMax);
      runningMax = x;
   });
   EXPECT_DOUBLE_EQ(runningMax, *m);
}

TEST_F(TDFCallbacks, JittedMax)
{
   // Max + Jitting + OnPartialResult
   auto m = tdf.Max("x");
   double runningMax = std::numeric_limits<double>::lowest();
   m.OnPartialResult(2, [&runningMax](double x) {
      EXPECT_GE(x, runningMax);
      runningMax = x;
   });
   EXPECT_DOUBLE_EQ(runningMax, *m);
}

TEST_F(TDFCallbacks, Mean)
{
   // Mean + OnPartialResult
   auto m = tdf.Mean<double>("x");
   // TODO find a better way to check that the running mean makes sense
   bool called = false;
   m.OnPartialResult(nEvents / 2, [&called](double) { called = true; });
   *m;
   EXPECT_TRUE(called);
}

TEST_F(TDFCallbacks, JittedMean)
{
   // Mean + Jitting + OnPartialResult
   auto m = tdf.Mean("x");
   // TODO find a better way to check that the running mean makes sense
   bool called = false;
   m.OnPartialResult(nEvents / 2, [&called](double) { called = true; });
   *m;
   EXPECT_TRUE(called);
}

TEST_F(TDFCallbacks, Take)
{
   // Take + OnPartialResult
   auto t = tdf.Take<double>("x");
   unsigned int i = 0u;
   t.OnPartialResult(1, [&](decltype(t)::Value_t &t_) {
      ++i;
      EXPECT_EQ(t_.size(), i);
   });
   *t;
}

TEST_F(TDFCallbacks, Count)
{
   // Count + OnPartialResult
   auto c = tdf.Count();
   ULong64_t i = 0ull;
   c.OnPartialResult(1, [&](decltype(c)::Value_t c_) {
      ++i;
      EXPECT_EQ(c_, i);
   });
   EXPECT_EQ(*c, i);
}

TEST_F(TDFCallbacks, Reduce)
{
   // Reduce + OnPartialResult
   double runningMin;
   auto m = tdf.Min<double>("x").OnPartialResult(1, [&runningMin](double m_) { runningMin = m_; });
   auto r = tdf.Reduce([](double x1, double x2) { return std::min(x1, x2); }, {"x"}, 0.);
   r.OnPartialResult(1, [&runningMin](double r_) { EXPECT_DOUBLE_EQ(r_, runningMin); });
   *r;
}

TEST_F(TDFCallbacks, Chaining)
{
   // Chaining of multiple OnPartialResult[Slot] calls
   unsigned int i = 0u;
   auto c = tdf.Count()
               .OnPartialResult(1, [&i](ULong64_t) { ++i; })
               .OnPartialResultSlot(1, [&i](unsigned int, ULong64_t) {++i; });
   *c;
   EXPECT_EQ(i, nEvents * 2);
}

TEST_F(TDFCallbacks, OrderOfExecution)
{
   // Test that callbacks are executed in the order they are registered
   unsigned int i = 0u;
   auto c = tdf.Count();
   c.OnPartialResult(1, [&i](ULong64_t) {
      EXPECT_EQ(i, 0u);
      i = 42u;
   });
   c.OnPartialResultSlot(1, [&i](unsigned int slot, ULong64_t) {
      if (slot == 0u) {
         EXPECT_EQ(i, 42u);
         i = 0u;
      }
   });
   *c;
   EXPECT_EQ(i, 0u);
}

TEST_F(TDFCallbacks, MultipleCallbacks)
{
   // registration of multiple callbacks on the same partial result
   auto h = tdf.Histo1D<double>({"", "", 128, -2., 2.}, "x");
   using value_t = typename decltype(h)::Value_t;
   ULong64_t everyN = 1ull;
   ULong64_t i = 0ull;
   h.OnPartialResult(everyN, [&i, everyN](value_t &h_) {
      i += everyN;
      EXPECT_EQ(h_.GetEntries(), i);
   });

   everyN = 2ull;
   ULong64_t i2 = 0ull;
   h.OnPartialResult(everyN, [&i2, everyN](value_t &h_) {
      i2 += everyN;
      EXPECT_EQ(h_.GetEntries(), i2);
   });

   *h;
}

TEST_F(TDFCallbacks, MultipleEventLoops)
{
   // callbacks must be de-registered after the event-loop is run
   auto h = tdf.Histo1D<double>({"", "", 128, -2., 2.}, "x");
   using value_t = typename decltype(h)::Value_t;
   ULong64_t i = 0ull;
   h.OnPartialResult(1ull, [&i](value_t &) { ++i; });
   *h;

   auto h2 = tdf.Histo1D<double>({"", "", 128, -2., 2.}, "x");
   *h2;

   EXPECT_EQ(i, nEvents);
}

class FunctorClass {
   unsigned int &i_;

public:
   FunctorClass(unsigned int &i) : i_(i) {}
   void operator()(ULong64_t) { ++i_; }
};

TEST_F(TDFCallbacks, FunctorClass)
{
   unsigned int i = 0;
   *(tdf.Count().OnPartialResult(1, FunctorClass(i)));
   EXPECT_EQ(i, nEvents);
}

unsigned int freeFunctionCounter = 0;
void FreeFunction(ULong64_t)
{
   freeFunctionCounter++;
}

TEST_F(TDFCallbacks, FreeFunction)
{
   *(tdf.Count().OnPartialResult(1, FreeFunction));
   EXPECT_EQ(freeFunctionCounter, nEvents);
}
<commit_msg>[TDF] Add test for calling a callback once, with and without IMT<commit_after>#include "ROOT/TDataFrame.hxx"
#include "TRandom.h"
#include "TROOT.h"
#include "gtest/gtest.h"
#include <limits>
using namespace ROOT::Experimental;
using namespace ROOT::Experimental::TDF;
using namespace ROOT::Detail::TDF;

/********* FIXTURES *********/
// fixture that provides a TDF with no data-source and a single column "x" containing normal-distributed doubles
class TDFCallbacks : public ::testing::Test {
protected:
   const ULong64_t nEvents = 8ull; // must be initialized before fLoopManager

private:
   TDataFrame fLoopManager;
   TInterface<TLoopManager> DefineRandomCol()
   {
      TRandom r;
      return fLoopManager.Define("x", [r]() mutable { return r.Gaus(); });
   }

protected:
   TDFCallbacks() : fLoopManager(nEvents), tdf(DefineRandomCol()) {}
   TInterface<TLoopManager> tdf;
};

// fixture that enables implicit MT and provides a TDF with no data-source and a single column "x" containing
// normal-distributed doubles
class TDFCallbacksMT : public ::testing::Test {
   class TIMTEnabler {
   public:
      TIMTEnabler(unsigned int nSlots) {
         ROOT::EnableImplicitMT(nSlots);
      }
      ~TIMTEnabler() {
         ROOT::DisableImplicitMT();
      }
   };

protected:
   const ULong64_t nEvents = 8ull; // must be initialized before fLoopManager
   const unsigned int nSlots = 4u;

private:
   TIMTEnabler fIMTEnabler;
   TDataFrame fLoopManager;
   TInterface<TLoopManager> DefineRandomCol()
   {
      std::vector<TRandom> rs;
      return fLoopManager.DefineSlot("x", [rs](unsigned int slot) mutable { return rs[slot].Gaus(); });
   }

protected:
   TDFCallbacksMT() : fIMTEnabler(nSlots), fLoopManager(nEvents), tdf(DefineRandomCol()) {}
   TInterface<TLoopManager> tdf;
};

/********* TESTS *********/
TEST_F(TDFCallbacks, Histo1DWithFillTOHelper)
{
   // Histo1D<double> + OnPartialResult + FillTOHelper
   auto h = tdf.Histo1D<double>({"", "", 128, -2., 2.}, "x");
   using value_t = typename decltype(h)::Value_t;
   ULong64_t i = 0ull;
   ULong64_t everyN = 1ull;
   h.OnPartialResult(everyN, [&i, &everyN](value_t &h_) {
      i += everyN;
      EXPECT_EQ(h_.GetEntries(), everyN * i);
   });
   *h;
   EXPECT_EQ(nEvents, everyN * i);
}

TEST_F(TDFCallbacks, JittedHisto1DWithFillTOHelper)
{
   // Histo1D + Jitting + OnPartialResult + FillTOHelper
   auto h = tdf.Histo1D({"", "", 128, -2., 2.}, "x");
   using value_t = typename decltype(h)::Value_t;
   ULong64_t i = 0ull;
   ULong64_t everyN = 1ull;
   h.OnPartialResult(everyN, [&i, &everyN](value_t &h_) {
      i += everyN;
      EXPECT_EQ(h_.GetEntries(), everyN * i);
   });
   *h;
   EXPECT_EQ(nEvents, everyN * i);
}

TEST_F(TDFCallbacks, Histo1DWithFillHelper)
{
   // Histo1D<double> + OnPartialResult + FillHelper
   auto h = tdf.Histo1D<double>("x");
   using value_t = typename decltype(h)::Value_t;
   ULong64_t i = 0ull;
   ULong64_t everyN = 1ull;
   h.OnPartialResult(everyN, [&i, &everyN](value_t &h_) {
      i += everyN;
      EXPECT_EQ(h_.GetEntries(), everyN * i);
   });
   *h;
   EXPECT_EQ(nEvents, everyN * i);
}

TEST_F(TDFCallbacks, JittedHisto1DWithFillHelper)
{
   // Histo1D + Jitting + OnPartialResult + FillHelper
   auto h = tdf.Histo1D("x");
   using value_t = typename decltype(h)::Value_t;
   ULong64_t i = 0ull;
   ULong64_t everyN = 1ull;
   h.OnPartialResult(everyN, [&i, &everyN](value_t &h_) {
      i += everyN;
      EXPECT_EQ(h_.GetEntries(), everyN * i);
   });
   *h;
   EXPECT_EQ(nEvents, everyN * i);
}

TEST_F(TDFCallbacks, Min)
{
   // Min + OnPartialResult
   auto m = tdf.Min<double>("x");
   double runningMin = std::numeric_limits<double>::max();
   m.OnPartialResult(2, [&runningMin](double x) {
      EXPECT_LE(x, runningMin);
      runningMin = x;
   });
   EXPECT_DOUBLE_EQ(runningMin, *m);
}

TEST_F(TDFCallbacks, JittedMin)
{
   // Min + Jitting + OnPartialResult
   auto m = tdf.Min("x");
   double runningMin = std::numeric_limits<double>::max();
   m.OnPartialResult(2, [&runningMin](double x) {
      EXPECT_LE(x, runningMin);
      runningMin = x;
   });
   EXPECT_DOUBLE_EQ(runningMin, *m);
}

TEST_F(TDFCallbacks, Max)
{
   // Max + OnPartialResult
   auto m = tdf.Max<double>("x");
   double runningMax = std::numeric_limits<double>::lowest();
   m.OnPartialResult(2, [&runningMax](double x) {
      EXPECT_GE(x, runningMax);
      runningMax = x;
   });
   EXPECT_DOUBLE_EQ(runningMax, *m);
}

TEST_F(TDFCallbacks, JittedMax)
{
   // Max + Jitting + OnPartialResult
   auto m = tdf.Max("x");
   double runningMax = std::numeric_limits<double>::lowest();
   m.OnPartialResult(2, [&runningMax](double x) {
      EXPECT_GE(x, runningMax);
      runningMax = x;
   });
   EXPECT_DOUBLE_EQ(runningMax, *m);
}

TEST_F(TDFCallbacks, Mean)
{
   // Mean + OnPartialResult
   auto m = tdf.Mean<double>("x");
   // TODO find a better way to check that the running mean makes sense
   bool called = false;
   m.OnPartialResult(nEvents / 2, [&called](double) { called = true; });
   *m;
   EXPECT_TRUE(called);
}

TEST_F(TDFCallbacks, JittedMean)
{
   // Mean + Jitting + OnPartialResult
   auto m = tdf.Mean("x");
   // TODO find a better way to check that the running mean makes sense
   bool called = false;
   m.OnPartialResult(nEvents / 2, [&called](double) { called = true; });
   *m;
   EXPECT_TRUE(called);
}

TEST_F(TDFCallbacks, Take)
{
   // Take + OnPartialResult
   auto t = tdf.Take<double>("x");
   unsigned int i = 0u;
   t.OnPartialResult(1, [&](decltype(t)::Value_t &t_) {
      ++i;
      EXPECT_EQ(t_.size(), i);
   });
   *t;
}

TEST_F(TDFCallbacks, Count)
{
   // Count + OnPartialResult
   auto c = tdf.Count();
   ULong64_t i = 0ull;
   c.OnPartialResult(1, [&](decltype(c)::Value_t c_) {
      ++i;
      EXPECT_EQ(c_, i);
   });
   EXPECT_EQ(*c, i);
}

TEST_F(TDFCallbacks, Reduce)
{
   // Reduce + OnPartialResult
   double runningMin;
   auto m = tdf.Min<double>("x").OnPartialResult(1, [&runningMin](double m_) { runningMin = m_; });
   auto r = tdf.Reduce([](double x1, double x2) { return std::min(x1, x2); }, {"x"}, 0.);
   r.OnPartialResult(1, [&runningMin](double r_) { EXPECT_DOUBLE_EQ(r_, runningMin); });
   *r;
}

TEST_F(TDFCallbacks, Chaining)
{
   // Chaining of multiple OnPartialResult[Slot] calls
   unsigned int i = 0u;
   auto c = tdf.Count()
               .OnPartialResult(1, [&i](ULong64_t) { ++i; })
               .OnPartialResultSlot(1, [&i](unsigned int, ULong64_t) {++i; });
   *c;
   EXPECT_EQ(i, nEvents * 2);
}

TEST_F(TDFCallbacks, OrderOfExecution)
{
   // Test that callbacks are executed in the order they are registered
   unsigned int i = 0u;
   auto c = tdf.Count();
   c.OnPartialResult(1, [&i](ULong64_t) {
      EXPECT_EQ(i, 0u);
      i = 42u;
   });
   c.OnPartialResultSlot(1, [&i](unsigned int slot, ULong64_t) {
      if (slot == 0u) {
         EXPECT_EQ(i, 42u);
         i = 0u;
      }
   });
   *c;
   EXPECT_EQ(i, 0u);
}

TEST_F(TDFCallbacks, ExecuteOnce)
{
   // OnPartialResult(kOnce)
   auto c = tdf.Count();
   unsigned int callCount = 0;
   c.OnPartialResult(0, [&callCount](ULong64_t) { callCount++; });
   *c;
   EXPECT_EQ(callCount, 1u);
}

TEST_F(TDFCallbacksMT, ExecuteOncePerSlot)
{
   // OnPartialResultSlot(kOnce)
   auto c = tdf.Count();
   std::atomic_uint callCount(0u);
   c.OnPartialResultSlot(c.kOnce, [&callCount](unsigned int, ULong64_t) { callCount++; });
   *c;
   EXPECT_EQ(callCount, nSlots);
}

TEST_F(TDFCallbacks, MultipleCallbacks)
{
   // registration of multiple callbacks on the same partial result
   auto h = tdf.Histo1D<double>({"", "", 128, -2., 2.}, "x");
   using value_t = typename decltype(h)::Value_t;
   ULong64_t everyN = 1ull;
   ULong64_t i = 0ull;
   h.OnPartialResult(everyN, [&i, everyN](value_t &h_) {
      i += everyN;
      EXPECT_EQ(h_.GetEntries(), i);
   });

   everyN = 2ull;
   ULong64_t i2 = 0ull;
   h.OnPartialResult(everyN, [&i2, everyN](value_t &h_) {
      i2 += everyN;
      EXPECT_EQ(h_.GetEntries(), i2);
   });

   *h;
}

TEST_F(TDFCallbacks, MultipleEventLoops)
{
   // callbacks must be de-registered after the event-loop is run
   auto h = tdf.Histo1D<double>({"", "", 128, -2., 2.}, "x");
   using value_t = typename decltype(h)::Value_t;
   ULong64_t i = 0ull;
   h.OnPartialResult(1ull, [&i](value_t &) { ++i; });
   *h;

   auto h2 = tdf.Histo1D<double>({"", "", 128, -2., 2.}, "x");
   *h2;

   EXPECT_EQ(i, nEvents);
}

class FunctorClass {
   unsigned int &i_;

public:
   FunctorClass(unsigned int &i) : i_(i) {}
   void operator()(ULong64_t) { ++i_; }
};

TEST_F(TDFCallbacks, FunctorClass)
{
   unsigned int i = 0;
   *(tdf.Count().OnPartialResult(1, FunctorClass(i)));
   EXPECT_EQ(i, nEvents);
}

unsigned int freeFunctionCounter = 0;
void FreeFunction(ULong64_t)
{
   freeFunctionCounter++;
}

TEST_F(TDFCallbacks, FreeFunction)
{
   *(tdf.Count().OnPartialResult(1, FreeFunction));
   EXPECT_EQ(freeFunctionCounter, nEvents);
}
<|endoftext|>


<commit_before><commit_msg>Water balance error corrected<commit_after><|endoftext|>


<commit_before>/*
 *  main.cpp
 *  Program:  kalarm
 *  (C) 2001 - 2003 by David Jarvie  software@astrojar.org.uk
 *
 *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "kalarm.h"

#include <stdlib.h>

#include <kcmdlineargs.h>
#include <kaboutdata.h>
#include <klocale.h>
#include <kdebug.h>

#include "kalarmapp.h"

#define PROGRAM_NAME "kalarm"

QCString execArguments;    // argument to --exec option

static KCmdLineOptions options[] =
{
	{ "a", 0, 0 },
	{ "ack-confirm", I18N_NOOP("Prompt for confirmation when alarm is acknowledged"), 0 },
	{ "A", 0, 0 },
	{ "attach <url>", I18N_NOOP("Attach file to email (repeat as needed)"), 0 },
	{ "bcc", I18N_NOOP("Blind copy email to self"), 0 },
	{ "b", 0, 0 },
	{ "beep", I18N_NOOP("Beep when message is displayed"), 0 },
	{ "colour", 0, 0 },
	{ "c", 0, 0 },
	{ "color <color>", I18N_NOOP("Message background color (name or hex 0xRRGGBB)"), 0 },
	{ "calendarURL <url>", I18N_NOOP("URL of calendar file"), 0 },
	{ "cancelEvent <eventID>", I18N_NOOP("Cancel alarm with the specified event ID"), 0 },
	{ "e", 0, 0 },
	{ "exec <commandline>", I18N_NOOP("Execute a shell command line"), 0 },
	{ "f", 0, 0 },
	{ "file <url>", I18N_NOOP("File to display"), 0 },
	{ "handleEvent <eventID>", I18N_NOOP("Trigger or cancel alarm with the specified event ID"), 0 },
	{ "i", 0, 0 },
	{ "interval <period>", I18N_NOOP("Interval between alarm recurrences"), 0 },
	{ "l", 0, 0 },
	{ "late-cancel", I18N_NOOP("Cancel alarm if it cannot be triggered on time"), 0 },
	{ "L", 0, 0 },
	{ "login", I18N_NOOP("Repeat alarm at every login"), 0 },
	{ "m", 0, 0 },
	{ "mail <address>", I18N_NOOP("Send an email to the given address (repeat as needed)"), 0 },
	{ "recurrence <spec>", I18N_NOOP("Specify alarm recurrence in RFC2445 format"), 0 },
	{ "R", 0, 0 },
	{ "reminder <period>", I18N_NOOP("Display reminder in advance of alarm"), 0 },
	{ "r", 0, 0 },
	{ "repeat <count>", I18N_NOOP("Number of times to repeat alarm (after the initial occasion)"), 0 },
	{ "reset", I18N_NOOP("Reset the alarm scheduling daemon"), 0 },
	{ "s", 0, 0 },
	{ "sound <url>", I18N_NOOP("Audio file to play"), 0 },
	{ "stop", I18N_NOOP("Stop the alarm scheduling daemon"), 0 },
	{ "S", 0, 0 },
	{ "subject ", I18N_NOOP("Email subject line"), 0 },
	{ "t", 0, 0 },
	{ "time <time>", I18N_NOOP("Trigger alarm at time [[[yyyy-]mm-]dd-]hh:mm, or date yyyy-mm-dd"), 0 },
	{ "tray", I18N_NOOP("Display system tray icon"), 0 },
	{ "u", 0, 0 },
	{ "until <time>", I18N_NOOP("Repeat until time [[[yyyy-]mm-]dd-]hh:mm, or date yyyy-mm-dd"), 0 },
	{ "displayEvent <eventID>", I18N_NOOP("Obsolete: use --triggerEvent instead"), 0 },
	{ "triggerEvent <eventID>", I18N_NOOP("Trigger alarm with the specified event ID"), 0 },
	{ "+[message]", I18N_NOOP("Message text to display"), 0 },
	{ 0, 0, 0 }
};

int main(int argc, char *argv[])
{
	KAboutData aboutData(PROGRAM_NAME, I18N_NOOP("KAlarm"), KALARM_VERSION,
		I18N_NOOP("Personal alarm message, command and email scheduler for KDE"),
		KAboutData::License_GPL,
		"(c) 2001 - 2003, David Jarvie", 0, "http://www.astrojar.org.uk/linux/kalarm.html");
	aboutData.addAuthor("David Jarvie", 0, "software@astrojar.org.uk");

	// Fetch all command line options/arguments after --exec and concatenate
	// them into a single argument. Then change the leading '-'.
	// This is necessary because the "!" indicator in the 'options'
	// array above doesn't work (on KDE2, at least)
	for (int i = 0;  i < argc;  ++i)
	{
		if (!strcmp(argv[i], "-e") || !strcmp(argv[i], "--exec"))
		{
			while (++i < argc)
			{
				execArguments += argv[i];
				if (i < argc - 1)
					execArguments += ' ';
				argv[i][0] = 'x';     // in case it's an option
			}
			break;
		}
	}
	KCmdLineArgs::init(argc, argv, &aboutData);
	KCmdLineArgs::addCmdLineOptions(options);
	KUniqueApplication::addCmdLineOptions();

	if (!KAlarmApp::start())
	{
		// An instance of the application is already running
		exit(0);
	}

	// This is the first time through
	kdDebug(5950) << "main(): initialising\n";
	KAlarmApp* app = KAlarmApp::getInstance();
	app->restoreSession();
	return app->exec();
}
<commit_msg>Improve help text for --recurrence<commit_after>/*
 *  main.cpp
 *  Program:  kalarm
 *  (C) 2001 - 2003 by David Jarvie  software@astrojar.org.uk
 *
 *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "kalarm.h"

#include <stdlib.h>

#include <kcmdlineargs.h>
#include <kaboutdata.h>
#include <klocale.h>
#include <kdebug.h>

#include "kalarmapp.h"

#define PROGRAM_NAME "kalarm"

QCString execArguments;    // argument to --exec option

static KCmdLineOptions options[] =
{
	{ "a", 0, 0 },
	{ "ack-confirm", I18N_NOOP("Prompt for confirmation when alarm is acknowledged"), 0 },
	{ "A", 0, 0 },
	{ "attach <url>", I18N_NOOP("Attach file to email (repeat as needed)"), 0 },
	{ "bcc", I18N_NOOP("Blind copy email to self"), 0 },
	{ "b", 0, 0 },
	{ "beep", I18N_NOOP("Beep when message is displayed"), 0 },
	{ "colour", 0, 0 },
	{ "c", 0, 0 },
	{ "color <color>", I18N_NOOP("Message background color (name or hex 0xRRGGBB)"), 0 },
	{ "calendarURL <url>", I18N_NOOP("URL of calendar file"), 0 },
	{ "cancelEvent <eventID>", I18N_NOOP("Cancel alarm with the specified event ID"), 0 },
	{ "e", 0, 0 },
	{ "exec <commandline>", I18N_NOOP("Execute a shell command line"), 0 },
	{ "f", 0, 0 },
	{ "file <url>", I18N_NOOP("File to display"), 0 },
	{ "handleEvent <eventID>", I18N_NOOP("Trigger or cancel alarm with the specified event ID"), 0 },
	{ "i", 0, 0 },
	{ "interval <period>", I18N_NOOP("Interval between alarm recurrences"), 0 },
	{ "l", 0, 0 },
	{ "late-cancel", I18N_NOOP("Cancel alarm if it cannot be triggered on time"), 0 },
	{ "L", 0, 0 },
	{ "login", I18N_NOOP("Repeat alarm at every login"), 0 },
	{ "m", 0, 0 },
	{ "mail <address>", I18N_NOOP("Send an email to the given address (repeat as needed)"), 0 },
	{ "recurrence <spec>", I18N_NOOP("Specify alarm recurrence using iCalendar syntax"), 0 },
	{ "R", 0, 0 },
	{ "reminder <period>", I18N_NOOP("Display reminder in advance of alarm"), 0 },
	{ "r", 0, 0 },
	{ "repeat <count>", I18N_NOOP("Number of times to repeat alarm (after the initial occasion)"), 0 },
	{ "reset", I18N_NOOP("Reset the alarm scheduling daemon"), 0 },
	{ "s", 0, 0 },
	{ "sound <url>", I18N_NOOP("Audio file to play"), 0 },
	{ "stop", I18N_NOOP("Stop the alarm scheduling daemon"), 0 },
	{ "S", 0, 0 },
	{ "subject ", I18N_NOOP("Email subject line"), 0 },
	{ "t", 0, 0 },
	{ "time <time>", I18N_NOOP("Trigger alarm at time [[[yyyy-]mm-]dd-]hh:mm, or date yyyy-mm-dd"), 0 },
	{ "tray", I18N_NOOP("Display system tray icon"), 0 },
	{ "u", 0, 0 },
	{ "until <time>", I18N_NOOP("Repeat until time [[[yyyy-]mm-]dd-]hh:mm, or date yyyy-mm-dd"), 0 },
	{ "displayEvent <eventID>", I18N_NOOP("Obsolete: use --triggerEvent instead"), 0 },
	{ "triggerEvent <eventID>", I18N_NOOP("Trigger alarm with the specified event ID"), 0 },
	{ "+[message]", I18N_NOOP("Message text to display"), 0 },
	{ 0, 0, 0 }
};

int main(int argc, char *argv[])
{
	KAboutData aboutData(PROGRAM_NAME, I18N_NOOP("KAlarm"), KALARM_VERSION,
		I18N_NOOP("Personal alarm message, command and email scheduler for KDE"),
		KAboutData::License_GPL,
		"(c) 2001 - 2003, David Jarvie", 0, "http://www.astrojar.org.uk/linux/kalarm.html");
	aboutData.addAuthor("David Jarvie", 0, "software@astrojar.org.uk");

	// Fetch all command line options/arguments after --exec and concatenate
	// them into a single argument. Then change the leading '-'.
	// This is necessary because the "!" indicator in the 'options'
	// array above doesn't work (on KDE2, at least)
	for (int i = 0;  i < argc;  ++i)
	{
		if (!strcmp(argv[i], "-e") || !strcmp(argv[i], "--exec"))
		{
			while (++i < argc)
			{
				execArguments += argv[i];
				if (i < argc - 1)
					execArguments += ' ';
				argv[i][0] = 'x';     // in case it's an option
			}
			break;
		}
	}
	KCmdLineArgs::init(argc, argv, &aboutData);
	KCmdLineArgs::addCmdLineOptions(options);
	KUniqueApplication::addCmdLineOptions();

	if (!KAlarmApp::start())
	{
		// An instance of the application is already running
		exit(0);
	}

	// This is the first time through
	kdDebug(5950) << "main(): initialising\n";
	KAlarmApp* app = KAlarmApp::getInstance();
	app->restoreSession();
	return app->exec();
}
<|endoftext|>


<commit_before>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "homeapplication.h"
#include <QDeclarativeContext>
#include <QDeclarativeEngine>
#include <QTimer>
#include <QDesktopWidget>
#include <QDBusMessage>
#include <QDBusConnection>
#include <QIcon>
#include <QX11Info>
#include <QDebug>
#include <QEvent>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xdamage.h>

#include "xtools/xeventlistener.h"
#include "xtools/xatomcache.h"
#include "xtools/xwindowmanager.h"
#include "xtools/homewindowmonitor.h"
#include "notifications/notificationmanager.h"
#include "components/windowmanager.h"
#include "components/windowinfo.h"
#include "lipsticksettings.h"
#include "lipstickdbusinterface.h"

// Define this if you'd like to see debug messages from the home app
#ifdef DEBUG_HOME
#define HOME_DEBUG(things) qDebug() << Q_FUNC_INFO << things
#else
#define HOME_DEBUG(things)
#endif

void HomeApplication::quitSignalHandler(int)
{
    qApp->quit();
}

HomeApplication::HomeApplication(int &argc, char **argv, const QString &qmlPath)
    : QApplication(argc, argv)
    , xEventListeners()
    , toBeRemovedEventListeners()
    , iteratorActiveForEventListenerContainer(false)
    , xDamageEventBase(0)
    , xDamageErrorBase(0)
    , _mainWindowInstance(0)
    , _qmlPath(qmlPath)
    , originalSigIntHandler(signal(SIGINT, quitSignalHandler))
    , originalSigTermHandler(signal(SIGTERM, quitSignalHandler))
{
    setApplicationName("Lipstick");
    // TODO: autogenerate this from tags
    setApplicationVersion("0.3.4");

    XDamageQueryExtension(QX11Info::display(), &xDamageEventBase, &xDamageErrorBase);

    // launch a timer for sending a dbus-signal upstart when basic construct is done
    QTimer::singleShot(0, this, SLOT(sendStartupNotifications()));

    // Initialize the notification manager;
    NotificationManager::instance();

    // Initialize the home window monitor
    HomeWindowMonitor::instance();

    new LipstickDBusInterface(this);
    QDBusConnection::sessionBus().registerService("org.nemomobile.lipstick");
    if (!QDBusConnection::sessionBus().registerObject("/request", this))
        qWarning("lipstick: CAN'T REGISTER DBUS");
}

HomeApplication::~HomeApplication()
{
    delete _mainWindowInstance;

    signal(SIGINT, originalSigIntHandler);
    signal(SIGTERM, originalSigTermHandler);
}

HomeApplication *HomeApplication::instance()
{
    return qobject_cast<HomeApplication *>(QApplication::instance());
}

void HomeApplication::addXEventListener(XEventListener *listener)
{
    if (listener != NULL && !xEventListeners.contains(listener)) {
        xEventListeners.append(listener);
    }
}

void HomeApplication::removeXEventListener(XEventListener *listener)
{
    if (iteratorActiveForEventListenerContainer) {
        toBeRemovedEventListeners.append(listener);
    } else {
        xEventListeners.removeOne(listener);
    }
}

void HomeApplication::sendStartupNotifications()
{
    static QDBusConnection systemBus = QDBusConnection::systemBus();
    QDBusMessage homeReadySignal =
        QDBusMessage::createSignal("/com/nokia/duihome",
                                   "com.nokia.duihome.readyNotifier",
                                   "ready");
    systemBus.send(homeReadySignal);

    // For device boot performance reasons initializing Home scene window must be done
    // only after ready signal is sent.
    mainWindowInstance()->showFullScreen();

    // Visibility change messages are required to make the appVisible() signal work
    XWindowAttributes attributes;
    XGetWindowAttributes(QX11Info::display(), _mainWindowInstance->winId(), &attributes);
    XSelectInput(QX11Info::display(), _mainWindowInstance->winId(), attributes.your_event_mask | VisibilityChangeMask);

    // Excluding it from the task bar
    XWindowManager::excludeFromTaskBar(_mainWindowInstance->winId());

    // Tell X that changes in the properties and the substructure of the root
    // window are interesting. These are used to get the list of windows and
    // for getting window close events.
    XSelectInput(QX11Info::display(), DefaultRootWindow(QX11Info::display()), PropertyChangeMask | SubstructureNotifyMask);
}

bool HomeApplication::x11EventFilter(XEvent *event)
{
    bool eventHandled = false;
    iteratorActiveForEventListenerContainer = true;

    if (event->type == xDamageEventBase + XDamageNotify) {
        HOME_DEBUG("Processing damage event");
        XDamageNotifyEvent *xevent = (XDamageNotifyEvent *) event;

        // xevent->more would inform us if there is more events for the
        // rendering operation. but there isn't interface to pass the
        // information to damageEvent.
        emit damageEvent(xevent->damage, xevent->area.x, xevent->area.y, xevent->area.width, xevent->area.height);
        eventHandled = true;
    }

    foreach (XEventListener* listener, xEventListeners) {
        if (!toBeRemovedEventListeners.contains(listener)) {
            if (listener->handleXEvent(*event)) {
                eventHandled = true;
            }
        }
    }
    iteratorActiveForEventListenerContainer = false;

    // Remove now any event listeners that got removed while going through the event listeners
    foreach (XEventListener* listener, toBeRemovedEventListeners) {
        xEventListeners.removeOne(listener);
    }
    toBeRemovedEventListeners.clear();

    if (!eventHandled) {
        eventHandled = QApplication::x11EventFilter(event);
    }

    return eventHandled;
}

const QString &HomeApplication::qmlPath() const
{
    return _qmlPath;
}

void HomeApplication::setQmlPath(const QString &path)
{
    _qmlPath = path;

    if (_mainWindowInstance)
        _mainWindowInstance->setSource(path);
}

QDeclarativeView *HomeApplication::mainWindowInstance()
{
    if (_mainWindowInstance)
        return _mainWindowInstance;

    _mainWindowInstance = new QDeclarativeView();
    _mainWindowInstance->setAttribute(Qt::WA_X11NetWmWindowTypeDesktop);

    // Setting optimalization flags
    _mainWindowInstance->setOptimizationFlag(QGraphicsView::DontSavePainterState);
    _mainWindowInstance->setResizeMode(QDeclarativeView::SizeRootObjectToView);
    _mainWindowInstance->setAutoFillBackground(false);
    _mainWindowInstance->setAttribute(Qt::WA_OpaquePaintEvent);
    _mainWindowInstance->setAttribute(Qt::WA_NoSystemBackground);
    _mainWindowInstance->viewport()->setAutoFillBackground(false);
    _mainWindowInstance->viewport()->setAttribute(Qt::WA_OpaquePaintEvent);
    _mainWindowInstance->viewport()->setAttribute(Qt::WA_NoSystemBackground);

    // Setting up the context and engine things
    QObject::connect(_mainWindowInstance->engine(), SIGNAL(quit()), QApplication::instance(), SLOT(quit()));
    _mainWindowInstance->rootContext()->setContextProperty("initialSize", QApplication::desktop()->screenGeometry(_mainWindowInstance).size());
    _mainWindowInstance->rootContext()->setContextProperty("windowManager", new WindowManager(this));
    _mainWindowInstance->rootContext()->setContextProperty("LipstickSettings", LipstickSettings::instance());

    // Setting the source, if present
    if (!_qmlPath.isEmpty())
        _mainWindowInstance->setSource(_qmlPath);

    return _mainWindowInstance;
}
<commit_msg>prepare 0.4.0<commit_after>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "homeapplication.h"
#include <QDeclarativeContext>
#include <QDeclarativeEngine>
#include <QTimer>
#include <QDesktopWidget>
#include <QDBusMessage>
#include <QDBusConnection>
#include <QIcon>
#include <QX11Info>
#include <QDebug>
#include <QEvent>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xdamage.h>

#include "xtools/xeventlistener.h"
#include "xtools/xatomcache.h"
#include "xtools/xwindowmanager.h"
#include "xtools/homewindowmonitor.h"
#include "notifications/notificationmanager.h"
#include "components/windowmanager.h"
#include "components/windowinfo.h"
#include "lipsticksettings.h"
#include "lipstickdbusinterface.h"

// Define this if you'd like to see debug messages from the home app
#ifdef DEBUG_HOME
#define HOME_DEBUG(things) qDebug() << Q_FUNC_INFO << things
#else
#define HOME_DEBUG(things)
#endif

void HomeApplication::quitSignalHandler(int)
{
    qApp->quit();
}

HomeApplication::HomeApplication(int &argc, char **argv, const QString &qmlPath)
    : QApplication(argc, argv)
    , xEventListeners()
    , toBeRemovedEventListeners()
    , iteratorActiveForEventListenerContainer(false)
    , xDamageEventBase(0)
    , xDamageErrorBase(0)
    , _mainWindowInstance(0)
    , _qmlPath(qmlPath)
    , originalSigIntHandler(signal(SIGINT, quitSignalHandler))
    , originalSigTermHandler(signal(SIGTERM, quitSignalHandler))
{
    setApplicationName("Lipstick");
    // TODO: autogenerate this from tags
    setApplicationVersion("0.4.0");

    XDamageQueryExtension(QX11Info::display(), &xDamageEventBase, &xDamageErrorBase);

    // launch a timer for sending a dbus-signal upstart when basic construct is done
    QTimer::singleShot(0, this, SLOT(sendStartupNotifications()));

    // Initialize the notification manager;
    NotificationManager::instance();

    // Initialize the home window monitor
    HomeWindowMonitor::instance();

    new LipstickDBusInterface(this);
    QDBusConnection::sessionBus().registerService("org.nemomobile.lipstick");
    if (!QDBusConnection::sessionBus().registerObject("/request", this))
        qWarning("lipstick: CAN'T REGISTER DBUS");
}

HomeApplication::~HomeApplication()
{
    delete _mainWindowInstance;

    signal(SIGINT, originalSigIntHandler);
    signal(SIGTERM, originalSigTermHandler);
}

HomeApplication *HomeApplication::instance()
{
    return qobject_cast<HomeApplication *>(QApplication::instance());
}

void HomeApplication::addXEventListener(XEventListener *listener)
{
    if (listener != NULL && !xEventListeners.contains(listener)) {
        xEventListeners.append(listener);
    }
}

void HomeApplication::removeXEventListener(XEventListener *listener)
{
    if (iteratorActiveForEventListenerContainer) {
        toBeRemovedEventListeners.append(listener);
    } else {
        xEventListeners.removeOne(listener);
    }
}

void HomeApplication::sendStartupNotifications()
{
    static QDBusConnection systemBus = QDBusConnection::systemBus();
    QDBusMessage homeReadySignal =
        QDBusMessage::createSignal("/com/nokia/duihome",
                                   "com.nokia.duihome.readyNotifier",
                                   "ready");
    systemBus.send(homeReadySignal);

    // For device boot performance reasons initializing Home scene window must be done
    // only after ready signal is sent.
    mainWindowInstance()->showFullScreen();

    // Visibility change messages are required to make the appVisible() signal work
    XWindowAttributes attributes;
    XGetWindowAttributes(QX11Info::display(), _mainWindowInstance->winId(), &attributes);
    XSelectInput(QX11Info::display(), _mainWindowInstance->winId(), attributes.your_event_mask | VisibilityChangeMask);

    // Excluding it from the task bar
    XWindowManager::excludeFromTaskBar(_mainWindowInstance->winId());

    // Tell X that changes in the properties and the substructure of the root
    // window are interesting. These are used to get the list of windows and
    // for getting window close events.
    XSelectInput(QX11Info::display(), DefaultRootWindow(QX11Info::display()), PropertyChangeMask | SubstructureNotifyMask);
}

bool HomeApplication::x11EventFilter(XEvent *event)
{
    bool eventHandled = false;
    iteratorActiveForEventListenerContainer = true;

    if (event->type == xDamageEventBase + XDamageNotify) {
        HOME_DEBUG("Processing damage event");
        XDamageNotifyEvent *xevent = (XDamageNotifyEvent *) event;

        // xevent->more would inform us if there is more events for the
        // rendering operation. but there isn't interface to pass the
        // information to damageEvent.
        emit damageEvent(xevent->damage, xevent->area.x, xevent->area.y, xevent->area.width, xevent->area.height);
        eventHandled = true;
    }

    foreach (XEventListener* listener, xEventListeners) {
        if (!toBeRemovedEventListeners.contains(listener)) {
            if (listener->handleXEvent(*event)) {
                eventHandled = true;
            }
        }
    }
    iteratorActiveForEventListenerContainer = false;

    // Remove now any event listeners that got removed while going through the event listeners
    foreach (XEventListener* listener, toBeRemovedEventListeners) {
        xEventListeners.removeOne(listener);
    }
    toBeRemovedEventListeners.clear();

    if (!eventHandled) {
        eventHandled = QApplication::x11EventFilter(event);
    }

    return eventHandled;
}

const QString &HomeApplication::qmlPath() const
{
    return _qmlPath;
}

void HomeApplication::setQmlPath(const QString &path)
{
    _qmlPath = path;

    if (_mainWindowInstance)
        _mainWindowInstance->setSource(path);
}

QDeclarativeView *HomeApplication::mainWindowInstance()
{
    if (_mainWindowInstance)
        return _mainWindowInstance;

    _mainWindowInstance = new QDeclarativeView();
    _mainWindowInstance->setAttribute(Qt::WA_X11NetWmWindowTypeDesktop);

    // Setting optimalization flags
    _mainWindowInstance->setOptimizationFlag(QGraphicsView::DontSavePainterState);
    _mainWindowInstance->setResizeMode(QDeclarativeView::SizeRootObjectToView);
    _mainWindowInstance->setAutoFillBackground(false);
    _mainWindowInstance->setAttribute(Qt::WA_OpaquePaintEvent);
    _mainWindowInstance->setAttribute(Qt::WA_NoSystemBackground);
    _mainWindowInstance->viewport()->setAutoFillBackground(false);
    _mainWindowInstance->viewport()->setAttribute(Qt::WA_OpaquePaintEvent);
    _mainWindowInstance->viewport()->setAttribute(Qt::WA_NoSystemBackground);

    // Setting up the context and engine things
    QObject::connect(_mainWindowInstance->engine(), SIGNAL(quit()), QApplication::instance(), SLOT(quit()));
    _mainWindowInstance->rootContext()->setContextProperty("initialSize", QApplication::desktop()->screenGeometry(_mainWindowInstance).size());
    _mainWindowInstance->rootContext()->setContextProperty("windowManager", new WindowManager(this));
    _mainWindowInstance->rootContext()->setContextProperty("LipstickSettings", LipstickSettings::instance());

    // Setting the source, if present
    if (!_qmlPath.isEmpty())
        _mainWindowInstance->setSource(_qmlPath);

    return _mainWindowInstance;
}
<|endoftext|>


<commit_before>/*
 * DISTRHO Plugin Framework (DPF)
 * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any purpose with
 * or without fee is hereby granted, provided that the above copyright notice and this
 * permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef DGL_IMAGE_WIDGETS_HPP_INCLUDED
#define DGL_IMAGE_WIDGETS_HPP_INCLUDED

#include "Image.hpp"
#include "Widget.hpp"
#include "Window.hpp"

START_NAMESPACE_DGL

// -----------------------------------------------------------------------

class ImageAboutWindow : public Window,
                         public Widget
{
public:
    explicit ImageAboutWindow(Window& parent, const Image& image = Image());
    explicit ImageAboutWindow(Widget* widget, const Image& image = Image());

    void setImage(const Image& image);

protected:
    void onDisplay() override;
    bool onKeyboard(const KeyboardEvent&) override;
    bool onMouse(const MouseEvent&) override;
    void onReshape(uint width, uint height) override;

private:
    Image fImgBackground;

    DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImageAboutWindow)
};

// -----------------------------------------------------------------------

class ImageButton : public Widget
{
public:
    class Callback
    {
    public:
        virtual ~Callback() {}
        virtual void imageButtonClicked(ImageButton* imageButton, int button) = 0;
    };

    explicit ImageButton(Window& parent, const Image& image);
    explicit ImageButton(Window& parent, const Image& imageNormal, const Image& imageDown);
    explicit ImageButton(Window& parent, const Image& imageNormal, const Image& imageHover, const Image& imageDown);

    explicit ImageButton(Widget* widget, const Image& image);
    explicit ImageButton(Widget* widget, const Image& imageNormal, const Image& imageDown);
    explicit ImageButton(Widget* widget, const Image& imageNormal, const Image& imageHover, const Image& imageDown);

    ~ImageButton() override;

    void setCallback(Callback* callback) noexcept;

protected:
     void onDisplay() override;
     bool onMouse(const MouseEvent&) override;
     bool onMotion(const MotionEvent&) override;

private:
    struct PrivateData;
    PrivateData* const pData;

    DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImageButton)
};

// -----------------------------------------------------------------------

class ImageKnob : public Widget
{
public:
    enum Orientation {
        Horizontal,
        Vertical
    };

    class Callback
    {
    public:
        virtual ~Callback() {}
        virtual void imageKnobDragStarted(ImageKnob* imageKnob) = 0;
        virtual void imageKnobDragFinished(ImageKnob* imageKnob) = 0;
        virtual void imageKnobValueChanged(ImageKnob* imageKnob, float value) = 0;
    };

    explicit ImageKnob(Window& parent, const Image& image, Orientation orientation = Vertical) noexcept;
    explicit ImageKnob(Widget* widget, const Image& image, Orientation orientation = Vertical) noexcept;
    explicit ImageKnob(const ImageKnob& imageKnob);
    ImageKnob& operator=(const ImageKnob& imageKnob);
    ~ImageKnob() override;

    float getValue() const noexcept;

    void setDefault(float def) noexcept;
    void setRange(float min, float max) noexcept;
    void setStep(float step) noexcept;
    void setValue(float value, bool sendCallback = false) noexcept;
    void setUsingLogScale(bool yesNo) noexcept;

    void setCallback(Callback* callback) noexcept;
    void setOrientation(Orientation orientation) noexcept;
    void setRotationAngle(int angle);

    void setImageLayerCount(uint count) noexcept;

protected:
     void onDisplay() override;
     bool onMouse(const MouseEvent&) override;
     bool onMotion(const MotionEvent&) override;
     bool onScroll(const ScrollEvent&) override;

private:
    Image fImage;
    float fMinimum;
    float fMaximum;
    float fStep;
    float fValue;
    float fValueDef;
    float fValueTmp;
    bool  fUsingDefault;
    bool  fUsingLog;
    Orientation fOrientation;

    int  fRotationAngle;
    bool fDragging;
    int  fLastX;
    int  fLastY;

    Callback* fCallback;

    bool fIsImgVertical;
    uint fImgLayerWidth;
    uint fImgLayerHeight;
    uint fImgLayerCount;
    bool fIsReady;
    GLuint fTextureId;

    float _logscale(float value) const;
    float _invlogscale(float value) const;

    DISTRHO_LEAK_DETECTOR(ImageKnob)
};

// -----------------------------------------------------------------------

// note set range and step before setting the value

class ImageSlider : public Widget
{
public:
    class Callback
    {
    public:
        virtual ~Callback() {}
        virtual void imageSliderDragStarted(ImageSlider* imageSlider) = 0;
        virtual void imageSliderDragFinished(ImageSlider* imageSlider) = 0;
        virtual void imageSliderValueChanged(ImageSlider* imageSlider, float value) = 0;
    };

    explicit ImageSlider(Window& parent, const Image& image) noexcept;
    explicit ImageSlider(Widget* widget, const Image& image) noexcept;

    float getValue() const noexcept;
    void setValue(float value, bool sendCallback = false) noexcept;
    void setDefault(float def) noexcept;

    void setStartPos(const Point<int>& startPos) noexcept;
    void setStartPos(int x, int y) noexcept;
    void setEndPos(const Point<int>& endPos) noexcept;
    void setEndPos(int x, int y) noexcept;

    void setInverted(bool inverted) noexcept;
    void setRange(float min, float max) noexcept;
    void setStep(float step) noexcept;

    void setCallback(Callback* callback) noexcept;

protected:
     void onDisplay() override;
     bool onMouse(const MouseEvent&) override;
     bool onMotion(const MotionEvent&) override;

private:
    Image fImage;
    float fMinimum;
    float fMaximum;
    float fStep;
    float fValue;
    float fValueDef;
    float fValueTmp;
    bool  fUsingDefault;

    bool fDragging;
    bool fInverted;
    bool fValueIsSet;
    int  fStartedX;
    int  fStartedY;

    Callback* fCallback;

    Point<int> fStartPos;
    Point<int> fEndPos;
    Rectangle<int> fSliderArea;

    void _recheckArea() noexcept;

    // these should not be used
    void setAbsoluteX(int) const noexcept {}
    void setAbsoluteY(int) const noexcept {}
    void setAbsolutePos(int, int) const noexcept {}
    void setAbsolutePos(const Point<int>&) const noexcept {}

    DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImageSlider)
};

// -----------------------------------------------------------------------

class ImageSwitch : public Widget
{
public:
    class Callback
    {
    public:
        virtual ~Callback() {}
        virtual void imageSwitchClicked(ImageSwitch* imageButton, bool down) = 0;
    };

    explicit ImageSwitch(Window& parent, const Image& imageNormal, const Image& imageDown) noexcept;
    explicit ImageSwitch(Widget* widget, const Image& imageNormal, const Image& imageDown) noexcept;
    explicit ImageSwitch(const ImageSwitch& imageSwitch) noexcept;
    ImageSwitch& operator=(const ImageSwitch& imageSwitch) noexcept;

    bool isDown() const noexcept;
    void setDown(bool down) noexcept;

    void setCallback(Callback* callback) noexcept;

protected:
     void onDisplay() override;
     bool onMouse(const MouseEvent&) override;

private:
    Image fImageNormal;
    Image fImageDown;
    bool  fIsDown;

    Callback* fCallback;

    DISTRHO_LEAK_DETECTOR(ImageSwitch)
};

// -----------------------------------------------------------------------

END_NAMESPACE_DGL

#endif // DGL_IMAGE_WIDGETS_HPP_INCLUDED
<commit_msg>Fix parameter name in ImageSwitch callback method signature (#92)<commit_after>/*
 * DISTRHO Plugin Framework (DPF)
 * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any purpose with
 * or without fee is hereby granted, provided that the above copyright notice and this
 * permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef DGL_IMAGE_WIDGETS_HPP_INCLUDED
#define DGL_IMAGE_WIDGETS_HPP_INCLUDED

#include "Image.hpp"
#include "Widget.hpp"
#include "Window.hpp"

START_NAMESPACE_DGL

// -----------------------------------------------------------------------

class ImageAboutWindow : public Window,
                         public Widget
{
public:
    explicit ImageAboutWindow(Window& parent, const Image& image = Image());
    explicit ImageAboutWindow(Widget* widget, const Image& image = Image());

    void setImage(const Image& image);

protected:
    void onDisplay() override;
    bool onKeyboard(const KeyboardEvent&) override;
    bool onMouse(const MouseEvent&) override;
    void onReshape(uint width, uint height) override;

private:
    Image fImgBackground;

    DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImageAboutWindow)
};

// -----------------------------------------------------------------------

class ImageButton : public Widget
{
public:
    class Callback
    {
    public:
        virtual ~Callback() {}
        virtual void imageButtonClicked(ImageButton* imageButton, int button) = 0;
    };

    explicit ImageButton(Window& parent, const Image& image);
    explicit ImageButton(Window& parent, const Image& imageNormal, const Image& imageDown);
    explicit ImageButton(Window& parent, const Image& imageNormal, const Image& imageHover, const Image& imageDown);

    explicit ImageButton(Widget* widget, const Image& image);
    explicit ImageButton(Widget* widget, const Image& imageNormal, const Image& imageDown);
    explicit ImageButton(Widget* widget, const Image& imageNormal, const Image& imageHover, const Image& imageDown);

    ~ImageButton() override;

    void setCallback(Callback* callback) noexcept;

protected:
     void onDisplay() override;
     bool onMouse(const MouseEvent&) override;
     bool onMotion(const MotionEvent&) override;

private:
    struct PrivateData;
    PrivateData* const pData;

    DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImageButton)
};

// -----------------------------------------------------------------------

class ImageKnob : public Widget
{
public:
    enum Orientation {
        Horizontal,
        Vertical
    };

    class Callback
    {
    public:
        virtual ~Callback() {}
        virtual void imageKnobDragStarted(ImageKnob* imageKnob) = 0;
        virtual void imageKnobDragFinished(ImageKnob* imageKnob) = 0;
        virtual void imageKnobValueChanged(ImageKnob* imageKnob, float value) = 0;
    };

    explicit ImageKnob(Window& parent, const Image& image, Orientation orientation = Vertical) noexcept;
    explicit ImageKnob(Widget* widget, const Image& image, Orientation orientation = Vertical) noexcept;
    explicit ImageKnob(const ImageKnob& imageKnob);
    ImageKnob& operator=(const ImageKnob& imageKnob);
    ~ImageKnob() override;

    float getValue() const noexcept;

    void setDefault(float def) noexcept;
    void setRange(float min, float max) noexcept;
    void setStep(float step) noexcept;
    void setValue(float value, bool sendCallback = false) noexcept;
    void setUsingLogScale(bool yesNo) noexcept;

    void setCallback(Callback* callback) noexcept;
    void setOrientation(Orientation orientation) noexcept;
    void setRotationAngle(int angle);

    void setImageLayerCount(uint count) noexcept;

protected:
     void onDisplay() override;
     bool onMouse(const MouseEvent&) override;
     bool onMotion(const MotionEvent&) override;
     bool onScroll(const ScrollEvent&) override;

private:
    Image fImage;
    float fMinimum;
    float fMaximum;
    float fStep;
    float fValue;
    float fValueDef;
    float fValueTmp;
    bool  fUsingDefault;
    bool  fUsingLog;
    Orientation fOrientation;

    int  fRotationAngle;
    bool fDragging;
    int  fLastX;
    int  fLastY;

    Callback* fCallback;

    bool fIsImgVertical;
    uint fImgLayerWidth;
    uint fImgLayerHeight;
    uint fImgLayerCount;
    bool fIsReady;
    GLuint fTextureId;

    float _logscale(float value) const;
    float _invlogscale(float value) const;

    DISTRHO_LEAK_DETECTOR(ImageKnob)
};

// -----------------------------------------------------------------------

// note set range and step before setting the value

class ImageSlider : public Widget
{
public:
    class Callback
    {
    public:
        virtual ~Callback() {}
        virtual void imageSliderDragStarted(ImageSlider* imageSlider) = 0;
        virtual void imageSliderDragFinished(ImageSlider* imageSlider) = 0;
        virtual void imageSliderValueChanged(ImageSlider* imageSlider, float value) = 0;
    };

    explicit ImageSlider(Window& parent, const Image& image) noexcept;
    explicit ImageSlider(Widget* widget, const Image& image) noexcept;

    float getValue() const noexcept;
    void setValue(float value, bool sendCallback = false) noexcept;
    void setDefault(float def) noexcept;

    void setStartPos(const Point<int>& startPos) noexcept;
    void setStartPos(int x, int y) noexcept;
    void setEndPos(const Point<int>& endPos) noexcept;
    void setEndPos(int x, int y) noexcept;

    void setInverted(bool inverted) noexcept;
    void setRange(float min, float max) noexcept;
    void setStep(float step) noexcept;

    void setCallback(Callback* callback) noexcept;

protected:
     void onDisplay() override;
     bool onMouse(const MouseEvent&) override;
     bool onMotion(const MotionEvent&) override;

private:
    Image fImage;
    float fMinimum;
    float fMaximum;
    float fStep;
    float fValue;
    float fValueDef;
    float fValueTmp;
    bool  fUsingDefault;

    bool fDragging;
    bool fInverted;
    bool fValueIsSet;
    int  fStartedX;
    int  fStartedY;

    Callback* fCallback;

    Point<int> fStartPos;
    Point<int> fEndPos;
    Rectangle<int> fSliderArea;

    void _recheckArea() noexcept;

    // these should not be used
    void setAbsoluteX(int) const noexcept {}
    void setAbsoluteY(int) const noexcept {}
    void setAbsolutePos(int, int) const noexcept {}
    void setAbsolutePos(const Point<int>&) const noexcept {}

    DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImageSlider)
};

// -----------------------------------------------------------------------

class ImageSwitch : public Widget
{
public:
    class Callback
    {
    public:
        virtual ~Callback() {}
        virtual void imageSwitchClicked(ImageSwitch* imageSwitch, bool down) = 0;
    };

    explicit ImageSwitch(Window& parent, const Image& imageNormal, const Image& imageDown) noexcept;
    explicit ImageSwitch(Widget* widget, const Image& imageNormal, const Image& imageDown) noexcept;
    explicit ImageSwitch(const ImageSwitch& imageSwitch) noexcept;
    ImageSwitch& operator=(const ImageSwitch& imageSwitch) noexcept;

    bool isDown() const noexcept;
    void setDown(bool down) noexcept;

    void setCallback(Callback* callback) noexcept;

protected:
     void onDisplay() override;
     bool onMouse(const MouseEvent&) override;

private:
    Image fImageNormal;
    Image fImageDown;
    bool  fIsDown;

    Callback* fCallback;

    DISTRHO_LEAK_DETECTOR(ImageSwitch)
};

// -----------------------------------------------------------------------

END_NAMESPACE_DGL

#endif // DGL_IMAGE_WIDGETS_HPP_INCLUDED
<|endoftext|>


<commit_before><commit_msg>REMOVED: un-need comments<commit_after><|endoftext|>