mirror of
https://github.com/polybar/polybar.git
synced 2024-11-18 13:55:11 -05:00
fix(tray): Re-activation
This commit is contained in:
parent
8c3f40db5b
commit
b11a662d81
5 changed files with 83 additions and 55 deletions
|
@ -96,7 +96,7 @@ class tray_manager : public xpp::event::sink<evt::expose, evt::visibility_notify
|
|||
|
||||
void acquire_selection();
|
||||
void notify_clients();
|
||||
void notify_clients_delayed(chrono::seconds delay = 1s);
|
||||
void notify_clients_delayed();
|
||||
|
||||
void track_selection_owner(xcb_window_t owner);
|
||||
void process_docking_request(xcb_window_t win);
|
||||
|
@ -157,6 +157,10 @@ class tray_manager : public xpp::event::sink<evt::expose, evt::visibility_notify
|
|||
bool m_restacked{false};
|
||||
|
||||
std::mutex m_mtx;
|
||||
|
||||
chrono::time_point<chrono::system_clock, chrono::milliseconds> m_drawtime;
|
||||
|
||||
bool m_firstactivation{true};
|
||||
};
|
||||
|
||||
POLYBAR_NS_END
|
||||
|
|
|
@ -26,7 +26,7 @@ config::make_type config::make(string path, string bar) {
|
|||
* Construct config object
|
||||
*/
|
||||
config::config(const logger& logger, const xresource_manager& xrm, string&& path, string&& bar)
|
||||
: m_logger(logger), m_xrm(xrm), m_file(forward<decltype(path)>(path)), m_barname(forward<decltype(bar)>(bar)) {
|
||||
: m_logger(logger), m_xrm(xrm), m_file(forward<string>(path)), m_barname(forward<string>(bar)) {
|
||||
if (!file_util::exists(m_file)) {
|
||||
throw application_error("Could not find config file: " + m_file);
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ void config::warn_deprecated(const string& section, const string& key, string re
|
|||
* Parse key/value pairs from the configuration file
|
||||
*/
|
||||
void config::parse_file() {
|
||||
std::ifstream in(m_file.c_str());
|
||||
std::ifstream in(m_file);
|
||||
string line;
|
||||
string section;
|
||||
uint32_t lineno{0};
|
||||
|
@ -117,8 +117,7 @@ void config::parse_file() {
|
|||
line.erase(0, equal_pos + 1);
|
||||
}
|
||||
|
||||
string value{string_util::trim(string_util::trim(move(line), ' '), '"')};
|
||||
|
||||
string value{string_util::trim(forward<string>(string_util::trim(move(line), ' ')), '"')};
|
||||
m_sections[section].emplace_hint(it, move(key), move(value));
|
||||
}
|
||||
|
||||
|
|
|
@ -120,10 +120,8 @@ void eventloop::stop() {
|
|||
* Enqueue event
|
||||
*/
|
||||
bool eventloop::enqueue(event&& evt) {
|
||||
uint8_t type{static_cast<uint8_t>(evt.type)};
|
||||
|
||||
if (!m_queue.enqueue(move(evt))) {
|
||||
m_log.warn("Failed to enqueue event (%d)", static_cast<uint8_t>(type));
|
||||
m_log.warn("Failed to enqueue event");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -122,30 +122,37 @@ namespace string_util {
|
|||
/**
|
||||
* Remove needle from the start of the string
|
||||
*/
|
||||
string ltrim(string&& haystack, const char& needle) {
|
||||
string str(haystack);
|
||||
while (str[0] == needle) {
|
||||
str.erase(0, 1);
|
||||
string ltrim(string&& value, const char& needle) {
|
||||
if (value.empty()) {
|
||||
return "";
|
||||
}
|
||||
return str;
|
||||
while (*value.begin() == needle) {
|
||||
value.erase(0, 1);
|
||||
}
|
||||
return forward<string>(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove needle from the end of the string
|
||||
*/
|
||||
string rtrim(string&& haystack, const char& needle) {
|
||||
string str(haystack);
|
||||
while (str[str.length() - 1] == needle) {
|
||||
str.erase(str.length() - 1, 1);
|
||||
string rtrim(string&& value, const char& needle) {
|
||||
if (value.empty()) {
|
||||
return "";
|
||||
}
|
||||
return str;
|
||||
while (*(value.end() - 1) == needle) {
|
||||
value.erase(value.length() - 1, 1);
|
||||
}
|
||||
return forward<string>(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove needle from the start and end of the string
|
||||
*/
|
||||
string trim(string&& value, const char& needle) {
|
||||
return rtrim(ltrim(move(value), needle), needle);
|
||||
if (value.empty()) {
|
||||
return "";
|
||||
}
|
||||
return rtrim(ltrim(forward<string>(value), needle), needle);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -51,12 +51,15 @@ tray_manager::make_type tray_manager::make() {
|
|||
}
|
||||
|
||||
tray_manager::tray_manager(connection& conn, signal_emitter& emitter, const logger& logger)
|
||||
: m_connection(conn), m_sig(emitter), m_log(logger) {}
|
||||
: m_connection(conn), m_sig(emitter), m_log(logger) {
|
||||
m_connection.attach_sink(this, SINK_PRIORITY_TRAY);
|
||||
}
|
||||
|
||||
tray_manager::~tray_manager() {
|
||||
if (m_delaythread.joinable()) {
|
||||
m_delaythread.join();
|
||||
}
|
||||
m_connection.detach_sink(this, SINK_PRIORITY_TRAY);
|
||||
deactivate();
|
||||
}
|
||||
|
||||
|
@ -198,7 +201,6 @@ void tray_manager::activate() {
|
|||
m_opts.running = true;
|
||||
|
||||
m_sig.attach(this);
|
||||
m_connection.attach_sink(this, SINK_PRIORITY_TRAY);
|
||||
|
||||
try {
|
||||
create_window();
|
||||
|
@ -221,13 +223,16 @@ void tray_manager::activate() {
|
|||
// notify clients waiting for a manager.
|
||||
acquire_selection();
|
||||
|
||||
// Notify pending tray clients
|
||||
notify_clients();
|
||||
|
||||
// Send delayed notification
|
||||
if (m_othermanager != XCB_NONE && m_othermanager != m_tray) {
|
||||
if (!m_firstactivation) {
|
||||
notify_clients_delayed();
|
||||
} else if (m_othermanager != XCB_NONE && m_othermanager != m_tray) {
|
||||
notify_clients_delayed();
|
||||
} else {
|
||||
notify_clients();
|
||||
}
|
||||
|
||||
m_firstactivation = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -243,7 +248,6 @@ void tray_manager::deactivate(bool clear_selection) {
|
|||
m_opts.running = false;
|
||||
|
||||
m_sig.detach(this);
|
||||
m_connection.detach_sink(this, SINK_PRIORITY_TRAY);
|
||||
|
||||
if (!m_connection.connection_has_error() && clear_selection && m_acquired_selection) {
|
||||
m_log.trace("tray: Unset selection owner");
|
||||
|
@ -506,7 +510,15 @@ void tray_manager::refresh_window() {
|
|||
* Redraw window
|
||||
*/
|
||||
void tray_manager::redraw_window(bool realloc_bg) {
|
||||
m_log.info("Redraw tray container (id=%s)", m_connection.id(m_tray));
|
||||
chrono::system_clock::time_point now{chrono::system_clock::now()};
|
||||
|
||||
if (!realloc_bg && now - 24ms < m_drawtime) {
|
||||
return m_log.trace("tray: Ignoring redraw (throttled)");
|
||||
}
|
||||
|
||||
m_drawtime = chrono::time_point_cast<chrono::milliseconds>(now);
|
||||
m_log.info("Redraw tray container (id=%s) %lu", m_connection.id(m_tray),
|
||||
chrono::duration_cast<chrono::microseconds>(chrono::system_clock::now().time_since_epoch()));
|
||||
reconfigure_bg(realloc_bg);
|
||||
refresh_window();
|
||||
}
|
||||
|
@ -669,23 +681,34 @@ void tray_manager::set_tray_colors() {
|
|||
* Acquire the systray selection
|
||||
*/
|
||||
void tray_manager::acquire_selection() {
|
||||
auto reply = m_connection.get_selection_owner_unchecked(m_atom);
|
||||
auto owner = reply.owner<xcb_window_t>();
|
||||
m_othermanager = XCB_NONE;
|
||||
;
|
||||
xcb_window_t owner;
|
||||
|
||||
try {
|
||||
owner = m_connection.get_selection_owner(m_atom).owner<xcb_window_t>();
|
||||
} catch (const exception& err) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (owner == m_tray) {
|
||||
m_log.info("tray: Already managing the systray selection");
|
||||
} else if ((m_othermanager = owner) != XCB_NONE) {
|
||||
m_log.info("Replacing selection manager %s", m_connection.id(owner));
|
||||
} else {
|
||||
m_log.trace("tray: Change selection owner to %s", m_connection.id(m_tray));
|
||||
m_connection.set_selection_owner_checked(m_tray, m_atom, XCB_CURRENT_TIME);
|
||||
|
||||
if (m_connection.get_selection_owner_unchecked(m_atom)->owner != m_tray) {
|
||||
throw application_error("Failed to get control of the systray selection");
|
||||
}
|
||||
|
||||
m_acquired_selection = false;
|
||||
m_log.trace("tray: Already managing the systray selection");
|
||||
m_acquired_selection = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((m_othermanager = owner) != XCB_NONE) {
|
||||
m_log.info("Replacing selection manager %s", m_connection.id(owner));
|
||||
}
|
||||
|
||||
m_log.trace("tray: Change selection owner to %s", m_connection.id(m_tray));
|
||||
m_connection.set_selection_owner_checked(m_tray, m_atom, XCB_CURRENT_TIME);
|
||||
|
||||
if (m_connection.get_selection_owner_unchecked(m_atom)->owner != m_tray) {
|
||||
throw application_error("Failed to get control of the systray selection");
|
||||
}
|
||||
|
||||
m_acquired_selection = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -705,16 +728,14 @@ void tray_manager::notify_clients() {
|
|||
/**
|
||||
* Send delayed notification to pending clients
|
||||
*/
|
||||
void tray_manager::notify_clients_delayed(chrono::seconds delay) {
|
||||
if (!m_activated) {
|
||||
return;
|
||||
} else if (m_delaythread.joinable()) {
|
||||
void tray_manager::notify_clients_delayed() {
|
||||
if (m_delaythread.joinable()) {
|
||||
m_delaythread.join();
|
||||
}
|
||||
m_delaythread = thread([this](auto&& delay) {
|
||||
this_thread::sleep_for(delay);
|
||||
m_delaythread = thread([this]() {
|
||||
this_thread::sleep_for(1s);
|
||||
notify_clients();
|
||||
}, move(delay));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -722,7 +743,7 @@ void tray_manager::notify_clients_delayed(chrono::seconds delay) {
|
|||
* If it gets destroyed or goes away we can reactivate the tray_manager
|
||||
*/
|
||||
void tray_manager::track_selection_owner(xcb_window_t owner) {
|
||||
if (owner) {
|
||||
if (owner != XCB_NONE) {
|
||||
m_log.trace("tray: Listen for events on the new selection window");
|
||||
const uint32_t mask{XCB_CW_EVENT_MASK};
|
||||
const uint32_t values[]{XCB_EVENT_MASK_STRUCTURE_NOTIFY};
|
||||
|
@ -987,11 +1008,11 @@ void tray_manager::handle(const evt::selection_clear& evt) {
|
|||
|
||||
try {
|
||||
m_log.warn("Lost systray selection, deactivating...");
|
||||
m_othermanager = m_connection.get_selection_owner(m_atom)->owner;
|
||||
m_othermanager = m_connection.get_selection_owner(m_atom).owner<xcb_window_t>();
|
||||
track_selection_owner(m_othermanager);
|
||||
} catch (const exception& err) {
|
||||
m_log.err("Failed to get systray selection owner");
|
||||
m_othermanager = 0;
|
||||
m_othermanager = XCB_NONE;
|
||||
}
|
||||
|
||||
deactivate(false);
|
||||
|
@ -1053,10 +1074,9 @@ void tray_manager::handle(const evt::reparent_notify& evt) {
|
|||
void tray_manager::handle(const evt::destroy_notify& evt) {
|
||||
if (m_activated && evt->window == m_tray) {
|
||||
deactivate();
|
||||
} else if (!m_activated && evt->window == m_othermanager && evt->window != m_tray) {
|
||||
m_log.trace("tray: Received destroy_notify");
|
||||
// m_log.info("Tray selection available... re-activating");
|
||||
// activate();
|
||||
} else if (!m_activated && evt->window == m_othermanager) {
|
||||
m_log.info("Tray selection available... re-activating");
|
||||
activate();
|
||||
} else if (m_activated && is_embedded(evt->window)) {
|
||||
m_log.trace("tray: Received destroy_notify for client, remove...");
|
||||
remove_client(evt->window);
|
||||
|
|
Loading…
Reference in a new issue