polybar-dwm/include/modules/meta/base.hpp
Patrick Ziegler abd96eb089
Enable module in start funcion (#2538)
Before it was enabled by default. That means if the constructor fails,
the destructor will complain that the module was not stopped before
deconstructing.

We can't just call stop if module creation fails because the module is
only partially initialized.
2021-10-15 10:33:10 +02:00

232 lines
5.6 KiB
C++

#pragma once
#include <algorithm>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <map>
#include <mutex>
#include "common.hpp"
#include "components/types.hpp"
#include "errors.hpp"
#include "utils/concurrency.hpp"
#include "utils/functional.hpp"
#include "utils/inotify.hpp"
#include "utils/string.hpp"
POLYBAR_NS
namespace chrono = std::chrono;
using namespace std::chrono_literals;
using std::atomic;
using std::map;
#define DEFAULT_FORMAT "format"
#define CONST_MOD(name) static_cast<name const&>(*this)
#define CAST_MOD(name) static_cast<name*>(this)
// fwd decl {{{
namespace drawtypes {
class ramp;
using ramp_t = shared_ptr<ramp>;
class progressbar;
using progressbar_t = shared_ptr<progressbar>;
class animation;
using animation_t = shared_ptr<animation>;
class iconset;
using iconset_t = shared_ptr<iconset>;
} // namespace drawtypes
class builder;
class config;
class logger;
class signal_emitter;
class action_router;
// }}}
namespace modules {
using namespace drawtypes;
DEFINE_ERROR(module_error);
DEFINE_CHILD_ERROR(undefined_format, module_error);
DEFINE_CHILD_ERROR(undefined_format_tag, module_error);
// class definition : module_format {{{
struct module_format {
string value{};
vector<string> tags{};
label_t prefix{};
label_t suffix{};
rgba fg{};
rgba bg{};
rgba ul{};
rgba ol{};
size_t ulsize{0};
size_t olsize{0};
size_t spacing{0};
size_t padding{0};
size_t margin{0};
int offset{0};
int font{0};
string decorate(builder* builder, string output);
};
// }}}
// class definition : module_formatter {{{
class module_formatter {
public:
explicit module_formatter(const config& conf, string modname) : m_conf(conf), m_modname(modname) {}
void add(string name, string fallback, vector<string>&& tags, vector<string>&& whitelist = {});
void add_optional(string name, vector<string>&& tags, vector<string>&& whitelist = {});
bool has(const string& tag, const string& format_name);
bool has(const string& tag);
bool has_format(const string& format_name);
shared_ptr<module_format> get(const string& format_name);
protected:
void add_value(string&& name, string&& value, vector<string>&& tags, vector<string>&& whitelist);
const config& m_conf;
string m_modname;
map<string, shared_ptr<module_format>> m_formats;
};
// }}}
// class definition : module_interface {{{
struct module_interface {
public:
virtual ~module_interface() {}
/**
* The type users have to specify in the module section `type` key
*/
virtual string type() const = 0;
/**
* Module name w/o 'module/' prefix
*/
virtual string name_raw() const = 0;
virtual string name() const = 0;
virtual bool running() const = 0;
virtual bool visible() const = 0;
/**
* Handle action, possibly with data attached
*
* Any implementation is free to ignore the data, if the action does not
* require additional data.
*
* \returns true if the action is supported and false otherwise
*/
virtual bool input(const string& action, const string& data) = 0;
virtual void start() = 0;
virtual void join() = 0;
virtual void stop() = 0;
virtual void halt(string error_message) = 0;
virtual string contents() = 0;
};
// }}}
// class definition : module {{{
template <class Impl>
class module : public module_interface {
public:
module(const bar_settings bar, string name);
~module() noexcept;
static constexpr auto EVENT_MODULE_TOGGLE = "module_toggle";
static constexpr auto EVENT_MODULE_SHOW = "module_show";
static constexpr auto EVENT_MODULE_HIDE = "module_hide";
string type() const override;
string name_raw() const override;
string name() const override;
bool running() const override;
bool visible() const override;
void start() override;
void join() final override;
void stop() override;
void halt(string error_message) override;
void teardown();
string contents() override;
bool input(const string& action, const string& data) final override;
protected:
void broadcast();
void idle();
void sleep(chrono::duration<double> duration);
template <class Clock, class Duration>
void sleep_until(chrono::time_point<Clock, Duration> point);
/**
* Wakes up the module.
*
* It should be possible to interrupt any blocking operation inside a
* module using this function.
*
* In addition, after a wake up whatever was woken up should immediately
* check whether the module is still running.
*
* Modules that don't follow this, could stall the operation of whatever
* code called this function.
*/
void wakeup();
string get_format() const;
string get_output();
void set_visible(bool value);
void action_module_toggle();
void action_module_show();
void action_module_hide();
protected:
signal_emitter& m_sig;
const bar_settings m_bar;
const logger& m_log;
const config& m_conf;
unique_ptr<action_router> m_router;
mutex m_buildlock;
mutex m_updatelock;
mutex m_sleeplock;
std::condition_variable m_sleephandler;
const string m_name;
const string m_name_raw;
unique_ptr<builder> m_builder;
unique_ptr<module_formatter> m_formatter;
vector<thread> m_threads;
thread m_mainthread;
bool m_handle_events{true};
private:
atomic<bool> m_enabled{false};
atomic<bool> m_visible{true};
atomic<bool> m_changed{true};
string m_cache;
};
// }}}
} // namespace modules
POLYBAR_NS_END