-----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 Language: Cpp
Standard: Cpp11 Standard: c++17
BasedOnStyle: Google BasedOnStyle: Google
ColumnLimit: 120 ColumnLimit: 120
NamespaceIndentation: All NamespaceIndentation: Inner
AlignAfterOpenBracket: DontAlign AlignAfterOpenBracket: DontAlign
AllowShortFunctionsOnASingleLine: Empty AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: false AllowShortIfStatementsOnASingleLine: false

View File

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

View File

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

View File

@ -1,4 +1,4 @@
name: Bug Report name: 🐞 Bug Report
description: Create a report for something that misbehaves description: Create a report for something that misbehaves
title: "[Bug]: " title: "[Bug]: "
labels: ["bug", "needs confirmation"] labels: ["bug", "needs confirmation"]
@ -33,7 +33,7 @@ body:
id: config id: config
attributes: attributes:
label: Minimal config 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 render: dosini
placeholder: | placeholder: |
[bar/example] [bar/example]
@ -103,7 +103,7 @@ body:
id: context id: context
attributes: attributes:
label: Additional Context / Screenshots 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: validations:
required: false required: false
- type: markdown - 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 blank_issues_enabled: false
contact_links: contact_links:
- name: Polybar Gitter Room - name: 🙋 Ask a question
url: https://gitter.im/polybar/polybar url: https://github.com/polybar/polybar/blob/master/SUPPORT.md
about: Please ask and answer questions here. about: Have a look at our support resources and channels
- name: Polybar subreddit - name: 💡 Feature request
url: https://www.reddit.com/r/polybar url: https://github.com/polybar/polybar/discussions/categories/ideas
about: Please ask and answer questions here. 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: jobs:
docs: docs:
runs-on: ubuntu-20.04 runs-on: ubuntu-22.04
env: env:
COLOR: "ON" COLOR: "ON"
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
with: with:
ref: ${{ github.event.inputs.ref }} ref: ${{ github.event.inputs.ref }}
- name: Install Dependencies - name: Install Dependencies
@ -29,7 +29,7 @@ jobs:
make doc make doc
ipc: ipc:
runs-on: ubuntu-20.04 runs-on: ubuntu-22.04
env: env:
COLOR: "ON" COLOR: "ON"
steps: steps:
@ -48,7 +48,7 @@ jobs:
python3-xcbgen \ python3-xcbgen \
libuv1-dev \ libuv1-dev \
xcb-proto xcb-proto
- uses: actions/checkout@v2 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
ref: ${{ github.event.inputs.ref }} ref: ${{ github.event.inputs.ref }}
@ -60,7 +60,7 @@ jobs:
make polybar-msg make polybar-msg
build: build:
runs-on: ubuntu-20.04 runs-on: ubuntu-22.04
strategy: strategy:
matrix: matrix:
cxx: [g++, clang++] cxx: [g++, clang++]
@ -115,7 +115,7 @@ jobs:
if [ "$POLYBAR_BUILD_TYPE" = "tests" ]; then if [ "$POLYBAR_BUILD_TYPE" = "tests" ]; then
sudo apt-get install -y lcov sudo apt-get install -y lcov
fi fi
- uses: actions/checkout@v2 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
ref: ${{ github.event.inputs.ref }} ref: ${{ github.event.inputs.ref }}
@ -125,7 +125,7 @@ jobs:
run: ./common/ci/configure.sh run: ./common/ci/configure.sh
- name: Build - name: Build
run: | run: |
cd $BUILD_DIR cd "$BUILD_DIR"
make make
- name: Collect initial coverage - name: Collect initial coverage
if: ${{ matrix.polybar_build_type == 'tests' }} if: ${{ matrix.polybar_build_type == 'tests' }}
@ -134,17 +134,17 @@ jobs:
- name: Tests - name: Tests
if: ${{ matrix.polybar_build_type == 'tests' }} if: ${{ matrix.polybar_build_type == 'tests' }}
run: | run: |
cd $BUILD_DIR cd "$BUILD_DIR"
make check make check
- name: Collect coverage - name: Collect coverage
if: ${{ matrix.polybar_build_type == 'tests' }} if: ${{ matrix.polybar_build_type == 'tests' }}
run: | run: |
lcov --capture --no-external --directory . -o cov_tests.info 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 --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 - name: Upload Coverage
if: ${{ matrix.polybar_build_type == 'tests' }} if: ${{ matrix.polybar_build_type == 'tests' }}
uses: codecov/codecov-action@v2 uses: codecov/codecov-action@v3
with: with:
flags: unittests flags: unittests
files: ./cov.info files: ./cov.info

View File

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

6
.gitignore vendored
View File

@ -8,4 +8,10 @@
.tags .tags
*.user *.user
# clangd
/.cache
polybar-*.tar 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)) - `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)) - `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 ## [3.6.3] - 2022-05-04
### Fixed ### Fixed
- `custom/script`: Output clearing when `exec-if` fails ([`#2674`](https://github.com/polybar/polybar/issues/2674)) - `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 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). - 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. - 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 ### Build
- New dependency: [libuv](https://github.com/libuv/libuv). At least version 1.3 is required. - 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 ### Fixed
- Empty color values are no longer treated as invalid and no longer produce an error. - 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.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.2]: https://github.com/polybar/polybar/releases/tag/3.6.2
[3.6.1]: https://github.com/polybar/polybar/releases/tag/3.6.1 [3.6.1]: https://github.com/polybar/polybar/releases/tag/3.6.1

View File

@ -22,6 +22,14 @@ else()
set(APP_VERSION "${version_txt}") set(APP_VERSION "${version_txt}")
endif() 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 list(APPEND CMAKE_MODULE_PATH
${PROJECT_SOURCE_DIR}/cmake ${PROJECT_SOURCE_DIR}/cmake
${PROJECT_SOURCE_DIR}/cmake/common ${PROJECT_SOURCE_DIR}/cmake/common
@ -60,10 +68,9 @@ if(BUILD_TESTS)
add_subdirectory(tests) add_subdirectory(tests)
endif() endif()
if(BUILD_CONFIG) if(BUILD_CONFIG)
install(FILES ${CMAKE_SOURCE_DIR}/doc/config.ini install(FILES ${CMAKE_SOURCE_DIR}/doc/config.ini
DESTINATION /etc/${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/${PROJECT_NAME}
COMPONENT config) COMPONENT config)
endif() endif()

View File

@ -53,7 +53,8 @@ PR being rejected because the feature you implemented was not actually something
we want in polybar. we want in polybar.
Issues with any of the following labels are generally safe to start working on, 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) * [bug](https://github.com/polybar/polybar/labels/bug)
* [confirmed](https://github.com/polybar/polybar/labels/confirmed) * [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. However, this is not always possible, for example when working on modules.
But at least isolated components should be tested. But at least isolated components should be tested.
See the [testing page](https://github.com/polybar/polybar/wiki/Testing) on the See the [testing
wiki for more information. 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 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. and some things may be harder/impossible to test right now.
@ -153,7 +155,8 @@ repo.
### Style ### 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 ## Donations

View File

@ -1,5 +1,6 @@
<p align="center"> <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>
<p align="center"> <p align="center">
@ -40,6 +41,7 @@ for their desktop environment, without the need of having a black belt in shell
* [Sponsors](#sponsors) * [Sponsors](#sponsors)
* [Backers](#backers) * [Backers](#backers)
* [License](#license) * [License](#license)
* [Signatures](#signatures)
## Introduction ## 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) 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) 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 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 If you are using **Ubuntu** 20.10 (Groovy Gorilla) or later, you can install polybar
using `sudo apt install polybar`. using `sudo apt install polybar`.
If you are using **Arch Linux**, you can install the AUR package If you are using **Arch Linux**, you can install
[polybar](https://aur.archlinux.org/packages/polybar/) to get the latest [polybar](https://archlinux.org/packages/community/x86_64/polybar/) to get the
version, or [polybar-git](https://aur.archlinux.org/packages/polybar-git/) for latest stable release using `sudo pacman -S polybar`. The latest unstable
the most up-to-date (unstable) changes. 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`. 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 **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 [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`. 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 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.
[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 **Gentoo**, both release and git-master versions are available in the [main](https://packages.gentoo.org/packages/x11-misc/polybar) repository. 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 ## Community
Want to get in touch? Want to get in touch?
* Join our Gitter room at [gitter.im/polybar/polybar](https://gitter.im/polybar/polybar) * Visit our [Discussion page](https://github.com/polybar/polybar/discussions)
* We have our own subreddit at [r/polybar](https://www.reddit.com/r/polybar). * Join our Gitter room at [`gitter.im/polybar/polybar`](https://gitter.im/polybar/polybar)
* Chat with us in the `#polybar` IRC channel on the [`irc.libera.chat:6697`](https://libera.chat/) server. * 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 ## Contributors
### Maintainers
* Patrick Ziegler [**@patrick96**](https://github.com/patrick96)
### Owner ### Owner
* Michael Carlberg [**@jaagr**](https://github.com/jaagr/) * Michael Carlberg [**@jaagr**](https://github.com/jaagr/)
### Maintainers ### Former Maintainers
* [**@Lomadriel**](https://github.com/Lomadriel)
* [**@NBonaparte**](https://github.com/NBonaparte) * [**@NBonaparte**](https://github.com/NBonaparte)
* Chase Geigle [**@skystrife**](https://github.com/skystrife) * Chase Geigle [**@skystrife**](https://github.com/skystrife)
* Patrick Ziegler [**@patrick96**](https://github.com/patrick96)
### Logo Design by ### Logo Design by
* [**@Tobaloidee**](https://github.com/Tobaloidee) * [**@Tobaloidee**](https://github.com/Tobaloidee)
@ -227,3 +234,9 @@ Polybar accepts donations through [open collective](https://opencollective.com/p
## License ## License
Polybar is licensed under the MIT license. [See LICENSE for more information](https://github.com/polybar/polybar/blob/master/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 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). * 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 [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. * 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 your question on [GitHub Discussions](https://github.com/polybar/polybar/discussions)
* Ask in our reddit community at [r/polybar](https://www.reddit.com/r/polybar) * Join our Gitter room at [`gitter.im/polybar/polybar`](https://gitter.im/polybar/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 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). * 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") CACHE STRING "Path to file containing the current temperature")
set(SETTING_PATH_TEMPERATURE_INFO "/sys/class/thermal/thermal_zone%zone%/temp" set(SETTING_PATH_TEMPERATURE_INFO "/sys/class/thermal/thermal_zone%zone%/temp"
CACHE STRING "Path to file containing the current temperature") 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 # folders where the clang tools should operate
set(CLANG_SEARCH_PATHS ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/tests) 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) # Dry-runs clang-format on all source files
add_custom_command(TARGET codeformat # Useful for CI since it will exit with an error code
COMMAND ${PROJECT_SOURCE_DIR}/common/clang-format.sh ${CLANG_SEARCH_PATHS}) 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) {{{ # Target: codecheck (clang-tidy) {{{
add_custom_target(codecheck) add_custom_target(codecheck)

View File

@ -13,11 +13,12 @@ if (BUILD_DOC)
endif() endif()
message(STATUS " Install Paths:") message(STATUS " Install Paths:")
message_colored(STATUS " PREFIX: ${CMAKE_INSTALL_PREFIX}" "32") message_colored(STATUS " PREFIX: ${CMAKE_INSTALL_PREFIX}" "32")
message_colored(STATUS " BINDIR: ${CMAKE_INSTALL_FULL_BINDIR}" "32") message_colored(STATUS " BINDIR: ${CMAKE_INSTALL_FULL_BINDIR}" "32")
message_colored(STATUS " DATADIR: ${CMAKE_INSTALL_FULL_DATADIR}" "32") message_colored(STATUS " DATADIR: ${CMAKE_INSTALL_FULL_DATADIR}" "32")
message_colored(STATUS " DOCDIR: ${CMAKE_INSTALL_FULL_DOCDIR}" "32") message_colored(STATUS " DOCDIR: ${CMAKE_INSTALL_FULL_DOCDIR}" "32")
message_colored(STATUS " MANDIR: ${CMAKE_INSTALL_FULL_MANDIR}" "32") message_colored(STATUS " MANDIR: ${CMAKE_INSTALL_FULL_MANDIR}" "32")
message_colored(STATUS " SYSCONFDIR: ${CMAKE_INSTALL_FULL_SYSCONFDIR}" "32")
message(STATUS " Targets:") message(STATUS " Targets:")
colored_option(" polybar" BUILD_POLYBAR) colored_option(" polybar" BUILD_POLYBAR)

View File

@ -15,20 +15,19 @@ endif()
option(CXXLIB_CLANG "Link against libc++" OFF) option(CXXLIB_CLANG "Link against libc++" OFF)
option(CXXLIB_GCC "Link against stdlibc++" 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_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_EXTENSIONS OFF)
set(THREADS_PREFER_PTHREAD_FLAG ON) set(THREADS_PREFER_PTHREAD_FLAG ON)
set(POLYBAR_FLAGS "" CACHE STRING "C++ compiler flags used for compiling polybar") set(POLYBAR_FLAGS "" CACHE STRING "C++ compiler flags used for compiling polybar")
list(APPEND cxx_base -Wall -Wextra -Wpedantic) list(APPEND cxx_base -Wall -Wextra -Wpedantic -Wdeprecated-copy-dtor)
list(APPEND cxx_debug -DDEBUG -g2) list(APPEND cxx_debug -DDEBUG -g2 -Og)
list(APPEND cxx_minsizerel "") 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_sanitize ${cxx_debug} -O0 -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer -fno-optimize-sibling-calls)
list(APPEND cxx_coverage --coverage) list(APPEND cxx_coverage ${cxx_debug} --coverage)
list(APPEND cxx_linker_base "") list(APPEND cxx_linker_base "")
list(APPEND cxx_linker_minsizerel "") list(APPEND cxx_linker_minsizerel "")
@ -79,8 +78,6 @@ elseif(CXXLIB_GCC)
list(APPEND cxx_linker_base -lstdc++) list(APPEND cxx_linker_base -lstdc++)
endif() 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_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_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}") 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> # Maintainer: Patrick Ziegler <p.ziegler96@gmail.com>
_pkgname=polybar _pkgname=polybar
pkgname="${_pkgname}-git" pkgname="${_pkgname}-git"
pkgver=3.5.7 pkgver=3.6.3
pkgrel=1 pkgrel=1
pkgdesc="A fast and easy-to-use status bar" 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" url="https://github.com/polybar/polybar"
license=("MIT") license=("MIT")
depends=("libuv" "cairo" "xcb-util-image" "xcb-util-wm" "xcb-util-xrm" depends=("libuv" "cairo" "xcb-util-image" "xcb-util-wm" "xcb-util-xrm"
"xcb-util-cursor" "alsa-lib" "libpulse" "libmpdclient" "libnl" "xcb-util-cursor" "alsa-lib" "libpulse" "libmpdclient" "libnl"
"jsoncpp" "curl") "jsoncpp" "curl")
optdepends=("i3-wm: i3 module support" 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" "git" "python" "pkg-config" "python-sphinx" makedepends=("cmake" "git" "python" "pkg-config" "python-sphinx"
"python-packaging" "i3-wm") "python-packaging" "i3-wm")
backup=("etc/polybar/config.ini")
provides=("polybar") provides=("polybar")
conflicts=("polybar") conflicts=("polybar")
install="${_pkgname}.install"
source=("${_pkgname}::git+${url}.git") source=("${_pkgname}::git+${url}.git")
sha256sums=("SKIP") 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,49 +18,57 @@ import datetime
import sphinx import sphinx
import packaging.version import packaging.version
def get_version(root_path): from sphinx.util.docfields import Field
""" from sphinx.locale import _
Reads the polybar version from the version.txt at the root of the repo.
"""
path = Path(root_path) / "version.txt"
with open(path, "r") as f:
for line in f.readlines():
if not line.startswith("#"):
# NB: we can't parse it yet since sphinx could import
# pkg_resources later on and it could patch packaging.version
return line
raise RuntimeError("No version found in {}".format(path))
def get_version(root_path):
"""
Reads the polybar version from the version.txt at the root of the repo.
"""
path = Path(root_path) / "version.txt"
with open(path, "r") as f:
for line in f.readlines():
if not line.startswith("#"):
# NB: we can't parse it yet since sphinx could import
# pkg_resources later on and it could patch packaging.version
return line
raise RuntimeError("No version found in {}".format(path))
sphinx_version = packaging.version.parse(sphinx.__version__)
# -- Project information ----------------------------------------------------- # -- Project information -----------------------------------------------------
project = 'Polybar User Manual' project = 'Polybar User Manual'
copyright = '2016-{}, Michael Carlberg & contributors'.format( copyright = '2016-{}, Michael Carlberg & contributors'.format(
datetime.datetime.now().year datetime.datetime.now().year
) )
author = 'Polybar Team' author = 'Polybar Team'
# is whether we are on readthedocs.io # is whether we are on readthedocs.io
on_rtd = os.environ.get('READTHEDOCS', None) == 'True' on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
if on_rtd: if on_rtd:
# On readthedocs, cmake isn't run so the version string isn't available # On readthedocs, cmake isn't run so the version string isn't available
version = os.environ.get('READTHEDOCS_VERSION', None) version = os.environ.get('READTHEDOCS_VERSION', None)
else: else:
# The short X.Y version # The short X.Y version
version = '@APP_VERSION@' version = '@APP_VERSION@'
# The full version, including alpha/beta/rc tags # The full version, including alpha/beta/rc tags
release = version release = version
# Set path to documentation # Set path to documentation
if on_rtd: if on_rtd:
# On readthedocs conf.py is already in the doc folder # On readthedocs conf.py is already in the doc folder
doc_path = '.' doc_path = '.'
else: else:
# In all other builds conf.py is configured with cmake and put into the # In all other builds conf.py is configured with cmake and put into the
# build folder. # build folder.
doc_path = '@doc_path@' doc_path = '@doc_path@'
# The version from the version.txt file. Since we are not always first # The version from the version.txt file. Since we are not always first
# configured by cmake, we don't necessarily have access to the current version # configured by cmake, we don't necessarily have access to the current version
@ -77,8 +85,18 @@ version_txt = get_version(Path(doc_path).absolute().parent)
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones. # ones.
extensions = [ 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. # Add any paths that contain templates here, relative to this directory.
templates_path = [doc_path + '/_templates'] templates_path = [doc_path + '/_templates']
@ -96,7 +114,7 @@ master_doc = 'index'
# #
# This is also used if you do content translation via gettext catalogs. # This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases. # 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 # List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files. # directories to ignore when looking for source files.
@ -110,22 +128,45 @@ highlight_language = 'none'
smartquotes = False 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 ------------------------------------------------- # -- Options for HTML output -------------------------------------------------
# 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'
else:
html_theme = 'alabaster'
# Theme options are theme-specific and customize the look and feel of a theme # 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 # further. For a list of options available for each theme, see the
# documentation. # documentation.
# #
# html_theme_options = {} 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'
html_theme_options['description'] = version
# Add any paths that contain custom static files (such as style sheets) here, # 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, # 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 # One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section). # (source start file, name, description, authors, manual section).
man_pages = [ 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.1', 'polybar',
('man/polybar.5', 'polybar', 'configuration file for polybar(1)', [], 5) '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 man_make_section_directory = False
@ -223,33 +273,82 @@ epub_exclude_files = ['search.html']
# The 'versionadded' and 'versionchanged' directives are overridden. # The 'versionadded' and 'versionchanged' directives are overridden.
suppress_warnings = ['app.add_directive'] 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 # 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. # 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 # 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 # built from master, documentation built for proper releases should not even
# mention unreleased changes. Because of that it's not that important that this # mention unreleased changes. Because of that it's not that important that this
# is added to local builds. # 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 typing import List
from docutils.nodes import Node from docutils.nodes import Node
from sphinx.domains.changeset import VersionChange from sphinx.domains.changeset import VersionChange
def setup(app): def inject_version_directives(app):
app.add_directive('deprecated', VersionDirective) app.add_directive('deprecated', VersionDirective)
app.add_directive('versionadded', VersionDirective) app.add_directive('versionadded', VersionDirective)
app.add_directive('versionchanged', VersionDirective) app.add_directive('versionchanged', VersionDirective)
class VersionDirective(VersionChange): class VersionDirective(VersionChange):
""" """
Overwrites the Sphinx directive for versionchanged, versionadded, and 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)
if directive_version > parsed_version_txt: def run(self) -> List[Node]:
self.arguments[0] += " (unreleased)" directive_version = packaging.version.parse(self.arguments[0])
parsed_version_txt = packaging.version.parse(version_txt)
return super().run() if directive_version > parsed_version_txt:
self.arguments[0] += " (unreleased)"
return super().run()

View File

@ -58,14 +58,18 @@ cursor-scroll = ns-resize
enable-ipc = true enable-ipc = true
; tray-position = right
; wm-restack = generic ; wm-restack = generic
; wm-restack = bspwm ; wm-restack = bspwm
; wm-restack = i3 ; wm-restack = i3
; override-redirect = true ; override-redirect = true
[module/systray]
type = internal/tray
format-margin = 8pt
tray-spacing = 16pt
[module/xworkspaces] [module/xworkspaces]
type = internal/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 Finishing Up
------------ ------------
Finally, subscribe to our `GitHub thread for package maintainers Finally, subscribe to our :issue:`GitHub thread for package maintainers <1971>`
<https://github.com/polybar/polybar/issues/1971>`_ to get notified about new to get notified about new releases and changes to how polybar is built.
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 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 Started <https://github.com/polybar/polybar#getting-started>`_ section of our
README. 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 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 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 a maintainer to create the release branch since they will also need to create
`Release Commit`_ to it. a `Release PR`_ for it.
Once the release branch is created and contains the right commits, the Once the release branch is created and contains the right commits, the
maintainer should follow `Publishing a new Release`_ to finish this patch 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 The process for publishing a release is the same for all release types. It goes
as follows: as follows:
* A `Release commit`_ is added to the tip of the release branch. * A `Release PR`_ is created for the release. This PR MUST NOT be merged in
* A draft PR is opened for the release branch. This PR MUST NOT be merged in
GitHub's interface, it is only here for review, merging happens at the GitHub's interface, it is only here for review, merging happens at the
commandline. commandline.
* A `draft release`_ is created in GitHub's release publishing tools * After approval, a signed git tag without message is created locally at the
* After approval, the GitHub release publishing tool is used to publish the tip of the release branch and pushed:
release and tag the tip of the release branch (the release commit).
.. 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 * After the tag is created, the release branch is manually merged into
``master``. ``master``.
Here it is vitally important that the history of the release branch does not 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 Here ``<release-branch>`` is either a ``release/X.Y.0`` branch or a
``hotfix/X.Y.Z`` branch. ``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 Changelog
~~~~~~~~~ ~~~~~~~~~
@ -193,8 +206,8 @@ Draft Release
On `GitHub <https://github.com/polybar/polybar/releases/new>`_ a new release On `GitHub <https://github.com/polybar/polybar/releases/new>`_ a new release
should be drafted. should be drafted.
The release targets the tip of the release branch (the release commit), the The release targets the git tag that was just pushed, the name of the release
name of the release and the tag is simply the release number. and the tag is simply the release number.
The content of the release message should contain the changelog copied from The content of the release message should contain the changelog copied from
``CHANGELOG.md`` under the heading ``## Changelog``. ``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. new contributors should be generated and put at the end of the release notes.
The generated list of PRs can be removed. 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 After-Release Checklist
~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~
* Make sure all the new functionality is documented on the wiki * Verify the release archive (see `Verify Release`_)
* Mark deprecated features appropriately (see `Deprecations`_) * Update the Wiki
* Remove all unreleased notes from the wiki (not for patch releases)
* Inform packagers of new release in `#1971 * Make sure all the new functionality is documented
<https://github.com/polybar/polybar/issues/1971>`_. Mention any dependency * Mark deprecated features appropriately (see `Deprecations`_)
* 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 changes and any changes to the build workflow. Also mention any new files are
created by the installation. created by the installation.
* Confirm that the release archive was added to the release. * Create a PR that updates the AUR ``PKGBUILD`` file for the ``polybar-git``
We have a GitHub action workflow called 'Release Workflow' that on every package (push after the release archive is uploaded).
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).
* Close the `GitHub Milestone <https://github.com/polybar/polybar/milestones>`_ * Close the `GitHub Milestone <https://github.com/polybar/polybar/milestones>`_
for the new release and move open issues (if any) to a later release. for the new release and move open issues (if any) to a later release.
* Activate the version on `Read the Docs * 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 previous versions for the same minor release (e.g. for 3.5.4, deactivate all
other 3.5.X versions). 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 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/actions
user/ipc user/ipc
user/modules/index
user/fonts/index
user/default-config
migration/index
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1
@ -33,6 +37,9 @@ Welcome to the official polybar documentation.
:maxdepth: 1 :maxdepth: 1
:caption: Developer Documentation: :caption: Developer Documentation:
dev/getting-started
dev/style-guide
dev/testing
dev/release-workflow dev/release-workflow
Getting Help 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 #pragma once
#ifdef USE_ALSALIB_H
#include <alsa/asoundlib.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 "common.hpp"
#include "settings.hpp" #include "settings.hpp"

View File

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

View File

@ -5,6 +5,7 @@
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include <deque> #include <deque>
#include <iomanip>
#include <iterator> #include <iterator>
#include "cairo/font.hpp" #include "cairo/font.hpp"
@ -163,9 +164,21 @@ namespace cairo {
std::iter_swap(fns.begin(), fns.begin() + t.font - 1); std::iter_swap(fns.begin(), fns.begin() + t.font - 1);
} }
string utf8 = string(t.contents); string utf8 = t.contents;
utils::unicode_charlist chars; string_util::unicode_charlist chars;
utils::utf8_to_ucs4((const unsigned char*)utf8.c_str(), 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()) { while (!chars.empty()) {
auto remaining = chars.size(); auto remaining = chars.size();
@ -196,6 +209,12 @@ namespace cairo {
cairo_text_extents_t extents; cairo_text_extents_t extents;
f->textwidth(subset, &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 // Draw the background
if (t.bg_rect.h != 0.0) { if (t.bg_rect.h != 0.0) {
save(); save();
@ -228,9 +247,9 @@ namespace cairo {
continue; continue;
} }
char unicode[6]{'\0'}; std::array<char, 5> unicode{};
utils::ucs4_to_utf8(unicode, chars.begin()->codepoint); string_util::ucs4_to_utf8(unicode, chars.begin()->codepoint);
m_log.warn("Dropping unmatched character %s (U+%04x) in '%s'", unicode, chars.begin()->codepoint, t.contents); 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); utf8.erase(chars.begin()->offset, chars.begin()->length);
for (auto&& c : chars) { for (auto&& c : chars) {
c.offset -= chars.begin()->length; c.offset -= chars.begin()->length;

View File

@ -15,327 +15,328 @@
POLYBAR_NS POLYBAR_NS
namespace cairo { namespace cairo {
/** /**
* @brief Global pointer to the Freetype library handler * @brief Global pointer to the Freetype library handler
*/ */
static FT_Library g_ftlib; static FT_Library g_ftlib;
/**
* @brief Abstract font face
*/
class font {
public:
explicit font(cairo_t* cairo, double offset) : m_cairo(cairo), m_offset(offset) {}
virtual ~font(){};
virtual string name() const = 0;
virtual string file() const = 0;
virtual double offset() const = 0;
virtual double size(double dpi) const = 0;
virtual cairo_font_extents_t extents() = 0;
virtual void use() {
cairo_set_font_face(m_cairo, cairo_font_face_reference(m_font_face));
}
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;
protected:
cairo_t* m_cairo;
cairo_font_face_t* m_font_face{nullptr};
cairo_font_extents_t m_extents{};
double m_offset{0.0};
};
/**
* @brief Font based on fontconfig/freetype
*/
class font_fc : public font {
public:
explicit font_fc(cairo_t* cairo, FcPattern* pattern, double offset, double dpi_x, double dpi_y)
: font(cairo, offset), m_pattern(pattern) {
cairo_matrix_t fm;
cairo_matrix_t ctm;
cairo_matrix_init_scale(&fm, size(dpi_x), size(dpi_y));
cairo_get_matrix(m_cairo, &ctm);
auto fontface = cairo_ft_font_face_create_for_pattern(m_pattern);
auto opts = cairo_font_options_create();
m_scaled = cairo_scaled_font_create(fontface, &fm, &ctm, opts);
cairo_font_options_destroy(opts);
cairo_font_face_destroy(fontface);
auto status = cairo_scaled_font_status(m_scaled);
if (status != CAIRO_STATUS_SUCCESS) {
throw application_error(sstream() << "cairo_scaled_font_create(): " << cairo_status_to_string(status));
}
auto lock = make_unique<utils::ft_face_lock>(m_scaled);
auto face = static_cast<FT_Face>(*lock);
if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) == FT_Err_Ok) {
return;
} else if (FT_Select_Charmap(face, FT_ENCODING_BIG5) == FT_Err_Ok) {
return;
} else if (FT_Select_Charmap(face, FT_ENCODING_SJIS) == FT_Err_Ok) {
return;
}
lock.reset();
}
~font_fc() override {
if (m_scaled != nullptr) {
cairo_scaled_font_destroy(m_scaled);
}
if (m_pattern != nullptr) {
FcPatternDestroy(m_pattern);
}
}
cairo_font_extents_t extents() override {
cairo_scaled_font_extents(m_scaled, &m_extents);
return m_extents;
}
string name() const override {
return property("family");
}
string file() const override {
return property("file");
}
double offset() const override {
return m_offset;
}
/** /**
* @brief Abstract font face * Calculates the font size in pixels for the given dpi
*
* We use the two font properties size and pixelsize. size is in points and
* needs to be scaled with the given dpi. pixelsize is not scaled.
*
* If both size properties are 0, we fall back to a default value of 10
* points for scalable fonts or 10 pixel for non-scalable ones. This should
* only happen if both properties are purposefully set to 0
*
* For scalable fonts we try to use the size property scaled according to
* the dpi.
* For non-scalable fonts we try to use the pixelsize property as-is
*/ */
class font { double size(double dpi) const override {
public: bool scalable;
explicit font(cairo_t* cairo, double offset) : m_cairo(cairo), m_offset(offset) {} double fc_pixelsize = 0, fc_size = 0;
virtual ~font(){};
virtual string name() const = 0; property(FC_SCALABLE, &scalable);
virtual string file() const = 0;
virtual double offset() const = 0;
virtual double size(double dpi) const = 0;
virtual cairo_font_extents_t extents() = 0; // Size in points
property(FC_SIZE, &fc_size);
virtual void use() { // Size in pixels
cairo_set_font_face(m_cairo, cairo_font_face_reference(m_font_face)); property(FC_PIXEL_SIZE, &fc_pixelsize);
}
virtual size_t match(utils::unicode_character& character) = 0; // Fall back to a default value if the size is 0
virtual size_t match(utils::unicode_charlist& charlist) = 0; double pixelsize = fc_pixelsize == 0 ? 10 : fc_pixelsize;
virtual size_t render(const string& text, double x = 0.0, double y = 0.0) = 0; double size = fc_size == 0 ? 10 : fc_size;
virtual void textwidth(const string& text, cairo_text_extents_t* extents) = 0;
protected: // Font size in pixels if we use the pixelsize property
cairo_t* m_cairo; int px_pixelsize = pixelsize + 0.5;
cairo_font_face_t* m_font_face{nullptr};
cairo_font_extents_t m_extents{};
double m_offset{0.0};
};
/** /*
* @brief Font based on fontconfig/freetype * Font size in pixels if we use the size property. Since the size
*/ * specifies the font size in points, this is converted to pixels
class font_fc : public font { * according to the dpi given.
public: * One point is 1/72 inches, thus this gives us the number of 'dots'
explicit font_fc(cairo_t* cairo, FcPattern* pattern, double offset, double dpi_x, double dpi_y) * (or pixels) for this font
: font(cairo, offset), m_pattern(pattern) {
cairo_matrix_t fm;
cairo_matrix_t ctm;
cairo_matrix_init_scale(&fm, size(dpi_x), size(dpi_y));
cairo_get_matrix(m_cairo, &ctm);
auto fontface = cairo_ft_font_face_create_for_pattern(m_pattern);
auto opts = cairo_font_options_create();
m_scaled = cairo_scaled_font_create(fontface, &fm, &ctm, opts);
cairo_font_options_destroy(opts);
cairo_font_face_destroy(fontface);
auto status = cairo_scaled_font_status(m_scaled);
if (status != CAIRO_STATUS_SUCCESS) {
throw application_error(sstream() << "cairo_scaled_font_create(): " << cairo_status_to_string(status));
}
auto lock = make_unique<utils::ft_face_lock>(m_scaled);
auto face = static_cast<FT_Face>(*lock);
if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) == FT_Err_Ok) {
return;
} else if (FT_Select_Charmap(face, FT_ENCODING_BIG5) == FT_Err_Ok) {
return;
} else if (FT_Select_Charmap(face, FT_ENCODING_SJIS) == FT_Err_Ok) {
return;
}
lock.reset();
}
~font_fc() override {
if (m_scaled != nullptr) {
cairo_scaled_font_destroy(m_scaled);
}
if (m_pattern != nullptr) {
FcPatternDestroy(m_pattern);
}
}
cairo_font_extents_t extents() override {
cairo_scaled_font_extents(m_scaled, &m_extents);
return m_extents;
}
string name() const override {
return property("family");
}
string file() const override {
return property("file");
}
double offset() const override {
return m_offset;
}
/**
* Calculates the font size in pixels for the given dpi
*
* We use the two font properties size and pixelsize. size is in points and
* needs to be scaled with the given dpi. pixelsize is not scaled.
*
* If both size properties are 0, we fall back to a default value of 10
* points for scalable fonts or 10 pixel for non-scalable ones. This should
* only happen if both properties are purposefully set to 0
*
* For scalable fonts we try to use the size property scaled according to
* the dpi.
* For non-scalable fonts we try to use the pixelsize property as-is
*/ */
double size(double dpi) const override { int px_size = size / 72.0 * dpi + 0.5;
bool scalable;
double fc_pixelsize = 0, fc_size = 0;
property(FC_SCALABLE, &scalable); if (fc_size == 0 && fc_pixelsize == 0) {
return scalable ? px_size : px_pixelsize;
// Size in points }
property(FC_SIZE, &fc_size);
// Size in pixels
property(FC_PIXEL_SIZE, &fc_pixelsize);
// Fall back to a default value if the size is 0
double pixelsize = fc_pixelsize == 0 ? 10 : fc_pixelsize;
double size = fc_size == 0 ? 10 : fc_size;
// Font size in pixels if we use the pixelsize property
int px_pixelsize = pixelsize + 0.5;
if (scalable) {
/* /*
* Font size in pixels if we use the size property. Since the size * Use the point size if it's not 0. The pixelsize is only used if the
* specifies the font size in points, this is converted to pixels * size property is 0 and pixelsize is not
* according to the dpi given.
* One point is 1/72 inches, thus this gives us the number of 'dots'
* (or pixels) for this font
*/ */
int px_size = size / 72.0 * dpi + 0.5; if (fc_size != 0) {
return px_size;
if (fc_size == 0 && fc_pixelsize == 0) {
return scalable ? px_size : px_pixelsize;
}
if (scalable) {
/*
* Use the point size if it's not 0. The pixelsize is only used if the
* size property is 0 and pixelsize is not
*/
if (fc_size != 0) {
return px_size;
} else {
return px_pixelsize;
}
} else { } else {
/* return px_pixelsize;
* Non-scalable fonts do it the other way around, here the size }
* property is only used if pixelsize is 0 and size is not } else {
*/ /*
if (fc_pixelsize != 0) { * Non-scalable fonts do it the other way around, here the size
return px_pixelsize; * property is only used if pixelsize is 0 and size is not
} else { */
return px_size; if (fc_pixelsize != 0) {
} return px_pixelsize;
} else {
return px_size;
}
}
}
void use() override {
cairo_set_scaled_font(m_cairo, m_scaled);
}
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(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;
for (auto&& c : charlist) {
if (FT_Get_Char_Index(face, c.codepoint)) {
available_chars++;
} else {
break;
} }
} }
void use() override { return available_chars;
cairo_set_scaled_font(m_cairo, m_scaled); }
size_t render(const string& text, double x = 0.0, double y = 0.0) override {
cairo_glyph_t* glyphs{nullptr};
cairo_text_cluster_t* clusters{nullptr};
cairo_text_cluster_flags_t cf{};
int nglyphs = 0;
int nclusters = 0;
string utf8 = string(text);
auto status = cairo_scaled_font_text_to_glyphs(
m_scaled, x, y, utf8.c_str(), utf8.size(), &glyphs, &nglyphs, &clusters, &nclusters, &cf);
if (status != CAIRO_STATUS_SUCCESS) {
throw application_error(sstream() << "cairo_scaled_font_text_to_glyphs() " << cairo_status_to_string(status));
} }
size_t match(utils::unicode_character& character) override { size_t bytes = 0;
auto lock = make_unique<utils::ft_face_lock>(m_scaled); for (int g = 0; g < nglyphs; g++) {
auto face = static_cast<FT_Face>(*lock); if (glyphs[g].index) {
return FT_Get_Char_Index(face, character.codepoint) ? 1 : 0; bytes += clusters[g].num_bytes;
} } else {
break;
size_t match(utils::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;
for (auto&& c : charlist) {
if (FT_Get_Char_Index(face, c.codepoint)) {
available_chars++;
} else {
break;
}
} }
return available_chars;
} }
size_t render(const string& text, double x = 0.0, double y = 0.0) override { if (bytes && bytes < text.size()) {
cairo_glyph_t* glyphs{nullptr}; cairo_glyph_free(glyphs);
cairo_text_cluster_t* clusters{nullptr}; cairo_text_cluster_free(clusters);
cairo_text_cluster_flags_t cf{};
int nglyphs = 0, nclusters = 0;
string utf8 = string(text); utf8 = text.substr(0, bytes);
auto status = cairo_scaled_font_text_to_glyphs( auto status = cairo_scaled_font_text_to_glyphs(
m_scaled, x, y, utf8.c_str(), utf8.size(), &glyphs, &nglyphs, &clusters, &nclusters, &cf); m_scaled, x, y, utf8.c_str(), utf8.size(), &glyphs, &nglyphs, &clusters, &nclusters, &cf);
if (status != CAIRO_STATUS_SUCCESS) { if (status != CAIRO_STATUS_SUCCESS) {
throw application_error(sstream() << "cairo_scaled_font_text_to_glyphs()" << cairo_status_to_string(status)); throw application_error(sstream() << "cairo_scaled_font_text_to_glyphs() " << cairo_status_to_string(status));
}
size_t bytes = 0;
for (int g = 0; g < nglyphs; g++) {
if (glyphs[g].index) {
bytes += clusters[g].num_bytes;
} else {
break;
}
}
if (bytes && bytes < text.size()) {
cairo_glyph_free(glyphs);
cairo_text_cluster_free(clusters);
utf8 = text.substr(0, bytes);
auto status = cairo_scaled_font_text_to_glyphs(
m_scaled, x, y, utf8.c_str(), utf8.size(), &glyphs, &nglyphs, &clusters, &nclusters, &cf);
if (status != CAIRO_STATUS_SUCCESS) {
throw application_error(sstream() << "cairo_scaled_font_text_to_glyphs()" << cairo_status_to_string(status));
}
}
if (bytes) {
// auto lock = make_unique<utils::device_lock>(cairo_surface_get_device(cairo_get_target(m_cairo)));
// if (lock.get()) {
// cairo_glyph_path(m_cairo, glyphs, nglyphs);
// }
cairo_text_extents_t extents{};
cairo_scaled_font_glyph_extents(m_scaled, glyphs, nglyphs, &extents);
cairo_show_text_glyphs(m_cairo, utf8.c_str(), utf8.size(), glyphs, nglyphs, clusters, nclusters, cf);
cairo_fill(m_cairo);
cairo_move_to(m_cairo, x + extents.x_advance, 0.0);
}
cairo_glyph_free(glyphs);
cairo_text_cluster_free(clusters);
return bytes;
}
void textwidth(const string& text, cairo_text_extents_t* extents) override {
cairo_scaled_font_text_extents(m_scaled, text.c_str(), extents);
}
protected:
string property(string&& property) const {
FcChar8* file;
if (FcPatternGetString(m_pattern, property.c_str(), 0, &file) == FcResultMatch) {
return string(reinterpret_cast<char*>(file));
} else {
return "";
} }
} }
void property(string&& property, bool* dst) const { if (bytes) {
FcBool b; // auto lock = make_unique<utils::device_lock>(cairo_surface_get_device(cairo_get_target(m_cairo)));
FcPatternGetBool(m_pattern, property.c_str(), 0, &b); // if (lock.get()) {
*dst = b; // cairo_glyph_path(m_cairo, glyphs, nglyphs);
// }
cairo_text_extents_t extents{};
cairo_scaled_font_glyph_extents(m_scaled, glyphs, nglyphs, &extents);
cairo_show_text_glyphs(m_cairo, utf8.c_str(), utf8.size(), glyphs, nglyphs, clusters, nclusters, cf);
cairo_fill(m_cairo);
cairo_move_to(m_cairo, x + extents.x_advance, 0.0);
} }
void property(string&& property, double* dst) const { cairo_glyph_free(glyphs);
FcPatternGetDouble(m_pattern, property.c_str(), 0, dst); cairo_text_cluster_free(clusters);
return bytes;
}
void textwidth(const string& text, cairo_text_extents_t* extents) override {
cairo_scaled_font_text_extents(m_scaled, text.c_str(), extents);
}
protected:
string property(string&& property) const {
FcChar8* file;
if (FcPatternGetString(m_pattern, property.c_str(), 0, &file) == FcResultMatch) {
return string(reinterpret_cast<char*>(file));
} else {
return "";
} }
}
void property(string&& property, int* dst) const { void property(string&& property, bool* dst) const {
FcPatternGetInteger(m_pattern, property.c_str(), 0, dst); FcBool b;
} FcPatternGetBool(m_pattern, property.c_str(), 0, &b);
*dst = b;
}
private: void property(string&& property, double* dst) const {
cairo_scaled_font_t* m_scaled{nullptr}; FcPatternGetDouble(m_pattern, property.c_str(), 0, dst);
FcPattern* m_pattern{nullptr}; }
};
/** void property(string&& property, int* dst) const {
* Match and create font from given fontconfig pattern FcPatternGetInteger(m_pattern, property.c_str(), 0, dst);
*/ }
inline decltype(auto) make_font(cairo_t* cairo, string&& fontname, double offset, double dpi_x, double dpi_y) {
static bool fc_init{false};
if (!fc_init && !(fc_init = FcInit())) {
throw application_error("Could not load fontconfig");
} else if (FT_Init_FreeType(&g_ftlib) != FT_Err_Ok) {
throw application_error("Could not load FreeType");
}
static auto fc_cleanup = scope_util::make_exit_handler([] { private:
FT_Done_FreeType(g_ftlib); cairo_scaled_font_t* m_scaled{nullptr};
FcFini(); FcPattern* m_pattern{nullptr};
}); };
auto pattern = FcNameParse((FcChar8*)fontname.c_str()); /**
* Match and create font from given fontconfig pattern
*/
inline decltype(auto) make_font(cairo_t* cairo, string&& fontname, double offset, double dpi_x, double dpi_y) {
static bool fc_init{false};
if (!fc_init && !(fc_init = FcInit())) {
throw application_error("Could not load fontconfig");
} else if (FT_Init_FreeType(&g_ftlib) != FT_Err_Ok) {
throw application_error("Could not load FreeType");
}
if (!pattern) { static scope_util::on_exit fc_cleanup([] {
logger::make().err("Could not parse font \"%s\"", fontname); FT_Done_FreeType(g_ftlib);
throw application_error("Could not parse font \"" + fontname + "\""); FcFini();
} });
FcDefaultSubstitute(pattern); auto pattern = FcNameParse((FcChar8*)fontname.c_str());
FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
FcResult result; if (!pattern) {
FcPattern* match = FcFontMatch(nullptr, pattern, &result); logger::make().err("Could not parse font \"%s\"", fontname);
FcPatternDestroy(pattern); throw application_error("Could not parse font \"" + fontname + "\"");
}
if (match == nullptr) { FcDefaultSubstitute(pattern);
throw application_error("Could not load font \"" + fontname + "\""); FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
}
FcResult result;
FcPattern* match = FcFontMatch(nullptr, pattern, &result);
FcPatternDestroy(pattern);
if (match == nullptr) {
throw application_error("Could not load font \"" + fontname + "\"");
}
#ifdef DEBUG_FONTCONFIG #ifdef DEBUG_FONTCONFIG
FcPatternPrint(match); FcPatternPrint(match);
#endif #endif
return make_shared<font_fc>(cairo, match, offset, dpi_x, dpi_y); return make_shared<font_fc>(cairo, match, offset, dpi_x, dpi_y);
} }
} // namespace cairo } // namespace cairo
POLYBAR_NS_END POLYBAR_NS_END

View File

@ -1,70 +1,47 @@
#pragma once #pragma once
#include <cairo/cairo-ft.h> #include <cairo/cairo-ft.h>
#include <list>
#include "common.hpp" #include "common.hpp"
POLYBAR_NS POLYBAR_NS
namespace cairo { namespace cairo {
namespace utils { namespace utils {
/** /**
* @brief RAII wrapper used acquire cairo_device_t * @brief RAII wrapper used acquire cairo_device_t
*/ */
class device_lock { class device_lock {
public: public:
explicit device_lock(cairo_device_t* device); explicit device_lock(cairo_device_t* device);
~device_lock(); ~device_lock();
operator bool() const; operator bool() const;
operator cairo_device_t*() const; operator cairo_device_t*() const;
private: private:
cairo_device_t* m_device{nullptr}; cairo_device_t* m_device{nullptr};
}; };
/** /**
* @brief RAII wrapper used to access the underlying * @brief RAII wrapper used to access the underlying
* FT_Face of a scaled font face * FT_Face of a scaled font face
*/ */
class ft_face_lock { class ft_face_lock {
public: public:
explicit ft_face_lock(cairo_scaled_font_t* font); explicit ft_face_lock(cairo_scaled_font_t* font);
~ft_face_lock(); ~ft_face_lock();
operator FT_Face() const; operator FT_Face() const;
private: private:
cairo_scaled_font_t* m_font; cairo_scaled_font_t* m_font;
FT_Face m_face; FT_Face m_face;
}; };
/** /**
* @brief Unicode character containing converted codepoint * @see <cairo/cairo.h>
* and details on where its position in the source string */
*/ cairo_operator_t str2operator(const string& mode, cairo_operator_t fallback);
struct unicode_character { } // namespace utils
explicit unicode_character(); } // namespace cairo
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);
}
}
POLYBAR_NS_END POLYBAR_NS_END

View File

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

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <cstdlib> #include <cstdlib>
#include <set>
#include "common.hpp" #include "common.hpp"
#include "components/eventloop.hpp" #include "components/eventloop.hpp"
@ -22,10 +23,12 @@ class connection;
class logger; class logger;
class renderer; class renderer;
class screen; class screen;
namespace legacy_tray {
class tray_manager; class tray_manager;
}
namespace tags { namespace tags {
class dispatch; 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 signal_receiver<SIGN_PRIORITY_BAR, signals::ui::dim_window> {
public: public:
using make_type = unique_ptr<bar>; 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>&&, 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>&&, unique_ptr<tags::dispatch>&&, unique_ptr<tags::action_context>&&, bool only_initialize_values);
bool only_initialize_values);
~bar(); ~bar();
const bar_settings& settings() const; const bar_settings& settings() const;
void start(); void start(const string& tray_module_name);
void parse(string&& data, bool force = false); 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; const logger& m_log;
eventloop::loop& m_loop; eventloop::loop& m_loop;
unique_ptr<screen> m_screen; 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<renderer> m_renderer;
unique_ptr<tags::dispatch> m_dispatch; unique_ptr<tags::dispatch> m_dispatch;
unique_ptr<tags::action_context> m_action_ctxt; 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_cursor{};
string m_lastinput{}; string m_lastinput{};
bool m_dblclicks{false}; std::set<mousebtn> m_dblclicks;
eventloop::TimerHandle& m_leftclick_timer{m_loop.handle<eventloop::TimerHandle>()}; eventloop::timer_handle_t m_leftclick_timer{m_loop.handle<eventloop::TimerHandle>()};
eventloop::TimerHandle& m_middleclick_timer{m_loop.handle<eventloop::TimerHandle>()}; eventloop::timer_handle_t m_middleclick_timer{m_loop.handle<eventloop::TimerHandle>()};
eventloop::TimerHandle& m_rightclick_timer{m_loop.handle<eventloop::TimerHandle>()}; eventloop::timer_handle_t m_rightclick_timer{m_loop.handle<eventloop::TimerHandle>()};
eventloop::TimerHandle& m_dim_timer{m_loop.handle<eventloop::TimerHandle>()}; eventloop::timer_handle_t m_dim_timer{m_loop.handle<eventloop::TimerHandle>()};
bool m_visible{true}; bool m_visible{true};
}; };

View File

@ -24,10 +24,7 @@ using file_list = vector<string>;
class config { class config {
public: public:
using make_type = const config&; explicit config(const logger& logger, string&& path, string&& bar)
static make_type make(string path = "", string bar = "");
explicit config(const logger& logger, string&& path = "", string&& bar = "")
: m_log(logger), m_file(move(path)), m_barname(move(bar)){}; : m_log(logger), m_file(move(path)), m_barname(move(bar)){};
const string& filepath() const; const string& filepath() const;
@ -44,33 +41,19 @@ class config {
void set_included(file_list included); 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 * Returns true if a given parameter exists
*/ */
bool has(const string& section, const string& key) const { 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();
}
/** /**
* Set parameter value * Set parameter value
*/ */
void set(const string& section, const string& key, string&& 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;
}
}
/** /**
* Get parameter for the current bar by name * Get parameter for the current bar by name
@ -92,7 +75,7 @@ class config {
if (it->second.find(key) == it->second.end()) { if (it->second.find(key) == it->second.end()) {
throw key_error("Missing parameter \"" + section + "." + key + "\""); 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 { T get(const string& section, const string& key, const T& default_value) const {
try { try {
string string_value{get<string>(section, key)}; string string_value{get<string>(section, key)};
T result{convert<T>(string{string_value})}; return convert<T>(dereference(move(section), move(key), move(string_value)));
return dereference<T>(move(section), move(key), move(string_value), move(result));
} catch (const key_error& err) { } catch (const key_error& err) {
return default_value; return default_value;
} catch (const std::exception& err) { } catch (const std::exception& err) {
@ -157,12 +139,11 @@ class config {
while (true) { while (true) {
try { try {
string string_value{get<string>(section, key + "-" + to_string(results.size()))}; string string_value{get<string>(section, key + "-" + to_string(results.size()))};
T value{convert<T>(string{string_value})};
if (!string_value.empty()) { 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 { } else {
results.emplace_back(move(value)); results.emplace_back(convert<T>(move(string_value)));
} }
} catch (const key_error& err) { } catch (const key_error& err) {
break; break;
@ -187,12 +168,11 @@ class config {
while (true) { while (true) {
try { try {
string string_value{get<string>(section, key + "-" + to_string(results.size()))}; string string_value{get<string>(section, key + "-" + to_string(results.size()))};
T value{convert<T>(string{string_value})};
if (!string_value.empty()) { 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 { } else {
results.emplace_back(move(value)); results.emplace_back(convert<T>(move(string_value)));
} }
} catch (const key_error& err) { } catch (const key_error& err) {
break; break;
@ -210,8 +190,6 @@ class config {
return default_value; 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 * 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 * warning message. If it fails load the value using the new key and given
@ -225,20 +203,10 @@ class config {
return value; return value;
} catch (const key_error& err) { } catch (const key_error& err) {
return get<T>(section, newkey, fallback); return get<T>(section, newkey, fallback);
} } catch (const std::exception& err) {
} m_log.err("Invalid value for \"%s.%s\", using fallback key \"%s.%s\" (reason: %s)", section, old, section, newkey,
err.what());
/** return get<T>(section, newkey, fallback);
* @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);
} }
} }
@ -251,27 +219,7 @@ class config {
/** /**
* Dereference value reference * Dereference value reference
*/ */
template <typename T> string dereference(const string& section, const string& key, const string& var) const;
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 + "\"");
}
}
/** /**
* Dereference local value reference defined using: * Dereference local value reference defined using:
@ -282,133 +230,28 @@ class config {
* ${section.key} * ${section.key}
* ${section.key:fallback} * ${section.key:fallback}
*/ */
template <typename T> string dereference_local(string section, const string& key, const string& current_section) const;
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)");
}
}
/** /**
* Dereference environment variable reference defined using: * Dereference environment variable reference defined using:
* ${env:key} * ${env:key}
* ${env:key:fallback value} * ${env:key:fallback value}
*/ */
template <typename T> string dereference_env(string var) const;
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)");
}
}
/** /**
* Dereference X resource db value defined using: * Dereference X resource db value defined using:
* ${xrdb:key} * ${xrdb:key}
* ${xrdb:key:fallback value} * ${xrdb:key:fallback value}
*/ */
template <typename T> string dereference_xrdb(string var) const;
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
}
/** /**
* Dereference file reference by reading its contents * Dereference file reference by reading its contents
* ${file:/absolute/file/path} * ${file:/absolute/file/path}
* ${file:/absolute/file/path:fallback value} * ${file:/absolute/file/path:fallback value}
*/ */
template <typename T> string dereference_file(string var) const;
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)");
}
}
private: private:
const logger& m_log; const logger& m_log;

View File

@ -90,12 +90,12 @@ struct line_t {
class config_parser { class config_parser {
public: 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 * This prevents passing a temporary logger to the constructor because that would be UB, as the temporary would be
* destroyed once the constructor returns. * 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 * @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 syntax_error If there was any kind of syntax error
* @throws parser_error If aynthing else went wrong * @throws parser_error If aynthing else went wrong
*/ */
config::make_type parse(); config parse(string barname);
protected: protected:
/** /**
@ -229,12 +229,7 @@ class config_parser {
/** /**
* @brief Absolute path to the main config file * @brief Absolute path to the main config file
*/ */
string m_config; string m_config_file;
/**
* Is used to resolve ${root...} references
*/
string m_barname;
/** /**
* @brief List of all the lines in the config (with included files) * @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> { signals::ipc::hook, signals::ui::button_press, signals::ui::update_background> {
public: public:
using make_type = unique_ptr<controller>; 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&); explicit controller(connection&, signal_emitter&, const logger&, const config&, bool has_ipc, eventloop::loop&);
~controller(); ~controller();
@ -55,12 +55,14 @@ class controller : public signal_receiver<SIGN_PRIORITY_CONTROLLER, signals::eve
void signal_handler(int signum); void signal_handler(int signum);
void conn_cb(); void conn_cb();
void create_config_watcher(const string& filename);
void confwatch_handler(const char* fname); void confwatch_handler(const char* fname);
void notifier_handler(); void notifier_handler();
void screenshot_handler(); void screenshot_handler();
protected: protected:
void trigger_notification(); void trigger_notification();
void start_modules();
void read_events(bool confwatch); void read_events(bool confwatch);
void process_inputdata(string&& cmd); void process_inputdata(string&& cmd);
bool process_update(bool force); bool process_update(bool force);
@ -100,6 +102,7 @@ class controller : public signal_receiver<SIGN_PRIORITY_CONTROLLER, signals::eve
eventloop::loop& m_loop; eventloop::loop& m_loop;
unique_ptr<bar> m_bar; unique_ptr<bar> m_bar;
bool m_has_ipc; bool m_has_ipc;
string m_tray_module_name;
/** /**
* @brief Async handle to notify the eventloop * @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. * This handle is used to notify the eventloop of changes which are not otherwise covered by other handles.
* E.g. click actions. * 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. * Notification data for the controller.

View File

@ -3,6 +3,7 @@
#include <uv.h> #include <uv.h>
#include <stdexcept> #include <stdexcept>
#include <utility>
#include "common.hpp" #include "common.hpp"
#include "components/logger.hpp" #include "components/logger.hpp"
@ -36,12 +37,12 @@ namespace eventloop {
get()->data = this; get()->data = this;
} }
Self& leak(std::unique_ptr<Self> h) { void leak(std::shared_ptr<Self> h) {
lifetime_extender = std::move(h); lifetime_extender = std::move(h);
return *lifetime_extender;
} }
void unleak() { void unleak() {
reset_callbacks();
lifetime_extender.reset(); lifetime_extender.reset();
} }
@ -73,6 +74,15 @@ namespace eventloop {
} }
protected: 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. * Generic callback function that can be used for all uv handle callbacks.
* *
@ -128,14 +138,14 @@ namespace eventloop {
uv_loop_t* uv_loop; 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. * 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 * 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. * is reset and the object is explicitly destroyed.
*/ */
std::unique_ptr<Self> lifetime_extender; std::shared_ptr<Self> lifetime_extender;
}; };
struct ErrorEvent { struct ErrorEvent {
@ -144,54 +154,32 @@ namespace eventloop {
using cb_error = cb_event<ErrorEvent>; using cb_error = cb_event<ErrorEvent>;
class WriteRequest : public non_copyable_mixin { class WriteRequest : public non_copyable_mixin, public non_movable_mixin {
public: public:
using cb_write = cb_void; using cb_write = cb_void;
WriteRequest(cb_write user_cb, cb_error err_cb) : write_callback(user_cb), write_err_cb(err_cb) { WriteRequest(cb_write&& user_cb, cb_error&& err_cb);
get()->data = this;
};
static WriteRequest& create(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));
};
uv_write_t* get() { uv_write_t* get();
return &req;
}
/** /**
* Trigger the write callback. * Trigger the write callback.
* *
* After that, this object is destroyed. * After that, this object is destroyed.
*/ */
void trigger(int status) { void trigger(int status);
if (status < 0) {
if (write_err_cb) {
write_err_cb(ErrorEvent{status});
}
} else {
if (write_callback) {
write_callback();
}
}
unleak();
}
protected: protected:
WriteRequest& leak(std::unique_ptr<WriteRequest> h) { WriteRequest& leak(std::unique_ptr<WriteRequest> h);
lifetime_extender = std::move(h);
return *lifetime_extender;
}
void unleak() { void unleak();
lifetime_extender.reset();
} void reset_callbacks();
private: private:
uv_write_t req; uv_write_t req{};
cb_write write_callback; cb_write write_callback;
cb_error write_err_cb; cb_error write_err_cb;
@ -208,13 +196,16 @@ namespace eventloop {
int signum; int signum;
}; };
class SignalHandle : public Handle<SignalHandle, uv_signal_t> { class SignalHandle final : public Handle<SignalHandle, uv_signal_t> {
public: public:
using Handle::Handle; using Handle::Handle;
using cb = cb_event<SignalEvent>; using cb = cb_event<SignalEvent>;
void init(); void init();
void start(int signum, cb user_cb); void start(int signum, cb&& user_cb);
protected:
void reset_callbacks() override;
private: private:
cb callback; cb callback;
@ -224,15 +215,18 @@ namespace eventloop {
uv_poll_event event; uv_poll_event event;
}; };
class PollHandle : public Handle<PollHandle, uv_poll_t> { class PollHandle final : public Handle<PollHandle, uv_poll_t> {
public: public:
using Handle::Handle; using Handle::Handle;
using cb = cb_event<PollEvent>; using cb = cb_event<PollEvent>;
void init(int fd); 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); static void poll_callback(uv_poll_t*, int status, int events);
protected:
void reset_callbacks() override;
private: private:
cb callback; cb callback;
cb_error err_cb; cb_error err_cb;
@ -243,41 +237,50 @@ namespace eventloop {
uv_fs_event event; uv_fs_event event;
}; };
class FSEventHandle : public Handle<FSEventHandle, uv_fs_event_t> { class FSEventHandle final : public Handle<FSEventHandle, uv_fs_event_t> {
public: public:
using Handle::Handle; using Handle::Handle;
using cb = cb_event<FSEvent>; using cb = cb_event<FSEvent>;
void init(); 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); static void fs_event_callback(uv_fs_event_t*, const char* path, int events, int status);
protected:
void reset_callbacks() override;
private: private:
cb callback; cb callback;
cb_error err_cb; cb_error err_cb;
}; };
class TimerHandle : public Handle<TimerHandle, uv_timer_t> { class TimerHandle final : public Handle<TimerHandle, uv_timer_t> {
public: public:
using Handle::Handle; using Handle::Handle;
using cb = cb_void; using cb = cb_void;
void init(); 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(); void stop();
protected:
void reset_callbacks() override;
private: private:
cb callback; cb callback;
}; };
class AsyncHandle : public Handle<AsyncHandle, uv_async_t> { class AsyncHandle final : public Handle<AsyncHandle, uv_async_t> {
public: public:
using Handle::Handle; using Handle::Handle;
using cb = cb_void; using cb = cb_void;
void init(cb user_cb); void init(cb&& user_cb);
void send(); void send();
protected:
void reset_callbacks() override;
private: private:
cb callback; cb callback;
}; };
@ -295,9 +298,9 @@ namespace eventloop {
using cb_read_eof = cb_void; using cb_read_eof = cb_void;
using cb_connection = cb_void; using cb_connection = cb_void;
void listen(int backlog, cb_connection user_cb, cb_error err_cb) { void listen(int backlog, cb_connection&& user_cb, cb_error&& err_cb) {
this->connection_callback = user_cb; this->connection_callback = std::move(user_cb);
this->connection_err_cb = err_cb; this->connection_err_cb = std::move(err_cb);
UV(uv_listen, this->template get<uv_stream_t>(), backlog, connection_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>()); 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) { void read_start(cb_read&& fun, cb_void&& eof_cb, cb_error&& err_cb) {
this->read_callback = fun; this->read_callback = std::move(fun);
this->read_eof_cb = eof_cb; this->read_eof_cb = std::move(eof_cb);
this->read_err_cb = err_cb; this->read_err_cb = std::move(err_cb);
UV(uv_read_start, this->template get<uv_stream_t>(), &this->alloc_callback, read_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) { 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 = {}) { void write(const vector<uint8_t>& data, WriteRequest::cb_write&& user_cb = {}, cb_error&& err_cb = {}) {
WriteRequest& req = WriteRequest::create(user_cb, err_cb); WriteRequest& req = WriteRequest::create(std::move(user_cb), std::move(err_cb));
uv_buf_t buf{(char*)data.data(), data.size()}; 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); }); [](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: private:
/** /**
* Callback for receiving data * Callback for receiving data
@ -371,7 +385,7 @@ namespace eventloop {
cb_error connection_err_cb; cb_error connection_err_cb;
}; };
class PipeHandle : public StreamHandle<PipeHandle, uv_pipe_t> { class PipeHandle final : public StreamHandle<PipeHandle, uv_pipe_t> {
public: public:
using StreamHandle::StreamHandle; using StreamHandle::StreamHandle;
using cb_connect = cb_void; using cb_connect = cb_void;
@ -381,7 +395,10 @@ namespace eventloop {
void bind(const string& path); 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: private:
static void connect_cb(uv_connect_t* req, int status); static void connect_cb(uv_connect_t* req, int status);
@ -390,27 +407,53 @@ namespace eventloop {
cb_connect connect_callback; 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 { class loop : public non_copyable_mixin, public non_movable_mixin {
public: public:
loop(); loop();
~loop(); ~loop();
void run(); void run();
void stop(); void stop();
uint64_t now() const;
template <typename H, typename... Args> template <typename H, typename... Args>
H& handle(Args... args) { shared_ptr<H> handle(Args&&... args) {
auto ptr = make_unique<H>(get()); auto ptr = make_shared<H>(get());
ptr->init(std::forward<Args>(args)...); ptr->init(std::forward<Args>(args)...);
return ptr->leak(std::move(ptr)); ptr->leak(ptr);
return ptr;
} }
protected:
uv_loop_t* get() const; uv_loop_t* get() const;
private: private:
std::unique_ptr<uv_loop_t> m_loop{nullptr}; std::unique_ptr<uv_loop_t> m_loop{nullptr};
}; };
} // namespace eventloop } // namespace eventloop
POLYBAR_NS_END POLYBAR_NS_END

View File

@ -34,11 +34,15 @@ class logger {
explicit logger(loglevel level); explicit logger(loglevel level);
const logger& operator=(const logger&) const {
return *this;
}
static loglevel parse_verbosity(const string& name, loglevel fallback = loglevel::NONE); static loglevel parse_verbosity(const string& name, loglevel fallback = loglevel::NONE);
void verbosity(loglevel level); void verbosity(loglevel level);
#ifdef DEBUG_LOGGER // {{{ #ifdef DEBUG_LOGGER // {{{
template <typename... Args> template <typename... Args>
void trace(const string& message, Args&&... args) const { void trace(const string& message, Args&&... args) const {
output(loglevel::TRACE, message, std::forward<Args>(args)...); output(loglevel::TRACE, message, std::forward<Args>(args)...);
@ -57,7 +61,7 @@ class logger {
void trace(Args&&...) const {} void trace(Args&&...) const {}
template <typename... Args> template <typename... Args>
void trace_x(Args&&...) const {} void trace_x(Args&&...) const {}
#endif // }}} #endif // }}}
/** /**
* Output an info message * Output an info message
@ -118,21 +122,21 @@ class logger {
return; return;
} }
#if defined(__clang__) // {{{ #if defined(__clang__) // {{{
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat-security" #pragma clang diagnostic ignored "-Wformat-security"
#elif defined(__GNUC__) #elif defined(__GNUC__)
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-security" #pragma GCC diagnostic ignored "-Wformat-security"
#endif // }}} #endif // }}}
dprintf(m_fd, (m_prefixes.at(level) + format + m_suffixes.at(level) + "\n").c_str(), convert(values)...); dprintf(m_fd, (m_prefixes.at(level) + format + m_suffixes.at(level) + "\n").c_str(), convert(values)...);
#if defined(__clang__) // {{{ #if defined(__clang__) // {{{
#pragma clang diagnostic pop #pragma clang diagnostic pop
#elif defined(__GNUC__) #elif defined(__GNUC__)
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif // }}} #endif // }}}
} }
private: private:

View File

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

View File

@ -16,23 +16,16 @@ class logger;
class connection; class connection;
class signal_emitter; 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: public:
using make_type = unique_ptr<screen>; 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); explicit screen(connection& conn, signal_emitter& emitter, const logger& logger, const config& conf);
~screen(); ~screen();
struct size size() const {
return m_size;
}
xcb_window_t root() const {
return m_root;
}
protected: protected:
void handle(const evt::map_notify& evt) override;
void handle(const evt::randr_screen_change_notify& evt) override; void handle(const evt::randr_screen_change_notify& evt) override;
private: private:
@ -50,6 +43,12 @@ class screen : public xpp::event::sink<evt::randr_screen_change_notify> {
}; };
bool m_sigraised{false}; 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; bool have_monitors_changed() const;
}; };

View File

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

View File

@ -21,6 +21,6 @@ namespace drawtypes {
}; };
using iconset_t = shared_ptr<iconset>; using iconset_t = shared_ptr<iconset>;
} // namespace drawtypes } // namespace drawtypes
POLYBAR_NS_END POLYBAR_NS_END

View File

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

View File

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

View File

@ -101,7 +101,7 @@ namespace signals {
} // namespace ui } // namespace ui
namespace ui_tray { 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; using base_type::base_type;
}; };
} // namespace ui_tray } // namespace ui_tray

View File

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

View File

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

View File

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

View File

@ -2,11 +2,25 @@
#include "components/config.hpp" #include "components/config.hpp"
#include "modules/meta/inotify_module.hpp" #include "modules/meta/inotify_module.hpp"
#include "modules/meta/types.hpp"
#include "settings.hpp" #include "settings.hpp"
POLYBAR_NS POLYBAR_NS
namespace modules { 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> { class backlight_module : public inotify_module<backlight_module> {
public: public:
struct brightness_handle { struct brightness_handle {
@ -19,14 +33,13 @@ namespace modules {
string get_output(); string get_output();
public: explicit backlight_module(const bar_settings&, string, const config&);
explicit backlight_module(const bar_settings&, string);
void idle(); void idle();
bool on_event(inotify_event* event); bool on_event(const inotify_event& event);
bool build(builder* builder, const string& tag) const; 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_INC = "inc";
static constexpr const char* EVENT_DEC = "dec"; static constexpr const char* EVENT_DEC = "dec";
@ -46,15 +59,19 @@ namespace modules {
label_t m_label; label_t m_label;
progressbar_t m_progressbar; progressbar_t m_progressbar;
string m_path_backlight; string m_path_backlight;
float m_max_brightness; float m_max_brightness{};
bool m_scroll{false}; bool m_scroll{false};
int m_scroll_interval{5};
bool m_use_actual_brightness{true}; bool m_use_actual_brightness{true};
brightness_handle m_val; brightness_handle m_val;
brightness_handle m_max; brightness_handle m_max;
int m_percentage = 0; int m_percentage = 0;
chrono::duration<double> m_interval{};
chrono::steady_clock::time_point m_lastpoll;
}; };
} // namespace modules } // namespace modules
POLYBAR_NS_END POLYBAR_NS_END

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "modules/meta/static_module.hpp" #include "modules/meta/static_module.hpp"
#include "modules/meta/types.hpp"
#include "utils/command.hpp" #include "utils/command.hpp"
POLYBAR_NS POLYBAR_NS
@ -24,15 +25,16 @@ namespace modules {
}; };
public: public:
explicit ipc_module(const bar_settings&, string); explicit ipc_module(const bar_settings&, string, const config&);
void start() override; void start() override;
void update(); void update();
string get_output(); string get_output();
string get_format() const;
bool build(builder* builder, const string& tag) const; bool build(builder* builder, const string& tag) const;
void on_message(const string& message); 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_SEND = "send";
static constexpr auto EVENT_HOOK = "hook"; static constexpr auto EVENT_HOOK = "hook";
@ -53,16 +55,21 @@ namespace modules {
bool has_hook() const; bool has_hook() const;
void set_hook(int h); void set_hook(int h);
void update_output() ;
private: 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; vector<unique_ptr<hook>> m_hooks;
map<mousebtn, string> m_actions; map<mousebtn, string> m_actions;
string m_output; string m_output;
int m_initial{-1}; int m_initial{-1};
int m_current_hook{-1}; int m_current_hook{-1};
void exec_hook(); void exec_hook();
}; };
} // namespace modules } // namespace modules
POLYBAR_NS_END POLYBAR_NS_END

View File

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

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "modules/meta/static_module.hpp" #include "modules/meta/static_module.hpp"
#include "modules/meta/types.hpp"
POLYBAR_NS POLYBAR_NS
@ -17,12 +18,12 @@ namespace modules {
}; };
public: 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; bool build(builder* builder, const string& tag) const;
void update() {} void update() {}
static constexpr auto TYPE = "custom/menu"; static constexpr auto TYPE = MENU_TYPE;
static constexpr auto EVENT_OPEN = "open"; static constexpr auto EVENT_OPEN = "open";
static constexpr auto EVENT_CLOSE = "close"; 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 <mutex>
#include "common.hpp" #include "common.hpp"
#include "components/config.hpp"
#include "components/types.hpp" #include "components/types.hpp"
#include "errors.hpp" #include "errors.hpp"
#include "utils/concurrency.hpp" #include "utils/concurrency.hpp"
@ -58,7 +59,6 @@ namespace modules {
struct module_format { struct module_format {
string value{}; string value{};
vector<string> tags{};
label_t prefix{}; label_t prefix{};
label_t suffix{}; label_t suffix{};
rgba fg{}; rgba fg{};
@ -142,7 +142,7 @@ namespace modules {
template <class Impl> template <class Impl>
class module : public module_interface { class module : public module_interface {
public: public:
module(const bar_settings& bar, string name); module(const bar_settings& bar, string name, const config&);
~module() noexcept; ~module() noexcept;
static constexpr auto EVENT_MODULE_TOGGLE = "module_toggle"; static constexpr auto EVENT_MODULE_TOGGLE = "module_toggle";
@ -189,7 +189,7 @@ namespace modules {
string get_format() const; string get_format() const;
string get_output(); string get_output();
void set_visible(bool value); virtual void set_visible(bool value);
void action_module_toggle(); void action_module_toggle();
void action_module_show(); void action_module_show();

View File

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

View File

@ -1,117 +1,25 @@
#pragma once #pragma once
#include "common.hpp" #include "common.hpp"
#include "modules/backlight.hpp" #include "components/logger.hpp"
#include "modules/battery.hpp" #include "components/types.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/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 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) { * Creates a new module instance.
if (name == counter_module::TYPE) { *
return new counter_module(bar, move(module_name)); * @param type The type of the module (as given by each module's TYPE field)
} else if (name == backlight_module::TYPE) { * @param bar An instance of the @ref bar_settings
return new backlight_module(bar, move(module_name)); * @param module_name The user-specified module name
} else if (name == battery_module::TYPE) { * @param log A @ref logger instance
return new battery_module(bar, move(module_name)); * @param config A @ref config instance
} else if (name == bspwm_module::TYPE) { */
return new bspwm_module(bar, move(module_name)); module_t make_module(string&& type, const bar_settings& bar, string module_name, const logger& log, const config& config);
} else if (name == cpu_module::TYPE) { } // namespace modules
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
POLYBAR_NS_END POLYBAR_NS_END

View File

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

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

View File

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

View File

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

View File

@ -2,6 +2,7 @@
#include "adapters/script_runner.hpp" #include "adapters/script_runner.hpp"
#include "modules/meta/base.hpp" #include "modules/meta/base.hpp"
#include "modules/meta/types.hpp"
#include "utils/command.hpp" #include "utils/command.hpp"
#include "utils/io.hpp" #include "utils/io.hpp"
@ -10,7 +11,7 @@ POLYBAR_NS
namespace modules { namespace modules {
class script_module : public module<script_module> { class script_module : public module<script_module> {
public: public:
explicit script_module(const bar_settings&, string); explicit script_module(const bar_settings&, string, const config&);
void start() override; void start() override;
void stop() override; void stop() override;
@ -20,7 +21,7 @@ namespace modules {
bool build(builder* builder, const string& tag) const; bool build(builder* builder, const string& tag) const;
static constexpr auto TYPE = "custom/script"; static constexpr auto TYPE = SCRIPT_TYPE;
protected: protected:
bool check_condition(); bool check_condition();
@ -33,7 +34,9 @@ namespace modules {
static constexpr auto FORMAT_FAIL = "format-fail"; static constexpr auto FORMAT_FAIL = "format-fail";
const bool m_tail; 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; 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 <istream>
#include "modules/meta/timer_module.hpp" #include "modules/meta/timer_module.hpp"
#include "modules/meta/types.hpp"
#include "settings.hpp" #include "settings.hpp"
POLYBAR_NS POLYBAR_NS
@ -12,13 +13,13 @@ namespace modules {
class temperature_module : public timer_module<temperature_module> { class temperature_module : public timer_module<temperature_module> {
public: public:
explicit temperature_module(const bar_settings&, string); explicit temperature_module(const bar_settings&, string, const config&);
bool update(); bool update();
string get_format() const; string get_format() const;
bool build(builder* builder, const string& tag) const; bool build(builder* builder, const string& tag) const;
static constexpr auto TYPE = "internal/temperature"; static constexpr auto TYPE = TEMPERATURE_TYPE;
private: private:
static constexpr auto TAG_LABEL = "<label>"; static constexpr auto TAG_LABEL = "<label>";
@ -30,6 +31,7 @@ namespace modules {
ramp_t m_ramp; ramp_t m_ramp;
string m_path; string m_path;
string m_zone_type;
int m_zone = 0; int m_zone = 0;
// Base temperature used for where to start the ramp // Base temperature used for where to start the ramp
int m_tempbase = 0; int m_tempbase = 0;

View File

@ -1,20 +1,29 @@
#pragma once #pragma once
#include "modules/meta/static_module.hpp" #include "modules/meta/static_module.hpp"
#include "modules/meta/types.hpp"
POLYBAR_NS POLYBAR_NS
namespace modules { namespace modules {
class text_module : public static_module<text_module> { class text_module : public static_module<text_module> {
public: public:
explicit text_module(const bar_settings&, string); explicit text_module(const bar_settings&, string, const config&);
void update() {} void update() {}
string get_format() const; string get_format() const;
string get_output(); 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 } // namespace modules
POLYBAR_NS_END POLYBAR_NS_END

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

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