From eff2e4cc49bfadd9716f3ad65854b3b0ca309b74 Mon Sep 17 00:00:00 2001 From: Joel Klinghed Date: Tue, 26 Sep 2017 23:44:35 +0200 Subject: Animate job count changes --- src/main.cc | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 95 insertions(+), 9 deletions(-) (limited to 'src/main.cc') diff --git a/src/main.cc b/src/main.cc index c5d47fd..d3017d9 100644 --- a/src/main.cc +++ b/src/main.cc @@ -12,6 +12,8 @@ #include #include +#include "animation.hh" +#include "animator.hh" #include "args.hh" #include "fake_monitor.hh" #include "io.hh" @@ -65,10 +67,11 @@ struct MwmHints { uint32_t status; }; -class MonMon : virtual Monitor::Observer { +class MonMon : virtual Monitor::Observer, virtual Animator::Observer { public: explicit MonMon(std::shared_ptr const& looper) - : looper_(looper), connected_(false), depth_(0), black_pixel_(0), + : looper_(looper), animator_(Animator::create(looper)), + connected_(false), depth_(0), black_pixel_(0), screen_(nullptr), max_jobs_(0), jobs_(0), requests_(0), x_(0), y_(0), w_(0), h_(0), rootpmap_(XCB_ATOM_NONE), desktop_window_(XCB_NONE), @@ -77,9 +80,11 @@ public: looper_->add(pipe_.read(), Looper::EV_READ, std::bind(&MonMon::pipe, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + animator_->add_observer(this); } ~MonMon() { + stop_all_animations(); unset_desktop_window(); close_pipe(); wnd_.reset(); @@ -179,6 +184,7 @@ public: depth_ = format.depth; black_pixel_ = screen->black_pixel; update_desktop_window(); + internal_draw(); xcb_map_window(wnd_.conn(), wnd_.get()); xcb_flush(wnd_.conn()); @@ -339,14 +345,22 @@ public: } private: - struct Machine { + class MachineAnimation; + + struct Machine : virtual Animator::AnimationObserver { uint32_t id; Monitor::Machine data; unsigned jobs; unsigned requests; + double x; + std::shared_ptr animation; explicit Machine(uint32_t id) - : id(id), jobs(0), requests(0) { + : id(id), jobs(0), requests(0), x(0.0) { + } + + ~Machine() override { + assert(!animation); } bool operator<(Machine const& machine) const { @@ -354,6 +368,48 @@ private: 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(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(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 unset_desktop_window() { @@ -453,6 +509,8 @@ private: } } + stop_all_animations(); + animator_.reset(); monitor_->disconnect(); looper_->exit_when_empty(); close_pipe(); @@ -462,6 +520,7 @@ private: switch (state) { case Monitor::SEARCHING: connected_ = false; + stop_all_animations(); machines_.clear(); max_jobs_ = 0; jobs_ = 0; @@ -476,19 +535,29 @@ private: } } + void stop_all_animations() { + if (!animator_) return; + for (auto& machine : machines_) { + if (machine.animation) animator_->stop(machine.animation.get()); + } + } + 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() { - internal_draw(); - xcb_flush(wnd_.conn()); + // Animator will draw soon anyway, so let it + if (animator_ && animator_->active()) return; + tick(nullptr); } static void rounded_path(cairo_t* cr, double x, double y, @@ -543,14 +612,13 @@ private: rounded_path(cairo_.get(), pad_x, y, box_width, box_height); cairo_set_source_rgba(cairo_.get(), 0.1, 0.1, 0.1, 0.7); - if (machine.jobs > 0) { + if (machine.x > 0.0) { cairo_fill_preserve(cairo_.get()); auto old = std::unique_ptr( cairo_copy_path(cairo_.get())); cairo_new_path(cairo_.get()); cairo_rectangle(cairo_.get(), pad_x, y, - (machine.jobs * box_width) / machine.data.max_jobs, - box_height); + machine.x * box_width, box_height); cairo_clip(cairo_.get()); cairo_append_path(cairo_.get(), old.get()); cairo_set_source(cairo_.get(), job_pattern_.get()); @@ -619,6 +687,7 @@ private: max_jobs_ -= it->data.max_jobs; requests_ -= it->requests; jobs_ -= it->jobs; + if (animator_) animator_->stop(it->animation.get()); machines_.erase(it); draw(); return; @@ -632,6 +701,7 @@ private: for (auto& machine : machines_) { if (machine.id == source) { ++machine.jobs; + animate(machine); } } } else { @@ -641,6 +711,7 @@ private: } if (machine.id == target) { ++machine.jobs; + animate(machine); } } ++requests_; @@ -654,6 +725,7 @@ private: for (auto& machine : machines_) { if (machine.id == source) { --machine.jobs; + animate(machine); } } } else { @@ -663,6 +735,7 @@ private: } if (machine.id == target) { --machine.jobs; + animate(machine); } } --requests_; @@ -671,8 +744,21 @@ private: draw(); } + void tick(Animator*) override { + internal_draw(); + xcb_flush(wnd_.conn()); + } + + void animate(Machine& machine) { + if (!animator_) return; + if (machine.animation) return; + machine.animation.reset(new MachineAnimation(&machine)); + animator_->start(machine.animation, &machine); + } + std::shared_ptr looper_; std::unique_ptr monitor_; + std::unique_ptr animator_; bool connected_; io::pipe pipe_; std::shared_ptr atoms_; -- cgit v1.3