<commit_before>#include "page.h"
#include <math.h>
#include "site.h"
#include "api.h"
#include "vendor/json.h"
#include "logger.h"

Page::Page(Profile *profile, Site *site, QList<Site*> sites, QStringList tags, int page, int limit, QStringList postFiltering, bool smart, QObject *parent, int pool, int lastPage, int lastPageMinId, int lastPageMaxId)
	: QObject(parent), m_site(site), m_regexApi(-1), m_postFiltering(postFiltering), m_errors(QStringList()), m_imagesPerPage(limit), m_currentSource(0), m_lastPage(lastPage), m_lastPageMinId(lastPageMinId), m_lastPageMaxId(lastPageMaxId), m_smart(smart)
{
	m_website = m_site->url();
	m_imagesCount = -1;
	m_pagesCount = -1;

	// Replace shortcuts to increase compatibility
	QString text = " "+tags.join(" ")+" ";
	text.replace(" rating:s ", " rating:safe ", Qt::CaseInsensitive)
		.replace(" rating:q ", " rating:questionable ", Qt::CaseInsensitive)
		.replace(" rating:e ", " rating:explicit ", Qt::CaseInsensitive)
		.replace(" -rating:s ", " -rating:safe ", Qt::CaseInsensitive)
		.replace(" -rating:q ", " -rating:questionable ", Qt::CaseInsensitive)
		.replace(" -rating:e ", " -rating:explicit ", Qt::CaseInsensitive);
	tags = text.split(" ", QString::SkipEmptyParts);

	// Get the list of all enabled modifiers
	QStringList modifiers = QStringList();
	for (Site *site : sites)
	{
		if (site->contains("Modifiers"))
		{ modifiers.append(site->value("Modifiers").trimmed().split(" ", QString::SkipEmptyParts)); }
	}
	if (m_site->contains("Modifiers"))
	{
		QStringList mods = m_site->value("Modifiers").trimmed().split(" ", QString::SkipEmptyParts);
		for (int j = 0; j < mods.size(); j++)
		{ modifiers.removeAll(mods[j]); }
	}

	// Remove modifiers from tags
	for (int k = 0; k < modifiers.size(); k++)
	{ tags.removeAll(modifiers[k]); }
	m_search = tags;

	// Generate pages
	m_siteApis = m_site->getApis(true);
	for (Api *api : m_siteApis)
	{
		m_pageApis.append(new PageApi(this, profile, m_site, api, m_search, page, limit, postFiltering, smart, parent, pool, lastPage, lastPageMinId, lastPageMaxId));
		if (api->getName() == "Html" && m_regexApi < 0)
		{ m_regexApi = m_pageApis.count() - 1; }
	}
	m_currentApi = -1;

	// Set values
	m_page = page;
	m_pool = pool;
	fallback(false);
}
Page::~Page()
{
	qDeleteAll(m_pageApis);
}

void Page::fallback(bool bload)
{
	if (m_currentApi >= m_siteApis.count() - 1)
	{
		log("No valid source of the site returned result.");
		m_errors.append(tr("No valid source of the site returned result."));
		emit failedLoading(this);
		return;
	}

	m_currentApi++;
	if (m_currentApi > 0)
		log(QString("Loading using %1 failed. Retry using %2.").arg(m_siteApis[m_currentApi - 1]->getName()).arg(m_siteApis[m_currentApi]->getName()));

	if (bload)
		load();
}

void Page::setLastPage(Page *page)
{
	m_lastPage = page->page();
	m_lastPageMaxId = page->maxId();
	m_lastPageMinId = page->minId();

	for (PageApi *api : m_pageApis)
		api->setLastPage(page);

	m_currentApi--;
	if (!page->nextPage().isEmpty())
	{ /*m_url = page->nextPage();*/ }
	else
	{ fallback(false); }
}

void Page::load(bool rateLimit)
{
	connect(m_pageApis[m_currentApi], &PageApi::finishedLoading, this, &Page::loadFinished);
	m_pageApis[m_currentApi]->load(rateLimit);
}
void Page::loadFinished(PageApi *api, PageApi::LoadResult status)
{
	if (api != m_pageApis[m_currentApi])
		return;

	if (status == PageApi::LoadResult::Ok)
		emit finishedLoading(this);
	else
		fallback();
}
void Page::abort()
{
	m_pageApis[m_currentApi]->abort();
}

void Page::loadTags()
{
	if (m_regexApi < 0)
		return;

	connect(m_pageApis[m_regexApi], &PageApi::finishedLoadingTags, this, &Page::loadTagsFinished);
	m_pageApis[m_regexApi]->loadTags();
}
void Page::loadTagsFinished(PageApi *api)
{
	if (m_regexApi < 0 || api != m_pageApis[m_regexApi])
		return;

	emit finishedLoadingTags(this);
}
void Page::abortTags()
{
	if (m_regexApi < 0)
		return;

	m_pageApis[m_regexApi]->abortTags();
}

void Page::clear()
{
	for (PageApi *pageApi : m_pageApis)
		pageApi->clear();
}

Site			*Page::site()		{ return m_site;								}
QString			Page::website()		{ return m_website;								}
QString			Page::wiki()		{ return m_wiki;								}
QStringList		Page::search()		{ return m_search;								}
QStringList		Page::errors()		{ return m_errors;								}
int				Page::imagesPerPage()	{ return m_imagesPerPage;					}
int				Page::page()		{ return m_page;								}
int				Page::pageImageCount()	{ return m_pageApis[m_currentApi]->pageImageCount();	}
QList<QSharedPointer<Image>>	Page::images()		{ return m_pageApis[m_currentApi]->images();	}
QUrl			Page::url()			{ return m_pageApis[m_currentApi]->url();		}
QUrl			Page::friendlyUrl()	{ return m_pageApis[m_regexApi < 0 ? m_currentApi : m_regexApi]->url();	}
QString			Page::source()		{ return m_pageApis[m_currentApi]->source();	}
QList<Tag>		Page::tags()		{ return m_pageApis[m_currentApi]->tags();		}
QUrl			Page::nextPage()	{ return m_pageApis[m_currentApi]->nextPage();	}
QUrl			Page::prevPage()	{ return m_pageApis[m_currentApi]->prevPage();	}
int				Page::highLimit()	{ return m_pageApis[m_currentApi]->highLimit(); }

int Page::imagesCount(bool guess)
{
	if (m_regexApi >= 0 && !m_pageApis[m_currentApi]->isImageCountSure())
	{
		int count = m_pageApis[m_regexApi]->imagesCount(false);
		if (count >= 0)
			return count;
	}
	return m_pageApis[m_currentApi]->imagesCount(guess);
}
int Page::pagesCount(bool guess)
{
	if (m_regexApi >= 0 && !m_pageApis[m_currentApi]->isPageCountSure())
	{
		int count = m_pageApis[m_regexApi]->pagesCount(false);
		if (count >= 0)
			return count;
	}
	return m_pageApis[m_currentApi]->pagesCount(guess);
}

int Page::maxId()
{
	return m_pageApis[m_currentApi]->maxId();
}
int Page::minId()
{
	return m_pageApis[m_currentApi]->minId();
}
<commit_msg>Fix tag list not working on non-regex API sources<commit_after>#include "page.h"
#include <math.h>
#include "site.h"
#include "api.h"
#include "vendor/json.h"
#include "logger.h"

Page::Page(Profile *profile, Site *site, QList<Site*> sites, QStringList tags, int page, int limit, QStringList postFiltering, bool smart, QObject *parent, int pool, int lastPage, int lastPageMinId, int lastPageMaxId)
	: QObject(parent), m_site(site), m_regexApi(-1), m_postFiltering(postFiltering), m_errors(QStringList()), m_imagesPerPage(limit), m_currentSource(0), m_lastPage(lastPage), m_lastPageMinId(lastPageMinId), m_lastPageMaxId(lastPageMaxId), m_smart(smart)
{
	m_website = m_site->url();
	m_imagesCount = -1;
	m_pagesCount = -1;

	// Replace shortcuts to increase compatibility
	QString text = " "+tags.join(" ")+" ";
	text.replace(" rating:s ", " rating:safe ", Qt::CaseInsensitive)
		.replace(" rating:q ", " rating:questionable ", Qt::CaseInsensitive)
		.replace(" rating:e ", " rating:explicit ", Qt::CaseInsensitive)
		.replace(" -rating:s ", " -rating:safe ", Qt::CaseInsensitive)
		.replace(" -rating:q ", " -rating:questionable ", Qt::CaseInsensitive)
		.replace(" -rating:e ", " -rating:explicit ", Qt::CaseInsensitive);
	tags = text.split(" ", QString::SkipEmptyParts);

	// Get the list of all enabled modifiers
	QStringList modifiers = QStringList();
	for (Site *site : sites)
	{
		if (site->contains("Modifiers"))
		{ modifiers.append(site->value("Modifiers").trimmed().split(" ", QString::SkipEmptyParts)); }
	}
	if (m_site->contains("Modifiers"))
	{
		QStringList mods = m_site->value("Modifiers").trimmed().split(" ", QString::SkipEmptyParts);
		for (int j = 0; j < mods.size(); j++)
		{ modifiers.removeAll(mods[j]); }
	}

	// Remove modifiers from tags
	for (int k = 0; k < modifiers.size(); k++)
	{ tags.removeAll(modifiers[k]); }
	m_search = tags;

	// Generate pages
	m_siteApis = m_site->getApis(true);
	for (Api *api : m_siteApis)
	{
		m_pageApis.append(new PageApi(this, profile, m_site, api, m_search, page, limit, postFiltering, smart, parent, pool, lastPage, lastPageMinId, lastPageMaxId));
		if (api->getName() == "Html" && m_regexApi < 0)
		{ m_regexApi = m_pageApis.count() - 1; }
	}
	m_currentApi = -1;

	// Set values
	m_page = page;
	m_pool = pool;
	fallback(false);
}
Page::~Page()
{
	qDeleteAll(m_pageApis);
}

void Page::fallback(bool bload)
{
	if (m_currentApi >= m_siteApis.count() - 1)
	{
		log("No valid source of the site returned result.");
		m_errors.append(tr("No valid source of the site returned result."));
		emit failedLoading(this);
		return;
	}

	m_currentApi++;
	if (m_currentApi > 0)
		log(QString("Loading using %1 failed. Retry using %2.").arg(m_siteApis[m_currentApi - 1]->getName()).arg(m_siteApis[m_currentApi]->getName()));

	if (bload)
		load();
}

void Page::setLastPage(Page *page)
{
	m_lastPage = page->page();
	m_lastPageMaxId = page->maxId();
	m_lastPageMinId = page->minId();

	for (PageApi *api : m_pageApis)
		api->setLastPage(page);

	m_currentApi--;
	if (!page->nextPage().isEmpty())
	{ /*m_url = page->nextPage();*/ }
	else
	{ fallback(false); }
}

void Page::load(bool rateLimit)
{
	connect(m_pageApis[m_currentApi], &PageApi::finishedLoading, this, &Page::loadFinished);
	m_pageApis[m_currentApi]->load(rateLimit);
}
void Page::loadFinished(PageApi *api, PageApi::LoadResult status)
{
	if (api != m_pageApis[m_currentApi])
		return;

	if (status == PageApi::LoadResult::Ok)
		emit finishedLoading(this);
	else
		fallback();
}
void Page::abort()
{
	m_pageApis[m_currentApi]->abort();
}

void Page::loadTags()
{
	if (m_regexApi < 0)
		return;

	connect(m_pageApis[m_regexApi], &PageApi::finishedLoadingTags, this, &Page::loadTagsFinished);
	m_pageApis[m_regexApi]->loadTags();
}
void Page::loadTagsFinished(PageApi *api)
{
	if (m_regexApi < 0 || api != m_pageApis[m_regexApi])
		return;

	emit finishedLoadingTags(this);
}
void Page::abortTags()
{
	if (m_regexApi < 0)
		return;

	m_pageApis[m_regexApi]->abortTags();
}

void Page::clear()
{
	for (PageApi *pageApi : m_pageApis)
		pageApi->clear();
}

Site			*Page::site()		{ return m_site;								}
QString			Page::website()		{ return m_website;								}
QString			Page::wiki()		{ return m_wiki;								}
QStringList		Page::search()		{ return m_search;								}
QStringList		Page::errors()		{ return m_errors;								}
int				Page::imagesPerPage()	{ return m_imagesPerPage;					}
int				Page::page()		{ return m_page;								}
int				Page::pageImageCount()	{ return m_pageApis[m_currentApi]->pageImageCount();	}
QList<QSharedPointer<Image>>	Page::images()		{ return m_pageApis[m_currentApi]->images();	}
QUrl			Page::url()			{ return m_pageApis[m_currentApi]->url();		}
QUrl			Page::friendlyUrl()	{ return m_pageApis[m_regexApi < 0 ? m_currentApi : m_regexApi]->url();	}
QString			Page::source()		{ return m_pageApis[m_currentApi]->source();	}
QList<Tag>		Page::tags()		{ return m_pageApis[m_regexApi < 0 ? m_currentApi : m_regexApi]->tags(); }
QUrl			Page::nextPage()	{ return m_pageApis[m_currentApi]->nextPage();	}
QUrl			Page::prevPage()	{ return m_pageApis[m_currentApi]->prevPage();	}
int				Page::highLimit()	{ return m_pageApis[m_currentApi]->highLimit(); }

int Page::imagesCount(bool guess)
{
	if (m_regexApi >= 0 && !m_pageApis[m_currentApi]->isImageCountSure())
	{
		int count = m_pageApis[m_regexApi]->imagesCount(false);
		if (count >= 0)
			return count;
	}
	return m_pageApis[m_currentApi]->imagesCount(guess);
}
int Page::pagesCount(bool guess)
{
	if (m_regexApi >= 0 && !m_pageApis[m_currentApi]->isPageCountSure())
	{
		int count = m_pageApis[m_regexApi]->pagesCount(false);
		if (count >= 0)
			return count;
	}
	return m_pageApis[m_currentApi]->pagesCount(guess);
}

int Page::maxId()
{
	return m_pageApis[m_currentApi]->maxId();
}
int Page::minId()
{
	return m_pageApis[m_currentApi]->minId();
}
<|endoftext|>


<commit_before>#include "compsys/Entity.hpp"
#include "compsys/Component.hpp"
#include <luabind/adopt_policy.hpp>
#include "compsys/ComponentRegistry.hpp"
#include "compsys/MetaComponent.hpp"
#include "LuaUtils.hpp"
#include "container.hpp"

char const libname[] = "EntitySystem";
#include "ExportThis.hpp"
#include <luabind/operator.hpp>
#include <luabind/dependency_policy.hpp>
#include <luabind/iterator_policy.hpp>

static std::vector<luabind::object> getComponents(Entity& this_, lua_State* L)
{
    LUAU_BALANCED_STACK_DBG(L);
    auto const& comps = this_.components();
    std::vector<luabind::object> result;
    for (Component const& c : comps) {
        c.metaComponent().castUp(L, const_cast<Component*>(&c));
        result.push_back(luabind::object(luabind::from_stack(L, -1)));
        lua_pop(L, 1);
    }
    return result;
}

static luabind::object getComponent(Entity& this_, lua_State* L, std::string const& name)
{
    Component* c = this_[ComponentRegistry::metaComponent(name)];
    if (!c)
        return luabind::object();
    c->metaComponent().castUp(L, c);
    return luabind::object(luabind::from_stack(L, -1));
}

static luabind::object requireComponent(Entity& this_, lua_State* L, std::string const& name)
{
    Component* c = this_[ComponentRegistry::metaComponent(name)];
    if (!c) {
        throw std::runtime_error(
            "required component \"" + name + "\" not available!");
    }
    c->metaComponent().castUp(L, c);
    return luabind::object(luabind::from_stack(L, -1));
}

static std::ostream& operator<< (std::ostream& os, Entity const& e)
{
    os << "jd.Entity ( @" << &e << "; ";
    auto const& comps = e.components();
    for (Component const& c : comps)
        os << c.metaComponent().name() << ' ';
    return os << ')';
}

static bool operator==(Entity const& lhs, Entity const* rhs)
    { return &lhs == rhs; }

void init(LuaVm& vm)
{
    LUAU_BALANCED_STACK_DBG(vm.L());

    typedef std::vector<luabind::object> ObjectVec;
    luabind::class_<ObjectVec> cObjectVec("ComponentList");
    exportRandomAccessContainer(cObjectVec);

    vm.initLib("ComponentSystem");
    LHMODULE [

#       define LHCURCLASS Entity
		LHCLASS
            .scope [
                cObjectVec
            ]
            .def(constructor<>())
            .LHMEMFN(finish)
            .LHMEMFN(kill)
            .LHPROPG(state)
            .enum_("state") [
                value("CREATED", Entity::created),
                value("FINISHED", Entity::finished),
                value("KILLED", Entity::killed)
            ]
            .def("components", &getComponents, dependency(_1, result))
            .def("component", &getComponent)
            .def("require", &requireComponent)
            .def(tostring(const_self))
            .def(const_self == other<Entity*>())
#       undef LHCURCLASS // avoid compiler warning
    ];
    lua_getglobal(vm.L(), "jd");
    luabind::object(vm.L(), static_cast<Entity*>(nullptr)).push(vm.L());
    lua_setfield(vm.L(), -2, "NIL_ENTITY");
    lua_pop(vm.L(), 1);
}
<commit_msg>EntitySystem luaexport: Only C++ ComponentRegistry available.<commit_after>#include "compsys/Entity.hpp"
#include "compsys/Component.hpp"
#include <luabind/adopt_policy.hpp>
#include "compsys/ComponentRegistry.hpp"
#include "compsys/MetaComponent.hpp"
#include "LuaUtils.hpp"
#include "container.hpp"

char const libname[] = "EntitySystem";
#include "ExportThis.hpp"
#include <luabind/operator.hpp>
#include <luabind/dependency_policy.hpp>
#include <luabind/iterator_policy.hpp>

static std::vector<luabind::object> getComponents(Entity& this_, lua_State* L)
{
    LUAU_BALANCED_STACK_DBG(L);
    auto const& comps = this_.components();
    std::vector<luabind::object> result;
    for (Component const& c : comps) {
        c.metaComponent().castUp(L, const_cast<Component*>(&c));
        result.push_back(luabind::object(luabind::from_stack(L, -1)));
        lua_pop(L, 1);
    }
    return result;
}

static luabind::object getComponent(Entity& this_, lua_State* L, std::string const& name)
{
    Component* c = this_[ComponentRegistry::metaComponent(name, L)];
    if (!c)
        return luabind::object();
    c->metaComponent().castUp(L, c);
    return luabind::object(luabind::from_stack(L, -1));
}

static luabind::object requireComponent(Entity& this_, lua_State* L, std::string const& name)
{
    Component* c = this_[ComponentRegistry::metaComponent(name, L)];
    if (!c) {
        throw std::runtime_error(
            "required component \"" + name + "\" not available!");
    }
    c->metaComponent().castUp(L, c);
    return luabind::object(luabind::from_stack(L, -1));
}

static std::ostream& operator<< (std::ostream& os, Entity const& e)
{
    os << "jd.Entity ( @" << &e << "; ";
    auto const& comps = e.components();
    for (Component const& c : comps)
        os << c.metaComponent().name() << ' ';
    return os << ')';
}

static bool operator==(Entity const& lhs, Entity const* rhs)
    { return &lhs == rhs; }

void init(LuaVm& vm)
{
    LUAU_BALANCED_STACK_DBG(vm.L());

    typedef std::vector<luabind::object> ObjectVec;
    luabind::class_<ObjectVec> cObjectVec("ComponentList");
    exportRandomAccessContainer(cObjectVec);

    vm.initLib("ComponentSystem");
    LHMODULE [

#       define LHCURCLASS Entity
		LHCLASS
            .scope [
                cObjectVec
            ]
            .def(constructor<>())
            .LHMEMFN(finish)
            .LHMEMFN(kill)
            .LHPROPG(state)
            .enum_("state") [
                value("CREATED", Entity::created),
                value("FINISHED", Entity::finished),
                value("KILLED", Entity::killed)
            ]
            .def("components", &getComponents, dependency(_1, result))
            .def("component", &getComponent)
            .def("require", &requireComponent)
            .def(tostring(const_self))
            .def(const_self == other<Entity*>())
#       undef LHCURCLASS // avoid compiler warning
    ];
    lua_getglobal(vm.L(), "jd");
    luabind::object(vm.L(), static_cast<Entity*>(nullptr)).push(vm.L());
    lua_setfield(vm.L(), -2, "NIL_ENTITY");
    lua_pop(vm.L(), 1);
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <tools/debug.hxx>
#include <vcl/bitmap.hxx>
#include <vcl/bitmapex.hxx>
#include <vcl/window.hxx>
#include <vcl/metaact.hxx>
#include <vcl/gdimtf.hxx>
#include <vcl/virdev.hxx>
#include <vcl/bmpacc.hxx>
#include <vcl/outdev.hxx>
#include <vcl/image.hxx>
#include <bmpfast.hxx>
#include <salbmp.hxx>
#include <salgdi.hxx>
#include <impbmp.hxx>
#include <sallayout.hxx>
#include <image.h>
#include <outdev.h>
#include <window.h>
#include <outdata.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
#include <boost/scoped_array.hpp>

extern const sal_uLong nVCLRLut[ 6 ];
extern const sal_uLong nVCLGLut[ 6 ];
extern const sal_uLong nVCLBLut[ 6 ];
extern const sal_uLong nVCLDitherLut[ 256 ];
extern const sal_uLong nVCLLut[ 256 ];

Color OutputDevice::GetPixel( const Point& rPt ) const
{

    Color aColor;

    if ( mpGraphics || AcquireGraphics() )
    {
        if ( mbInitClipRegion )
            const_cast<OutputDevice*>(this)->ImplInitClipRegion();

        if ( !mbOutputClipped )
        {
            const long      nX = ImplLogicXToDevicePixel( rPt.X() );
            const long      nY = ImplLogicYToDevicePixel( rPt.Y() );
            const SalColor  aSalCol = mpGraphics->GetPixel( nX, nY, this );
            aColor.SetRed( SALCOLOR_RED( aSalCol ) );
            aColor.SetGreen( SALCOLOR_GREEN( aSalCol ) );
            aColor.SetBlue( SALCOLOR_BLUE( aSalCol ) );
        }
    }
    return aColor;
}

void OutputDevice::DrawPixel( const Point& rPt )
{

    if ( mpMetaFile )
        mpMetaFile->AddAction( new MetaPointAction( rPt ) );

    if ( !IsDeviceOutputNecessary() || !mbLineColor || ImplIsRecordLayout() )
        return;

    Point aPt = ImplLogicToDevicePixel( rPt );

    if ( !mpGraphics )
    {
        if ( !AcquireGraphics() )
            return;
    }

    if ( mbInitClipRegion )
        ImplInitClipRegion();
    if ( mbOutputClipped )
        return;

    if ( mbInitLineColor )
        InitLineColor();

    mpGraphics->DrawPixel( aPt.X(), aPt.Y(), this );

    if( mpAlphaVDev )
        mpAlphaVDev->DrawPixel( rPt );
}

void OutputDevice::DrawPixel( const Point& rPt, const Color& rColor )
{

    Color aColor = ImplDrawModeToColor( rColor );

    if ( mpMetaFile )
        mpMetaFile->AddAction( new MetaPixelAction( rPt, aColor ) );

    if ( !IsDeviceOutputNecessary() || ImplIsColorTransparent( aColor ) || ImplIsRecordLayout() )
        return;

    Point aPt = ImplLogicToDevicePixel( rPt );

    if ( !mpGraphics )
    {
        if ( !AcquireGraphics() )
            return;
    }

    if ( mbInitClipRegion )
        ImplInitClipRegion();
    if ( mbOutputClipped )
        return;

    mpGraphics->DrawPixel( aPt.X(), aPt.Y(), ImplColorToSal( aColor ), this );

    if( mpAlphaVDev )
        mpAlphaVDev->DrawPixel( rPt );
}

void OutputDevice::DrawPixel( const Polygon& rPts, const Color* pColors )
{
    if ( !pColors )
        DrawPixel( rPts, GetLineColor() );
    else
    {
        DBG_ASSERT( pColors, "OutputDevice::DrawPixel: No color array specified" );

        const sal_uInt16 nSize = rPts.GetSize();

        if ( nSize )
        {
            if ( mpMetaFile )
                for ( sal_uInt16 i = 0; i < nSize; i++ )
                    mpMetaFile->AddAction( new MetaPixelAction( rPts[ i ], pColors[ i ] ) );

            if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
                return;

            if ( mpGraphics || AcquireGraphics() )
            {
                if ( mbInitClipRegion )
                    ImplInitClipRegion();

                if ( mbOutputClipped )
                    return;

                for ( sal_uInt16 i = 0; i < nSize; i++ )
                {
                    const Point aPt( ImplLogicToDevicePixel( rPts[ i ] ) );
                    mpGraphics->DrawPixel( aPt.X(), aPt.Y(), ImplColorToSal( pColors[ i ] ), this );
                }
            }
        }
    }

    if( mpAlphaVDev )
        mpAlphaVDev->DrawPixel( rPts, pColors );
}

void OutputDevice::DrawPixel( const Polygon& rPts, const Color& rColor )
{
    if( rColor != COL_TRANSPARENT && ! ImplIsRecordLayout() )
    {
        const sal_uInt16    nSize = rPts.GetSize();
        boost::scoped_array<Color> pColArray(new Color[ nSize ]);

        for( sal_uInt16 i = 0; i < nSize; i++ )
            pColArray[ i ] = rColor;

        DrawPixel( rPts, pColArray.get() );
    }

    if( mpAlphaVDev )
        mpAlphaVDev->DrawPixel( rPts, rColor );
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>VCL: Remove unnecessary headers from outdev/pixel.cxx<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <vcl/outdev.hxx>
#include <vcl/virdev.hxx>
#include <vcl/window.hxx>

#include <salgdi.hxx>

#include <outdata.hxx>

#include <boost/scoped_array.hpp>

extern const sal_uLong nVCLRLut[ 6 ];
extern const sal_uLong nVCLGLut[ 6 ];
extern const sal_uLong nVCLBLut[ 6 ];
extern const sal_uLong nVCLDitherLut[ 256 ];
extern const sal_uLong nVCLLut[ 256 ];

Color OutputDevice::GetPixel( const Point& rPt ) const
{

    Color aColor;

    if ( mpGraphics || AcquireGraphics() )
    {
        if ( mbInitClipRegion )
            const_cast<OutputDevice*>(this)->ImplInitClipRegion();

        if ( !mbOutputClipped )
        {
            const long      nX = ImplLogicXToDevicePixel( rPt.X() );
            const long      nY = ImplLogicYToDevicePixel( rPt.Y() );
            const SalColor  aSalCol = mpGraphics->GetPixel( nX, nY, this );
            aColor.SetRed( SALCOLOR_RED( aSalCol ) );
            aColor.SetGreen( SALCOLOR_GREEN( aSalCol ) );
            aColor.SetBlue( SALCOLOR_BLUE( aSalCol ) );
        }
    }
    return aColor;
}

void OutputDevice::DrawPixel( const Point& rPt )
{

    if ( mpMetaFile )
        mpMetaFile->AddAction( new MetaPointAction( rPt ) );

    if ( !IsDeviceOutputNecessary() || !mbLineColor || ImplIsRecordLayout() )
        return;

    Point aPt = ImplLogicToDevicePixel( rPt );

    if ( !mpGraphics )
    {
        if ( !AcquireGraphics() )
            return;
    }

    if ( mbInitClipRegion )
        ImplInitClipRegion();
    if ( mbOutputClipped )
        return;

    if ( mbInitLineColor )
        InitLineColor();

    mpGraphics->DrawPixel( aPt.X(), aPt.Y(), this );

    if( mpAlphaVDev )
        mpAlphaVDev->DrawPixel( rPt );
}

void OutputDevice::DrawPixel( const Point& rPt, const Color& rColor )
{

    Color aColor = ImplDrawModeToColor( rColor );

    if ( mpMetaFile )
        mpMetaFile->AddAction( new MetaPixelAction( rPt, aColor ) );

    if ( !IsDeviceOutputNecessary() || ImplIsColorTransparent( aColor ) || ImplIsRecordLayout() )
        return;

    Point aPt = ImplLogicToDevicePixel( rPt );

    if ( !mpGraphics )
    {
        if ( !AcquireGraphics() )
            return;
    }

    if ( mbInitClipRegion )
        ImplInitClipRegion();
    if ( mbOutputClipped )
        return;

    mpGraphics->DrawPixel( aPt.X(), aPt.Y(), ImplColorToSal( aColor ), this );

    if( mpAlphaVDev )
        mpAlphaVDev->DrawPixel( rPt );
}

void OutputDevice::DrawPixel( const Polygon& rPts, const Color* pColors )
{
    if ( !pColors )
        DrawPixel( rPts, GetLineColor() );
    else
    {
        DBG_ASSERT( pColors, "OutputDevice::DrawPixel: No color array specified" );

        const sal_uInt16 nSize = rPts.GetSize();

        if ( nSize )
        {
            if ( mpMetaFile )
                for ( sal_uInt16 i = 0; i < nSize; i++ )
                    mpMetaFile->AddAction( new MetaPixelAction( rPts[ i ], pColors[ i ] ) );

            if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
                return;

            if ( mpGraphics || AcquireGraphics() )
            {
                if ( mbInitClipRegion )
                    ImplInitClipRegion();

                if ( mbOutputClipped )
                    return;

                for ( sal_uInt16 i = 0; i < nSize; i++ )
                {
                    const Point aPt( ImplLogicToDevicePixel( rPts[ i ] ) );
                    mpGraphics->DrawPixel( aPt.X(), aPt.Y(), ImplColorToSal( pColors[ i ] ), this );
                }
            }
        }
    }

    if( mpAlphaVDev )
        mpAlphaVDev->DrawPixel( rPts, pColors );
}

void OutputDevice::DrawPixel( const Polygon& rPts, const Color& rColor )
{
    if( rColor != COL_TRANSPARENT && ! ImplIsRecordLayout() )
    {
        const sal_uInt16    nSize = rPts.GetSize();
        boost::scoped_array<Color> pColArray(new Color[ nSize ]);

        for( sal_uInt16 i = 0; i < nSize; i++ )
            pColArray[ i ] = rColor;

        DrawPixel( rPts, pColArray.get() );
    }

    if( mpAlphaVDev )
        mpAlphaVDev->DrawPixel( rPts, rColor );
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: gtkinst.cxx,v $
 *
 *  $Revision: 1.17 $
 *
 *  last change: $Author: vg $ $Date: 2007-08-30 13:55:37 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"

#include <osl/module.h>
#include <plugins/gtk/gtkdata.hxx>
#include <plugins/gtk/gtkinst.hxx>
#include <salframe.h>
#include <salobj.h>
#include <plugins/gtk/gtkframe.hxx>
#include <plugins/gtk/gtkobject.hxx>
#include <plugins/gtk/atkbridge.hxx>

#include <rtl/strbuf.hxx>

#if OSL_DEBUG_LEVEL > 1
#include <stdio.h>
#endif

#include <dlfcn.h>
#include <fcntl.h>
#include <unistd.h>

GtkHookedYieldMutex::GtkHookedYieldMutex()
{
}

/*
 * These methods always occur in pairs
 * A ThreadsEnter is followed by a ThreadsLeave
 * We need to queue up the recursive lock count
 * for each pair, so we can accurately restore
 * it later.
 */
void GtkHookedYieldMutex::ThreadsEnter()
{
    acquire();
    if( !aYieldStack.empty() )
    { /* Previously called ThreadsLeave() */
        ULONG nCount = aYieldStack.front();
        aYieldStack.pop_front();
        while( nCount-- > 1 )
            acquire();
    }
}

void GtkHookedYieldMutex::ThreadsLeave()
{
    aYieldStack.push_front( mnCount );

#if OSL_DEBUG_LEVEL > 1
    if( mnThreadId &&
        mnThreadId != NAMESPACE_VOS(OThread)::getCurrentIdentifier())
        fprintf( stderr, "\n\n--- A different thread owns the mutex ...---\n\n\n");
#endif

    while( mnCount > 1 )
        release();
    release();
}

void GtkHookedYieldMutex::acquire()
{
    SalYieldMutex::acquire();
}

void GtkHookedYieldMutex::release()
{
    SalYieldMutex::release();
}

extern "C"
{
    #define GET_YIELD_MUTEX() static_cast<GtkHookedYieldMutex*>(GetSalData()->m_pInstance->GetYieldMutex())
    static void GdkThreadsEnter( void )
    {
        GtkHookedYieldMutex *pYieldMutex = GET_YIELD_MUTEX();
        pYieldMutex->ThreadsEnter();
    }
    static void GdkThreadsLeave( void )
    {
        GtkHookedYieldMutex *pYieldMutex = GET_YIELD_MUTEX();
        pYieldMutex->ThreadsLeave();
    }
    static bool hookLocks( oslModule pModule )
    {
        typedef void (*GdkLockFn) (GCallback enter_fn, GCallback leave_fn);
        rtl::OUString aSymbolName( RTL_CONSTASCII_USTRINGPARAM( "gdk_threads_set_lock_functions") );

        GdkLockFn gdk_threads_set_lock_functions =
                (GdkLockFn) osl_getFunctionSymbol( pModule, aSymbolName.pData );
        if ( !gdk_threads_set_lock_functions )
        {
#if OSL_DEBUG_LEVEL > 1
            fprintf( stderr, "Failed to hook gdk threads locks\n" );
#endif
            return false;
        }

        gdk_threads_set_lock_functions (GdkThreadsEnter, GdkThreadsLeave);
#if OSL_DEBUG_LEVEL > 1
        fprintf( stderr, "Hooked gdk threads locks\n" );
#endif
        return true;
    }

    VCL_DLLPUBLIC SalInstance* create_SalInstance( oslModule pModule )
    {
        #if OSL_DEBUG_LEVEL > 1
        int nFd = open( "/home/pl93762/log.txt", O_CREAT | O_TRUNC | O_WRONLY, 0755 );
        dup2( nFd, STDERR_FILENO );
        #endif

        const gchar* pVersion = gtk_check_version( 2, 2, 0 );
        if( pVersion )
        {
#if OSL_DEBUG_LEVEL > 1
            fprintf( stderr, "gtk version conflict: %s\n", pVersion );
#endif
            return NULL;
        }

        GtkYieldMutex *pYieldMutex;

        // init gdk thread protection
        if ( !g_thread_supported() )
            g_thread_init( NULL );

        if ( hookLocks( pModule ) )
            pYieldMutex = new GtkHookedYieldMutex();
        else
            pYieldMutex = new GtkYieldMutex();

        gdk_threads_init();

        GtkInstance* pInstance = new GtkInstance( pYieldMutex );
#if OSL_DEBUG_LEVEL > 1
        fprintf( stderr, "creating GtkSalInstance 0x%p\n", pInstance );
#endif

        // initialize SalData
        GtkData *pSalData = new GtkData();
        SetSalData( pSalData );
        pSalData->m_pInstance = pInstance;
        pSalData->Init();
        pSalData->initNWF();

        const char* pGtkModules = getenv( "GTK_MODULES" );
        if( pGtkModules )
        {
            rtl::OString aModules( pGtkModules );
            sal_Int32 nIndex = 0;
            while( nIndex >= 0 )
            {
                rtl::OString aToken = aModules.getToken( 0, ':', nIndex );
                if( aToken.equals( "gail" ) || aToken.equals( "atk-bridge" ) )
                {
                    InitAtkBridge();
                    break;
                }
            }
        }

        return pInstance;
    }
}

GtkInstance::~GtkInstance()
{
    DeInitAtkBridge();
}

SalFrame* GtkInstance::CreateFrame( SalFrame* pParent, ULONG nStyle )
{
    return new GtkSalFrame( pParent, nStyle );
}

SalFrame* GtkInstance::CreateChildFrame( SystemParentData* pParentData, ULONG )
{
    SalFrame* pFrame = new GtkSalFrame( pParentData );

    return pFrame;
}

SalObject* GtkInstance::CreateObject( SalFrame* pParent, SystemWindowData* pWindowData )
{
    // there is no method to set a visual for a GtkWidget
    // so we need the X11SalObject in that case
    if( pWindowData )
        return X11SalObject::CreateObject( pParent, pWindowData );

    return new GtkSalObject( static_cast<GtkSalFrame*>(pParent) );
}

GtkYieldMutex::GtkYieldMutex()
{
}

void GtkYieldMutex::acquire()
{
    vos::OThread::TThreadIdentifier aCurrentThread = vos::OThread::getCurrentIdentifier();
    // protect member manipulation
    OMutex::acquire();
    if( mnCount > 0 && mnThreadId == aCurrentThread )
    {
        mnCount++;
        OMutex::release();
        return;
    }
    OMutex::release();

    // obtain gdk mutex
    gdk_threads_enter();

    // obtained gdk mutex, now lock count is one by definition
    OMutex::acquire();
    mnCount = 1;
    mnThreadId = aCurrentThread;
    OMutex::release();
}

void GtkYieldMutex::release()
{
    vos::OThread::TThreadIdentifier aCurrentThread = vos::OThread::getCurrentIdentifier();
    // protect member manipulation
    OMutex::acquire();
    // strange things happen, do nothing if we don't own the mutex
    if( mnThreadId == aCurrentThread )
    {
        mnCount--;
        if( mnCount == 0 )
        {
            gdk_threads_leave();
            mnThreadId = 0;
        }
    }
    OMutex::release();
}

sal_Bool GtkYieldMutex::tryToAcquire()
{
    vos::OThread::TThreadIdentifier aCurrentThread = vos::OThread::getCurrentIdentifier();
    // protect member manipulation
    OMutex::acquire();
    if( mnCount > 0 )
    {
        if( mnThreadId == aCurrentThread )
        {
            mnCount++;
            OMutex::release();
            return sal_True;
        }
        else
        {
            OMutex::release();
            return sal_False;
        }
    }
    OMutex::release();

    // HACK: gdk_threads_mutex is private, we shouldn't use it.
    // how to we do a try_lock without having a gdk_threads_try_enter ?
    if( ! g_mutex_trylock( gdk_threads_mutex ) )
        return sal_False;

    // obtained gdk mutex, now lock count is one by definition
    OMutex::acquire();
    mnCount = 1;
    mnThreadId = aCurrentThread;
    OMutex::release();

    return sal_True;
}

int GtkYieldMutex::Grab()
{
    // this MUST only be called by gdk/gtk callbacks:
    // they are entered with gdk mutex locked; the mutex
    // was unlocked by GtkYieldMutex befor yielding which
    // is now locked again by gtk implicitly

    // obtained gdk mutex, now lock count is one by definition
    OMutex::acquire();
    int nRet = mnCount;
    if( mnCount == 0 ) // recursive else
        mnThreadId = vos::OThread::getCurrentIdentifier();
#if OSL_DEBUG_LEVEL > 1
    else if( mnThreadId != vos::OThread::getCurrentIdentifier() )
    {
        fprintf( stderr, "Yield mutex grabbed in different thread !\n" );
        abort();
    }
#endif
    mnCount = 1;
    OMutex::release();
    return nRet;
}

void GtkYieldMutex::Ungrab( int nGrabs )
{
    // this MUST only be called when leaving the callback
    // that locked the mutex with Grab()
    OMutex::acquire();
    mnCount = nGrabs;
    if( mnCount == 0 )
        mnThreadId = 0;
    OMutex::release();
}
<commit_msg>INTEGRATION: CWS transogl02 (1.17.104); FILE MERGED 2007/12/10 19:00:18 radekdoulik 1.17.104.1: add BOOL bShow parameter to SystemChildWindow constructor to allow creating of unmapped window with possibility to show it (map it) later to avoid flicker<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: gtkinst.cxx,v $
 *
 *  $Revision: 1.18 $
 *
 *  last change: $Author: vg $ $Date: 2008-01-29 08:37:57 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"

#include <osl/module.h>
#include <plugins/gtk/gtkdata.hxx>
#include <plugins/gtk/gtkinst.hxx>
#include <salframe.h>
#include <salobj.h>
#include <plugins/gtk/gtkframe.hxx>
#include <plugins/gtk/gtkobject.hxx>
#include <plugins/gtk/atkbridge.hxx>

#include <rtl/strbuf.hxx>

#if OSL_DEBUG_LEVEL > 1
#include <stdio.h>
#endif

#include <dlfcn.h>
#include <fcntl.h>
#include <unistd.h>

GtkHookedYieldMutex::GtkHookedYieldMutex()
{
}

/*
 * These methods always occur in pairs
 * A ThreadsEnter is followed by a ThreadsLeave
 * We need to queue up the recursive lock count
 * for each pair, so we can accurately restore
 * it later.
 */
void GtkHookedYieldMutex::ThreadsEnter()
{
    acquire();
    if( !aYieldStack.empty() )
    { /* Previously called ThreadsLeave() */
        ULONG nCount = aYieldStack.front();
        aYieldStack.pop_front();
        while( nCount-- > 1 )
            acquire();
    }
}

void GtkHookedYieldMutex::ThreadsLeave()
{
    aYieldStack.push_front( mnCount );

#if OSL_DEBUG_LEVEL > 1
    if( mnThreadId &&
        mnThreadId != NAMESPACE_VOS(OThread)::getCurrentIdentifier())
        fprintf( stderr, "\n\n--- A different thread owns the mutex ...---\n\n\n");
#endif

    while( mnCount > 1 )
        release();
    release();
}

void GtkHookedYieldMutex::acquire()
{
    SalYieldMutex::acquire();
}

void GtkHookedYieldMutex::release()
{
    SalYieldMutex::release();
}

extern "C"
{
    #define GET_YIELD_MUTEX() static_cast<GtkHookedYieldMutex*>(GetSalData()->m_pInstance->GetYieldMutex())
    static void GdkThreadsEnter( void )
    {
        GtkHookedYieldMutex *pYieldMutex = GET_YIELD_MUTEX();
        pYieldMutex->ThreadsEnter();
    }
    static void GdkThreadsLeave( void )
    {
        GtkHookedYieldMutex *pYieldMutex = GET_YIELD_MUTEX();
        pYieldMutex->ThreadsLeave();
    }
    static bool hookLocks( oslModule pModule )
    {
        typedef void (*GdkLockFn) (GCallback enter_fn, GCallback leave_fn);
        rtl::OUString aSymbolName( RTL_CONSTASCII_USTRINGPARAM( "gdk_threads_set_lock_functions") );

        GdkLockFn gdk_threads_set_lock_functions =
                (GdkLockFn) osl_getFunctionSymbol( pModule, aSymbolName.pData );
        if ( !gdk_threads_set_lock_functions )
        {
#if OSL_DEBUG_LEVEL > 1
            fprintf( stderr, "Failed to hook gdk threads locks\n" );
#endif
            return false;
        }

        gdk_threads_set_lock_functions (GdkThreadsEnter, GdkThreadsLeave);
#if OSL_DEBUG_LEVEL > 1
        fprintf( stderr, "Hooked gdk threads locks\n" );
#endif
        return true;
    }

    VCL_DLLPUBLIC SalInstance* create_SalInstance( oslModule pModule )
    {
        #if OSL_DEBUG_LEVEL > 1
        int nFd = open( "/home/pl93762/log.txt", O_CREAT | O_TRUNC | O_WRONLY, 0755 );
        dup2( nFd, STDERR_FILENO );
        #endif

        const gchar* pVersion = gtk_check_version( 2, 2, 0 );
        if( pVersion )
        {
#if OSL_DEBUG_LEVEL > 1
            fprintf( stderr, "gtk version conflict: %s\n", pVersion );
#endif
            return NULL;
        }

        GtkYieldMutex *pYieldMutex;

        // init gdk thread protection
        if ( !g_thread_supported() )
            g_thread_init( NULL );

        if ( hookLocks( pModule ) )
            pYieldMutex = new GtkHookedYieldMutex();
        else
            pYieldMutex = new GtkYieldMutex();

        gdk_threads_init();

        GtkInstance* pInstance = new GtkInstance( pYieldMutex );
#if OSL_DEBUG_LEVEL > 1
        fprintf( stderr, "creating GtkSalInstance 0x%p\n", pInstance );
#endif

        // initialize SalData
        GtkData *pSalData = new GtkData();
        SetSalData( pSalData );
        pSalData->m_pInstance = pInstance;
        pSalData->Init();
        pSalData->initNWF();

        const char* pGtkModules = getenv( "GTK_MODULES" );
        if( pGtkModules )
        {
            rtl::OString aModules( pGtkModules );
            sal_Int32 nIndex = 0;
            while( nIndex >= 0 )
            {
                rtl::OString aToken = aModules.getToken( 0, ':', nIndex );
                if( aToken.equals( "gail" ) || aToken.equals( "atk-bridge" ) )
                {
                    InitAtkBridge();
                    break;
                }
            }
        }

        return pInstance;
    }
}

GtkInstance::~GtkInstance()
{
    DeInitAtkBridge();
}

SalFrame* GtkInstance::CreateFrame( SalFrame* pParent, ULONG nStyle )
{
    return new GtkSalFrame( pParent, nStyle );
}

SalFrame* GtkInstance::CreateChildFrame( SystemParentData* pParentData, ULONG )
{
    SalFrame* pFrame = new GtkSalFrame( pParentData );

    return pFrame;
}

SalObject* GtkInstance::CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, BOOL bShow )
{
    // there is no method to set a visual for a GtkWidget
    // so we need the X11SalObject in that case
    if( pWindowData )
        return X11SalObject::CreateObject( pParent, pWindowData, bShow );

    return new GtkSalObject( static_cast<GtkSalFrame*>(pParent), bShow );
}

GtkYieldMutex::GtkYieldMutex()
{
}

void GtkYieldMutex::acquire()
{
    vos::OThread::TThreadIdentifier aCurrentThread = vos::OThread::getCurrentIdentifier();
    // protect member manipulation
    OMutex::acquire();
    if( mnCount > 0 && mnThreadId == aCurrentThread )
    {
        mnCount++;
        OMutex::release();
        return;
    }
    OMutex::release();

    // obtain gdk mutex
    gdk_threads_enter();

    // obtained gdk mutex, now lock count is one by definition
    OMutex::acquire();
    mnCount = 1;
    mnThreadId = aCurrentThread;
    OMutex::release();
}

void GtkYieldMutex::release()
{
    vos::OThread::TThreadIdentifier aCurrentThread = vos::OThread::getCurrentIdentifier();
    // protect member manipulation
    OMutex::acquire();
    // strange things happen, do nothing if we don't own the mutex
    if( mnThreadId == aCurrentThread )
    {
        mnCount--;
        if( mnCount == 0 )
        {
            gdk_threads_leave();
            mnThreadId = 0;
        }
    }
    OMutex::release();
}

sal_Bool GtkYieldMutex::tryToAcquire()
{
    vos::OThread::TThreadIdentifier aCurrentThread = vos::OThread::getCurrentIdentifier();
    // protect member manipulation
    OMutex::acquire();
    if( mnCount > 0 )
    {
        if( mnThreadId == aCurrentThread )
        {
            mnCount++;
            OMutex::release();
            return sal_True;
        }
        else
        {
            OMutex::release();
            return sal_False;
        }
    }
    OMutex::release();

    // HACK: gdk_threads_mutex is private, we shouldn't use it.
    // how to we do a try_lock without having a gdk_threads_try_enter ?
    if( ! g_mutex_trylock( gdk_threads_mutex ) )
        return sal_False;

    // obtained gdk mutex, now lock count is one by definition
    OMutex::acquire();
    mnCount = 1;
    mnThreadId = aCurrentThread;
    OMutex::release();

    return sal_True;
}

int GtkYieldMutex::Grab()
{
    // this MUST only be called by gdk/gtk callbacks:
    // they are entered with gdk mutex locked; the mutex
    // was unlocked by GtkYieldMutex befor yielding which
    // is now locked again by gtk implicitly

    // obtained gdk mutex, now lock count is one by definition
    OMutex::acquire();
    int nRet = mnCount;
    if( mnCount == 0 ) // recursive else
        mnThreadId = vos::OThread::getCurrentIdentifier();
#if OSL_DEBUG_LEVEL > 1
    else if( mnThreadId != vos::OThread::getCurrentIdentifier() )
    {
        fprintf( stderr, "Yield mutex grabbed in different thread !\n" );
        abort();
    }
#endif
    mnCount = 1;
    OMutex::release();
    return nRet;
}

void GtkYieldMutex::Ungrab( int nGrabs )
{
    // this MUST only be called when leaving the callback
    // that locked the mutex with Grab()
    OMutex::acquire();
    mnCount = nGrabs;
    if( mnCount == 0 )
        mnThreadId = 0;
    OMutex::release();
}
<|endoftext|>


<commit_before>#include "rpcconsole.h"
#include "ui_rpcconsole.h"

#include "clientmodel.h"
#include "bitcoinrpc.h"
#include "guiutil.h"

#include <QTime>
#include <QTimer>
#include <QThread>
#include <QTextEdit>
#include <QKeyEvent>

#include <boost/tokenizer.hpp>

// TODO: make it possible to filter out categories (esp debug messages when implemented)
// TODO: receive errors and debug messages through ClientModel

const int CONSOLE_SCROLLBACK = 50;
const int CONSOLE_HISTORY = 50;

/* Object for executing console RPC commands in a separate thread.
*/
class RPCExecutor: public QObject
{
    Q_OBJECT
public slots:
    void start();
    void request(const QString &command);
signals:
    void reply(int category, const QString &command);
};

#include "rpcconsole.moc"

void RPCExecutor::start()
{
   // Nothing to do
}

void RPCExecutor::request(const QString &command)
{
    // Parse shell-like command line into separate arguments
    boost::escaped_list_separator<char> els('\\',' ','\"');
    std::string strCommand = command.toStdString();
    boost::tokenizer<boost::escaped_list_separator<char> > tok(strCommand, els);

    std::string strMethod;
    std::vector<std::string> strParams;
    int n = 0;
    for(boost::tokenizer<boost::escaped_list_separator<char> >::iterator beg=tok.begin(); beg!=tok.end();++beg,++n)
    {
        if(n == 0) // First parameter is the command
            strMethod = *beg;
        else
            strParams.push_back(*beg);
    }

    try {
        std::string strPrint;
        json_spirit::Value result = tableRPC.execute(strMethod, RPCConvertValues(strMethod, strParams));

        // Format result reply
        if (result.type() == json_spirit::null_type)
            strPrint = "";
        else if (result.type() == json_spirit::str_type)
            strPrint = result.get_str();
        else
            strPrint = write_string(result, true);

        emit reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint));
    }
    catch (json_spirit::Object& objError)
    {
        emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(write_string(json_spirit::Value(objError), false)));
    }
    catch (std::exception& e)
    {
        emit reply(RPCConsole::CMD_ERROR, QString("Error: ") + QString::fromStdString(e.what()));
    }
}

RPCConsole::RPCConsole(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::RPCConsole),
    firstLayout(true),
    historyPtr(0)
{
    ui->setupUi(this);
    ui->messagesWidget->horizontalHeader()->setResizeMode(1, QHeaderView::Stretch);
    ui->messagesWidget->setContextMenuPolicy(Qt::ActionsContextMenu);

#ifndef WIN32
    // Show Debug logfile label and Open button only for Windows
    ui->labelDebugLogfile->setVisible(false);
    ui->openDebugLogfileButton->setVisible(false);
#endif

    // Install event filter for up and down arrow
    ui->lineEdit->installEventFilter(this);

    // Add "Copy message" to context menu explicitly
    QAction *copyMessageAction = new QAction(tr("&Copy"), this);
    copyMessageAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_C));
    copyMessageAction->setShortcutContext(Qt::WidgetShortcut);
    connect(copyMessageAction, SIGNAL(triggered()), this, SLOT(copyMessage()));
    ui->messagesWidget->addAction(copyMessageAction);

    connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));
    connect(ui->openDebugLogfileButton, SIGNAL(clicked()), this, SLOT(on_openDebugLogfileButton_clicked()));

    startExecutor();

    clear();
}

RPCConsole::~RPCConsole()
{
    emit stopExecutor();
    delete ui;
}

bool RPCConsole::eventFilter(QObject* obj, QEvent *event)
{
    if(obj == ui->lineEdit)
    {
        if(event->type() == QEvent::KeyPress)
        {
            QKeyEvent *key = static_cast<QKeyEvent*>(event);
            switch(key->key())
            {
            case Qt::Key_Up: browseHistory(-1); return true;
            case Qt::Key_Down: browseHistory(1); return true;
            }
        }
    }
    return QDialog::eventFilter(obj, event);
}

void RPCConsole::setClientModel(ClientModel *model)
{
    this->clientModel = model;
    if(model)
    {
        // Subscribe to information, replies, messages, errors
        connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
        connect(model, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int)));

        // Provide initial values
        ui->clientVersion->setText(model->formatFullVersion());
        ui->clientName->setText(model->clientName());
        ui->buildDate->setText(model->formatBuildDate());

        setNumConnections(model->getNumConnections());
        ui->isTestNet->setChecked(model->isTestNet());

        setNumBlocks(model->getNumBlocks());
    }
}

static QColor categoryColor(int category)
{
    switch(category)
    {
    case RPCConsole::MC_ERROR:     return QColor(255,0,0); break;
    case RPCConsole::MC_DEBUG:     return QColor(192,192,192); break;
    case RPCConsole::CMD_REQUEST:  return QColor(128,128,128); break;
    case RPCConsole::CMD_REPLY:    return QColor(128,255,128); break;
    case RPCConsole::CMD_ERROR:    return QColor(255,128,128); break;
    default:           return QColor(0,0,0);
    }
}

void RPCConsole::clear()
{
    ui->messagesWidget->clear();
    ui->messagesWidget->setRowCount(0);
    ui->lineEdit->clear();
    ui->lineEdit->setFocus();

    message(CMD_REPLY, tr("Welcome to the bitcoin RPC console.")+"\n"+
                       tr("Use up and down arrows to navigate history, and Ctrl-L to clear screen.")+"\n"+
                       tr("Type \"help\" for an overview of available commands."));
}

void RPCConsole::message(int category, const QString &message)
{
    // Add row to messages widget
    int row = ui->messagesWidget->rowCount();
    ui->messagesWidget->setRowCount(row+1);

    QTime time = QTime::currentTime();
    QTableWidgetItem *newTime = new QTableWidgetItem(time.toString());
    newTime->setData(Qt::DecorationRole, categoryColor(category));
    newTime->setForeground(QColor(128,128,128));
    newTime->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); // make non-editable

    int numLines = message.count("\n") + 1;
    // As Qt doesn't like very tall cells (they break scrolling) keep only short messages in
    // the cell text, longer messages trigger a display widget with scroll bar
    if(numLines < 5)
    {
        QTableWidgetItem *newItem = new QTableWidgetItem(message);
        newItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); // make non-editable
        if(category == CMD_ERROR) // Coloring error messages in red
            newItem->setForeground(QColor(255,16,16));
        ui->messagesWidget->setItem(row, 1, newItem);
    } else {
        QTextEdit *newWidget = new QTextEdit;
        newWidget->setText(message);
        newWidget->setMaximumHeight(100);
        newWidget->setReadOnly(true);
        ui->messagesWidget->setCellWidget(row, 1, newWidget);
    }

    ui->messagesWidget->setItem(row, 0, newTime);
    ui->messagesWidget->resizeRowToContents(row);
    // Preserve only limited scrollback buffer
    while(ui->messagesWidget->rowCount() > CONSOLE_SCROLLBACK)
        ui->messagesWidget->removeRow(0);
    // Scroll to bottom after table is updated
    QTimer::singleShot(0, ui->messagesWidget, SLOT(scrollToBottom()));
}

void RPCConsole::setNumConnections(int count)
{
    ui->numberOfConnections->setText(QString::number(count));
}

void RPCConsole::setNumBlocks(int count)
{
    ui->numberOfBlocks->setText(QString::number(count));
    if(clientModel)
    {
        ui->totalBlocks->setText(QString::number(clientModel->getNumBlocksOfPeers()));
        ui->lastBlockTime->setText(clientModel->getLastBlockDate().toString());
    }
}

void RPCConsole::on_lineEdit_returnPressed()
{
    QString cmd = ui->lineEdit->text();
    ui->lineEdit->clear();

    if(!cmd.isEmpty())
    {
        message(CMD_REQUEST, cmd);
        emit cmdRequest(cmd);
        // Truncate history from current position
        history.erase(history.begin() + historyPtr, history.end());
        // Append command to history
        history.append(cmd);
        // Enforce maximum history size
        while(history.size() > CONSOLE_HISTORY)
            history.removeFirst();
        // Set pointer to end of history
        historyPtr = history.size();
    }
}

void RPCConsole::browseHistory(int offset)
{
    historyPtr += offset;
    if(historyPtr < 0)
        historyPtr = 0;
    if(historyPtr > history.size())
        historyPtr = history.size();
    QString cmd;
    if(historyPtr < history.size())
        cmd = history.at(historyPtr);
    ui->lineEdit->setText(cmd);
}

void RPCConsole::startExecutor()
{
    QThread* thread = new QThread;
    RPCExecutor *executor = new RPCExecutor();
    executor->moveToThread(thread);

    // Notify executor when thread started (in executor thread)
    connect(thread, SIGNAL(started()), executor, SLOT(start()));
    // Replies from executor object must go to this object
    connect(executor, SIGNAL(reply(int,QString)), this, SLOT(message(int,QString)));
    // Requests from this object must go to executor
    connect(this, SIGNAL(cmdRequest(QString)), executor, SLOT(request(QString)));
    // On stopExecutor signal
    // - queue executor for deletion (in execution thread)
    // - quit the Qt event loop in the execution thread
    connect(this, SIGNAL(stopExecutor()), executor, SLOT(deleteLater()));
    connect(this, SIGNAL(stopExecutor()), thread, SLOT(quit()));
    // Queue the thread for deletion (in this thread) when it is finished
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

    // Default implementation of QThread::run() simply spins up an event loop in the thread,
    // which is what we want.
    thread->start();
}

void RPCConsole::copyMessage()
{
    GUIUtil::copyEntryData(ui->messagesWidget, 1, Qt::EditRole);
}

void RPCConsole::on_tabWidget_currentChanged(int index)
{
    if(ui->tabWidget->widget(index) == ui->tab_console)
    {
        if(firstLayout)
        {
            // Work around QTableWidget issue:
            // Call resizeRowsToContents on first Layout request with widget visible,
            // to make sure multiline messages that were added before the console was shown
            // have the right height.
            firstLayout = false;
            ui->messagesWidget->resizeRowsToContents();
        }
        ui->lineEdit->setFocus();
    }
}

void RPCConsole::on_openDebugLogfileButton_clicked()
{
    GUIUtil::openDebugLogfile();
}
<commit_msg>if there is no current block number available display N/A on totalBlocks label, instead of 0, which can not ever be true<commit_after>#include "rpcconsole.h"
#include "ui_rpcconsole.h"

#include "clientmodel.h"
#include "bitcoinrpc.h"
#include "guiutil.h"

#include <QTime>
#include <QTimer>
#include <QThread>
#include <QTextEdit>
#include <QKeyEvent>

#include <boost/tokenizer.hpp>

// TODO: make it possible to filter out categories (esp debug messages when implemented)
// TODO: receive errors and debug messages through ClientModel

const int CONSOLE_SCROLLBACK = 50;
const int CONSOLE_HISTORY = 50;

/* Object for executing console RPC commands in a separate thread.
*/
class RPCExecutor: public QObject
{
    Q_OBJECT
public slots:
    void start();
    void request(const QString &command);
signals:
    void reply(int category, const QString &command);
};

#include "rpcconsole.moc"

void RPCExecutor::start()
{
   // Nothing to do
}

void RPCExecutor::request(const QString &command)
{
    // Parse shell-like command line into separate arguments
    boost::escaped_list_separator<char> els('\\',' ','\"');
    std::string strCommand = command.toStdString();
    boost::tokenizer<boost::escaped_list_separator<char> > tok(strCommand, els);

    std::string strMethod;
    std::vector<std::string> strParams;
    int n = 0;
    for(boost::tokenizer<boost::escaped_list_separator<char> >::iterator beg=tok.begin(); beg!=tok.end();++beg,++n)
    {
        if(n == 0) // First parameter is the command
            strMethod = *beg;
        else
            strParams.push_back(*beg);
    }

    try {
        std::string strPrint;
        json_spirit::Value result = tableRPC.execute(strMethod, RPCConvertValues(strMethod, strParams));

        // Format result reply
        if (result.type() == json_spirit::null_type)
            strPrint = "";
        else if (result.type() == json_spirit::str_type)
            strPrint = result.get_str();
        else
            strPrint = write_string(result, true);

        emit reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint));
    }
    catch (json_spirit::Object& objError)
    {
        emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(write_string(json_spirit::Value(objError), false)));
    }
    catch (std::exception& e)
    {
        emit reply(RPCConsole::CMD_ERROR, QString("Error: ") + QString::fromStdString(e.what()));
    }
}

RPCConsole::RPCConsole(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::RPCConsole),
    firstLayout(true),
    historyPtr(0)
{
    ui->setupUi(this);
    ui->messagesWidget->horizontalHeader()->setResizeMode(1, QHeaderView::Stretch);
    ui->messagesWidget->setContextMenuPolicy(Qt::ActionsContextMenu);

#ifndef WIN32
    // Show Debug logfile label and Open button only for Windows
    ui->labelDebugLogfile->setVisible(false);
    ui->openDebugLogfileButton->setVisible(false);
#endif

    // Install event filter for up and down arrow
    ui->lineEdit->installEventFilter(this);

    // Add "Copy message" to context menu explicitly
    QAction *copyMessageAction = new QAction(tr("&Copy"), this);
    copyMessageAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_C));
    copyMessageAction->setShortcutContext(Qt::WidgetShortcut);
    connect(copyMessageAction, SIGNAL(triggered()), this, SLOT(copyMessage()));
    ui->messagesWidget->addAction(copyMessageAction);

    connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));
    connect(ui->openDebugLogfileButton, SIGNAL(clicked()), this, SLOT(on_openDebugLogfileButton_clicked()));

    startExecutor();

    clear();
}

RPCConsole::~RPCConsole()
{
    emit stopExecutor();
    delete ui;
}

bool RPCConsole::eventFilter(QObject* obj, QEvent *event)
{
    if(obj == ui->lineEdit)
    {
        if(event->type() == QEvent::KeyPress)
        {
            QKeyEvent *key = static_cast<QKeyEvent*>(event);
            switch(key->key())
            {
            case Qt::Key_Up: browseHistory(-1); return true;
            case Qt::Key_Down: browseHistory(1); return true;
            }
        }
    }
    return QDialog::eventFilter(obj, event);
}

void RPCConsole::setClientModel(ClientModel *model)
{
    this->clientModel = model;
    if(model)
    {
        // Subscribe to information, replies, messages, errors
        connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
        connect(model, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int)));

        // Provide initial values
        ui->clientVersion->setText(model->formatFullVersion());
        ui->clientName->setText(model->clientName());
        ui->buildDate->setText(model->formatBuildDate());

        setNumConnections(model->getNumConnections());
        ui->isTestNet->setChecked(model->isTestNet());

        setNumBlocks(model->getNumBlocks());
    }
}

static QColor categoryColor(int category)
{
    switch(category)
    {
    case RPCConsole::MC_ERROR:     return QColor(255,0,0); break;
    case RPCConsole::MC_DEBUG:     return QColor(192,192,192); break;
    case RPCConsole::CMD_REQUEST:  return QColor(128,128,128); break;
    case RPCConsole::CMD_REPLY:    return QColor(128,255,128); break;
    case RPCConsole::CMD_ERROR:    return QColor(255,128,128); break;
    default:           return QColor(0,0,0);
    }
}

void RPCConsole::clear()
{
    ui->messagesWidget->clear();
    ui->messagesWidget->setRowCount(0);
    ui->lineEdit->clear();
    ui->lineEdit->setFocus();

    message(CMD_REPLY, tr("Welcome to the bitcoin RPC console.")+"\n"+
                       tr("Use up and down arrows to navigate history, and Ctrl-L to clear screen.")+"\n"+
                       tr("Type \"help\" for an overview of available commands."));
}

void RPCConsole::message(int category, const QString &message)
{
    // Add row to messages widget
    int row = ui->messagesWidget->rowCount();
    ui->messagesWidget->setRowCount(row+1);

    QTime time = QTime::currentTime();
    QTableWidgetItem *newTime = new QTableWidgetItem(time.toString());
    newTime->setData(Qt::DecorationRole, categoryColor(category));
    newTime->setForeground(QColor(128,128,128));
    newTime->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); // make non-editable

    int numLines = message.count("\n") + 1;
    // As Qt doesn't like very tall cells (they break scrolling) keep only short messages in
    // the cell text, longer messages trigger a display widget with scroll bar
    if(numLines < 5)
    {
        QTableWidgetItem *newItem = new QTableWidgetItem(message);
        newItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); // make non-editable
        if(category == CMD_ERROR) // Coloring error messages in red
            newItem->setForeground(QColor(255,16,16));
        ui->messagesWidget->setItem(row, 1, newItem);
    } else {
        QTextEdit *newWidget = new QTextEdit;
        newWidget->setText(message);
        newWidget->setMaximumHeight(100);
        newWidget->setReadOnly(true);
        ui->messagesWidget->setCellWidget(row, 1, newWidget);
    }

    ui->messagesWidget->setItem(row, 0, newTime);
    ui->messagesWidget->resizeRowToContents(row);
    // Preserve only limited scrollback buffer
    while(ui->messagesWidget->rowCount() > CONSOLE_SCROLLBACK)
        ui->messagesWidget->removeRow(0);
    // Scroll to bottom after table is updated
    QTimer::singleShot(0, ui->messagesWidget, SLOT(scrollToBottom()));
}

void RPCConsole::setNumConnections(int count)
{
    ui->numberOfConnections->setText(QString::number(count));
}

void RPCConsole::setNumBlocks(int count)
{
    ui->numberOfBlocks->setText(QString::number(count));
    if(clientModel)
    {
        // If there is no current number available display N/A instead of 0, which can't ever be true
        ui->totalBlocks->setText(clientModel->getNumBlocksOfPeers() == 0 ? tr("N/A") : QString::number(clientModel->getNumBlocksOfPeers()));
        ui->lastBlockTime->setText(clientModel->getLastBlockDate().toString());
    }
}

void RPCConsole::on_lineEdit_returnPressed()
{
    QString cmd = ui->lineEdit->text();
    ui->lineEdit->clear();

    if(!cmd.isEmpty())
    {
        message(CMD_REQUEST, cmd);
        emit cmdRequest(cmd);
        // Truncate history from current position
        history.erase(history.begin() + historyPtr, history.end());
        // Append command to history
        history.append(cmd);
        // Enforce maximum history size
        while(history.size() > CONSOLE_HISTORY)
            history.removeFirst();
        // Set pointer to end of history
        historyPtr = history.size();
    }
}

void RPCConsole::browseHistory(int offset)
{
    historyPtr += offset;
    if(historyPtr < 0)
        historyPtr = 0;
    if(historyPtr > history.size())
        historyPtr = history.size();
    QString cmd;
    if(historyPtr < history.size())
        cmd = history.at(historyPtr);
    ui->lineEdit->setText(cmd);
}

void RPCConsole::startExecutor()
{
    QThread* thread = new QThread;
    RPCExecutor *executor = new RPCExecutor();
    executor->moveToThread(thread);

    // Notify executor when thread started (in executor thread)
    connect(thread, SIGNAL(started()), executor, SLOT(start()));
    // Replies from executor object must go to this object
    connect(executor, SIGNAL(reply(int,QString)), this, SLOT(message(int,QString)));
    // Requests from this object must go to executor
    connect(this, SIGNAL(cmdRequest(QString)), executor, SLOT(request(QString)));
    // On stopExecutor signal
    // - queue executor for deletion (in execution thread)
    // - quit the Qt event loop in the execution thread
    connect(this, SIGNAL(stopExecutor()), executor, SLOT(deleteLater()));
    connect(this, SIGNAL(stopExecutor()), thread, SLOT(quit()));
    // Queue the thread for deletion (in this thread) when it is finished
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

    // Default implementation of QThread::run() simply spins up an event loop in the thread,
    // which is what we want.
    thread->start();
}

void RPCConsole::copyMessage()
{
    GUIUtil::copyEntryData(ui->messagesWidget, 1, Qt::EditRole);
}

void RPCConsole::on_tabWidget_currentChanged(int index)
{
    if(ui->tabWidget->widget(index) == ui->tab_console)
    {
        if(firstLayout)
        {
            // Work around QTableWidget issue:
            // Call resizeRowsToContents on first Layout request with widget visible,
            // to make sure multiline messages that were added before the console was shown
            // have the right height.
            firstLayout = false;
            ui->messagesWidget->resizeRowsToContents();
        }
        ui->lineEdit->setFocus();
    }
}

void RPCConsole::on_openDebugLogfileButton_clicked()
{
    GUIUtil::openDebugLogfile();
}
<|endoftext|>


<commit_before>/* -------------------------------------------------------------------------- *
 *                        OpenSim:  testInitState.cpp                         *
 * -------------------------------------------------------------------------- *
 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
 * See http://opensim.stanford.edu and the NOTICE file for more information.  *
 * OpenSim is developed at Stanford University and supported by the US        *
 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
 * through the Warrior Web program.                                           *
 *                                                                            *
 * Copyright (c) 2005-2016 Stanford University and the Authors                *
 * Author(s): Peter Eastman, Ajay Seth                                        *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
 * not use this file except in compliance with the License. You may obtain a  *
 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 * -------------------------------------------------------------------------- */
#include <stdint.h>
#include <OpenSim/Simulation/Manager/Manager.h>
#include <OpenSim/Simulation/Control/ControlSetController.h>
#include <OpenSim/Simulation/Model/Model.h>
#include <OpenSim/Common/LoadOpenSimLibrary.h>
#include <OpenSim/Auxiliary/auxiliaryTestFunctions.h>

using namespace OpenSim;
using namespace std;

//==============================================================================
// testInitState tests that a Model consistently generates the same default
// state from its initSystem() method. It also tests that when the properties
// are updated (after a simulation) that the defaults match the values in the
// new state.
//==============================================================================
void testStates(const string& modelFile);
//==============================================================================
// testMemoryUsage tests that repeated initialization of the state does not
// cause the memory footprint of the process to increase significantly.
//==============================================================================
void testMemoryUsage(const string& modelFile);

static const int MAX_N_TRIES = 100;

int main()
{
    try {
        LoadOpenSimLibrary("osimActuators");
        testStates("arm26.osim");
        testMemoryUsage("arm26.osim");
        testMemoryUsage("PushUpToesOnGroundWithMuscles.osim");
    }
    catch (const Exception& e) {
        cout << "testInitState failed: ";
        e.print(cout);
        return 1;
    }
    catch (const std::exception& e) {
        cout << "testInitState failed: " << e.what() << endl;
        return 1;
    }
    cout << "Done" << endl;
    return 0;
}

//==============================================================================
// Test Cases
//==============================================================================
void testStates(const string& modelFile)
{
    using namespace SimTK;

    //==========================================================================
    // Setup OpenSim model
    Model model(modelFile);
    ControlSetController* controller = new ControlSetController();
    controller->setControlSetFileName("arm26_StaticOptimization_controls.xml");

    model.addController( controller );
    // original default state
    State& state = model.initSystem();

    // hold on to original default continuous state variables
    Vector y1 = state.getY();
    y1 = state.getY();
    y1.dump("y1: Initial state:");

    // update state to contain muscle states that yield muscle equilibrium
    model.equilibrateMuscles(state);
    state.getY().dump("y1: State after equilibrateMuscles:");
    //==========================================================================
    // Compute the force and torque at the specified times.

    RungeKuttaMersonIntegrator integrator(model.getMultibodySystem());
    Manager manager(model, integrator);
    manager.setInitialTime(0.0);
    manager.setFinalTime(0.05);

    // update state after a short simulation forward in time
    manager.integrate(state);

    // continuous state variables after simulation
    Vector y2 = state.getY();
    y2.dump("y2: State after integration:");

    // reset model working state to default state
    State& state2 = model.initializeState();

    // another version of default continuous state variables
    // should be unaffected by simulation of the system
    Vector y3 = state2.getY();
    y3.dump("y3: Model reset to Initial state:");

    // update state to contain muscle states that yield muscle equilibrium
    model.equilibrateMuscles(state2);
    state.getY().dump("y3: State after equilibrateMuscles:");
    //==========================================================================
    // Compute the force and torque at the specified times.

    RungeKuttaMersonIntegrator integrator2(model.getMultibodySystem());
    Manager manager2(model, integrator);
    manager2.setInitialTime(0.0);
    manager2.setFinalTime(0.05);

    // update state after a short simulation forward in time
    manager2.integrate(state2);

    // get the default continuous state variables updated
    // from the state after the simulation
    Vector y4 = state2.getY();

    y4.dump("y4: Default State after second simulation:");

    for (int i = 0; i < y1.size(); i++)
    {
        cout << i <<" : y1[i] = " << y1[i] << " :: y3[i] = " << y3[i] << endl;
        ASSERT_EQUAL(y1[i], y3[i], 1e-5,__FILE__, __LINE__,
            "Model failed to maintain default state after simulation.");
        cout << i <<" : y2[i] = " << y2[i] << " :: y4[i] = " << y4[i] << endl;
        ASSERT_EQUAL(y2[i], y4[i], 1e-5,__FILE__, __LINE__,
            "Model failed to properly update default state after simulation.");
    }
    ASSERT(max(abs(y1-y2)) > 1e-4);
}

void testMemoryUsage(const string& modelFile)
{
    using namespace SimTK;

    //=========================================================================
    // Setup OpenSim model
    // base footprint
    size_t mem0 = getCurrentRSS();
    size_t current_size{ 0 };

    Model model;

    // getCurrentRSS() can be unreliable at evaluating the memory usage of a
    // current process because of caching, shared memory and a litany of
    // other reason including some platform specific details.
    // When this occurs, the model_size is determined to be zero, which is not
    // possible. This was leading to an invalid (NaN) leak % and the test was
    // failing. Redoing the test (or restarting the CI tests) often remedies
    // the issue (see #473) but it is a waste of time and CI resources.
    // The following code was added to retry loading the model until a nonzero
    // value is registered so that the test can proceed without requiring
    // to be rerun. It is not 100% that it will work, but it should be an
    // improvement.
    int ntries = 0;
    while (ntries++ < 10) {
        model = Model(modelFile);
        current_size = getCurrentRSS();

        // Exit if memory footprint increased.
        if (current_size > mem0)
            break;

        // Update mem0 if memory footprint decreased.
        if (current_size < mem0)
            mem0 = current_size;
    }

    // Ensure subtraction does not wrap unsigned int through zero.
    const size_t model_size = current_size > mem0 ? current_size-mem0 : 0;

    if (ntries > 1) {
        cout << "testMemoryUsage: required " << to_string(ntries);
        cout << " load attempts to record a nonzero model_size." << endl;
    }

    cout << "*********************** testMemoryUsage ***********************" << endl;
    cout << "MODEL: " << modelFile << " uses " << model_size / 1024.0 << "KB" << endl;

    ASSERT(model_size > 0, __FILE__, __LINE__,
        "testMemoryUsage: model size was found to be zero.\n"
        "Memory instrumentation code failed to estimate model size correctly.");

    State state = model.initSystem();

    // initial footprint
    size_t mem1 = getCurrentRSS();

    // also time how long initializing the state takes
    clock_t startTime = clock();

    for(int i=0; i< MAX_N_TRIES; ++i){
        state = model.initializeState();
    }

    // New memory footprint after MAX_N_TRIES.
    size_t mem2 = getCurrentRSS();
    // Increase in memory footprint.
    int64_t memory_increase = mem2 > mem1 ? mem2-mem1 : 0;
    int64_t leak = memory_increase/MAX_N_TRIES;

    long double leak_percent = 100.0 * double(leak)/model_size;

    long double dT = (long double)(clock()-startTime) / CLOCKS_PER_SEC;
    long double meanT = 1.0e3 * dT/MAX_N_TRIES; // in ms

    cout << memory_increase/1024 << "KB increase in memory use after "
         << MAX_N_TRIES << " state initializations." << endl;
    cout << "Approximate leak size: " << leak/1024.0 << "KB or " <<
             leak_percent << "% of model size." << endl;
    cout << "Average initialization time: " << meanT << "ms" << endl;

    // If we are leaking more than 0.5% of the model's footprint that is significant
    ASSERT( (leak_percent) < 0.5, __FILE__, __LINE__,
        "testMemoryUsage: state initialization leak > 0.5% of model memory footprint.");

    // If we ever leak over 100MB total we should know about it.
    ASSERT( memory_increase < 1e8, __FILE__, __LINE__,
        "testMemoryUsage: total estimated memory leaked > 100MB.");
}
<commit_msg>Simplified testInitState to use general utilities in auxiliaryTestFunctions.h to compute model size and estimate the change due to initializeState.<commit_after>/* -------------------------------------------------------------------------- *
 *                        OpenSim:  testInitState.cpp                         *
 * -------------------------------------------------------------------------- *
 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
 * See http://opensim.stanford.edu and the NOTICE file for more information.  *
 * OpenSim is developed at Stanford University and supported by the US        *
 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
 * through the Warrior Web program.                                           *
 *                                                                            *
 * Copyright (c) 2005-2016 Stanford University and the Authors                *
 * Author(s): Peter Eastman, Ajay Seth                                        *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
 * not use this file except in compliance with the License. You may obtain a  *
 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 * -------------------------------------------------------------------------- */
#include <stdint.h>
#include <OpenSim/Simulation/Manager/Manager.h>
#include <OpenSim/Simulation/Control/ControlSetController.h>
#include <OpenSim/Simulation/Model/Model.h>
#include <OpenSim/Common/LoadOpenSimLibrary.h>
#include <OpenSim/Auxiliary/auxiliaryTestFunctions.h>

using namespace OpenSim;
using namespace std;

//==============================================================================
// testInitState tests that a Model consistently generates the same default
// state from its initSystem() method. It also tests that when the properties
// are updated (after a simulation) that the defaults match the values in the
// new state.
//==============================================================================
void testStates(const string& modelFile);
//==============================================================================
// testMemoryUsage tests that repeated initialization of the state does not
// cause the memory footprint of the process to increase significantly.
//==============================================================================
void testMemoryUsage(const string& modelFile);

static const int MAX_N_TRIES = 100;

int main()
{
    try {
        LoadOpenSimLibrary("osimActuators");
        testStates("arm26.osim");
        testMemoryUsage("arm26.osim");
        testMemoryUsage("PushUpToesOnGroundWithMuscles.osim");
    }
    catch (const Exception& e) {
        cout << "testInitState failed: ";
        e.print(cout);
        return 1;
    }
    catch (const std::exception& e) {
        cout << "testInitState failed: " << e.what() << endl;
        return 1;
    }
    cout << "Done" << endl;
    return 0;
}

//==============================================================================
// Test Cases
//==============================================================================
void testStates(const string& modelFile)
{
    using namespace SimTK;

    //==========================================================================
    // Setup OpenSim model
    Model model(modelFile);
    ControlSetController* controller = new ControlSetController();
    controller->setControlSetFileName("arm26_StaticOptimization_controls.xml");

    model.addController( controller );
    // original default state
    State& state = model.initSystem();

    // hold on to original default continuous state variables
    Vector y1 = state.getY();
    y1 = state.getY();
    //y1.dump("y1: Initial state:");

    // update state to contain muscle states that yield muscle equilibrium
    model.equilibrateMuscles(state);
    state.getY().dump("y1: State after equilibrateMuscles:");
    //==========================================================================
    // Compute the force and torque at the specified times.

    RungeKuttaMersonIntegrator integrator(model.getMultibodySystem());
    Manager manager(model, integrator);
    manager.setInitialTime(0.0);
    manager.setFinalTime(0.05);

    // update state after a short simulation forward in time
    manager.integrate(state);

    // continuous state variables after simulation
    Vector y2 = state.getY();
    //y2.dump("y2: State after integration:");

    // reset model working state to default state
    State& state2 = model.initializeState();

    // another version of default continuous state variables
    // should be unaffected by simulation of the system
    Vector y3 = state2.getY();
    //y3.dump("y3: Model reset to Initial state:");

    // update state to contain muscle states that yield muscle equilibrium
    model.equilibrateMuscles(state2);
    state.getY().dump("y3: State after equilibrateMuscles:");
    //==========================================================================
    // Compute the force and torque at the specified times.

    RungeKuttaMersonIntegrator integrator2(model.getMultibodySystem());
    Manager manager2(model, integrator);
    manager2.setInitialTime(0.0);
    manager2.setFinalTime(0.05);

    // update state after a short simulation forward in time
    manager2.integrate(state2);

    // get the default continuous state variables updated
    // from the state after the simulation
    Vector y4 = state2.getY();

    //y4.dump("y4: Default State after second simulation:");

    for (int i = 0; i < y1.size(); i++)
    {
        cout << i <<" : y1[i] = " << y1[i] << " :: y3[i] = " << y3[i] << endl;
        ASSERT_EQUAL(y1[i], y3[i], 1e-5,__FILE__, __LINE__,
            "Model failed to maintain default state after simulation.");
        cout << i <<" : y2[i] = " << y2[i] << " :: y4[i] = " << y4[i] << endl;
        ASSERT_EQUAL(y2[i], y4[i], 1e-5,__FILE__, __LINE__,
            "Model failed to properly update default state after simulation.");
    }
    ASSERT(max(abs(y1-y2)) > 1e-4);
}

void testMemoryUsage(const string& modelFile)
{
    using namespace SimTK;

    if (isGetRSSValid) {
        //=========================================================================
        // Estimate the size of the model when loaded into memory
        const size_t model_size = estimateMemoryChangeForModelLoading(modelFile, 10);

        Model model(modelFile);
        State state = model.initSystem();

        // also time how long initializing the state takes
        clock_t startTime = clock();

        // determine the change in memory usage due to invoking model.initialiState
        auto command = [&model]() mutable { model.initializeState(); };
        const size_t leak = estimateMemoryChangeForCommand(command, MAX_N_TRIES);

        long double leak_percent = 100.0 * double(leak) / model_size;

        long double dT = (long double)(clock() - startTime) / CLOCKS_PER_SEC;
        long double meanT = 1.0e3 * dT / MAX_N_TRIES; // in ms

        cout << "Approximate leak size: " << leak / 1024.0 << "KB or " <<
            leak_percent << "% of model size." << endl;
        cout << "Average initialization time: " << meanT << "ms" << endl;

        // If we are leaking more than 0.5% of the model's footprint that is significant
        ASSERT((leak_percent) < 0.5, __FILE__, __LINE__,
            "testMemoryUsage: state initialization leak > 0.5% of model memory footprint.");
    }
}
<|endoftext|>