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>
|
2020-05-01 15:43:14 +00:00
|
|
|
#include <set>
|
2016-11-26 08:38:55 +00:00
|
|
|
#include <utility>
|
|
|
|
|
2016-11-26 05:14:58 +00:00
|
|
|
#include "drawtypes/iconset.hpp"
|
|
|
|
#include "drawtypes/label.hpp"
|
2020-01-07 12:40:24 +00:00
|
|
|
#include "modules/meta/base.inl"
|
2016-12-04 03:11:47 +00:00
|
|
|
#include "utils/math.hpp"
|
2016-11-26 05:14:58 +00:00
|
|
|
#include "x11/atoms.hpp"
|
|
|
|
#include "x11/connection.hpp"
|
2021-09-22 20:27:04 +00:00
|
|
|
#include "x11/icccm.hpp"
|
2016-11-26 05:14:58 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
2020-05-01 15:43:14 +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);
|
|
|
|
}
|
|
|
|
|
2016-11-26 05:14:58 +00:00
|
|
|
namespace modules {
|
|
|
|
template class module<xworkspaces_module>;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Construct module
|
|
|
|
*/
|
2016-12-21 07:00:09 +00:00
|
|
|
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()) {
|
2021-10-03 00:57:49 +00:00
|
|
|
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(); });
|
2021-01-04 09:25:52 +00:00
|
|
|
|
2016-11-26 08:38:55 +00:00
|
|
|
// Load config values
|
2016-12-30 22:32:05 +00:00
|
|
|
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);
|
2021-01-28 09:11:33 +00:00
|
|
|
m_revscroll = m_conf.get(name(), "reverse-scroll", m_revscroll);
|
2016-11-26 05:14:58 +00:00
|
|
|
|
|
|
|
// 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 05:14:58 +00:00
|
|
|
|
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)) {
|
2016-12-03 12:45:22 +00:00
|
|
|
// 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)));
|
2016-12-03 12:45:22 +00:00
|
|
|
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
|
2016-11-26 05:14:58 +00:00
|
|
|
}
|
|
|
|
|
2021-09-21 19:15:49 +00:00
|
|
|
m_icons = std::make_shared<iconset>();
|
|
|
|
m_icons->add(DEFAULT_ICON, std::make_shared<label>(m_conf.get(name(), DEFAULT_ICON, ""s)));
|
2016-11-26 05:14:58 +00:00
|
|
|
|
2022-02-21 18:57:25 +00:00
|
|
|
int i = 0;
|
2016-11-26 05:14:58 +00:00
|
|
|
for (const auto& workspace : m_conf.get_list<string>(name(), "icon", {})) {
|
2019-11-21 21:26:53 +00:00
|
|
|
auto vec = string_util::tokenize(workspace, ';');
|
2016-11-26 05:14:58 +00:00
|
|
|
if (vec.size() == 2) {
|
2021-09-21 19:15:49 +00:00
|
|
|
m_icons->add(vec[0], std::make_shared<label>(vec[1]));
|
2022-02-21 18:57:25 +00:00
|
|
|
} 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");
|
2016-11-26 05:14:58 +00:00
|
|
|
}
|
2022-02-21 18:57:25 +00:00
|
|
|
|
|
|
|
i++;
|
2016-11-26 05:14:58 +00:00
|
|
|
}
|
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
|
2019-02-08 12:32:31 +00:00
|
|
|
m_desktop_names = get_desktop_names();
|
2021-03-03 20:55:43 +00:00
|
|
|
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();
|
2016-11-26 05:14:58 +00:00
|
|
|
}
|
|
|
|
|
2021-03-03 20:55:43 +00:00
|
|
|
void xworkspaces_module::update_current_desktop() {
|
|
|
|
m_current_desktop = ewmh_util::get_current_desktop();
|
|
|
|
}
|
|
|
|
|
2016-11-26 05:14:58 +00:00
|
|
|
/**
|
|
|
|
* Handler for XCB_PROPERTY_NOTIFY events
|
|
|
|
*/
|
|
|
|
void xworkspaces_module::handle(const evt::property_notify& evt) {
|
2022-03-21 20:15:22 +00:00
|
|
|
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();
|
2022-03-21 20:15:22 +00:00
|
|
|
} else if (evt->atom == m_ewmh->_NET_DESKTOP_NAMES || evt->atom == m_ewmh->_NET_NUMBER_OF_DESKTOPS) {
|
2019-02-08 12:32:31 +00:00
|
|
|
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();
|
2022-03-21 20:15:22 +00:00
|
|
|
} else if (evt->atom == m_ewmh->_NET_CURRENT_DESKTOP) {
|
2021-03-03 20:55:43 +00:00
|
|
|
update_current_desktop();
|
2017-01-25 02:29:11 +00:00
|
|
|
rebuild_desktop_states();
|
2017-02-20 07:25:19 +00:00
|
|
|
} else if (evt->atom == WM_HINTS) {
|
2020-12-31 14:49:39 +00:00
|
|
|
rebuild_urgent_hints();
|
|
|
|
rebuild_desktop_states();
|
2016-11-26 05:14:58 +00:00
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-12-05 22:28:48 +00:00
|
|
|
broadcast();
|
2016-11-26 05:14:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-01-25 02:29:11 +00:00
|
|
|
* Rebuild the list of managed clients
|
2016-11-26 05:14:58 +00:00
|
|
|
*/
|
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) {
|
2022-03-20 13:27:05 +00:00
|
|
|
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();
|
2021-01-04 09:17:27 +00:00
|
|
|
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) {
|
2020-12-31 14:49:39 +00:00
|
|
|
auto desk = ewmh_util::get_desktop_from_window(client);
|
|
|
|
m_clients[client] = desk;
|
2021-01-04 09:17:27 +00:00
|
|
|
m_windows[desk]++;
|
2020-12-31 14:49:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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()) {
|
2022-03-21 20:15:22 +00:00
|
|
|
uint32_t desk = ewmh_util::get_desktop_from_window(client);
|
2021-01-15 19:23:25 +00:00
|
|
|
/*
|
|
|
|
* 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
|
2020-05-01 15:43:14 +00:00
|
|
|
*
|
|
|
|
* 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();
|
|
|
|
|
2020-05-01 15:43:14 +00:00
|
|
|
/*
|
|
|
|
* Stores the _NET_DESKTOP_VIEWPORT hint
|
|
|
|
*
|
|
|
|
* For WMs that don't support that hint, we store an empty vector
|
|
|
|
*
|
2022-03-23 13:07:51 +00:00
|
|
|
* The vector will be padded/reduced to _NET_NUMBER_OF_DESKTOPS.
|
|
|
|
* All desktops which aren't explicitly assigned a postion will be
|
2020-05-01 15:43:14 +00:00
|
|
|
* assigned (0, 0)
|
|
|
|
*
|
|
|
|
* We use this to map workspaces to viewports, desktop i is at position
|
|
|
|
* ws_positions[i].
|
|
|
|
*/
|
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
|
|
|
|
2022-03-23 13:07:51 +00:00
|
|
|
auto num_desktops = m_desktop_names.size();
|
|
|
|
|
2020-05-01 15:43:14 +00:00
|
|
|
/*
|
|
|
|
* Not all desktops were assigned a viewport, add (0, 0) for all missing
|
|
|
|
* desktops.
|
|
|
|
*/
|
2022-03-23 13:07:51 +00:00
|
|
|
if (ws_positions.size() < num_desktops) {
|
|
|
|
auto num_insert = num_desktops - ws_positions.size();
|
|
|
|
ws_positions.reserve(num_desktops);
|
2020-05-01 15:43:14 +00:00
|
|
|
std::fill_n(std::back_inserter(ws_positions), num_insert, position{0, 0});
|
2019-01-03 17:59:55 +00:00
|
|
|
}
|
2020-05-01 15:43:14 +00:00
|
|
|
|
2022-03-23 13:07:51 +00:00
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
|
2020-05-01 15:43:14 +00:00
|
|
|
/*
|
|
|
|
* 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;
|
2020-05-01 15:43:14 +00:00
|
|
|
viewport->pos = viewport_pos;
|
2017-01-25 02:29:11 +00:00
|
|
|
|
|
|
|
for (auto&& m : m_monitors) {
|
2020-05-01 15:43:14 +00:00
|
|
|
if (m->contains(viewport->pos)) {
|
2017-01-25 02:29:11 +00:00
|
|
|
viewport->name = m->name;
|
|
|
|
viewport->state = viewport_state::FOCUSED;
|
|
|
|
}
|
|
|
|
}
|
2016-11-26 05:14:58 +00:00
|
|
|
|
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;
|
|
|
|
}();
|
|
|
|
|
2022-03-23 13:07:51 +00:00
|
|
|
/*
|
|
|
|
* Search for all desktops on this viewport and store them in the
|
|
|
|
* desktop list of the viewport.
|
|
|
|
*/
|
2020-05-01 15:43:14 +00:00
|
|
|
for (size_t i = 0; i < ws_positions.size(); i++) {
|
|
|
|
auto&& ws_pos = ws_positions[i];
|
|
|
|
if (ws_pos == viewport_pos) {
|
2019-11-02 22:16:30 +00:00
|
|
|
viewport->desktops.emplace_back(make_unique<struct desktop>(i, desktop_state::EMPTY, label_t{}));
|
2020-05-01 15:43:14 +00:00
|
|
|
}
|
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
|
|
|
}
|
|
|
|
}
|
2016-11-26 05:14:58 +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) {
|
2020-12-31 14:49:39 +00:00
|
|
|
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();
|
2019-11-02 22:16:30 +00:00
|
|
|
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]);
|
2021-01-04 09:17:27 +00:00
|
|
|
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
|
|
|
}
|
2016-11-26 05:14:58 +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() {
|
2019-02-08 12:32:31 +00:00
|
|
|
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()) {
|
2019-02-08 12:32:31 +00:00
|
|
|
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());
|
2019-02-08 12:32:31 +00:00
|
|
|
return names;
|
|
|
|
}
|
2020-01-07 12:40:24 +00:00
|
|
|
for (unsigned int i = names.size(); i < desktops_number; i++) {
|
|
|
|
names.insert(names.end(), to_string(i + 1));
|
2019-02-08 12:32:31 +00:00
|
|
|
}
|
|
|
|
return names;
|
|
|
|
}
|
|
|
|
|
2017-01-25 02:29:11 +00:00
|
|
|
/**
|
|
|
|
* Fetch and parse data
|
|
|
|
*/
|
|
|
|
void xworkspaces_module::update() {}
|
|
|
|
|
2016-11-26 05:14:58 +00:00
|
|
|
/**
|
|
|
|
* 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
|
2016-11-26 05:14:58 +00:00
|
|
|
string output;
|
2016-11-26 08:38:55 +00:00
|
|
|
for (m_index = 0; m_index < m_viewports.size(); m_index++) {
|
2016-11-26 05:14:58 +00:00
|
|
|
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);
|
2016-11-26 05:14:58 +00:00
|
|
|
}
|
2017-01-25 02:29:11 +00:00
|
|
|
output += module::get_output();
|
2016-11-26 05:14:58 +00:00
|
|
|
}
|
2017-01-25 02:29:11 +00:00
|
|
|
|
2018-02-03 22:22:17 +00:00
|
|
|
if (m_scroll) {
|
2021-01-28 09:11:33 +00:00
|
|
|
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, "");
|
2018-02-03 22:22:17 +00:00
|
|
|
}
|
2017-01-25 02:29:11 +00:00
|
|
|
|
2022-03-14 17:39:34 +00:00
|
|
|
m_builder->node(output);
|
2017-01-25 02:29:11 +00:00
|
|
|
|
2020-05-24 16:35:12 +00:00
|
|
|
m_builder->action_close();
|
|
|
|
m_builder->action_close();
|
2017-01-25 02:29:11 +00:00
|
|
|
|
|
|
|
return m_builder->flush();
|
2016-11-26 05:14:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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;
|
2016-11-26 09:33:32 +00:00
|
|
|
}
|
2017-01-25 02:29:11 +00:00
|
|
|
} else if (tag == TAG_LABEL_STATE) {
|
|
|
|
unsigned int added_states = 0;
|
2016-11-26 09:33:32 +00:00
|
|
|
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) {
|
2020-05-23 22:36:16 +00:00
|
|
|
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
|
|
|
}
|
2016-11-26 09:33:32 +00:00
|
|
|
}
|
2017-01-25 02:29:11 +00:00
|
|
|
return added_states > 0;
|
|
|
|
} else {
|
|
|
|
return false;
|
2016-11-26 05:14:58 +00:00
|
|
|
}
|
|
|
|
}
|
2016-11-26 09:33:32 +00:00
|
|
|
|
2021-01-04 09:25:52 +00:00
|
|
|
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
|
|
|
|
2021-09-04 12:36:01 +00:00
|
|
|
/**
|
|
|
|
* Focuses either the next or previous desktop.
|
|
|
|
*
|
|
|
|
* Will wrap around at the ends and go in the order the desktops are displayed.
|
|
|
|
*/
|
2021-01-04 09:25:52 +00:00
|
|
|
void xworkspaces_module::focus_direction(bool next) {
|
2021-09-04 12:36:01 +00:00
|
|
|
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;
|
|
|
|
|
2016-12-03 12:45:22 +00:00
|
|
|
for (auto&& viewport : m_viewports) {
|
|
|
|
for (auto&& desktop : viewport->desktops) {
|
2021-09-04 12:36:01 +00:00
|
|
|
if (current_desktop == desktop->index) {
|
|
|
|
current_index = indices.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
indices.emplace_back(desktop->index);
|
2016-12-03 12:45:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-04 12:36:01 +00:00
|
|
|
if (current_index == -1) {
|
|
|
|
m_log.err("%s: Current desktop (%u) not found in list of desktops", name(), current_desktop);
|
|
|
|
return;
|
2016-11-26 09:33:32 +00:00
|
|
|
}
|
|
|
|
|
2021-09-21 19:15:49 +00:00
|
|
|
int offset = next ? 1 : -1;
|
2021-09-04 12:36:01 +00:00
|
|
|
|
|
|
|
int new_index = (current_index + offset + indices.size()) % indices.size();
|
|
|
|
focus_desktop(indices.at(new_index));
|
2021-01-04 09:25:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void xworkspaces_module::focus_desktop(unsigned new_desktop) {
|
|
|
|
unsigned int current_desktop{ewmh_util::get_current_desktop()};
|
2016-12-03 12:45:22 +00:00
|
|
|
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);
|
2016-12-03 12:45:22 +00:00
|
|
|
} else {
|
|
|
|
m_log.info("%s: Ignoring change to current desktop", name());
|
|
|
|
}
|
2016-11-26 09:33:32 +00:00
|
|
|
}
|
2022-03-06 15:40:42 +00:00
|
|
|
} // namespace modules
|
2016-11-26 05:14:58 +00:00
|
|
|
|
|
|
|
POLYBAR_NS_END
|