-----BEGIN PGP SIGNATURE-----

iQEzBAABCAAdFiEEHVeRNS1RoijU3dukUh5eA668oacFAmVkwa4ACgkQUh5eA668
 oackXggAtyUMZSVxtxrjS9LLYwSFR0p09a7ns1QYJmGjQo2ZHW3f4hHQuajqFPLE
 J8icknCPtRge2tm6J7XGQakZ+PUXe7ILLCBFf8DFbgdbCe3YiEvxHtnRa6MCR1yO
 4ljwg7MIlS58ynJt92nh3R/7PxigZYKn/DqV2HeMvXqLimLXvXLDbAjVwPbvHNDJ
 Eq/jJExEyX4ZrXEIIGxq3/QnxeSI+IPbReMbVZbERWG9jZt2RJoPUepRDH6jhWJN
 03oUZ6gm5qU8frvhbpGfqZ2hVncnyJRskXR1CJ31OyGGiS2WfGK5viI0geQyRAse
 LxaRJHdrURVX7x1VSzdah6yzaSo1fA==
 =Wy/L
 -----END PGP SIGNATURE-----

Merge tag '3.7.1'
This commit is contained in:
Przemek Grondek 2024-02-27 15:33:34 +01:00
commit 6d42ccedd6
213 changed files with 7630 additions and 4660 deletions

View File

@ -1,9 +1,9 @@
---
Language: Cpp
Standard: Cpp11
Standard: c++17
BasedOnStyle: Google
ColumnLimit: 120
NamespaceIndentation: All
NamespaceIndentation: Inner
AlignAfterOpenBracket: DontAlign
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: false

View File

@ -16,6 +16,7 @@ Checks: '
-modernize-raw-string-literal,
-modernize-use-bool-literals,
-modernize-use-trailing-return-type,
-readability-identifier-length,
-readability-implicit-bool-cast,
-readability-else-after-return,
-readability-named-parameter,
@ -26,7 +27,8 @@ Checks: '
-cppcoreguidelines-pro-type-reinterpret-cast,
-cppcoreguidelines-pro-type-union-access,
-cppcoreguidelines-pro-type-cstyle-cast,
-cppcoreguidelines-pro-bounds-constant-array-index
-cppcoreguidelines-pro-bounds-constant-array-index,
-cppcoreguidelines-owning-memory,
'
CheckOptions:

View File

@ -7,6 +7,9 @@ indent_style = space
indent_size = 2
charset = utf-8
[*.py]
indent_size = 4
[Makefile]
indent_style = tab
indent_size = 2

View File

@ -1,4 +1,4 @@
name: Bug Report
name: 🐞 Bug Report
description: Create a report for something that misbehaves
title: "[Bug]: "
labels: ["bug", "needs confirmation"]
@ -33,7 +33,7 @@ body:
id: config
attributes:
label: Minimal config
description: A minimal but complete config with which the problem occurs.
description: A minimal but **complete** config with which the problem occurs.
render: dosini
placeholder: |
[bar/example]
@ -103,7 +103,7 @@ body:
id: context
attributes:
label: Additional Context / Screenshots
description: If applicaple, add screenshots and additional context to explain your problem
description: If applicable, add screenshots and additional context to explain your problem
validations:
required: false
- type: markdown

View File

@ -1,81 +0,0 @@
name: Build Issues
description: Report issues while building polybar from source
labels: ["build", "needs confirmation"]
body:
- type: checkboxes
id: checklist
attributes:
label: Checklist
description: Please carefully go through this checklist and check each option.
options:
- label: I have followed every step on the [compiling wiki page](https://github.com/polybar/polybar/wiki/Compiling) and installed all necessary dependencies.
required: true
- label: My problem is not described on the [known issues page](https://github.com/polybar/polybar/wiki/Known-Issues)
required: true
- label: I have searched for other open and closed [issues](https://github.com/polybar/polybar/issues?q=is%3Aissue) that may have already reported this problem.
required: true
- label: I was able to reproduce this build issue in a clean build
required: true
- type: dropdown
id: source
attributes:
label: From where are you building polybar?
options:
- From a release archive
- By cloning this repository
- Some other way (How?)
validations:
required: true
- type: input
id: how
attributes:
label: Describe how you are building polybar.
description: Only if you selected "Some other way".
placeholder: ex. polybar from the AUR
validations:
required: false
- type: input
id: version
attributes:
label: Version
description: What version of polybar are you trying to build? If you are building directly from git, this is the output of `git describe --tags`.
placeholder: ex. 3.5.7
validations:
required: true
- type: textarea
id: commands
attributes:
label: Build Process
description: List the exact commands you are using to build polybar
render: shell
placeholder: |
mkdir build
cd build
cmake ..
...
validations:
required: true
- type: textarea
id: logs
attributes:
label: Build log
description: |
Copy-paste all the terminal output produced while building polybar.
This MUST include the output of the `cmake`, `make`, and/or `build.sh` commands, if you used them.
render: text
validations:
required: true
- type: input
id: distro
attributes:
label: Linux Distribution
placeholder: ex. Ubuntu 21.04
validations:
required: true
- type: textarea
id: context
attributes:
label: Additional Context
description: Add any other context that you think is necessary about the problem here
validations:
required: false

View File

@ -1,8 +1,11 @@
blank_issues_enabled: false
contact_links:
- name: Polybar Gitter Room
url: https://gitter.im/polybar/polybar
about: Please ask and answer questions here.
- name: Polybar subreddit
url: https://www.reddit.com/r/polybar
about: Please ask and answer questions here.
- name: 🙋 Ask a question
url: https://github.com/polybar/polybar/blob/master/SUPPORT.md
about: Have a look at our support resources and channels
- name: 💡 Feature request
url: https://github.com/polybar/polybar/discussions/categories/ideas
about: Suggest your idea over in Discussions
- name: 🛠️ Build Issues
url: https://github.com/polybar/polybar/discussions/categories/build-support
about: Get support when building polybar from source

View File

@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
labels: feature, needs confirmation
---
## Is your feature request related to a problem? Please describe.
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
## Why does polybar need this feature?
<!-- Describe why this feature would be useful to a large percentage of users (You need to convince us). -->
## Describe the solution you'd like
<!-- A clear and concise description of how your solution would work. This includes possible config options that should be added. -->
## Describe alternatives you've considered
<!-- A clear and concise description of any alternative solutions or features you've considered, if any. -->
## Additional context
<!-- Add any other context or screenshots about the feature request here. -->

View File

View File

@ -10,11 +10,11 @@ on:
jobs:
docs:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
env:
COLOR: "ON"
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
ref: ${{ github.event.inputs.ref }}
- name: Install Dependencies
@ -29,7 +29,7 @@ jobs:
make doc
ipc:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
env:
COLOR: "ON"
steps:
@ -48,7 +48,7 @@ jobs:
python3-xcbgen \
libuv1-dev \
xcb-proto
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: true
ref: ${{ github.event.inputs.ref }}
@ -60,7 +60,7 @@ jobs:
make polybar-msg
build:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
strategy:
matrix:
cxx: [g++, clang++]
@ -115,7 +115,7 @@ jobs:
if [ "$POLYBAR_BUILD_TYPE" = "tests" ]; then
sudo apt-get install -y lcov
fi
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: true
ref: ${{ github.event.inputs.ref }}
@ -125,7 +125,7 @@ jobs:
run: ./common/ci/configure.sh
- name: Build
run: |
cd $BUILD_DIR
cd "$BUILD_DIR"
make
- name: Collect initial coverage
if: ${{ matrix.polybar_build_type == 'tests' }}
@ -134,17 +134,17 @@ jobs:
- name: Tests
if: ${{ matrix.polybar_build_type == 'tests' }}
run: |
cd $BUILD_DIR
cd "$BUILD_DIR"
make check
- name: Collect coverage
if: ${{ matrix.polybar_build_type == 'tests' }}
run: |
lcov --capture --no-external --directory . -o cov_tests.info
lcov --add-tracefile cov_base.info --add-tracefile cov_tests.info -o cov_total.info
lcov --remove cov_total.info ${PWD}'/build/*' ${PWD}'/tests/*' ${PWD}'/lib/*' -o cov.info
lcov --remove cov_total.info "${PWD}/build/*" "${PWD}/tests/*" "${PWD}/lib/*" -o cov.info
- name: Upload Coverage
if: ${{ matrix.polybar_build_type == 'tests' }}
uses: codecov/codecov-action@v2
uses: codecov/codecov-action@v3
with:
flags: unittests
files: ./cov.info

View File

@ -31,9 +31,11 @@ jobs:
RELEASE_TAG=${GITHUB_REF#refs/tags/}
fi
echo "Publishing Version $RELEASE_TAG"
echo "RELEASE_TAG=$RELEASE_TAG" >> "$GITHUB_ENV"
echo "POLYBAR_DIR=polybar-$RELEASE_TAG" >> "$GITHUB_ENV"
echo "POLYBAR_ARCHIVE=polybar-$RELEASE_TAG.tar.gz" >> "$GITHUB_ENV"
{
echo "RELEASE_TAG=$RELEASE_TAG"
echo "POLYBAR_DIR=polybar-$RELEASE_TAG"
echo "POLYBAR_ARCHIVE=polybar-$RELEASE_TAG.tar.gz"
} >> "$GITHUB_ENV"
# Checks out the target tag
- uses: actions/checkout@v2
@ -91,7 +93,7 @@ jobs:
const fname = '${{ env.POLYBAR_ARCHIVE }}'
const url = '${{ steps.upload_archive.outputs.browser_download_url }}'
const hash = '${{ env.SHA256SUM }}'
let body = "## Download:\n\n"
let body = "## Download\n\n"
body += `[${fname}](${url}) (**sha256**: \`${hash}\`)\n\n`
body += process.env.RELEASE_BODY;

6
.gitignore vendored
View File

@ -8,4 +8,10 @@
.tags
*.user
# clangd
/.cache
polybar-*.tar
*.cache
.venv

22
.readthedocs.yaml Normal file
View File

@ -0,0 +1,22 @@
---
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Set the version of Python and other tools you might need
build:
os: ubuntu-22.04
tools:
python: "3"
# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: doc/conf.py
fail_on_warning: true
python:
install:
- requirements: doc/requirements.txt

View File

@ -1,126 +0,0 @@
import os
import ycm_core
# Default flags
flags = [
'-std=c++14',
'-Wall',
'-Wextra',
# Relative paths are corrected by MakeRelativePathsInFlagsAbsolute
'-Isrc',
'-Iinclude',
'-Ilib/concurrentqueue/include',
'-Ilib/i3ipcpp/include',
'-Ilib/xpp/include',
'-Itests',
'-I/usr/include',
'-I/usr/include/freetype2',
]
# Base directory of the project, parent directory of all source files
project_dir = os.path.dirname(os.path.abspath(__file__))
# This assumes that everyone coding for this project builds inside the 'build'
# directory
compilation_database_folder = project_dir + "/build"
if os.path.exists(compilation_database_folder):
database = ycm_core.CompilationDatabase(compilation_database_folder)
else:
database = None
SOURCE_EXTENSIONS = ['.cpp', '.cxx', '.cc', '.c', '.m', '.mm']
# Converts all relative paths in the given flag list to absolute paths with
# working_directory as the base directory
def MakeRelativePathsInFlagsAbsolute(flags, working_directory):
if not working_directory:
return list(flags)
new_flags = []
make_next_absolute = False
path_flags = ['-isystem', '-I', '-iquote', '--sysroot=']
for flag in flags:
new_flag = flag
if make_next_absolute:
make_next_absolute = False
if not flag.startswith('/'):
new_flag = os.path.join(working_directory, flag)
for path_flag in path_flags:
if flag == path_flag:
make_next_absolute = True
break
if flag.startswith(path_flag):
path = flag[len(path_flag):]
new_flag = path_flag + os.path.join(working_directory, path)
break
if new_flag:
new_flags.append(new_flag)
return new_flags
def IsHeaderFile(filename):
extension = os.path.splitext(filename)[1]
return extension in ['.h', '.hxx', '.hpp', '.hh', ".inl"]
# Tries to query the compilation database for flags
# For header files it tries to use the flags for a corresponding source file
def GetCompilationInfoForFile(filename):
if not database:
return None
# The compilation_commands.json file generated by CMake does not have entries
# for header files. We try to use the compile flags used for the corresponding
# source file.
#
# For this try to replace the file extension with an extension that
# corresponds to a source and we also try to replace the 'include' folder in
# the path with 'src'
if IsHeaderFile(filename) :
basename = os.path.splitext(filename)[0]
# Absolute path of the include and source directories
include_dir = project_dir + "/include"
src_dir = project_dir + "/src"
# Absolute path without file extension, with the 'include' folder replaced
# with 'src' in the path
src_basename = None
# If the header file is inside the include dir, try to search in the src dir
if basename.startswith(include_dir):
# file path relative to include dir
rel_path_include = os.path.relpath(basename, include_dir)
src_basename = os.path.join(src_dir, rel_path_include)
for extension in SOURCE_EXTENSIONS:
# A list of all possible replacement files to be searched
replacement_files = [basename + extension]
if src_basename:
replacement_files.append(src_basename + extension)
for replacement_file in replacement_files:
if os.path.exists(replacement_file):
comp_info = database.GetCompilationInfoForFile(replacement_file)
if comp_info.compiler_flags_:
return comp_info
return database.GetCompilationInfoForFile(filename)
def FlagsForFile(filename, **kwargs):
compilation_info = GetCompilationInfoForFile(filename)
if compilation_info and compilation_info.compiler_flags_:
# Bear in mind that compilation_info.compiler_flags_ does NOT return a
# python list, but a "list-like" StringVec object
final_flags = MakeRelativePathsInFlagsAbsolute(
[x for x in compilation_info.compiler_flags_ if x != "-Werror"],
compilation_info.compiler_working_dir_)
else:
# We use default flags if GetCompilationInfoForFile can't find any flags
relative_to = project_dir
final_flags = MakeRelativePathsInFlagsAbsolute(flags, relative_to)
return {'flags': final_flags, 'do_cache': True}

View File

@ -65,6 +65,81 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `internal/i3`: module errors when i3 has negative gaps ([`#2888`](https://github.com/polybar/polybar/issues/2888), [`#2889`](https://github.com/polybar/polybar/pull/2889))
- `wm-restack = bspwm`: bar may become unclickable if there are overlapping monitors ([`#2873`](https://github.com/polybar/polybar/issues/2873), [`#2961`](https://github.com/polybar/polybar/pull/2961))
## [3.7.1] - 2023-11-27
### Build
- Fixed missing header when using `libc++` in clang 15 and below
### Changed
- `internal/tray`: The module must use the `<tray>` tag (this is the default) ([`#3037`](https://github.com/polybar/polybar/pull/3037))
## Fixed
- Modules did not validate that all tags (e.g. `<label>`) used in a format were valid for that format ([`#3043`](https://github.com/polybar/polybar/issues/3043), [`#3045`](https://github.com/polybar/polybar/pull/3045))
- `internal/tray`: Fixed `module-margin` and `separator` being applied to completely empty tray module ([`#3036`](https://github.com/polybar/polybar/issues/3036), [`#3037`](https://github.com/polybar/polybar/pull/3037))
## [3.7.0] - 2023-11-05
### Breaking
- `custom/script`:
- No longer hides the module if the `exec` command failed and did not change the output from the previous run ([`#2636`](https://github.com/polybar/polybar/issues/2636)). Somewhat similar original behaviour can be imitated with `format-fail`, if necessary.
- If the `exec` command produced no output and exited with a non-zero exit code the module is no longer completely empty, but just has an empty `%output%` token. If you relied on this behavior to hide the module under certain circumstances, make sure the script exits with an exit code of zero. ([`#2857`](https://github.com/polybar/polybar/discussions/2857), [`#2861`](https://github.com/polybar/polybar/pull/2861))
### Build
- Respect `CMAKE_INSTALL_PREFIX` when installing default config ([`#2770`](https://github.com/polybar/polybar/pull/2770), [`#2917`](https://github.com/polybar/polybar/pull/2917))
- Change default `CMAKE_INSTALL_PREFIX` to `/usr`. Installations with default flags will now go into `/usr` instead of `/usr/local` ([`#2917`](https://github.com/polybar/polybar/pull/2917))
- Bump C++ version to C++17 ([`#2847`](https://github.com/polybar/polybar/pull/2847))
### 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))
- tray: All tray-related settings in the bar section are deprecated. They are replaced by the new tray module ([`#3002`](https://github.com/polybar/polybar/pull/3002))
- `tray-position`, `tray-detached`, `tray-maxsize`, `tray-scale`, `tray-transparent`, `tray-background`, `tray-foreground`, `tray-padding`, `tray-offset-x`, `tray-offset-y`
### Added
- A tray module with type `internal/tray` for positioning the tray like a module ([`#2689`](https://github.com/polybar/polybar/issues/2689))
- `internal/temperature`: `%temperature-k%` token displays the temperature in degrees Kelvin ([`#2774`](https://github.com/polybar/polybar/discussions/2774), [`#2784`](https://github.com/polybar/polybar/pull/2784))
- `internal/pulseaudio`: `reverse-scroll` option ([`#2664`](https://github.com/polybar/polybar/pull/2664))
- `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/ipc`:
- Added support for `<label>` in `format` ([`#2841`](https://github.com/polybar/polybar/pull/2841)) by [@madhavpcm](https://github.com/madhavpcm).
- Added support for `format-i` for each defined `hook-i` ([`#2775`](https://github.com/polybar/polybar/issues/2775), [`#2810`](https://github.com/polybar/polybar/pull/2810)) by [@madhavpcm](https://github.com/madhavpcm).
- `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))
- `internal/backlight`:
- `scroll-interval` option ([`#2696`](https://github.com/polybar/polybar/issues/2696), [`#2700`](https://github.com/polybar/polybar/pull/2700))
- `poll-interval` setting controls how often the module is updated (in case it does not happen when the brightness changes) ([`#2835`](https://github.com/polybar/polybar/issues/2835), [`#3028`](https://github.com/polybar/polybar/pull/3028))
- `internal/temperature`: Added `zone-type` setting ([`#2572`](https://github.com/polybar/polybar/issues/2572), [`#2752`](https://github.com/polybar/polybar/pull/2752)) by [@xphoniex](https://github.com/xphoniex)
- `internal/xwindow`: `%class%` and `%instance%` tokens, which show the contents of the `WM_CLASS` property of the active window ([`#2830`](https://github.com/polybar/polybar/pull/2830))
- Added `enable-struts` option in bar section to enable/disable struts ([`#2769`](https://github.com/polybar/polybar/issues/2769), [`#2844`](https://github.com/polybar/polybar/pull/2844)) by [@VanillaViking](https://github.com/VanillaViking).
- `wm-restack`:
- `bottom`: lowers polybar to the bottom of the window stack (same as the previous behavior of `generic`) ([`#2961`](https://github.com/polybar/polybar/pull/2961))
- `ewmh`: Tries to use the `_NET_SUPPORTING_WM_CHECK` hint to position the bar ([`#2961`](https://github.com/polybar/polybar/pull/2961))
- `internal/xworkspaces`: `group-by-monitor` setting to decide whether `_NET_DESKTOP_VIEWPORT` should be used to group workspaces by monitor; ([`#2603`](https://github.com/polybar/polybar/issues/2603), [`#2926`](https://github.com/polybar/polybar/pull/2926)) by [@slotThe](https://github.com/slotThe/).
### Changed
- `custom/script`:
- No longer produces a completely empty module if the `exec` command failed. It only produces an empty module if the script had a zero exit code. ([`#2857`](https://github.com/polybar/polybar/discussions/2857), [`#2861`](https://github.com/polybar/polybar/pull/2861))
- Bumped the script polling interval (not related to the `interval` setting) to decrease wakeups. Polybar may take slightly longer to shut down. [`#2879`](https://github.com/polybar/polybar/pull/2879)
- `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))
- `use-actual-brightness` now always defaults to `true` (even for `amdgpu` backlights) ([`#2835`](https://github.com/polybar/polybar/issues/2835), [`2839`](https://github.com/polybar/polybar/pull/2839))
- Providing a negative min-width to a token adds right-padding ([`#2789`](https://github.com/polybar/polybar/issues/2789), [`#2801`](https://github.com/polybar/polybar/pull/2801)) by [@VanillaViking](https://github.com/VanillaViking).
- Changed fuzzy match option on i3 and bspwm modules to find longest match instead of the first match ([`#2831`](https://github.com/polybar/polybar/pull/2831), [`#2829`](https://github.com/polybar/polybar/issues/2829)) by [@Ron0Studios](https://github.com/ron0studios/).
- `wm-restack`
- `generic`: Is now a best effort combination of other restacking strategies. First tries `ewmh` and then the `bottom` strategy ([`#2961`](https://github.com/polybar/polybar/pull/2961))
- `bspwm`: Will restack above the topmost bspwm root window instead of the root window associated with the monitor polybar is on ([`#3019`](https://github.com/polybar/polybar/pull/3019))
### 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))
- renderer:
- Small gaps when rendering emojis ([`#2785`](https://github.com/polybar/polybar/issues/2785), [`#2802`](https://github.com/polybar/polybar/pull/2802))
- Crash when using pseudo-transparency with certain wallpapers ([`#2798`](https://github.com/polybar/polybar/issues/2798), [`#2813`](https://github.com/polybar/polybar/pull/2813))
- Crash when invalid UTF-8 text is encountered ([`#2091`](https://github.com/polybar/polybar/issues/2091), [`#2958`](https://github.com/polybar/polybar/pull/2958))
- 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))
- `internal/xwindow`: module does not crash when a tag is not provided in format ([`#2826`](https://github.com/polybar/polybar/issues/2826), [`#2833`](https://github.com/polybar/polybar/pull/2833)) by [@VanillaViking](https://github.com/VanillaViking)
- `internal/i3`: module errors when i3 has negative gaps ([`#2888`](https://github.com/polybar/polybar/issues/2888), [`#2889`](https://github.com/polybar/polybar/pull/2889))
- `internal/backlight`: Fix module being one step behind every update ([`#2835`](https://github.com/polybar/polybar/issues/2835), [`#3028`](https://github.com/polybar/polybar/pull/3028))
- `wm-restack = bspwm`: bar may become unclickable if there are overlapping monitors ([`#2873`](https://github.com/polybar/polybar/issues/2873), [`#2961`](https://github.com/polybar/polybar/pull/2961))
## [3.6.3] - 2022-05-04
### Fixed
- `custom/script`: Output clearing when `exec-if` fails ([`#2674`](https://github.com/polybar/polybar/issues/2674))
@ -101,7 +176,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- We added the backslash escape character (\\) for configuration values. This means that the literal backslash character now has special meaning in configuration files, therefore if you want to use it in a value as a literal backslash, you need to escape it with the backslash escape character. The parser logs an error if any unescaped backslashes are found in a value. This affects you only if you are using two consecutive backslashes in a config value, which will now be interpreted as a single literal backslash. ([`#2354`](https://github.com/polybar/polybar/issues/2354))
- We rewrote our formatting tag parser. This shouldn't break anything, if you experience any problems, please let us know. The new parser now gives errors for certain invalid tags where the old parser would just silently ignore them. Adding extra text to the end of a valid tag now produces an error. For example, tags like `%{T-a}`, `%{T2abc}`, `%{rfoo}`, and others will now start producing errors. This does not affect you unless you are producing your own invalid formatting tags (for example in a script).
- For security reasons, the named pipe at `/tmp/polybar_mqueue.<PID>` had its permission bits changed from `666` to `600` to prevent sending ipc messages to polybar processes running under a different user.
- Also for security reasons, the `polybar-msg` command will now only send messages to polybar processes running under the same user. See the [IPC documentation](https://polybar.readthedocs.io/en/stable/user/ipc.html) for what exactly this means.
- Also for security reasons, the `polybar-msg` command will now only send messages to polybar processes running under the same user. See the [IPC documentation](https://polybar.readthedocs.io/user/ipc.html) for what exactly this means.
### Build
- New dependency: [libuv](https://github.com/libuv/libuv). At least version 1.3 is required.
@ -238,7 +313,9 @@ 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.3...HEAD
[Unreleased]: https://github.com/polybar/polybar/compare/3.7.1...HEAD
[3.7.1]: https://github.com/polybar/polybar/releases/tag/3.7.1
[3.7.0]: https://github.com/polybar/polybar/releases/tag/3.7.0
[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

View File

@ -22,6 +22,14 @@ else()
set(APP_VERSION "${version_txt}")
endif()
# Set the default installation prefix to /usr
# Otherwise the default value is /usr/local which causes the default config
# file to be installed to /usr/local/etc, with /usr, cmake has special handling
# for this.
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "Project-default installation prefix" FORCE)
endif()
list(APPEND CMAKE_MODULE_PATH
${PROJECT_SOURCE_DIR}/cmake
${PROJECT_SOURCE_DIR}/cmake/common
@ -60,10 +68,9 @@ if(BUILD_TESTS)
add_subdirectory(tests)
endif()
if(BUILD_CONFIG)
install(FILES ${CMAKE_SOURCE_DIR}/doc/config.ini
DESTINATION /etc/${PROJECT_NAME}
DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/${PROJECT_NAME}
COMPONENT config)
endif()

View File

@ -53,7 +53,8 @@ PR being rejected because the feature you implemented was not actually something
we want in polybar.
Issues with any of the following labels are generally safe to start working on,
unless someone else has already claimed them:
unless they also have the `needs confirmation` label or someone else has
already claimed them:
* [bug](https://github.com/polybar/polybar/labels/bug)
* [confirmed](https://github.com/polybar/polybar/labels/confirmed)
@ -98,8 +99,9 @@ If possible, you should also add tests for the things you write.
However, this is not always possible, for example when working on modules.
But at least isolated components should be tested.
See the [testing page](https://github.com/polybar/polybar/wiki/Testing) on the
wiki for more information.
See the [testing
page](https://polybar.readthedocs.io/en/latest/dev/testing.html) in the
documentation.
Also don't hesitate to ask for help, testing isn't that mature in polybar yet
and some things may be harder/impossible to test right now.
@ -153,7 +155,8 @@ repo.
### Style
Please read our [style guide](https://github.com/polybar/polybar/wiki/Style-Guide).
Please read our [style
guide](https://polybar.readthedocs.io/en/latest/dev/style-guide.html).
## Donations

View File

@ -1,5 +1,6 @@
<p align="center">
<img src="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,19 @@ 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`.
If you are using **Void Linux**, you can install [polybar](https://github.com/void-linux/void-packages/blob/master/srcpkgs/polybar/template) using `xbps-install -S polybar`.
@ -110,16 +116,13 @@ 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`.
The package is available for openSUSE Leap 15.3 and above.
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.
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.
If you are using **FreeBSD**, [polybar](https://www.freshports.org/x11/polybar) can be installed using `pkg install polybar`. Make sure you are using the `latest` package branch.
If you are using **Gentoo**, both release and git-master versions are available in the [main](https://packages.gentoo.org/packages/x11-misc/polybar) repository.
@ -133,19 +136,23 @@ If you can't find your distro here, you will have to [build from source](https:/
## Community
Want to get in touch?
* Join our Gitter room at [gitter.im/polybar/polybar](https://gitter.im/polybar/polybar)
* We have our own subreddit at [r/polybar](https://www.reddit.com/r/polybar).
* Chat with us in the `#polybar` IRC channel on the [`irc.libera.chat:6697`](https://libera.chat/) server.
* Visit our [Discussion page](https://github.com/polybar/polybar/discussions)
* Join our Gitter room at [`gitter.im/polybar/polybar`](https://gitter.im/polybar/polybar)
* We have our own subreddit at [`r/polybar`](https://www.reddit.com/r/polybar)
* Chat with us in the `#polybar` IRC channel on the [`irc.libera.chat:6697`](https://libera.chat/) server
## Contributors
### Maintainers
* Patrick Ziegler [**@patrick96**](https://github.com/patrick96)
### Owner
* Michael Carlberg [**@jaagr**](https://github.com/jaagr/)
### Maintainers
### Former Maintainers
* [**@Lomadriel**](https://github.com/Lomadriel)
* [**@NBonaparte**](https://github.com/NBonaparte)
* Chase Geigle [**@skystrife**](https://github.com/skystrife)
* Patrick Ziegler [**@patrick96**](https://github.com/patrick96)
### Logo Design by
* [**@Tobaloidee**](https://github.com/Tobaloidee)
@ -227,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`

View File

@ -1,14 +1,34 @@
Getting Help
============
# Getting Help
If you need help or troubleshooting tips or just have a question:
* If applicable, go through our [debugging guide](https://github.com/polybar/polybar/wiki/Debugging-your-Config).
* Read the [Known Issues page](https://github.com/polybar/polybar/wiki/Known-Issues), maybe others had the same issue before.
* Read the [Wiki page](https://github.com/polybar/polybar/wiki) for the thing you have problems with.
* Join our Gitter room at [gitter.im/polybar/polybar](https://gitter.im/polybar/polybar)
* Ask in our reddit community at [r/polybar](https://www.reddit.com/r/polybar)
* Join the official IRC channel `#polybar` on the [`irc.libera.chat:6697`](https://libera.chat/) network. If you don't get an answer try asking on [Gitter](https://gitter.im/polybar/polybar).
* Ask your question on [GitHub Discussions](https://github.com/polybar/polybar/discussions)
* Join our Gitter room at [`gitter.im/polybar/polybar`](https://gitter.im/polybar/polybar)
* Ask in our reddit community at [`r/polybar`](https://www.reddit.com/r/polybar)
* Join the official IRC channel `#polybar` on the [`irc.libera.chat:6697`](https://libera.chat/) network. This is IRC, you will need to be connected to receive answers.
* Ask on [Unix & Linux StackExchange](https://unix.stackexchange.com/). Though not all questions may be suited over there, make sure you're [on topic](https://unix.stackexchange.com/help/on-topic).
Please **do not** use the github issue tracker to ask for help or if you have a question, it is meant for bug reports and feature requests. Issues will be closed and you will be referred to the above resources.
**Do not** use the GitHub issue tracker to ask for help or if you have questions, it is meant for bug reports.
Issues will be closed and you will be referred to the above resources.
## Asking Quality Questions
Spending some time to precisely frame your question will save a lot of time.
You will better understand your problem and may be able to solve it yourself
and other will be able to better understand what you are asking.
Here are some tips:
* Be explicit and precise:
* What are you trying to achieve?
* What problems have you encountered while trying to achieve this?
* What is stopping you from overcoming these problems?
* If a problem is difficult to describe, screenshots can help. Do not make
screenshots of your config file or error messages, copy-paste them as text.
* Provide as much context as possible. In most cases this includes at least the following:
* Window Manager
* Polybar version
* Relevant portions of your config file. If you are not sure what is relevant, provide the whole thing.
* How you start polybar

View File

@ -20,3 +20,5 @@ set(SETTING_PATH_MESSAGING_FIFO "/tmp/polybar_mqueue.%pid%"
CACHE STRING "Path to file containing the current temperature")
set(SETTING_PATH_TEMPERATURE_INFO "/sys/class/thermal/thermal_zone%zone%/temp"
CACHE STRING "Path to file containing the current temperature")
set(SETTING_PATH_THERMAL_ZONE_WILDCARD "/sys/class/thermal/thermal_zone*"
CACHE STRING "Wildcard path to different thermal zones")

View File

@ -17,13 +17,23 @@ add_custom_target(uninstall
# folders where the clang tools should operate
set(CLANG_SEARCH_PATHS ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/tests)
# Target: codeformat (clang-format) {{{
# Runs clang-format on all source files
add_custom_target(
clangformat
COMMAND ${PROJECT_SOURCE_DIR}/common/file-runner.py
--dirs ${CLANG_SEARCH_PATHS}
-- clang-format -style=file -i --verbose
)
add_custom_target(codeformat)
add_custom_command(TARGET codeformat
COMMAND ${PROJECT_SOURCE_DIR}/common/clang-format.sh ${CLANG_SEARCH_PATHS})
# Dry-runs clang-format on all source files
# Useful for CI since it will exit with an error code
add_custom_target(
clangformat-dryrun
COMMAND ${PROJECT_SOURCE_DIR}/common/file-runner.py
--dirs ${CLANG_SEARCH_PATHS}
-- clang-format -style=file --dry-run -Werror --verbose
)
# }}}
# Target: codecheck (clang-tidy) {{{
add_custom_target(codecheck)

View File

@ -18,6 +18,7 @@ message_colored(STATUS " BINDIR: ${CMAKE_INSTALL_FULL_BINDIR}" "32")
message_colored(STATUS " DATADIR: ${CMAKE_INSTALL_FULL_DATADIR}" "32")
message_colored(STATUS " DOCDIR: ${CMAKE_INSTALL_FULL_DOCDIR}" "32")
message_colored(STATUS " MANDIR: ${CMAKE_INSTALL_FULL_MANDIR}" "32")
message_colored(STATUS " SYSCONFDIR: ${CMAKE_INSTALL_FULL_SYSCONFDIR}" "32")
message(STATUS " Targets:")
colored_option(" polybar" BUILD_POLYBAR)

View File

@ -15,20 +15,19 @@ endif()
option(CXXLIB_CLANG "Link against libc++" OFF)
option(CXXLIB_GCC "Link against stdlibc++" OFF)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(THREADS_PREFER_PTHREAD_FLAG ON)
set(POLYBAR_FLAGS "" CACHE STRING "C++ compiler flags used for compiling polybar")
list(APPEND cxx_base -Wall -Wextra -Wpedantic)
list(APPEND cxx_debug -DDEBUG -g2)
list(APPEND cxx_base -Wall -Wextra -Wpedantic -Wdeprecated-copy-dtor)
list(APPEND cxx_debug -DDEBUG -g2 -Og)
list(APPEND cxx_minsizerel "")
list(APPEND cxx_sanitize -O0 -g -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer -fno-optimize-sibling-calls)
list(APPEND cxx_coverage --coverage)
list(APPEND cxx_sanitize ${cxx_debug} -O0 -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer -fno-optimize-sibling-calls)
list(APPEND cxx_coverage ${cxx_debug} --coverage)
list(APPEND cxx_linker_base "")
list(APPEND cxx_linker_minsizerel "")
@ -79,8 +78,6 @@ elseif(CXXLIB_GCC)
list(APPEND cxx_linker_base -lstdc++)
endif()
# Custom build type 'Coverage', inherits the debug flags
list(APPEND cxx_coverage ${cxx_debug} ${cxx_coverage})
SET(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_DEBUG} ${CMAKE_CXX_FLAGS_COVERAGE}")
SET(CMAKE_EXE_LINKER_FLAGS_COVERAGE "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${CMAKE_EXE_LINKER_FLAGS_COVERAGE}")
SET(CMAKE_SHARED_LINKER_FLAGS_COVERAGE "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} ${CMAKE_SHARED_LINKER_FLAGS_COVERAGE}")

View File

@ -1,20 +0,0 @@
#!/bin/sh
main() {
if [ $# -lt 1 ]; then
echo "$0 DIR..." 1>&2
exit 1
fi
# Search paths
search="${*:-.}"
echo "$0 in $search"
# shellcheck disable=2086
find $search -regex ".*.[c|h]pp" \
-exec printf "\\033[32;1m** \\033[0mFormatting %s\\n" {} \; \
-exec clang-format -style=file -i {} \;
}
main "$@"

50
common/file-runner.py Executable file
View File

@ -0,0 +1,50 @@
#!/usr/bin/env python3
from pathlib import Path
import sys
import os
import argparse
import subprocess
EXTENSIONS = set('.' + ext for ext in ['c', 'h', 'cpp', 'hpp', 'inl'])
def get_files(dirs):
"""
Generator which yields all files in the given directories with any of the
EXTENSIONS.
"""
for dir in dirs:
for root, _, files in os.walk(dir):
for file in files:
path = Path(os.path.join(root, file))
if path.suffix in EXTENSIONS:
yield path
def main():
parser = argparse.ArgumentParser(
description="""
Run command on all C/C++ source files in the given directories
""")
parser.add_argument('--dirs', type=Path, nargs='+',
help='Directories to search in')
parser.add_argument('command', nargs='+',
help='Command to which to pass found files')
args = parser.parse_args()
all_files = list(str(file) for file in get_files(args.dirs))
if not all_files:
print("No files found")
sys.exit(1)
result = subprocess.run(args.command + all_files)
print(f'Formatted {len(all_files)} files')
if result.returncode != 0:
sys.exit(result.returncode)
if __name__ == '__main__':
main()

View File

@ -1,24 +1,22 @@
# Maintainer: Patrick Ziegler <p.ziegler96@gmail.com>
_pkgname=polybar
pkgname="${_pkgname}-git"
pkgver=3.5.7
pkgver=3.6.3
pkgrel=1
pkgdesc="A fast and easy-to-use status bar"
arch=("i686" "x86_64")
# 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"
"ttf-unifont: Font used in example config"
"siji-git: Font used in example config"
"xorg-fonts-misc: Font used in example config")
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")
install="${_pkgname}.install"
source=("${_pkgname}::git+${url}.git")
sha256sums=("SKIP")

View File

@ -1,36 +0,0 @@
# Maintainer: Patrick Ziegler <p.ziegler96@gmail.com>
pkgname=polybar
pkgver=3.5.7
pkgrel=1
pkgdesc="A fast and easy-to-use status bar"
arch=("i686" "x86_64")
url="https://github.com/polybar/polybar"
license=("MIT")
depends=("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"
"ttf-unifont: Font used in example config"
"siji-git: Font used in example config"
"xorg-fonts-misc: Font used in example config")
makedepends=("cmake" "python" "pkg-config" "python-sphinx" "python-packaging" "i3-wm")
conflicts=("polybar-git")
install="${pkgname}.install"
source=(${url}/releases/download/${pkgver}/${pkgname}-${pkgver}.tar.gz)
sha256sums=('73210e6d74217acb953b253990b4302343b7b6a7870fe1da9a1855daa44123db')
_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

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

BIN
doc/_static/nerd-fonts/bad.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

BIN
doc/_static/nerd-fonts/good.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

26
doc/_templates/layout.html vendored Normal file
View File

@ -0,0 +1,26 @@
{% extends "!layout.html" -%}
{# Refer to https://github.com/readthedocs/sphinx_rtd_theme/blob/master/sphinx_rtd_theme/layout.html #}
{%- block document %}
{#
Adds a warning message on the 'latest' version.
The warning is only added on readthedocs, if the version is 'latest'.
For the 'dev' folder, no warning is shown since the 'latest' version is
usually the most up-to-date.
#}
{% if READTHEDOCS and polybar_is_latest and not pagename.startswith('dev/') %}
<div class="admonition important">
<p class="admonition-title">Development Version</p>
<p>
This is the <code class="docutils literal notranslate"><span class="pre">latest</span></code>
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of polybar.
</p>
<p>
See the <a href="https://polybar.readthedocs.io/{{ pagename }}.html">stable version</a> of this documentation page instead.
</p>
</div>
{% endif %}
{{ super() }}
{%- endblock %}

View File

@ -18,6 +18,10 @@ import datetime
import sphinx
import packaging.version
from sphinx.util.docfields import Field
from sphinx.locale import _
def get_version(root_path):
"""
Reads the polybar version from the version.txt at the root of the repo.
@ -32,8 +36,12 @@ def get_version(root_path):
raise RuntimeError("No version found in {}".format(path))
sphinx_version = packaging.version.parse(sphinx.__version__)
# -- Project information -----------------------------------------------------
project = 'Polybar User Manual'
copyright = '2016-{}, Michael Carlberg & contributors'.format(
datetime.datetime.now().year
@ -77,6 +85,16 @@ version_txt = get_version(Path(doc_path).absolute().parent)
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
"sphinx.ext.extlinks",
]
if on_rtd:
extensions += [
# The custom 404 page is only needed
"notfound.extension",
# The search extension works only on readthedocs
# See https://readthedocs-sphinx-search.readthedocs.io
"sphinx_search.extension",
]
# Add any paths that contain templates here, relative to this directory.
@ -96,7 +114,7 @@ master_doc = 'index'
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
@ -110,22 +128,45 @@ highlight_language = 'none'
smartquotes = False
# Quickly link to issues or PRs using :issue:`...` or :pull:`...`
if sphinx_version >= packaging.version.parse("4.0.0"):
extlinks = {
"issue": ("https://github.com/polybar/polybar/issues/%s", "#%s"),
"pull": ("https://github.com/polybar/polybar/pull/%s", "PR #%s"),
}
else:
# Versions before 4.0 (e.g. on readthedocs) do not support %s in the
# caption and simply append the value
extlinks = {
"issue": ("https://github.com/polybar/polybar/issues/%s", "#"),
"pull": ("https://github.com/polybar/polybar/pull/%s", "PR #"),
}
extlinks_detect_hardcoded_links = True
# -- Options for HTML output -------------------------------------------------
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
html_theme_options = {}
html_context = {
'polybar_is_latest': version == 'latest',
}
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
if on_rtd or os.environ.get('USE_RTD_THEME', '0') == '1':
html_theme = 'sphinx_rtd_theme'
html_theme_options['collapse_navigation'] = False
html_theme_options['style_external_links'] = True
else:
html_theme = 'alabaster'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
html_theme_options['description'] = version
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
@ -183,9 +224,18 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('man/polybar.1', 'polybar', 'A fast and easy-to-use tool status bar', [], 1),
('man/polybar-msg.1', 'polybar-msg', 'Send IPC messages to polybar', [], 1),
('man/polybar.5', 'polybar', 'configuration file for polybar(1)', [], 5)
(
'man/polybar.1', 'polybar',
'A fast and easy-to-use tool status bar', [], 1
),
(
'man/polybar-msg.1', 'polybar-msg',
'Send IPC messages to polybar', [], 1
),
(
'man/polybar.5', 'polybar',
'configuration file for polybar(1)', [], 5
)
]
man_make_section_directory = False
@ -223,19 +273,66 @@ epub_exclude_files = ['search.html']
# The 'versionadded' and 'versionchanged' directives are overridden.
suppress_warnings = ['app.add_directive']
def setup(app):
# Adds a new directive for document a polybar config setting
# Inside goes the description of the option as well as custom roles to
# document the type, default value, etc:
# .. poly-setting:: NAME
#
# Description
# :type: ...
# :default: ...
app.add_object_type(
'poly-setting',
'poly-setting',
objname='configuration value',
indextemplate='pair: %s; configuration value',
doc_field_types=[
Field('type',
label=_("Type"),
names=['type'],
has_arg=False,
),
Field('tags',
label=_("Available Tags"),
names=['tags'],
has_arg=False,
),
Field('tokens',
label=_("Supported Tokens"),
names=['tokens'],
has_arg=False,
),
Field('default',
label=_("Default Value"),
names=['default'],
has_arg=False,
),
]
)
try:
inject_version_directives(app)
except NameError:
# Function was not defined because sphinx version was too low
pass
# It is not exactly clear in which version the VersionChange class was
# introduced, but we know it is available in at least 1.8.5.
# This feature is mainly needed for the online docs on readthedocs for the docs
# built from master, documentation built for proper releases should not even
# mention unreleased changes. Because of that it's not that important that this
# is added to local builds.
if packaging.version.parse(sphinx.__version__) >= packaging.version.parse("1.8.5"):
if sphinx_version >= packaging.version.parse("1.8.5"):
from typing import List
from docutils.nodes import Node
from sphinx.domains.changeset import VersionChange
def setup(app):
def inject_version_directives(app):
app.add_directive('deprecated', VersionDirective)
app.add_directive('versionadded', VersionDirective)
app.add_directive('versionchanged', VersionDirective)
@ -243,8 +340,10 @@ if packaging.version.parse(sphinx.__version__) >= packaging.version.parse("1.8.5
class VersionDirective(VersionChange):
"""
Overwrites the Sphinx directive for versionchanged, versionadded, and
deprecated and adds an unreleased tag to versions that are not yet released
deprecated and adds an unreleased tag to versions that are not yet
released
"""
def run(self) -> List[Node]:
directive_version = packaging.version.parse(self.arguments[0])
parsed_version_txt = packaging.version.parse(version_txt)

View File

@ -58,14 +58,18 @@ cursor-scroll = ns-resize
enable-ipc = true
; tray-position = right
; wm-restack = generic
; wm-restack = bspwm
; wm-restack = i3
; override-redirect = true
[module/systray]
type = internal/tray
format-margin = 8pt
tray-spacing = 16pt
[module/xworkspaces]
type = internal/xworkspaces

View File

@ -0,0 +1,41 @@
Getting Started
===============
Setting up polybar for development is basically the same process as `compiling
it from source <https://github.com/polybar/polybar/wiki/Compiling>`_.
However, we recommend using the ``Debug`` or ``Sanitize`` cmake build type when
configuring the project:
.. code-block:: shell
cmake -DCMAKE_BUILD_TYPE=Debug ..
# Or
cmake -DCMAKE_BUILD_TYPE=Sanitize ..
This will give you debug symbols in the executable and the ``Sanitize`` build
type will also enable the ``AddressSanitizer`` and
``UndefinedBehaviorSanitizer``, which can give you very useful information
about crashes and undefined behavior at runtime.
Editors
-------
Since this is a cmake project, most IDEs will have built-in support or a plugin
to automatically setup this project.
In addition, the ``cmake`` command creates a ``compile_commands.json`` file in
the build folder, which can be used by many `language servers
<https://microsoft.github.io/language-server-protocol/>`_.
If you are using a C++ language server in your editor, it should be as easy as
symlinking the ``compile_commands.json`` into the repo root directory:
.. code-block:: shell
ln -s build/compile_commands.json .
Distro-Specific Setup
---------------------
The wiki contains user-contributed `setup tips
<https://github.com/polybar/polybar/wiki/Distro-Specific-Setup>`_ for some
distros.

View File

@ -78,9 +78,8 @@ Instead of ``sudo make install``, you will most likely want to use
Finishing Up
------------
Finally, subscribe to our `GitHub thread for package maintainers
<https://github.com/polybar/polybar/issues/1971>`_ to get notified about new
releases and changes to how polybar is built.
Finally, subscribe to our :issue:`GitHub thread for package maintainers <1971>`
to get notified about new releases and changes to how polybar is built.
If you want to, you can also open a PR to add your package to the `Getting
Started <https://github.com/polybar/polybar#getting-started>`_ section of our
README.

View File

@ -90,8 +90,8 @@ branch and cherry-picks the bugfix commits.
Alternatively, the contributor can also ``git rebase --onto`` to base the
branch off the previous release tag. However, in most cases it makes sense for
a maintainer to create the release branch since they will also need to add a
`Release Commit`_ to it.
a maintainer to create the release branch since they will also need to create
a `Release PR`_ for it.
Once the release branch is created and contains the right commits, the
maintainer should follow `Publishing a new Release`_ to finish this patch
@ -110,13 +110,19 @@ Publishing a new Release
The process for publishing a release is the same for all release types. It goes
as follows:
* A `Release commit`_ is added to the tip of the release branch.
* A draft PR is opened for the release branch. This PR MUST NOT be merged in
* A `Release PR`_ is created for the release. 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 without message is created locally at the
tip of the release branch and pushed:
.. code-block:: shell
git tag -m "" -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
@ -136,16 +142,23 @@ as follows:
Here ``<release-branch>`` is either a ``release/X.Y.0`` branch or a
``hotfix/X.Y.Z`` branch.
Release Commit
~~~~~~~~~~~~~~
Release PR
~~~~~~~~~~
When merging, a release commit must be at the tip of the release branch.
The final state of the release branch is prepared as a draft PR on
GitHub.
That PR is not merged from the GitHub interface though.
The release commit needs to update the version number in:
The release PR must do the following things:
* ``version.txt``
* Write any missing migration guides for:
The release commit must also finalize the `Changelog`_ for this release.
* Deprecated or removed options
* New features that it might be worth migrating to
* Have a release commit at its tip with the message ``Version X.Y.Z`` and the following changes
* Finalizes the `Changelog`_ for this release
* Updates the version number in ``version.txt``
Changelog
~~~~~~~~~
@ -193,8 +206,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``.
@ -202,23 +215,30 @@ In addition using GitHub's "Auto-generate release notes" feature, the list of
new contributors should be generated and put at the end of the release notes.
The generated list of PRs can be removed.
For minor and major releases, add a link to the migration guide directly under
the ``## Changelog`` header:
.. code-block:: markdown
**[Migration Guide](https://polybar.readthedocs.io/en/stable/migration/X.Y/index.html)**
At the bottom, check the two boxes "Set as the latest release" and "Create a
discussion for this release" (select the category "Announcements").
After-Release Checklist
~~~~~~~~~~~~~~~~~~~~~~~
* Make sure all the new functionality is documented on the wiki
* Verify the release archive (see `Verify Release`_)
* Update the Wiki
* Make sure all the new functionality is documented
* Mark deprecated features appropriately (see `Deprecations`_)
* Remove all unreleased notes from the wiki (not for patch releases)
* Inform packagers of new release in `#1971
<https://github.com/polybar/polybar/issues/1971>`_. Mention any dependency
* Remove all "unreleased" notes (not for patch releases)
* Inform packagers of new release in :issue:`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 +246,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
~~~~~~~~~~~~

75
doc/dev/style-guide.rst Normal file
View File

@ -0,0 +1,75 @@
Style Guide
===========
There is a ``.editorconfig`` and a ``.clang-format`` file in the project root
that defines some basic guidelines, mainly relating to indentation.
Code Formatting
---------------
We use ``clang-format`` for code formatting, the style rules are defined in
``.clang-format``, before submitting a PR, make sure to run the following command
on all the C++ files you changed:
.. code-block:: shell
clang-format -style=file -i <FILES>
**Note:** Depending on which file you change, this may produce a lot of changes
because we have not run ``clang-format`` on all files in the project. This is
fine.
Indentation
~~~~~~~~~~~
Files use 2 spaces for indentation.
Line Width
~~~~~~~~~~
Lines should not be longer than 120 characters, ``clang-format`` will enforce
this when run. However, try to keep lines under 80 characters if it seems
reasonable in the current situation.
In some cases it makes sense to have lines longer than 80 characters for
readability. But long lines can just the same be unreadable, for example if you
have long if-conditions or use complex expressions as function parameters. Make
sure you only use longer lines if keeping it under 80 would be less readable.
Comments
--------
Use Doxygen ``/** */`` comments in front of functions, methods, types, members and
classes:
.. code-block:: cpp
/**
* @brief Generates a config object from a config file
*
* For modularity the parsing and storing of the config is separated
*/
class config_parser {
...
/**
* @brief Is used to resolve ${root...} references
*/
string m_barname;
...
}
For all other comments use ``//`` for single-line and ``/* */`` for multi-line comments.
Your comments should describe the intent and purpose of your code, not necessarily what it does.
Header Files
------------
Header files should end in ``.hpp``.
We use pragmas instead of include guards to guarantee header files are included
only once:
.. code-block:: cpp
#pragma once

26
doc/dev/testing.rst Normal file
View File

@ -0,0 +1,26 @@
Testing
=======
Polybar uses `googletest <https://google.github.io/googletest/>`_ as its
testing and mocking framework.
Tests live in the ``tests/`` directory; they can be enabled during cmake with
``-DBUILD_TESTS=ON`` and compiled with ``make all_unit_tests``.
Each test gets its own executable in ``build/tests``, which can be executed to run
a specific test.
Running all tests is preferably done with the following command:
.. code-block:: shell
make check
This runs all available tests and prints the output in color for failed tests
only.
Adding New Tests
----------------
All new tests need to be added to the ``tests/CMakeLists.txt`` file. Have a look
at the other unit tests in ``tests/unit_tests`` to see how to write tests for your
code.

View File

@ -14,6 +14,10 @@ Welcome to the official polybar documentation.
user/actions
user/ipc
user/modules/index
user/fonts/index
user/default-config
migration/index
.. toctree::
:maxdepth: 1
@ -33,6 +37,9 @@ Welcome to the official polybar documentation.
:maxdepth: 1
:caption: Developer Documentation:
dev/getting-started
dev/style-guide
dev/testing
dev/release-workflow
Getting Help

View File

@ -0,0 +1,40 @@
Migrating From Version 3.6 to 3.7
=================================
Text Module (``custom/text``)
-----------------------------
Using ``content`` to specify the text of the module is deprecated in favor of
using the same concepts as all other modules (formats and labels).
For example, the following text module:
.. code-block:: dosini
[module/text]
type = custom/text
content = Hello World
content-foreground = #ff0000
Should now look like this:
.. code-block:: dosini
[module/text]
type = custom/text
label = Hello World
label-foreground = #ff0000
Because it is set to its default value, the ``format`` setting can also be
completely left out.
In general, all properties on ``content`` also apply the same on ``label``
(e.g. ``background``, ``font``), except for ``offset``,
``prefix``, ``suffix`` (and their sub-properties).
Those three properties have to instead be applied to ``format`` (e.g.
``format-offset``).
System Tray
-----------
.. include:: tray.rst

View File

@ -0,0 +1,57 @@
..
File included directly in other pages describing migrating to the new tray module
Polybar version 3.7 introduced the new tray module and deprecated the legacy
tray implementation which uses ``tray-position`` to position the tray.
You should switch over to the tray module as soon as possible.
The legacy tray was configured in the `bar section
<https://github.com/polybar/polybar/wiki/Configuration#bar-settings>`_, the
setting for the module live in that module's section of the config file.
The settings in the bar section don't always directly correspond to an
equivalent setting in the module section for the new tray module.
The following lists how each old setting in the bar section should be migrated:
``tray-position``
The tray is now positioned as a module and so its positioning is done by
placing it where you want it to appear in one of the three module lists
``modules-left``, ``modules-center``, ``modules-right``.
``tray-detached``
This setting does not have an equivalent, detaching the tray is no longer
possible.
``tray-maxsize``
The :poly-setting:`tray-size` setting now determines the size of tray icons.
``tray-transparent``
Was already deprecated and does not exist in the tray module.
Transparency is enabled automatically if a transparent background is used.
``tray-background``
Also exists in the module section (see :poly-setting:`tray-background`). Now,
the setting only applies to the icons themselves and no longer to the space
around them.
``tray-foreground``
Also exists in the module section with the same functionality (see
:poly-setting:`tray-foreground`).
``tray-offset-x``, ``tray-offset-y``
Has no direct equivalent in the module settings. Horizontally, the tray can
be moved in the same way other module content can be moved; by reordering the
modules or using things like ``format-offset``, ``format-margin``, or
``format-padding``.
The tray can't be moved vertically.
In any case, the tray can no longer be moved outside of the bar window.
``tray-padding``
Spacing between tray icons works a bit different now and needs to be
completely reconfigured (see :poly-setting:`tray-padding` and
:poly-setting:`tray-spacing`).
``tray-scale``
No longer exist. The size of the icons is solely determined by
:poly-setting:`tray-size`.

24
doc/migration/index.rst Normal file
View File

@ -0,0 +1,24 @@
Polybar Migration Guides
========================
Updating polybar to the newest version often requires updating your
configuration files to use the newest features and replace outdated settings.
Starting from version 3.7, we include a small guide here for how to migrate
from the previous version.
If you are upgrading over multiple versions (e.g. from 3.5 to 3.7), also read
the migration guides for all versions in between.
For migration guides before version 3.7, please look at our `release blog posts
<https://polybar.github.io/blog/>`_.
When upgrading make sure to run polybar from the terminal and look for errors,
warnings, and deprecation messages.
This can save you a lot of issues in the future when deprecated settings and
features are removed.
.. toctree::
:maxdepth: 1
:caption: Guides
3.7/index

7
doc/requirements.txt Normal file
View File

@ -0,0 +1,7 @@
# Installing these packages is only really needed on readthedocs, building
# locally works as long as sphinx is installed.
# For local development, you may want to install some of these though.
sphinx~=7.2.6
sphinx-rtd-theme~=2.0.0rc2
sphinx-notfound-page~=1.0.0
readthedocs-sphinx-search~=0.3.1

View File

@ -0,0 +1,16 @@
Default Configuration
=====================
.. versionadded:: 3.6.0
Polybar's default configuration lives in ``/etc/polybar/config.ini`` and is
loaded if no other configuration file can be found.
.. image:: ../_static/default.png
:alt: Screenshot of default polybar configuration
.. literalinclude:: ../config.ini
:language: ini
:linenos:
:caption: :download:`Download <../config.ini>`

8
doc/user/fonts/index.rst Normal file
View File

@ -0,0 +1,8 @@
Fonts
=====
.. toctree::
:maxdepth: 1
Wiki <https://github.com/polybar/polybar/wiki/Fonts>
Nerd Fonts <nerd-fonts>

View File

@ -0,0 +1,54 @@
Nerd Fonts
==========
`Nerd Fonts <https://www.nerdfonts.com/>`_ (`GitHub
<https://github.com/ryanoasis/nerd-fonts/>`_) is a project that patches
together a textual font with font icons (or glyphs) from other projects (e.g.
`Font Awesome <https://github.com/FortAwesome/Font-Awesome>`_, `Material Design
Icons <https://github.com/Templarian/MaterialDesign>`_, etc.) into a single
font.
In polybar, just using nerd fonts can lead to some issues:
* Cut-off Characters
* Overlapping
* No Spacing
These look something like this:
.. image:: /_static/nerd-fonts/bad.png
:alt: Showcase of the three issues listed above.
This behavior is intrinsic to Nerd Fonts and is described in more detail `here
<https://github.com/ryanoasis/nerd-fonts/issues/442#issuecomment-1263358904>`_.
Also see :issue:`991` for more information.
**To resolve these issues, we recommend using Nerd Fonts like this:**
The monospaced variants of the different Nerd Fonts (all characters have the
same width) don't have this issue.
However, then you often have the problem that the icons are too small and that
their size cannot be set independently of the text.
Due to that, we recommend using ``Symbols Nerd Font Mono`` (available for
`download <https://github.com/ryanoasis/nerd-fonts/releases/>`_ as
``NerdFontsSymbolsOnly.zip``).
This font only contains the nerd font icons and no text.
For the text, simply use any non-Nerd Font:
.. code-block:: ini
font-0 = "Liberation Mono:size=20"
font-1 = "Symbols Nerd Font Mono:size=26"
Now the icon sizes can be adjusted separately to get the best experience.
This solves all three problems shown above:
.. image:: /_static/nerd-fonts/good.png
:alt: The same config as in the previous screenshot but using ``Symbols Nerd
Font Mono`` for the font icons
.. note::
In the overlap example, there is no space between the icon and text, that's
why they're so close together.

13
doc/user/modules/defs.rst Normal file
View File

@ -0,0 +1,13 @@
.. highlight:: ini
..
Substitutions for quickly referencing different config value types
.. |type-format| replace:: `format <type-format_>`_
.. |type-extent| replace:: `extent <type-extent_>`_
.. |type-pwo| replace:: `percentage with offset <type-pwo_>`_
.. |type-color| replace:: color
.. _type-format: https://github.com/polybar/polybar/wiki/Formatting#formats
.. _type-extent: https://github.com/polybar/polybar/wiki/Formatting#extent
.. _type-pwo: https://github.com/polybar/polybar/wiki/Formatting#percentage-with-offset

View File

@ -0,0 +1,31 @@
Modules
=======
.. toctree::
:maxdepth: 1
System Tray <tray>
Alsa <https://github.com/polybar/polybar/wiki/Module:-alsa>
Backlight <https://github.com/polybar/polybar/wiki/Module:-backlight>
Battery <https://github.com/polybar/polybar/wiki/Module:-battery>
bspwm <https://github.com/polybar/polybar/wiki/Module:-bspwm>
CPU <https://github.com/polybar/polybar/wiki/Module:-cpu>
Date and Time <https://github.com/polybar/polybar/wiki/Module:-date>
Filesystem <https://github.com/polybar/polybar/wiki/Module:-filesystem>
GitHub <https://github.com/polybar/polybar/wiki/Module:-github>
i3 <https://github.com/polybar/polybar/wiki/Module:-i3>
Inter-process-messaging (IPC) <https://github.com/polybar/polybar/wiki/Module:-ipc>
Memory <https://github.com/polybar/polybar/wiki/Module:-memory>
Menu <https://github.com/polybar/polybar/wiki/Module:-menu>
MPD <https://github.com/polybar/polybar/wiki/Module:-mpd>
Network <https://github.com/polybar/polybar/wiki/Module:-network>
PulseAudio <https://github.com/polybar/polybar/wiki/Module:-pulseaudio>
Script <https://github.com/polybar/polybar/wiki/Module:-script>
Temperature <https://github.com/polybar/polybar/wiki/Module:-temperature>
Text <https://github.com/polybar/polybar/wiki/Module:-text>
XBacklight <https://github.com/polybar/polybar/wiki/Module:-xbacklight>
XKeyboard <https://github.com/polybar/polybar/wiki/Module:-xkeyboard>
XWindow <https://github.com/polybar/polybar/wiki/Module:-xwindow>
XWorkspaces <https://github.com/polybar/polybar/wiki/Module:-xworkspaces>
User contributed modules <https://github.com/polybar/polybar/wiki/User-contributed-modules>

116
doc/user/modules/tray.rst Normal file
View File

@ -0,0 +1,116 @@
.. include:: defs.rst
Tray Module
===========
.. poly-setting:: type = internal/tray
.. versionadded:: 3.7.0
The tray module displays system tray application icons on the bar.
This module is a bit different from the other modules.
The tray icons (also called clients) are individual windows managed by their
respective application (e.g. the Dropbox tray icon is created and managed by
the Dropbox application).
Polybar is only responsible for embedding the windows in the bar and
positioning them correctly.
.. note::
Only a single instance of this module can be active at the same time (across
all polybar instances).
The way the `system tray protocol <systray-spec_>`_ works, at most one tray
can exist at any time.
Polybar will produce a warning if additional tray instances are created.
For transparent background colors, the tray will use pseudo-transparency, true
transparency is not possible for the tray icons.
Formats
-------
The module only has a single format:
.. poly-setting:: format
:type: |type-format|
:tags: ``<tray>``: Shows tray icons
:default: ``<tray>``
Settings
--------
.. poly-setting:: tray-spacing
Space added between tray icons
:type: |type-extent|, non-negative
:default: ``0px``
.. poly-setting:: tray-padding
Space added before and after each tray icon
:type: |type-extent|, non-negative
:default: ``0px``
.. poly-setting:: tray-size
Size of individual tray icons
:type: |type-pwo|, relative to bar height, non-negative
:default: 66%
.. poly-setting:: tray-background
Background color of tray icons
.. note::
This only affects the color of the individual icons and not the space in
between, changing this setting to anything else than the bar background
will likely not look good unless the background color is also changed for
the rest of the tray module (e.g. with ``format-background``).
:type: |type-color|
:default: ``${root.background}``
.. poly-setting:: tray-foreground
Tray icon color
This serves as a hint to the tray icon application for which color to use for
the icon.
This is not guaranteed to have any effect (likely only in GTK3) because it
targets a non-standard part of the `system tray protocol <systray-spec_>`_ by
setting the ``_NET_SYSTEM_TRAY_COLORS`` atom on the tray window.
:type: |type-color|
:default: ``${tray-foreground}``
Example
-------
::
[module/tray]
type = internal/tray
format-margin = 8px
tray-spacing = 8px
Migrating From Legacy Tray Implementation
-----------------------------------------
.. include:: /migration/3.7/tray.rst
References
----------
* `System Tray Protocol Specification <systray-spec_>`_
* `XEmbed Protocol Specification <xembed_>`_
.. _systray-spec: https://specifications.freedesktop.org/systemtray-spec/systemtray-spec-latest.html
.. _xembed: https://specifications.freedesktop.org/xembed-spec/xembed-spec-latest.html

View File

@ -1,46 +1,6 @@
#pragma once
#ifdef USE_ALSALIB_H
#include <alsa/asoundlib.h>
#else
#include <assert.h>
#ifndef __FreeBSD__
#include <endian.h>
#endif
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <poll.h>
#include <sys/types.h>
#include <unistd.h>
#ifndef __GNUC__
#define __inline__ inline
#endif
#include <alsa/asoundef.h>
#include <alsa/version.h>
#include <alsa/global.h>
#include <alsa/input.h>
#include <alsa/output.h>
#include <alsa/error.h>
#include <alsa/conf.h>
#include <alsa/pcm.h>
#include <alsa/rawmidi.h>
#include <alsa/timer.h>
#include <alsa/hwdep.h>
#include <alsa/control.h>
#include <alsa/mixer.h>
#include <alsa/seq_event.h>
#include <alsa/seq.h>
#include <alsa/seqmid.h>
#include <alsa/seq_midi_event.h>
#endif
#include "common.hpp"
#include "settings.hpp"

View File

@ -21,8 +21,8 @@ class script_runner {
using on_update = std::function<void(const data&)>;
using interval = std::chrono::duration<double>;
script_runner(on_update on_update, const string& exec, const string& exec_if, bool tail, interval interval,
const vector<pair<string, string>>& env);
script_runner(on_update on_update, const string& exec, const string& exec_if, bool tail, interval interval_success,
interval interval_fail, const vector<pair<string, string>>& env);
bool check_condition() const;
interval process();
@ -48,7 +48,8 @@ class script_runner {
const string m_exec;
const string m_exec_if;
const bool m_tail;
const interval m_interval;
const interval m_interval_success;
const interval m_interval_fail;
const vector<pair<string, string>> m_env;
data m_data;

View File

@ -5,6 +5,7 @@
#include <algorithm>
#include <cmath>
#include <deque>
#include <iomanip>
#include <iterator>
#include "cairo/font.hpp"
@ -163,9 +164,21 @@ namespace cairo {
std::iter_swap(fns.begin(), fns.begin() + t.font - 1);
}
string utf8 = string(t.contents);
utils::unicode_charlist chars;
utils::utf8_to_ucs4((const unsigned char*)utf8.c_str(), chars);
string utf8 = t.contents;
string_util::unicode_charlist chars;
bool valid = string_util::utf8_to_ucs4(utf8, chars);
// The conversion already removed any invalid chunks. We should probably log a warning though.
if (!valid) {
sstream hex;
hex << std::hex << std::setw(2) << std::setfill('0');
for(const char& c: utf8) {
hex << (static_cast<int>(c) & 0xff) << " ";
}
m_log.warn("Dropping invalid parts of UTF8 text '%s' %s", utf8, hex.to_string());
}
while (!chars.empty()) {
auto remaining = chars.size();
@ -196,6 +209,12 @@ namespace cairo {
cairo_text_extents_t extents;
f->textwidth(subset, &extents);
/*
* Make sure we don't advance partial pixels, this can cause problems
* later when cairo renders background colors over half-pixels.
*/
extents.x_advance = std::ceil(extents.x_advance);
// Draw the background
if (t.bg_rect.h != 0.0) {
save();
@ -228,9 +247,9 @@ namespace cairo {
continue;
}
char unicode[6]{'\0'};
utils::ucs4_to_utf8(unicode, chars.begin()->codepoint);
m_log.warn("Dropping unmatched character %s (U+%04x) in '%s'", unicode, chars.begin()->codepoint, t.contents);
std::array<char, 5> unicode{};
string_util::ucs4_to_utf8(unicode, chars.begin()->codepoint);
m_log.warn("Dropping unmatched character '%s' (U+%04x) in '%s'", unicode.data(), chars.begin()->codepoint, t.contents);
utf8.erase(chars.begin()->offset, chars.begin()->length);
for (auto&& c : chars) {
c.offset -= chars.begin()->length;

View File

@ -39,8 +39,8 @@ namespace cairo {
cairo_set_font_face(m_cairo, cairo_font_face_reference(m_font_face));
}
virtual size_t match(utils::unicode_character& character) = 0;
virtual size_t match(utils::unicode_charlist& charlist) = 0;
virtual size_t match(string_util::unicode_character& character) = 0;
virtual size_t match(string_util::unicode_charlist& charlist) = 0;
virtual size_t render(const string& text, double x = 0.0, double y = 0.0) = 0;
virtual void textwidth(const string& text, cairo_text_extents_t* extents) = 0;
@ -187,13 +187,13 @@ namespace cairo {
cairo_set_scaled_font(m_cairo, m_scaled);
}
size_t match(utils::unicode_character& character) override {
size_t match(string_util::unicode_character& character) override {
auto lock = make_unique<utils::ft_face_lock>(m_scaled);
auto face = static_cast<FT_Face>(*lock);
return FT_Get_Char_Index(face, character.codepoint) ? 1 : 0;
}
size_t match(utils::unicode_charlist& charlist) override {
size_t match(string_util::unicode_charlist& charlist) override {
auto lock = make_unique<utils::ft_face_lock>(m_scaled);
auto face = static_cast<FT_Face>(*lock);
size_t available_chars = 0;
@ -212,7 +212,8 @@ namespace cairo {
cairo_glyph_t* glyphs{nullptr};
cairo_text_cluster_t* clusters{nullptr};
cairo_text_cluster_flags_t cf{};
int nglyphs = 0, nclusters = 0;
int nglyphs = 0;
int nclusters = 0;
string utf8 = string(text);
auto status = cairo_scaled_font_text_to_glyphs(
@ -307,7 +308,7 @@ namespace cairo {
throw application_error("Could not load FreeType");
}
static auto fc_cleanup = scope_util::make_exit_handler([] {
static scope_util::on_exit fc_cleanup([] {
FT_Done_FreeType(g_ftlib);
FcFini();
});

View File

@ -1,7 +1,6 @@
#pragma once
#include <cairo/cairo-ft.h>
#include <list>
#include "common.hpp"
@ -38,33 +37,11 @@ namespace cairo {
FT_Face m_face;
};
/**
* @brief Unicode character containing converted codepoint
* and details on where its position in the source string
*/
struct unicode_character {
explicit unicode_character();
unsigned long codepoint;
int offset;
int length;
};
using unicode_charlist = std::list<unicode_character>;
/**
* @see <cairo/cairo.h>
*/
cairo_operator_t str2operator(const string& mode, cairo_operator_t fallback);
/**
* @brief Create a UCS-4 codepoint from a utf-8 encoded string
*/
bool utf8_to_ucs4(const unsigned char* src, unicode_charlist& result_list);
/**
* @brief Convert a UCS-4 codepoint to a utf-8 encoded string
*/
size_t ucs4_to_utf8(char* utf8, unsigned int ucs);
}
}
} // namespace utils
} // namespace cairo
POLYBAR_NS_END

View File

@ -1,9 +1,11 @@
#pragma once
#include <array>
#include <functional>
#include <memory>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#include "settings.hpp"

View File

@ -1,6 +1,7 @@
#pragma once
#include <cstdlib>
#include <set>
#include "common.hpp"
#include "components/eventloop.hpp"
@ -22,7 +23,9 @@ class connection;
class logger;
class renderer;
class screen;
namespace legacy_tray {
class tray_manager;
}
namespace tags {
class dispatch;
@ -34,16 +37,15 @@ class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::propert
public signal_receiver<SIGN_PRIORITY_BAR, signals::ui::dim_window> {
public:
using make_type = unique_ptr<bar>;
static make_type make(eventloop::loop&, bool only_initialize_values = false);
static make_type make(eventloop::loop&, const config&, bool only_initialize_values = false);
explicit bar(connection&, signal_emitter&, const config&, const logger&, eventloop::loop&, unique_ptr<screen>&&,
unique_ptr<tray_manager>&&, unique_ptr<tags::dispatch>&&, unique_ptr<tags::action_context>&&,
bool only_initialize_values);
unique_ptr<tags::dispatch>&&, unique_ptr<tags::action_context>&&, bool only_initialize_values);
~bar();
const bar_settings& settings() const;
void start();
void start(const string& tray_module_name);
void parse(string&& data, bool force = false);
@ -92,7 +94,7 @@ class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::propert
const logger& m_log;
eventloop::loop& m_loop;
unique_ptr<screen> m_screen;
unique_ptr<tray_manager> m_tray;
unique_ptr<legacy_tray::tray_manager> m_tray;
unique_ptr<renderer> m_renderer;
unique_ptr<tags::dispatch> m_dispatch;
unique_ptr<tags::action_context> m_action_ctxt;
@ -105,12 +107,12 @@ 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>()};
eventloop::TimerHandle& m_rightclick_timer{m_loop.handle<eventloop::TimerHandle>()};
eventloop::TimerHandle& m_dim_timer{m_loop.handle<eventloop::TimerHandle>()};
eventloop::timer_handle_t m_leftclick_timer{m_loop.handle<eventloop::TimerHandle>()};
eventloop::timer_handle_t m_middleclick_timer{m_loop.handle<eventloop::TimerHandle>()};
eventloop::timer_handle_t m_rightclick_timer{m_loop.handle<eventloop::TimerHandle>()};
eventloop::timer_handle_t m_dim_timer{m_loop.handle<eventloop::TimerHandle>()};
bool m_visible{true};
};

View File

@ -24,10 +24,7 @@ using file_list = vector<string>;
class config {
public:
using make_type = const config&;
static make_type make(string path = "", string bar = "");
explicit config(const logger& logger, string&& path = "", string&& bar = "")
explicit config(const logger& logger, string&& path, string&& bar)
: m_log(logger), m_file(move(path)), m_barname(move(bar)){};
const string& filepath() const;
@ -44,33 +41,19 @@ class config {
void set_included(file_list included);
void warn_deprecated(const string& section, const string& key, string replacement) const;
file_list get_included_files() const;
void warn_deprecated(const string& section, const string& key, string replacement = "") const;
/**
* Returns true if a given parameter exists
*/
bool has(const string& section, const string& key) const {
auto it = m_sections.find(section);
return it != m_sections.end() && it->second.find(key) != it->second.end();
}
bool has(const string& section, const string& key) const;
/**
* Set parameter value
*/
void set(const string& section, const string& key, string&& value) {
auto it = m_sections.find(section);
if (it == m_sections.end()) {
valuemap_t values;
values[key] = value;
m_sections[section] = move(values);
}
auto it2 = it->second.find(key);
if ((it2 = it->second.find(key)) == it->second.end()) {
it2 = it->second.emplace_hint(it2, key, value);
} else {
it2->second = value;
}
}
void set(const string& section, const string& key, string&& value);
/**
* Get parameter for the current bar by name
@ -92,7 +75,7 @@ class config {
if (it->second.find(key) == it->second.end()) {
throw key_error("Missing parameter \"" + section + "." + key + "\"");
}
return dereference<T>(section, key, it->second.at(key), convert<T>(string{it->second.at(key)}));
return convert<T>(dereference(section, key, it->second.at(key)));
}
/**
@ -103,8 +86,7 @@ class config {
T get(const string& section, const string& key, const T& default_value) const {
try {
string string_value{get<string>(section, key)};
T result{convert<T>(string{string_value})};
return dereference<T>(move(section), move(key), move(string_value), move(result));
return convert<T>(dereference(move(section), move(key), move(string_value)));
} catch (const key_error& err) {
return default_value;
} catch (const std::exception& err) {
@ -157,12 +139,11 @@ class config {
while (true) {
try {
string string_value{get<string>(section, key + "-" + to_string(results.size()))};
T value{convert<T>(string{string_value})};
if (!string_value.empty()) {
results.emplace_back(dereference<T>(section, key, move(string_value), move(value)));
results.emplace_back(convert<T>(dereference(section, key, move(string_value))));
} else {
results.emplace_back(move(value));
results.emplace_back(convert<T>(move(string_value)));
}
} catch (const key_error& err) {
break;
@ -187,12 +168,11 @@ class config {
while (true) {
try {
string string_value{get<string>(section, key + "-" + to_string(results.size()))};
T value{convert<T>(string{string_value})};
if (!string_value.empty()) {
results.emplace_back(dereference<T>(section, key, move(string_value), move(value)));
results.emplace_back(convert<T>(dereference(section, key, move(string_value))));
} else {
results.emplace_back(move(value));
results.emplace_back(convert<T>(move(string_value)));
}
} catch (const key_error& err) {
break;
@ -210,8 +190,6 @@ class config {
return default_value;
}
void ignore_key(const string& section, const string& key) const;
/**
* Attempt to load value using the deprecated key name. If successful show a
* warning message. If it fails load the value using the new key and given
@ -225,20 +203,10 @@ class config {
return value;
} catch (const key_error& err) {
return get<T>(section, newkey, fallback);
}
}
/**
* @see deprecated<T>
*/
template <typename T = string>
T deprecated_list(const string& section, const string& old, const string& newkey, const vector<T>& fallback) const {
try {
vector<T> value{get_list<T>(section, old)};
warn_deprecated(section, old, newkey);
return value;
} catch (const key_error& err) {
return get_list<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);
}
}
@ -251,27 +219,7 @@ class config {
/**
* Dereference value reference
*/
template <typename T>
T dereference(const string& section, const string& key, const string& var, const T& fallback) const {
if (var.substr(0, 2) != "${" || var.substr(var.length() - 1) != "}") {
return fallback;
}
auto path = var.substr(2, var.length() - 3);
size_t pos;
if (path.compare(0, 4, "env:") == 0) {
return dereference_env<T>(path.substr(4));
} else if (path.compare(0, 5, "xrdb:") == 0) {
return dereference_xrdb<T>(path.substr(5));
} else if (path.compare(0, 5, "file:") == 0) {
return dereference_file<T>(path.substr(5));
} else if ((pos = path.find(".")) != string::npos) {
return dereference_local<T>(path.substr(0, pos), path.substr(pos + 1), section);
} else {
throw value_error("Invalid reference defined at \"" + section + "." + key + "\"");
}
}
string dereference(const string& section, const string& key, const string& var) const;
/**
* Dereference local value reference defined using:
@ -282,133 +230,28 @@ class config {
* ${section.key}
* ${section.key:fallback}
*/
template <typename T>
T dereference_local(string section, const string& key, const string& current_section) const {
if (section == "BAR") {
m_log.warn("${BAR.key} is deprecated. Use ${root.key} instead");
}
section = string_util::replace(section, "BAR", this->section(), 0, 3);
section = string_util::replace(section, "root", this->section(), 0, 4);
section = string_util::replace(section, "self", current_section, 0, 4);
try {
string string_value{get<string>(section, key)};
T result{convert<T>(string{string_value})};
return dereference<T>(string(section), move(key), move(string_value), move(result));
} catch (const key_error& err) {
size_t pos;
if ((pos = key.find(':')) != string::npos) {
string fallback = key.substr(pos + 1);
m_log.info("The reference ${%s.%s} does not exist, using defined fallback value \"%s\"", section,
key.substr(0, pos), fallback);
return convert<T>(move(fallback));
}
throw value_error("The reference ${" + section + "." + key + "} does not exist (no fallback set)");
}
}
string dereference_local(string section, const string& key, const string& current_section) const;
/**
* Dereference environment variable reference defined using:
* ${env:key}
* ${env:key:fallback value}
*/
template <typename T>
T dereference_env(string var) const {
size_t pos;
string env_default;
/*
* This is needed because with only the string we cannot distinguish
* between an empty string as default and not default
*/
bool has_default = false;
if ((pos = var.find(':')) != string::npos) {
env_default = var.substr(pos + 1);
has_default = true;
var.erase(pos);
}
if (env_util::has(var)) {
string env_value{env_util::get(var)};
m_log.info("Environment var reference ${%s} found (value=%s)", var, env_value);
return convert<T>(move(env_value));
} else if (has_default) {
m_log.info("Environment var ${%s} is undefined, using defined fallback value \"%s\"", var, env_default);
return convert<T>(move(env_default));
} else {
throw value_error(sstream() << "Environment var ${" << var << "} does not exist (no fallback set)");
}
}
string dereference_env(string var) const;
/**
* Dereference X resource db value defined using:
* ${xrdb:key}
* ${xrdb:key:fallback value}
*/
template <typename T>
T dereference_xrdb(string var) const {
size_t pos;
#if not WITH_XRM
m_log.warn("No built-in support to dereference ${xrdb:%s} references (requires `xcb-util-xrm`)", var);
if ((pos = var.find(':')) != string::npos) {
return convert<T>(var.substr(pos + 1));
}
return convert<T>("");
#else
if (!m_xrm) {
throw application_error("xrm is not initialized");
}
string fallback;
bool has_fallback = false;
if ((pos = var.find(':')) != string::npos) {
fallback = var.substr(pos + 1);
has_fallback = true;
var.erase(pos);
}
try {
auto value = m_xrm->require<string>(var.c_str());
m_log.info("Found matching X resource \"%s\" (value=%s)", var, value);
return convert<T>(move(value));
} catch (const xresource_error& err) {
if (has_fallback) {
m_log.info("%s, using defined fallback value \"%s\"", err.what(), fallback);
return convert<T>(move(fallback));
}
throw value_error(sstream() << err.what() << " (no fallback set)");
}
#endif
}
string dereference_xrdb(string var) const;
/**
* Dereference file reference by reading its contents
* ${file:/absolute/file/path}
* ${file:/absolute/file/path:fallback value}
*/
template <typename T>
T dereference_file(string var) const {
size_t pos;
string fallback;
bool has_fallback = false;
if ((pos = var.find(':')) != string::npos) {
fallback = var.substr(pos + 1);
has_fallback = true;
var.erase(pos);
}
var = file_util::expand(var);
if (file_util::exists(var)) {
m_log.info("File reference \"%s\" found", var);
return convert<T>(string_util::trim(file_util::contents(var), '\n'));
} else if (has_fallback) {
m_log.info("File reference \"%s\" not found, using defined fallback value \"%s\"", var, fallback);
return convert<T>(move(fallback));
} else {
throw value_error(sstream() << "The file \"" << var << "\" does not exist (no fallback set)");
}
}
string dereference_file(string var) const;
private:
const logger& m_log;

View File

@ -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 parse(string barname);
protected:
/**
@ -229,12 +229,7 @@ class config_parser {
/**
* @brief Absolute path to the main config file
*/
string m_config;
/**
* Is used to resolve ${root...} references
*/
string m_barname;
string m_config_file;
/**
* @brief List of all the lines in the config (with included files)

View File

@ -39,7 +39,7 @@ class controller : public signal_receiver<SIGN_PRIORITY_CONTROLLER, signals::eve
signals::ipc::hook, signals::ui::button_press, signals::ui::update_background> {
public:
using make_type = unique_ptr<controller>;
static make_type make(bool has_ipc, eventloop::loop&);
static make_type make(bool has_ipc, eventloop::loop&, const config&);
explicit controller(connection&, signal_emitter&, const logger&, const config&, bool has_ipc, eventloop::loop&);
~controller();
@ -55,12 +55,14 @@ class controller : public signal_receiver<SIGN_PRIORITY_CONTROLLER, signals::eve
void signal_handler(int signum);
void conn_cb();
void create_config_watcher(const string& filename);
void confwatch_handler(const char* fname);
void notifier_handler();
void screenshot_handler();
protected:
void trigger_notification();
void start_modules();
void read_events(bool confwatch);
void process_inputdata(string&& cmd);
bool process_update(bool force);
@ -100,6 +102,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
@ -107,7 +110,7 @@ class controller : public signal_receiver<SIGN_PRIORITY_CONTROLLER, signals::eve
* This handle is used to notify the eventloop of changes which are not otherwise covered by other handles.
* E.g. click actions.
*/
eventloop::AsyncHandle& m_notifier{m_loop.handle<eventloop::AsyncHandle>([this]() { notifier_handler(); })};
eventloop::async_handle_t m_notifier{m_loop.handle<eventloop::AsyncHandle>([this]() { notifier_handler(); })};
/**
* Notification data for the controller.

View File

@ -3,6 +3,7 @@
#include <uv.h>
#include <stdexcept>
#include <utility>
#include "common.hpp"
#include "components/logger.hpp"
@ -36,12 +37,12 @@ namespace eventloop {
get()->data = this;
}
Self& leak(std::unique_ptr<Self> h) {
void leak(std::shared_ptr<Self> h) {
lifetime_extender = std::move(h);
return *lifetime_extender;
}
void unleak() {
reset_callbacks();
lifetime_extender.reset();
}
@ -73,6 +74,15 @@ namespace eventloop {
}
protected:
~Handle() = default;
/**
* Resets all callbacks stored in the handle as part of closing the handle.
*
* This releases any lambda captures, breaking possible cyclic dependencies in shared_ptr.
*/
virtual void reset_callbacks() = 0;
/**
* Generic callback function that can be used for all uv handle callbacks.
*
@ -128,14 +138,14 @@ namespace eventloop {
uv_loop_t* uv_loop;
/**
* The handle stores the unique_ptr to itself so that it effectively leaks memory.
* The handle stores the shared_ptr to itself so that it effectively leaks memory.
*
* This saves us from having to guarantee that the handle's lifetime extends to at least after it is closed.
*
* Once the handle is closed, either explicitly or by walking all handles when the loop shuts down, this reference
* is reset and the object is explicitly destroyed.
*/
std::unique_ptr<Self> lifetime_extender;
std::shared_ptr<Self> lifetime_extender;
};
struct ErrorEvent {
@ -144,54 +154,32 @@ namespace eventloop {
using cb_error = cb_event<ErrorEvent>;
class WriteRequest : public non_copyable_mixin {
class WriteRequest : public non_copyable_mixin, public non_movable_mixin {
public:
using cb_write = cb_void;
WriteRequest(cb_write user_cb, cb_error err_cb) : write_callback(user_cb), write_err_cb(err_cb) {
get()->data = this;
};
WriteRequest(cb_write&& user_cb, cb_error&& err_cb);
static WriteRequest& create(cb_write user_cb, cb_error err_cb) {
auto r = std::make_unique<WriteRequest>(user_cb, err_cb);
return r->leak(std::move(r));
};
static WriteRequest& create(cb_write&& user_cb, cb_error&& err_cb);
uv_write_t* get() {
return &req;
}
uv_write_t* get();
/**
* Trigger the write callback.
*
* After that, this object is destroyed.
*/
void trigger(int status) {
if (status < 0) {
if (write_err_cb) {
write_err_cb(ErrorEvent{status});
}
} else {
if (write_callback) {
write_callback();
}
}
unleak();
}
void trigger(int status);
protected:
WriteRequest& leak(std::unique_ptr<WriteRequest> h) {
lifetime_extender = std::move(h);
return *lifetime_extender;
}
WriteRequest& leak(std::unique_ptr<WriteRequest> h);
void unleak() {
lifetime_extender.reset();
}
void unleak();
void reset_callbacks();
private:
uv_write_t req;
uv_write_t req{};
cb_write write_callback;
cb_error write_err_cb;
@ -208,13 +196,16 @@ namespace eventloop {
int signum;
};
class SignalHandle : public Handle<SignalHandle, uv_signal_t> {
class SignalHandle final : public Handle<SignalHandle, uv_signal_t> {
public:
using Handle::Handle;
using cb = cb_event<SignalEvent>;
void init();
void start(int signum, cb user_cb);
void start(int signum, cb&& user_cb);
protected:
void reset_callbacks() override;
private:
cb callback;
@ -224,15 +215,18 @@ namespace eventloop {
uv_poll_event event;
};
class PollHandle : public Handle<PollHandle, uv_poll_t> {
class PollHandle final : public Handle<PollHandle, uv_poll_t> {
public:
using Handle::Handle;
using cb = cb_event<PollEvent>;
void init(int fd);
void start(int events, cb user_cb, cb_error err_cb);
void start(int events, cb&& user_cb, cb_error&& err_cb);
static void poll_callback(uv_poll_t*, int status, int events);
protected:
void reset_callbacks() override;
private:
cb callback;
cb_error err_cb;
@ -243,41 +237,50 @@ namespace eventloop {
uv_fs_event event;
};
class FSEventHandle : public Handle<FSEventHandle, uv_fs_event_t> {
class FSEventHandle final : public Handle<FSEventHandle, uv_fs_event_t> {
public:
using Handle::Handle;
using cb = cb_event<FSEvent>;
void init();
void start(const string& path, int flags, cb user_cb, cb_error err_cb);
void start(const string& path, int flags, cb&& user_cb, cb_error&& err_cb);
static void fs_event_callback(uv_fs_event_t*, const char* path, int events, int status);
protected:
void reset_callbacks() override;
private:
cb callback;
cb_error err_cb;
};
class TimerHandle : public Handle<TimerHandle, uv_timer_t> {
class TimerHandle final : public Handle<TimerHandle, uv_timer_t> {
public:
using Handle::Handle;
using cb = cb_void;
void init();
void start(uint64_t timeout, uint64_t repeat, cb user_cb);
void start(uint64_t timeout, uint64_t repeat, cb&& user_cb);
void stop();
protected:
void reset_callbacks() override;
private:
cb callback;
};
class AsyncHandle : public Handle<AsyncHandle, uv_async_t> {
class AsyncHandle final : public Handle<AsyncHandle, uv_async_t> {
public:
using Handle::Handle;
using cb = cb_void;
void init(cb user_cb);
void init(cb&& user_cb);
void send();
protected:
void reset_callbacks() override;
private:
cb callback;
};
@ -295,9 +298,9 @@ namespace eventloop {
using cb_read_eof = cb_void;
using cb_connection = cb_void;
void listen(int backlog, cb_connection user_cb, cb_error err_cb) {
this->connection_callback = user_cb;
this->connection_err_cb = err_cb;
void listen(int backlog, cb_connection&& user_cb, cb_error&& err_cb) {
this->connection_callback = std::move(user_cb);
this->connection_err_cb = std::move(err_cb);
UV(uv_listen, this->template get<uv_stream_t>(), backlog, connection_cb);
};
@ -316,11 +319,11 @@ namespace eventloop {
UV(uv_accept, this->template get<uv_stream_t>(), client.template get<uv_stream_t>());
}
void read_start(cb_read fun, cb_void eof_cb, cb_error err_cb) {
this->read_callback = fun;
this->read_eof_cb = eof_cb;
this->read_err_cb = err_cb;
UV(uv_read_start, this->template get<uv_stream_t>(), &this->alloc_callback, read_cb);
void read_start(cb_read&& fun, cb_void&& eof_cb, cb_error&& err_cb) {
this->read_callback = std::move(fun);
this->read_eof_cb = std::move(eof_cb);
this->read_err_cb = std::move(err_cb);
UV(uv_read_start, this->template get<uv_stream_t>(), &this->alloc_callback, &read_cb);
};
static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) {
@ -340,8 +343,8 @@ namespace eventloop {
}
};
void write(const vector<uint8_t>& data, WriteRequest::cb_write user_cb = {}, cb_error err_cb = {}) {
WriteRequest& req = WriteRequest::create(user_cb, err_cb);
void write(const vector<uint8_t>& data, WriteRequest::cb_write&& user_cb = {}, cb_error&& err_cb = {}) {
WriteRequest& req = WriteRequest::create(std::move(user_cb), std::move(err_cb));
uv_buf_t buf{(char*)data.data(), data.size()};
@ -349,6 +352,17 @@ namespace eventloop {
[](uv_write_t* r, int status) { static_cast<WriteRequest*>(r->data)->trigger(status); });
}
protected:
~StreamHandle() = default;
void reset_callbacks() override {
read_callback = nullptr;
read_eof_cb = nullptr;
read_err_cb = nullptr;
connection_callback = nullptr;
connection_err_cb = nullptr;
}
private:
/**
* Callback for receiving data
@ -371,7 +385,7 @@ namespace eventloop {
cb_error connection_err_cb;
};
class PipeHandle : public StreamHandle<PipeHandle, uv_pipe_t> {
class PipeHandle final : public StreamHandle<PipeHandle, uv_pipe_t> {
public:
using StreamHandle::StreamHandle;
using cb_connect = cb_void;
@ -381,7 +395,10 @@ namespace eventloop {
void bind(const string& path);
void connect(const string& name, cb_connect user_cb, cb_error err_cb);
void connect(const string& name, cb_connect&& user_cb, cb_error&& err_cb);
protected:
void reset_callbacks() override;
private:
static void connect_cb(uv_connect_t* req, int status);
@ -390,21 +407,47 @@ namespace eventloop {
cb_connect connect_callback;
};
class PrepareHandle final : public Handle<PrepareHandle, uv_prepare_t> {
public:
using Handle::Handle;
using cb = cb_void;
void init();
void start(cb&& user_cb);
protected:
void reset_callbacks() override;
private:
static void connect_cb(uv_connect_t* req, int status);
cb callback;
};
using signal_handle_t = shared_ptr<SignalHandle>;
using poll_handle_t = shared_ptr<PollHandle>;
using fs_event_handle_t = shared_ptr<FSEventHandle>;
using timer_handle_t = shared_ptr<TimerHandle>;
using async_handle_t = shared_ptr<AsyncHandle>;
using pipe_handle_t = shared_ptr<PipeHandle>;
using prepare_handle_t = shared_ptr<PrepareHandle>;
class loop : public non_copyable_mixin, public non_movable_mixin {
public:
loop();
~loop();
void run();
void stop();
uint64_t now() const;
template <typename H, typename... Args>
H& handle(Args... args) {
auto ptr = make_unique<H>(get());
shared_ptr<H> handle(Args&&... args) {
auto ptr = make_shared<H>(get());
ptr->init(std::forward<Args>(args)...);
return ptr->leak(std::move(ptr));
ptr->leak(ptr);
return ptr;
}
protected:
uv_loop_t* get() const;
private:

View File

@ -34,6 +34,10 @@ class logger {
explicit logger(loglevel level);
const logger& operator=(const logger&) const {
return *this;
}
static loglevel parse_verbosity(const string& name, loglevel fallback = loglevel::NONE);
void verbosity(loglevel level);

View File

@ -46,13 +46,15 @@ class renderer : public renderer_interface,
public signal_receiver<SIGN_PRIORITY_RENDERER, signals::ui::request_snapshot> {
public:
using make_type = unique_ptr<renderer>;
static make_type make(const bar_settings& bar, tags::action_context& action_ctxt);
static make_type make(const bar_settings& bar, tags::action_context& action_ctxt, const config&);
explicit renderer(connection& conn, signal_emitter& sig, const config&, const logger& logger, const bar_settings& bar,
background_manager& background_manager, tags::action_context& action_ctxt);
~renderer();
xcb_window_t window() const;
xcb_visualtype_t* visual() const;
int depth() const;
void begin(xcb_rectangle_t rect);
void end();
@ -67,6 +69,8 @@ class renderer : public renderer_interface,
double get_alignment_start(const alignment align) const override;
void apply_tray_position(const tags::context& context) override;
protected:
void fill_background();
void fill_overline(rgba color, double x, double w);
@ -100,18 +104,22 @@ class renderer : public renderer_interface,
const bar_settings& m_bar;
std::shared_ptr<bg_slice> m_background;
int m_depth{32};
int m_depth{-1};
xcb_window_t m_window;
xcb_colormap_t m_colormap;
xcb_colormap_t m_colormap{XCB_NONE};
xcb_visualtype_t* m_visual;
xcb_gcontext_t m_gcontext;
/**
* Background pixmap for the bar window
*
* All bar contents are rendered onto this.
*/
xcb_pixmap_t m_pixmap;
xcb_rectangle_t m_rect{0, 0, 0U, 0U};
reserve_area m_cleararea{};
// bool m_autosize{false};
unique_ptr<cairo::context> m_context;
unique_ptr<cairo::xcb_surface> m_surface;
map<alignment, alignment_block> m_blocks;

View File

@ -33,6 +33,8 @@ class renderer_interface {
*/
virtual double get_alignment_start(const alignment align) const = 0;
virtual void apply_tray_position(const tags::context& context) = 0;
protected:
/**
* Stores information about actions in the current render cycle.

View File

@ -16,23 +16,16 @@ class logger;
class connection;
class signal_emitter;
class screen : public xpp::event::sink<evt::randr_screen_change_notify> {
class screen : public xpp::event::sink<evt::map_notify, evt::randr_screen_change_notify> {
public:
using make_type = unique_ptr<screen>;
static make_type make();
static make_type make(const config&);
explicit screen(connection& conn, signal_emitter& emitter, const logger& logger, const config& conf);
~screen();
struct size size() const {
return m_size;
}
xcb_window_t root() const {
return m_root;
}
protected:
void handle(const evt::map_notify& evt) override;
void handle(const evt::randr_screen_change_notify& evt) override;
private:
@ -50,6 +43,12 @@ class screen : public xpp::event::sink<evt::randr_screen_change_notify> {
};
bool m_sigraised{false};
/**
* Original event mask on the root window.
* Used to restore event mask after the proxy window is mapped.
*/
uint32_t m_root_mask{0};
bool have_monitors_changed() const;
};

View File

@ -82,11 +82,15 @@ enum class strut {
struct position {
int x{0};
int y{0};
bool operator==(const position& other) {
return this->x == other.x && this->y == other.y;
}
};
struct size {
unsigned int w{1U};
unsigned int h{1U};
unsigned w{1U};
unsigned h{1U};
};
enum class spacing_type { SPACE, POINT, PIXEL };
@ -163,11 +167,21 @@ struct action {
string command{};
};
/**
* Settings specific to the X window system.
*/
struct x_settings {
xcb_window_t window{XCB_NONE};
xcb_visualtype_t* visual{nullptr};
int depth{-1};
};
struct bar_settings {
explicit bar_settings() = default;
bar_settings(const bar_settings& other) = default;
xcb_window_t window{XCB_NONE};
x_settings x_data;
monitor_t monitor{};
bool monitor_strict{false};
bool monitor_exact{true};
@ -183,6 +197,7 @@ struct bar_settings {
position offset{0, 0};
side_values padding{ZERO_SPACE, ZERO_SPACE};
side_values module_margin{ZERO_SPACE, ZERO_SPACE};
bool struts{true};
struct {
int top;
int bottom;
@ -275,9 +290,4 @@ struct event_timer {
};
};
enum class output_policy {
REDIRECTED,
IGNORED,
};
POLYBAR_NS_END

View File

@ -16,6 +16,7 @@ namespace drawtypes {
size_t max{0_z};
string suffix{""s};
bool zpad{false};
bool rpadding{false};
};
class label : public non_copyable_mixin {

View File

@ -8,14 +8,13 @@
POLYBAR_NS
using std::strerror;
using std::exception;
using std::runtime_error;
using std::strerror;
class application_error : public runtime_error {
public:
explicit application_error(const string& message, int code = 0) : runtime_error(message), code(code) {}
virtual ~application_error() {}
int code{0};
};
@ -24,7 +23,6 @@ class system_error : public application_error {
explicit system_error() : application_error(strerror(errno), errno) {}
explicit system_error(const string& message)
: application_error(message + " (reason: " + strerror(errno) + ")", errno) {}
virtual ~system_error() {}
};
#define DEFINE_CHILD_ERROR(error, parent) \

View File

@ -101,7 +101,7 @@ namespace signals {
} // namespace ui
namespace ui_tray {
struct mapped_clients : public detail::value_signal<mapped_clients, unsigned int> {
struct tray_pos_change : public detail::value_signal<tray_pos_change, int> {
using base_type::base_type;
};
} // namespace ui_tray

View File

@ -35,8 +35,8 @@ namespace signals {
struct update_geometry;
} // namespace ui
namespace ui_tray {
struct mapped_clients;
}
struct tray_pos_change;
} // namespace ui_tray
} // namespace signals
POLYBAR_NS_END

View File

@ -42,14 +42,14 @@ namespace ipc {
const logger& m_log;
eventloop::loop& m_loop;
eventloop::PipeHandle& socket;
eventloop::pipe_handle_t m_socket;
class connection : public non_copyable_mixin, public non_movable_mixin {
public:
using cb = std::function<void(connection&, uint8_t, type_t, const std::vector<uint8_t>&)>;
connection(eventloop::loop& loop, cb msg_callback);
~connection();
eventloop::PipeHandle& client_pipe;
eventloop::pipe_handle_t client_pipe;
decoder dec;
};
@ -79,7 +79,7 @@ namespace ipc {
struct fifo {
fifo(eventloop::loop& loop, ipc& ipc, const string& path);
~fifo();
eventloop::PipeHandle& pipe_handle;
eventloop::pipe_handle_t pipe_handle;
};
unique_ptr<fifo> ipc_pipe;
@ -89,7 +89,7 @@ namespace ipc {
* Buffer for the currently received IPC message over the named pipe
*/
string m_pipe_buffer{};
void receive_data(string buf);
void receive_data(const string& buf);
void receive_eof();
};
} // namespace ipc

View File

@ -1,6 +1,7 @@
#pragma once
#include "modules/meta/event_module.hpp"
#include "modules/meta/types.hpp"
#include "settings.hpp"
POLYBAR_NS
@ -20,7 +21,7 @@ namespace modules {
class alsa_module : public event_module<alsa_module> {
public:
explicit alsa_module(const bar_settings&, string);
explicit alsa_module(const bar_settings&, string, const config&);
void teardown();
bool has_event();
@ -29,7 +30,7 @@ namespace modules {
string get_output();
bool build(builder* builder, const string& tag) const;
static constexpr auto TYPE = "internal/alsa";
static constexpr auto TYPE = ALSA_TYPE;
static constexpr auto EVENT_INC = "inc";
static constexpr auto EVENT_DEC = "dec";

View File

@ -2,11 +2,25 @@
#include "components/config.hpp"
#include "modules/meta/inotify_module.hpp"
#include "modules/meta/types.hpp"
#include "settings.hpp"
POLYBAR_NS
namespace modules {
/**
* Reads value from `/sys/class/backlight/` to get a brightness value for some device.
*
* There are two file providing brightness values: `brightness` and `actual_brightness`.
* The `actual_brightness` file is usually more reliable, but in some cases does not work (provides completely wrong
* values, doesn't update) depending on kernel version, graphics driver, and/or graphics card.
* Which file is used is controlled by the use-actual-brightness setting.
*
* The general issue with the `brightness` file seems to be that, while it does receive inotify events, the events it
* receives are not for modification of the file and arrive just before the file is updated with a new value. The module
* thus reads and displays an outdated brightness value. To compensate for this, the module periodically (controlled by
* `poll-interval`) forces an update. By default, this is only enabled if the `backlight` file is used.
*/
class backlight_module : public inotify_module<backlight_module> {
public:
struct brightness_handle {
@ -19,14 +33,13 @@ namespace modules {
string get_output();
public:
explicit backlight_module(const bar_settings&, string);
explicit backlight_module(const bar_settings&, string, const config&);
void idle();
bool on_event(inotify_event* event);
bool on_event(const inotify_event& event);
bool build(builder* builder, const string& tag) const;
static constexpr auto TYPE = "internal/backlight";
static constexpr auto TYPE = BACKLIGHT_TYPE;
static constexpr const char* EVENT_INC = "inc";
static constexpr const char* EVENT_DEC = "dec";
@ -46,14 +59,18 @@ namespace modules {
label_t m_label;
progressbar_t m_progressbar;
string m_path_backlight;
float m_max_brightness;
float m_max_brightness{};
bool m_scroll{false};
int m_scroll_interval{5};
bool m_use_actual_brightness{true};
brightness_handle m_val;
brightness_handle m_max;
int m_percentage = 0;
chrono::duration<double> m_interval{};
chrono::steady_clock::time_point m_lastpoll;
};
} // namespace modules

View File

@ -2,6 +2,7 @@
#include "common.hpp"
#include "modules/meta/inotify_module.hpp"
#include "modules/meta/types.hpp"
POLYBAR_NS
@ -46,16 +47,16 @@ namespace modules {
using consumption_reader = mutex_wrapper<value_reader<string /* watts */>>;
public:
explicit battery_module(const bar_settings&, string);
explicit battery_module(const bar_settings&, string, const config&);
void start() override;
void teardown();
void idle();
bool on_event(inotify_event* event);
bool on_event(const inotify_event& event);
string get_format() const;
bool build(builder* builder, const string& tag) const;
static constexpr auto TYPE = "internal/battery";
static constexpr auto TYPE = BATTERY_TYPE;
protected:
state current_state();

View File

@ -1,6 +1,7 @@
#pragma once
#include "modules/meta/event_module.hpp"
#include "modules/meta/types.hpp"
#include "utils/bspwm.hpp"
POLYBAR_NS
@ -39,7 +40,7 @@ namespace modules {
};
public:
explicit bspwm_module(const bar_settings&, string);
explicit bspwm_module(const bar_settings&, string, const config&);
void stop() override;
bool has_event();
@ -47,7 +48,7 @@ namespace modules {
string get_output();
bool build(builder* builder, const string& tag) const;
static constexpr auto TYPE = "internal/bspwm";
static constexpr auto TYPE = BSPWM_TYPE;
static constexpr auto EVENT_FOCUS = "focus";
static constexpr auto EVENT_NEXT = "next";

View File

@ -1,18 +1,19 @@
#pragma once
#include "modules/meta/timer_module.hpp"
#include "modules/meta/types.hpp"
POLYBAR_NS
namespace modules {
class counter_module : public timer_module<counter_module> {
public:
explicit counter_module(const bar_settings&, string);
explicit counter_module(const bar_settings&, string, const config&);
bool update();
bool build(builder* builder, const string& tag) const;
static constexpr auto TYPE = "internal/counter";
static constexpr auto TYPE = COUNTER_TYPE;
private:
static constexpr auto TAG_COUNTER = "<counter>";

View File

@ -1,6 +1,7 @@
#pragma once
#include "modules/meta/timer_module.hpp"
#include "modules/meta/types.hpp"
#include "settings.hpp"
POLYBAR_NS
@ -20,13 +21,13 @@ namespace modules {
class cpu_module : public timer_module<cpu_module> {
public:
explicit cpu_module(const bar_settings&, string);
explicit cpu_module(const bar_settings&, string, const config&);
bool update();
string get_format() const;
bool build(builder* builder, const string& tag) const;
static constexpr auto TYPE = "internal/cpu";
static constexpr auto TYPE = CPU_TYPE;
protected:
bool read_values();

View File

@ -6,18 +6,19 @@
#include <iostream>
#include "modules/meta/timer_module.hpp"
#include "modules/meta/types.hpp"
POLYBAR_NS
namespace modules {
class date_module : public timer_module<date_module> {
public:
explicit date_module(const bar_settings&, string);
explicit date_module(const bar_settings&, string, const config&);
bool update();
bool build(builder* builder, const string& tag) const;
static constexpr auto TYPE = "internal/date";
static constexpr auto TYPE = DATE_TYPE;
static constexpr auto EVENT_TOGGLE = "toggle";

View File

@ -3,6 +3,7 @@
#include <dwmipcpp/connection.hpp>
#include "modules/meta/event_module.hpp"
#include "modules/meta/types.hpp"
POLYBAR_NS
@ -46,7 +47,7 @@ namespace modules {
label_t label;
};
static constexpr auto TYPE = "internal/dwm";
static constexpr auto TYPE = DWM_TYPE;
void stop() override;
bool has_event();

View File

@ -2,6 +2,7 @@
#include "components/config.hpp"
#include "modules/meta/timer_module.hpp"
#include "modules/meta/types.hpp"
#include "settings.hpp"
POLYBAR_NS
@ -35,14 +36,14 @@ namespace modules {
*/
class fs_module : public timer_module<fs_module> {
public:
explicit fs_module(const bar_settings&, string);
explicit fs_module(const bar_settings&, string, const config&);
bool update();
string get_format() const;
string get_output();
bool build(builder* builder, const string& tag) const;
static constexpr auto TYPE = "internal/fs";
static constexpr auto TYPE = FS_TYPE;
private:
static constexpr auto FORMAT_MOUNTED = "format-mounted";

View File

@ -3,6 +3,7 @@
#include <atomic>
#include "modules/meta/timer_module.hpp"
#include "modules/meta/types.hpp"
#include "settings.hpp"
#include "utils/http.hpp"
@ -14,13 +15,13 @@ namespace modules {
*/
class github_module : public timer_module<github_module> {
public:
explicit github_module(const bar_settings&, string);
explicit github_module(const bar_settings&, string, const config&);
bool update();
bool build(builder* builder, const string& tag) const;
string get_format() const;
static constexpr auto TYPE = "internal/github";
static constexpr auto TYPE = GITHUB_TYPE;
private:
void update_label(int);
@ -35,7 +36,7 @@ namespace modules {
string m_api_url;
string m_user;
string m_accesstoken{};
unique_ptr<http_downloader> m_http{};
http_downloader m_http{};
bool m_empty_notifications{false};
std::atomic<bool> m_offline{false};
};

View File

@ -4,6 +4,7 @@
#include "components/config.hpp"
#include "modules/meta/event_module.hpp"
#include "modules/meta/types.hpp"
#include "utils/i3.hpp"
#include "utils/io.hpp"
@ -44,14 +45,14 @@ namespace modules {
};
public:
explicit i3_module(const bar_settings&, string);
explicit i3_module(const bar_settings&, string, const config&);
void stop() override;
bool has_event();
bool update();
bool build(builder* builder, const string& tag) const;
static constexpr auto TYPE = "internal/i3";
static constexpr auto TYPE = I3_TYPE;
static constexpr auto EVENT_FOCUS = "focus";
static constexpr auto EVENT_NEXT = "next";

View File

@ -1,6 +1,7 @@
#pragma once
#include "modules/meta/static_module.hpp"
#include "modules/meta/types.hpp"
#include "utils/command.hpp"
POLYBAR_NS
@ -24,15 +25,16 @@ namespace modules {
};
public:
explicit ipc_module(const bar_settings&, string);
explicit ipc_module(const bar_settings&, string, const config&);
void start() override;
void update();
string get_output();
string get_format() const;
bool build(builder* builder, const string& tag) const;
void on_message(const string& message);
static constexpr auto TYPE = "custom/ipc";
static constexpr auto TYPE = IPC_TYPE;
static constexpr auto EVENT_SEND = "send";
static constexpr auto EVENT_HOOK = "hook";
@ -53,12 +55,17 @@ namespace modules {
bool has_hook() const;
void set_hook(int h);
void update_output() ;
private:
static constexpr const char* TAG_OUTPUT{"<output>"};
static constexpr auto TAG_OUTPUT = "<output>";
static constexpr auto TAG_LABEL = "<label>";
label_t m_label;
vector<unique_ptr<hook>> m_hooks;
map<mousebtn, string> m_actions;
string m_output;
int m_initial{-1};
int m_current_hook{-1};
void exec_hook();

View File

@ -1,6 +1,7 @@
#pragma once
#include "modules/meta/timer_module.hpp"
#include "modules/meta/types.hpp"
#include "settings.hpp"
POLYBAR_NS
@ -10,13 +11,13 @@ namespace modules {
enum class memory_state { NORMAL = 0, WARN };
class memory_module : public timer_module<memory_module> {
public:
explicit memory_module(const bar_settings&, string);
explicit memory_module(const bar_settings&, string, const config&);
bool update();
string get_format() const;
bool build(builder* builder, const string& tag) const;
static constexpr auto TYPE = "internal/memory";
static constexpr auto TYPE = MEMORY_TYPE;
private:
static constexpr const char* TAG_LABEL{"<label>"};

View File

@ -1,6 +1,7 @@
#pragma once
#include "modules/meta/static_module.hpp"
#include "modules/meta/types.hpp"
POLYBAR_NS
@ -17,12 +18,12 @@ namespace modules {
};
public:
explicit menu_module(const bar_settings&, string);
explicit menu_module(const bar_settings&, string, const config&);
bool build(builder* builder, const string& tag) const;
void update() {}
static constexpr auto TYPE = "custom/menu";
static constexpr auto TYPE = MENU_TYPE;
static constexpr auto EVENT_OPEN = "open";
static constexpr auto EVENT_CLOSE = "close";

View File

@ -0,0 +1,48 @@
#pragma once
/**
* Header file to include the headers for all modules.
*/
#include "modules/backlight.hpp"
#include "modules/battery.hpp"
#include "modules/bspwm.hpp"
#include "modules/counter.hpp"
#include "modules/cpu.hpp"
#include "modules/date.hpp"
#include "modules/fs.hpp"
#include "modules/ipc.hpp"
#include "modules/memory.hpp"
#include "modules/menu.hpp"
#include "modules/meta/base.hpp"
#include "modules/script.hpp"
#include "modules/temperature.hpp"
#include "modules/text.hpp"
#include "modules/tray.hpp"
#include "modules/xbacklight.hpp"
#include "modules/xwindow.hpp"
#include "modules/xworkspaces.hpp"
#if ENABLE_I3
#include "modules/i3.hpp"
#endif
#if ENABLE_DWM
#include "modules/dwm.hpp"
#endif
#if ENABLE_MPD
#include "modules/mpd.hpp"
#endif
#if ENABLE_NETWORK
#include "modules/network.hpp"
#endif
#if ENABLE_ALSA
#include "modules/alsa.hpp"
#endif
#if ENABLE_PULSEAUDIO
#include "modules/pulseaudio.hpp"
#endif
#if ENABLE_CURL
#include "modules/github.hpp"
#endif
#if ENABLE_XKEYBOARD
#include "modules/xkeyboard.hpp"
#endif

View File

@ -8,6 +8,7 @@
#include <mutex>
#include "common.hpp"
#include "components/config.hpp"
#include "components/types.hpp"
#include "errors.hpp"
#include "utils/concurrency.hpp"
@ -58,7 +59,6 @@ namespace modules {
struct module_format {
string value{};
vector<string> tags{};
label_t prefix{};
label_t suffix{};
rgba fg{};
@ -142,7 +142,7 @@ namespace modules {
template <class Impl>
class module : public module_interface {
public:
module(const bar_settings& bar, string name);
module(const bar_settings& bar, string name, const config&);
~module() noexcept;
static constexpr auto EVENT_MODULE_TOGGLE = "module_toggle";
@ -189,7 +189,7 @@ namespace modules {
string get_format() const;
string get_output();
void set_visible(bool value);
virtual void set_visible(bool value);
void action_module_toggle();
void action_module_show();

View File

@ -1,7 +1,7 @@
#pragma once
#include <cassert>
#include "components/builder.hpp"
#include "components/config.hpp"
#include "components/logger.hpp"
#include "events/signal.hpp"
#include "events/signal_emitter.hpp"
@ -15,11 +15,11 @@ namespace modules {
// module<Impl> public {{{
template <typename Impl>
module<Impl>::module(const bar_settings& bar, string name)
module<Impl>::module(const bar_settings& bar, string name, const config& conf)
: m_sig(signal_emitter::make())
, m_bar(bar)
, m_log(logger::make())
, m_conf(config::make())
, m_conf(conf)
, m_router(make_unique<action_router>())
, m_name("module/" + name)
, m_name_raw(name)

View File

@ -1,117 +1,25 @@
#pragma once
#include "common.hpp"
#include "modules/backlight.hpp"
#include "modules/battery.hpp"
#include "modules/bspwm.hpp"
#include "modules/counter.hpp"
#include "modules/cpu.hpp"
#include "modules/date.hpp"
#include "modules/fs.hpp"
#include "modules/ipc.hpp"
#include "modules/memory.hpp"
#include "modules/menu.hpp"
#include "components/logger.hpp"
#include "components/types.hpp"
#include "modules/meta/base.hpp"
#include "modules/script.hpp"
#if DEBUG
#include "modules/systray.hpp"
#endif
#include "modules/temperature.hpp"
#include "modules/text.hpp"
#include "modules/xbacklight.hpp"
#include "modules/xwindow.hpp"
#include "modules/xworkspaces.hpp"
#if ENABLE_I3
#include "modules/i3.hpp"
#endif
#if ENABLE_DWM
#include "modules/dwm.hpp"
#endif
#if ENABLE_MPD
#include "modules/mpd.hpp"
#endif
#if ENABLE_NETWORK
#include "modules/network.hpp"
#endif
#if ENABLE_ALSA
#include "modules/alsa.hpp"
#endif
#if ENABLE_PULSEAUDIO
#include "modules/pulseaudio.hpp"
#endif
#if ENABLE_CURL
#include "modules/github.hpp"
#endif
#if ENABLE_XKEYBOARD
#include "modules/xkeyboard.hpp"
#endif
#include "modules/unsupported.hpp"
POLYBAR_NS
using namespace modules;
namespace modules {
using module_t = shared_ptr<module_interface>;
namespace {
module_interface* make_module(string&& name, const bar_settings& bar, string module_name, const logger& m_log) {
if (name == counter_module::TYPE) {
return new counter_module(bar, move(module_name));
} else if (name == backlight_module::TYPE) {
return new backlight_module(bar, move(module_name));
} else if (name == battery_module::TYPE) {
return new battery_module(bar, move(module_name));
} else if (name == bspwm_module::TYPE) {
return new bspwm_module(bar, move(module_name));
} else if (name == cpu_module::TYPE) {
return new cpu_module(bar, move(module_name));
} else if (name == date_module::TYPE) {
return new date_module(bar, move(module_name));
} else if (name == dwm_module::TYPE) {
return new dwm_module(bar, move(module_name));
} else if (name == github_module::TYPE) {
return new github_module(bar, move(module_name));
} else if (name == fs_module::TYPE) {
return new fs_module(bar, move(module_name));
} else if (name == memory_module::TYPE) {
return new memory_module(bar, move(module_name));
} else if (name == i3_module::TYPE) {
return new i3_module(bar, move(module_name));
} else if (name == mpd_module::TYPE) {
return new mpd_module(bar, move(module_name));
} else if (name == "internal/volume") {
m_log.warn("internal/volume is deprecated, use %s instead", string(alsa_module::TYPE));
return new alsa_module(bar, move(module_name));
} else if (name == alsa_module::TYPE) {
return new alsa_module(bar, move(module_name));
} else if (name == pulseaudio_module::TYPE) {
return new pulseaudio_module(bar, move(module_name));
} else if (name == network_module::TYPE) {
return new network_module(bar, move(module_name));
#if DEBUG
} else if (name == systray_module::TYPE) {
return new systray_module(bar, move(module_name));
#endif
} else if (name == temperature_module::TYPE) {
return new temperature_module(bar, move(module_name));
} else if (name == xbacklight_module::TYPE) {
return new xbacklight_module(bar, move(module_name));
} else if (name == xkeyboard_module::TYPE) {
return new xkeyboard_module(bar, move(module_name));
} else if (name == xwindow_module::TYPE) {
return new xwindow_module(bar, move(module_name));
} else if (name == xworkspaces_module::TYPE) {
return new xworkspaces_module(bar, move(module_name));
} else if (name == text_module::TYPE) {
return new text_module(bar, move(module_name));
} else if (name == script_module::TYPE) {
return new script_module(bar, move(module_name));
} else if (name == menu_module::TYPE) {
return new menu_module(bar, move(module_name));
} else if (name == ipc_module::TYPE) {
return new ipc_module(bar, move(module_name));
} else {
throw application_error("Unknown module: " + name);
}
}
} // namespace
/**
* Creates a new module instance.
*
* @param type The type of the module (as given by each module's TYPE field)
* @param bar An instance of the @ref bar_settings
* @param module_name The user-specified module name
* @param log A @ref logger instance
* @param config A @ref config instance
*/
module_t make_module(string&& type, const bar_settings& bar, string module_name, const logger& log, const config& config);
} // namespace modules
POLYBAR_NS_END

View File

@ -22,7 +22,7 @@ namespace modules {
try {
// Warm up module output before entering the loop
std::unique_lock<std::mutex> guard(this->m_updatelock);
CAST_MOD(Impl)->on_event(nullptr);
CAST_MOD(Impl)->on_event({});
CAST_MOD(Impl)->broadcast();
guard.unlock();
@ -47,15 +47,14 @@ namespace modules {
}
void poll_events() {
vector<unique_ptr<inotify_watch>> watches;
vector<inotify_watch> watches;
try {
for (auto&& w : m_watchlist) {
watches.emplace_back(inotify_util::make_watch(w.first));
watches.back()->attach(w.second);
watches.emplace_back(w.first);
watches.back().attach(w.second);
}
} catch (const system_error& e) {
watches.clear();
this->m_log.err("%s: Error while creating inotify watch (what: %s)", this->name(), e.what());
CAST_MOD(Impl)->sleep(0.1s);
return;
@ -63,25 +62,21 @@ namespace modules {
while (this->running()) {
for (auto&& w : watches) {
this->m_log.trace_x("%s: Poll inotify watch %s", this->name(), w->path());
this->m_log.trace_x("%s: Poll inotify watch %s", this->name(), w.path());
if (w->poll(1000 / watches.size())) {
auto event = w->get_event();
for (auto&& w : watches) {
w->remove(true);
}
if (CAST_MOD(Impl)->on_event(event.get())) {
if (w.poll(1000 / watches.size())) {
auto event = w.get_event();
if (CAST_MOD(Impl)->on_event(event)) {
CAST_MOD(Impl)->broadcast();
}
CAST_MOD(Impl)->idle();
return;
}
if (!this->running())
if (!this->running()) {
break;
}
}
CAST_MOD(Impl)->idle();
}
}

View File

@ -0,0 +1,38 @@
#pragma once
#include "common.hpp"
POLYBAR_NS
namespace modules {
static constexpr const char ALSA_TYPE[] = "internal/alsa";
static constexpr const char BACKLIGHT_TYPE[] = "internal/backlight";
static constexpr const char BATTERY_TYPE[] = "internal/battery";
static constexpr const char BSPWM_TYPE[] = "internal/bspwm";
static constexpr const char COUNTER_TYPE[] = "internal/counter";
static constexpr const char CPU_TYPE[] = "internal/cpu";
static constexpr const char DATE_TYPE[] = "internal/date";
static constexpr const char FS_TYPE[] = "internal/fs";
static constexpr const char GITHUB_TYPE[] = "internal/github";
static constexpr const char I3_TYPE[] = "internal/i3";
static constexpr const char DWM_TYPE[] = "internal/dwm";
static constexpr const char MEMORY_TYPE[] = "internal/memory";
static constexpr const char MPD_TYPE[] = "internal/mpd";
static constexpr const char NETWORK_TYPE[] = "internal/network";
static constexpr const char PULSEAUDIO_TYPE[] = "internal/pulseaudio";
static constexpr const char TEMPERATURE_TYPE[] = "internal/temperature";
static constexpr const char TRAY_TYPE[] = "internal/tray";
static constexpr const char XBACKLIGHT_TYPE[] = "internal/xbacklight";
static constexpr const char XKEYBOARD_TYPE[] = "internal/xkeyboard";
static constexpr const char XWINDOW_TYPE[] = "internal/xwindow";
static constexpr const char XWORKSPACES_TYPE[] = "internal/xworkspaces";
static constexpr const char IPC_TYPE[] = "custom/ipc";
static constexpr const char MENU_TYPE[] = "custom/menu";
static constexpr const char SCRIPT_TYPE[] = "custom/script";
static constexpr const char TEXT_TYPE[] = "custom/text";
} // namespace modules
POLYBAR_NS_END

View File

@ -4,6 +4,7 @@
#include "adapters/mpd.hpp"
#include "modules/meta/event_module.hpp"
#include "modules/meta/types.hpp"
#include "utils/env.hpp"
POLYBAR_NS
@ -13,7 +14,7 @@ using namespace mpd;
namespace modules {
class mpd_module : public event_module<mpd_module> {
public:
explicit mpd_module(const bar_settings&, string);
explicit mpd_module(const bar_settings&, string, const config&);
void teardown();
inline bool connected() const;
@ -24,7 +25,7 @@ namespace modules {
string get_output();
bool build(builder* builder, const string& tag) const;
static constexpr auto TYPE = "internal/mpd";
static constexpr auto TYPE = MPD_TYPE;
static constexpr const char* EVENT_PLAY = "play";
static constexpr const char* EVENT_PAUSE = "pause";

View File

@ -3,6 +3,7 @@
#include "adapters/net.hpp"
#include "components/config.hpp"
#include "modules/meta/timer_module.hpp"
#include "modules/meta/types.hpp"
POLYBAR_NS
@ -11,14 +12,14 @@ namespace modules {
class network_module : public timer_module<network_module> {
public:
explicit network_module(const bar_settings&, string);
explicit network_module(const bar_settings&, string, const config&);
void teardown();
bool update();
string get_format() const;
bool build(builder* builder, const string& tag) const;
static constexpr auto TYPE = "internal/network";
static constexpr auto TYPE = NETWORK_TYPE;
protected:
void subthread_routine();

View File

@ -1,6 +1,7 @@
#pragma once
#include "modules/meta/event_module.hpp"
#include "modules/meta/types.hpp"
#include "settings.hpp"
POLYBAR_NS
@ -13,7 +14,7 @@ namespace modules {
class pulseaudio_module : public event_module<pulseaudio_module> {
public:
explicit pulseaudio_module(const bar_settings&, string);
explicit pulseaudio_module(const bar_settings&, string, const config&);
void teardown();
bool has_event();
@ -22,7 +23,7 @@ namespace modules {
string get_output();
bool build(builder* builder, const string& tag) const;
static constexpr auto TYPE = "internal/pulseaudio";
static constexpr auto TYPE = PULSEAUDIO_TYPE;
static constexpr auto EVENT_INC = "inc";
static constexpr auto EVENT_DEC = "dec";
@ -53,6 +54,7 @@ namespace modules {
atomic<bool> m_muted{false};
atomic<int> m_volume{0};
atomic<double> m_decibels{0};
atomic<bool> m_reverse_scroll{false};
};
} // namespace modules

View File

@ -2,6 +2,7 @@
#include "adapters/script_runner.hpp"
#include "modules/meta/base.hpp"
#include "modules/meta/types.hpp"
#include "utils/command.hpp"
#include "utils/io.hpp"
@ -10,7 +11,7 @@ POLYBAR_NS
namespace modules {
class script_module : public module<script_module> {
public:
explicit script_module(const bar_settings&, string);
explicit script_module(const bar_settings&, string, const config&);
void start() override;
void stop() override;
@ -20,7 +21,7 @@ namespace modules {
bool build(builder* builder, const string& tag) const;
static constexpr auto TYPE = "custom/script";
static constexpr auto TYPE = SCRIPT_TYPE;
protected:
bool check_condition();
@ -33,7 +34,9 @@ namespace modules {
static constexpr auto FORMAT_FAIL = "format-fail";
const bool m_tail;
const script_runner::interval m_interval{0};
const script_runner::interval m_interval_success{0};
const script_runner::interval m_interval_fail{0};
const script_runner::interval m_interval_if{0};
script_runner m_runner;

View File

@ -1,41 +0,0 @@
#if DEBUG
#pragma once
#include "modules/meta/static_module.hpp"
POLYBAR_NS
class connection;
namespace modules {
/**
* Module used to display information about the
* currently active X window.
*/
class systray_module : public static_module<systray_module> {
public:
explicit systray_module(const bar_settings&, string);
void update();
bool build(builder* builder, const string& tag) const;
static constexpr auto TYPE = "internal/systray";
static constexpr auto EVENT_TOGGLE = "toggle";
protected:
void action_toggle();
private:
static constexpr const char* TAG_LABEL_TOGGLE{"<label-toggle>"};
static constexpr const char* TAG_TRAY_CLIENTS{"<tray-clients>"};
connection& m_connection;
label_t m_label;
bool m_hidden{false};
};
} // namespace modules
POLYBAR_NS_END
#endif

View File

@ -3,6 +3,7 @@
#include <istream>
#include "modules/meta/timer_module.hpp"
#include "modules/meta/types.hpp"
#include "settings.hpp"
POLYBAR_NS
@ -12,13 +13,13 @@ namespace modules {
class temperature_module : public timer_module<temperature_module> {
public:
explicit temperature_module(const bar_settings&, string);
explicit temperature_module(const bar_settings&, string, const config&);
bool update();
string get_format() const;
bool build(builder* builder, const string& tag) const;
static constexpr auto TYPE = "internal/temperature";
static constexpr auto TYPE = TEMPERATURE_TYPE;
private:
static constexpr auto TAG_LABEL = "<label>";
@ -30,6 +31,7 @@ namespace modules {
ramp_t m_ramp;
string m_path;
string m_zone_type;
int m_zone = 0;
// Base temperature used for where to start the ramp
int m_tempbase = 0;

View File

@ -1,19 +1,28 @@
#pragma once
#include "modules/meta/static_module.hpp"
#include "modules/meta/types.hpp"
POLYBAR_NS
namespace modules {
class text_module : public static_module<text_module> {
public:
explicit text_module(const bar_settings&, string);
explicit text_module(const bar_settings&, string, const config&);
void update() {}
string get_format() const;
string get_output();
bool build(builder* builder, const string& tag) const;
static constexpr auto TYPE = "custom/text";
static constexpr auto TYPE = TEXT_TYPE;
private:
static constexpr const char* TAG_LABEL{"<label>"};
label_t m_label;
string m_format{DEFAULT_FORMAT};
};
} // namespace modules

39
include/modules/tray.hpp Normal file
View File

@ -0,0 +1,39 @@
#pragma once
#include "common.hpp"
#include "components/bar.hpp"
#include "modules/meta/static_module.hpp"
#include "modules/meta/types.hpp"
#include "x11/tray_manager.hpp"
POLYBAR_NS
namespace modules {
/**
* Wraps the tray_manager in a module.
*
* The module produces the `%{Pt}` formatting tag, which is used by the renderer
* to place the tray.
* The visibility of the tray icons is directly tied to the visibility of the
* module.
*/
class tray_module : public static_module<tray_module> {
public:
explicit tray_module(const bar_settings& bar_settings, string name_, const config&);
string get_format() const;
void set_visible(bool value) override;
void start() override;
bool build(builder* builder, const string& tag) const;
void update() {}
static constexpr auto TYPE = TRAY_TYPE;
private:
static constexpr const char* TAG_TRAY{"<tray>"};
tray::manager m_tray;
};
} // namespace modules
POLYBAR_NS_END

View File

@ -1,71 +0,0 @@
#pragma once
#include "modules/meta/base.hpp"
#include "modules/meta/base.inl"
POLYBAR_NS
namespace modules {
struct module_interface;
#define DEFINE_UNSUPPORTED_MODULE(MODULE_NAME, MODULE_TYPE) \
class MODULE_NAME : public module_interface { \
public: \
MODULE_NAME(const bar_settings, string) { \
throw application_error("No built-in support for '" + string{MODULE_TYPE} + "'"); \
} \
static constexpr auto TYPE = MODULE_TYPE; \
string type() const override { \
return ""; \
} \
string name_raw() const override { \
return ""; \
} \
string name() const override { \
return ""; \
} \
bool running() const override { \
return false; \
} \
bool visible() const override { \
return false; \
} \
void start() override {} \
void stop() override {} \
void join() override {} \
void halt(string) override {} \
string contents() override { \
return ""; \
} \
bool input(const string&, const string&) override { \
return false; \
} \
}
#if not ENABLE_I3
DEFINE_UNSUPPORTED_MODULE(i3_module, "internal/i3");
#endif
#if not ENABLE_DWM
DEFINE_UNSUPPORTED_MODULE(dwm_module, "internal/dwm");
#endif
#if not ENABLE_MPD
DEFINE_UNSUPPORTED_MODULE(mpd_module, "internal/mpd");
#endif
#if not ENABLE_NETWORK
DEFINE_UNSUPPORTED_MODULE(network_module, "internal/network");
#endif
#if not ENABLE_ALSA
DEFINE_UNSUPPORTED_MODULE(alsa_module, "internal/alsa");
#endif
#if not ENABLE_PULSEAUDIO
DEFINE_UNSUPPORTED_MODULE(pulseaudio_module, "internal/pulseaudio");
#endif
#if not ENABLE_CURL
DEFINE_UNSUPPORTED_MODULE(github_module, "internal/github");
#endif
#if not ENABLE_XKEYBOARD
DEFINE_UNSUPPORTED_MODULE(xkeyboard_module, "internal/xkeyboard");
#endif
} // namespace modules
POLYBAR_NS_END

View File

@ -3,6 +3,7 @@
#include "components/config.hpp"
#include "modules/meta/event_handler.hpp"
#include "modules/meta/static_module.hpp"
#include "modules/meta/types.hpp"
#include "settings.hpp"
#include "x11/extensions/randr.hpp"
@ -24,13 +25,13 @@ namespace modules {
*/
class xbacklight_module : public static_module<xbacklight_module>, public event_handler<evt::randr_notify> {
public:
explicit xbacklight_module(const bar_settings& bar, string name_);
explicit xbacklight_module(const bar_settings& bar, string name_, const config&);
void update();
string get_output();
bool build(builder* builder, const string& tag) const;
static constexpr auto TYPE = "internal/xbacklight";
static constexpr auto TYPE = XBACKLIGHT_TYPE;
static constexpr const char* EVENT_INC = "inc";
static constexpr const char* EVENT_DEC = "dec";

Some files were not shown because too many files have changed in this diff Show More