/* * 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 */ #include #include #include #include #include #include #define foreach BOOST_FOREACH #include #include "privateoption.h" #include #include #include template class std::vector; template class std::vector; template class std::vector; namespace { CompOption::Value::Vector & emptyList () { static CompOption::Value::Vector v; 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 () { static unsigned short v[4] = { 0, 0, 0, 0 }; return v; } template::type & (*get_default)()> struct get_or_default_call : public boost::static_visitor { TargetType& operator()(TargetType& a) { return a; } template TargetType& operator()(T&) { return get_default(); } }; template::type Default> struct get_or_default_val : public boost::static_visitor { TargetType operator()(TargetType& a) { return a; } template TargetType operator()(T&) { return Default; } }; struct get_float : public boost::static_visitor { float operator()(float const& a) { return a; } template float operator()(T&) { return 0.0; } }; } CompOption::Vector & noOptions () { static CompOption::Vector v; return 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) { mListType = t; mValue = v; } bool CompOption::Value::b () const { get_or_default_val tmp; return boost::apply_visitor(tmp, mValue); } int CompOption::Value::i () const { get_or_default_val tmp; return boost::apply_visitor(tmp, mValue); } float CompOption::Value::f () const { get_float tmp; return boost::apply_visitor(tmp, mValue); } unsigned short* CompOption::Value::c () const { try { return const_cast (&((boost::get(mValue))[0])); } catch (...) { return emptyColor (); } } const CompString & CompOption::Value::s () const { get_or_default_call tmp; return boost::apply_visitor(tmp, mValue); } CompString & CompOption::Value::s () { get_or_default_call tmp; return boost::apply_visitor(tmp, mValue); } const CompMatch & CompOption::Value::match () const { get_or_default_call tmp; return boost::apply_visitor(tmp, mValue); } CompMatch & CompOption::Value::match () { get_or_default_call tmp; return boost::apply_visitor(tmp, mValue); } const CompAction & CompOption::Value::action () const { get_or_default_call tmp; return boost::apply_visitor(tmp, mValue); } CompAction & CompOption::Value::action () { get_or_default_call tmp; return boost::apply_visitor(tmp, mValue); } // Type listType () const; const CompOption::Value::Vector & CompOption::Value::list () const { get_or_default_call tmp; return boost::apply_visitor(tmp, mValue); } CompOption::Value::Vector & CompOption::Value::list () { get_or_default_call tmp; return boost::apply_visitor(tmp, mValue); } bool CompOption::Value::operator== (const Value & rhs) const { return mValue == rhs.mValue; } bool CompOption::Value::operator!= (const Value & rhs) const { return !(mValue == rhs.mValue); } CompOption::Restriction::Restriction () : priv (new PrivateRestriction ()) { } CompOption::Restriction::Restriction (const CompOption::Restriction &r) : priv (new PrivateRestriction (*r.priv)) { } CompOption::Restriction::~Restriction () { delete priv; } int CompOption::Restriction::iMin () { if (priv->type == CompOption::TypeInt) return priv->rest.i.min; return MINSHORT; } int CompOption::Restriction::iMax () { if (priv->type == CompOption::TypeInt) return priv->rest.i.max; return MAXSHORT; } float CompOption::Restriction::fMin () { if (priv->type == CompOption::TypeFloat) return priv->rest.f.min; return MINSHORT; } float CompOption::Restriction::fMax () { if (priv->type == CompOption::TypeFloat) return priv->rest.f.min; return MINSHORT; } 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 * 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++) { if (options[i].priv->name == name) { if (index) *index = i; return &options[i]; } } return NULL; } 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) screen->removeAction (&action); } catch (...) { } delete priv; } void CompOption::reset () { priv->name = ""; priv->type = TypeUnset; } void CompOption::setName (CompString name, CompOption::Type type) { priv->name = name; priv->type = type; } void CompOption::setName (const char *name, CompOption::Type type) { if (!name && !priv->name.empty ()) priv->name.clear (); else if (name && priv->name != name) priv->name = name; priv->type = type; } const CompString & CompOption::name () const { return priv->name; } CompOption::Type CompOption::type () const { return priv->type; } CompOption::Value & CompOption::value () { return priv->value; } 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, "Can't set Value with type %d to " "option \"%s\" with type %d", val.type (), priv->name.c_str (), priv->type); return false; } if (priv->value == val) return false; if (isAction () && priv->value.action ().state () & CompAction::StateAutoGrab && screen) { if (!screen->addAction (&val.action ())) return false; else 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; default: break; } priv->value = val; return true; } bool 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; } bool CompOption::getBoolOptionNamed (const Vector& options, const CompString& name, bool defaultValue) { foreach (const CompOption &o, options) if (o.priv->type == CompOption::TypeBool && o.priv->name == name) return o.priv->value.b (); return defaultValue; } int CompOption::getIntOptionNamed (const Vector& options, const CompString& name, int defaultValue) { foreach (const CompOption &o, options) if (o.priv->type == CompOption::TypeInt && o.priv->name == name) return o.priv->value.i (); return defaultValue; } float CompOption::getFloatOptionNamed (const Vector& options, const CompString& name, const float& defaultValue) { foreach (const CompOption &o, options) if (o.priv->type == CompOption::TypeFloat && o.priv->name == name) return o.priv->value.f (); return defaultValue; } CompString CompOption::getStringOptionNamed (const Vector& options, const CompString& name, const CompString& defaultValue) { foreach (const CompOption &o, options) if (o.priv->type == CompOption::TypeString && o.priv->name == name) return o.priv->value.s (); return defaultValue; } unsigned short * CompOption::getColorOptionNamed (const Vector& options, const CompString& name, unsigned short *defaultValue) { foreach (const CompOption &o, options) if (o.priv->type == CompOption::TypeColor && o.priv->name == name) return o.priv->value.c (); return defaultValue; } CompMatch CompOption::getMatchOptionNamed (const Vector& options, const CompString& name, const CompMatch& defaultValue) { 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]; return true; } return false; } 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; } return "unknown"; } bool CompOption::setOption (CompOption &o, CompOption::Value &value) { return o.set (value); } PrivateOption::PrivateOption () : name (""), type (CompOption::TypeUnset), value (), rest () { } PrivateOption::PrivateOption (const PrivateOption &p) : name (p.name), type (p.type), value (p.value), rest (p.rest) { }