Compare commits

...

238 Commits

Author SHA1 Message Date
e72993e14d Update dwm module after merge 3.7.0 version 2024-02-27 15:46:56 +01:00
6d42ccedd6 -----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'
2024-02-27 15:33:34 +01:00
patrick96
91bd85cf50
Version 3.7.1 2023-11-27 17:15:23 +01:00
patrick96
ade2ee0981 build: Update i3ipcpp
Closes #3042
Includes polybar/i3ipcpp#16
2023-11-27 15:53:30 +01:00
patrick96
c552df3b66 fix: Modules did not validate tags used in formats
The 'value' variable that was used for validation, was empty because it
was used in a move at the beginning of the function.

Fixes #3043
2023-11-16 22:29:00 +01:00
patrick96
432e19df01 build: Add missing headers in common.hpp 2023-11-12 15:18:34 +01:00
patrick96
cbfbba0700 Remove tray_visibility signal
No longer needed since tray visibility is now controlled directly by the
enclosing module
2023-11-11 04:01:26 +01:00
patrick96
8566051336 fix(tray): Allow module to disappear for empty tray
Modules that don't produce any output are hidden by the controller
(don't have margins or separators).
The tray module should also do that for `format = <tray>` when there are
no icons.

This required the visibility handling to be tied to the module
visibility instead of being handled by the renderer.
Otherwise, the renderer would hide the tray (because the %{Pt} tag was
never sent) and the tray would not unhide when new icons appeared; it
can't differentiate between hidden because empty and hidden because the
module is hidden by the user (the latter is the reason the renderer does
hiding at all).

Fixes #3036
2023-11-11 04:01:26 +01:00
patrick96
2471f3595c
Version 3.7.0 2023-11-05 23:36:13 +01:00
patrick96
cd57c1252c
Write migration guide for the content in custom/text 2023-11-05 22:53:09 +01:00
patrick96
ea3b47a65e
Improve release workflow documentation 2023-11-05 22:05:43 +01:00
patrick96
70c400d20d
doc: Specify boxes to check in GitHub release tool 2023-11-05 22:05:43 +01:00
patrick96
f8983e2bd3
Remove colon from download header 2023-11-05 22:05:40 +01:00
Tony Zorman
f7a755799c feat(xworkspaces): Add group-by-monitor flag
By default, we group workspaces by monitor with the help of
_NET_DESKTOP_VIEWPORT.  However, some users may experience this as an
unpredictable "shuffling" of workspaces.  While WMs could disable
advertising the property itself, it seems more sensible to handle this
at the level of polybar.  Hence, introduce a new group-by-monitor
flag—defaulting to true—which can be used to disable this behaviour.

Closes: https://github.com/polybar/polybar/issues/2603
Related: https://github.com/xmonad/xmonad-contrib/pull/791
Related: https://github.com/qtile/qtile/issues/3375

Co-authored-by: scaramangado <scaramangado@gmail.com>
2023-10-29 16:15:10 +01:00
patrick96
0a19c5e3d7 doc: Bump sphinx-rtd-theme to version 2
The notfound plugin (404 page) does not seem to work with older versions
of the theme.
2023-10-23 01:08:14 +02:00
patrick96
eaa3ba5f83 doc: Fix sphinx version 2023-10-23 00:32:46 +02:00
patrick96
7972c20fe9 fix(xpp): Allow for custom python executable
Includes polybar/xpp#34
2023-10-23 00:32:46 +02:00
patrick96
38f67f4269 doc: Add sphinx 404 page 2023-10-23 00:32:46 +02:00
patrick96
6a648c8ef7 doc: Update readthedocs URLs
There is a redirect setup that redirects anything to `/en/stable` (or
whatever the default version is).
This allows us to create version-agnostic direct links that always
redirect to the default version
2023-10-23 00:32:46 +02:00
patrick96
054b9f4d33 docs: Add banner for 'latest' version 2023-10-23 00:32:46 +02:00
patrick96
80aa2bade5 build: Fix cmake warnings in submodules
Includes polybar/xpp#33
Includes polybar/i3ipcpp#15
2023-10-22 15:40:33 +02:00
patrick96
aebdb5328a fix(backlight): Poll if necessary
The `backlight` file seems to not receive modification events for
inotify (it does receive other events though).
These other events still trigger an update, but the value read is still
the old value because the events arrive just slightly before the file is
updated.

The new `poll-interval` setting will inject an event every X seconds to
force an update.
If the actual_brightness file is used, the interval is set to 0 and thus
turned off.

This does not add any more wakeups to the module, the inotify modules
wake up every second anyway and during that time, the interval is
checked.

Fixes #2835
2023-10-21 20:32:11 +02:00
patrick96
278584fa27 feat(doc): Add rtd search extension
Provides real-time search on readthedocs

Ref: https://readthedocs-sphinx-search.readthedocs.io
2023-10-08 21:24:37 +02:00
patrick96
19e8d53320 doc: Explicitly specify sphinx rtd theme dependency
Since August 7, 2023, readthedocs will not install the rtd theme by
default anymore.

Ref: https://blog.readthedocs.com/python-core-requirements-changed/
2023-10-08 21:16:21 +02:00
patrick96
c9752598a5 fix(bspwm): Restack against topmost root window.
The ewmh strategy has to be dropped because the
`_NET_SUPPORTING_WM_CHECK` window may (at least in bspwm) appear
anywhere in the window stack.

To fix the overlapping monitors issue in #2873, we simply restack
against the topmost of these root windows.

Fixes #2972
Fixes #2873 (again)
2023-10-08 21:04:29 +02:00
patrick96
1bfe117c5d Document recommendations for nerd fonts 2023-09-30 19:32:48 +02:00
patrick96
16102c258a alsa: include asoundlib.h instead of all alsa headers
In alsa 1.2.10, the `alsa/control.h` header cannot be included on its
own because it does not include all symbols it uses.

We are basically duplicating asoundlib.h anyway and there is even a
macro variable to switch to it.

Ref: #3009
Ref: https://github.com/alsa-project/alsa-lib/issues/348
2023-09-28 19:30:49 +02:00
patrick96
53661e995a doc: Fix FreeBSD link 2023-08-20 11:59:43 +02:00
patrick96
1043354aec tray: Deprecate all legacy tray settings 2023-08-06 15:26:28 +02:00
patrick96
97ce1f6e7a Add inactive tray module to default config
Replaces the commented out `tray-position`
2023-08-06 15:26:28 +02:00
dvermd
b754790642
Cleanup base::tags (#2991) 2023-07-06 09:46:33 +02:00
Andrew Tran
c747599ef5
fix(tray): check for visibility when docking (#2973)
Fixes #2968
2023-06-13 11:25:36 +02:00
Vincent Bernat
2cd0809a46
fix(randr): avoid querying hardware to get current configuration (#2470)
When using `get_screen_resources`, XRandR will query the hardware to
detect any change. This takes some time.
`get_screen_resources_current` uses the cached information and is
pretty fast.

In my case, the information is always already present in cache because
it was set by the program that did configure the screens (autorandr in
my case, but this applies to most frontends). As polybar is not used
to configure stuff, I think this is fine. There should be something
configuring the screen before polybar is able to use it.

However, maybe some people are using `polybar --list-monitors` just
after plugging a screen. It won't display the new screen in this case.
So, maybe this is not a good idea. It makes polybar starts
faster (500ms faster in my case when there are 3 screens plugged).
Also, I did this change because running `polybar --list-monitor` in
parallel with starting `polybar` (in a for loop for example), I get
some curious bug where my screens disappear and reappear. I don't need
this change as this was easy to fix by avoiding the parallel access to
XRandR properties, but maybe this would avoid other people running
into the same problem.

Your take!
2023-05-18 11:29:30 +02:00
dvermd
06a3de0b89
Refactor config::dereference* (#2963)
* Refactor config::dereference*

* move config::deprecated* implementation to cpp file

* config: move more functions implementation to cpp file
2023-05-18 09:47:45 +02:00
patrick96
ea3eb6eaa4 ci: Update ubuntu version 2023-05-15 14:44:50 +02:00
patrick96
4d1bba2c4e Add changelog 2023-05-15 14:44:50 +02:00
patrick96
2c23f7a87f restack: Make bspwm first try ewmh strategy 2023-05-15 14:44:50 +02:00
patrick96
4f9f07eefd restack: Add ewmh restacking strategy
Positions the bar window above the _NET_SUPPORTING_WM_CHECK window

The generic restacking strategy now first tries the ewmh strategy, the
the bottom strategy.
2023-05-15 14:44:50 +02:00
patrick96
b11a2ff653 restack: Add bottom restacking strategy
For now this is the same as the generic one
2023-05-15 14:44:50 +02:00
patrick96
59acb4150b Clean up restacking code
Restacking algorithms now only need to provide the sibling window and
stacking mode.
2023-05-15 14:44:50 +02:00
patrick96
76c7ee3bf6 Introduce restacking utilities
Aim is to clean up restacking logic and remove some duplicated code
2023-05-15 14:44:50 +02:00
patrick96
f78ec80df3 Add changelog entry 2023-05-10 17:06:00 +02:00
patrick96
425d4dc338 Cleanup 2023-05-10 17:06:00 +02:00
patrick96
32c78aa63a Cleanup ucs4_to_utf8 2023-05-10 17:06:00 +02:00
patrick96
40bc8c7955 Test utf8_to_ucs4 error correction 2023-05-10 17:06:00 +02:00
patrick96
5b1fae4fc1 Make utf8_to_ucs4 take a string reference 2023-05-10 17:06:00 +02:00
patrick96
5e5a0a7c4d Make unicode_charlist a vector 2023-05-10 17:06:00 +02:00
patrick96
c86519f077 test: utf8_to_ucs4 with invalid strings 2023-05-10 17:06:00 +02:00
patrick96
3a27e891d2 fix(renderer): Drop strings with invalid UTF8 2023-05-10 17:06:00 +02:00
patrick96
63443f82d5 Refactor utf8_to_ucs4 2023-05-10 17:06:00 +02:00
patrick96
270c0a340c Add tests for utf8_to_ucs4 2023-05-10 17:06:00 +02:00
patrick96
71c65447f8 Move utf8 conversion code to string utils 2023-05-10 17:06:00 +02:00
patrick96
6e716296ff Formatting 2023-05-10 17:06:00 +02:00
patrick96
d74a4fab77 i3: Better error reporting when connection fails
Prints the output and exit code of 'i3 --get-socketpath' if it fails and
prints the socket path if the connection fails.

Ref polybar/i3ipcpp#13
Ref #2942
2023-05-10 09:42:05 +02:00
dvermd
f5169abde2
Remove unsupported.hpp (#2956)
* Remove unsupported.hpp

* Rename names.hpp to types.hpp

* Replace macro by function

* Add missing cassert include in controller.cpp
2023-05-08 19:36:12 +02:00
Patrick Ziegler
031a29332a
doc: Use readthedocs config file (#2957)
This is the recommended way to configure the project instead of using
the website.

It should also help fix readthedocs/readthedocs.org#10290
2023-05-08 19:13:02 +02:00
dvermd
0caa30683c
Remove config singleton (#2951)
* Remove unused function

* Refactor deprecation warning

* Modules take config as parameter instead of using the singleton

* Bar take config as parameter instead of using the singleton

* Renderer take config as parameter instead of using the singleton

* Legacy Tray Manager take config as parameter instead of using the singleton

* Screen take config as parameter instead of using the singleton

* Controller take config as parameter instead of using the singleton

* Remove the config singleton

* Apply review suggestion

Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>

* Apply style suggestion

Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>

* Apply style suggestion

Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>

* Apply style suggestion

Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>

* Apply style suggestion

Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>

* Apply style suggestion

Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>

* Apply style suggestion

Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>

* Apply style suggestion

Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>

* Apply style suggestion

Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>

* Apply style suggestion

Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>

---------

Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>
2023-05-01 14:58:52 +02:00
patrick96
61f0e9dd5d fix(tray): Vertically center in inner bar area
The tray should be vertically centered in the inner area of the bar.
Unequal top and bottom borders should not affect the alignment relative
to other text.

Fixes #2950
2023-04-29 14:45:01 +02:00
patrick96
7bc673b8f2 fix(doc): %s in extlinks caption before sphinx 4.0
There is no way to support extlinks with a custom caption in both sphinx
< 4 and >= 4 at the same time without implementing different behavior
per version.
2023-04-20 01:24:02 +02:00
patrick96
89ca0255f1 doc: Fix extlinks %s substitution in caption
Substitutions in the caption are only supported in version 4 of
sphinx.
However, RTD uses sphinx 1.8.6

Just letting it append the value seems to work in both 1.8.6 and newer
versions.
2023-04-18 15:48:38 +02:00
patrick96
cf802ad431 doc: Mention errors and warnings in migration guide 2023-04-18 15:48:38 +02:00
patrick96
dbac7d8ae8 doc: Finish tray migration guide 2023-04-18 15:48:38 +02:00
patrick96
fcef90be24 doc: Start tray migration guide 2023-04-18 15:48:38 +02:00
patrick96
6148bb7f14 doc: Add empty migration page 2023-04-18 15:48:38 +02:00
patrick96
30bb1584fc doc: Add page about default config 2023-04-18 15:48:38 +02:00
patrick96
f3c911991c doc: Document custom directive in python script 2023-04-18 15:48:38 +02:00
patrick96
44b5f87884 doc: Use issue directive to link to issue 2023-04-18 15:48:38 +02:00
patrick96
006e971dad doc: Add module links 2023-04-18 15:48:38 +02:00
patrick96
6e0cff97ff doc(tray): Add type at the beginning 2023-04-18 15:48:38 +02:00
patrick96
fc422b1107 doc: Style external links in RTD theme 2023-04-18 15:48:38 +02:00
patrick96
81684a6c9d doc: Show version in alabaster theme (local builds) 2023-04-18 15:48:38 +02:00
patrick96
0032f27686 doc: Use extlinks for linking to issues and PRs 2023-04-18 15:48:38 +02:00
patrick96
234e606b41 doc: Replace custom domain with add_object_type
Less overhead and doesn't require a new dependency
2023-04-18 15:48:38 +02:00
patrick96
c48aa1998c fix(doc): Setup function not always running
If the sphinx version was below 1.8.5, no setup function was defined at
all.
2023-04-18 15:48:38 +02:00
patrick96
98d58b6f27 doc: Reformat conf.py 2023-04-18 15:48:38 +02:00
patrick96
c6eb3f88ea doc(tray): Initial experiments 2023-04-18 15:48:38 +02:00
patrick96
df32703a22 tray: Rework tray spacing
tray-padding determines space added before and after each icon
tray-spacing determines space added between icons (but not at the edge)

Both are an extent value and accept both pixel and point values.
2023-04-01 21:04:58 +02:00
patrick96
7fbd2d175c tray: Cleanup position calculation 2023-04-01 21:04:58 +02:00
patrick96
b5f8466117 tray: Replace tray-maxsize module setting with tray-size
The size accepts a percentage with offset relative to the bar height and
determines the width and height of tray icons.

Defaults to 66%

Does not affect spacing
2023-04-01 21:04:58 +02:00
patrick96
4e66b1f4b8 tray: Remove tray-scale module setting 2023-04-01 21:04:58 +02:00
patrick96
921e2d0670
Merge remote-tracking branch 'upstream/master' into tray-child-window 2023-03-25 22:04:21 +01:00
patrick96
04fefa0a0e
fix(tray): Correct y-position with border
The border size was not taken into account when calculating the tray
icon's y-position
2023-03-25 20:17:22 +01:00
patrick96
11746455ee
tray: Cleanup & documentation 2023-03-25 20:17:02 +01:00
patrick96
f3ce047c52
tray: Remove delayed notifications
Unclear why it is needed, neither i3bar, nor stalonetray do delayed
notifications
2023-03-25 19:28:43 +01:00
patrick96
23153c3a23
tray: Address rendering related TODOs
Currently, we don't support 32-bit visuals and don't set
_NET_SYSTEM_TRAY_VISUAL

It is unclear what happens if the default visual (which is used as a
fallback if _NET_SYSTEM_TRAY_VISUAL is not set) is 32-bit.
In that case, we may need to explicitly use a 24-bit visual.
2023-03-25 19:19:09 +01:00
patrick96
3e3a380069
tray: Remove option TODOs
They are noted in #2689
2023-03-25 19:18:34 +01:00
patrick96
ac589b32dd
Remove TODOs
Not doign this. Using the desired background as the X window background
color would require us to always first check before using the pixmap or
cairo context.
2023-03-25 17:31:52 +01:00
patrick96
616b3fe3e7
color: fix tests 2023-03-23 23:15:21 +01:00
patrick96
47f6d9c25d
renderer: documentation 2023-03-23 23:12:50 +01:00
patrick96
58e0911ac6
tray: Disable pseudo-transparency for opaque bgs 2023-03-23 23:03:45 +01:00
patrick96
89f29fa12e
tray: documentation 2023-03-23 22:41:40 +01:00
patrick96
f6172e1459
Remove tray client gc
Not actually used anywhere
2023-03-23 22:27:43 +01:00
patrick96
1aeac226a6
Delete tray client pixmap and gc in destructor 2023-03-23 22:27:11 +01:00
patrick96
8cc1b4fcfd fix(build): Use CMAKE_INSTALL_FULL_<dir> for default config
Using CMAKE_INSTALL_SYSCONFDIR does respect CMAKE_INSTALL_PREFIX, but it
prefixes it to CMAKE_INSTALL_SYSCONFDIR, which results in the default
config being installed to /usr/etc/polybar/config.ini or
/usr/local/etc/polybar/config.ini

CMAKE_INSTALL_FULL_SYSCONFDIR gives an absolute path that respects the
prefix but does the right thing (uses /etc) if it is /usr

Ref: #2770
2023-02-13 22:08:57 +01:00
patrick96
b3cbf0a644 ci: Update codecov and checkout actions
The coverage job fails because of the outdated codecov action and the
checkout v2 action uses a deprecated version of nodejs
2023-02-13 22:00:43 +01:00
patrick96
fc423c0921 fix(i3): Deal with negative coordinates
Pulls in fix in i3ipcpp repo: https://github.com/polybar/i3ipcpp/pull/12

Fixes https://github.com/polybar/polybar/issues/2888
Ref https://github.com/i3/i3/discussions/5352
2023-01-05 22:11:08 +01:00
patrick96
e8870d6537
tray: Prevent crash when no wallpaper is found 2022-12-21 23:47:57 +01:00
patrick96
edf37385cb script: Bump poll timeout to 250ms
The module has a poll timeout because it needs to periodically check if
it is shutting down. Otherwise, it would be stuck polling and the bar
couldn't shut down until the script produces a new line.

However, this causes the bar to wake up intermittently (currently
~40/s) due to the 25ms timeout.
Bumping this to 250ms still gives us timely shut downs and caps the
number of wake ups to 4/s.

This is only a stop-gap solution, ideally the script runner is
integrated into the main event loop and uses its polling handles which
don't have to wake up to check for a shutdown.

Ref #1778
Ref #2337
2022-12-12 00:52:13 +01:00
patrick96
65279883c3
Replace wait_for_response with handle callback
The poll-loop could in theory swallow events which would not be seen by
the main eventloop
2022-11-30 15:06:17 +01:00
patrick96
aadd4ce1c8
Remove screen realloc argument
Replaced with explicit reset function
2022-11-30 13:41:25 +01:00
patrick96
d5498c8a8a script: Require zero exit code to show empty module.
Showing an empty module if the script failed but produced no output does
not make too much sense.

Ref #2857
2022-11-05 12:43:43 +01:00
patrick96
d296d67953
Merge remote-tracking branch 'upstream/master' into tray-child-window 2022-10-31 23:30:07 +01:00
patrick96
f5d16891dd
tray: Cleanup 2022-10-31 23:21:00 +01:00
patrick96
ca25b5685c
tray: Add back legacy tray implementation
Is used for trays defined through tray-position and nothing else.
2022-10-31 23:05:23 +01:00
patrick96
cfe9a81f55
clang-format: Only indent inner namespaces 2022-10-31 23:04:57 +01:00
tnixeu
ed6a0e90fb fix code in order to support cmake unity builds 2022-10-29 15:09:03 +02:00
patrick96
10cdec3b9f build: Fix deprecation errors 2022-10-23 15:20:21 +02:00
patrick96
87750c064e build: Bump C++ to C++17
Now requires gcc8 or clang7
2022-10-23 15:20:21 +02:00
patrick96
291a4844bc fix(ipc): Crash when sending to multiple instances
In polybar-msg, the connection handle was captured as a reference to a
shared_ptr, but the shared_ptr went out of scope right after.

This probably always caused UB, but was only noticeable for two or more
instances.
2022-10-23 14:19:26 +02:00
Madhav Prabhu C M
30e1cc2595
feat(ipc): <label> support (#2841)
* Label = %output% working

* build fix

* Output as deprecated, Label as default

* Corrections

 * Corrections Simplified

* Changelog updated
2022-10-23 10:47:22 +02:00
Ashwin
1e582accb8 moved warnings near config options 2022-10-22 13:06:06 +02:00
Ashwin
cbf5439e80 changelog 2022-10-22 13:06:06 +02:00
Ashwin
cbfb417dce option to turn off struts 2022-10-22 13:06:06 +02:00
patrick96
7049c755c5
--wip-- [skip ci] tray experiments 2022-10-16 21:31:25 +02:00
patrick96
6d74ae51e7
Merge remote-tracking branch 'upstream/master' into tray-child-window 2022-10-16 21:31:07 +02:00
patrick96
31bdacb3d7 Remove never used systray module
Not the same as the new tray module
2022-10-16 21:25:48 +02:00
patrick96
b0e33053f9 Use debug flags for sanitizer builds 2022-10-16 21:25:48 +02:00
patrick96
3561fd3ad1 Templatify module factory
Saves us a lot of code duplication by generating module type-indexed map
and factory functions from the module class names.
2022-10-16 21:25:48 +02:00
Patrick Ziegler
56779a5902
Make the event loop return shared_ptrs (#2842)
* Return shared_ptr from eventloop

* Add -Wdeprecated-copy-dtor warning

Produces a warning if classes don't have explicit copy operations if
they have a user-defined constructor.
This helps us stick to the rule of 5 (kinda, no warnings for missing
move operators).

* Clean up eventloop

* Fix compiler warnings

* Fix fs_event_handle_t name
2022-10-15 23:21:40 +02:00
patrick96
d6997659fa
cleanup 2022-10-12 23:34:38 +02:00
Madhav Prabhu C M
54b75f23ab
feat(ipc). Per hook format (#2810)
* Added format-x support for ipc_module, tested with demo config

* Certain cases not working

* Certain cases not working, build

* Changed label to output tag, Mixing of default formats wont work

* created changelog
2022-10-09 18:42:36 +02:00
patrick96
3cfa01233c
tray: Fix infinite update loop
tray_client::clear_window is called on expose events for the wrapper
window, thus it must not produce expose events for itself again.
2022-10-09 17:47:39 +02:00
Patrick Ziegler
e9713185cb
backlight: Remove actual_brightness amdgpu check (#2839)
The issue has been fixed in the linux kernel version 5.9 and above so we
are removing our workaround for this from polybar.
Users with older versions can still work around this by explicitly
setting `use-actual-brightness` to false, it is just not done by default
anymore.

Closes #2835
Ref https://bugzilla.kernel.org/show_bug.cgi?id=203905
Ref 69d9f4278d
2022-10-08 15:52:47 +02:00
Ron0Studios
303015244e
feat: longest match ws-icon fuzzy matching (#2831)
* better fuzzy matching

Improved fuzzy matching so that it finds the longest matching icon instead of the first possible match

* Update CHANGELOG.md

* removed debug output

* added tests and improved fuzzy finder

- added return statements to the fuzzy finder
- added tests to check whether the fuzzy finder works.

* minor style changes

* minor change to iconset.cpp

* Delete tasks.json
2022-10-05 23:05:44 +02:00
patrick96
0096fea839
Merge remote-tracking branch 'upstream/master' into tray-child-window 2022-10-05 23:02:18 +02:00
patrick96
2e902fee04
Add .cache to gitignore
Used by clangd
2022-10-05 23:01:54 +02:00
Ashwin Rajesh
03987b19a5
fix(xwindow): Crash when no tag is set in format (#2833)
* xwindow works without tag

* changelog
2022-10-05 21:39:02 +02:00
patrick96
5719d130fd feat(xwindow): %instance%, %class% from WM_CLASS 2022-10-02 20:57:29 +02:00
patrick96
ae3deab0db
Remove unused operator== 2022-10-01 22:28:08 +02:00
patrick96
463ef963a1
Add pseudo transparency back to tray icons 2022-10-01 22:24:23 +02:00
patrick96
c44336573b build: Create clangformat(-dryrun) build targets
The clangformat target updates all files in-place while the
clangformat-dryrun target prints an error message for each format-change
clang-format would apply.
The latter exits with a non-zero error code if there are any changes.
2022-09-28 22:00:33 +02:00
patrick96
def2682b8c
tray: Set _NET_SYSTEM_TRAY_VISUAL 2022-09-26 21:39:10 +02:00
patrick96
5c38d5cb17
tray: Store clients in unique_ptr 2022-09-24 13:20:02 +02:00
patrick96
3da2662022 xwindow: Also listen for WM_NAME changes 2022-09-19 22:54:41 +02:00
Patrick Ziegler
918bc212ee
doc: Remove sphinx language setting (#2822)
Sphinx now emits a warning if `language` is set to `None`
2022-09-19 22:49:03 +02:00
patrick96
0c223ae2bb
fix(tray): Too many printf directives 2022-09-19 21:39:11 +02:00
patrick96
627d43dad2
tray: Set _NET_SYSTEM_TRAY_ORIENTATION 2022-09-19 21:23:22 +02:00
patrick96
63c6b13cbf
tray: Cleanup client state handling 2022-09-15 19:38:45 +02:00
patrick96
5fd62edfca
tray: Cleanup logging 2022-09-14 21:53:02 +02:00
patrick96
8ec9807145
Merge remote-tracking branch 'upstream/master' into tray-child-window 2022-09-13 14:24:59 +02:00
Patrick Ziegler
1d4e30c4be
fix: Handle X events before polling for IO (#2820)
* Use m_connection.poll_for_event

* fix: Handle X events before polling for IO

Polling the XCB file descriptor for X events doesn't detect events that
are already in XCB's event queue but not yet handled.

If this happens, the eventloop polls for IO and the queued events wait
until another event arrives, causing some desyncs in the bar.

This can easily happen if something (e.g. a click event) triggers some
xcb calls, which as a consequence buffer some incoming events.

We "fix" this by adding a libuv prepare handle (which runs right before
polling for IO) that processes pending X events.
2022-09-13 14:21:36 +02:00
patrick96
60173e5042
tray: Better lifecycle handling 2022-09-11 21:51:08 +02:00
patrick96
ea5ffdd6b1
Merge remote-tracking branch 'upstream/master' into tray-child-window 2022-09-11 19:32:29 +02:00
Patrick Ziegler
053a7eb2d8
fix: Crash on root pixmap and window depth mismatch (#2813)
The background_manager used the root window depth for creating its
pixmaps, but when the root pixmap has a different depth, this causes the
copy_area_checked call to fail and crash the bar.

We now load the root pixmap before finding the visual and creating the
slice pixmaps.

Fixes #2798
2022-09-05 09:58:12 +02:00
patrick96
3b9ff04f40
tray: Fix build error 2022-09-04 12:00:45 +02:00
patrick96
fe9660254c
Merge remote-tracking branch 'upstream/master' into tray-child-window 2022-09-04 11:46:32 +02:00
patrick96
901183a60a
tray: Fix tray not updating after (un)map_notify
The issue was that the event was for the wrapper window and that the
tray_client's move constructors didn't correctly copy over all data and
so when the m_clients vector grew, it corrupted the state of all
existing clients.
2022-09-03 22:34:00 +02:00
patrick96
1127792ccf
tray: Update module using callback 2022-09-03 21:33:22 +02:00
patrick96
b72458a6b0
tray: Load settings from module section 2022-09-03 20:56:32 +02:00
patrick96
03a2e6bb17
tray: Read width directly from tray_manager 2022-08-28 15:29:36 +02:00
patrick96
ffcdf7d690
tray: Start tray from module 2022-08-28 15:15:48 +02:00
patrick96
1dcff9396a
tray: Stop listening to ui::visibility_change
If the bar window (un)maps, the tray icons are automatically (un)mapped
2022-08-28 15:05:22 +02:00
patrick96
de560fe810
tray: Remove mutex 2022-08-28 14:56:56 +02:00
patrick96
d658c07177
tray: Cleanup tray settings 2022-08-28 14:49:09 +02:00
patrick96
ef06472a6d
tray: Remove tray window
Each tray client is directly reparented to the bar window. This saves us
the hassle of having to configure a basically useless tray window and
keeping its background pixmap in sync.

The only disadvantages are having to (un)map each client window
individually and calculating its position relative to the bar window
(which changes all the time) instead of relative to the tray window
(which only changes when clients are added/removed).
2022-08-27 23:02:34 +02:00
Patrick Ziegler
d817080ee8
fix(renderer): Small gaps when rendering emojis (#2802)
If any rendered text uses a non-integer number of pixels (often emojis),
rendering of subsequent text blocks will start between pixels which
results in small gaps in the background and over/underline colors caused
by cairo only rendering at fractional-intensity in the beginning and end
pixel.

Simply rounding up text width can solve this.

Fixes #2785
2022-08-25 00:55:16 +02:00
Ashwin Rajesh
7838241a77
feat(tokens): Negative minimum length adds right padding (#2801)
* negative minimum length adds right padding

* missing else statement

* updated changelog
2022-08-25 00:36:38 +02:00
Dave
6ccecbfca2
feat(temperature): Add zone-type setting (#2752)
Signed-off-by: xphoniex <dj.2dixx@gmail.com>

Signed-off-by: xphoniex <dj.2dixx@gmail.com>
2022-08-21 19:25:42 +02:00
Quantenzitrone
708bd9c891
feat(temperature): %temperature-k% token for Kelvin (#2784)
* added kelvin option for module/temperature

* changelog for the changes i made

* fixed typos

* fixed the temperature conversion to be more precise

* Update CHANGELOG.md

Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>

* changed the calculation of the different temperatures

it now uses float as a initial value and makes m_temp temp_k and temp_f by converting and rounding with std::round

* std::lround makes more sense to use than std::round

Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>
2022-08-21 19:10:48 +02:00
patrick96
dca9e15339
tray: Store position relative to inner area 2022-07-26 21:33:28 +02:00
patrick96
9c759549c6
tray: Remove background_manager
The tray window uses the pixmap of the bar window and clears window
content on every update.
2022-07-26 00:01:21 +02:00
patrick96
4bbb28baaf
Merge remote-tracking branch 'upstream/master' into tray-child-window 2022-07-25 23:40:45 +02:00
Patrick Ziegler
b5764c8a93
Use CMAKE_INSTALL_SYSCONFDIR instead of /etc (#2770)
Some distro's build infrastructure (e.g. gentoo) can use
CMAKE_INSTALL_PREFIX to install to a different location.
When the config path is hardcoded to /etc, CMAKE_INSTALL_PREFIX has no
effect.

Ref: https://bugs.gentoo.org/858797
2022-07-19 23:26:11 +02:00
Patrick Ziegler
f4d0ba9186
config_parser: Pass barname as argument to parse() (#2765)
Doesn't need to be a class field
2022-07-09 13:12:37 +02:00
patrick96
841b799299
Add include-file reload fix to changelog 2022-07-09 12:26:07 +02:00
Tuur Vanhoutte
98d584c8fe
Also monitor include-files for changes when --reload is set (#2759)
* fixes #675

* feat(configwatcher): method to create config monitor handler

* cleanup

Co-authored-by: patrick96 <p.ziegler96@gmail.com>
2022-07-09 12:24:21 +02:00
raffael0
a20f76d7e5
fix: tray flickers due to excessive redrawing/visibility changing (#2747)
Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>
2022-07-09 09:09:55 +02:00
raffael0
9f4e88c07d
fix: tray isn't visible when a module updates (#2742) 2022-07-09 08:45:09 +02:00
sysek
a42e533089
doc: change openSUSE description (#2749)
* change openSUSE description

* Update README.md

Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>
2022-06-23 06:38:04 +02:00
raffael0
f3e27a205e
backlight: auto-detect default card (#2728)
* auto-detect a default backlight

* Implemented suggestions

* added changelog

* Implemented suggestions

* Fix changelog formatting

Co-authored-by: patrick96 <p.ziegler96@gmail.com>
2022-06-16 12:54:38 +02:00
raffael0
b2c5d8e0e2
tray: implement hiding functionality (#2723)
* tray hiding works

* clang-format

* Implemented suggestions
2022-06-16 12:53:49 +02:00
raffael0
86f2baa550
tray: remove tray-position = adaptive (#2726)
The tray is automatically started if there is a tray module. In addition, `tray-position` and the tray module conflict.

Ref #2689
2022-06-15 11:09:13 +02:00
raffael0
6a43758b5b
tray is no longer pushed off the bar (#2727) 2022-06-14 15:35:49 +02:00
Franklin Timóteo
ca06be1d0e
Updated instructions for installing on Debian (#2732)
Current version backports is bullseye.
2022-06-12 19:28:18 +02:00
Maxim Kolesnikov
0331a5fda4
fix: error reporting for deprecated config values (#2725) 2022-06-12 16:31:11 +02:00
Patrick Ziegler
1ee11f7c9e
Adapt release workflow to produce signed releases (#2720) 2022-05-09 17:00:14 +02:00
Patrick Ziegler
1f55eaf73d
Adapt to official Arch Linux package (#2719)
Now that polybar is in the official repos, we only need the polybar-git
PKGBUILD.
2022-05-09 16:36:54 +02:00
Leonidas Spyropoulos
8a4fc1f4f7
Update Arch Linux installation instructions (#2717)
polybar is now available in official repos
2022-05-09 15:17:13 +02:00
Patrick Ziegler
f0dbb4cc63
Add darkmode banner (#2712)
Ref #2706
2022-05-04 21:31:25 +02:00
Patrick Ziegler
80bcf55844
Update PKGBUILD for 3.6.3 (#2711) 2022-05-04 11:39:06 +02:00
patrick96
46358792e0
fix(build): Changes in inotify module 2022-05-04 11:09:55 +02:00
patrick96
7a1824a9b9
Merge remote-tracking branch 'origin/hotfix/3.6.3' 2022-05-04 11:08:12 +02:00
Mathis Weber
423cc1720f
fs: fallback if no mountpoints specified (#2705)
Ref #2572
2022-05-02 12:54:03 +02:00
Patrick Ziegler
f9fc02e69c
Add backup directive to PKGBUILD (#2704)
This way changes to the default config made by users are preserved if
polybar ever changes the default config

Ref: https://aur.archlinux.org/packages/polybar-git#comment-863283
2022-04-30 23:03:00 +02:00
marxlaml
6a2d7b5dde
feat(backlight): Add scroll-interval (#2700)
Closes #2696

* Added `scroll-interval` option to `internal/backlight`

* Added PR to CHANGELOG.md

* Fixed indentation
2022-04-27 19:53:06 +02:00
Mathis Weber
b5292791ef
fix: check if double click action associated (#2695)
When a module is clicked, only wait for the double click interval if a
double click action is associated with that module. Otherwise trigger
the click right away.

Fixes: #2663
2022-04-25 12:59:40 +02:00
patrick96
d743a22817 --wip-- [skip ci] 2022-04-16 00:20:00 +02:00
patrick96
9ad73da05f
tray: Remove calculate_client_x 2022-04-16 00:16:50 +02:00
patrick96
bdfe655556
tray: Reuse bar visual 2022-04-16 00:16:50 +02:00
patrick96
81d1f74b7b
Move client configuration into tray_client 2022-04-16 00:16:50 +02:00
patrick96
48d8187f90
Collect bar window, visual, and depth in bar_settings 2022-04-16 00:16:50 +02:00
patrick96
b5c742a63e
Use connection.root() to get root window 2022-04-16 00:16:50 +02:00
patrick96
6043f856b6
controller: Keep only eventloop in try-catch
If an exception is thrown earlier, stopping the eventloop produces an
error.
2022-04-16 00:16:49 +02:00
patrick96
9b1afe7369
Cleanup selection of visual for bar window 2022-04-16 00:16:49 +02:00
patrick96
b8c275d6ac
Fix BadMatch error for wrapper window
The wrapper window must define a border background if the depth doesn't
match the parent window.
2022-04-16 00:16:49 +02:00
patrick96
3711e999ba
Use individual wrapper window for each tray client 2022-04-16 00:16:49 +02:00
patrick96
9544130b9c
Fix screen messing up if client docking fails
The client window has to be added to the save set after it has been
reparented. Otherwise if the reparenting fails weird stuff happens
(windows in the save set have to be child windows of windows created by
the current connection).
2022-04-16 00:16:49 +02:00
patrick96
ab7612ea4a
tray: Make m_clients exclusive owner of clients 2022-04-16 00:16:49 +02:00
patrick96
ab2b5f603c
Use bar window depth for tray pixmap 2022-04-16 00:16:49 +02:00
patrick96
6fa85d2ce8
Remove unused parameter 2022-04-16 00:16:48 +02:00
patrick96
7acd4c703c
xcb: Cleanup value packing 2022-04-16 00:16:48 +02:00
patrick96
ba0e478026
Cleanup tray position handling 2022-04-16 00:16:44 +02:00
patrick96
3244b10ce3
Make tray window a bar subwindow
Currently requires a dirty workaround to prevent tray icons with
different depths from crashing
2022-04-16 00:13:53 +02:00
patrick96
18485d00c2
Cleanup tray code 2022-04-16 00:00:30 +02:00
raffael0
4961a7dcfc
feat(tray): Position using a module (#2595)
Closes: #1526
Closes: #314

* debug log

* semi-working prototype. works on the left and the center but not on the right

* fixes formatting

* fixes tests

* - fixed tray_width_change signal
- implements suggestions

* - fixes error with tray positioning

* - tries to fix tests. Does not work

* - fixes tests

* - implemented suggestions

* reverted formatting in comake and doc

* - changed unique_ptr to const reference

* - fixed formatting errors in code

* - actually fixed formatting(ran clang-format)

* - implemented suggestions

* - Added CHANGELOG.md entry(not sure about wording)

* - removed bar_settings from tray_manager::setup

* - fixed issue from rebase

* - fixed issue with tests from rebase

* implemented suggestions

* Update CHANGELOG.md

Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>
2022-04-15 23:50:04 +02:00
patrick96
973b1fa3d3 feat(text): Add standard format with label
Closes #1331
Closes #1342
Fixes #2673
2022-04-04 12:01:06 +02:00
patrick96
652652f943 Update PKGBUILD for 3.6.2 2022-04-03 20:24:02 +02:00
patrick96
49b18fb3b7
Merge branch 'hotfix/3.6.2' 2022-04-03 20:11:19 +02:00
patrick96
8363b20793 doc: Disable collapse_navigation in rtd_theme 2022-04-03 14:32:15 +02:00
patrick96
80173c6413 Add section about distro specific setups 2022-04-03 14:32:15 +02:00
patrick96
61c4976bb5 doc: Add getting started for developers 2022-04-03 14:32:15 +02:00
patrick96
e1856cf8ec Move testing page to repo 2022-04-03 14:32:15 +02:00
patrick96
f6651d58d0 Move style guide to repo 2022-04-03 14:32:15 +02:00
Patrick Ziegler
aaac4c45ff
Fix changelog entry for interval-fail (#2669)
It was mistakenly added to the 3.6 changelog
2022-04-03 13:11:28 +02:00
Farseen
a2c1392c12
feat(pulseaudio): define reverse-scroll option (#2664)
* pulseaudio: define reverse-scroll option

When we enable natural scrolling option in libinput,
it sends scroll down event when we swipe up on the touchpad.
This makes the pulseaudio module feel weird.
This option fixes that.

* Update CHANGELOG.md

Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>
2022-04-02 23:45:54 +02:00
indev
36d19d372d fix(script): do not hide failing scripts with constant output 2022-04-02 23:24:05 +02:00
patrick96
ff6ac9fefc Make ewmh_connection act as xcb_ewmh_connection_t*
This way, we don't have to explicitly get the xcb_ewmh_connection_t
pointer from the object and can simply derference the ewmh instance
itself.
2022-03-21 21:37:12 +01:00
patrick96
b8075c9b4d Add polybar-msg same-user restriction to changelog 2022-03-19 12:26:53 +01:00
patrick96
3079acb34c Remove YCM config
Not clear if it even works anymore.
We suggest maintaining your own YCM config or using a language server
like CCLS in combination with the generated compile_commands.json
2022-03-13 21:26:54 +01:00
patrick96
39a640d5d0 Move banner to doc folder 2022-03-13 21:26:54 +01:00
patrick96
b8af14fa8c Move codecov.yml to .github folder 2022-03-13 21:26:54 +01:00
Ishaan Bhimwal
6e4ef632eb
readme: add manjaro (#2638) 2022-03-13 21:19:26 +01:00
patrick96
880fbc242d Expand support page 2022-03-07 22:34:16 +01:00
patrick96
9badbd00f3 Update maintainers in README 2022-03-07 22:34:16 +01:00
patrick96
245878e91c Update markdown files to point to discussions 2022-03-07 22:34:16 +01:00
patrick96
67fb58c993 Move features request and build issues to Discussions 2022-03-07 22:34:16 +01:00
patrick96
60eb7b522a Issue template typo 2022-03-07 22:34:16 +01:00
Frank Großgasteiger
638a57379b
Redraw tray on wallpaper change, only if transparent (#2604)
The tray manager of polybar listens on multiple atoms for the background of the root window. On change of these atoms, it will redraw its window-background and message its tray-client to redraw also.

On fast changes of of background, this leads to immense messaging and eventual flickering of the systray.

This patch tries to soften the issue in a way, that tray-window and its client will only redraw, if the bar has transparency. If not, there should be no reason to redraw on wallpaper-change.

* Redraw on background change only if transparent

* Replace tab with spaces
2022-03-07 19:16:07 +01:00
indev
5b2de60353 feat(script): add repeat interval for script failure and exec-if 2022-03-07 15:44:55 +01:00
patrick96
50eac859fd Cleanup use of pointers in util code 2022-03-06 18:28:26 +01:00
patrick96
8ddf9d2cdf Stop using unique_ptr for on_exit 2022-03-06 18:28:26 +01:00
patrick96
b66f920308 Cleanup xcb stuff 2022-03-06 18:28:26 +01:00
patrick96
8db3e04727 Update PKGBUILD for 3.6.1 2022-03-05 14:38:09 +01:00
patrick96
1a4ad828c6
Merge branch 'hotfix/3.6.1' 2022-03-05 14:30:38 +01:00
patrick96
f37124f5af renderer: Enforce valid alignment
No renderer_interface function (except change_alignment) should be
called with a NONE alignment in the context.
2022-03-05 13:37:28 +01:00
patrick96
fdaecdb113 tests: Use fake renderer for dispatch test 2022-03-05 13:37:28 +01:00
patrick96
219171cf79 Update PKGBUILD for 3.6.0 2022-03-01 20:44:54 +01:00
patrick96
57589ee896 Update PKGBUILD for 3.6.0 2022-03-01 19:47:50 +01:00
214 changed files with 7632 additions and 4662 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,13 +3,14 @@
#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
namespace modules { namespace modules {
class dwm_module : public event_module<dwm_module> { class dwm_module : public event_module<dwm_module> {
public: public:
explicit dwm_module(const bar_settings&, string); explicit dwm_module(const bar_settings&, string, const config&);
using tag_mask_t = unsigned int; using tag_mask_t = unsigned int;
using window_t = unsigned int; using window_t = unsigned int;
@ -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