diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b926d882..6347c367 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -38,7 +38,7 @@ set(conky_sources colours.cc combine.cc common.cc conky.cc core.cc diskio.cc entropy.cc exec.cc fs.cc mail.cc mixer.cc net_stat.cc template.cc mboxscan.cc read_tcp.cc scroll.cc specials.cc tailhead.cc temphelper.cc text_object.cc timeinfo.cc top.cc algebra.cc prioqueue.c proc.cc - user.cc luamm.cc) + user.cc luamm.cc data-source.cc) # add timed thread library add_library(timed-thread timed-thread.cc) diff --git a/src/data-source.cc b/src/data-source.cc new file mode 100644 index 00000000..5ce84d29 --- /dev/null +++ b/src/data-source.cc @@ -0,0 +1,106 @@ +/* -*- mode: c++; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*- + * vim: ts=4 sw=4 noet ai cindent syntax=cpp + * + * Conky, a system monitor, based on torsmo + * + * Please see COPYING for details + * + * Copyright (C) 2010 Pavel Labath et al. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include + +#include "data-source.hh" + +#include +#include +#include +#include + +namespace conky { + namespace { + /* + * Returned when there is no data available. + * An alternative would be to throw an exception, but if we don't want to react too + * aggresively when the user e.g. uses a nonexisting variable, then returning NaN will do + * just fine. + */ + float NaN = std::numeric_limits::quiet_NaN(); + + /* + * We cannot construct this object statically, because order of object construction in + * different modules is not defined, so register_source could be called before this + * object is constructed. Therefore, we create it on the first call to register_source. + */ + typedef std::unordered_map data_sources_t; + data_sources_t *data_sources; + + void register_data_source_(const std::string &name, const data_source_factory &factory_func) + { + struct data_source_constructor { + data_source_constructor() { data_sources = new data_sources_t(); } + ~data_source_constructor() { delete data_sources; data_sources = NULL; } + }; + static data_source_constructor constructor; + + bool inserted = data_sources->insert({name, factory_func}).second; + if(not inserted) + throw std::logic_error("Data source with name '" + name + "' already registered"); + } + + static std::shared_ptr + disabled_source_factory(lua::state &l, const std::string &name, const std::string &setting) + { + // XXX some generic way of reporting errors? NORM_ERR? + std::cerr << "Support for setting '" << name + << "' has been disabled during compilation. Please recompile with '" + << setting << "'" << std::endl; + + return simple_numeric_source::factory(l, name, &NaN); + } + } + + double data_source_base::get_number() const + { return NaN; } + + std::string data_source_base::get_text() const + { + std::ostringstream s; + s << get_number(); + return s.str(); + } + + template + std::shared_ptr + simple_numeric_source::factory(lua::state &l, const std::string &name, const T *source) + { + l.pop(); + return std::shared_ptr(new simple_numeric_source(name, source)); + } + + register_data_source::register_data_source(const std::string &name, + const data_source_factory &factory_func) + { register_data_source_(name, factory_func); } + + register_disabled_data_source::register_disabled_data_source(const std::string &name, + const std::string &setting) + { + register_data_source_(name, + std::bind(disabled_source_factory, + std::placeholders::_1, std::placeholders::_2, setting) + ); + } +} diff --git a/src/data-source.hh b/src/data-source.hh new file mode 100644 index 00000000..f11806eb --- /dev/null +++ b/src/data-source.hh @@ -0,0 +1,107 @@ +/* -*- mode: c++; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*- + * vim: ts=4 sw=4 noet ai cindent syntax=cpp + * + * Conky, a system monitor, based on torsmo + * + * Please see COPYING for details + * + * Copyright (C) 2010 Pavel Labath et al. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef DATA_SOURCE_HH +#define DATA_SOURCE_HH + +#include +#include +#include +#include + +#include "luamm.hh" + +namespace conky { + + class data_source_base; + + /* + * Recieves a lua table on the stack and the name the object was registered with. It should + * pop the table after consuming it and return the data source. + */ + typedef std::function (lua::state &l, const std::string &name)> data_source_factory; + + /* + * A base class for all data sources. + * API consists of two functions: + * - get_number should return numeric representation of the data (if available). This can + * then be used when drawing graphs, bars, ... The default implementation returns NaN. + * - get_text should return textual representation of the data. This is used when simple + * displaying the value of the data source. The default implementation converts + * get_number() to a string, but you can override to return anything (e.g. add units) + */ + class data_source_base { + public: + const std::string name; + + data_source_base(const std::string &name_) + : name(name_) + {} + + virtual ~data_source_base() {} + virtual double get_number() const; + virtual std::string get_text() const; + }; + + /* + * A simple data source that returns the value of some variable. + * It ignores the lua table, but one can create a wrapper for the factory function that uses + * data in the table to decide which variable to return. + */ + template + class simple_numeric_source: public data_source_base { + static_assert(std::is_convertible::value, "T must be convertible to double"); + + const T *source; + + simple_numeric_source(const std::string &name_, const T *source_) + : data_source_base(name_), source(source_) + {} + public: + static std::shared_ptr + factory(lua::state &l, const std::string &name, const T *source); + + virtual double get_number() const + { return *source; } + }; + + /* + * Declaring an object of this type at global scope will register a data source with the give + * name and factory function. + */ + class register_data_source { + public: + register_data_source(const std::string &name, const data_source_factory &factory_func); + }; + + /* + * Use this to declare a data source that has been disabled during compilation. We can then + * print a nice error message telling the used which setting to enable. + */ + class register_disabled_data_source { + public: + register_disabled_data_source(const std::string &name, const std::string &setting); + }; +} + +#endif /* DATA_SOURCE_HH */