polybar/src/modules/xworkspaces.cpp

450 lines
14 KiB
C++
Raw Normal View History

feat(xworkspaces): Support occupied workspaces (#882) A workspace is occupied if it is not active and there is at least one window managed by the WM (`_NET_CLIENT_LIST`) that has set `_NET_WM_DESKTOP` to that workspace. The behavior when `_NET_WM_DESKTOP` is not set is not yet clear but this is unlikely to happen since most WMs will position windows on some desktop. Closes #874 Fixes #1444 Fixes #1033 * Set Desktop OCCUPIED if a window moves there This covers more of an edge-case. I did this first by accident, it might vanish later on. * Replace tracking change of WS with currently used WS * Untrack occupied workspaces * Track windows and their desktops in pairs * Match type of occupied_desktops with current_desktop Because the index needs to be matched later on, type mismatches would be non-ideal. * Recreate the occupied desktops everytime and remove duplicates * Readd support for moving windows to other desktops * Use less characters to empty the vector * Rename variable storing the desktops * Recount windows on every occasion This alone simplifies the management and the lookup for occupation of a workspace * Keep track of number of windows in every workspace * Add debugging output that shall be removed before merging * Remove obsolete TODO * m_client_list should always be diff'd, since the desktop may change Therefore we update the desktop-count tally every time the client_list changes. It may just be a desktop-change without a change of clients.size()... * Add more logging-spam to understand window/desktop lifecycle * Lock event-handler to serialize handling of events * Fix occupied workspace counting and change to bool array Also, performance improvements when diffing new and old client lists * Fix crash when all clients are removed * Conform to linter and styleguide * Shorten conditional as it is standard enough Since this only guards against 0-divisions, it can be shortened without risking too much confusion down the road. * Guard against multiple threads accessing and modifying data Fixes #1444 Modification of internal data happens through the handle-method, while the build-method tries to access the data structures for display. Since some modifications clear e.g. the m_viewports, references may become invalid between looping over them an accessing them. The mutex should guard against this simultanuous access. * Do not 'adopt_lock', because calls come from very different threads To my understanding, adopt_lock has some dependency on the mutex-ownership. Since the lock is once called from the inside (in handle) and once from the outside (in build), there might be a problem. After brief testing, the segfaults happened fewer times. See #1444 * Also listen to _NET_WM_DESKTOP In order to move a window from one desktop to another, it is sufficient to set the desktop-property of that window. xmonad fires a lot of events in the case of moving a window, herbstluftwm only updates the _NET_WM_DESKTOP-atom of the window. This change reloads the clientlist in order to correctly set the desktop state "occupied". * Describe need and use of mutex It might be possible to relieve the guard in xworkspaces_module::handle, but I am unsure about this. Since xmonad emits a lot of events on almost every minor change, I would let the guard keep its post, avoiding race-conditions in event-handling. * Give temporary variables better names * Clarify purpose of loop About 80% of this comment are taken from https://github.com/jaagr/polybar/pull/882#discussion_r255317363 * Remove merge-remainder * Use a simpler method to list occupied desktops. Co-authored-by: Jérôme Boulmier <jerome.boulmier@outlook.fr> * Document m_clients field
2019-10-21 08:00:38 +00:00
#include "modules/xworkspaces.hpp"
2017-01-25 02:29:11 +00:00
#include <algorithm>
#include <set>
2016-11-26 08:38:55 +00:00
#include <utility>
#include "drawtypes/iconset.hpp"
#include "drawtypes/label.hpp"
#include "modules/meta/base.inl"
2016-12-04 03:11:47 +00:00
#include "utils/math.hpp"
#include "x11/atoms.hpp"
#include "x11/connection.hpp"
#include "x11/icccm.hpp"
POLYBAR_NS
2017-01-25 02:29:11 +00:00
namespace {
inline bool operator==(const position& a, const position& b) {
return a.x + a.y == b.x + b.y;
}
2022-03-06 15:40:42 +00:00
} // namespace
2017-01-25 02:29:11 +00:00
/**
* Defines a lexicographical order on position
*/
bool operator<(const position& a, const position& b) {
return std::make_tuple(a.x, a.y) < std::make_tuple(b.x, b.y);
}
namespace modules {
template class module<xworkspaces_module>;
/**
* Construct module
*/
xworkspaces_module::xworkspaces_module(const bar_settings& bar, string name_)
2022-03-06 15:40:42 +00:00
: static_module<xworkspaces_module>(bar, move(name_))
, m_connection(connection::make())
, m_ewmh(ewmh_util::initialize()) {
m_router->register_action_with_data(EVENT_FOCUS, [this](const std::string& data) { action_focus(data); });
m_router->register_action(EVENT_NEXT, [this]() { action_next(); });
m_router->register_action(EVENT_PREV, [this]() { action_prev(); });
2016-11-26 08:38:55 +00:00
// Load config values
m_pinworkspaces = m_conf.get(name(), "pin-workspaces", m_pinworkspaces);
m_click = m_conf.get(name(), "enable-click", m_click);
m_scroll = m_conf.get(name(), "enable-scroll", m_scroll);
m_revscroll = m_conf.get(name(), "reverse-scroll", m_revscroll);
// Add formats and elements
2016-11-26 08:38:55 +00:00
m_formatter->add(DEFAULT_FORMAT, TAG_LABEL_STATE, {TAG_LABEL_STATE, TAG_LABEL_MONITOR});
2016-11-26 08:38:55 +00:00
if (m_formatter->has(TAG_LABEL_MONITOR)) {
m_monitorlabel = load_optional_label(m_conf, name(), "label-monitor", DEFAULT_LABEL_MONITOR);
}
if (m_formatter->has(TAG_LABEL_STATE)) {
// clang-format off
m_labels.insert(make_pair(
desktop_state::ACTIVE, load_optional_label(m_conf, name(), "label-active", DEFAULT_LABEL_STATE)));
2016-11-26 08:38:55 +00:00
m_labels.insert(make_pair(
desktop_state::OCCUPIED, load_optional_label(m_conf, name(), "label-occupied", DEFAULT_LABEL_STATE)));
m_labels.insert(make_pair(
desktop_state::URGENT, load_optional_label(m_conf, name(), "label-urgent", DEFAULT_LABEL_STATE)));
m_labels.insert(make_pair(
desktop_state::EMPTY, load_optional_label(m_conf, name(), "label-empty", DEFAULT_LABEL_STATE)));
// clang-format on
}
m_icons = std::make_shared<iconset>();
m_icons->add(DEFAULT_ICON, std::make_shared<label>(m_conf.get(name(), DEFAULT_ICON, ""s)));
int i = 0;
for (const auto& workspace : m_conf.get_list<string>(name(), "icon", {})) {
auto vec = string_util::tokenize(workspace, ';');
if (vec.size() == 2) {
m_icons->add(vec[0], std::make_shared<label>(vec[1]));
} else {
2022-03-06 15:40:42 +00:00
m_log.err(
"%s: Ignoring icon-%d because it has %s semicolons", name(), i, vec.size() > 2 ? "too many" : "too few");
}
i++;
}
2017-01-25 02:29:11 +00:00
// Get list of monitors
m_monitors = randr_util::get_monitors(m_connection, m_connection.root(), false);
// Get desktop details
m_desktop_names = get_desktop_names();
update_current_desktop();
2017-01-25 02:29:11 +00:00
rebuild_desktops();
// Get _NET_CLIENT_LIST
rebuild_clientlist();
feat(xworkspaces): Support occupied workspaces (#882) A workspace is occupied if it is not active and there is at least one window managed by the WM (`_NET_CLIENT_LIST`) that has set `_NET_WM_DESKTOP` to that workspace. The behavior when `_NET_WM_DESKTOP` is not set is not yet clear but this is unlikely to happen since most WMs will position windows on some desktop. Closes #874 Fixes #1444 Fixes #1033 * Set Desktop OCCUPIED if a window moves there This covers more of an edge-case. I did this first by accident, it might vanish later on. * Replace tracking change of WS with currently used WS * Untrack occupied workspaces * Track windows and their desktops in pairs * Match type of occupied_desktops with current_desktop Because the index needs to be matched later on, type mismatches would be non-ideal. * Recreate the occupied desktops everytime and remove duplicates * Readd support for moving windows to other desktops * Use less characters to empty the vector * Rename variable storing the desktops * Recount windows on every occasion This alone simplifies the management and the lookup for occupation of a workspace * Keep track of number of windows in every workspace * Add debugging output that shall be removed before merging * Remove obsolete TODO * m_client_list should always be diff'd, since the desktop may change Therefore we update the desktop-count tally every time the client_list changes. It may just be a desktop-change without a change of clients.size()... * Add more logging-spam to understand window/desktop lifecycle * Lock event-handler to serialize handling of events * Fix occupied workspace counting and change to bool array Also, performance improvements when diffing new and old client lists * Fix crash when all clients are removed * Conform to linter and styleguide * Shorten conditional as it is standard enough Since this only guards against 0-divisions, it can be shortened without risking too much confusion down the road. * Guard against multiple threads accessing and modifying data Fixes #1444 Modification of internal data happens through the handle-method, while the build-method tries to access the data structures for display. Since some modifications clear e.g. the m_viewports, references may become invalid between looping over them an accessing them. The mutex should guard against this simultanuous access. * Do not 'adopt_lock', because calls come from very different threads To my understanding, adopt_lock has some dependency on the mutex-ownership. Since the lock is once called from the inside (in handle) and once from the outside (in build), there might be a problem. After brief testing, the segfaults happened fewer times. See #1444 * Also listen to _NET_WM_DESKTOP In order to move a window from one desktop to another, it is sufficient to set the desktop-property of that window. xmonad fires a lot of events in the case of moving a window, herbstluftwm only updates the _NET_WM_DESKTOP-atom of the window. This change reloads the clientlist in order to correctly set the desktop state "occupied". * Describe need and use of mutex It might be possible to relieve the guard in xworkspaces_module::handle, but I am unsure about this. Since xmonad emits a lot of events on almost every minor change, I would let the guard keep its post, avoiding race-conditions in event-handling. * Give temporary variables better names * Clarify purpose of loop About 80% of this comment are taken from https://github.com/jaagr/polybar/pull/882#discussion_r255317363 * Remove merge-remainder * Use a simpler method to list occupied desktops. Co-authored-by: Jérôme Boulmier <jerome.boulmier@outlook.fr> * Document m_clients field
2019-10-21 08:00:38 +00:00
rebuild_desktop_states();
}
void xworkspaces_module::update_current_desktop() {
m_current_desktop = ewmh_util::get_current_desktop();
}
/**
* Handler for XCB_PROPERTY_NOTIFY events
*/
void xworkspaces_module::handle(const evt::property_notify& evt) {
if (evt->atom == m_ewmh->_NET_CLIENT_LIST || evt->atom == m_ewmh->_NET_WM_DESKTOP) {
2017-01-25 02:29:11 +00:00
rebuild_clientlist();
feat(xworkspaces): Support occupied workspaces (#882) A workspace is occupied if it is not active and there is at least one window managed by the WM (`_NET_CLIENT_LIST`) that has set `_NET_WM_DESKTOP` to that workspace. The behavior when `_NET_WM_DESKTOP` is not set is not yet clear but this is unlikely to happen since most WMs will position windows on some desktop. Closes #874 Fixes #1444 Fixes #1033 * Set Desktop OCCUPIED if a window moves there This covers more of an edge-case. I did this first by accident, it might vanish later on. * Replace tracking change of WS with currently used WS * Untrack occupied workspaces * Track windows and their desktops in pairs * Match type of occupied_desktops with current_desktop Because the index needs to be matched later on, type mismatches would be non-ideal. * Recreate the occupied desktops everytime and remove duplicates * Readd support for moving windows to other desktops * Use less characters to empty the vector * Rename variable storing the desktops * Recount windows on every occasion This alone simplifies the management and the lookup for occupation of a workspace * Keep track of number of windows in every workspace * Add debugging output that shall be removed before merging * Remove obsolete TODO * m_client_list should always be diff'd, since the desktop may change Therefore we update the desktop-count tally every time the client_list changes. It may just be a desktop-change without a change of clients.size()... * Add more logging-spam to understand window/desktop lifecycle * Lock event-handler to serialize handling of events * Fix occupied workspace counting and change to bool array Also, performance improvements when diffing new and old client lists * Fix crash when all clients are removed * Conform to linter and styleguide * Shorten conditional as it is standard enough Since this only guards against 0-divisions, it can be shortened without risking too much confusion down the road. * Guard against multiple threads accessing and modifying data Fixes #1444 Modification of internal data happens through the handle-method, while the build-method tries to access the data structures for display. Since some modifications clear e.g. the m_viewports, references may become invalid between looping over them an accessing them. The mutex should guard against this simultanuous access. * Do not 'adopt_lock', because calls come from very different threads To my understanding, adopt_lock has some dependency on the mutex-ownership. Since the lock is once called from the inside (in handle) and once from the outside (in build), there might be a problem. After brief testing, the segfaults happened fewer times. See #1444 * Also listen to _NET_WM_DESKTOP In order to move a window from one desktop to another, it is sufficient to set the desktop-property of that window. xmonad fires a lot of events in the case of moving a window, herbstluftwm only updates the _NET_WM_DESKTOP-atom of the window. This change reloads the clientlist in order to correctly set the desktop state "occupied". * Describe need and use of mutex It might be possible to relieve the guard in xworkspaces_module::handle, but I am unsure about this. Since xmonad emits a lot of events on almost every minor change, I would let the guard keep its post, avoiding race-conditions in event-handling. * Give temporary variables better names * Clarify purpose of loop About 80% of this comment are taken from https://github.com/jaagr/polybar/pull/882#discussion_r255317363 * Remove merge-remainder * Use a simpler method to list occupied desktops. Co-authored-by: Jérôme Boulmier <jerome.boulmier@outlook.fr> * Document m_clients field
2019-10-21 08:00:38 +00:00
rebuild_desktop_states();
} else if (evt->atom == m_ewmh->_NET_DESKTOP_NAMES || evt->atom == m_ewmh->_NET_NUMBER_OF_DESKTOPS) {
m_desktop_names = get_desktop_names();
2017-01-25 02:29:11 +00:00
rebuild_desktops();
feat(xworkspaces): Support occupied workspaces (#882) A workspace is occupied if it is not active and there is at least one window managed by the WM (`_NET_CLIENT_LIST`) that has set `_NET_WM_DESKTOP` to that workspace. The behavior when `_NET_WM_DESKTOP` is not set is not yet clear but this is unlikely to happen since most WMs will position windows on some desktop. Closes #874 Fixes #1444 Fixes #1033 * Set Desktop OCCUPIED if a window moves there This covers more of an edge-case. I did this first by accident, it might vanish later on. * Replace tracking change of WS with currently used WS * Untrack occupied workspaces * Track windows and their desktops in pairs * Match type of occupied_desktops with current_desktop Because the index needs to be matched later on, type mismatches would be non-ideal. * Recreate the occupied desktops everytime and remove duplicates * Readd support for moving windows to other desktops * Use less characters to empty the vector * Rename variable storing the desktops * Recount windows on every occasion This alone simplifies the management and the lookup for occupation of a workspace * Keep track of number of windows in every workspace * Add debugging output that shall be removed before merging * Remove obsolete TODO * m_client_list should always be diff'd, since the desktop may change Therefore we update the desktop-count tally every time the client_list changes. It may just be a desktop-change without a change of clients.size()... * Add more logging-spam to understand window/desktop lifecycle * Lock event-handler to serialize handling of events * Fix occupied workspace counting and change to bool array Also, performance improvements when diffing new and old client lists * Fix crash when all clients are removed * Conform to linter and styleguide * Shorten conditional as it is standard enough Since this only guards against 0-divisions, it can be shortened without risking too much confusion down the road. * Guard against multiple threads accessing and modifying data Fixes #1444 Modification of internal data happens through the handle-method, while the build-method tries to access the data structures for display. Since some modifications clear e.g. the m_viewports, references may become invalid between looping over them an accessing them. The mutex should guard against this simultanuous access. * Do not 'adopt_lock', because calls come from very different threads To my understanding, adopt_lock has some dependency on the mutex-ownership. Since the lock is once called from the inside (in handle) and once from the outside (in build), there might be a problem. After brief testing, the segfaults happened fewer times. See #1444 * Also listen to _NET_WM_DESKTOP In order to move a window from one desktop to another, it is sufficient to set the desktop-property of that window. xmonad fires a lot of events in the case of moving a window, herbstluftwm only updates the _NET_WM_DESKTOP-atom of the window. This change reloads the clientlist in order to correctly set the desktop state "occupied". * Describe need and use of mutex It might be possible to relieve the guard in xworkspaces_module::handle, but I am unsure about this. Since xmonad emits a lot of events on almost every minor change, I would let the guard keep its post, avoiding race-conditions in event-handling. * Give temporary variables better names * Clarify purpose of loop About 80% of this comment are taken from https://github.com/jaagr/polybar/pull/882#discussion_r255317363 * Remove merge-remainder * Use a simpler method to list occupied desktops. Co-authored-by: Jérôme Boulmier <jerome.boulmier@outlook.fr> * Document m_clients field
2019-10-21 08:00:38 +00:00
rebuild_clientlist();
2017-01-25 02:29:11 +00:00
rebuild_desktop_states();
} else if (evt->atom == m_ewmh->_NET_CURRENT_DESKTOP) {
update_current_desktop();
2017-01-25 02:29:11 +00:00
rebuild_desktop_states();
} else if (evt->atom == WM_HINTS) {
rebuild_urgent_hints();
rebuild_desktop_states();
} else {
return;
}
broadcast();
}
/**
2017-01-25 02:29:11 +00:00
* Rebuild the list of managed clients
*/
2017-01-25 02:29:11 +00:00
void xworkspaces_module::rebuild_clientlist() {
feat(xworkspaces): Support occupied workspaces (#882) A workspace is occupied if it is not active and there is at least one window managed by the WM (`_NET_CLIENT_LIST`) that has set `_NET_WM_DESKTOP` to that workspace. The behavior when `_NET_WM_DESKTOP` is not set is not yet clear but this is unlikely to happen since most WMs will position windows on some desktop. Closes #874 Fixes #1444 Fixes #1033 * Set Desktop OCCUPIED if a window moves there This covers more of an edge-case. I did this first by accident, it might vanish later on. * Replace tracking change of WS with currently used WS * Untrack occupied workspaces * Track windows and their desktops in pairs * Match type of occupied_desktops with current_desktop Because the index needs to be matched later on, type mismatches would be non-ideal. * Recreate the occupied desktops everytime and remove duplicates * Readd support for moving windows to other desktops * Use less characters to empty the vector * Rename variable storing the desktops * Recount windows on every occasion This alone simplifies the management and the lookup for occupation of a workspace * Keep track of number of windows in every workspace * Add debugging output that shall be removed before merging * Remove obsolete TODO * m_client_list should always be diff'd, since the desktop may change Therefore we update the desktop-count tally every time the client_list changes. It may just be a desktop-change without a change of clients.size()... * Add more logging-spam to understand window/desktop lifecycle * Lock event-handler to serialize handling of events * Fix occupied workspace counting and change to bool array Also, performance improvements when diffing new and old client lists * Fix crash when all clients are removed * Conform to linter and styleguide * Shorten conditional as it is standard enough Since this only guards against 0-divisions, it can be shortened without risking too much confusion down the road. * Guard against multiple threads accessing and modifying data Fixes #1444 Modification of internal data happens through the handle-method, while the build-method tries to access the data structures for display. Since some modifications clear e.g. the m_viewports, references may become invalid between looping over them an accessing them. The mutex should guard against this simultanuous access. * Do not 'adopt_lock', because calls come from very different threads To my understanding, adopt_lock has some dependency on the mutex-ownership. Since the lock is once called from the inside (in handle) and once from the outside (in build), there might be a problem. After brief testing, the segfaults happened fewer times. See #1444 * Also listen to _NET_WM_DESKTOP In order to move a window from one desktop to another, it is sufficient to set the desktop-property of that window. xmonad fires a lot of events in the case of moving a window, herbstluftwm only updates the _NET_WM_DESKTOP-atom of the window. This change reloads the clientlist in order to correctly set the desktop state "occupied". * Describe need and use of mutex It might be possible to relieve the guard in xworkspaces_module::handle, but I am unsure about this. Since xmonad emits a lot of events on almost every minor change, I would let the guard keep its post, avoiding race-conditions in event-handling. * Give temporary variables better names * Clarify purpose of loop About 80% of this comment are taken from https://github.com/jaagr/polybar/pull/882#discussion_r255317363 * Remove merge-remainder * Use a simpler method to list occupied desktops. Co-authored-by: Jérôme Boulmier <jerome.boulmier@outlook.fr> * Document m_clients field
2019-10-21 08:00:38 +00:00
vector<xcb_window_t> newclients = ewmh_util::get_client_list();
std::sort(newclients.begin(), newclients.end());
for (auto&& client : newclients) {
if (m_clients.count(client) == 0) {
try {
// new client: listen for changes (wm_hint or desktop)
m_connection.ensure_event_mask(client, XCB_EVENT_MASK_PROPERTY_CHANGE);
} catch (const xpp::x::error::window& e) {
/*
* The "new client" may have already disappeared between reading the
* client list and setting the event mask.
* This is not a severe issue and it will eventually correct itself
* when a new _NET_CLIENT_LIST value is set.
*/
m_log.info("%s: New client window no longer exists, ignoring...");
}
2017-01-25 02:29:11 +00:00
}
2016-11-26 08:38:55 +00:00
}
feat(xworkspaces): Support occupied workspaces (#882) A workspace is occupied if it is not active and there is at least one window managed by the WM (`_NET_CLIENT_LIST`) that has set `_NET_WM_DESKTOP` to that workspace. The behavior when `_NET_WM_DESKTOP` is not set is not yet clear but this is unlikely to happen since most WMs will position windows on some desktop. Closes #874 Fixes #1444 Fixes #1033 * Set Desktop OCCUPIED if a window moves there This covers more of an edge-case. I did this first by accident, it might vanish later on. * Replace tracking change of WS with currently used WS * Untrack occupied workspaces * Track windows and their desktops in pairs * Match type of occupied_desktops with current_desktop Because the index needs to be matched later on, type mismatches would be non-ideal. * Recreate the occupied desktops everytime and remove duplicates * Readd support for moving windows to other desktops * Use less characters to empty the vector * Rename variable storing the desktops * Recount windows on every occasion This alone simplifies the management and the lookup for occupation of a workspace * Keep track of number of windows in every workspace * Add debugging output that shall be removed before merging * Remove obsolete TODO * m_client_list should always be diff'd, since the desktop may change Therefore we update the desktop-count tally every time the client_list changes. It may just be a desktop-change without a change of clients.size()... * Add more logging-spam to understand window/desktop lifecycle * Lock event-handler to serialize handling of events * Fix occupied workspace counting and change to bool array Also, performance improvements when diffing new and old client lists * Fix crash when all clients are removed * Conform to linter and styleguide * Shorten conditional as it is standard enough Since this only guards against 0-divisions, it can be shortened without risking too much confusion down the road. * Guard against multiple threads accessing and modifying data Fixes #1444 Modification of internal data happens through the handle-method, while the build-method tries to access the data structures for display. Since some modifications clear e.g. the m_viewports, references may become invalid between looping over them an accessing them. The mutex should guard against this simultanuous access. * Do not 'adopt_lock', because calls come from very different threads To my understanding, adopt_lock has some dependency on the mutex-ownership. Since the lock is once called from the inside (in handle) and once from the outside (in build), there might be a problem. After brief testing, the segfaults happened fewer times. See #1444 * Also listen to _NET_WM_DESKTOP In order to move a window from one desktop to another, it is sufficient to set the desktop-property of that window. xmonad fires a lot of events in the case of moving a window, herbstluftwm only updates the _NET_WM_DESKTOP-atom of the window. This change reloads the clientlist in order to correctly set the desktop state "occupied". * Describe need and use of mutex It might be possible to relieve the guard in xworkspaces_module::handle, but I am unsure about this. Since xmonad emits a lot of events on almost every minor change, I would let the guard keep its post, avoiding race-conditions in event-handling. * Give temporary variables better names * Clarify purpose of loop About 80% of this comment are taken from https://github.com/jaagr/polybar/pull/882#discussion_r255317363 * Remove merge-remainder * Use a simpler method to list occupied desktops. Co-authored-by: Jérôme Boulmier <jerome.boulmier@outlook.fr> * Document m_clients field
2019-10-21 08:00:38 +00:00
// rebuild entire mapping of clients to desktops
m_clients.clear();
m_windows.clear();
feat(xworkspaces): Support occupied workspaces (#882) A workspace is occupied if it is not active and there is at least one window managed by the WM (`_NET_CLIENT_LIST`) that has set `_NET_WM_DESKTOP` to that workspace. The behavior when `_NET_WM_DESKTOP` is not set is not yet clear but this is unlikely to happen since most WMs will position windows on some desktop. Closes #874 Fixes #1444 Fixes #1033 * Set Desktop OCCUPIED if a window moves there This covers more of an edge-case. I did this first by accident, it might vanish later on. * Replace tracking change of WS with currently used WS * Untrack occupied workspaces * Track windows and their desktops in pairs * Match type of occupied_desktops with current_desktop Because the index needs to be matched later on, type mismatches would be non-ideal. * Recreate the occupied desktops everytime and remove duplicates * Readd support for moving windows to other desktops * Use less characters to empty the vector * Rename variable storing the desktops * Recount windows on every occasion This alone simplifies the management and the lookup for occupation of a workspace * Keep track of number of windows in every workspace * Add debugging output that shall be removed before merging * Remove obsolete TODO * m_client_list should always be diff'd, since the desktop may change Therefore we update the desktop-count tally every time the client_list changes. It may just be a desktop-change without a change of clients.size()... * Add more logging-spam to understand window/desktop lifecycle * Lock event-handler to serialize handling of events * Fix occupied workspace counting and change to bool array Also, performance improvements when diffing new and old client lists * Fix crash when all clients are removed * Conform to linter and styleguide * Shorten conditional as it is standard enough Since this only guards against 0-divisions, it can be shortened without risking too much confusion down the road. * Guard against multiple threads accessing and modifying data Fixes #1444 Modification of internal data happens through the handle-method, while the build-method tries to access the data structures for display. Since some modifications clear e.g. the m_viewports, references may become invalid between looping over them an accessing them. The mutex should guard against this simultanuous access. * Do not 'adopt_lock', because calls come from very different threads To my understanding, adopt_lock has some dependency on the mutex-ownership. Since the lock is once called from the inside (in handle) and once from the outside (in build), there might be a problem. After brief testing, the segfaults happened fewer times. See #1444 * Also listen to _NET_WM_DESKTOP In order to move a window from one desktop to another, it is sufficient to set the desktop-property of that window. xmonad fires a lot of events in the case of moving a window, herbstluftwm only updates the _NET_WM_DESKTOP-atom of the window. This change reloads the clientlist in order to correctly set the desktop state "occupied". * Describe need and use of mutex It might be possible to relieve the guard in xworkspaces_module::handle, but I am unsure about this. Since xmonad emits a lot of events on almost every minor change, I would let the guard keep its post, avoiding race-conditions in event-handling. * Give temporary variables better names * Clarify purpose of loop About 80% of this comment are taken from https://github.com/jaagr/polybar/pull/882#discussion_r255317363 * Remove merge-remainder * Use a simpler method to list occupied desktops. Co-authored-by: Jérôme Boulmier <jerome.boulmier@outlook.fr> * Document m_clients field
2019-10-21 08:00:38 +00:00
for (auto&& client : newclients) {
auto desk = ewmh_util::get_desktop_from_window(client);
m_clients[client] = desk;
m_windows[desk]++;
}
rebuild_urgent_hints();
}
/**
* Goes through all clients and updates the urgent hints on the desktop they are on.
*/
void xworkspaces_module::rebuild_urgent_hints() {
m_urgent_desktops.assign(m_desktop_names.size(), false);
for (auto&& client : ewmh_util::get_client_list()) {
uint32_t desk = ewmh_util::get_desktop_from_window(client);
/*
* EWMH allows for 0xFFFFFFFF to be returned here, which means the window
* should appear on all desktops.
*
* We don't take those windows into account for the urgency hint because
* it would mark all workspaces as urgent.
*/
if (desk < m_urgent_desktops.size()) {
m_urgent_desktops[desk] = m_urgent_desktops[desk] || icccm_util::get_wm_urgency(m_connection, client);
}
feat(xworkspaces): Support occupied workspaces (#882) A workspace is occupied if it is not active and there is at least one window managed by the WM (`_NET_CLIENT_LIST`) that has set `_NET_WM_DESKTOP` to that workspace. The behavior when `_NET_WM_DESKTOP` is not set is not yet clear but this is unlikely to happen since most WMs will position windows on some desktop. Closes #874 Fixes #1444 Fixes #1033 * Set Desktop OCCUPIED if a window moves there This covers more of an edge-case. I did this first by accident, it might vanish later on. * Replace tracking change of WS with currently used WS * Untrack occupied workspaces * Track windows and their desktops in pairs * Match type of occupied_desktops with current_desktop Because the index needs to be matched later on, type mismatches would be non-ideal. * Recreate the occupied desktops everytime and remove duplicates * Readd support for moving windows to other desktops * Use less characters to empty the vector * Rename variable storing the desktops * Recount windows on every occasion This alone simplifies the management and the lookup for occupation of a workspace * Keep track of number of windows in every workspace * Add debugging output that shall be removed before merging * Remove obsolete TODO * m_client_list should always be diff'd, since the desktop may change Therefore we update the desktop-count tally every time the client_list changes. It may just be a desktop-change without a change of clients.size()... * Add more logging-spam to understand window/desktop lifecycle * Lock event-handler to serialize handling of events * Fix occupied workspace counting and change to bool array Also, performance improvements when diffing new and old client lists * Fix crash when all clients are removed * Conform to linter and styleguide * Shorten conditional as it is standard enough Since this only guards against 0-divisions, it can be shortened without risking too much confusion down the road. * Guard against multiple threads accessing and modifying data Fixes #1444 Modification of internal data happens through the handle-method, while the build-method tries to access the data structures for display. Since some modifications clear e.g. the m_viewports, references may become invalid between looping over them an accessing them. The mutex should guard against this simultanuous access. * Do not 'adopt_lock', because calls come from very different threads To my understanding, adopt_lock has some dependency on the mutex-ownership. Since the lock is once called from the inside (in handle) and once from the outside (in build), there might be a problem. After brief testing, the segfaults happened fewer times. See #1444 * Also listen to _NET_WM_DESKTOP In order to move a window from one desktop to another, it is sufficient to set the desktop-property of that window. xmonad fires a lot of events in the case of moving a window, herbstluftwm only updates the _NET_WM_DESKTOP-atom of the window. This change reloads the clientlist in order to correctly set the desktop state "occupied". * Describe need and use of mutex It might be possible to relieve the guard in xworkspaces_module::handle, but I am unsure about this. Since xmonad emits a lot of events on almost every minor change, I would let the guard keep its post, avoiding race-conditions in event-handling. * Give temporary variables better names * Clarify purpose of loop About 80% of this comment are taken from https://github.com/jaagr/polybar/pull/882#discussion_r255317363 * Remove merge-remainder * Use a simpler method to list occupied desktops. Co-authored-by: Jérôme Boulmier <jerome.boulmier@outlook.fr> * Document m_clients field
2019-10-21 08:00:38 +00:00
}
2017-01-25 02:29:11 +00:00
}
2016-11-26 08:38:55 +00:00
2017-01-25 02:29:11 +00:00
/**
* Rebuild the desktop tree
*
* This requires m_desktop_names to have an up-to-date value
2017-01-25 02:29:11 +00:00
*/
void xworkspaces_module::rebuild_desktops() {
2016-11-26 08:38:55 +00:00
m_viewports.clear();
/*
* Stores the _NET_DESKTOP_VIEWPORT hint
*
* For WMs that don't support that hint, we store an empty vector
*
* The vector will be padded/reduced to _NET_NUMBER_OF_DESKTOPS.
* All desktops which aren't explicitly assigned a postion will be
* assigned (0, 0)
*
* We use this to map workspaces to viewports, desktop i is at position
* ws_positions[i].
*/
The xworkspaces module should wait for EWMH to become available (#2429) * The xworkspaces module should wait for EWMH to become available Before this change if EWMH wasn't available the xworkspaces module was permanently disabled. When polybar was started alongside the window manager e.g. from .xinitrc this caused a race condition between polybar and the window manager and the xworkspaces module may or may not be displayed. After this change polybar will wait for EWMH to become available. This change closes #1915, see that issue for more details. Curiously this only required the removal of the error condition which used the be raised when EWMH wasn't available. The xworkspaces module will show up on the bar as soon as the first EWMH event is processed by the existing event handling code. I can't argue much about the correctness of this patch but it seems to work flawlessly in my testing with xmonad. I didn't test any other window managers. Note that removing the error condition below which checks that _NET_DESKTOP_VIEWPORT is available might make this work with pin-workspaces=true. I couldn't test the effects of that change because I only tested with xmonad and xmonad doesn't support _NET_DESKTOP_VIEWPORT, so I didn't make that change. * xworkspaces: Remove check fo _NET_DESKTOP_VIEWPORT Implementations that don't support it will just return an empty list for get_desktop_viewports and pin-workspaces won't do anything. * Update changelog Fixes #1915 Co-authored-by: Tim Schumacher <tim@timakro.de> Co-authored-by: patrick96 <p.ziegler96@gmail.com>
2021-10-11 12:40:14 +00:00
vector<position> ws_positions = ewmh_util::get_desktop_viewports();
2017-01-25 02:29:11 +00:00
auto num_desktops = m_desktop_names.size();
/*
* Not all desktops were assigned a viewport, add (0, 0) for all missing
* desktops.
*/
if (ws_positions.size() < num_desktops) {
auto num_insert = num_desktops - ws_positions.size();
ws_positions.reserve(num_desktops);
std::fill_n(std::back_inserter(ws_positions), num_insert, position{0, 0});
}
/*
* If there are too many workspace positions, trim to fit the number of desktops.
*/
if (ws_positions.size() > num_desktops) {
ws_positions.erase(ws_positions.begin() + num_desktops, ws_positions.end());
}
/*
* There must be as many workspace positions as desktops because the indices
* into ws_positions are also used to index into m_desktop_names.
*/
assert(ws_positions.size() == num_desktops);
/*
* The list of viewports is the set of unique positions in ws_positions
* Using a set automatically removes duplicates.
*/
std::set<position> viewports(ws_positions.begin(), ws_positions.end());
for (auto&& viewport_pos : viewports) {
/*
* If pin-workspaces is set, we only add the viewport if it's in the
* monitor the bar is on.
* Generally viewport_pos is the same as the top-left coordinate of the
* monitor but we use `contains` here as a safety in case it isn't exactly.
*/
if (!m_pinworkspaces || m_bar.monitor->contains(viewport_pos)) {
2017-01-25 02:29:11 +00:00
auto viewport = make_unique<struct viewport>();
viewport->state = viewport_state::UNFOCUSED;
viewport->pos = viewport_pos;
2017-01-25 02:29:11 +00:00
for (auto&& m : m_monitors) {
if (m->contains(viewport->pos)) {
2017-01-25 02:29:11 +00:00
viewport->name = m->name;
viewport->state = viewport_state::FOCUSED;
}
}
2017-01-25 02:29:11 +00:00
viewport->label = [&] {
label_t label;
if (m_monitorlabel) {
label = m_monitorlabel->clone();
label->reset_tokens();
label->replace_token("%name%", viewport->name);
2016-11-26 08:38:55 +00:00
}
2017-01-25 02:29:11 +00:00
return label;
}();
/*
* Search for all desktops on this viewport and store them in the
* desktop list of the viewport.
*/
for (size_t i = 0; i < ws_positions.size(); i++) {
auto&& ws_pos = ws_positions[i];
if (ws_pos == viewport_pos) {
viewport->desktops.emplace_back(make_unique<struct desktop>(i, desktop_state::EMPTY, label_t{}));
}
2016-11-26 08:38:55 +00:00
}
2017-01-25 02:29:11 +00:00
m_viewports.emplace_back(move(viewport));
2016-11-26 08:38:55 +00:00
}
2017-01-25 02:29:11 +00:00
}
}
2017-01-25 02:29:11 +00:00
/**
* Update active state of current desktops
*/
void xworkspaces_module::rebuild_desktop_states() {
feat(xworkspaces): Support occupied workspaces (#882) A workspace is occupied if it is not active and there is at least one window managed by the WM (`_NET_CLIENT_LIST`) that has set `_NET_WM_DESKTOP` to that workspace. The behavior when `_NET_WM_DESKTOP` is not set is not yet clear but this is unlikely to happen since most WMs will position windows on some desktop. Closes #874 Fixes #1444 Fixes #1033 * Set Desktop OCCUPIED if a window moves there This covers more of an edge-case. I did this first by accident, it might vanish later on. * Replace tracking change of WS with currently used WS * Untrack occupied workspaces * Track windows and their desktops in pairs * Match type of occupied_desktops with current_desktop Because the index needs to be matched later on, type mismatches would be non-ideal. * Recreate the occupied desktops everytime and remove duplicates * Readd support for moving windows to other desktops * Use less characters to empty the vector * Rename variable storing the desktops * Recount windows on every occasion This alone simplifies the management and the lookup for occupation of a workspace * Keep track of number of windows in every workspace * Add debugging output that shall be removed before merging * Remove obsolete TODO * m_client_list should always be diff'd, since the desktop may change Therefore we update the desktop-count tally every time the client_list changes. It may just be a desktop-change without a change of clients.size()... * Add more logging-spam to understand window/desktop lifecycle * Lock event-handler to serialize handling of events * Fix occupied workspace counting and change to bool array Also, performance improvements when diffing new and old client lists * Fix crash when all clients are removed * Conform to linter and styleguide * Shorten conditional as it is standard enough Since this only guards against 0-divisions, it can be shortened without risking too much confusion down the road. * Guard against multiple threads accessing and modifying data Fixes #1444 Modification of internal data happens through the handle-method, while the build-method tries to access the data structures for display. Since some modifications clear e.g. the m_viewports, references may become invalid between looping over them an accessing them. The mutex should guard against this simultanuous access. * Do not 'adopt_lock', because calls come from very different threads To my understanding, adopt_lock has some dependency on the mutex-ownership. Since the lock is once called from the inside (in handle) and once from the outside (in build), there might be a problem. After brief testing, the segfaults happened fewer times. See #1444 * Also listen to _NET_WM_DESKTOP In order to move a window from one desktop to another, it is sufficient to set the desktop-property of that window. xmonad fires a lot of events in the case of moving a window, herbstluftwm only updates the _NET_WM_DESKTOP-atom of the window. This change reloads the clientlist in order to correctly set the desktop state "occupied". * Describe need and use of mutex It might be possible to relieve the guard in xworkspaces_module::handle, but I am unsure about this. Since xmonad emits a lot of events on almost every minor change, I would let the guard keep its post, avoiding race-conditions in event-handling. * Give temporary variables better names * Clarify purpose of loop About 80% of this comment are taken from https://github.com/jaagr/polybar/pull/882#discussion_r255317363 * Remove merge-remainder * Use a simpler method to list occupied desktops. Co-authored-by: Jérôme Boulmier <jerome.boulmier@outlook.fr> * Document m_clients field
2019-10-21 08:00:38 +00:00
std::set<unsigned int> occupied_desks;
for (auto&& c : m_clients) {
occupied_desks.insert(c.second);
}
2017-01-25 02:29:11 +00:00
for (auto&& v : m_viewports) {
for (auto&& d : v->desktops) {
if (m_urgent_desktops[d->index]) {
d->state = desktop_state::URGENT;
} else if (d->index == m_current_desktop) {
2017-01-25 02:29:11 +00:00
d->state = desktop_state::ACTIVE;
feat(xworkspaces): Support occupied workspaces (#882) A workspace is occupied if it is not active and there is at least one window managed by the WM (`_NET_CLIENT_LIST`) that has set `_NET_WM_DESKTOP` to that workspace. The behavior when `_NET_WM_DESKTOP` is not set is not yet clear but this is unlikely to happen since most WMs will position windows on some desktop. Closes #874 Fixes #1444 Fixes #1033 * Set Desktop OCCUPIED if a window moves there This covers more of an edge-case. I did this first by accident, it might vanish later on. * Replace tracking change of WS with currently used WS * Untrack occupied workspaces * Track windows and their desktops in pairs * Match type of occupied_desktops with current_desktop Because the index needs to be matched later on, type mismatches would be non-ideal. * Recreate the occupied desktops everytime and remove duplicates * Readd support for moving windows to other desktops * Use less characters to empty the vector * Rename variable storing the desktops * Recount windows on every occasion This alone simplifies the management and the lookup for occupation of a workspace * Keep track of number of windows in every workspace * Add debugging output that shall be removed before merging * Remove obsolete TODO * m_client_list should always be diff'd, since the desktop may change Therefore we update the desktop-count tally every time the client_list changes. It may just be a desktop-change without a change of clients.size()... * Add more logging-spam to understand window/desktop lifecycle * Lock event-handler to serialize handling of events * Fix occupied workspace counting and change to bool array Also, performance improvements when diffing new and old client lists * Fix crash when all clients are removed * Conform to linter and styleguide * Shorten conditional as it is standard enough Since this only guards against 0-divisions, it can be shortened without risking too much confusion down the road. * Guard against multiple threads accessing and modifying data Fixes #1444 Modification of internal data happens through the handle-method, while the build-method tries to access the data structures for display. Since some modifications clear e.g. the m_viewports, references may become invalid between looping over them an accessing them. The mutex should guard against this simultanuous access. * Do not 'adopt_lock', because calls come from very different threads To my understanding, adopt_lock has some dependency on the mutex-ownership. Since the lock is once called from the inside (in handle) and once from the outside (in build), there might be a problem. After brief testing, the segfaults happened fewer times. See #1444 * Also listen to _NET_WM_DESKTOP In order to move a window from one desktop to another, it is sufficient to set the desktop-property of that window. xmonad fires a lot of events in the case of moving a window, herbstluftwm only updates the _NET_WM_DESKTOP-atom of the window. This change reloads the clientlist in order to correctly set the desktop state "occupied". * Describe need and use of mutex It might be possible to relieve the guard in xworkspaces_module::handle, but I am unsure about this. Since xmonad emits a lot of events on almost every minor change, I would let the guard keep its post, avoiding race-conditions in event-handling. * Give temporary variables better names * Clarify purpose of loop About 80% of this comment are taken from https://github.com/jaagr/polybar/pull/882#discussion_r255317363 * Remove merge-remainder * Use a simpler method to list occupied desktops. Co-authored-by: Jérôme Boulmier <jerome.boulmier@outlook.fr> * Document m_clients field
2019-10-21 08:00:38 +00:00
} else if (occupied_desks.count(d->index) > 0) {
d->state = desktop_state::OCCUPIED;
2017-05-17 03:34:03 +00:00
} else {
2017-01-25 02:29:11 +00:00
d->state = desktop_state::EMPTY;
feat(xworkspaces): Support occupied workspaces (#882) A workspace is occupied if it is not active and there is at least one window managed by the WM (`_NET_CLIENT_LIST`) that has set `_NET_WM_DESKTOP` to that workspace. The behavior when `_NET_WM_DESKTOP` is not set is not yet clear but this is unlikely to happen since most WMs will position windows on some desktop. Closes #874 Fixes #1444 Fixes #1033 * Set Desktop OCCUPIED if a window moves there This covers more of an edge-case. I did this first by accident, it might vanish later on. * Replace tracking change of WS with currently used WS * Untrack occupied workspaces * Track windows and their desktops in pairs * Match type of occupied_desktops with current_desktop Because the index needs to be matched later on, type mismatches would be non-ideal. * Recreate the occupied desktops everytime and remove duplicates * Readd support for moving windows to other desktops * Use less characters to empty the vector * Rename variable storing the desktops * Recount windows on every occasion This alone simplifies the management and the lookup for occupation of a workspace * Keep track of number of windows in every workspace * Add debugging output that shall be removed before merging * Remove obsolete TODO * m_client_list should always be diff'd, since the desktop may change Therefore we update the desktop-count tally every time the client_list changes. It may just be a desktop-change without a change of clients.size()... * Add more logging-spam to understand window/desktop lifecycle * Lock event-handler to serialize handling of events * Fix occupied workspace counting and change to bool array Also, performance improvements when diffing new and old client lists * Fix crash when all clients are removed * Conform to linter and styleguide * Shorten conditional as it is standard enough Since this only guards against 0-divisions, it can be shortened without risking too much confusion down the road. * Guard against multiple threads accessing and modifying data Fixes #1444 Modification of internal data happens through the handle-method, while the build-method tries to access the data structures for display. Since some modifications clear e.g. the m_viewports, references may become invalid between looping over them an accessing them. The mutex should guard against this simultanuous access. * Do not 'adopt_lock', because calls come from very different threads To my understanding, adopt_lock has some dependency on the mutex-ownership. Since the lock is once called from the inside (in handle) and once from the outside (in build), there might be a problem. After brief testing, the segfaults happened fewer times. See #1444 * Also listen to _NET_WM_DESKTOP In order to move a window from one desktop to another, it is sufficient to set the desktop-property of that window. xmonad fires a lot of events in the case of moving a window, herbstluftwm only updates the _NET_WM_DESKTOP-atom of the window. This change reloads the clientlist in order to correctly set the desktop state "occupied". * Describe need and use of mutex It might be possible to relieve the guard in xworkspaces_module::handle, but I am unsure about this. Since xmonad emits a lot of events on almost every minor change, I would let the guard keep its post, avoiding race-conditions in event-handling. * Give temporary variables better names * Clarify purpose of loop About 80% of this comment are taken from https://github.com/jaagr/polybar/pull/882#discussion_r255317363 * Remove merge-remainder * Use a simpler method to list occupied desktops. Co-authored-by: Jérôme Boulmier <jerome.boulmier@outlook.fr> * Document m_clients field
2019-10-21 08:00:38 +00:00
}
2016-11-26 08:38:55 +00:00
2017-01-25 02:29:11 +00:00
d->label = m_labels.at(d->state)->clone();
d->label->reset_tokens();
d->label->replace_token("%index%", to_string(d->index + 1));
2017-01-25 02:29:11 +00:00
d->label->replace_token("%name%", m_desktop_names[d->index]);
d->label->replace_token("%nwin%", to_string(m_windows[d->index]));
2017-01-25 02:29:11 +00:00
d->label->replace_token("%icon%", m_icons->get(m_desktop_names[d->index], DEFAULT_ICON)->get());
}
2016-11-26 08:38:55 +00:00
}
}
feat(xworkspaces): Support occupied workspaces (#882) A workspace is occupied if it is not active and there is at least one window managed by the WM (`_NET_CLIENT_LIST`) that has set `_NET_WM_DESKTOP` to that workspace. The behavior when `_NET_WM_DESKTOP` is not set is not yet clear but this is unlikely to happen since most WMs will position windows on some desktop. Closes #874 Fixes #1444 Fixes #1033 * Set Desktop OCCUPIED if a window moves there This covers more of an edge-case. I did this first by accident, it might vanish later on. * Replace tracking change of WS with currently used WS * Untrack occupied workspaces * Track windows and their desktops in pairs * Match type of occupied_desktops with current_desktop Because the index needs to be matched later on, type mismatches would be non-ideal. * Recreate the occupied desktops everytime and remove duplicates * Readd support for moving windows to other desktops * Use less characters to empty the vector * Rename variable storing the desktops * Recount windows on every occasion This alone simplifies the management and the lookup for occupation of a workspace * Keep track of number of windows in every workspace * Add debugging output that shall be removed before merging * Remove obsolete TODO * m_client_list should always be diff'd, since the desktop may change Therefore we update the desktop-count tally every time the client_list changes. It may just be a desktop-change without a change of clients.size()... * Add more logging-spam to understand window/desktop lifecycle * Lock event-handler to serialize handling of events * Fix occupied workspace counting and change to bool array Also, performance improvements when diffing new and old client lists * Fix crash when all clients are removed * Conform to linter and styleguide * Shorten conditional as it is standard enough Since this only guards against 0-divisions, it can be shortened without risking too much confusion down the road. * Guard against multiple threads accessing and modifying data Fixes #1444 Modification of internal data happens through the handle-method, while the build-method tries to access the data structures for display. Since some modifications clear e.g. the m_viewports, references may become invalid between looping over them an accessing them. The mutex should guard against this simultanuous access. * Do not 'adopt_lock', because calls come from very different threads To my understanding, adopt_lock has some dependency on the mutex-ownership. Since the lock is once called from the inside (in handle) and once from the outside (in build), there might be a problem. After brief testing, the segfaults happened fewer times. See #1444 * Also listen to _NET_WM_DESKTOP In order to move a window from one desktop to another, it is sufficient to set the desktop-property of that window. xmonad fires a lot of events in the case of moving a window, herbstluftwm only updates the _NET_WM_DESKTOP-atom of the window. This change reloads the clientlist in order to correctly set the desktop state "occupied". * Describe need and use of mutex It might be possible to relieve the guard in xworkspaces_module::handle, but I am unsure about this. Since xmonad emits a lot of events on almost every minor change, I would let the guard keep its post, avoiding race-conditions in event-handling. * Give temporary variables better names * Clarify purpose of loop About 80% of this comment are taken from https://github.com/jaagr/polybar/pull/882#discussion_r255317363 * Remove merge-remainder * Use a simpler method to list occupied desktops. Co-authored-by: Jérôme Boulmier <jerome.boulmier@outlook.fr> * Document m_clients field
2019-10-21 08:00:38 +00:00
vector<string> xworkspaces_module::get_desktop_names() {
vector<string> names = ewmh_util::get_desktop_names();
unsigned int desktops_number = ewmh_util::get_number_of_desktops();
feat(xworkspaces): Support occupied workspaces (#882) A workspace is occupied if it is not active and there is at least one window managed by the WM (`_NET_CLIENT_LIST`) that has set `_NET_WM_DESKTOP` to that workspace. The behavior when `_NET_WM_DESKTOP` is not set is not yet clear but this is unlikely to happen since most WMs will position windows on some desktop. Closes #874 Fixes #1444 Fixes #1033 * Set Desktop OCCUPIED if a window moves there This covers more of an edge-case. I did this first by accident, it might vanish later on. * Replace tracking change of WS with currently used WS * Untrack occupied workspaces * Track windows and their desktops in pairs * Match type of occupied_desktops with current_desktop Because the index needs to be matched later on, type mismatches would be non-ideal. * Recreate the occupied desktops everytime and remove duplicates * Readd support for moving windows to other desktops * Use less characters to empty the vector * Rename variable storing the desktops * Recount windows on every occasion This alone simplifies the management and the lookup for occupation of a workspace * Keep track of number of windows in every workspace * Add debugging output that shall be removed before merging * Remove obsolete TODO * m_client_list should always be diff'd, since the desktop may change Therefore we update the desktop-count tally every time the client_list changes. It may just be a desktop-change without a change of clients.size()... * Add more logging-spam to understand window/desktop lifecycle * Lock event-handler to serialize handling of events * Fix occupied workspace counting and change to bool array Also, performance improvements when diffing new and old client lists * Fix crash when all clients are removed * Conform to linter and styleguide * Shorten conditional as it is standard enough Since this only guards against 0-divisions, it can be shortened without risking too much confusion down the road. * Guard against multiple threads accessing and modifying data Fixes #1444 Modification of internal data happens through the handle-method, while the build-method tries to access the data structures for display. Since some modifications clear e.g. the m_viewports, references may become invalid between looping over them an accessing them. The mutex should guard against this simultanuous access. * Do not 'adopt_lock', because calls come from very different threads To my understanding, adopt_lock has some dependency on the mutex-ownership. Since the lock is once called from the inside (in handle) and once from the outside (in build), there might be a problem. After brief testing, the segfaults happened fewer times. See #1444 * Also listen to _NET_WM_DESKTOP In order to move a window from one desktop to another, it is sufficient to set the desktop-property of that window. xmonad fires a lot of events in the case of moving a window, herbstluftwm only updates the _NET_WM_DESKTOP-atom of the window. This change reloads the clientlist in order to correctly set the desktop state "occupied". * Describe need and use of mutex It might be possible to relieve the guard in xworkspaces_module::handle, but I am unsure about this. Since xmonad emits a lot of events on almost every minor change, I would let the guard keep its post, avoiding race-conditions in event-handling. * Give temporary variables better names * Clarify purpose of loop About 80% of this comment are taken from https://github.com/jaagr/polybar/pull/882#discussion_r255317363 * Remove merge-remainder * Use a simpler method to list occupied desktops. Co-authored-by: Jérôme Boulmier <jerome.boulmier@outlook.fr> * Document m_clients field
2019-10-21 08:00:38 +00:00
if (desktops_number == names.size()) {
return names;
feat(xworkspaces): Support occupied workspaces (#882) A workspace is occupied if it is not active and there is at least one window managed by the WM (`_NET_CLIENT_LIST`) that has set `_NET_WM_DESKTOP` to that workspace. The behavior when `_NET_WM_DESKTOP` is not set is not yet clear but this is unlikely to happen since most WMs will position windows on some desktop. Closes #874 Fixes #1444 Fixes #1033 * Set Desktop OCCUPIED if a window moves there This covers more of an edge-case. I did this first by accident, it might vanish later on. * Replace tracking change of WS with currently used WS * Untrack occupied workspaces * Track windows and their desktops in pairs * Match type of occupied_desktops with current_desktop Because the index needs to be matched later on, type mismatches would be non-ideal. * Recreate the occupied desktops everytime and remove duplicates * Readd support for moving windows to other desktops * Use less characters to empty the vector * Rename variable storing the desktops * Recount windows on every occasion This alone simplifies the management and the lookup for occupation of a workspace * Keep track of number of windows in every workspace * Add debugging output that shall be removed before merging * Remove obsolete TODO * m_client_list should always be diff'd, since the desktop may change Therefore we update the desktop-count tally every time the client_list changes. It may just be a desktop-change without a change of clients.size()... * Add more logging-spam to understand window/desktop lifecycle * Lock event-handler to serialize handling of events * Fix occupied workspace counting and change to bool array Also, performance improvements when diffing new and old client lists * Fix crash when all clients are removed * Conform to linter and styleguide * Shorten conditional as it is standard enough Since this only guards against 0-divisions, it can be shortened without risking too much confusion down the road. * Guard against multiple threads accessing and modifying data Fixes #1444 Modification of internal data happens through the handle-method, while the build-method tries to access the data structures for display. Since some modifications clear e.g. the m_viewports, references may become invalid between looping over them an accessing them. The mutex should guard against this simultanuous access. * Do not 'adopt_lock', because calls come from very different threads To my understanding, adopt_lock has some dependency on the mutex-ownership. Since the lock is once called from the inside (in handle) and once from the outside (in build), there might be a problem. After brief testing, the segfaults happened fewer times. See #1444 * Also listen to _NET_WM_DESKTOP In order to move a window from one desktop to another, it is sufficient to set the desktop-property of that window. xmonad fires a lot of events in the case of moving a window, herbstluftwm only updates the _NET_WM_DESKTOP-atom of the window. This change reloads the clientlist in order to correctly set the desktop state "occupied". * Describe need and use of mutex It might be possible to relieve the guard in xworkspaces_module::handle, but I am unsure about this. Since xmonad emits a lot of events on almost every minor change, I would let the guard keep its post, avoiding race-conditions in event-handling. * Give temporary variables better names * Clarify purpose of loop About 80% of this comment are taken from https://github.com/jaagr/polybar/pull/882#discussion_r255317363 * Remove merge-remainder * Use a simpler method to list occupied desktops. Co-authored-by: Jérôme Boulmier <jerome.boulmier@outlook.fr> * Document m_clients field
2019-10-21 08:00:38 +00:00
} else if (desktops_number < names.size()) {
names.erase(names.begin() + desktops_number, names.end());
return names;
}
for (unsigned int i = names.size(); i < desktops_number; i++) {
names.insert(names.end(), to_string(i + 1));
}
return names;
}
2017-01-25 02:29:11 +00:00
/**
* Fetch and parse data
*/
void xworkspaces_module::update() {}
/**
* Generate module output
*/
string xworkspaces_module::get_output() {
2017-01-25 02:29:11 +00:00
// Get the module output early so that
// the format prefix/suffix also gets wrapped
// with the cmd handlers
string output;
2016-11-26 08:38:55 +00:00
for (m_index = 0; m_index < m_viewports.size(); m_index++) {
if (m_index > 0) {
Add units support (POINT, PIXEL, SPACE) (#2578) * add units support (POINT, PIXEL, SPACE) for polybar - add a size_with_unit struct - add a geometry_format_values struct - move dpi initialisation from renderer.cpp to bar.cpp - add a string to size_with_unit converter - add point support (with pt) - add pixel support (with px) * Fix unit test compilation * clang-format * Better names The old names didn't really capture the purpose of the structs and function. space_type -> spacing_type space_size -> spacing_val size_type -> extent_type geometry -> extent_val geometry_format_values -> percentage_with_offset * Remove parse_size_with_unit No longer needed. The convert<spacing_val> function in config.cpp already does all the work for us and always setting the type to pixel was wrong. In addition, line-size should not be of type spacing_val but extent_val. * Cleanup I tried to address most of my comments on the old PR * Fix renderer width calculation We can't just blindly add the x difference to the width because for example the width should increase if x < width and the increase keeps x < width. Similarly, we can't just add the offset to the width. * Rename geom_format_to_pixels to percentage_with_offset_to_pixel * Cleanup * Apply suggested changes from Patrick on GitHub Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/bar.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/config.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/builder.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/builder.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * config: Use stod for parsing percentage * Use stof instead of strtof * units: Fix test edge cases * Remove unnecessary clang-format toggle * Use percentage_with_offset for margin-{top,bottom} * Support negative extent values * Rename unit to units and create a cpp file * Move percentage_with_offset_to_pixel unit test to units * Add unit tests for units_utils * Clarify when and how negative spacing/extent is allowed Negative spacing is never allowed and produces a config error. Extents allow negative values in theory, but only a few use-cases accept it. Only the extent value used for the `%{O}` tag and the offset value in percentage_with_offset can be negative. Everything else is capped below at 0. The final pixel value of percentage_with_offset also caps below at 0. * Fix parsing errors not being caught in config * Print a proper error message for uncaught exceptions * Cleanup module::get_output All changes preserve the existing semantics * Stop using remove_trailing_space in module::get_output Instead, we first check if the current tag is built, and only if it is, the spacing is prepended. * Remove unused imports * Restore old behavior If there are two tags and the second one isn't built (module::build returns false), the space in between them is removed. For example in the mpd module: format-online = <toggle> <label-song> foo If mpd is not running, the mpd module will return false when trying to build the `<label-song>` tag. If we don't remove the space between `<toggle>` and `<label-song>`, we end up with two spaces between `<toggle>` and `foo`. This change is to match the old behavior where at least one trailing space character was removed from the builder. * Add changelog entry * Remove unused setting * Use percentage with offset for tray-offset Co-authored-by: Jérôme BOULMIER <jerome.boulmier@outlook.fr> Co-authored-by: Joe Groocock <github@frebib.net>
2022-02-20 20:08:57 +00:00
m_builder->spacing(m_formatter->get(DEFAULT_FORMAT)->spacing);
}
2017-01-25 02:29:11 +00:00
output += module::get_output();
}
2017-01-25 02:29:11 +00:00
if (m_scroll) {
m_builder->action(mousebtn::SCROLL_DOWN, *this, m_revscroll ? EVENT_NEXT : EVENT_PREV, "");
m_builder->action(mousebtn::SCROLL_UP, *this, m_revscroll ? EVENT_PREV : EVENT_NEXT, "");
}
2017-01-25 02:29:11 +00:00
m_builder->node(output);
2017-01-25 02:29:11 +00:00
m_builder->action_close();
m_builder->action_close();
2017-01-25 02:29:11 +00:00
return m_builder->flush();
}
/**
* Output content as defined in the config
*/
bool xworkspaces_module::build(builder* builder, const string& tag) const {
2017-01-25 02:29:11 +00:00
if (tag == TAG_LABEL_MONITOR) {
if (m_viewports[m_index]->state != viewport_state::NONE) {
builder->node(m_viewports[m_index]->label);
return true;
} else {
return false;
}
2017-01-25 02:29:11 +00:00
} else if (tag == TAG_LABEL_STATE) {
unsigned int added_states = 0;
for (auto&& desktop : m_viewports[m_index]->desktops) {
2017-01-25 02:29:11 +00:00
if (desktop->label.get()) {
if (m_click && desktop->state != desktop_state::ACTIVE) {
builder->action(mousebtn::LEFT, *this, EVENT_FOCUS, to_string(desktop->index), desktop->label);
2017-01-25 02:29:11 +00:00
} else {
builder->node(desktop->label);
}
added_states++;
2016-11-26 08:38:55 +00:00
}
}
2017-01-25 02:29:11 +00:00
return added_states > 0;
} else {
return false;
}
}
void xworkspaces_module::action_focus(const string& data) {
focus_desktop(std::strtoul(data.c_str(), nullptr, 10));
}
void xworkspaces_module::action_next() {
focus_direction(true);
}
void xworkspaces_module::action_prev() {
focus_direction(false);
}
feat(xworkspaces): Support occupied workspaces (#882) A workspace is occupied if it is not active and there is at least one window managed by the WM (`_NET_CLIENT_LIST`) that has set `_NET_WM_DESKTOP` to that workspace. The behavior when `_NET_WM_DESKTOP` is not set is not yet clear but this is unlikely to happen since most WMs will position windows on some desktop. Closes #874 Fixes #1444 Fixes #1033 * Set Desktop OCCUPIED if a window moves there This covers more of an edge-case. I did this first by accident, it might vanish later on. * Replace tracking change of WS with currently used WS * Untrack occupied workspaces * Track windows and their desktops in pairs * Match type of occupied_desktops with current_desktop Because the index needs to be matched later on, type mismatches would be non-ideal. * Recreate the occupied desktops everytime and remove duplicates * Readd support for moving windows to other desktops * Use less characters to empty the vector * Rename variable storing the desktops * Recount windows on every occasion This alone simplifies the management and the lookup for occupation of a workspace * Keep track of number of windows in every workspace * Add debugging output that shall be removed before merging * Remove obsolete TODO * m_client_list should always be diff'd, since the desktop may change Therefore we update the desktop-count tally every time the client_list changes. It may just be a desktop-change without a change of clients.size()... * Add more logging-spam to understand window/desktop lifecycle * Lock event-handler to serialize handling of events * Fix occupied workspace counting and change to bool array Also, performance improvements when diffing new and old client lists * Fix crash when all clients are removed * Conform to linter and styleguide * Shorten conditional as it is standard enough Since this only guards against 0-divisions, it can be shortened without risking too much confusion down the road. * Guard against multiple threads accessing and modifying data Fixes #1444 Modification of internal data happens through the handle-method, while the build-method tries to access the data structures for display. Since some modifications clear e.g. the m_viewports, references may become invalid between looping over them an accessing them. The mutex should guard against this simultanuous access. * Do not 'adopt_lock', because calls come from very different threads To my understanding, adopt_lock has some dependency on the mutex-ownership. Since the lock is once called from the inside (in handle) and once from the outside (in build), there might be a problem. After brief testing, the segfaults happened fewer times. See #1444 * Also listen to _NET_WM_DESKTOP In order to move a window from one desktop to another, it is sufficient to set the desktop-property of that window. xmonad fires a lot of events in the case of moving a window, herbstluftwm only updates the _NET_WM_DESKTOP-atom of the window. This change reloads the clientlist in order to correctly set the desktop state "occupied". * Describe need and use of mutex It might be possible to relieve the guard in xworkspaces_module::handle, but I am unsure about this. Since xmonad emits a lot of events on almost every minor change, I would let the guard keep its post, avoiding race-conditions in event-handling. * Give temporary variables better names * Clarify purpose of loop About 80% of this comment are taken from https://github.com/jaagr/polybar/pull/882#discussion_r255317363 * Remove merge-remainder * Use a simpler method to list occupied desktops. Co-authored-by: Jérôme Boulmier <jerome.boulmier@outlook.fr> * Document m_clients field
2019-10-21 08:00:38 +00:00
/**
* Focuses either the next or previous desktop.
*
* Will wrap around at the ends and go in the order the desktops are displayed.
*/
void xworkspaces_module::focus_direction(bool next) {
unsigned int current_desktop{ewmh_util::get_current_desktop()};
int current_index = -1;
/*
* Desktop indices in the order they are displayed.
*/
vector<unsigned int> indices;
for (auto&& viewport : m_viewports) {
for (auto&& desktop : viewport->desktops) {
if (current_desktop == desktop->index) {
current_index = indices.size();
}
indices.emplace_back(desktop->index);
}
}
if (current_index == -1) {
m_log.err("%s: Current desktop (%u) not found in list of desktops", name(), current_desktop);
return;
}
int offset = next ? 1 : -1;
int new_index = (current_index + offset + indices.size()) % indices.size();
focus_desktop(indices.at(new_index));
}
void xworkspaces_module::focus_desktop(unsigned new_desktop) {
unsigned int current_desktop{ewmh_util::get_current_desktop()};
if (new_desktop != current_desktop) {
2016-12-23 19:43:52 +00:00
m_log.info("%s: Requesting change to desktop #%u", name(), new_desktop);
2017-01-24 07:49:27 +00:00
ewmh_util::change_current_desktop(new_desktop);
} else {
m_log.info("%s: Ignoring change to current desktop", name());
}
}
2022-03-06 15:40:42 +00:00
} // namespace modules
POLYBAR_NS_END