mirror of
https://github.com/polybar/polybar.git
synced 2024-11-25 13:55:47 -05:00
wip: Window autohide
This commit is contained in:
parent
3aa7c3b106
commit
81e6fb062f
11 changed files with 257 additions and 61 deletions
|
@ -1,17 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
#include "common.hpp"
|
||||
#include "components/types.hpp"
|
||||
#include "errors.hpp"
|
||||
#include "events/signal_fwd.hpp"
|
||||
#include "events/signal_receiver.hpp"
|
||||
#include "x11/events.hpp"
|
||||
#include "x11/types.hpp"
|
||||
#include "x11/window.hpp"
|
||||
|
||||
POLYBAR_NS
|
||||
|
||||
namespace chrono = std::chrono;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
// fwd
|
||||
class connection;
|
||||
class logger;
|
||||
|
@ -22,8 +27,12 @@ class signal_emitter;
|
|||
class taskqueue;
|
||||
class tray_manager;
|
||||
|
||||
namespace sig_ui = signals::ui;
|
||||
namespace sig_ev = signals::eventqueue;
|
||||
|
||||
class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::property_notify, evt::enter_notify,
|
||||
evt::leave_notify, evt::destroy_notify, evt::client_message> {
|
||||
evt::leave_notify, evt::destroy_notify, evt::client_message>,
|
||||
public signal_receiver<SIGN_PRIORITY_BAR, sig_ui::tick, sig_ui::shade_window, sig_ui::unshade_window, sig_ui::dim_window> {
|
||||
public:
|
||||
using make_type = unique_ptr<bar>;
|
||||
static make_type make();
|
||||
|
@ -52,6 +61,11 @@ class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::propert
|
|||
void handle(const evt::expose& evt);
|
||||
void handle(const evt::property_notify& evt);
|
||||
|
||||
bool on(const sig_ui::unshade_window&);
|
||||
bool on(const sig_ui::shade_window&);
|
||||
bool on(const sig_ui::tick&);
|
||||
bool on(const sig_ui::dim_window&);
|
||||
|
||||
private:
|
||||
connection& m_connection;
|
||||
signal_emitter& m_sig;
|
||||
|
@ -73,6 +87,8 @@ class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::propert
|
|||
|
||||
event_timer m_buttonpress{0L, 5L};
|
||||
event_timer m_doubleclick{0L, 150L};
|
||||
|
||||
double m_anim_step{0};
|
||||
};
|
||||
|
||||
POLYBAR_NS_END
|
||||
|
|
|
@ -16,17 +16,20 @@ using namespace std::chrono_literals;
|
|||
|
||||
class taskqueue : non_copyable_mixin<taskqueue> {
|
||||
public:
|
||||
struct deferred : non_copyable_mixin<deferred> {
|
||||
struct deferred {
|
||||
using clock = chrono::high_resolution_clock;
|
||||
using duration = chrono::milliseconds;
|
||||
using timepoint = chrono::time_point<chrono::high_resolution_clock, duration>;
|
||||
using callback = function<void()>;
|
||||
using timepoint = chrono::time_point<clock, duration>;
|
||||
using callback = function<void(size_t remaining)>;
|
||||
|
||||
explicit deferred(string&& id, timepoint&& tp, callback&& fn)
|
||||
: id(forward<decltype(id)>(id)), when(forward<decltype(tp)>(tp)), func(forward<decltype(fn)>(fn)) {}
|
||||
explicit deferred(string id, timepoint now, duration wait, callback fn, size_t count)
|
||||
: id(move(id)), func(move(fn)), now(move(now)), wait(move(wait)), count(move(count)) {}
|
||||
|
||||
const string id;
|
||||
const timepoint when;
|
||||
const callback func;
|
||||
timepoint now;
|
||||
duration wait;
|
||||
size_t count;
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -36,10 +39,13 @@ class taskqueue : non_copyable_mixin<taskqueue> {
|
|||
explicit taskqueue();
|
||||
~taskqueue();
|
||||
|
||||
void defer(string&& id, deferred::duration&& ms, deferred::callback&& fn);
|
||||
void defer_unique(string&& id, deferred::duration&& ms, deferred::callback&& fn);
|
||||
void defer(
|
||||
string id, deferred::duration ms, deferred::callback fn, deferred::duration offset = 0ms, size_t count = 1);
|
||||
void defer_unique(
|
||||
string id, deferred::duration ms, deferred::callback fn, deferred::duration offset = 0ms, size_t count = 1);
|
||||
|
||||
bool has_deferred(string&& id);
|
||||
bool exist(const string& id);
|
||||
bool purge(const string& id);
|
||||
|
||||
protected:
|
||||
void tick();
|
||||
|
|
|
@ -151,6 +151,12 @@ struct bar_settings {
|
|||
bool dimmed{false};
|
||||
double dimvalue{1.0};
|
||||
|
||||
bool shaded{false};
|
||||
struct size shade_size {
|
||||
1U, 1U
|
||||
};
|
||||
position shade_pos{1U, 1U};
|
||||
|
||||
const xcb_rectangle_t inner_area(bool abspos = false) const {
|
||||
xcb_rectangle_t rect{0, 0, size.w, size.h};
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ namespace signals {
|
|||
DEFINE_VALUE_SIGNAL(1, process_quit, event);
|
||||
DEFINE_VALUE_SIGNAL(2, process_update, event);
|
||||
DEFINE_VALUE_SIGNAL(3, process_input, string);
|
||||
DEFINE_VALUE_SIGNAL(4, process_check, event);
|
||||
DEFINE_SIGNAL(4, process_check);
|
||||
}
|
||||
|
||||
namespace ipc {
|
||||
|
@ -105,9 +105,12 @@ namespace signals {
|
|||
}
|
||||
|
||||
namespace ui {
|
||||
DEFINE_VALUE_SIGNAL(50, button_press, string);
|
||||
DEFINE_VALUE_SIGNAL(51, visibility_change, bool);
|
||||
DEFINE_VALUE_SIGNAL(52, dim_window, double);
|
||||
DEFINE_SIGNAL(50, tick);
|
||||
DEFINE_VALUE_SIGNAL(51, button_press, string);
|
||||
DEFINE_VALUE_SIGNAL(52, visibility_change, bool);
|
||||
DEFINE_VALUE_SIGNAL(53, dim_window, double);
|
||||
DEFINE_SIGNAL(54, shade_window);
|
||||
DEFINE_SIGNAL(55, unshade_window);
|
||||
}
|
||||
|
||||
namespace parser {
|
||||
|
|
|
@ -17,9 +17,12 @@ namespace signals {
|
|||
struct process_action;
|
||||
}
|
||||
namespace ui {
|
||||
struct tick;
|
||||
struct button_press;
|
||||
struct visibility_change;
|
||||
struct dim_window;
|
||||
struct shade_window;
|
||||
struct unshade_window;
|
||||
}
|
||||
namespace parser {
|
||||
struct change_background;
|
||||
|
|
|
@ -283,6 +283,8 @@ bar::bar(connection& conn, signal_emitter& emitter, const config& config, const
|
|||
m_tray->setup(static_cast<const bar_settings&>(m_opts));
|
||||
|
||||
broadcast_visibility();
|
||||
|
||||
m_sig.attach(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -291,6 +293,7 @@ bar::bar(connection& conn, signal_emitter& emitter, const config& config, const
|
|||
bar::~bar() {
|
||||
std::lock_guard<std::mutex> guard(m_mutex);
|
||||
m_connection.detach_sink(this, SINK_PRIORITY_BAR);
|
||||
m_sig.detach(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -313,6 +316,10 @@ void bar::parse(const string& data, bool force) {
|
|||
|
||||
std::lock_guard<std::mutex> guard(m_mutex, std::adopt_lock);
|
||||
|
||||
if (m_opts.shaded) {
|
||||
return m_log.trace("bar: Ignoring update (shaded)");
|
||||
}
|
||||
|
||||
if (data == m_lastinput && !force) {
|
||||
return;
|
||||
}
|
||||
|
@ -449,10 +456,7 @@ void bar::broadcast_visibility() {
|
|||
* Event handler for XCB_DESTROY_NOTIFY events
|
||||
*/
|
||||
void bar::handle(const evt::client_message& evt) {
|
||||
if (evt->type != WM_PROTOCOLS || evt->data.data32[0] != WM_DELETE_WINDOW) {
|
||||
return;
|
||||
}
|
||||
if (evt->window == m_opts.window) {
|
||||
if (evt->type == WM_PROTOCOLS && evt->data.data32[0] == WM_DELETE_WINDOW && evt->window == m_opts.window) {
|
||||
m_log.err("Bar window has been destroyed, shutting down...");
|
||||
m_connection.disconnect();
|
||||
}
|
||||
|
@ -474,11 +478,18 @@ void bar::handle(const evt::destroy_notify& evt) {
|
|||
* _NET_WM_WINDOW_OPACITY atom value
|
||||
*/
|
||||
void bar::handle(const evt::enter_notify&) {
|
||||
#if DEBUG
|
||||
if (m_opts.origin == edge::TOP) {
|
||||
m_taskqueue->defer_unique("window-hover", 25ms, [&](size_t) { m_sig.emit(sig_ui::unshade_window{}); });
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_opts.dimmed) {
|
||||
window win{m_connection, m_opts.window};
|
||||
wm_util::set_wm_window_opacity(m_connection, m_opts.window, 1.0 * 0xFFFFFFFF);
|
||||
m_sig.emit(dim_window{1.0});
|
||||
m_opts.dimmed = false;
|
||||
m_taskqueue->defer_unique("window-dim", 25ms, [&](size_t) {
|
||||
m_opts.dimmed = false;
|
||||
m_sig.emit(dim_window{1.0});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -489,11 +500,18 @@ void bar::handle(const evt::enter_notify&) {
|
|||
* _NET_WM_WINDOW_OPACITY atom value
|
||||
*/
|
||||
void bar::handle(const evt::leave_notify&) {
|
||||
#if DEBUG
|
||||
if (m_opts.origin == edge::TOP) {
|
||||
m_taskqueue->defer_unique("window-hover", 25ms, [&](size_t) { m_sig.emit(sig_ui::shade_window{}); });
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!m_opts.dimmed) {
|
||||
window win{m_connection, m_opts.window};
|
||||
wm_util::set_wm_window_opacity(m_connection, m_opts.window, m_opts.dimvalue * 0xFFFFFFFF);
|
||||
m_sig.emit(dim_window{double{m_opts.dimvalue}});
|
||||
m_opts.dimmed = true;
|
||||
m_taskqueue->defer_unique("window-dim", 3s, [&](size_t) {
|
||||
m_opts.dimmed = true;
|
||||
m_sig.emit(dim_window{double{m_opts.dimvalue}});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -518,7 +536,7 @@ void bar::handle(const evt::button_press& evt) {
|
|||
m_buttonpress_btn = static_cast<mousebtn>(evt->detail);
|
||||
m_buttonpress_pos = evt->event_x;
|
||||
|
||||
const auto deferred_fn = [&] {
|
||||
const auto deferred_fn = [&](size_t) {
|
||||
for (auto&& action : m_renderer->get_actions()) {
|
||||
if (action.button == m_buttonpress_btn && !action.active && action.test(m_buttonpress_pos)) {
|
||||
m_log.trace("Found matching input area");
|
||||
|
@ -537,13 +555,13 @@ void bar::handle(const evt::button_press& evt) {
|
|||
};
|
||||
|
||||
const auto check_double = [&](string&& id, mousebtn&& btn) {
|
||||
if (!m_taskqueue->has_deferred(string{id})) {
|
||||
if (!m_taskqueue->exist(id)) {
|
||||
m_doubleclick.event = evt->time;
|
||||
m_taskqueue->defer_unique(string{id}, chrono::milliseconds{m_doubleclick.offset}, deferred_fn);
|
||||
m_taskqueue->defer(id, taskqueue::deferred::duration{m_doubleclick.offset}, deferred_fn);
|
||||
} else if (m_doubleclick.deny(evt->time)) {
|
||||
m_doubleclick.event = 0;
|
||||
m_buttonpress_btn = forward<decltype(btn)>(btn);
|
||||
m_taskqueue->defer_unique(string{id}, 0ms, deferred_fn);
|
||||
m_buttonpress_btn = btn;
|
||||
m_taskqueue->defer_unique(id, 0ms, deferred_fn);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -554,7 +572,7 @@ void bar::handle(const evt::button_press& evt) {
|
|||
} else if (evt->detail == static_cast<uint8_t>(mousebtn::RIGHT)) {
|
||||
check_double("buttonpress-right", mousebtn::DOUBLE_RIGHT);
|
||||
} else {
|
||||
deferred_fn();
|
||||
deferred_fn(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -597,4 +615,113 @@ void bar::handle(const evt::property_notify& evt) {
|
|||
}
|
||||
}
|
||||
|
||||
bool bar::on(const sig_ui::unshade_window&) {
|
||||
m_opts.shaded = false;
|
||||
m_opts.shade_size.w = m_opts.size.w;
|
||||
m_opts.shade_size.h = m_opts.size.h;
|
||||
m_opts.shade_pos.x = m_opts.pos.x;
|
||||
m_opts.shade_pos.y = m_opts.pos.y;
|
||||
|
||||
double distance{static_cast<double>(m_opts.shade_size.h - m_connection.get_geometry(m_opts.window)->height)};
|
||||
double steptime{25.0 / 10.0};
|
||||
m_anim_step = distance / steptime / 2.0;
|
||||
|
||||
m_taskqueue->defer_unique("window-shade", 25ms,
|
||||
[&](size_t remaining) {
|
||||
if (!m_opts.shaded) {
|
||||
m_sig.emit(sig_ui::tick{});
|
||||
}
|
||||
if (!remaining) {
|
||||
m_renderer->flush(false);
|
||||
}
|
||||
if (m_opts.dimmed) {
|
||||
m_opts.dimmed = false;
|
||||
m_sig.emit(dim_window{1.0});
|
||||
}
|
||||
},
|
||||
taskqueue::deferred::duration{25ms}, 10U);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bar::on(const sig_ui::shade_window&) {
|
||||
taskqueue::deferred::duration offset{2000ms};
|
||||
|
||||
if (!m_opts.shaded && m_opts.shade_size.h != m_opts.size.h) {
|
||||
offset = taskqueue::deferred::duration{25ms};
|
||||
}
|
||||
|
||||
m_opts.shaded = true;
|
||||
m_opts.shade_size.h = 5;
|
||||
m_opts.shade_size.w = m_opts.size.w;
|
||||
m_opts.shade_pos.x = m_opts.pos.x;
|
||||
m_opts.shade_pos.y = m_opts.pos.y;
|
||||
|
||||
if (m_opts.origin == edge::BOTTOM) {
|
||||
m_opts.shade_pos.y = m_opts.pos.y + m_opts.size.h - m_opts.shade_size.h;
|
||||
}
|
||||
|
||||
double distance{static_cast<double>(m_connection.get_geometry(m_opts.window)->height - m_opts.shade_size.h)};
|
||||
double steptime{25.0 / 10.0};
|
||||
m_anim_step = distance / steptime / 2.0;
|
||||
|
||||
m_taskqueue->defer_unique("window-shade", 25ms,
|
||||
[&](size_t remaining) {
|
||||
if (m_opts.shaded) {
|
||||
m_sig.emit(sig_ui::tick{});
|
||||
}
|
||||
if (!remaining) {
|
||||
m_renderer->flush(false);
|
||||
}
|
||||
if (!m_opts.dimmed) {
|
||||
m_opts.dimmed = true;
|
||||
m_sig.emit(dim_window{double{m_opts.dimvalue}});
|
||||
}
|
||||
},
|
||||
move(offset), 10U);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bar::on(const sig_ui::tick&) {
|
||||
auto geom = m_connection.get_geometry(m_opts.window);
|
||||
if (geom->y == m_opts.shade_pos.y && geom->height == m_opts.shade_size.h) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t mask{0};
|
||||
uint32_t values[7]{0};
|
||||
xcb_params_configure_window_t params{};
|
||||
|
||||
if (m_opts.shade_size.h > geom->height) {
|
||||
XCB_AUX_ADD_PARAM(&mask, ¶ms, height, static_cast<uint16_t>(geom->height + m_anim_step));
|
||||
params.height = std::max(1U, std::min(params.height, static_cast<uint32_t>(m_opts.shade_size.h)));
|
||||
} else if (m_opts.shade_size.h < geom->height) {
|
||||
XCB_AUX_ADD_PARAM(&mask, ¶ms, height, static_cast<uint16_t>(geom->height - m_anim_step));
|
||||
params.height = std::max(1U, std::max(params.height, static_cast<uint32_t>(m_opts.shade_size.h)));
|
||||
}
|
||||
|
||||
if (m_opts.shade_pos.y > geom->y) {
|
||||
XCB_AUX_ADD_PARAM(&mask, ¶ms, y, static_cast<int16_t>(geom->y + m_anim_step));
|
||||
params.y = std::min(params.y, static_cast<int32_t>(m_opts.shade_pos.y));
|
||||
} else if (m_opts.shade_pos.y < geom->y) {
|
||||
XCB_AUX_ADD_PARAM(&mask, ¶ms, y, static_cast<int16_t>(geom->y - m_anim_step));
|
||||
params.y = std::max(params.y, static_cast<int32_t>(m_opts.shade_pos.y));
|
||||
}
|
||||
|
||||
xutils::pack_values(mask, ¶ms, values);
|
||||
|
||||
m_connection.configure_window(m_opts.window, mask, values);
|
||||
m_connection.flush();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bar::on(const sig_ui::dim_window& sig) {
|
||||
m_opts.dimmed = *sig.data() != 1.0;
|
||||
wm_util::set_wm_window_opacity(m_connection, m_opts.window, *sig.data() * 0xFFFFFFFF);
|
||||
m_connection.flush();
|
||||
return false;
|
||||
}
|
||||
|
||||
POLYBAR_NS_END
|
||||
|
|
|
@ -321,14 +321,14 @@ void controller::process_eventqueue() {
|
|||
}
|
||||
}
|
||||
|
||||
if (evt.type == static_cast<uint8_t>(event_type::INPUT)) {
|
||||
if (evt.type == static_cast<uint8_t>(event_type::UPDATE)) {
|
||||
m_sig.emit(sig_ev::process_update{make_update_evt(evt.flag)});
|
||||
} else if (evt.type == static_cast<uint8_t>(event_type::INPUT)) {
|
||||
process_inputdata();
|
||||
} else if (evt.type == static_cast<uint8_t>(event_type::QUIT)) {
|
||||
m_sig.emit(sig_ev::process_quit{make_quit_evt(evt.flag)});
|
||||
} else if (evt.type == static_cast<uint8_t>(event_type::UPDATE)) {
|
||||
m_sig.emit(sig_ev::process_update{make_update_evt(evt.flag)});
|
||||
} else if (evt.type == static_cast<uint8_t>(event_type::CHECK)) {
|
||||
m_sig.emit(sig_ev::process_check{make_check_evt()});
|
||||
m_sig.emit(sig_ev::process_check{});
|
||||
} else {
|
||||
m_log.warn("Unknown event type for enqueued event (%d)", evt.type);
|
||||
}
|
||||
|
|
|
@ -254,6 +254,22 @@ void renderer::flush(bool clear) {
|
|||
m_cleared = clear_area;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
if (m_bar.shaded && m_bar.origin == edge::TOP) {
|
||||
m_log.trace("renderer: copy pixmap (shaded=1, clear=%i, geom=%dx%d+%d+%d)", clear, r.width, r.height, r.x, r.y);
|
||||
auto geom = m_connection.get_geometry(m_window);
|
||||
auto x1 = 0;
|
||||
auto y1 = r.height - m_bar.shade_size.h - r.y - geom->height;
|
||||
auto x2 = r.x;
|
||||
auto y2 = r.y;
|
||||
auto w = r.width;
|
||||
auto h = r.height - m_bar.shade_size.h + geom->height;
|
||||
m_connection.copy_area(m_pixmap, m_window, m_gcontexts.at(gc::FG), x1, y1, x2, y2, w, h);
|
||||
m_connection.flush();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_log.trace("renderer: copy pixmap (clear=%i, geom=%dx%d+%d+%d)", clear, r.width, r.height, r.x, r.y);
|
||||
m_connection.copy_area(m_pixmap, m_window, m_gcontexts.at(gc::FG), 0, 0, r.x, r.y, r.width, r.height);
|
||||
|
||||
|
|
|
@ -17,11 +17,12 @@ taskqueue::taskqueue() {
|
|||
if (m_deferred.empty()) {
|
||||
m_hold.wait(guard);
|
||||
} else {
|
||||
auto now = deferred::timepoint::clock::now();
|
||||
auto wait = m_deferred.front()->when;
|
||||
auto now = deferred::clock::now();
|
||||
auto wait = m_deferred.front()->now + m_deferred.front()->wait;
|
||||
for (auto&& task : m_deferred) {
|
||||
if (task->when < wait) {
|
||||
wait = task->when;
|
||||
auto when = task->now + task->wait;
|
||||
if (when < wait) {
|
||||
wait = move(when);
|
||||
}
|
||||
}
|
||||
if (wait > now) {
|
||||
|
@ -44,41 +45,59 @@ taskqueue::~taskqueue() {
|
|||
}
|
||||
}
|
||||
|
||||
void taskqueue::defer(string&& id, deferred::duration&& ms, deferred::callback&& fn) {
|
||||
void taskqueue::defer(
|
||||
string id, deferred::duration ms, deferred::callback fn, deferred::duration offset, size_t count) {
|
||||
std::unique_lock<std::mutex> guard(m_lock);
|
||||
auto when = chrono::time_point_cast<deferred::duration>(deferred::timepoint::clock::now() + ms);
|
||||
m_deferred.emplace_back(make_unique<deferred>(forward<decltype(id)>(id), move(when), forward<decltype(fn)>(fn)));
|
||||
deferred::timepoint now{chrono::time_point_cast<deferred::duration>(deferred::clock::now() + move(offset))};
|
||||
m_deferred.emplace_back(make_unique<deferred>(move(id), move(now), move(ms), move(fn), move(count)));
|
||||
guard.unlock();
|
||||
m_hold.notify_one();
|
||||
}
|
||||
|
||||
void taskqueue::defer_unique(string&& id, deferred::duration&& ms, deferred::callback&& fn) {
|
||||
void taskqueue::defer_unique(
|
||||
string id, deferred::duration ms, deferred::callback fn, deferred::duration offset, size_t count) {
|
||||
purge(id);
|
||||
std::unique_lock<std::mutex> guard(m_lock);
|
||||
for (auto it = m_deferred.rbegin(); it != m_deferred.rend(); ++it) {
|
||||
if ((*it)->id == id) {
|
||||
m_deferred.erase(std::remove(m_deferred.begin(), m_deferred.end(), (*it)), m_deferred.end());
|
||||
}
|
||||
}
|
||||
auto when = chrono::time_point_cast<deferred::duration>(deferred::timepoint::clock::now() + ms);
|
||||
m_deferred.emplace_back(make_unique<deferred>(forward<decltype(id)>(id), move(when), forward<decltype(fn)>(fn)));
|
||||
deferred::timepoint now{chrono::time_point_cast<deferred::duration>(deferred::clock::now() + move(offset))};
|
||||
m_deferred.emplace_back(make_unique<deferred>(move(id), move(now), move(ms), move(fn), move(count)));
|
||||
guard.unlock();
|
||||
m_hold.notify_one();
|
||||
}
|
||||
|
||||
void taskqueue::tick() {
|
||||
if (m_lock.try_lock()) {
|
||||
std::lock_guard<std::mutex> guard(m_lock, std::adopt_lock);
|
||||
auto now = deferred::timepoint::clock::now();
|
||||
for (auto it = m_deferred.rbegin(); it != m_deferred.rend(); ++it) {
|
||||
if ((*it)->when <= now) {
|
||||
(*it)->func();
|
||||
m_deferred.erase(std::remove(m_deferred.begin(), m_deferred.end(), (*it)), m_deferred.end());
|
||||
}
|
||||
if (!m_lock.try_lock()) {
|
||||
return;
|
||||
}
|
||||
std::unique_lock<std::mutex> guard(m_lock, std::adopt_lock);
|
||||
auto now = chrono::time_point_cast<deferred::duration>(deferred::clock::now());
|
||||
vector<pair<deferred::callback, size_t>> cbs;
|
||||
for (auto it = m_deferred.rbegin(); it != m_deferred.rend(); ++it) {
|
||||
auto& task = *it;
|
||||
if (task->now + task->wait > now) {
|
||||
continue;
|
||||
} else if (task->count--) {
|
||||
cbs.emplace_back(make_pair(task->func, task->count));
|
||||
task->now = now;
|
||||
} else {
|
||||
m_deferred.erase(std::remove_if(m_deferred.begin(), m_deferred.end(),
|
||||
[&](const unique_ptr<deferred>& d) { return d == task; }),
|
||||
m_deferred.end());
|
||||
}
|
||||
}
|
||||
guard.unlock();
|
||||
for (auto&& p : cbs) {
|
||||
p.first(p.second);
|
||||
}
|
||||
}
|
||||
|
||||
bool taskqueue::has_deferred(string&& id) {
|
||||
bool taskqueue::purge(const string& id) {
|
||||
std::lock_guard<std::mutex> guard(m_lock);
|
||||
return m_deferred.erase(std::remove_if(m_deferred.begin(), m_deferred.end(),
|
||||
[id](const unique_ptr<deferred>& d) { return d->id == id; }),
|
||||
m_deferred.end()) == m_deferred.end();
|
||||
}
|
||||
|
||||
bool taskqueue::exist(const string& id) {
|
||||
std::lock_guard<std::mutex> guard(m_lock);
|
||||
for (const auto& task : m_deferred) {
|
||||
if (task->id == id) {
|
||||
|
|
|
@ -1148,6 +1148,7 @@ bool tray_manager::on(const visibility_change& evt) {
|
|||
bool tray_manager::on(const dim_window& evt) {
|
||||
if (m_activated) {
|
||||
wm_util::set_wm_window_opacity(m_connection, m_tray, *evt.data() * 0xFFFFFFFF);
|
||||
m_connection.flush();
|
||||
}
|
||||
// let the event bubble
|
||||
return false;
|
||||
|
|
|
@ -42,7 +42,6 @@ namespace wm_util {
|
|||
xcb_intern_atom_reply(conn, xcb_intern_atom(conn, false, 22, "_NET_WM_WINDOW_OPACITY"), nullptr)};
|
||||
if (reply) {
|
||||
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win, reply->atom, XCB_ATOM_CARDINAL, 32, 1, &values);
|
||||
xcb_flush(conn);
|
||||
free(reply);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue