Merge remote-tracking branch 'upstream/master' into tray-child-window
This commit is contained in:
commit
4bbb28baaf
27
CHANGELOG.md
27
CHANGELOG.md
@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Breaking
|
||||
- `custom/script`: now doesn't hide failing script if it's output is not changing ([`#2636`](https://github.com/polybar/polybar/issues/2636)). Somewhat similar behaviour can be imitated with `format-fail`, if necessary.
|
||||
|
||||
### Build
|
||||
- Respect `CMAKE_INSTALL_PREFIX` when installing default config ([`#2770`](https://github.com/polybar/polybar/pull/2770))
|
||||
|
||||
### Deprecated
|
||||
- `custom/text`: The `content` setting and all its properties are deprecated in favor of `format` with the same functionality. ([`#2676`](https://github.com/polybar/polybar/pull/2676))
|
||||
|
||||
@ -20,6 +23,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- `custom/script`: Repeat interval for script failure (`interval-fail`) and `exec-if` (`interval-if`) ([`#943`](https://github.com/polybar/polybar/issues/943), [`#2606`](https://github.com/polybar/polybar/issues/2606), [`#2630`](https://github.com/polybar/polybar/pull/2630))
|
||||
- `custom/text`: Loads the `format` setting, which supports the `<label>` tag, if the deprecated `content` is not defined ([`#1331`](https://github.com/polybar/polybar/issues/1331), [`#2673`](https://github.com/polybar/polybar/pull/2673), [`#2676`](https://github.com/polybar/polybar/pull/2676))
|
||||
- Added experimental support for positioning the tray like a module
|
||||
- `internal/backlight`: `scroll-interval` option ([`#2696`](https://github.com/polybar/polybar/issues/2696), [`#2700`](https://github.com/polybar/polybar/pull/2700))
|
||||
|
||||
### Changed
|
||||
- `internal/fs`: Use `/` as a fallback if no mountpoints are specified ([`#2572`](https://github.com/polybar/polybar/issues/2572), [`#2705`](https://github.com/polybar/polybar/pull/2705))
|
||||
- `internal/backlight`: Detect backlight if none specified ([`#2572`](https://github.com/polybar/polybar/issues/2572), [`#2728`](https://github.com/polybar/polybar/pull/2728))
|
||||
|
||||
### Fixed
|
||||
- Waiting for double click interval on modules that don't have a double click action ([`#2663`](https://github.com/polybar/polybar/issues/2663), [`#2695`](https://github.com/polybar/polybar/pull/2695))
|
||||
- config:
|
||||
- Error reporting for deprecated config values ([`#2724`](https://github.com/polybar/polybar/issues/2724))
|
||||
- Also monitor include-files for changes when --reload is set ([`#675`](https://github.com/polybar/polybar/issues/675), [`#2759`](https://github.com/polybar/polybar/pull/2759))
|
||||
|
||||
## [3.6.3] - 2022-05-04
|
||||
### Fixed
|
||||
- `custom/script`: Output clearing when `exec-if` fails ([`#2674`](https://github.com/polybar/polybar/issues/2674))
|
||||
- `internal/battery`: `poll-interval` not working ([`#2649`](https://github.com/polybar/polybar/issues/2649), [`#2677`](https://github.com/polybar/polybar/pull/2677))
|
||||
- ipc: Polybar failing to open IPC channel after another user already ran polybar, if `XDG_RUNTIME_DIR` is not set ([`#2683`](https://github.com/polybar/polybar/issues/2683), [`#2684`](https://github.com/polybar/polybar/pull/2684))
|
||||
- No overlines/underlines being drawn when using offsets ([`#2685`](https://github.com/polybar/polybar/pull/2685))
|
||||
- Update struts (`_NET_WM_STRUT_PARTIAL`) when hiding the bar ([`#2702`](https://github.com/polybar/polybar/pull/2702))
|
||||
- `internal/pulseaudio`: Hanging during startup ([`#2707`](https://github.com/polybar/polybar/issues/2707), [`#2709`](https://github.com/polybar/polybar/pull/2709))
|
||||
- `internal/xworkspaces`: Updates of `_NET_DESKTOP_VIEWPORT` being ignored ([`#2693`](https://github.com/polybar/polybar/issues/2693), [`#2698`](https://github.com/polybar/polybar/pull/2698))
|
||||
|
||||
## [3.6.2] - 2022-04-03
|
||||
### Fixed
|
||||
@ -184,7 +208,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Fixed
|
||||
- Empty color values are no longer treated as invalid and no longer produce an error.
|
||||
|
||||
[Unreleased]: https://github.com/polybar/polybar/compare/3.6.2...HEAD
|
||||
[Unreleased]: https://github.com/polybar/polybar/compare/3.6.3...HEAD
|
||||
[3.6.3]: https://github.com/polybar/polybar/releases/tag/3.6.3
|
||||
[3.6.2]: https://github.com/polybar/polybar/releases/tag/3.6.2
|
||||
[3.6.1]: https://github.com/polybar/polybar/releases/tag/3.6.1
|
||||
[3.6.0]: https://github.com/polybar/polybar/releases/tag/3.6.0
|
||||
|
@ -63,7 +63,7 @@ endif()
|
||||
|
||||
if(BUILD_CONFIG)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/doc/config.ini
|
||||
DESTINATION /etc/${PROJECT_NAME}
|
||||
DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/${PROJECT_NAME}
|
||||
COMPONENT config)
|
||||
endif()
|
||||
|
||||
|
31
README.md
31
README.md
@ -1,5 +1,6 @@
|
||||
<p align="center">
|
||||
<img src="doc/_static/banner.png" alt="Polybar">
|
||||
<img src="doc/_static/banner.png#gh-light-mode-only" alt="Polybar">
|
||||
<img src="doc/_static/banner-dark-mode.png#gh-dark-mode-only" alt="Polybar">
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@ -40,6 +41,7 @@ for their desktop environment, without the need of having a black belt in shell
|
||||
* [Sponsors](#sponsors)
|
||||
* [Backers](#backers)
|
||||
* [License](#license)
|
||||
* [Signatures](#signatures)
|
||||
|
||||
## Introduction
|
||||
|
||||
@ -92,15 +94,17 @@ list of available polybar packages.
|
||||
If you are using **Debian** (bullseye/11/stable) or later, you can install [polybar](https://tracker.debian.org/pkg/polybar)
|
||||
using `sudo apt install polybar`. Newer releases of polybar are sometimes provided in the [backports](https://wiki.debian.org/Backports)
|
||||
repository for stable users, you need to enable [backports](https://wiki.debian.org/Backports) and then install using
|
||||
`sudo apt -t buster-backports install polybar`.
|
||||
`sudo apt -t bullseye-backports install polybar`.
|
||||
|
||||
If you are using **Ubuntu** 20.10 (Groovy Gorilla) or later, you can install polybar
|
||||
using `sudo apt install polybar`.
|
||||
|
||||
If you are using **Arch Linux**, you can install the AUR package
|
||||
[polybar](https://aur.archlinux.org/packages/polybar/) to get the latest
|
||||
version, or [polybar-git](https://aur.archlinux.org/packages/polybar-git/) for
|
||||
the most up-to-date (unstable) changes.
|
||||
If you are using **Arch Linux**, you can install
|
||||
[polybar](https://archlinux.org/packages/community/x86_64/polybar/) to get the
|
||||
latest stable release using `sudo pacman -S polybar`. The latest unstable
|
||||
changes are also available in the
|
||||
[`polybar-git`](https://aur.archlinux.org/packages/polybar-git) package in the
|
||||
AUR.
|
||||
|
||||
If you are using **Manjaro**, you can install [polybar](https://software.manjaro.org/package/polybar) to get the latest stable release using `sudo pacman -S polybar`.
|
||||
|
||||
@ -112,14 +116,11 @@ If you are using **Slackware**, polybar is available from the [SlackBuilds](http
|
||||
|
||||
If you are using **Source Mage GNU/Linux**, polybar spell is available in test grimoire and can be installed via `cast polybar`.
|
||||
|
||||
If you are using **openSUSE Tumbleweed**, polybar is available from the
|
||||
If you are using **openSUSE Leap** or **openSUSE Tumbleweed**, polybar is available from the
|
||||
[official
|
||||
repositories](https://build.opensuse.org/package/show/openSUSE%3AFactory/polybar)
|
||||
repositories](https://build.opensuse.org/package/show/X11:Utilities/polybar)
|
||||
and can be installed via `zypper install polybar`.
|
||||
|
||||
If you are using **openSUSE Leap**, polybar is available from
|
||||
[OBS](https://build.opensuse.org/package/show/X11:Utilities/polybar/).
|
||||
The package is available for openSUSE Leap 15.1 and above.
|
||||
The package is available for openSUSE Leap 15.3 and above.
|
||||
|
||||
If you are using **FreeBSD**, [polybar](https://svnweb.freebsd.org/ports/head/x11/polybar/) can be installed using `pkg install polybar`. Make sure you are using the `latest` package branch.
|
||||
|
||||
@ -233,3 +234,9 @@ Polybar accepts donations through [open collective](https://opencollective.com/p
|
||||
## License
|
||||
|
||||
Polybar is licensed under the MIT license. [See LICENSE for more information](https://github.com/polybar/polybar/blob/master/LICENSE).
|
||||
|
||||
## Signatures
|
||||
|
||||
Release archives and tags are signed by a maintainer using GPG. Currently
|
||||
everything is signed by [Patrick Ziegler](https://www.patrickziegler.ch/gpg)
|
||||
with fingerprint `1D5791352D51A228D4DDDBA4521E5E03AEBCA1A7`
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Maintainer: Patrick Ziegler <p.ziegler96@gmail.com>
|
||||
_pkgname=polybar
|
||||
pkgname="${_pkgname}-git"
|
||||
pkgver=3.6.2
|
||||
pkgver=3.6.3
|
||||
pkgrel=1
|
||||
pkgdesc="A fast and easy-to-use status bar"
|
||||
# aarch64 is not officially supported by polybar, it is only listed here for convenience
|
||||
@ -14,6 +14,7 @@ depends=("libuv" "cairo" "xcb-util-image" "xcb-util-wm" "xcb-util-xrm"
|
||||
optdepends=("i3-wm: i3 module support")
|
||||
makedepends=("cmake" "git" "python" "pkg-config" "python-sphinx"
|
||||
"python-packaging" "i3-wm")
|
||||
backup=("etc/polybar/config.ini")
|
||||
provides=("polybar")
|
||||
conflicts=("polybar")
|
||||
source=("${_pkgname}::git+${url}.git")
|
||||
|
@ -1,34 +0,0 @@
|
||||
# Maintainer: Patrick Ziegler <p.ziegler96@gmail.com>
|
||||
pkgname=polybar
|
||||
pkgver=3.6.2
|
||||
pkgrel=1
|
||||
pkgdesc="A fast and easy-to-use status bar"
|
||||
# aarch64 is not officially supported by polybar, it is only listed here for convenience
|
||||
arch=("i686" "x86_64" "aarch64")
|
||||
url="https://github.com/polybar/polybar"
|
||||
license=("MIT")
|
||||
depends=("libuv" "cairo" "xcb-util-image" "xcb-util-wm" "xcb-util-xrm"
|
||||
"xcb-util-cursor" "alsa-lib" "libpulse" "libmpdclient" "libnl"
|
||||
"jsoncpp" "curl")
|
||||
optdepends=("i3-wm: i3 module support")
|
||||
makedepends=("cmake" "python" "pkg-config" "python-sphinx" "python-packaging" "i3-wm")
|
||||
conflicts=("polybar-git")
|
||||
source=(${url}/releases/download/${pkgver}/${pkgname}-${pkgver}.tar.gz)
|
||||
sha256sums=('73becc942e7d2418bc72bd194f2037a2a86792219fd561b663a8509fd5f547a0')
|
||||
_dir="${pkgname}-${pkgver}"
|
||||
|
||||
prepare() {
|
||||
mkdir -p "${_dir}/build"
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${_dir}/build" || exit 1
|
||||
# Force cmake to use system python (to detect xcbgen)
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DPYTHON_EXECUTABLE=/usr/bin/python3 ..
|
||||
cmake --build .
|
||||
}
|
||||
|
||||
package() {
|
||||
cmake --build "${_dir}/build" --target install -- DESTDIR="${pkgdir}"
|
||||
install -Dm644 "${_dir}/LICENSE" "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
|
||||
}
|
BIN
doc/_static/banner-dark-mode.png
vendored
Normal file
BIN
doc/_static/banner-dark-mode.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
@ -114,9 +114,16 @@ as follows:
|
||||
* A draft PR is opened for the release branch. This PR MUST NOT be merged in
|
||||
GitHub's interface, it is only here for review, merging happens at the
|
||||
commandline.
|
||||
* A `draft release`_ is created in GitHub's release publishing tools
|
||||
* After approval, the GitHub release publishing tool is used to publish the
|
||||
release and tag the tip of the release branch (the release commit).
|
||||
* After approval, a signed git tag is created locally at the tip of the release
|
||||
branch and pushed:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
git tag -s X.Y.Z <release-branch>
|
||||
git push --tags
|
||||
|
||||
* A `draft release`_ targetting the new tag is created in GitHub's release
|
||||
publishing tools and published.
|
||||
* After the tag is created, the release branch is manually merged into
|
||||
``master``.
|
||||
Here it is vitally important that the history of the release branch does not
|
||||
@ -193,8 +200,8 @@ Draft Release
|
||||
|
||||
On `GitHub <https://github.com/polybar/polybar/releases/new>`_ a new release
|
||||
should be drafted.
|
||||
The release targets the tip of the release branch (the release commit), the
|
||||
name of the release and the tag is simply the release number.
|
||||
The release targets the git tag that was just pushed, the name of the release
|
||||
and the tag is simply the release number.
|
||||
|
||||
The content of the release message should contain the changelog copied from
|
||||
``CHANGELOG.md`` under the heading ``## Changelog``.
|
||||
@ -205,6 +212,7 @@ The generated list of PRs can be removed.
|
||||
After-Release Checklist
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Verify the release archive (see `Verify Release`_)
|
||||
* Make sure all the new functionality is documented on the wiki
|
||||
* Mark deprecated features appropriately (see `Deprecations`_)
|
||||
* Remove all unreleased notes from the wiki (not for patch releases)
|
||||
@ -212,13 +220,8 @@ After-Release Checklist
|
||||
<https://github.com/polybar/polybar/issues/1971>`_. Mention any dependency
|
||||
changes and any changes to the build workflow. Also mention any new files are
|
||||
created by the installation.
|
||||
* Confirm that the release archive was added to the release.
|
||||
We have a GitHub action workflow called 'Release Workflow' that on every
|
||||
release automatically creates a release archive, uploads it to the release,
|
||||
and adds a 'Download' section to the release body.
|
||||
If this fails for some reason, it should be triggered manually.
|
||||
* Create a PR that updates the AUR ``PKGBUILD`` files for the ``polybar`` and
|
||||
``polybar-git`` packages (push after the release archive is uploaded).
|
||||
* Create a PR that updates the AUR ``PKGBUILD`` file for the ``polybar-git``
|
||||
package (push after the release archive is uploaded).
|
||||
* Close the `GitHub Milestone <https://github.com/polybar/polybar/milestones>`_
|
||||
for the new release and move open issues (if any) to a later release.
|
||||
* Activate the version on `Read the Docs
|
||||
@ -226,6 +229,24 @@ After-Release Checklist
|
||||
previous versions for the same minor release (e.g. for 3.5.4, deactivate all
|
||||
other 3.5.X versions).
|
||||
|
||||
Verify Release
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Confirm that the release archive was added to the release.
|
||||
We have a GitHub action workflow called 'Release Workflow' that on every
|
||||
release automatically creates a release archive, uploads it to the release,
|
||||
and adds a 'Download' section to the release body.
|
||||
If this fails for some reason, it should be triggered manually.
|
||||
|
||||
Afterwards, download the archive, verify its hash, and sign it:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
gpg --armor --detach-sign polybar-X.Y.Z.tar.gz
|
||||
|
||||
Finally, upload the generated ``polybar-X.Y.Z.tar.gz.asc`` to the GitHub
|
||||
release.
|
||||
|
||||
Deprecations
|
||||
~~~~~~~~~~~~
|
||||
|
||||
|
@ -406,20 +406,22 @@ Below you can see an example of a menu module:
|
||||
[module/apps]
|
||||
type = custom/menu
|
||||
|
||||
label-open = Apps
|
||||
|
||||
menu-0-0 = Browsers
|
||||
menu-0-0-exec = menu-open-1
|
||||
menu-0-1 = Multimedia
|
||||
menu-0-1-exec = menu-open-2
|
||||
|
||||
menu-1-0 = Firefox
|
||||
menu-1-0-exec = firefox &
|
||||
menu-1-0-exec = firefox
|
||||
menu-1-1 = Chromium
|
||||
menu-1-1-exec = chromium &
|
||||
menu-1-1-exec = chromium
|
||||
|
||||
menu-2-0 = Gimp
|
||||
menu-2-0-exec = gimp &
|
||||
menu-2-0-exec = gimp
|
||||
menu-2-1 = Scrot
|
||||
menu-2-1-exec = scrot &
|
||||
menu-2-1-exec = scrot
|
||||
|
||||
This module uses two actions: ``menu-open-1`` and ``menu-open-2``.
|
||||
These are actions with data, the data specifies which level of the menu should
|
||||
@ -437,17 +439,19 @@ likely not use ``apps``, but the name of your module.
|
||||
[module/apps]
|
||||
type = custom/menu
|
||||
|
||||
label-open = Apps
|
||||
|
||||
menu-0-0 = Browsers
|
||||
menu-0-0-exec = #apps.open.1
|
||||
menu-0-1 = Multimedia
|
||||
menu-0-1-exec = #apps.open.2
|
||||
|
||||
menu-1-0 = Firefox
|
||||
menu-1-0-exec = firefox &
|
||||
menu-1-0-exec = firefox
|
||||
menu-1-1 = Chromium
|
||||
menu-1-1-exec = chromium &
|
||||
menu-1-1-exec = chromium
|
||||
|
||||
menu-2-0 = Gimp
|
||||
menu-2-0-exec = gimp &
|
||||
menu-2-0-exec = gimp
|
||||
menu-2-1 = Scrot
|
||||
menu-2-1-exec = scrot &
|
||||
menu-2-1-exec = scrot
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <pulse/pulseaudio.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <queue>
|
||||
|
||||
#include "common.hpp"
|
||||
@ -58,6 +59,11 @@ class pulseaudio {
|
||||
|
||||
const logger& m_log;
|
||||
|
||||
/**
|
||||
* Has context_state_callback signalled the mainloop during connection.
|
||||
*/
|
||||
std::atomic_bool m_state_callback_signal{false};
|
||||
|
||||
// used for temporary callback results
|
||||
int success{0};
|
||||
pa_cvolume cv{};
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdlib>
|
||||
#include <set>
|
||||
|
||||
#include "common.hpp"
|
||||
#include "components/eventloop.hpp"
|
||||
@ -42,7 +43,7 @@ class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::propert
|
||||
|
||||
const bar_settings& settings() const;
|
||||
|
||||
void start();
|
||||
void start(const string& tray_module_name);
|
||||
|
||||
void parse(string&& data, bool force = false);
|
||||
|
||||
@ -104,7 +105,7 @@ class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::propert
|
||||
string m_cursor{};
|
||||
|
||||
string m_lastinput{};
|
||||
bool m_dblclicks{false};
|
||||
std::set<mousebtn> m_dblclicks;
|
||||
|
||||
eventloop::TimerHandle& m_leftclick_timer{m_loop.handle<eventloop::TimerHandle>()};
|
||||
eventloop::TimerHandle& m_middleclick_timer{m_loop.handle<eventloop::TimerHandle>()};
|
||||
|
@ -44,6 +44,8 @@ class config {
|
||||
|
||||
void set_included(file_list included);
|
||||
|
||||
file_list get_included_files() const;
|
||||
|
||||
void warn_deprecated(const string& section, const string& key, string replacement) const;
|
||||
|
||||
/**
|
||||
@ -225,6 +227,10 @@ class config {
|
||||
return value;
|
||||
} catch (const key_error& err) {
|
||||
return get<T>(section, newkey, fallback);
|
||||
} catch (const std::exception& err) {
|
||||
m_log.err("Invalid value for \"%s.%s\", using fallback key \"%s.%s\" (reason: %s)", section, old, section, newkey,
|
||||
err.what());
|
||||
return get<T>(section, newkey, fallback);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,12 +90,12 @@ struct line_t {
|
||||
|
||||
class config_parser {
|
||||
public:
|
||||
config_parser(const logger& logger, string&& file, string&& bar);
|
||||
config_parser(const logger& logger, string&& file);
|
||||
/**
|
||||
* This prevents passing a temporary logger to the constructor because that would be UB, as the temporary would be
|
||||
* destroyed once the constructor returns.
|
||||
*/
|
||||
config_parser(logger&& logger, string&& file, string&& bar) = delete;
|
||||
config_parser(logger&& logger, string&& file) = delete;
|
||||
|
||||
/**
|
||||
* @brief Performs the parsing of the main config file m_file
|
||||
@ -105,7 +105,7 @@ class config_parser {
|
||||
* @throws syntax_error If there was any kind of syntax error
|
||||
* @throws parser_error If aynthing else went wrong
|
||||
*/
|
||||
config::make_type parse();
|
||||
config::make_type parse(string barname);
|
||||
|
||||
protected:
|
||||
/**
|
||||
@ -231,11 +231,6 @@ class config_parser {
|
||||
*/
|
||||
string m_config;
|
||||
|
||||
/**
|
||||
* Is used to resolve ${root...} references
|
||||
*/
|
||||
string m_barname;
|
||||
|
||||
/**
|
||||
* @brief List of all the lines in the config (with included files)
|
||||
*
|
||||
|
@ -55,6 +55,7 @@ class controller : public signal_receiver<SIGN_PRIORITY_CONTROLLER, signals::eve
|
||||
void signal_handler(int signum);
|
||||
|
||||
void conn_cb();
|
||||
void create_config_watcher(const string& fname);
|
||||
void confwatch_handler(const char* fname);
|
||||
void notifier_handler();
|
||||
void screenshot_handler();
|
||||
@ -100,6 +101,7 @@ class controller : public signal_receiver<SIGN_PRIORITY_CONTROLLER, signals::eve
|
||||
eventloop::loop& m_loop;
|
||||
unique_ptr<bar> m_bar;
|
||||
bool m_has_ipc;
|
||||
string m_tray_module_name;
|
||||
|
||||
/**
|
||||
* @brief Async handle to notify the eventloop
|
||||
|
@ -77,7 +77,7 @@ class renderer : public renderer_interface,
|
||||
void fill_overline(rgba color, double x, double w);
|
||||
void fill_underline(rgba color, double x, double w);
|
||||
void fill_borders();
|
||||
void draw_offset(rgba color, double x, double w);
|
||||
void draw_offset(const tags::context& ctxt, rgba color, double x, double w);
|
||||
|
||||
double block_x(alignment a) const;
|
||||
double block_y(alignment a) const;
|
||||
|
@ -107,6 +107,9 @@ namespace signals {
|
||||
struct tray_pos_change : public detail::value_signal<tray_pos_change, int> {
|
||||
using base_type::base_type;
|
||||
};
|
||||
struct tray_visibility : public detail::value_signal<tray_visibility, bool> {
|
||||
using base_type::base_type;
|
||||
};
|
||||
} // namespace ui_tray
|
||||
} // namespace signals
|
||||
|
||||
|
@ -37,7 +37,8 @@ namespace signals {
|
||||
namespace ui_tray {
|
||||
struct tray_width_change;
|
||||
struct tray_pos_change;
|
||||
}
|
||||
struct tray_visibility;
|
||||
} // namespace ui_tray
|
||||
} // namespace signals
|
||||
|
||||
POLYBAR_NS_END
|
||||
|
@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "common.hpp"
|
||||
@ -94,6 +92,6 @@ namespace ipc {
|
||||
void receive_data(string buf);
|
||||
void receive_eof();
|
||||
};
|
||||
} // namespace ipc
|
||||
} // namespace ipc
|
||||
|
||||
POLYBAR_NS_END
|
||||
|
@ -48,6 +48,7 @@ namespace modules {
|
||||
string m_path_backlight;
|
||||
float m_max_brightness;
|
||||
bool m_scroll{false};
|
||||
int m_scroll_interval{5};
|
||||
bool m_use_actual_brightness{true};
|
||||
|
||||
brightness_handle m_val;
|
||||
|
@ -39,8 +39,10 @@ class connection;
|
||||
class background_manager;
|
||||
class bg_slice;
|
||||
|
||||
enum class tray_postition { NONE = 0, LEFT, CENTER, RIGHT, MODULE };
|
||||
|
||||
struct tray_settings {
|
||||
alignment align{alignment::NONE};
|
||||
tray_postition tray_position{tray_postition::NONE};
|
||||
bool running{false};
|
||||
|
||||
/**
|
||||
@ -83,16 +85,16 @@ struct tray_settings {
|
||||
rgba foreground{};
|
||||
bool transparent{false};
|
||||
bool detached{false};
|
||||
bool adaptive{false};
|
||||
|
||||
xcb_window_t bar_window;
|
||||
};
|
||||
|
||||
class tray_manager : public xpp::event::sink<evt::expose, evt::visibility_notify, evt::client_message,
|
||||
evt::configure_request, evt::resize_request, evt::selection_clear, evt::property_notify,
|
||||
evt::reparent_notify, evt::destroy_notify, evt::map_notify, evt::unmap_notify>,
|
||||
public signal_receiver<SIGN_PRIORITY_TRAY, signals::ui::visibility_change, signals::ui::dim_window,
|
||||
signals::ui::update_background, signals::ui_tray::tray_pos_change> {
|
||||
class tray_manager
|
||||
: public xpp::event::sink<evt::expose, evt::visibility_notify, evt::client_message, evt::configure_request,
|
||||
evt::resize_request, evt::selection_clear, evt::property_notify, evt::reparent_notify, evt::destroy_notify,
|
||||
evt::map_notify, evt::unmap_notify>,
|
||||
public signal_receiver<SIGN_PRIORITY_TRAY, signals::ui::visibility_change, signals::ui::dim_window,
|
||||
signals::ui::update_background, signals::ui_tray::tray_pos_change, signals::ui_tray::tray_visibility> {
|
||||
public:
|
||||
using make_type = unique_ptr<tray_manager>;
|
||||
static make_type make(const bar_settings& bar_opts);
|
||||
@ -104,7 +106,7 @@ class tray_manager : public xpp::event::sink<evt::expose, evt::visibility_notify
|
||||
|
||||
const tray_settings settings() const;
|
||||
|
||||
void setup();
|
||||
void setup(const string& tray_module_name);
|
||||
void activate();
|
||||
void activate_delayed(chrono::duration<double, std::milli> delay = 1s);
|
||||
void deactivate(bool clear_selection = true);
|
||||
@ -144,6 +146,7 @@ class tray_manager : public xpp::event::sink<evt::expose, evt::visibility_notify
|
||||
void remove_client(xcb_window_t win, bool reconfigure = true);
|
||||
int mapped_clients() const;
|
||||
bool has_mapped_clients() const;
|
||||
bool change_visibility(bool visible);
|
||||
|
||||
void handle(const evt::expose& evt) override;
|
||||
void handle(const evt::visibility_notify& evt) override;
|
||||
@ -161,6 +164,7 @@ class tray_manager : public xpp::event::sink<evt::expose, evt::visibility_notify
|
||||
bool on(const signals::ui::dim_window& evt) override;
|
||||
bool on(const signals::ui::update_background& evt) override;
|
||||
bool on(const signals::ui_tray::tray_pos_change& evt) override;
|
||||
bool on(const signals::ui_tray::tray_visibility& evt) override;
|
||||
|
||||
private:
|
||||
connection& m_connection;
|
||||
|
@ -24,6 +24,8 @@ pulseaudio::pulseaudio(const logger& logger, string&& sink_name, bool max_volume
|
||||
|
||||
pa_context_set_state_callback(m_context, context_state_callback, this);
|
||||
|
||||
m_state_callback_signal = false;
|
||||
|
||||
if (pa_context_connect(m_context, nullptr, PA_CONTEXT_NOFLAGS, nullptr) < 0) {
|
||||
pa_context_disconnect(m_context);
|
||||
pa_context_unref(m_context);
|
||||
@ -42,7 +44,17 @@ pulseaudio::pulseaudio(const logger& logger, string&& sink_name, bool max_volume
|
||||
|
||||
m_log.trace("pulseaudio: started mainloop");
|
||||
|
||||
pa_threaded_mainloop_wait(m_mainloop);
|
||||
/*
|
||||
* Only wait for signal from the context state callback, if it has not
|
||||
* already signalled the mainloop since pa_context_connect was called,
|
||||
* otherwise, we would wait forever.
|
||||
*
|
||||
* The while loop ensures spurious wakeups are handled.
|
||||
*/
|
||||
while (!m_state_callback_signal) {
|
||||
pa_threaded_mainloop_wait(m_mainloop);
|
||||
}
|
||||
|
||||
if (pa_context_get_state(m_context) != PA_CONTEXT_READY) {
|
||||
pa_threaded_mainloop_unlock(m_mainloop);
|
||||
pa_threaded_mainloop_stop(m_mainloop);
|
||||
@ -310,6 +322,7 @@ void pulseaudio::context_state_callback(pa_context* context, void* userdata) {
|
||||
case PA_CONTEXT_READY:
|
||||
case PA_CONTEXT_TERMINATED:
|
||||
case PA_CONTEXT_FAILED:
|
||||
This->m_state_callback_signal = true;
|
||||
pa_threaded_mainloop_signal(This->m_mainloop, 0);
|
||||
break;
|
||||
|
||||
|
@ -46,7 +46,10 @@ script_runner::interval script_runner::process() {
|
||||
}
|
||||
|
||||
void script_runner::clear_output() {
|
||||
set_output("");
|
||||
auto changed = set_output("");
|
||||
if (changed) {
|
||||
m_on_update(m_data);
|
||||
}
|
||||
}
|
||||
|
||||
void script_runner::stop() {
|
||||
|
@ -131,12 +131,7 @@ bar::bar(connection& conn, signal_emitter& emitter, const config& config, const
|
||||
m_log.info("Loaded monitor %s (%ix%i+%i+%i)", m_opts.monitor->name, m_opts.monitor->w, m_opts.monitor->h,
|
||||
m_opts.monitor->x, m_opts.monitor->y);
|
||||
|
||||
try {
|
||||
m_opts.override_redirect = m_conf.get<bool>(bs, "dock");
|
||||
m_conf.warn_deprecated(bs, "dock", "override-redirect");
|
||||
} catch (const key_error& err) {
|
||||
m_opts.override_redirect = m_conf.get(bs, "override-redirect", m_opts.override_redirect);
|
||||
}
|
||||
m_opts.override_redirect = m_conf.deprecated(bs, "dock", "override-redirect", m_opts.override_redirect);
|
||||
|
||||
m_opts.dimvalue = m_conf.get(bs, "dim-value", 1.0);
|
||||
m_opts.dimvalue = math_util::cap(m_opts.dimvalue, 0.0, 1.0);
|
||||
@ -393,13 +388,14 @@ void bar::parse(string&& data, bool force) {
|
||||
|
||||
auto rect = m_opts.inner_area();
|
||||
|
||||
if (m_tray && !m_tray->settings().detached && m_tray->settings().num_mapped_clients > 0 && !m_tray->settings().adaptive) {
|
||||
auto trayalign = m_tray->settings().align;
|
||||
if (m_tray && !m_tray->settings().detached && m_tray->settings().num_mapped_clients > 0 &&
|
||||
m_tray->settings().tray_position != tray_postition::MODULE) {
|
||||
auto tray_pos = m_tray->settings().tray_position;
|
||||
auto traywidth = m_tray->settings().win_size.w;
|
||||
if (trayalign == alignment::LEFT) {
|
||||
if (tray_pos == tray_postition::LEFT) {
|
||||
rect.x += traywidth;
|
||||
rect.width -= traywidth;
|
||||
} else if (trayalign == alignment::RIGHT) {
|
||||
} else if (tray_pos == tray_postition::RIGHT) {
|
||||
rect.width -= traywidth;
|
||||
}
|
||||
}
|
||||
@ -415,19 +411,12 @@ void bar::parse(string&& data, bool force) {
|
||||
|
||||
m_renderer->end();
|
||||
|
||||
const auto check_dblclicks = [&]() -> bool {
|
||||
if (m_action_ctxt->has_double_click()) {
|
||||
return true;
|
||||
m_dblclicks.clear();
|
||||
for (auto&& action : m_opts.actions) {
|
||||
if (static_cast<int>(action.button) >= static_cast<int>(mousebtn::DOUBLE_LEFT)) {
|
||||
m_dblclicks.insert(action.button);
|
||||
}
|
||||
|
||||
for (auto&& action : m_opts.actions) {
|
||||
if (static_cast<int>(action.button) >= static_cast<int>(mousebtn::DOUBLE_LEFT)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
m_dblclicks = check_dblclicks();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -440,10 +429,11 @@ void bar::hide() {
|
||||
|
||||
try {
|
||||
m_log.info("Hiding bar window");
|
||||
m_visible = false;
|
||||
reconfigure_struts();
|
||||
m_sig.emit(visibility_change{false});
|
||||
m_connection.unmap_window_checked(m_opts.x_data.window);
|
||||
m_connection.flush();
|
||||
m_visible = false;
|
||||
} catch (const exception& err) {
|
||||
m_log.err("Failed to unmap bar window (err=%s", err.what());
|
||||
}
|
||||
@ -556,42 +546,46 @@ void bar::reconfigure_pos() {
|
||||
* Reconfigure window strut values
|
||||
*/
|
||||
void bar::reconfigure_struts() {
|
||||
auto geom = m_connection.get_geometry(m_connection.root());
|
||||
int h = m_opts.size.h + m_opts.offset.y;
|
||||
window win{m_connection, m_opts.x_data.window};
|
||||
if (m_visible) {
|
||||
auto geom = m_connection.get_geometry(m_connection.root());
|
||||
int h = m_opts.size.h + m_opts.offset.y;
|
||||
|
||||
// Apply user-defined margins
|
||||
if (m_opts.bottom) {
|
||||
h += m_opts.strut.top;
|
||||
} else {
|
||||
h += m_opts.strut.bottom;
|
||||
}
|
||||
|
||||
h = std::max(h, 0);
|
||||
|
||||
int correction = 0;
|
||||
|
||||
// Only apply correction if any space is requested
|
||||
if (h > 0) {
|
||||
/*
|
||||
* Strut coordinates have to be relative to root window and not any monitor.
|
||||
* If any monitor is not aligned at the top or bottom
|
||||
*/
|
||||
// Apply user-defined margins
|
||||
if (m_opts.bottom) {
|
||||
/*
|
||||
* For bottom-algined bars, the correction is the number of pixels between
|
||||
* the root window's bottom edge and the monitor's bottom edge
|
||||
*/
|
||||
correction = geom->height - (m_opts.monitor->y + m_opts.monitor->h);
|
||||
h += m_opts.strut.top;
|
||||
} else {
|
||||
// For top-aligned bars, we simply add the monitor's y-position
|
||||
correction = m_opts.monitor->y;
|
||||
h += m_opts.strut.bottom;
|
||||
}
|
||||
|
||||
correction = std::max(correction, 0);
|
||||
}
|
||||
h = std::max(h, 0);
|
||||
|
||||
window win{m_connection, m_opts.x_data.window};
|
||||
win.reconfigure_struts(m_opts.size.w, h + correction, m_opts.pos.x, m_opts.bottom);
|
||||
int correction = 0;
|
||||
|
||||
// Only apply correction if any space is requested
|
||||
if (h > 0) {
|
||||
/*
|
||||
* Strut coordinates have to be relative to root window and not any monitor.
|
||||
* If any monitor is not aligned at the top or bottom
|
||||
*/
|
||||
if (m_opts.bottom) {
|
||||
/*
|
||||
* For bottom-algined bars, the correction is the number of pixels between
|
||||
* the root window's bottom edge and the monitor's bottom edge
|
||||
*/
|
||||
correction = geom->height - (m_opts.monitor->y + m_opts.monitor->h);
|
||||
} else {
|
||||
// For top-aligned bars, we simply add the monitor's y-position
|
||||
correction = m_opts.monitor->y;
|
||||
}
|
||||
|
||||
correction = std::max(correction, 0);
|
||||
}
|
||||
win.reconfigure_struts(m_opts.size.w, h + correction, m_opts.pos.x, m_opts.bottom);
|
||||
} else {
|
||||
// Set struts to 0 for invisible bars
|
||||
win.reconfigure_struts(0, 0, 0, m_opts.bottom);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -634,6 +628,8 @@ void bar::broadcast_visibility() {
|
||||
}
|
||||
|
||||
void bar::map_window() {
|
||||
m_visible = true;
|
||||
|
||||
/**
|
||||
* First reconfigures the window so that WMs that discard some information
|
||||
* when unmapping have the correct window properties (geometry etc).
|
||||
@ -648,8 +644,6 @@ void bar::map_window() {
|
||||
* mapping. Additionally updating the window position after mapping seems to fix that.
|
||||
*/
|
||||
reconfigure_pos();
|
||||
|
||||
m_visible = true;
|
||||
}
|
||||
|
||||
void bar::trigger_click(mousebtn btn, int pos) {
|
||||
@ -818,9 +812,12 @@ void bar::handle(const evt::button_press& evt) {
|
||||
}
|
||||
};
|
||||
|
||||
mousebtn double_btn = mousebtn_get_double(btn);
|
||||
bool has_dblclick = m_dblclicks.count(double_btn) || m_action_ctxt->has_action(double_btn, pos) != tags::NO_ACTION;
|
||||
|
||||
// If there are no double click handlers defined we can
|
||||
// just by-pass the click timer handling
|
||||
if (!m_dblclicks) {
|
||||
if (!has_dblclick) {
|
||||
trigger_click(btn, pos);
|
||||
} else if (btn == mousebtn::LEFT) {
|
||||
check_double(m_leftclick_timer, btn, pos);
|
||||
@ -876,7 +873,7 @@ void bar::handle(const evt::configure_notify&) {
|
||||
m_sig.emit(signals::ui::update_geometry{});
|
||||
}
|
||||
|
||||
void bar::start() {
|
||||
void bar::start(const string& tray_module_name) {
|
||||
m_log.trace("bar: Create renderer");
|
||||
m_renderer = renderer::make(m_opts, *m_action_ctxt, *m_tray);
|
||||
|
||||
@ -907,7 +904,7 @@ void bar::start() {
|
||||
m_renderer->end();
|
||||
|
||||
m_log.trace("bar: Setup tray manager");
|
||||
m_tray->setup();
|
||||
m_tray->setup(tray_module_name);
|
||||
|
||||
broadcast_visibility();
|
||||
}
|
||||
|
@ -59,6 +59,10 @@ void config::set_included(file_list included) {
|
||||
m_included = move(included);
|
||||
}
|
||||
|
||||
file_list config::get_included_files() const {
|
||||
return m_included;
|
||||
}
|
||||
|
||||
void config::ignore_key(const string& section, const string& key) const {
|
||||
if (has(section, key)) {
|
||||
m_log.warn(
|
||||
|
@ -10,10 +10,10 @@
|
||||
|
||||
POLYBAR_NS
|
||||
|
||||
config_parser::config_parser(const logger& logger, string&& file, string&& bar)
|
||||
: m_log(logger), m_config(file_util::expand(file)), m_barname(move(bar)) {}
|
||||
config_parser::config_parser(const logger& logger, string&& file)
|
||||
: m_log(logger), m_config(file_util::expand(file)) {}
|
||||
|
||||
config::make_type config_parser::parse() {
|
||||
config::make_type config_parser::parse(string barname) {
|
||||
m_log.notice("Parsing config file: %s", m_config);
|
||||
|
||||
parse_file(m_config, {});
|
||||
@ -21,21 +21,21 @@ config::make_type config_parser::parse() {
|
||||
sectionmap_t sections = create_sectionmap();
|
||||
|
||||
vector<string> bars = get_bars(sections);
|
||||
if (m_barname.empty()) {
|
||||
if (barname.empty()) {
|
||||
if (bars.size() == 1) {
|
||||
m_barname = bars[0];
|
||||
barname = bars[0];
|
||||
} else if (bars.empty()) {
|
||||
throw application_error("The config file contains no bar.");
|
||||
} else {
|
||||
throw application_error("The config file contains multiple bars, but no bar name was given. Available bars: " +
|
||||
string_util::join(bars, ", "));
|
||||
}
|
||||
} else if (sections.find("bar/" + m_barname) == sections.end()) {
|
||||
} else if (sections.find("bar/" + barname) == sections.end()) {
|
||||
if (bars.empty()) {
|
||||
throw application_error("Undefined bar: " + m_barname + ". The config file contains no bar.");
|
||||
throw application_error("Undefined bar: " + barname + ". The config file contains no bar.");
|
||||
} else {
|
||||
throw application_error(
|
||||
"Undefined bar: " + m_barname + ". Available bars: " + string_util::join(get_bars(sections), ", "));
|
||||
"Undefined bar: " + barname + ". Available bars: " + string_util::join(get_bars(sections), ", "));
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ config::make_type config_parser::parse() {
|
||||
* second element onwards for the included list
|
||||
*/
|
||||
file_list included(m_files.begin() + 1, m_files.end());
|
||||
config::make_type result = config::make(m_config, m_barname);
|
||||
config::make_type result = config::make(m_config, barname);
|
||||
|
||||
// Cast to non-const to set sections, included and xrm
|
||||
config& m_conf = const_cast<config&>(result);
|
||||
|
@ -197,6 +197,16 @@ void controller::signal_handler(int signum) {
|
||||
stop(signum == SIGUSR1);
|
||||
}
|
||||
|
||||
void controller::create_config_watcher(const string& filename) {
|
||||
auto& fs_event_handler = m_loop.handle<FSEventHandle>();
|
||||
fs_event_handler.start(
|
||||
filename, 0, [this](const auto& e) { confwatch_handler(e.path); },
|
||||
[this, &fs_event_handler](const auto& e) {
|
||||
m_log.err("libuv error while watching included file for changes: %s", uv_strerror(e.status));
|
||||
fs_event_handler.close();
|
||||
});
|
||||
}
|
||||
|
||||
void controller::confwatch_handler(const char* filename) {
|
||||
m_log.notice("Watched config file changed %s", filename);
|
||||
stop(true);
|
||||
@ -239,7 +249,7 @@ void controller::read_events(bool confwatch) {
|
||||
m_log.info("Entering event loop (thread-id=%lu)", this_thread::get_id());
|
||||
|
||||
if (!m_writeback) {
|
||||
m_bar->start();
|
||||
m_bar->start(m_tray_module_name);
|
||||
}
|
||||
|
||||
auto& poll_handle = m_loop.handle<PollHandle>(m_connection.get_file_descriptor());
|
||||
@ -256,13 +266,11 @@ void controller::read_events(bool confwatch) {
|
||||
}
|
||||
|
||||
if (confwatch) {
|
||||
auto& fs_event_handle = m_loop.handle<FSEventHandle>();
|
||||
fs_event_handle.start(
|
||||
m_conf.filepath(), 0, [this](const auto& e) { confwatch_handler(e.path); },
|
||||
[this, &fs_event_handle](const auto& e) {
|
||||
m_log.err("libuv error while watching config file for changes: %s", uv_strerror(e.status));
|
||||
fs_event_handle.close();
|
||||
});
|
||||
create_config_watcher(m_conf.filepath());
|
||||
// also watch the include-files for changes
|
||||
for (auto& module_path : m_conf.get_included_files()) {
|
||||
create_config_watcher(module_path);
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_snapshot_dst.empty()) {
|
||||
@ -595,6 +603,13 @@ size_t controller::setup_modules(alignment align) {
|
||||
try {
|
||||
auto type = m_conf.get("module/" + module_name, "type");
|
||||
|
||||
if (type == tray_module::TYPE) {
|
||||
if (!m_tray_module_name.empty()) {
|
||||
throw module_error("Multiple trays defined. Using tray `" + m_tray_module_name + "`");
|
||||
}
|
||||
m_tray_module_name = module_name;
|
||||
}
|
||||
|
||||
if (type == ipc_module::TYPE && !m_has_ipc) {
|
||||
throw application_error("Inter-process messaging needs to be enabled");
|
||||
}
|
||||
|
@ -748,8 +748,12 @@ void renderer::render_text(const tags::context& ctxt, const string&& contents) {
|
||||
}
|
||||
}
|
||||
|
||||
void renderer::draw_offset(rgba color, double x, double w) {
|
||||
if (w > 0 && color != m_bar.background) {
|
||||
void renderer::draw_offset(const tags::context& ctxt, rgba color, double x, double w) {
|
||||
if (w <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (color != m_bar.background) {
|
||||
m_log.trace_x("renderer: offset(x=%f, w=%f)", x, w);
|
||||
m_context->save();
|
||||
*m_context << m_comp_bg;
|
||||
@ -759,6 +763,14 @@ void renderer::draw_offset(rgba color, double x, double w) {
|
||||
m_context->fill();
|
||||
m_context->restore();
|
||||
}
|
||||
|
||||
if (ctxt.has_underline()) {
|
||||
fill_underline(ctxt.get_ul(), x, w);
|
||||
}
|
||||
|
||||
if (ctxt.has_overline()) {
|
||||
fill_overline(ctxt.get_ol(), x, w);
|
||||
}
|
||||
}
|
||||
|
||||
void renderer::render_offset(const tags::context& ctxt, const extent_val offset) {
|
||||
@ -767,7 +779,7 @@ void renderer::render_offset(const tags::context& ctxt, const extent_val offset)
|
||||
|
||||
int offset_width = units_utils::extent_to_pixel(offset, m_bar.dpi_x);
|
||||
rgba bg = ctxt.get_bg();
|
||||
draw_offset(bg, m_blocks[m_align].x, offset_width);
|
||||
draw_offset(ctxt, bg, m_blocks[m_align].x, offset_width);
|
||||
increase_x(offset_width);
|
||||
}
|
||||
|
||||
@ -835,6 +847,9 @@ void renderer::apply_tray_position(const tags::context& context) {
|
||||
int absolute_x = static_cast<int>(
|
||||
block_x(context.get_relative_tray_position().first) + context.get_relative_tray_position().second);
|
||||
m_sig.emit(signals::ui_tray::tray_pos_change{absolute_x});
|
||||
m_sig.emit(signals::ui_tray::tray_visibility{true});
|
||||
} else {
|
||||
m_sig.emit(signals::ui_tray::tray_visibility{false});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "ipc/util.hpp"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "errors.hpp"
|
||||
#include "utils/env.hpp"
|
||||
@ -12,8 +13,14 @@ POLYBAR_NS
|
||||
namespace ipc {
|
||||
|
||||
static constexpr auto SUFFIX = ".sock";
|
||||
static constexpr auto XDG_RUNTIME_DIR = "XDG_RUNTIME_DIR";
|
||||
|
||||
string get_runtime_path() {
|
||||
if (env_util::has(XDG_RUNTIME_DIR)) {
|
||||
return env_util::get("XDG_RUNTIME_DIR") + "/polybar";
|
||||
} else {
|
||||
return "/tmp/polybar-" + to_string(getuid());
|
||||
}
|
||||
return env_util::get("XDG_RUNTIME_DIR", "/tmp") + "/polybar";
|
||||
}
|
||||
|
||||
@ -59,6 +66,6 @@ namespace ipc {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} // namespace ipc
|
||||
} // namespace ipc
|
||||
|
||||
POLYBAR_NS_END
|
||||
|
@ -127,8 +127,8 @@ int main(int argc, char** argv) {
|
||||
barname = cli->get(0);
|
||||
}
|
||||
|
||||
config_parser parser{logger, move(confpath), move(barname)};
|
||||
config::make_type conf = parser.parse();
|
||||
config_parser parser{logger, move(confpath)};
|
||||
config::make_type conf = parser.parse(move(barname));
|
||||
|
||||
//==================================================
|
||||
// Dump requested data
|
||||
|
@ -27,12 +27,33 @@ namespace modules {
|
||||
: inotify_module<backlight_module>(bar, move(name_)) {
|
||||
m_router->register_action(EVENT_DEC, [this]() { action_dec(); });
|
||||
m_router->register_action(EVENT_INC, [this]() { action_inc(); });
|
||||
auto card = m_conf.get(name(), "card", ""s);
|
||||
if (card.empty()) {
|
||||
vector<string> backlight_card_names = file_util::list_files(string_util::replace(PATH_BACKLIGHT, "%card%", ""));
|
||||
backlight_card_names.erase(std::remove_if(backlight_card_names.begin(), backlight_card_names.end(),
|
||||
[&](const string& card) -> bool {
|
||||
auto dir = string_util::replace(PATH_BACKLIGHT, "%card%", card);
|
||||
return !(file_util::is_file(dir + "/actual_brightness") &&
|
||||
file_util::is_file(dir + "/brightness") &&
|
||||
file_util::is_file(dir + "/max_brightness"));
|
||||
}),
|
||||
backlight_card_names.end());
|
||||
|
||||
auto card = m_conf.get(name(), "card");
|
||||
|
||||
if (backlight_card_names.empty()) {
|
||||
throw module_error("no viable default backlight found");
|
||||
}
|
||||
card = backlight_card_names.at(0);
|
||||
if (backlight_card_names.size() > 1) {
|
||||
m_log.warn("%s: multiple backlights found, using %s", name(), card);
|
||||
} else {
|
||||
m_log.info("%s: no backlight specified, using `%s`", name(), card);
|
||||
}
|
||||
}
|
||||
// Get flag to check if we should add scroll handlers for changing value
|
||||
m_scroll = m_conf.get(name(), "enable-scroll", m_scroll);
|
||||
|
||||
m_scroll_interval = m_conf.get(name(), "scroll-interval", m_scroll_interval);
|
||||
|
||||
// Add formats and elements
|
||||
m_formatter->add(DEFAULT_FORMAT, TAG_LABEL, {TAG_LABEL, TAG_BAR, TAG_RAMP});
|
||||
|
||||
@ -120,11 +141,11 @@ namespace modules {
|
||||
}
|
||||
|
||||
void backlight_module::action_inc() {
|
||||
change_value(5);
|
||||
change_value(m_scroll_interval);
|
||||
}
|
||||
|
||||
void backlight_module::action_dec() {
|
||||
change_value(-5);
|
||||
change_value(-m_scroll_interval);
|
||||
}
|
||||
|
||||
void backlight_module::change_value(int value_mod) {
|
||||
|
@ -199,7 +199,7 @@ namespace modules {
|
||||
if (chrono::duration_cast<decltype(m_interval)>(now - m_lastpoll) > m_interval) {
|
||||
m_lastpoll = now;
|
||||
m_log.info("%s: Polling values (inotify fallback)", name());
|
||||
read(*m_capacity_reader);
|
||||
on_event({});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,11 @@ namespace modules {
|
||||
* setting up required components
|
||||
*/
|
||||
fs_module::fs_module(const bar_settings& bar, string name_) : timer_module<fs_module>(bar, move(name_)) {
|
||||
m_mountpoints = m_conf.get_list(name(), "mount");
|
||||
m_mountpoints = m_conf.get_list(name(), "mount", {});
|
||||
if (m_mountpoints.empty()) {
|
||||
m_log.info("%s: No mountpoints specified, using fallback \"/\"", name());
|
||||
m_mountpoints.emplace_back("/");
|
||||
}
|
||||
m_remove_unmounted = m_conf.get(name(), "remove-unmounted", m_remove_unmounted);
|
||||
m_perc_used_warn = m_conf.get(name(), "warn-percentage", 90);
|
||||
m_fixed = m_conf.get(name(), "fixed-values", m_fixed);
|
||||
|
@ -108,7 +108,8 @@ namespace modules {
|
||||
if (evt->atom == m_ewmh->_NET_CLIENT_LIST || evt->atom == m_ewmh->_NET_WM_DESKTOP) {
|
||||
rebuild_clientlist();
|
||||
rebuild_desktop_states();
|
||||
} else if (evt->atom == m_ewmh->_NET_DESKTOP_NAMES || evt->atom == m_ewmh->_NET_NUMBER_OF_DESKTOPS) {
|
||||
} else if (evt->atom == m_ewmh->_NET_DESKTOP_NAMES || evt->atom == m_ewmh->_NET_NUMBER_OF_DESKTOPS ||
|
||||
evt->atom == m_ewmh->_NET_DESKTOP_VIEWPORT) {
|
||||
m_desktop_names = get_desktop_names();
|
||||
rebuild_desktops();
|
||||
rebuild_clientlist();
|
||||
|
@ -67,25 +67,26 @@ tray_manager::~tray_manager() {
|
||||
deactivate();
|
||||
}
|
||||
|
||||
void tray_manager::setup() {
|
||||
void tray_manager::setup(const string& tray_module_name) {
|
||||
const config& conf = config::make();
|
||||
auto bs = conf.section();
|
||||
string position;
|
||||
string position = conf.get(bs, "tray-position", "none"s);
|
||||
|
||||
try {
|
||||
position = conf.get(bs, "tray-position");
|
||||
} catch (const key_error& err) {
|
||||
return m_log.info("Disabling tray manager (reason: missing `tray-position`)");
|
||||
if (!position.empty() && position != "none" && !tray_module_name.empty()) {
|
||||
m_log.warn(
|
||||
"The tray position is manually defined (`tray-position`) and also set by the tray module (%s). `tray-position` "
|
||||
"will be ignored",
|
||||
tray_module_name);
|
||||
}
|
||||
|
||||
if (position == "left") {
|
||||
m_opts.align = alignment::LEFT;
|
||||
if (!tray_module_name.empty()) {
|
||||
m_opts.tray_position = tray_postition::MODULE;
|
||||
} else if (position == "left") {
|
||||
m_opts.tray_position = tray_postition::LEFT;
|
||||
} else if (position == "right") {
|
||||
m_opts.align = alignment::RIGHT;
|
||||
m_opts.tray_position = tray_postition::RIGHT;
|
||||
} else if (position == "center") {
|
||||
m_opts.align = alignment::CENTER;
|
||||
} else if (position == "adaptive") {
|
||||
m_opts.adaptive = true;
|
||||
m_opts.tray_position = tray_postition::CENTER;
|
||||
} else if (position != "none") {
|
||||
return m_log.err("Disabling tray manager (reason: Invalid position \"" + position + "\")");
|
||||
} else {
|
||||
@ -114,12 +115,12 @@ void tray_manager::setup() {
|
||||
m_opts.win_size.h *= scale;
|
||||
|
||||
m_opts.pos.x = inner_area.x + [&]() -> int {
|
||||
switch (m_opts.align) {
|
||||
case alignment::LEFT:
|
||||
switch (m_opts.tray_position) {
|
||||
case tray_postition::LEFT:
|
||||
return 0;
|
||||
case alignment::CENTER:
|
||||
case tray_postition::CENTER:
|
||||
return inner_area.width / 2 - m_opts.client_size.w / 2;
|
||||
case alignment::RIGHT:
|
||||
case tray_postition::RIGHT:
|
||||
return inner_area.width;
|
||||
default:
|
||||
return 0;
|
||||
@ -755,9 +756,9 @@ void tray_manager::process_docking_request(xcb_window_t win) {
|
||||
*/
|
||||
int tray_manager::calculate_x(unsigned int width) const {
|
||||
auto x = m_opts.pos.x;
|
||||
if (m_opts.align == alignment::RIGHT) {
|
||||
if (m_opts.tray_position == tray_postition::RIGHT) {
|
||||
x -= ((m_opts.client_size.w + m_opts.spacing) * m_clients.size() + m_opts.spacing);
|
||||
} else if (m_opts.align == alignment::CENTER) {
|
||||
} else if (m_opts.tray_position == tray_postition::CENTER) {
|
||||
x -= (width / 2) - (m_opts.client_size.w / 2);
|
||||
}
|
||||
return x;
|
||||
@ -849,6 +850,29 @@ bool tray_manager::has_mapped_clients() const {
|
||||
return std::find_if(m_clients.begin(), m_clients.end(), [](const auto& c) { return c.mapped(); }) != m_clients.end();
|
||||
}
|
||||
|
||||
bool tray_manager::change_visibility(bool visible) {
|
||||
bool has_clients = has_mapped_clients();
|
||||
|
||||
m_log.trace("tray: visibility_change (state=%i, activated=%i, mapped=%i, hidden=%i)", visible,
|
||||
static_cast<bool>(m_activated), static_cast<bool>(m_mapped), static_cast<bool>(m_hidden));
|
||||
|
||||
m_hidden = !visible;
|
||||
|
||||
if (!m_activated) {
|
||||
return false;
|
||||
} else if (!m_hidden && !m_mapped && has_clients) {
|
||||
m_connection.map_window(m_tray);
|
||||
} else if ((!has_clients || m_hidden) && m_mapped) {
|
||||
m_connection.unmap_window(m_tray);
|
||||
} else if (m_mapped && !m_hidden && has_clients) {
|
||||
redraw_window();
|
||||
}
|
||||
|
||||
m_connection.flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event callback : XCB_EXPOSE
|
||||
*/
|
||||
@ -1073,27 +1097,7 @@ void tray_manager::handle(const evt::unmap_notify& evt) {
|
||||
* toggle the tray window whenever the visibility of the bar window changes.
|
||||
*/
|
||||
bool tray_manager::on(const signals::ui::visibility_change& evt) {
|
||||
bool visible{evt.cast()};
|
||||
bool has_clients = has_mapped_clients();
|
||||
|
||||
m_log.trace("tray: visibility_change (state=%i, activated=%i, mapped=%i, hidden=%i)", visible,
|
||||
static_cast<bool>(m_activated), static_cast<bool>(m_mapped), static_cast<bool>(m_hidden));
|
||||
|
||||
m_hidden = !visible;
|
||||
|
||||
if (!m_activated) {
|
||||
return false;
|
||||
} else if (!m_hidden && !m_mapped && has_clients) {
|
||||
m_connection.map_window(m_tray);
|
||||
} else if ((!has_clients || m_hidden) && m_mapped) {
|
||||
m_connection.unmap_window(m_tray);
|
||||
} else if (m_mapped && !m_hidden && has_clients) {
|
||||
redraw_window();
|
||||
}
|
||||
|
||||
m_connection.flush();
|
||||
|
||||
return true;
|
||||
return change_visibility(evt.cast());
|
||||
}
|
||||
|
||||
bool tray_manager::on(const signals::ui::dim_window& evt) {
|
||||
@ -1112,10 +1116,20 @@ bool tray_manager::on(const signals::ui::update_background&) {
|
||||
}
|
||||
|
||||
bool tray_manager::on(const signals::ui_tray::tray_pos_change& evt) {
|
||||
m_opts.pos.x = m_bar_opts.inner_area(true).x + evt.cast();
|
||||
m_opts.pos.x =
|
||||
m_bar_opts.inner_area(false).x + std::max(0, std::min(evt.cast(), (int)(m_bar_opts.size.w - calculate_w())));
|
||||
|
||||
reconfigure_window();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tray_manager::on(const signals::ui_tray::tray_visibility& evt) {
|
||||
if (evt.cast() == m_hidden && m_opts.tray_position == tray_postition::MODULE) {
|
||||
return change_visibility(evt.cast());
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
POLYBAR_NS_END
|
||||
|
@ -57,14 +57,16 @@ window window::reconfigure_pos(short int x, short int y) {
|
||||
window window::reconfigure_struts(uint32_t w, uint32_t strut, uint32_t x, bool bottom) {
|
||||
std::array<uint32_t, 12> values{};
|
||||
|
||||
uint32_t end_x = std::max<int>(0, x + w - 1);
|
||||
|
||||
if (bottom) {
|
||||
values[to_integral(strut::BOTTOM)] = strut;
|
||||
values[to_integral(strut::BOTTOM_START_X)] = x;
|
||||
values[to_integral(strut::BOTTOM_END_X)] = x + w - 1;
|
||||
values[to_integral(strut::BOTTOM_END_X)] = end_x;
|
||||
} else {
|
||||
values[to_integral(strut::TOP)] = strut;
|
||||
values[to_integral(strut::TOP_START_X)] = x;
|
||||
values[to_integral(strut::TOP_END_X)] = x + w - 1;
|
||||
values[to_integral(strut::TOP_END_X)] = end_x;
|
||||
}
|
||||
|
||||
connection().change_property_checked(
|
||||
|
@ -13,8 +13,8 @@ class TestableConfigParser : public config_parser {
|
||||
using config_parser::config_parser;
|
||||
|
||||
public:
|
||||
TestableConfigParser(const logger& logger, string&& file, string&& bar)
|
||||
: config_parser(logger, move(file), move(bar)) {
|
||||
TestableConfigParser(const logger& logger, string&& file)
|
||||
: config_parser(logger, move(file)) {
|
||||
m_files.push_back("test_config");
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ class TestableConfigParser : public config_parser {
|
||||
class ConfigParser : public ::testing::Test {
|
||||
protected:
|
||||
const logger l = logger(loglevel::NONE);
|
||||
unique_ptr<TestableConfigParser> parser = make_unique<TestableConfigParser>(l, "/dev/zero", "TEST");
|
||||
unique_ptr<TestableConfigParser> parser = make_unique<TestableConfigParser>(l, "/dev/zero");
|
||||
};
|
||||
|
||||
// ParseLineTest {{{
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Polybar version information
|
||||
# Update this on every release
|
||||
# This is used to create the version string if a git repo is not available
|
||||
3.6.2
|
||||
3.6.3
|
||||
|
Loading…
Reference in New Issue
Block a user