diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/icecc.cc | 357 | ||||
| -rw-r--r-- | src/icecc.hh | 21 | ||||
| -rw-r--r-- | src/main.cc | 344 |
3 files changed, 380 insertions, 342 deletions
diff --git a/src/icecc.cc b/src/icecc.cc new file mode 100644 index 0000000..5e99981 --- /dev/null +++ b/src/icecc.cc @@ -0,0 +1,357 @@ +#include "common.hh" + +#include <algorithm> +#include <math.h> + +#include "animation.hh" +#include "args.hh" +#include "blissful_monitor.hh" +#include "cairo.hh" +#include "fake_monitor.hh" +#include "icecc.hh" +#include "monitor.hh" +#include "pango.hh" + +namespace { + +class IceccMonMonImpl : public IceccMonMon, virtual Monitor::Observer { +public: + IceccMonMonImpl(std::shared_ptr<PollLooper> const& looper, unsigned columns) + : IceccMonMon(looper), connected_(false), max_jobs_(0), jobs_(0), + requests_(0), force_columns_(columns) { + } + + void connect(Args const* args) override { + std::unique_ptr<Monitor> monitor; +#if FAKE_MONITOR + monitor = FakeMonitor::create(looper_); +#else + monitor = Monitor::create(looper_); +#endif + monitor_ = BlissfulMonitor::create(looper_, std::move(monitor)); + monitor_->add_observer(this); + monitor_->connect(args->arg("network", ""), + args->arg("scheduler", "")); + } + +protected: + void width_changed() override { + job_pattern_.reset(); + } + +#if FAKE_MONITOR + void do_toggle_fakes() override { + monitor_->toggle_fakes(); + } +#endif + +private: + class MachineAnimation; + + struct Machine : virtual Animator::AnimationObserver { + uint32_t id; + Monitor::Machine data; + unsigned jobs; + unsigned requests; + double x; + std::shared_ptr<MachineAnimation> animation; + + explicit Machine(uint32_t id) + : id(id), jobs(0), requests(0), x(0.0) { + } + + Machine(Machine const&) = delete; + Machine& operator=(Machine const&) = delete; + + ~Machine() override { + assert(!animation); + } + + bool operator<(Machine const& machine) const { + if (data.name < machine.data.name) return true; + if (data.name > machine.data.name) return false; + return id < machine.id; + } + + void ticked(Animator*, Animation*, double value) override { + x = value; + } + + void stopped(Animator*, Animation*) override { + x = static_cast<double>(jobs) / data.max_jobs; + animation.reset(); + } + }; + + class MachineAnimation : public Animation { + public: + explicit MachineAnimation(Machine* machine) + : machine_(machine), last_(0.0) { + } + + bool tick(double duration, double* value) override { + auto target = static_cast<double>(machine_->jobs) + / machine_->data.max_jobs; + if (duration == 0.0) { + last_ = duration; + *value = machine_->x; + return machine_->x != target; + } else { + double diff = target - machine_->x; + double max = (duration - last_) * .5; + last_ = duration; + if (fabs(diff) > max) { + diff = diff < 0.0 ? -max : max; + *value = machine_->x + diff; + return true; + } else { + *value = target; + return false; + } + } + } + + private: + Machine* machine_; + double last_; + }; + + + void state(Monitor*, Monitor::State state) override { + switch (state) { + case Monitor::SEARCHING: + connected_ = false; + stop_all_animations(); + machines_.clear(); + max_jobs_ = 0; + jobs_ = 0; + requests_ = 0; + if (!wnd_) return; + draw(); + break; + case Monitor::CONNECTED: + connected_ = true; + draw(); + break; + } + } + + void stop_all_animations() override { + if (!animator_) return; + for (auto& machine : machines_) { + if (machine->animation) animator_->stop(machine->animation.get()); + } + } + + void internal_quit() override { + monitor_->disconnect(); + } + + void update(Machine* machine) { + auto old = machine->data.max_jobs; + machine->data = monitor_->machine(machine->id); + if (old < machine->data.max_jobs) { + max_jobs_ += machine->data.max_jobs - old; + if (machine->jobs) animate(machine); + } else if (old > machine->data.max_jobs) { + max_jobs_ -= old - machine->data.max_jobs; + if (machine->jobs) animate(machine); + } + } + + void draw_content(cairo_t* cairo, PangoLayout* layout, uint16_t w, uint16_t h) + override { + auto const pad_x = std::min(9.0, w / 20.0), pad_y = pad_x; + auto const margin_x = std::min(7.5, w / 20.0), margin_y = margin_x; + auto y = pad_y; + auto const columns = force_columns_ ? force_columns_ : std::max(1, w / h); + auto const box_width = (w - pad_x) / columns - pad_x; + auto const box_height = box_height_ + margin_y * 2; + if (!job_pattern_) { + job_pattern_.reset(cairo_pattern_create_linear(0.0, 0.0, box_width, 0.0)); + cairo_pattern_add_color_stop_rgb(job_pattern_.get(), 0.000000, + 0.000000, 0.000000, 0.000000); + cairo_pattern_add_color_stop_rgb(job_pattern_.get(), 0.594324, + 0.729412, 0.000000, 0.000000); + cairo_pattern_add_color_stop_rgb(job_pattern_.get(), 0.809683, + 1.000000, 0.545098, 0.196078); + cairo_pattern_add_color_stop_rgb(job_pattern_.get(), 0.899833, + 0.972549, 0.937255, 0.074510); + cairo_pattern_add_color_stop_rgb(job_pattern_.get(), 1.000000, + 0.976471, 0.968627, 0.831373); + } + pango_layout_set_width(layout, + (box_width - margin_x * 2) * PANGO_SCALE); + unsigned col = 0; + for (auto const& machine : machines_) { + pango_layout_set_text(layout, machine->data.name.data(), + machine->data.name.size()); + auto x = pad_x + col * (box_width + pad_x); + rounded_path(cairo, x, y, box_width, box_height); + cairo_set_source_rgba(cairo, 0.1, 0.1, 0.1, 0.7); + + if (machine->x > 0.0) { + cairo_fill_preserve(cairo); + auto old = cairo::unique_path(cairo_copy_path(cairo)); + cairo_new_path(cairo); + cairo_rectangle(cairo, x, y, machine->x * box_width, box_height); + cairo_clip(cairo); + cairo_append_path(cairo, old.get()); + cairo_matrix_t matrix; + cairo_matrix_init_translate(&matrix, -x, 0); + cairo_pattern_set_matrix(job_pattern_.get(), &matrix); + cairo_set_source(cairo, job_pattern_.get()); + cairo_fill(cairo); + cairo_reset_clip(cairo); + } else { + cairo_fill(cairo); + } + if (machine->requests > 0) { + auto radius = box_height / 10.0; + cairo_set_line_width(cairo, 1.5); + cairo_new_path(cairo); + cairo_move_to(cairo, x + box_width - radius, y); + cairo_rel_line_to(cairo, + -(machine->requests * (box_width - radius * 2)) + / requests_, 0); + cairo_set_source_rgb(cairo, 0, 0.6, 0); + cairo_stroke(cairo); + } + + cairo_move_to(cairo, x + margin_x, y + margin_y); + pango_cairo_layout_path(cairo, layout); + cairo_set_source_rgb(cairo, 0.0, 0.0, 0.0); + cairo_set_line_cap(cairo, CAIRO_LINE_CAP_ROUND); + cairo_set_line_width(cairo, 2.0); + cairo_stroke(cairo); + cairo_set_source_rgb(cairo, 1.0, 1.0, 1.0); + cairo_move_to(cairo, x + margin_x, y + margin_y); + pango_cairo_show_layout(cairo, layout); + if (++col == columns) { + col = 0; + y += box_height + pad_y * 2; + if (y >= h) break; + } + } + } + + void added_machine(Monitor*, uint32_t id) override { + auto machine = std::make_unique<Machine>(id); + update(machine.get()); + machines_.emplace( + std::lower_bound(machines_.begin(), machines_.end(), machine, + compare_machine), + std::move(machine)); + draw(); + } + + static bool compare_machine(std::unique_ptr<Machine> const& m1, + std::unique_ptr<Machine> const& m2) { + return *m1 < *m2; + } + + void updated_machine(Monitor*, uint32_t id) override { + for (auto& machine : machines_) { + if (machine->id == id) { + auto old = machine->data.name; + update(machine.get()); + if (machine->data.name != old) { + // TODO: Perhaps remove and insert instead? + std::sort(machines_.begin(), machines_.end(), compare_machine); + } + draw(); + return; + } + } + assert(false); + } + + void removed_machine(Monitor*, uint32_t id) override { + for (auto it = machines_.begin(); it != machines_.end(); ++it) { + if ((*it)->id == id) { + max_jobs_ -= (*it)->data.max_jobs; + requests_ -= (*it)->requests; + jobs_ -= (*it)->jobs; + if (animator_) animator_->stop((*it)->animation.get()); + machines_.erase(it); + draw(); + return; + } + } + assert(false); + } + + void added_job(Monitor*, uint32_t source, uint32_t target) override { + if (source == target) { + for (auto& machine : machines_) { + if (machine->id == source) { + ++machine->jobs; + animate(machine.get()); + } + } + } else { + for (auto& machine : machines_) { + if (machine->id == source) { + ++machine->requests; + } + if (machine->id == target) { + ++machine->jobs; + animate(machine.get()); + } + } + ++requests_; + } + ++jobs_; + draw(); + } + + void removed_job(Monitor*, uint32_t source, uint32_t target) override { + if (source == target) { + for (auto& machine : machines_) { + if (machine->id == source) { + --machine->jobs; + animate(machine.get()); + } + } + } else { + for (auto& machine : machines_) { + if (machine->id == source) { + --machine->requests; + } + if (machine->id == target) { + --machine->jobs; + animate(machine.get()); + } + } + --requests_; + } + --jobs_; + draw(); + } + + void animate(Machine* machine) { + if (!animator_) return; + if (machine->animation) return; + machine->animation = std::make_unique<MachineAnimation>(machine); + animator_->start(machine->animation, machine); + } + + std::unique_ptr<Monitor> monitor_; + bool connected_; + std::vector<std::unique_ptr<Machine>> machines_; + unsigned max_jobs_; + unsigned jobs_; + unsigned requests_; + cairo::unique_pattern job_pattern_; + unsigned force_columns_; +}; + +} // namespace + +IceccMonMon::IceccMonMon(std::shared_ptr<PollLooper> const& looper) + : MonMon(looper) {} + +std::unique_ptr<IceccMonMon> create_icecc_monmon( + std::shared_ptr<PollLooper> const& looper, unsigned columns) { + return std::make_unique<IceccMonMonImpl>(looper, columns); +} diff --git a/src/icecc.hh b/src/icecc.hh new file mode 100644 index 0000000..2b3cdf0 --- /dev/null +++ b/src/icecc.hh @@ -0,0 +1,21 @@ +#ifndef ICECC_HH +#define ICECC_HH + +#include <memory> + +#include "monmon.hh" + +class Args; + +class IceccMonMon : public MonMon { +public: + virtual void connect(Args const* args) = 0; + +protected: + IceccMonMon(std::shared_ptr<PollLooper> const& looper); +}; + +std::unique_ptr<IceccMonMon> create_icecc_monmon( + std::shared_ptr<PollLooper> const& looper, unsigned columns); + +#endif // ICECC_HH diff --git a/src/main.cc b/src/main.cc index c8be11c..53e9a7f 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,361 +1,21 @@ #include "common.hh" -#include <algorithm> #include <iostream> -#include <math.h> #include <string.h> #include <thread> #include <xcb/xcb_event.h> -#include <xcb/xcb_icccm.h> #include <xcb/xcb_keysyms.h> -#include "animation.hh" #include "animator.hh" #include "args.hh" -#include "blissful_monitor.hh" -#include "cairo.hh" -#include "fake_monitor.hh" #include "io.hh" -#include "monitor.hh" +#include "icecc.hh" #include "monmon.hh" -#include "pango.hh" #include "poll_looper.hh" #include "x.hh" namespace { -class IceccMonMon : public MonMon, virtual Monitor::Observer { -public: - IceccMonMon(std::shared_ptr<PollLooper> const& looper, unsigned columns) - : MonMon(looper), connected_(false), max_jobs_(0), jobs_(0), requests_(0), - force_columns_(columns) { - } - - void connect(Args const* args) { - std::unique_ptr<Monitor> monitor; -#if FAKE_MONITOR - monitor = FakeMonitor::create(looper_); -#else - monitor = Monitor::create(looper_); -#endif - monitor_ = BlissfulMonitor::create(looper_, std::move(monitor)); - monitor_->add_observer(this); - monitor_->connect(args->arg("network", ""), - args->arg("scheduler", "")); - } - -protected: - void width_changed() override { - job_pattern_.reset(); - } - -#if FAKE_MONITOR - void do_toggle_fakes() override { - monitor_->toggle_fakes(); - } -#endif - -private: - class MachineAnimation; - - struct Machine : virtual Animator::AnimationObserver { - uint32_t id; - Monitor::Machine data; - unsigned jobs; - unsigned requests; - double x; - std::shared_ptr<MachineAnimation> animation; - - explicit Machine(uint32_t id) - : id(id), jobs(0), requests(0), x(0.0) { - } - - Machine(Machine const&) = delete; - Machine& operator=(Machine const&) = delete; - - ~Machine() override { - assert(!animation); - } - - bool operator<(Machine const& machine) const { - if (data.name < machine.data.name) return true; - if (data.name > machine.data.name) return false; - return id < machine.id; - } - - void ticked(Animator*, Animation*, double value) override { - x = value; - } - - void stopped(Animator*, Animation*) override { - x = static_cast<double>(jobs) / data.max_jobs; - animation.reset(); - } - }; - - class MachineAnimation : public Animation { - public: - explicit MachineAnimation(Machine* machine) - : machine_(machine), last_(0.0) { - } - - bool tick(double duration, double* value) override { - auto target = static_cast<double>(machine_->jobs) - / machine_->data.max_jobs; - if (duration == 0.0) { - last_ = duration; - *value = machine_->x; - return machine_->x != target; - } else { - double diff = target - machine_->x; - double max = (duration - last_) * .5; - last_ = duration; - if (fabs(diff) > max) { - diff = diff < 0.0 ? -max : max; - *value = machine_->x + diff; - return true; - } else { - *value = target; - return false; - } - } - } - - private: - Machine* machine_; - double last_; - }; - - - void state(Monitor*, Monitor::State state) override { - switch (state) { - case Monitor::SEARCHING: - connected_ = false; - stop_all_animations(); - machines_.clear(); - max_jobs_ = 0; - jobs_ = 0; - requests_ = 0; - if (!wnd_) return; - draw(); - break; - case Monitor::CONNECTED: - connected_ = true; - draw(); - break; - } - } - - void stop_all_animations() override { - if (!animator_) return; - for (auto& machine : machines_) { - if (machine->animation) animator_->stop(machine->animation.get()); - } - } - - void internal_quit() override { - monitor_->disconnect(); - } - - void update(Machine* machine) { - auto old = machine->data.max_jobs; - machine->data = monitor_->machine(machine->id); - if (old < machine->data.max_jobs) { - max_jobs_ += machine->data.max_jobs - old; - if (machine->jobs) animate(machine); - } else if (old > machine->data.max_jobs) { - max_jobs_ -= old - machine->data.max_jobs; - if (machine->jobs) animate(machine); - } - } - - void draw_content(cairo_t* cairo, PangoLayout* layout, uint16_t w, uint16_t h) - override { - auto const pad_x = std::min(9.0, w / 20.0), pad_y = pad_x; - auto const margin_x = std::min(7.5, w / 20.0), margin_y = margin_x; - auto y = pad_y; - auto const columns = force_columns_ ? force_columns_ : std::max(1, w / h); - auto const box_width = (w - pad_x) / columns - pad_x; - auto const box_height = box_height_ + margin_y * 2; - if (!job_pattern_) { - job_pattern_.reset(cairo_pattern_create_linear(0.0, 0.0, box_width, 0.0)); - cairo_pattern_add_color_stop_rgb(job_pattern_.get(), 0.000000, - 0.000000, 0.000000, 0.000000); - cairo_pattern_add_color_stop_rgb(job_pattern_.get(), 0.594324, - 0.729412, 0.000000, 0.000000); - cairo_pattern_add_color_stop_rgb(job_pattern_.get(), 0.809683, - 1.000000, 0.545098, 0.196078); - cairo_pattern_add_color_stop_rgb(job_pattern_.get(), 0.899833, - 0.972549, 0.937255, 0.074510); - cairo_pattern_add_color_stop_rgb(job_pattern_.get(), 1.000000, - 0.976471, 0.968627, 0.831373); - } - pango_layout_set_width(layout, - (box_width - margin_x * 2) * PANGO_SCALE); - unsigned col = 0; - for (auto const& machine : machines_) { - pango_layout_set_text(layout, machine->data.name.data(), - machine->data.name.size()); - auto x = pad_x + col * (box_width + pad_x); - rounded_path(cairo, x, y, box_width, box_height); - cairo_set_source_rgba(cairo, 0.1, 0.1, 0.1, 0.7); - - if (machine->x > 0.0) { - cairo_fill_preserve(cairo); - auto old = cairo::unique_path(cairo_copy_path(cairo)); - cairo_new_path(cairo); - cairo_rectangle(cairo, x, y, machine->x * box_width, box_height); - cairo_clip(cairo); - cairo_append_path(cairo, old.get()); - cairo_matrix_t matrix; - cairo_matrix_init_translate(&matrix, -x, 0); - cairo_pattern_set_matrix(job_pattern_.get(), &matrix); - cairo_set_source(cairo, job_pattern_.get()); - cairo_fill(cairo); - cairo_reset_clip(cairo); - } else { - cairo_fill(cairo); - } - if (machine->requests > 0) { - auto radius = box_height / 10.0; - cairo_set_line_width(cairo, 1.5); - cairo_new_path(cairo); - cairo_move_to(cairo, x + box_width - radius, y); - cairo_rel_line_to(cairo, - -(machine->requests * (box_width - radius * 2)) - / requests_, 0); - cairo_set_source_rgb(cairo, 0, 0.6, 0); - cairo_stroke(cairo); - } - - cairo_move_to(cairo, x + margin_x, y + margin_y); - pango_cairo_layout_path(cairo, layout); - cairo_set_source_rgb(cairo, 0.0, 0.0, 0.0); - cairo_set_line_cap(cairo, CAIRO_LINE_CAP_ROUND); - cairo_set_line_width(cairo, 2.0); - cairo_stroke(cairo); - cairo_set_source_rgb(cairo, 1.0, 1.0, 1.0); - cairo_move_to(cairo, x + margin_x, y + margin_y); - pango_cairo_show_layout(cairo, layout); - if (++col == columns) { - col = 0; - y += box_height + pad_y * 2; - if (y >= h) break; - } - } - } - - void added_machine(Monitor*, uint32_t id) override { - auto machine = std::make_unique<Machine>(id); - update(machine.get()); - machines_.emplace( - std::lower_bound(machines_.begin(), machines_.end(), machine, - compare_machine), - std::move(machine)); - draw(); - } - - static bool compare_machine(std::unique_ptr<Machine> const& m1, - std::unique_ptr<Machine> const& m2) { - return *m1 < *m2; - } - - void updated_machine(Monitor*, uint32_t id) override { - for (auto& machine : machines_) { - if (machine->id == id) { - auto old = machine->data.name; - update(machine.get()); - if (machine->data.name != old) { - // TODO: Perhaps remove and insert instead? - std::sort(machines_.begin(), machines_.end(), compare_machine); - } - draw(); - return; - } - } - assert(false); - } - - void removed_machine(Monitor*, uint32_t id) override { - for (auto it = machines_.begin(); it != machines_.end(); ++it) { - if ((*it)->id == id) { - max_jobs_ -= (*it)->data.max_jobs; - requests_ -= (*it)->requests; - jobs_ -= (*it)->jobs; - if (animator_) animator_->stop((*it)->animation.get()); - machines_.erase(it); - draw(); - return; - } - } - assert(false); - } - - void added_job(Monitor*, uint32_t source, uint32_t target) override { - if (source == target) { - for (auto& machine : machines_) { - if (machine->id == source) { - ++machine->jobs; - animate(machine.get()); - } - } - } else { - for (auto& machine : machines_) { - if (machine->id == source) { - ++machine->requests; - } - if (machine->id == target) { - ++machine->jobs; - animate(machine.get()); - } - } - ++requests_; - } - ++jobs_; - draw(); - } - - void removed_job(Monitor*, uint32_t source, uint32_t target) override { - if (source == target) { - for (auto& machine : machines_) { - if (machine->id == source) { - --machine->jobs; - animate(machine.get()); - } - } - } else { - for (auto& machine : machines_) { - if (machine->id == source) { - --machine->requests; - } - if (machine->id == target) { - --machine->jobs; - animate(machine.get()); - } - } - --requests_; - } - --jobs_; - draw(); - } - - void animate(Machine* machine) { - if (!animator_) return; - if (machine->animation) return; - machine->animation = std::make_unique<MachineAnimation>(machine); - animator_->start(machine->animation, machine); - } - - std::unique_ptr<Monitor> monitor_; - bool connected_; - std::vector<std::unique_ptr<Machine>> machines_; - unsigned max_jobs_; - unsigned jobs_; - unsigned requests_; - cairo::unique_pattern job_pattern_; - unsigned force_columns_; -}; - struct XcbKeySymbolsDelete { void operator()(xcb_key_symbols_t* ptr) const { if (ptr) xcb_key_symbols_free(ptr); @@ -540,7 +200,7 @@ int main(int argc, char** argv) { atoms->preload("__MONMON_QUIT"); MonMon::preload(atoms.get()); std::shared_ptr<x::Ewmh> ewmh(x::Ewmh::create(conn, screen_index)); - auto monmon = std::make_shared<IceccMonMon>(looper, columns); + std::shared_ptr<IceccMonMon> monmon(create_icecc_monmon(looper, columns)); monmon->init(conn, screen, format, atoms, ewmh, 400, 400, args->is_set("titlebar"), args->is_set("black")); monmon->connect(args.get()); |
