tray: Cleanup client state handling

This commit is contained in:
patrick96 2022-09-14 22:12:13 +02:00
parent 5fd62edfca
commit 63c6b13cbf
No known key found for this signature in database
GPG Key ID: 521E5E03AEBCA1A7
4 changed files with 61 additions and 44 deletions

View File

@ -40,6 +40,8 @@ class tray_client : public non_copyable_mixin {
void hidden(bool state); void hidden(bool state);
bool should_be_mapped() const;
xcb_window_t embedder() const; xcb_window_t embedder() const;
xcb_window_t client() const; xcb_window_t client() const;
@ -97,9 +99,14 @@ class tray_client : public non_copyable_mixin {
*/ */
xembed::info m_xembed; xembed::info m_xembed;
// TODO /**
* Whether the wrapper window is currently mapped.
*/
bool m_mapped{false}; bool m_mapped{false};
/**
* Whether the
*/
bool m_hidden{false}; bool m_hidden{false};
size m_size; size m_size;

View File

@ -58,9 +58,9 @@ struct tray_settings {
using on_update = std::function<void(void)>; using on_update = std::function<void(void)>;
class tray_manager : public xpp::event::sink<evt::expose, evt::visibility_notify, evt::client_message, class tray_manager : public xpp::event::sink<evt::expose, evt::client_message, evt::configure_request,
evt::configure_request, evt::resize_request, evt::selection_clear, evt::property_notify, evt::resize_request, evt::selection_clear, evt::property_notify, evt::reparent_notify,
evt::reparent_notify, evt::destroy_notify, evt::map_notify, evt::unmap_notify>, evt::destroy_notify, evt::map_notify, evt::unmap_notify>,
public signal_receiver<SIGN_PRIORITY_TRAY, signals::ui::update_background, public signal_receiver<SIGN_PRIORITY_TRAY, signals::ui::update_background,
signals::ui_tray::tray_pos_change, signals::ui_tray::tray_visibility> { signals::ui_tray::tray_pos_change, signals::ui_tray::tray_visibility> {
public: public:
@ -81,6 +81,8 @@ class tray_manager : public xpp::event::sink<evt::expose, evt::visibility_notify
bool is_inactive() const; bool is_inactive() const;
bool is_waiting() const; bool is_waiting() const;
bool is_visible() const;
protected: protected:
void reconfigure_window(); void reconfigure_window();
void reconfigure_clients(); void reconfigure_clients();
@ -115,12 +117,11 @@ class tray_manager : public xpp::event::sink<evt::expose, evt::visibility_notify
bool is_embedded(const xcb_window_t& win); bool is_embedded(const xcb_window_t& win);
tray_client* find_client(const xcb_window_t& win); tray_client* find_client(const xcb_window_t& win);
void remove_client(const tray_client& client, bool reconfigure = true); void remove_client(const tray_client& client);
void remove_client(xcb_window_t win, bool reconfigure = true); void remove_client(xcb_window_t win);
bool change_visibility(bool visible); bool change_visibility(bool visible);
void handle(const evt::expose& evt) override; void handle(const evt::expose& evt) override;
void handle(const evt::visibility_notify& evt) override;
void handle(const evt::client_message& evt) override; void handle(const evt::client_message& evt) override;
void handle(const evt::configure_request& evt) override; void handle(const evt::configure_request& evt) override;
void handle(const evt::resize_request& evt) override; void handle(const evt::resize_request& evt) override;

View File

@ -167,6 +167,21 @@ void tray_client::hidden(bool state) {
m_hidden = state; m_hidden = state;
} }
/**
* Whether the current state indicates the client should be mapped.
*/
bool tray_client::should_be_mapped() const {
if (m_hidden) {
return false;
}
if (is_xembed_supported()) {
return m_xembed.is_mapped();
}
return true;
}
xcb_window_t tray_client::embedder() const { xcb_window_t tray_client::embedder() const {
return m_wrapper; return m_wrapper;
} }
@ -209,22 +224,15 @@ void tray_client::add_to_save_set() const {
* Make sure that the window mapping state is correct * Make sure that the window mapping state is correct
*/ */
void tray_client::ensure_state() const { void tray_client::ensure_state() const {
bool should_be_mapped = true; bool new_state = should_be_mapped();
if (is_xembed_supported()) { if (new_state == m_mapped) {
should_be_mapped = m_xembed.is_mapped(); return;
} }
if (m_hidden) { m_log.trace("%s: ensure_state (hidden=%i, mapped=%i, should_be_mapped=%i)", name(), m_hidden, m_mapped, new_state);
should_be_mapped = false;
}
// TODO can we stop here if should_be_mapped == m_mapped? if (new_state) {
m_log.trace(
"%s: ensure_state (hidden=%i, mapped=%i, should_be_mapped=%i)", name(), m_hidden, m_mapped, should_be_mapped);
if (should_be_mapped) {
m_log.trace("%s: Map client", name()); m_log.trace("%s: Map client", name());
m_connection.map_window_checked(embedder()); m_connection.map_window_checked(embedder());
m_connection.map_window_checked(client()); m_connection.map_window_checked(client());

View File

@ -115,6 +115,10 @@ bool tray_manager::is_waiting() const {
return m_state == state::WAITING; return m_state == state::WAITING;
} }
bool tray_manager::is_visible() const {
return is_active() && !m_hidden;
}
/** /**
* Activate systray management * Activate systray management
*/ */
@ -268,13 +272,13 @@ void tray_manager::reconfigure_clients() {
for (auto it = m_clients.rbegin(); it != m_clients.rend(); it++) { for (auto it = m_clients.rbegin(); it != m_clients.rend(); it++) {
try { try {
it->ensure_state(); it->ensure_state();
// TODO skip if the client isn't mapped
it->reconfigure(x, calculate_client_y()); it->reconfigure(x, calculate_client_y());
x += m_opts.client_size.w + m_opts.spacing; x += m_opts.client_size.w + m_opts.spacing;
} catch (const xpp::x::error::window& err) { } catch (const xpp::x::error::window& err) {
// TODO print error
m_log.err("Failed to reconfigure %s, removing ... (%s)", it->name(), err.what()); m_log.err("Failed to reconfigure %s, removing ... (%s)", it->name(), err.what());
remove_client(*it, false); remove_client(*it);
} }
} }
} }
@ -283,8 +287,7 @@ void tray_manager::reconfigure_clients() {
* Refresh the bar window by clearing it along with each client window * Refresh the bar window by clearing it along with each client window
*/ */
void tray_manager::refresh_window() { void tray_manager::refresh_window() {
// TODO create method that checks is_active and !m_hidden if (!is_visible()) {
if (!is_active() || m_hidden) {
return; return;
} }
@ -502,19 +505,19 @@ tray_client* tray_manager::find_client(const xcb_window_t& win) {
/** /**
* Remove tray client * Remove tray client
*/ */
void tray_manager::remove_client(const tray_client& client, bool reconfigure) { void tray_manager::remove_client(const tray_client& client) {
remove_client(client.client(), reconfigure); remove_client(client.client());
} }
/** /**
* Remove tray client by window * Remove tray client by window
*/ */
void tray_manager::remove_client(xcb_window_t win, bool reconfigure) { void tray_manager::remove_client(xcb_window_t win) {
auto old_size = m_clients.size();
m_clients.erase( m_clients.erase(
std::remove_if(m_clients.begin(), m_clients.end(), [win](const auto& client) { return client.match(win); })); std::remove_if(m_clients.begin(), m_clients.end(), [win](const auto& client) { return client.match(win); }));
// TODO remove param. Reconfigure if clients were deleted if (old_size != m_clients.size()) {
if (reconfigure) {
tray_manager::reconfigure(); tray_manager::reconfigure();
} }
} }
@ -551,17 +554,6 @@ void tray_manager::handle(const evt::expose& evt) {
} }
} }
/**
* Event callback : XCB_VISIBILITY_NOTIFY
*/
void tray_manager::handle(const evt::visibility_notify& evt) {
// TODO for which windows is this important?
if (is_active() && !m_clients.empty()) {
m_log.trace("tray: Received visibility_notify for %s", m_connection.id(evt->window));
reconfigure_window();
}
}
/** /**
* Event callback : XCB_CLIENT_MESSAGE * Event callback : XCB_CLIENT_MESSAGE
*/ */
@ -669,14 +661,11 @@ void tray_manager::handle(const evt::property_notify& evt) {
client->query_xembed(); client->query_xembed();
} catch (const xpp::x::error::window& err) { } catch (const xpp::x::error::window& err) {
m_log.err("Failed to query _XEMBED_INFO, removing %s ... (%s)", client->name(), err.what()); m_log.err("Failed to query _XEMBED_INFO, removing %s ... (%s)", client->name(), err.what());
remove_client(*client, true); remove_client(*client);
return; return;
} }
// TODO only reconfigure if should_be_mapped changed client->ensure_state();
if (client->get_xembed().is_mapped()) {
reconfigure();
}
} }
/** /**
@ -723,6 +712,12 @@ void tray_manager::handle(const evt::map_notify& evt) {
redraw_window(); redraw_window();
} else if (is_embedded(evt->window)) { } else if (is_embedded(evt->window)) {
auto client = find_client(evt->window); auto client = find_client(evt->window);
// If we received a notification on the wrapped window, we don't want to do anything.
if (client->embedder() != evt->window) {
return;
}
m_log.trace("%s: Received map_notify", client->name()); m_log.trace("%s: Received map_notify", client->name());
if (!client->mapped()) { if (!client->mapped()) {
@ -738,6 +733,12 @@ void tray_manager::handle(const evt::map_notify& evt) {
void tray_manager::handle(const evt::unmap_notify& evt) { void tray_manager::handle(const evt::unmap_notify& evt) {
if (is_active() && is_embedded(evt->window)) { if (is_active() && is_embedded(evt->window)) {
auto client = find_client(evt->window); auto client = find_client(evt->window);
// If we received a notification on the wrapped window, we don't want to do anything.
if (client->embedder() != evt->window) {
return;
}
m_log.trace("%s: Received unmap_notify", client->name()); m_log.trace("%s: Received unmap_notify", client->name());
if (client->mapped()) { if (client->mapped()) {