1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
|
#pragma once
#include <algorithm>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <map>
#include <mutex>
#include "common.hpp"
#include "components/config.hpp"
#include "components/types.hpp"
#include "errors.hpp"
#include "utils/concurrency.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{};
label_t prefix{};
label_t suffix{};
rgba fg{};
rgba bg{};
rgba ul{};
rgba ol{};
size_t ulsize{0};
size_t olsize{0};
spacing_val spacing{ZERO_SPACE};
spacing_val padding{ZERO_SPACE};
spacing_val margin{ZERO_SPACE};
extent_val offset{ZERO_PX_EXTENT};
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, const config&);
~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();
virtual 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
|