fix(tray): Re-activation

This commit is contained in:
Michael Carlberg 2016-12-14 11:34:09 +01:00
parent 8c3f40db5b
commit b11a662d81
5 changed files with 83 additions and 55 deletions

View File

@ -96,7 +96,7 @@ class tray_manager : public xpp::event::sink<evt::expose, evt::visibility_notify
void acquire_selection(); void acquire_selection();
void notify_clients(); void notify_clients();
void notify_clients_delayed(chrono::seconds delay = 1s); void notify_clients_delayed();
void track_selection_owner(xcb_window_t owner); void track_selection_owner(xcb_window_t owner);
void process_docking_request(xcb_window_t win); 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}; bool m_restacked{false};
std::mutex m_mtx; std::mutex m_mtx;
chrono::time_point<chrono::system_clock, chrono::milliseconds> m_drawtime;
bool m_firstactivation{true};
}; };
POLYBAR_NS_END POLYBAR_NS_END

View File

@ -26,7 +26,7 @@ config::make_type config::make(string path, string bar) {
* Construct config object * Construct config object
*/ */
config::config(const logger& logger, const xresource_manager& xrm, string&& path, string&& bar) 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)) { if (!file_util::exists(m_file)) {
throw application_error("Could not find config file: " + 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 * Parse key/value pairs from the configuration file
*/ */
void config::parse_file() { void config::parse_file() {
std::ifstream in(m_file.c_str()); std::ifstream in(m_file);
string line; string line;
string section; string section;
uint32_t lineno{0}; uint32_t lineno{0};
@ -117,8 +117,7 @@ void config::parse_file() {
line.erase(0, equal_pos + 1); 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)); m_sections[section].emplace_hint(it, move(key), move(value));
} }

View File

@ -120,10 +120,8 @@ void eventloop::stop() {
* Enqueue event * Enqueue event
*/ */
bool eventloop::enqueue(event&& evt) { bool eventloop::enqueue(event&& evt) {
uint8_t type{static_cast<uint8_t>(evt.type)};
if (!m_queue.enqueue(move(evt))) { 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; return false;
} }

View File

@ -122,30 +122,37 @@ namespace string_util {
/** /**
* Remove needle from the start of the string * Remove needle from the start of the string
*/ */
string ltrim(string&& haystack, const char& needle) { string ltrim(string&& value, const char& needle) {
string str(haystack); if (value.empty()) {
while (str[0] == needle) { return "";
str.erase(0, 1);
} }
return str; while (*value.begin() == needle) {
value.erase(0, 1);
}
return forward<string>(value);
} }
/** /**
* Remove needle from the end of the string * Remove needle from the end of the string
*/ */
string rtrim(string&& haystack, const char& needle) { string rtrim(string&& value, const char& needle) {
string str(haystack); if (value.empty()) {
while (str[str.length() - 1] == needle) { return "";
str.erase(str.length() - 1, 1);
} }
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 * Remove needle from the start and end of the string
*/ */
string trim(string&& value, const char& needle) { 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);
} }
/** /**

View File

@ -51,12 +51,15 @@ tray_manager::make_type tray_manager::make() {
} }
tray_manager::tray_manager(connection& conn, signal_emitter& emitter, const logger& logger) 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() { tray_manager::~tray_manager() {
if (m_delaythread.joinable()) { if (m_delaythread.joinable()) {
m_delaythread.join(); m_delaythread.join();
} }
m_connection.detach_sink(this, SINK_PRIORITY_TRAY);
deactivate(); deactivate();
} }
@ -198,7 +201,6 @@ void tray_manager::activate() {
m_opts.running = true; m_opts.running = true;
m_sig.attach(this); m_sig.attach(this);
m_connection.attach_sink(this, SINK_PRIORITY_TRAY);
try { try {
create_window(); create_window();
@ -221,13 +223,16 @@ void tray_manager::activate() {
// notify clients waiting for a manager. // notify clients waiting for a manager.
acquire_selection(); acquire_selection();
// Notify pending tray clients
notify_clients();
// Send delayed notification // Send delayed notification
if (m_othermanager != XCB_NONE && m_othermanager != m_tray) { if (!m_firstactivation) {
notify_clients_delayed(); 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_opts.running = false;
m_sig.detach(this); m_sig.detach(this);
m_connection.detach_sink(this, SINK_PRIORITY_TRAY);
if (!m_connection.connection_has_error() && clear_selection && m_acquired_selection) { if (!m_connection.connection_has_error() && clear_selection && m_acquired_selection) {
m_log.trace("tray: Unset selection owner"); m_log.trace("tray: Unset selection owner");
@ -506,7 +510,15 @@ void tray_manager::refresh_window() {
* Redraw window * Redraw window
*/ */
void tray_manager::redraw_window(bool realloc_bg) { 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); reconfigure_bg(realloc_bg);
refresh_window(); refresh_window();
} }
@ -669,23 +681,34 @@ void tray_manager::set_tray_colors() {
* Acquire the systray selection * Acquire the systray selection
*/ */
void tray_manager::acquire_selection() { void tray_manager::acquire_selection() {
auto reply = m_connection.get_selection_owner_unchecked(m_atom); m_othermanager = XCB_NONE;
auto owner = reply.owner<xcb_window_t>(); ;
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) { if (owner == m_tray) {
m_log.info("tray: Already managing the systray selection"); m_log.trace("tray: Already managing the systray selection");
} else if ((m_othermanager = owner) != XCB_NONE) { m_acquired_selection = true;
m_log.info("Replacing selection manager %s", m_connection.id(owner)); return;
} 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;
} }
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 * Send delayed notification to pending clients
*/ */
void tray_manager::notify_clients_delayed(chrono::seconds delay) { void tray_manager::notify_clients_delayed() {
if (!m_activated) { if (m_delaythread.joinable()) {
return;
} else if (m_delaythread.joinable()) {
m_delaythread.join(); m_delaythread.join();
} }
m_delaythread = thread([this](auto&& delay) { m_delaythread = thread([this]() {
this_thread::sleep_for(delay); this_thread::sleep_for(1s);
notify_clients(); 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 * If it gets destroyed or goes away we can reactivate the tray_manager
*/ */
void tray_manager::track_selection_owner(xcb_window_t owner) { 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"); m_log.trace("tray: Listen for events on the new selection window");
const uint32_t mask{XCB_CW_EVENT_MASK}; const uint32_t mask{XCB_CW_EVENT_MASK};
const uint32_t values[]{XCB_EVENT_MASK_STRUCTURE_NOTIFY}; const uint32_t values[]{XCB_EVENT_MASK_STRUCTURE_NOTIFY};
@ -987,11 +1008,11 @@ void tray_manager::handle(const evt::selection_clear& evt) {
try { try {
m_log.warn("Lost systray selection, deactivating..."); 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); track_selection_owner(m_othermanager);
} catch (const exception& err) { } catch (const exception& err) {
m_log.err("Failed to get systray selection owner"); m_log.err("Failed to get systray selection owner");
m_othermanager = 0; m_othermanager = XCB_NONE;
} }
deactivate(false); deactivate(false);
@ -1053,10 +1074,9 @@ void tray_manager::handle(const evt::reparent_notify& evt) {
void tray_manager::handle(const evt::destroy_notify& evt) { void tray_manager::handle(const evt::destroy_notify& evt) {
if (m_activated && evt->window == m_tray) { if (m_activated && evt->window == m_tray) {
deactivate(); deactivate();
} else if (!m_activated && evt->window == m_othermanager && evt->window != m_tray) { } else if (!m_activated && evt->window == m_othermanager) {
m_log.trace("tray: Received destroy_notify"); m_log.info("Tray selection available... re-activating");
// m_log.info("Tray selection available... re-activating"); activate();
// activate();
} else if (m_activated && is_embedded(evt->window)) { } else if (m_activated && is_embedded(evt->window)) {
m_log.trace("tray: Received destroy_notify for client, remove..."); m_log.trace("tray: Received destroy_notify for client, remove...");
remove_client(evt->window); remove_client(evt->window);