Integrate bar taskqueue into eventloop (#2510)
* Remove DEBUG_SHADED Was disabled by default AND behind an #if 0 * Make TimerHandle expose more libuv functions * Prepare for moving double clicks into eventloop * Make eventloop available to bar * Remove bar mutex Everything in the bar is now in the same thread * Move double-click handling to eventloop * Extract double click deferred function into method * Stop throttling clicks * Increase double click interval to 400 and add option double-click-interval in the bar section Closes #1441 * Implement dimming using timer handles * Remove taskqueue * Remove unused dependencies * Cleanup & Comments
This commit is contained in:
parent
55eb19fdc7
commit
8afd5b71df
@ -59,6 +59,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
triggers if they happen directly after one another, leading to only a single
|
triggers if they happen directly after one another, leading to only a single
|
||||||
bar update.
|
bar update.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- `DEBUG_SHADED` cmake variable and its associated functionality.
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- `drawtypes/ramp`: Add support for ramp weights.
|
- `drawtypes/ramp`: Add support for ramp weights.
|
||||||
([1750](https://github.com/polybar/polybar/issues/1750))
|
([1750](https://github.com/polybar/polybar/issues/1750))
|
||||||
@ -114,6 +117,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
([`#2427`](https://github.com/polybar/polybar/issues/2427))
|
([`#2427`](https://github.com/polybar/polybar/issues/2427))
|
||||||
- `custom/ipc`: `send` action to send arbitrary strings to be displayed in the module.
|
- `custom/ipc`: `send` action to send arbitrary strings to be displayed in the module.
|
||||||
([`#2455`](https://github.com/polybar/polybar/issues/2455))
|
([`#2455`](https://github.com/polybar/polybar/issues/2455))
|
||||||
|
- Added `double-click-interval` setting to the bar section to control the time
|
||||||
|
interval in which a double-click is recognized. Defaults to 400 (ms)
|
||||||
|
([`#1441`](https://github.com/polybar/polybar/issues/1441))
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- We rewrote polybar's main event loop. This shouldn't change any behavior for
|
- We rewrote polybar's main event loop. This shouldn't change any behavior for
|
||||||
@ -130,6 +136,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- `internal/network`:
|
- `internal/network`:
|
||||||
- Increased precision for upload and download speeds: 0 decimal places for
|
- Increased precision for upload and download speeds: 0 decimal places for
|
||||||
KB/s (as before), 1 for MB/s and 2 for GB/s.
|
KB/s (as before), 1 for MB/s and 2 for GB/s.
|
||||||
|
- Clicks arriving in close succession, no longer get dropped. Before polybar
|
||||||
|
would drop any click that arrived within 5ms of the previous one.
|
||||||
|
- Increased the double click interval from 150ms to 400ms.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Trailing space after the layout label when indicators are empty and made sure right amount
|
- Trailing space after the layout label when indicators are empty and made sure right amount
|
||||||
|
@ -55,6 +55,5 @@ if (BUILD_LIBPOLY)
|
|||||||
colored_option(" Trace logging (verbose)" DEBUG_LOGGER_VERBOSE)
|
colored_option(" Trace logging (verbose)" DEBUG_LOGGER_VERBOSE)
|
||||||
colored_option(" Draw clickable areas" DEBUG_HINTS)
|
colored_option(" Draw clickable areas" DEBUG_HINTS)
|
||||||
colored_option(" Print fc-match details" DEBUG_FONTCONFIG)
|
colored_option(" Print fc-match details" DEBUG_FONTCONFIG)
|
||||||
colored_option(" Enable window shading" DEBUG_SHADED)
|
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
|
#include "components/eventloop.hpp"
|
||||||
#include "components/types.hpp"
|
#include "components/types.hpp"
|
||||||
#include "errors.hpp"
|
#include "errors.hpp"
|
||||||
#include "events/signal_fwd.hpp"
|
#include "events/signal_fwd.hpp"
|
||||||
@ -23,7 +24,6 @@ class connection;
|
|||||||
class logger;
|
class logger;
|
||||||
class renderer;
|
class renderer;
|
||||||
class screen;
|
class screen;
|
||||||
class taskqueue;
|
|
||||||
class tray_manager;
|
class tray_manager;
|
||||||
|
|
||||||
namespace tags {
|
namespace tags {
|
||||||
@ -55,8 +55,7 @@ inline double geom_format_to_pixels(std::string str, double max) {
|
|||||||
|
|
||||||
class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::property_notify, evt::enter_notify,
|
class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::property_notify, evt::enter_notify,
|
||||||
evt::leave_notify, evt::motion_notify, evt::destroy_notify, evt::client_message, evt::configure_notify>,
|
evt::leave_notify, evt::motion_notify, evt::destroy_notify, evt::client_message, evt::configure_notify>,
|
||||||
public signal_receiver<SIGN_PRIORITY_BAR, signals::ui::tick, signals::ui::shade_window,
|
public signal_receiver<SIGN_PRIORITY_BAR, signals::ui::dim_window
|
||||||
signals::ui::unshade_window, signals::ui::dim_window
|
|
||||||
#if WITH_XCURSOR
|
#if WITH_XCURSOR
|
||||||
,
|
,
|
||||||
signals::ui::cursor_change
|
signals::ui::cursor_change
|
||||||
@ -64,11 +63,11 @@ class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::propert
|
|||||||
> {
|
> {
|
||||||
public:
|
public:
|
||||||
using make_type = unique_ptr<bar>;
|
using make_type = unique_ptr<bar>;
|
||||||
static make_type make(bool only_initialize_values = false);
|
static make_type make(eventloop&, bool only_initialize_values = false);
|
||||||
|
|
||||||
explicit bar(connection&, signal_emitter&, const config&, const logger&, unique_ptr<screen>&&,
|
explicit bar(connection&, signal_emitter&, const config&, const logger&, eventloop&, unique_ptr<screen>&&,
|
||||||
unique_ptr<tray_manager>&&, unique_ptr<tags::dispatch>&&, unique_ptr<tags::action_context>&&,
|
unique_ptr<tray_manager>&&, unique_ptr<tags::dispatch>&&, unique_ptr<tags::action_context>&&,
|
||||||
unique_ptr<taskqueue>&&, bool only_initialize_values);
|
bool only_initialize_values);
|
||||||
~bar();
|
~bar();
|
||||||
|
|
||||||
const bar_settings settings() const;
|
const bar_settings settings() const;
|
||||||
@ -90,6 +89,8 @@ class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::propert
|
|||||||
void reconfigure_wm_hints();
|
void reconfigure_wm_hints();
|
||||||
void broadcast_visibility();
|
void broadcast_visibility();
|
||||||
|
|
||||||
|
void trigger_click(mousebtn btn, int pos);
|
||||||
|
|
||||||
void handle(const evt::client_message& evt) override;
|
void handle(const evt::client_message& evt) override;
|
||||||
void handle(const evt::destroy_notify& evt) override;
|
void handle(const evt::destroy_notify& evt) override;
|
||||||
void handle(const evt::enter_notify& evt) override;
|
void handle(const evt::enter_notify& evt) override;
|
||||||
@ -100,9 +101,6 @@ class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::propert
|
|||||||
void handle(const evt::property_notify& evt) override;
|
void handle(const evt::property_notify& evt) override;
|
||||||
void handle(const evt::configure_notify& evt) override;
|
void handle(const evt::configure_notify& evt) override;
|
||||||
|
|
||||||
bool on(const signals::ui::unshade_window&) override;
|
|
||||||
bool on(const signals::ui::shade_window&) override;
|
|
||||||
bool on(const signals::ui::tick&) override;
|
|
||||||
bool on(const signals::ui::dim_window&) override;
|
bool on(const signals::ui::dim_window&) override;
|
||||||
#if WITH_XCURSOR
|
#if WITH_XCURSOR
|
||||||
bool on(const signals::ui::cursor_change&) override;
|
bool on(const signals::ui::cursor_change&) override;
|
||||||
@ -113,29 +111,26 @@ class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::propert
|
|||||||
signal_emitter& m_sig;
|
signal_emitter& m_sig;
|
||||||
const config& m_conf;
|
const config& m_conf;
|
||||||
const logger& m_log;
|
const logger& m_log;
|
||||||
|
eventloop& m_loop;
|
||||||
unique_ptr<screen> m_screen;
|
unique_ptr<screen> m_screen;
|
||||||
unique_ptr<tray_manager> m_tray;
|
unique_ptr<tray_manager> m_tray;
|
||||||
unique_ptr<renderer> m_renderer;
|
unique_ptr<renderer> m_renderer;
|
||||||
unique_ptr<tags::dispatch> m_dispatch;
|
unique_ptr<tags::dispatch> m_dispatch;
|
||||||
unique_ptr<tags::action_context> m_action_ctxt;
|
unique_ptr<tags::action_context> m_action_ctxt;
|
||||||
unique_ptr<taskqueue> m_taskqueue;
|
|
||||||
|
|
||||||
bar_settings m_opts{};
|
bar_settings m_opts{};
|
||||||
|
|
||||||
string m_lastinput{};
|
string m_lastinput{};
|
||||||
std::mutex m_mutex{};
|
bool m_dblclicks{false};
|
||||||
std::atomic<bool> m_dblclicks{false};
|
|
||||||
|
|
||||||
mousebtn m_buttonpress_btn{mousebtn::NONE};
|
|
||||||
int m_buttonpress_pos{0};
|
|
||||||
#if WITH_XCURSOR
|
#if WITH_XCURSOR
|
||||||
int m_motion_pos{0};
|
int m_motion_pos{0};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
event_timer m_buttonpress{0L, 5L};
|
TimerHandle_t m_leftclick_timer{m_loop.timer_handle(nullptr)};
|
||||||
event_timer m_doubleclick{0L, 150L};
|
TimerHandle_t m_middleclick_timer{m_loop.timer_handle(nullptr)};
|
||||||
|
TimerHandle_t m_rightclick_timer{m_loop.timer_handle(nullptr)};
|
||||||
double m_anim_step{0.0};
|
TimerHandle_t m_dim_timer{m_loop.timer_handle(nullptr)};
|
||||||
|
|
||||||
bool m_visible{true};
|
bool m_visible{true};
|
||||||
};
|
};
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "components/eventloop.hpp"
|
#include "components/eventloop.hpp"
|
||||||
@ -42,7 +41,7 @@ class controller : public signal_receiver<SIGN_PRIORITY_CONTROLLER, signals::eve
|
|||||||
using make_type = unique_ptr<controller>;
|
using make_type = unique_ptr<controller>;
|
||||||
static make_type make(unique_ptr<ipc>&& ipc);
|
static make_type make(unique_ptr<ipc>&& ipc);
|
||||||
|
|
||||||
explicit controller(connection&, signal_emitter&, const logger&, const config&, unique_ptr<bar>&&, unique_ptr<ipc>&&);
|
explicit controller(connection&, signal_emitter&, const logger&, const config&, unique_ptr<ipc>&&);
|
||||||
~controller();
|
~controller();
|
||||||
|
|
||||||
bool run(bool writeback, string snapshot_dst, bool confwatch);
|
bool run(bool writeback, string snapshot_dst, bool confwatch);
|
||||||
@ -98,15 +97,14 @@ class controller : public signal_receiver<SIGN_PRIORITY_CONTROLLER, signals::eve
|
|||||||
signal_emitter& m_sig;
|
signal_emitter& m_sig;
|
||||||
const logger& m_log;
|
const logger& m_log;
|
||||||
const config& m_conf;
|
const config& m_conf;
|
||||||
|
unique_ptr<eventloop> m_loop;
|
||||||
unique_ptr<bar> m_bar;
|
unique_ptr<bar> m_bar;
|
||||||
unique_ptr<ipc> m_ipc;
|
unique_ptr<ipc> m_ipc;
|
||||||
|
|
||||||
std::unique_ptr<eventloop> eloop;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Once this is set to true, 'eloop' and any uv handles can be used.
|
* Once this is set to true, 'm_loop' and any uv handles can be used.
|
||||||
*/
|
*/
|
||||||
std::atomic_bool m_eloop_ready{false};
|
std::atomic_bool m_loop_ready{false};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Async handle to notify the eventloop
|
* \brief Async handle to notify the eventloop
|
||||||
|
@ -45,11 +45,19 @@ struct UVHandleGeneric {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void close() {
|
void close() {
|
||||||
if (handle && !uv_is_closing((uv_handle_t*)handle)) {
|
if (!is_closing()) {
|
||||||
uv_close((uv_handle_t*)handle, close_callback);
|
uv_close((uv_handle_t*)handle, close_callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_closing() {
|
||||||
|
return !handle || uv_is_closing((uv_handle_t*)handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_active() {
|
||||||
|
return uv_is_active((uv_handle_t*)handle) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
void cleanup_resources() {
|
void cleanup_resources() {
|
||||||
if (handle) {
|
if (handle) {
|
||||||
delete handle;
|
delete handle;
|
||||||
@ -109,7 +117,8 @@ struct PipeHandle : public UVHandleGeneric<uv_pipe_t, uv_stream_t, ssize_t, cons
|
|||||||
|
|
||||||
struct TimerHandle : public UVHandle<uv_timer_t> {
|
struct TimerHandle : public UVHandle<uv_timer_t> {
|
||||||
TimerHandle(uv_loop_t* loop, function<void(void)> fun);
|
TimerHandle(uv_loop_t* loop, function<void(void)> fun);
|
||||||
void start(uint64_t timeout, uint64_t repeat);
|
void start(uint64_t timeout, uint64_t repeat, function<void(void)> new_cb = function<void(void)>(nullptr));
|
||||||
|
void stop();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AsyncHandle : public UVHandle<uv_async_t> {
|
struct AsyncHandle : public UVHandle<uv_async_t> {
|
||||||
@ -121,8 +130,8 @@ using SignalHandle_t = std::unique_ptr<SignalHandle>;
|
|||||||
using PollHandle_t = std::unique_ptr<PollHandle>;
|
using PollHandle_t = std::unique_ptr<PollHandle>;
|
||||||
using FSEventHandle_t = std::unique_ptr<FSEventHandle>;
|
using FSEventHandle_t = std::unique_ptr<FSEventHandle>;
|
||||||
using PipeHandle_t = std::unique_ptr<PipeHandle>;
|
using PipeHandle_t = std::unique_ptr<PipeHandle>;
|
||||||
using TimerHandle_t = std::unique_ptr<TimerHandle>;
|
// shared_ptr because we also return the pointer in order to call methods on it
|
||||||
// shared_ptr because we need a reference outside to call send
|
using TimerHandle_t = std::shared_ptr<TimerHandle>;
|
||||||
using AsyncHandle_t = std::shared_ptr<AsyncHandle>;
|
using AsyncHandle_t = std::shared_ptr<AsyncHandle>;
|
||||||
|
|
||||||
class eventloop {
|
class eventloop {
|
||||||
@ -136,7 +145,7 @@ class eventloop {
|
|||||||
void fs_event_handle(const string& path, function<void(const char*, uv_fs_event)> fun, function<void(int)> err_cb);
|
void fs_event_handle(const string& path, function<void(const char*, uv_fs_event)> fun, function<void(int)> err_cb);
|
||||||
void pipe_handle(
|
void pipe_handle(
|
||||||
const string& path, function<void(const string)> fun, function<void(void)> eof_cb, function<void(int)> err_cb);
|
const string& path, function<void(const string)> fun, function<void(void)> eof_cb, function<void(int)> err_cb);
|
||||||
void timer_handle(uint64_t timeout, uint64_t repeat, function<void(void)> fun);
|
TimerHandle_t timer_handle(function<void(void)> fun);
|
||||||
AsyncHandle_t async_handle(function<void(void)> fun);
|
AsyncHandle_t async_handle(function<void(void)> fun);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <chrono>
|
|
||||||
#include <condition_variable>
|
|
||||||
#include <mutex>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
#include "common.hpp"
|
|
||||||
#include "utils/mixins.hpp"
|
|
||||||
|
|
||||||
POLYBAR_NS
|
|
||||||
|
|
||||||
namespace chrono = std::chrono;
|
|
||||||
using namespace std::chrono_literals;
|
|
||||||
|
|
||||||
class taskqueue : non_copyable_mixin<taskqueue> {
|
|
||||||
public:
|
|
||||||
struct deferred {
|
|
||||||
using clock = chrono::high_resolution_clock;
|
|
||||||
using duration = chrono::milliseconds;
|
|
||||||
using timepoint = chrono::time_point<clock, duration>;
|
|
||||||
using callback = function<void(size_t remaining)>;
|
|
||||||
|
|
||||||
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 callback func;
|
|
||||||
timepoint now;
|
|
||||||
duration wait;
|
|
||||||
size_t count;
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
using make_type = unique_ptr<taskqueue>;
|
|
||||||
static make_type make();
|
|
||||||
|
|
||||||
explicit taskqueue();
|
|
||||||
~taskqueue();
|
|
||||||
|
|
||||||
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 exist(const string& id);
|
|
||||||
bool purge(const string& id);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void tick();
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::thread m_thread;
|
|
||||||
std::mutex m_lock{};
|
|
||||||
std::condition_variable m_hold;
|
|
||||||
std::atomic_bool m_active{true};
|
|
||||||
|
|
||||||
vector<unique_ptr<deferred>> m_deferred;
|
|
||||||
};
|
|
||||||
|
|
||||||
POLYBAR_NS_END
|
|
@ -46,6 +46,19 @@ enum class mousebtn {
|
|||||||
BTN_COUNT,
|
BTN_COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline mousebtn mousebtn_get_double(mousebtn btn) {
|
||||||
|
switch (btn) {
|
||||||
|
case mousebtn::LEFT:
|
||||||
|
return mousebtn::DOUBLE_LEFT;
|
||||||
|
case mousebtn::MIDDLE:
|
||||||
|
return mousebtn::DOUBLE_MIDDLE;
|
||||||
|
case mousebtn::RIGHT:
|
||||||
|
return mousebtn::DOUBLE_RIGHT;
|
||||||
|
default:
|
||||||
|
return mousebtn::NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum class strut {
|
enum class strut {
|
||||||
LEFT = 0,
|
LEFT = 0,
|
||||||
RIGHT,
|
RIGHT,
|
||||||
@ -146,6 +159,8 @@ struct bar_settings {
|
|||||||
|
|
||||||
bool override_redirect{false};
|
bool override_redirect{false};
|
||||||
|
|
||||||
|
int double_click_interval{400};
|
||||||
|
|
||||||
string cursor{};
|
string cursor{};
|
||||||
string cursor_click{};
|
string cursor_click{};
|
||||||
string cursor_scroll{};
|
string cursor_scroll{};
|
||||||
@ -155,12 +170,6 @@ struct bar_settings {
|
|||||||
bool dimmed{false};
|
bool dimmed{false};
|
||||||
double dimvalue{1.0};
|
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 {
|
const xcb_rectangle_t inner_area(bool abspos = false) const {
|
||||||
xcb_rectangle_t rect = this->outer_area(abspos);
|
xcb_rectangle_t rect = this->outer_area(abspos);
|
||||||
|
|
||||||
|
@ -80,9 +80,6 @@ namespace signals {
|
|||||||
struct changed : public detail::base_signal<changed> {
|
struct changed : public detail::base_signal<changed> {
|
||||||
using base_type::base_type;
|
using base_type::base_type;
|
||||||
};
|
};
|
||||||
struct tick : public detail::base_signal<tick> {
|
|
||||||
using base_type::base_type;
|
|
||||||
};
|
|
||||||
struct button_press : public detail::value_signal<button_press, string> {
|
struct button_press : public detail::value_signal<button_press, string> {
|
||||||
using base_type::base_type;
|
using base_type::base_type;
|
||||||
};
|
};
|
||||||
@ -95,12 +92,6 @@ namespace signals {
|
|||||||
struct dim_window : public detail::value_signal<dim_window, double> {
|
struct dim_window : public detail::value_signal<dim_window, double> {
|
||||||
using base_type::base_type;
|
using base_type::base_type;
|
||||||
};
|
};
|
||||||
struct shade_window : public detail::base_signal<shade_window> {
|
|
||||||
using base_type::base_type;
|
|
||||||
};
|
|
||||||
struct unshade_window : public detail::base_signal<unshade_window> {
|
|
||||||
using base_type::base_type;
|
|
||||||
};
|
|
||||||
struct request_snapshot : public detail::value_signal<request_snapshot, string> {
|
struct request_snapshot : public detail::value_signal<request_snapshot, string> {
|
||||||
using base_type::base_type;
|
using base_type::base_type;
|
||||||
};
|
};
|
||||||
|
@ -27,13 +27,10 @@ namespace signals {
|
|||||||
} // namespace ipc
|
} // namespace ipc
|
||||||
namespace ui {
|
namespace ui {
|
||||||
struct changed;
|
struct changed;
|
||||||
struct tick;
|
|
||||||
struct button_press;
|
struct button_press;
|
||||||
struct cursor_change;
|
struct cursor_change;
|
||||||
struct visibility_change;
|
struct visibility_change;
|
||||||
struct dim_window;
|
struct dim_window;
|
||||||
struct shade_window;
|
|
||||||
struct unshade_window;
|
|
||||||
struct request_snapshot;
|
struct request_snapshot;
|
||||||
struct update_background;
|
struct update_background;
|
||||||
struct update_geometry;
|
struct update_geometry;
|
||||||
|
@ -41,7 +41,6 @@ extern const char* const APP_VERSION;
|
|||||||
#cmakedefine DEBUG_LOGGER_VERBOSE
|
#cmakedefine DEBUG_LOGGER_VERBOSE
|
||||||
#cmakedefine DEBUG_HINTS
|
#cmakedefine DEBUG_HINTS
|
||||||
#cmakedefine DEBUG_WHITESPACE
|
#cmakedefine DEBUG_WHITESPACE
|
||||||
#cmakedefine DEBUG_SHADED
|
|
||||||
#cmakedefine DEBUG_FONTCONFIG
|
#cmakedefine DEBUG_FONTCONFIG
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -66,7 +66,6 @@ if(BUILD_LIBPOLY)
|
|||||||
${src_dir}/components/logger.cpp
|
${src_dir}/components/logger.cpp
|
||||||
${src_dir}/components/renderer.cpp
|
${src_dir}/components/renderer.cpp
|
||||||
${src_dir}/components/screen.cpp
|
${src_dir}/components/screen.cpp
|
||||||
${src_dir}/components/taskqueue.cpp
|
|
||||||
${src_dir}/components/eventloop.cpp
|
${src_dir}/components/eventloop.cpp
|
||||||
|
|
||||||
${src_dir}/drawtypes/animation.cpp
|
${src_dir}/drawtypes/animation.cpp
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
#include "components/config.hpp"
|
#include "components/config.hpp"
|
||||||
#include "components/renderer.hpp"
|
#include "components/renderer.hpp"
|
||||||
#include "components/screen.hpp"
|
#include "components/screen.hpp"
|
||||||
#include "components/taskqueue.hpp"
|
|
||||||
#include "components/types.hpp"
|
#include "components/types.hpp"
|
||||||
#include "drawtypes/label.hpp"
|
#include "drawtypes/label.hpp"
|
||||||
#include "events/signal.hpp"
|
#include "events/signal.hpp"
|
||||||
@ -37,7 +36,7 @@ using namespace signals::ui;
|
|||||||
/**
|
/**
|
||||||
* Create instance
|
* Create instance
|
||||||
*/
|
*/
|
||||||
bar::make_type bar::make(bool only_initialize_values) {
|
bar::make_type bar::make(eventloop& loop, bool only_initialize_values) {
|
||||||
auto action_ctxt = make_unique<tags::action_context>();
|
auto action_ctxt = make_unique<tags::action_context>();
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
@ -46,11 +45,11 @@ bar::make_type bar::make(bool only_initialize_values) {
|
|||||||
signal_emitter::make(),
|
signal_emitter::make(),
|
||||||
config::make(),
|
config::make(),
|
||||||
logger::make(),
|
logger::make(),
|
||||||
|
loop,
|
||||||
screen::make(),
|
screen::make(),
|
||||||
tray_manager::make(),
|
tray_manager::make(),
|
||||||
tags::dispatch::make(*action_ctxt),
|
tags::dispatch::make(*action_ctxt),
|
||||||
std::move(action_ctxt),
|
std::move(action_ctxt),
|
||||||
taskqueue::make(),
|
|
||||||
only_initialize_values);
|
only_initialize_values);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
}
|
}
|
||||||
@ -60,18 +59,18 @@ bar::make_type bar::make(bool only_initialize_values) {
|
|||||||
*
|
*
|
||||||
* TODO: Break out all tray handling
|
* TODO: Break out all tray handling
|
||||||
*/
|
*/
|
||||||
bar::bar(connection& conn, signal_emitter& emitter, const config& config, const logger& logger,
|
bar::bar(connection& conn, signal_emitter& emitter, const config& config, const logger& logger, eventloop& loop,
|
||||||
unique_ptr<screen>&& screen, unique_ptr<tray_manager>&& tray_manager, unique_ptr<tags::dispatch>&& dispatch,
|
unique_ptr<screen>&& screen, unique_ptr<tray_manager>&& tray_manager, unique_ptr<tags::dispatch>&& dispatch,
|
||||||
unique_ptr<tags::action_context>&& action_ctxt, unique_ptr<taskqueue>&& taskqueue, bool only_initialize_values)
|
unique_ptr<tags::action_context>&& action_ctxt, bool only_initialize_values)
|
||||||
: m_connection(conn)
|
: m_connection(conn)
|
||||||
, m_sig(emitter)
|
, m_sig(emitter)
|
||||||
, m_conf(config)
|
, m_conf(config)
|
||||||
, m_log(logger)
|
, m_log(logger)
|
||||||
|
, m_loop(loop)
|
||||||
, m_screen(forward<decltype(screen)>(screen))
|
, m_screen(forward<decltype(screen)>(screen))
|
||||||
, m_tray(forward<decltype(tray_manager)>(tray_manager))
|
, m_tray(forward<decltype(tray_manager)>(tray_manager))
|
||||||
, m_dispatch(forward<decltype(dispatch)>(dispatch))
|
, m_dispatch(forward<decltype(dispatch)>(dispatch))
|
||||||
, m_action_ctxt(forward<decltype(action_ctxt)>(action_ctxt))
|
, m_action_ctxt(forward<decltype(action_ctxt)>(action_ctxt)) {
|
||||||
, m_taskqueue(forward<decltype(taskqueue)>(taskqueue)) {
|
|
||||||
string bs{m_conf.section()};
|
string bs{m_conf.section()};
|
||||||
|
|
||||||
// Get available RandR outputs
|
// Get available RandR outputs
|
||||||
@ -179,6 +178,8 @@ bar::bar(connection& conn, signal_emitter& emitter, const config& config, const
|
|||||||
m_opts.module_margin.left = m_conf.get(bs, "module-margin-left", margin);
|
m_opts.module_margin.left = m_conf.get(bs, "module-margin-left", margin);
|
||||||
m_opts.module_margin.right = m_conf.get(bs, "module-margin-right", margin);
|
m_opts.module_margin.right = m_conf.get(bs, "module-margin-right", margin);
|
||||||
|
|
||||||
|
m_opts.double_click_interval = m_conf.get(bs, "double-click-interval", m_opts.double_click_interval);
|
||||||
|
|
||||||
if (only_initialize_values) {
|
if (only_initialize_values) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -308,7 +309,6 @@ bar::bar(connection& conn, signal_emitter& emitter, const config& config, const
|
|||||||
* Cleanup signal handlers and destroy the bar window
|
* Cleanup signal handlers and destroy the bar window
|
||||||
*/
|
*/
|
||||||
bar::~bar() {
|
bar::~bar() {
|
||||||
std::lock_guard<std::mutex> guard(m_mutex);
|
|
||||||
m_connection.detach_sink(this, SINK_PRIORITY_BAR);
|
m_connection.detach_sink(this, SINK_PRIORITY_BAR);
|
||||||
m_sig.detach(this);
|
m_sig.detach(this);
|
||||||
}
|
}
|
||||||
@ -327,12 +327,6 @@ const bar_settings bar::settings() const {
|
|||||||
* \param force Unless true, do not parse unchanged data
|
* \param force Unless true, do not parse unchanged data
|
||||||
*/
|
*/
|
||||||
void bar::parse(string&& data, bool force) {
|
void bar::parse(string&& data, bool force) {
|
||||||
if (!m_mutex.try_lock()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> guard(m_mutex, std::adopt_lock);
|
|
||||||
|
|
||||||
bool unchanged = data == m_lastinput;
|
bool unchanged = data == m_lastinput;
|
||||||
|
|
||||||
m_lastinput = data;
|
m_lastinput = data;
|
||||||
@ -341,8 +335,6 @@ void bar::parse(string&& data, bool force) {
|
|||||||
m_log.trace("bar: Force update");
|
m_log.trace("bar: Force update");
|
||||||
} else if (!m_visible) {
|
} else if (!m_visible) {
|
||||||
return m_log.trace("bar: Ignoring update (invisible)");
|
return m_log.trace("bar: Ignoring update (invisible)");
|
||||||
} else if (m_opts.shaded) {
|
|
||||||
return m_log.trace("bar: Ignoring update (shaded)");
|
|
||||||
} else if (unchanged) {
|
} else if (unchanged) {
|
||||||
return m_log.trace("bar: Ignoring update (unchanged)");
|
return m_log.trace("bar: Ignoring update (unchanged)");
|
||||||
}
|
}
|
||||||
@ -575,6 +567,25 @@ void bar::broadcast_visibility() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bar::trigger_click(mousebtn btn, int pos) {
|
||||||
|
tags::action_t action = m_action_ctxt->has_action(btn, pos);
|
||||||
|
|
||||||
|
if (action != tags::NO_ACTION) {
|
||||||
|
m_log.trace("Found matching input area");
|
||||||
|
m_sig.emit(button_press{m_action_ctxt->get_action(action)});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto&& action : m_opts.actions) {
|
||||||
|
if (action.button == btn && !action.command.empty()) {
|
||||||
|
m_log.trace("Found matching fallback handler");
|
||||||
|
m_sig.emit(button_press{string{action.command}});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_log.info("No matching input area found (btn=%i)", static_cast<int>(btn));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event handler for XCB_DESTROY_NOTIFY events
|
* Event handler for XCB_DESTROY_NOTIFY events
|
||||||
*/
|
*/
|
||||||
@ -601,21 +612,13 @@ void bar::handle(const evt::destroy_notify& evt) {
|
|||||||
* _NET_WM_WINDOW_OPACITY atom value
|
* _NET_WM_WINDOW_OPACITY atom value
|
||||||
*/
|
*/
|
||||||
void bar::handle(const evt::enter_notify&) {
|
void bar::handle(const evt::enter_notify&) {
|
||||||
#if 0
|
|
||||||
#ifdef DEBUG_SHADED
|
|
||||||
if (m_opts.origin == edge::TOP) {
|
|
||||||
m_taskqueue->defer_unique("window-hover", 25ms, [&](size_t) { m_sig.emit(signals::ui::unshade_window{}); });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
if (m_opts.dimmed) {
|
if (m_opts.dimmed) {
|
||||||
m_taskqueue->defer_unique("window-dim", 25ms, [&](size_t) {
|
m_dim_timer->start(25, 0, [this]() {
|
||||||
m_opts.dimmed = false;
|
m_opts.dimmed = false;
|
||||||
m_sig.emit(dim_window{1.0});
|
m_sig.emit(dim_window{1.0});
|
||||||
});
|
});
|
||||||
} else if (m_taskqueue->exist("window-dim")) {
|
} else if (m_dim_timer->is_active()) {
|
||||||
m_taskqueue->purge("window-dim");
|
m_dim_timer->stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -626,20 +629,15 @@ void bar::handle(const evt::enter_notify&) {
|
|||||||
* _NET_WM_WINDOW_OPACITY atom value
|
* _NET_WM_WINDOW_OPACITY atom value
|
||||||
*/
|
*/
|
||||||
void bar::handle(const evt::leave_notify&) {
|
void bar::handle(const evt::leave_notify&) {
|
||||||
#if 0
|
// Only trigger dimming, if the dim-value is not fully opaque.
|
||||||
#ifdef DEBUG_SHADED
|
if (m_opts.dimvalue < 1.0) {
|
||||||
if (m_opts.origin == edge::TOP) {
|
|
||||||
m_taskqueue->defer_unique("window-hover", 25ms, [&](size_t) { m_sig.emit(signals::ui::shade_window{}); });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
if (!m_opts.dimmed) {
|
if (!m_opts.dimmed) {
|
||||||
m_taskqueue->defer_unique("window-dim", 3s, [&](size_t) {
|
m_dim_timer->start(3000, 0, [this]() {
|
||||||
m_opts.dimmed = true;
|
m_opts.dimmed = true;
|
||||||
m_sig.emit(dim_window{double(m_opts.dimvalue)});
|
m_sig.emit(dim_window{double(m_opts.dimvalue)});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -648,12 +646,6 @@ void bar::handle(const evt::leave_notify&) {
|
|||||||
* Used to change the cursor depending on the module
|
* Used to change the cursor depending on the module
|
||||||
*/
|
*/
|
||||||
void bar::handle(const evt::motion_notify& evt) {
|
void bar::handle(const evt::motion_notify& evt) {
|
||||||
if (!m_mutex.try_lock()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> guard(m_mutex, std::adopt_lock);
|
|
||||||
|
|
||||||
m_log.trace("bar: Detected motion: %i at pos(%i, %i)", evt->detail, evt->event_x, evt->event_y);
|
m_log.trace("bar: Detected motion: %i at pos(%i, %i)", evt->detail, evt->event_x, evt->event_y);
|
||||||
#if WITH_XCURSOR
|
#if WITH_XCURSOR
|
||||||
m_motion_pos = evt->event_x;
|
m_motion_pos = evt->event_x;
|
||||||
@ -735,63 +727,37 @@ void bar::handle(const evt::motion_notify& evt) {
|
|||||||
* Used to map mouse clicks to bar actions
|
* Used to map mouse clicks to bar actions
|
||||||
*/
|
*/
|
||||||
void bar::handle(const evt::button_press& evt) {
|
void bar::handle(const evt::button_press& evt) {
|
||||||
if (!m_mutex.try_lock()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> guard(m_mutex, std::adopt_lock);
|
|
||||||
|
|
||||||
if (m_buttonpress.deny(evt->time)) {
|
|
||||||
return m_log.trace_x("bar: Ignoring button press (throttled)...");
|
|
||||||
}
|
|
||||||
|
|
||||||
m_log.trace("bar: Received button press: %i at pos(%i, %i)", evt->detail, evt->event_x, evt->event_y);
|
m_log.trace("bar: Received button press: %i at pos(%i, %i)", evt->detail, evt->event_x, evt->event_y);
|
||||||
|
|
||||||
m_buttonpress_btn = static_cast<mousebtn>(evt->detail);
|
mousebtn btn = static_cast<mousebtn>(evt->detail);
|
||||||
m_buttonpress_pos = evt->event_x;
|
int pos = evt->event_x;
|
||||||
|
|
||||||
const auto deferred_fn = [&](size_t) {
|
/*
|
||||||
tags::action_t action = m_action_ctxt->has_action(m_buttonpress_btn, m_buttonpress_pos);
|
* For possible double-clicks we need to delay the triggering of the click by
|
||||||
|
* the configured interval and if in that time another click arrives, we
|
||||||
if (action != tags::NO_ACTION) {
|
* need to trigger a double click.
|
||||||
m_log.trace("Found matching input area");
|
*/
|
||||||
m_sig.emit(button_press{m_action_ctxt->get_action(action)});
|
const auto check_double = [this](TimerHandle_t handle, mousebtn btn, int pos) {
|
||||||
return;
|
if (!handle->is_active()) {
|
||||||
}
|
handle->start(m_opts.double_click_interval, 0, [=]() { trigger_click(btn, pos); });
|
||||||
|
} else {
|
||||||
for (auto&& action : m_opts.actions) {
|
handle->stop();
|
||||||
if (action.button == m_buttonpress_btn && !action.command.empty()) {
|
trigger_click(mousebtn_get_double(btn), pos);
|
||||||
m_log.trace("Found matching fallback handler");
|
|
||||||
m_sig.emit(button_press{string{action.command}});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_log.info("No matching input area found (btn=%i)", static_cast<int>(m_buttonpress_btn));
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto check_double = [&](string&& id, mousebtn&& btn) {
|
|
||||||
if (!m_taskqueue->exist(id)) {
|
|
||||||
m_doubleclick.event = evt->time;
|
|
||||||
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 = btn;
|
|
||||||
m_taskqueue->defer_unique(id, 0ms, deferred_fn);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// If there are no double click handlers defined we can
|
// If there are no double click handlers defined we can
|
||||||
// just by-pass the click timer handling
|
// just by-pass the click timer handling
|
||||||
if (!m_dblclicks) {
|
if (!m_dblclicks) {
|
||||||
deferred_fn(0);
|
trigger_click(btn, pos);
|
||||||
} else if (evt->detail == static_cast<int>(mousebtn::LEFT)) {
|
} else if (btn == mousebtn::LEFT) {
|
||||||
check_double("buttonpress-left", mousebtn::DOUBLE_LEFT);
|
check_double(m_leftclick_timer, btn, pos);
|
||||||
} else if (evt->detail == static_cast<int>(mousebtn::MIDDLE)) {
|
} else if (btn == mousebtn::MIDDLE) {
|
||||||
check_double("buttonpress-middle", mousebtn::DOUBLE_MIDDLE);
|
check_double(m_middleclick_timer, btn, pos);
|
||||||
} else if (evt->detail == static_cast<int>(mousebtn::RIGHT)) {
|
} else if (btn == mousebtn::RIGHT) {
|
||||||
check_double("buttonpress-right", mousebtn::DOUBLE_RIGHT);
|
check_double(m_rightclick_timer, btn, pos);
|
||||||
} else {
|
} else {
|
||||||
deferred_fn(0);
|
trigger_click(btn, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -876,110 +842,6 @@ void bar::start() {
|
|||||||
broadcast_visibility();
|
broadcast_visibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bar::on(const signals::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 / 2.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(signals::ui::tick{});
|
|
||||||
}
|
|
||||||
if (!remaining) {
|
|
||||||
m_renderer->flush();
|
|
||||||
}
|
|
||||||
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 signals::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 / 2.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(signals::ui::tick{});
|
|
||||||
}
|
|
||||||
if (!remaining) {
|
|
||||||
m_renderer->flush();
|
|
||||||
}
|
|
||||||
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 signals::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;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int mask{0};
|
|
||||||
unsigned int 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<unsigned int>(geom->height + m_anim_step));
|
|
||||||
params.height = std::max(1U, std::min(params.height, static_cast<unsigned int>(m_opts.shade_size.h)));
|
|
||||||
} else if (m_opts.shade_size.h < geom->height) {
|
|
||||||
XCB_AUX_ADD_PARAM(&mask, ¶ms, height, static_cast<unsigned int>(geom->height - m_anim_step));
|
|
||||||
params.height = std::max(1U, std::max(params.height, static_cast<unsigned int>(m_opts.shade_size.h)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_opts.shade_pos.y > geom->y) {
|
|
||||||
XCB_AUX_ADD_PARAM(&mask, ¶ms, y, static_cast<int>(geom->y + m_anim_step));
|
|
||||||
params.y = std::min(params.y, static_cast<int>(m_opts.shade_pos.y));
|
|
||||||
} else if (m_opts.shade_pos.y < geom->y) {
|
|
||||||
XCB_AUX_ADD_PARAM(&mask, ¶ms, y, static_cast<int>(geom->y - m_anim_step));
|
|
||||||
params.y = std::max(params.y, static_cast<int>(m_opts.shade_pos.y));
|
|
||||||
}
|
|
||||||
|
|
||||||
connection::pack_values(mask, ¶ms, values);
|
|
||||||
|
|
||||||
m_connection.configure_window(m_opts.window, mask, values);
|
|
||||||
m_connection.flush();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bar::on(const signals::ui::dim_window& sig) {
|
bool bar::on(const signals::ui::dim_window& sig) {
|
||||||
m_opts.dimmed = sig.cast() != 1.0;
|
m_opts.dimmed = sig.cast() != 1.0;
|
||||||
ewmh_util::set_wm_window_opacity(m_opts.window, sig.cast() * 0xFFFFFFFF);
|
ewmh_util::set_wm_window_opacity(m_opts.window, sig.cast() * 0xFFFFFFFF);
|
||||||
|
@ -31,20 +31,21 @@ POLYBAR_NS
|
|||||||
* Build controller instance
|
* Build controller instance
|
||||||
*/
|
*/
|
||||||
controller::make_type controller::make(unique_ptr<ipc>&& ipc) {
|
controller::make_type controller::make(unique_ptr<ipc>&& ipc) {
|
||||||
return std::make_unique<controller>(connection::make(), signal_emitter::make(), logger::make(), config::make(),
|
return std::make_unique<controller>(
|
||||||
bar::make(), forward<decltype(ipc)>(ipc));
|
connection::make(), signal_emitter::make(), logger::make(), config::make(), forward<decltype(ipc)>(ipc));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct controller
|
* Construct controller
|
||||||
*/
|
*/
|
||||||
controller::controller(connection& conn, signal_emitter& emitter, const logger& logger, const config& config,
|
controller::controller(
|
||||||
unique_ptr<bar>&& bar, unique_ptr<ipc>&& ipc)
|
connection& conn, signal_emitter& emitter, const logger& logger, const config& config, unique_ptr<ipc>&& ipc)
|
||||||
: m_connection(conn)
|
: m_connection(conn)
|
||||||
, m_sig(emitter)
|
, m_sig(emitter)
|
||||||
, m_log(logger)
|
, m_log(logger)
|
||||||
, m_conf(config)
|
, m_conf(config)
|
||||||
, m_bar(forward<decltype(bar)>(bar))
|
, m_loop(make_unique<eventloop>())
|
||||||
|
, m_bar(bar::make(*m_loop))
|
||||||
, m_ipc(forward<decltype(ipc)>(ipc)) {
|
, m_ipc(forward<decltype(ipc)>(ipc)) {
|
||||||
m_conf.ignore_key("settings", "throttle-input-for");
|
m_conf.ignore_key("settings", "throttle-input-for");
|
||||||
m_conf.ignore_key("settings", "throttle-output");
|
m_conf.ignore_key("settings", "throttle-output");
|
||||||
@ -152,14 +153,14 @@ void controller::trigger_update(bool force) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void controller::trigger_notification() {
|
void controller::trigger_notification() {
|
||||||
if (m_eloop_ready) {
|
if (m_loop_ready) {
|
||||||
m_notifier->send();
|
m_notifier->send();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void controller::stop(bool reload) {
|
void controller::stop(bool reload) {
|
||||||
update_reload(reload);
|
update_reload(reload);
|
||||||
eloop->stop();
|
m_loop->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void controller::conn_cb(uv_poll_event) {
|
void controller::conn_cb(uv_poll_event) {
|
||||||
@ -210,7 +211,7 @@ void controller::notifier_handler() {
|
|||||||
|
|
||||||
if (data.quit) {
|
if (data.quit) {
|
||||||
update_reload(data.reload);
|
update_reload(data.reload);
|
||||||
eloop->stop();
|
m_loop->stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,29 +235,23 @@ void controller::screenshot_handler() {
|
|||||||
void controller::read_events(bool confwatch) {
|
void controller::read_events(bool confwatch) {
|
||||||
m_log.info("Entering event loop (thread-id=%lu)", this_thread::get_id());
|
m_log.info("Entering event loop (thread-id=%lu)", this_thread::get_id());
|
||||||
|
|
||||||
if (!m_writeback) {
|
|
||||||
m_bar->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
eloop = std::make_unique<eventloop>();
|
m_loop->poll_handle(
|
||||||
|
|
||||||
eloop->poll_handle(
|
|
||||||
UV_READABLE, m_connection.get_file_descriptor(), [this](uv_poll_event events) { conn_cb(events); },
|
UV_READABLE, m_connection.get_file_descriptor(), [this](uv_poll_event events) { conn_cb(events); },
|
||||||
[](int status) { throw runtime_error("libuv error while polling X connection: "s + uv_strerror(status)); });
|
[](int status) { throw runtime_error("libuv error while polling X connection: "s + uv_strerror(status)); });
|
||||||
|
|
||||||
for (auto s : {SIGINT, SIGQUIT, SIGTERM, SIGUSR1, SIGALRM}) {
|
for (auto s : {SIGINT, SIGQUIT, SIGTERM, SIGUSR1, SIGALRM}) {
|
||||||
eloop->signal_handle(s, [this](int signum) { signal_handler(signum); });
|
m_loop->signal_handle(s, [this](int signum) { signal_handler(signum); });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (confwatch) {
|
if (confwatch) {
|
||||||
eloop->fs_event_handle(
|
m_loop->fs_event_handle(
|
||||||
m_conf.filepath(), [this](const char* path, uv_fs_event events) { confwatch_handler(path, events); },
|
m_conf.filepath(), [this](const char* path, uv_fs_event events) { confwatch_handler(path, events); },
|
||||||
[this](int err) { m_log.err("libuv error while watching config file for changes: %s", uv_strerror(err)); });
|
[this](int err) { m_log.err("libuv error while watching config file for changes: %s", uv_strerror(err)); });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_ipc) {
|
if (m_ipc) {
|
||||||
eloop->pipe_handle(
|
m_loop->pipe_handle(
|
||||||
m_ipc->get_path(), [this](const string payload) { m_ipc->receive_data(payload); },
|
m_ipc->get_path(), [this](const string payload) { m_ipc->receive_data(payload); },
|
||||||
[this]() { m_ipc->receive_eof(); },
|
[this]() { m_ipc->receive_eof(); },
|
||||||
[this](int err) { m_log.err("libuv error while listening to IPC channel: %s", uv_strerror(err)); });
|
[this](int err) { m_log.err("libuv error while listening to IPC channel: %s", uv_strerror(err)); });
|
||||||
@ -264,19 +259,23 @@ void controller::read_events(bool confwatch) {
|
|||||||
|
|
||||||
if (!m_snapshot_dst.empty()) {
|
if (!m_snapshot_dst.empty()) {
|
||||||
// Trigger a single screenshot after 3 seconds
|
// Trigger a single screenshot after 3 seconds
|
||||||
eloop->timer_handle(3000, 0, [this]() { screenshot_handler(); });
|
m_loop->timer_handle([this]() { screenshot_handler(); })->start(3000, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_notifier = eloop->async_handle([this]() { notifier_handler(); });
|
m_notifier = m_loop->async_handle([this]() { notifier_handler(); });
|
||||||
|
|
||||||
m_eloop_ready.store(true);
|
m_loop_ready = true;
|
||||||
|
|
||||||
|
if (!m_writeback) {
|
||||||
|
m_bar->start();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Immediately trigger and update so that the bar displays something.
|
* Immediately trigger and update so that the bar displays something.
|
||||||
*/
|
*/
|
||||||
trigger_update(true);
|
trigger_update(true);
|
||||||
|
|
||||||
eloop->run();
|
m_loop->run();
|
||||||
} catch (const exception& err) {
|
} catch (const exception& err) {
|
||||||
m_log.err("Fatal Error in eventloop: %s", err.what());
|
m_log.err("Fatal Error in eventloop: %s", err.what());
|
||||||
stop(false);
|
stop(false);
|
||||||
@ -284,7 +283,8 @@ void controller::read_events(bool confwatch) {
|
|||||||
|
|
||||||
m_log.info("Eventloop finished");
|
m_log.info("Eventloop finished");
|
||||||
|
|
||||||
eloop.reset();
|
m_loop_ready = false;
|
||||||
|
m_loop.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -141,7 +141,7 @@ void PipeHandle::read_cb(ssize_t nread, const uv_buf_t* buf) {
|
|||||||
*
|
*
|
||||||
* We reuse the memory for the underlying uv handle
|
* We reuse the memory for the underlying uv handle
|
||||||
*/
|
*/
|
||||||
if (!uv_is_closing((uv_handle_t*)handle)) {
|
if (!is_closing()) {
|
||||||
uv_close((uv_handle_t*)handle, [](uv_handle_t* handle) {
|
uv_close((uv_handle_t*)handle, [](uv_handle_t* handle) {
|
||||||
PipeHandle* This = static_cast<PipeHandle*>(handle->data);
|
PipeHandle* This = static_cast<PipeHandle*>(handle->data);
|
||||||
UV(uv_pipe_init, This->loop(), This->handle, false);
|
UV(uv_pipe_init, This->loop(), This->handle, false);
|
||||||
@ -158,9 +158,17 @@ TimerHandle::TimerHandle(uv_loop_t* loop, function<void(void)> fun) : UVHandle(f
|
|||||||
UV(uv_timer_init, loop, handle);
|
UV(uv_timer_init, loop, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimerHandle::start(uint64_t timeout, uint64_t repeat) {
|
void TimerHandle::start(uint64_t timeout, uint64_t repeat, function<void(void)> new_cb) {
|
||||||
|
if (new_cb) {
|
||||||
|
this->func = new_cb;
|
||||||
|
}
|
||||||
|
|
||||||
UV(uv_timer_start, handle, callback, timeout, repeat);
|
UV(uv_timer_start, handle, callback, timeout, repeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TimerHandle::stop() {
|
||||||
|
UV(uv_timer_stop, handle);
|
||||||
|
}
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
// AsyncHandle {{{
|
// AsyncHandle {{{
|
||||||
@ -243,9 +251,9 @@ void eventloop::pipe_handle(
|
|||||||
m_pipe_handles.back()->start();
|
m_pipe_handles.back()->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void eventloop::timer_handle(uint64_t timeout, uint64_t repeat, function<void(void)> fun) {
|
TimerHandle_t eventloop::timer_handle(function<void(void)> fun) {
|
||||||
m_timer_handles.emplace_back(std::make_unique<TimerHandle>(get(), fun));
|
m_timer_handles.emplace_back(std::make_shared<TimerHandle>(get(), fun));
|
||||||
m_timer_handles.back()->start(timeout, repeat);
|
return m_timer_handles.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncHandle_t eventloop::async_handle(function<void(void)> fun) {
|
AsyncHandle_t eventloop::async_handle(function<void(void)> fun) {
|
||||||
|
@ -381,25 +381,6 @@ void renderer::flush() {
|
|||||||
|
|
||||||
highlight_clickable_areas();
|
highlight_clickable_areas();
|
||||||
|
|
||||||
#if 0
|
|
||||||
#ifdef DEBUG_SHADED
|
|
||||||
if (m_bar.shaded && m_bar.origin == edge::TOP) {
|
|
||||||
m_log.trace_x(
|
|
||||||
"renderer: copy pixmap (shaded=1, geom=%dx%d+%d+%d)", m_rect.width, m_rect.height, m_rect.x, m_rect.y);
|
|
||||||
auto geom = m_connection.get_geometry(m_window);
|
|
||||||
auto x1 = 0;
|
|
||||||
auto y1 = m_rect.height - m_bar.shade_size.h - m_rect.y - geom->height;
|
|
||||||
auto x2 = m_rect.x;
|
|
||||||
auto y2 = m_rect.y;
|
|
||||||
auto w = m_rect.width;
|
|
||||||
auto h = m_rect.height - m_bar.shade_size.h + geom->height;
|
|
||||||
m_connection.copy_area(m_pixmap, m_window, m_gcontext, x1, y1, x2, y2, w, h);
|
|
||||||
m_connection.flush();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
m_surface->flush();
|
m_surface->flush();
|
||||||
m_connection.copy_area(m_pixmap, m_window, m_gcontext, 0, 0, 0, 0, m_bar.size.w, m_bar.size.h);
|
m_connection.copy_area(m_pixmap, m_window, m_gcontext, 0, 0, 0, 0, m_bar.size.w, m_bar.size.h);
|
||||||
m_connection.flush();
|
m_connection.flush();
|
||||||
|
@ -1,109 +0,0 @@
|
|||||||
#include "components/taskqueue.hpp"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
POLYBAR_NS
|
|
||||||
|
|
||||||
taskqueue::make_type taskqueue::make() {
|
|
||||||
return std::make_unique<taskqueue>();
|
|
||||||
}
|
|
||||||
|
|
||||||
taskqueue::taskqueue() {
|
|
||||||
m_thread = std::thread([&] {
|
|
||||||
while (m_active) {
|
|
||||||
std::unique_lock<std::mutex> guard(m_lock);
|
|
||||||
|
|
||||||
if (m_deferred.empty()) {
|
|
||||||
m_hold.wait(guard);
|
|
||||||
} else {
|
|
||||||
auto now = deferred::clock::now();
|
|
||||||
auto wait = m_deferred.front()->now + m_deferred.front()->wait;
|
|
||||||
for (auto&& task : m_deferred) {
|
|
||||||
auto when = task->now + task->wait;
|
|
||||||
if (when < wait) {
|
|
||||||
wait = move(when);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (wait > now) {
|
|
||||||
m_hold.wait_for(guard, wait - now);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!m_deferred.empty()) {
|
|
||||||
guard.unlock();
|
|
||||||
tick();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
taskqueue::~taskqueue() {
|
|
||||||
if (m_active && m_thread.joinable()) {
|
|
||||||
m_active = false;
|
|
||||||
m_hold.notify_all();
|
|
||||||
m_thread.join();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
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, deferred::duration offset, size_t count) {
|
|
||||||
purge(id);
|
|
||||||
std::unique_lock<std::mutex> guard(m_lock);
|
|
||||||
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()) {
|
|
||||||
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::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) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
POLYBAR_NS_END
|
|
@ -127,7 +127,8 @@ int main(int argc, char** argv) {
|
|||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
if (cli->has("print-wmname")) {
|
if (cli->has("print-wmname")) {
|
||||||
printf("%s\n", bar::make(true)->settings().wmname.c_str());
|
eventloop loop{};
|
||||||
|
printf("%s\n", bar::make(loop, true)->settings().wmname.c_str());
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
|
#include "utils/env.hpp"
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <thread>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "utils/env.hpp"
|
|
||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
namespace env_util {
|
namespace env_util {
|
||||||
@ -17,6 +16,6 @@ namespace env_util {
|
|||||||
const char* value{std::getenv(var.c_str())};
|
const char* value{std::getenv(var.c_str())};
|
||||||
return value != nullptr ? value : move(fallback);
|
return value != nullptr ? value : move(fallback);
|
||||||
}
|
}
|
||||||
}
|
} // namespace env_util
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
Loading…
Reference in New Issue
Block a user