Skip to content
option.cpp 14.8 KiB
Newer Older
David Reveman's avatar
David Reveman committed
/*
 * Copyright © 2005 Novell, Inc.
 *
 * Permission to use, copy, modify, distribute, and sell this software
 * and its documentation for any purpose is hereby granted without
 * fee, provided that the above copyright notice appear in all copies
 * and that both that copyright notice and this permission notice
 * appear in supporting documentation, and that the name of
 * Novell, Inc. not be used in advertising or publicity pertaining to
 * distribution of the software without specific, written prior permission.
 * Novell, Inc. makes no representations about the suitability of this
 * software for any purpose. It is provided "as is" without express or
 * implied warranty.
 *
 * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
 * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, 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.
 *
 * Author: David Reveman <davidr@novell.com>
 */

#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
David Reveman's avatar
David Reveman committed
#include <math.h>

#include <boost/foreach.hpp>
#define foreach BOOST_FOREACH

#include <core/option.h>
#include "privateoption.h"
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/type_traits/remove_const.hpp>
David Reveman's avatar
David Reveman committed

template class std::vector<unsigned short>;
template class std::vector<CompOption::Value>;
template class std::vector<CompOption>;

namespace
{
    CompOption::Value::Vector & emptyList ()
    {
	return v;
    }

    CompString & emptyString ()
    {
	static CompString v;
	return v;
    }

    CompMatch & emptyMatch ()
    {
	static CompMatch v;
	return v;
    }

    CompAction & emptyAction ()
    {
	static CompAction v;
	return v;
    }

    unsigned short * emptyColor ()
    {
smspillaz's avatar
smspillaz committed
	static unsigned short v[4] = { 0, 0, 0, 0 };
    template<typename TargetType, typename boost::remove_const<TargetType>::type & (*get_default)()>
    struct get_or_default_call : public boost::static_visitor<TargetType &>
    {
	TargetType& operator()(TargetType& a)
	{
	    return a;
	}

	template<typename T>
	TargetType& operator()(T&)
	{
	    return get_default();
	}
    };

Alan Griffiths's avatar
Alan Griffiths committed
    template<typename TargetType, typename boost::remove_const<TargetType>::type Default>
    struct get_or_default_val : public boost::static_visitor<TargetType>
    {
	TargetType operator()(TargetType& a)
	{
	    return a;
	}

	template<typename T>
	TargetType operator()(T&)
	{
	    return Default;
	}
    };
Alan Griffiths's avatar
Alan Griffiths committed

    struct get_float : public boost::static_visitor<float const>
    {
	float operator()(float const& a)
	{
	    return a;
	}

	template<typename T>
	float operator()(T&)
	{
	    return 0.0;
	}
    };
smspillaz's avatar
smspillaz committed
    static CompOption::Vector v;
static bool
checkIsAction (CompOption::Type type)
{
    switch (type) {
	case CompOption::TypeAction:
	case CompOption::TypeKey:
	case CompOption::TypeButton:
	case CompOption::TypeEdge:
	case CompOption::TypeBell:
	    return true;
	default:
	    break;
    }

    return false;
}

CompOption::Value::~Value()
void
CompOption::Value::set (Type t, const CompOption::Value::Vector & v)
Alan Griffiths's avatar
Alan Griffiths committed
    get_or_default_val<bool const, false> tmp;
    return boost::apply_visitor(tmp, mValue);
Alan Griffiths's avatar
Alan Griffiths committed
    get_or_default_val<int const, 0> tmp;
    return boost::apply_visitor(tmp, mValue);
Alan Griffiths's avatar
Alan Griffiths committed
    get_float tmp;
    return boost::apply_visitor(tmp, mValue);
unsigned short*
CompOption::Value::c () const
	return const_cast <unsigned short *> (&((boost::get<ColorVector>(mValue))[0]));
const CompString &
CompOption::Value::s () const
    get_or_default_call<CompString const, emptyString> tmp;
    return boost::apply_visitor(tmp, mValue);
    get_or_default_call<CompString, emptyString> tmp;
    return boost::apply_visitor(tmp, mValue);
const CompMatch &
CompOption::Value::match () const
    get_or_default_call<CompMatch const, emptyMatch> tmp;
    return boost::apply_visitor(tmp, mValue);
    get_or_default_call<CompMatch, emptyMatch> tmp;
    return boost::apply_visitor(tmp, mValue);
const CompAction &
CompOption::Value::action () const
David Reveman's avatar
David Reveman committed
{
    get_or_default_call<CompAction const, emptyAction> tmp;
    return boost::apply_visitor(tmp, mValue);
    get_or_default_call<CompAction, emptyAction> tmp;
    return boost::apply_visitor(tmp, mValue);
const CompOption::Value::Vector &
CompOption::Value::list () const
    get_or_default_call<CompOption::Value::Vector const, emptyList> tmp;
    return boost::apply_visitor(tmp, mValue);
David Reveman's avatar
David Reveman committed

CompOption::Value::Vector &
CompOption::Value::list ()
    get_or_default_call<CompOption::Value::Vector, emptyList> tmp;
    return boost::apply_visitor(tmp, mValue);
David Reveman's avatar
David Reveman committed

CompOption::Value::operator== (const Value & rhs) const
bool
CompOption::Value::operator!= (const Value & rhs) const
CompOption::Restriction::Restriction () :
    priv (new PrivateRestriction ())
Dennis Kasprzyk's avatar
Dennis Kasprzyk committed
CompOption::Restriction::Restriction (const CompOption::Restriction &r) :
    priv (new PrivateRestriction (*r.priv))
{
}
CompOption::Restriction::~Restriction ()
{
    delete priv;
CompOption::Restriction::iMin ()
    if (priv->type == CompOption::TypeInt)
	return priv->rest.i.min;
int
CompOption::Restriction::iMax ()
{
    if (priv->type == CompOption::TypeInt)
	return priv->rest.i.max;
CompOption::Restriction::fMin ()
    if (priv->type == CompOption::TypeFloat)
	return priv->rest.f.min;
float
CompOption::Restriction::fMax ()
    if (priv->type == CompOption::TypeFloat)
	return priv->rest.f.min;
float
CompOption::Restriction::fPrecision ()
    if (priv->type == CompOption::TypeFloat)
	return priv->rest.f.precision;
    return 0.1f;
}
void
CompOption::Restriction::set (int min, int max)
{
    priv->type = CompOption::TypeInt;
    priv->rest.i.min = min;
    priv->rest.i.max = max;
void
CompOption::Restriction::set (float min, float max, float precision)
    priv->type = CompOption::TypeFloat;
    priv->rest.f.min       = min;
    priv->rest.f.max       = max;
    priv->rest.f.precision = precision;
}
bool
CompOption::Restriction::inRange (int i)
{
    if (priv->type != CompOption::TypeInt)
	return true;
    if (i < priv->rest.i.min)
	return false;
    if (i > priv->rest.i.max)
	return false;
    return true;
}
bool
CompOption::Restriction::inRange (float f)
{
    if (priv->type != CompOption::TypeFloat)
	return true;
    if (f < priv->rest.f.min)
	return false;
    if (f > priv->rest.f.max)
	return false;
    return true;
CompOption::Restriction &
CompOption::Restriction::operator= (const CompOption::Restriction &rest)
    if (this == &rest)
	return *this;
    delete priv;
    priv = new PrivateRestriction (*rest.priv);
    return *this;
}
CompOption::Class::getOption (const CompString &name)
{
    CompOption *o = CompOption::findOption (getOptions (), name);
    return o;
}

CompOption *
CompOption::findOption (CompOption::Vector &options,
			CompString         name,
			unsigned int       *index)
{
    for (unsigned int i = 0; i < options.size (); i++)
Danny Baumann's avatar
Danny Baumann committed
	if (options[i].priv->name == name)
	    if (index)
		*index = i;
	    return &options[i];
	}
CompOption::CompOption () :
    priv (new PrivateOption ())
CompOption::CompOption (const CompOption &o) :
    priv (new PrivateOption (*o.priv))
CompOption::CompOption (CompString name, CompOption::Type type) :
    priv (new PrivateOption ())
    setName (name, type);
CompOption::~CompOption ()
    /* Remove any added actions */
    try
    {
	CompAction &action = value ().action ();

	if (action.active () && screen)
void
CompOption::setName (CompString name, CompOption::Type type)
{
    priv->name = name;
    priv->type = type;
}
Danny Baumann's avatar
Danny Baumann committed

void
CompOption::setName (const char *name, CompOption::Type type)
{
    if (!name && !priv->name.empty ())
	priv->name.clear ();
    else if (name && priv->name != name)
Sam Spilsbury's avatar
Sam Spilsbury committed
const CompString &
CompOption::name () const
{
    return priv->name;
CompOption::Type
CompOption::type () const
{
    return priv->type;
}

CompOption::Value &
CompOption::value ()
{
    return priv->value;
}
Sam Spilsbury's avatar
Sam Spilsbury committed
const CompOption::Value &
CompOption::value () const
{
    return priv->value;
}

CompOption::Restriction &
CompOption::rest ()
{
    return priv->rest;
bool
CompOption::set (CompOption::Value &val)
    /* XXX: It is uncertain as to why this is done. The only
     * logical reason would be that actions are stateful and
     * we don't want to care about the old state from the
     * action that we're setting this value to, so we're just
     * clearing that state and starting over, however copyState
     * does a lot more than that */
    if (isAction () && priv->type != CompOption::TypeAction)
	val.action ().copyState (priv->value.action ());

    if (priv->type != val.type () &&
	(!isAction () || !checkIsAction (val.type ())))
    {
	compLogMessage ("core", CompLogLevelWarn,
Danny Baumann's avatar
Danny Baumann committed
			"Can't set Value with type %d to "
			"option \"%s\" with type %d",
			val.type (), priv->name.c_str (), priv->type);
    if (priv->value == val)
	return false;

        priv->value.action ().state () & CompAction::StateAutoGrab && screen)
	if (!screen->addAction (&val.action ()))
	    screen->removeAction (&priv->value.action ());
    switch (priv->type)
	case CompOption::TypeInt:
	    if (!priv->rest.inRange (val.i ()))
		return false;
	    break;
	case CompOption::TypeFloat:
	{
	    float v, p;
	    int sign = (val.f () < 0 ? -1 : 1);
	    if (!priv->rest.inRange (val.f ()))
		return false;
	    p = 1.0f / priv->rest.fPrecision ();
	    v = ((int) (val.f () * p + sign * 0.5f)) / p;
	    priv->value.set (v);
	    return true;
	}
	case CompOption::TypeAction:
	    return false;
	case CompOption::TypeKey:
	    if (val.action ().type () == value().action ().type () &&
		!(val.action ().type () & CompAction::BindingTypeKey))
		return false;
	    break;
	case CompOption::TypeButton:
	    if (val.action ().type () == value().action ().type () &&
		!(val.action ().type () & (CompAction::BindingTypeButton |
					   CompAction::BindingTypeEdgeButton)))
		return false;
	    break;
    priv->value = val;
Sam Spilsbury's avatar
Sam Spilsbury committed
CompOption::isAction () const
    return checkIsAction (priv->type);
CompOption &
CompOption::operator= (const CompOption &option)
    if (this == &option)
	return *this;
    delete priv;
    priv = new PrivateOption (*option.priv);
    return *this;
Danny Baumann's avatar
Danny Baumann committed
CompOption::getBoolOptionNamed (const Vector&     options,
				const CompString& name,
				bool              defaultValue)
Danny Baumann's avatar
Danny Baumann committed
    foreach (const CompOption &o, options)
	if (o.priv->type == CompOption::TypeBool && o.priv->name == name)
	    return o.priv->value.b ();
    return defaultValue;
}
Danny Baumann's avatar
Danny Baumann committed
CompOption::getIntOptionNamed (const Vector&     options,
			       const CompString& name,
			       int               defaultValue)
Danny Baumann's avatar
Danny Baumann committed
    foreach (const CompOption &o, options)
	if (o.priv->type == CompOption::TypeInt && o.priv->name == name)
	    return o.priv->value.i ();
    return defaultValue;
}
Danny Baumann's avatar
Danny Baumann committed
CompOption::getFloatOptionNamed (const Vector&     options,
				 const CompString& name,
				 const float&      defaultValue)
Danny Baumann's avatar
Danny Baumann committed
    foreach (const CompOption &o, options)
	if (o.priv->type == CompOption::TypeFloat && o.priv->name == name)
	    return o.priv->value.f ();
    return defaultValue;
}
Danny Baumann's avatar
Danny Baumann committed
CompOption::getStringOptionNamed (const Vector&     options,
				  const CompString& name,
				  const CompString& defaultValue)
Danny Baumann's avatar
Danny Baumann committed
    foreach (const CompOption &o, options)
	if (o.priv->type == CompOption::TypeString && o.priv->name == name)
	    return o.priv->value.s ();
    return defaultValue;
}
unsigned short *
Danny Baumann's avatar
Danny Baumann committed
CompOption::getColorOptionNamed (const Vector&        options,
				 const CompString&    name,
				 unsigned short       *defaultValue)
Danny Baumann's avatar
Danny Baumann committed
    foreach (const CompOption &o, options)
	if (o.priv->type == CompOption::TypeColor && o.priv->name == name)
	    return o.priv->value.c ();
    return defaultValue;
Danny Baumann's avatar
Danny Baumann committed
CompMatch
CompOption::getMatchOptionNamed (const Vector&     options,
				 const CompString& name,
				 const CompMatch&  defaultValue)
Danny Baumann's avatar
Danny Baumann committed
    foreach (const CompOption &o, options)
	if (o.priv->type == CompOption::TypeMatch && o.priv->name == name)
	    return o.priv->value.match ();
    return defaultValue;
}
bool
CompOption::stringToColor (CompString     color,
			   unsigned short *rgba)
{
    int c[4];
    if (sscanf (color.c_str (), "#%2x%2x%2x%2x",
		&c[0], &c[1], &c[2], &c[3]) == 4)
    {
	rgba[0] = c[0] << 8 | c[0];
	rgba[1] = c[1] << 8 | c[1];
	rgba[2] = c[2] << 8 | c[2];
	rgba[3] = c[3] << 8 | c[3];
CompString
CompOption::colorToString (unsigned short *rgba)
    return compPrintf ("#%.2x%.2x%.2x%.2x", rgba[0] / 256, rgba[1] / 256,
					    rgba[2] / 256, rgba[3] / 256);
CompString
CompOption::typeToString (CompOption::Type type)
    switch (type) {
	case CompOption::TypeBool:
	    return "bool";
	case CompOption::TypeInt:
	    return "int";
	case CompOption::TypeFloat:
	    return "float";
	case CompOption::TypeString:
	    return "string";
	case CompOption::TypeColor:
	    return "color";
	case CompOption::TypeAction:
	    return "action";
	case CompOption::TypeKey:
	    return "key";
	case CompOption::TypeButton:
	    return "button";
	case CompOption::TypeEdge:
	    return "edge";
	case CompOption::TypeBell:
	    return "bell";
	case CompOption::TypeMatch:
	    return "match";
	case CompOption::TypeList:
	    return "list";
	default:
	    break;
CompOption::setOption (CompOption        &o,
		       CompOption::Value &value)
    return o.set (value);
PrivateOption::PrivateOption () :
    name (""),
    type (CompOption::TypeUnset),
PrivateOption::PrivateOption (const PrivateOption &p) :
    name (p.name),
    type (p.type),
    value (p.value),
    rest (p.rest)
{