mirror of
https://github.com/rad4day/Waybar.git
synced 2023-12-21 10:22:59 +01:00
Compare commits
74 Commits
Author | SHA1 | Date | |
---|---|---|---|
3c1ba0a240 | |||
6c7acf18b5 | |||
ead1b2f0dc | |||
115c6e36e6 | |||
210f4454f0 | |||
77d8376fef | |||
0e580236ce | |||
1aa7587cac | |||
b6655e475b | |||
903fc2b6a2 | |||
50fc63b749 | |||
383d999fec | |||
56ebb09e5f | |||
35d6da3965 | |||
be1d2a02ca | |||
5e7ba0c9e3 | |||
18717d4b12 | |||
4dc1989744 | |||
54085dbde0 | |||
4635e8c5f8 | |||
adc67b6f75 | |||
ebe4424795 | |||
e3f56b8110 | |||
8f3fbebede | |||
a595b61e0f | |||
91339f6ad4 | |||
3c18c43b9a | |||
ac20428fdf | |||
ad5ea7ad2b | |||
851508df5e | |||
fc818dd794 | |||
e066e3080e | |||
1a93a6cfa5 | |||
074b559da5 | |||
7a61a00fb3 | |||
d4da04a750 | |||
f3819ee954 | |||
2697d432a4 | |||
061cb76fc4 | |||
6c188455a4 | |||
12caae8fd2 | |||
26ea6fae32 | |||
26419e45b7 | |||
6be741afc9 | |||
c80cc873af | |||
2b42872b6c | |||
895bc878f8 | |||
a0ee9e7fc1 | |||
941cf47693 | |||
32d42749f9 | |||
96caa9f094 | |||
f4f1267a71 | |||
bcadf64031 | |||
8974bbf7b4 | |||
1c08d26af0 | |||
c4cc7ae396 | |||
65dd245362 | |||
667d0a45f4 | |||
53fc750fc3 | |||
27df7a9aa7 | |||
d575646c2d | |||
3a6e5be59d | |||
81f0bcb3a3 | |||
9ae99c2621 | |||
5abdecc402 | |||
2301788a81 | |||
d22d6a4522 | |||
ece86c96d7 | |||
bb7b376fa6 | |||
e10c9dd011 | |||
b0eab5d793 | |||
17bb5643ae | |||
8d9e322507 | |||
94e53c3777 |
4
.github/workflows/freebsd.yml
vendored
4
.github/workflows/freebsd.yml
vendored
@ -11,7 +11,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Test in FreeBSD VM
|
- name: Test in FreeBSD VM
|
||||||
uses: vmactions/freebsd-vm@v0.1.5 # aka FreeBSD 13.0
|
uses: vmactions/freebsd-vm@v0.1.6 # aka FreeBSD 13.0
|
||||||
with:
|
with:
|
||||||
mem: 2048
|
mem: 2048
|
||||||
usesh: true
|
usesh: true
|
||||||
@ -21,7 +21,7 @@ jobs:
|
|||||||
pkg install -y git # subprojects/date
|
pkg install -y git # subprojects/date
|
||||||
pkg install -y catch evdev-proto gtk-layer-shell gtkmm30 jsoncpp \
|
pkg install -y catch evdev-proto gtk-layer-shell gtkmm30 jsoncpp \
|
||||||
libdbusmenu libevdev libfmt libmpdclient libudev-devd meson \
|
libdbusmenu libevdev libfmt libmpdclient libudev-devd meson \
|
||||||
pkgconf pulseaudio scdoc sndio spdlog
|
pkgconf pulseaudio scdoc sndio spdlog wayland-protocols
|
||||||
run: |
|
run: |
|
||||||
meson build -Dman-pages=enabled
|
meson build -Dman-pages=enabled
|
||||||
ninja -C build
|
ninja -C build
|
||||||
|
11
README.md
11
README.md
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
> Highly customizable Wayland bar for Sway and Wlroots based compositors.<br>
|
> Highly customizable Wayland bar for Sway and Wlroots based compositors.<br>
|
||||||
> Available in Arch [community](https://www.archlinux.org/packages/community/x86_64/waybar/) or
|
> Available in Arch [community](https://www.archlinux.org/packages/community/x86_64/waybar/) or
|
||||||
[AUR](https://aur.archlinux.org/packages/waybar-git/), [Gentoo](https://packages.gentoo.org/packages/gui-apps/waybar), [openSUSE](https://build.opensuse.org/package/show/X11:Wayland/waybar), and [Alpine Linux](https://pkgs.alpinelinux.org/packages?name=waybar)<br>
|
[AUR](https://aur.archlinux.org/packages/waybar-git/), [Gentoo](https://packages.gentoo.org/packages/gui-apps/waybar), [openSUSE](https://build.opensuse.org/package/show/X11:Wayland/waybar), and [Alpine Linux](https://pkgs.alpinelinux.org/packages?name=waybar).<br>
|
||||||
> *Waybar [examples](https://github.com/Alexays/Waybar/wiki/Examples)*
|
> *Waybar [examples](https://github.com/Alexays/Waybar/wiki/Examples)*
|
||||||
|
|
||||||
#### Current features
|
#### Current features
|
||||||
@ -20,7 +20,7 @@
|
|||||||
- MPD
|
- MPD
|
||||||
- Custom scripts
|
- Custom scripts
|
||||||
- Multiple output configuration
|
- Multiple output configuration
|
||||||
- And much more customizations
|
- And many more customizations
|
||||||
|
|
||||||
#### Configuration and Styling
|
#### Configuration and Styling
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ scdoc
|
|||||||
wayland-protocols
|
wayland-protocols
|
||||||
```
|
```
|
||||||
|
|
||||||
On Ubuntu you can install all the relevant dependencies using this command (tested with 19.10 and 20.04):
|
On Ubuntu, you can install all the relevant dependencies using this command (tested with 19.10 and 20.04):
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo apt install \
|
sudo apt install \
|
||||||
@ -107,8 +107,9 @@ sudo apt install \
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
Contributions welcome! - have fun :)<br>
|
Contributions welcome!<br>
|
||||||
The style guidelines is [Google's](https://google.github.io/styleguide/cppguide.html)
|
Have fun :)<br>
|
||||||
|
The style guidelines are [Google's](https://google.github.io/styleguide/cppguide.html)
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
25
include/AIconLabel.hpp
Normal file
25
include/AIconLabel.hpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gtkmm/box.h>
|
||||||
|
#include <gtkmm/image.h>
|
||||||
|
|
||||||
|
#include "ALabel.hpp"
|
||||||
|
|
||||||
|
namespace waybar {
|
||||||
|
|
||||||
|
class AIconLabel : public ALabel {
|
||||||
|
public:
|
||||||
|
AIconLabel(const Json::Value &config, const std::string &name, const std::string &id,
|
||||||
|
const std::string &format, uint16_t interval = 0, bool ellipsize = false,
|
||||||
|
bool enable_click = false, bool enable_scroll = false);
|
||||||
|
virtual ~AIconLabel() = default;
|
||||||
|
virtual auto update() -> void;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Gtk::Image image_;
|
||||||
|
Gtk::Box box_;
|
||||||
|
|
||||||
|
bool iconEnabled() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace waybar
|
@ -11,6 +11,7 @@ struct waybar_time;
|
|||||||
namespace modules {
|
namespace modules {
|
||||||
|
|
||||||
const std::string kCalendarPlaceholder = "calendar";
|
const std::string kCalendarPlaceholder = "calendar";
|
||||||
|
const std::string KTimezonedTimeListPlaceholder = "timezoned_time_list";
|
||||||
|
|
||||||
class Clock : public ALabel {
|
class Clock : public ALabel {
|
||||||
public:
|
public:
|
||||||
@ -26,6 +27,7 @@ class Clock : public ALabel {
|
|||||||
date::year_month_day cached_calendar_ymd_ = date::January/1/0;
|
date::year_month_day cached_calendar_ymd_ = date::January/1/0;
|
||||||
std::string cached_calendar_text_;
|
std::string cached_calendar_text_;
|
||||||
bool is_calendar_in_tooltip_;
|
bool is_calendar_in_tooltip_;
|
||||||
|
bool is_timezoned_list_in_tooltip_;
|
||||||
|
|
||||||
bool handleScroll(GdkEventScroll* e);
|
bool handleScroll(GdkEventScroll* e);
|
||||||
|
|
||||||
@ -34,6 +36,7 @@ class Clock : public ALabel {
|
|||||||
auto first_day_of_week() -> date::weekday;
|
auto first_day_of_week() -> date::weekday;
|
||||||
const date::time_zone* current_timezone();
|
const date::time_zone* current_timezone();
|
||||||
bool is_timezone_fixed();
|
bool is_timezone_fixed();
|
||||||
|
auto timezones_text(std::chrono::_V2::system_clock::time_point *now) -> std::string;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace modules
|
} // namespace modules
|
||||||
|
@ -24,8 +24,6 @@ class KeyboardState : public AModule {
|
|||||||
auto update() -> void;
|
auto update() -> void;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static auto openDevice(const std::string&) -> std::pair<int, libevdev*>;
|
|
||||||
|
|
||||||
Gtk::Box box_;
|
Gtk::Box box_;
|
||||||
Gtk::Label numlock_label_;
|
Gtk::Label numlock_label_;
|
||||||
Gtk::Label capslock_label_;
|
Gtk::Label capslock_label_;
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include "ALabel.hpp"
|
|
||||||
|
#include "AIconLabel.hpp"
|
||||||
#include "bar.hpp"
|
#include "bar.hpp"
|
||||||
#include "client.hpp"
|
#include "client.hpp"
|
||||||
#include "modules/sway/ipc/client.hpp"
|
#include "modules/sway/ipc/client.hpp"
|
||||||
@ -10,7 +11,7 @@
|
|||||||
|
|
||||||
namespace waybar::modules::sway {
|
namespace waybar::modules::sway {
|
||||||
|
|
||||||
class Window : public ALabel, public sigc::trackable {
|
class Window : public AIconLabel, public sigc::trackable {
|
||||||
public:
|
public:
|
||||||
Window(const std::string&, const waybar::Bar&, const Json::Value&);
|
Window(const std::string&, const waybar::Bar&, const Json::Value&);
|
||||||
~Window() = default;
|
~Window() = default;
|
||||||
@ -23,6 +24,7 @@ class Window : public ALabel, public sigc::trackable {
|
|||||||
std::string& output);
|
std::string& output);
|
||||||
void getTree();
|
void getTree();
|
||||||
std::string rewriteTitle(const std::string& title);
|
std::string rewriteTitle(const std::string& title);
|
||||||
|
void updateAppIcon();
|
||||||
|
|
||||||
const Bar& bar_;
|
const Bar& bar_;
|
||||||
std::string window_;
|
std::string window_;
|
||||||
|
@ -68,7 +68,10 @@ inline int close(FILE* fp, pid_t pid) {
|
|||||||
inline FILE* open(const std::string& cmd, int& pid) {
|
inline FILE* open(const std::string& cmd, int& pid) {
|
||||||
if (cmd == "") return nullptr;
|
if (cmd == "") return nullptr;
|
||||||
int fd[2];
|
int fd[2];
|
||||||
pipe(fd);
|
if (pipe(fd) != 0){
|
||||||
|
spdlog::error("Unable to pipe fd");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
pid_t child_pid = fork();
|
pid_t child_pid = fork();
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
#include <glibmm/ustring.h>
|
||||||
|
|
||||||
class pow_format {
|
class pow_format {
|
||||||
public:
|
public:
|
||||||
@ -84,5 +85,15 @@ namespace fmt {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Glib ustirng support
|
||||||
|
template <>
|
||||||
|
struct formatter<Glib::ustring> : formatter<std::string> {
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const Glib::ustring& value, FormatContext& ctx) {
|
||||||
|
return formatter<std::string>::format(value, ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
const std::string WHITESPACE = " \n\r\t\f\v";
|
const std::string WHITESPACE = " \n\r\t\f\v";
|
||||||
|
|
||||||
std::string ltrim(const std::string s) {
|
inline std::string ltrim(const std::string& s) {
|
||||||
size_t begin = s.find_first_not_of(WHITESPACE);
|
size_t begin = s.find_first_not_of(WHITESPACE);
|
||||||
return (begin == std::string::npos) ? "" : s.substr(begin);
|
return (begin == std::string::npos) ? "" : s.substr(begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string rtrim(const std::string s) {
|
inline std::string rtrim(const std::string& s) {
|
||||||
size_t end = s.find_last_not_of(WHITESPACE);
|
size_t end = s.find_last_not_of(WHITESPACE);
|
||||||
return (end == std::string::npos) ? "" : s.substr(0, end + 1);
|
return (end == std::string::npos) ? "" : s.substr(0, end + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string trim(const std::string& s) { return rtrim(ltrim(s)); }
|
inline std::string trim(const std::string& s) { return rtrim(ltrim(s)); }
|
||||||
|
@ -86,11 +86,17 @@ The *clock* module displays the current date and time.
|
|||||||
typeof: double ++
|
typeof: double ++
|
||||||
Threshold to be used when scrolling.
|
Threshold to be used when scrolling.
|
||||||
|
|
||||||
|
*tooltip*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: true ++
|
||||||
|
Option to disable tooltip on hover.
|
||||||
|
|
||||||
View all valid format options in *strftime(3)*.
|
View all valid format options in *strftime(3)*.
|
||||||
|
|
||||||
# FORMAT REPLACEMENTS
|
# FORMAT REPLACEMENTS
|
||||||
|
|
||||||
*{calendar}*: Current month calendar
|
*{calendar}*: Current month calendar
|
||||||
|
*{timezoned_time_list}*: List of time in the rest timezones, if more than one timezone is set in the config
|
||||||
|
|
||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
|
|
||||||
|
@ -151,7 +151,8 @@ $text\\n$tooltip\\n$class*
|
|||||||
"max-length": 40,
|
"max-length": 40,
|
||||||
"interval": 30, // Remove this if your script is endless and write in loop
|
"interval": 30, // Remove this if your script is endless and write in loop
|
||||||
"exec": "$HOME/.config/waybar/mediaplayer.sh 2> /dev/null", // Script in resources folder
|
"exec": "$HOME/.config/waybar/mediaplayer.sh 2> /dev/null", // Script in resources folder
|
||||||
"exec-if": "pgrep spotify"
|
"exec-if": "pgrep spotify",
|
||||||
|
"return-type": "json"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@ waybar - keyboard-state module
|
|||||||
|
|
||||||
The *keyboard-state* module displays the state of number lock, caps lock, and scroll lock.
|
The *keyboard-state* module displays the state of number lock, caps lock, and scroll lock.
|
||||||
|
|
||||||
|
You must be a member of the input group to use this module.
|
||||||
|
|
||||||
# CONFIGURATION
|
# CONFIGURATION
|
||||||
|
|
||||||
*interval*: ++
|
*interval*: ++
|
||||||
|
@ -84,12 +84,20 @@ Addressed by *memory*
|
|||||||
|
|
||||||
*{percentage}*: Percentage of memory in use.
|
*{percentage}*: Percentage of memory in use.
|
||||||
|
|
||||||
|
*{swapPercentage}*: Percentage of swap in use.
|
||||||
|
|
||||||
*{total}*: Amount of total memory available in GiB.
|
*{total}*: Amount of total memory available in GiB.
|
||||||
|
|
||||||
|
*{swapTotal}*: Amount of total swap available in GiB.
|
||||||
|
|
||||||
*{used}*: Amount of used memory in GiB.
|
*{used}*: Amount of used memory in GiB.
|
||||||
|
|
||||||
|
*{swapUsed}*: Amount of used swap in GiB.
|
||||||
|
|
||||||
*{avail}*: Amount of available memory in GiB.
|
*{avail}*: Amount of available memory in GiB.
|
||||||
|
|
||||||
|
*{swapAvail}*: Amount of available swap in GiB.
|
||||||
|
|
||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -69,7 +69,7 @@ Addressed by *sway/mode*
|
|||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
|
|
||||||
```
|
```
|
||||||
"sway/window": {
|
"sway/mode": {
|
||||||
"format": " {}",
|
"format": " {}",
|
||||||
"max-length": 50
|
"max-length": 50
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,11 @@ Addressed by *sway/window*
|
|||||||
typeof: object ++
|
typeof: object ++
|
||||||
Rules to rewrite window title. See *rewrite rules*.
|
Rules to rewrite window title. See *rewrite rules*.
|
||||||
|
|
||||||
|
*icon*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
Option to hide the application icon.
|
||||||
|
|
||||||
# REWRITE RULES
|
# REWRITE RULES
|
||||||
|
|
||||||
*rewrite* is an object where keys are regular expressions and values are
|
*rewrite* is an object where keys are regular expressions and values are
|
||||||
|
@ -29,6 +29,10 @@ Addressed by *tray*
|
|||||||
typeof: integer ++
|
typeof: integer ++
|
||||||
Defines the spacing between the tray icons.
|
Defines the spacing between the tray icons.
|
||||||
|
|
||||||
|
*reverse-direction*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
Defines if new app icons should be added in a reverse order
|
||||||
|
|
||||||
*on-update*: ++
|
*on-update*: ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
Command to execute when the module is updated.
|
Command to execute when the module is updated.
|
||||||
|
@ -93,10 +93,15 @@ Addressed by *wlr/taskbar*
|
|||||||
# CLICK ACTIONS
|
# CLICK ACTIONS
|
||||||
|
|
||||||
*activate*: Bring the application into foreground.
|
*activate*: Bring the application into foreground.
|
||||||
|
|
||||||
*minimize*: Toggle application's minimized state.
|
*minimize*: Toggle application's minimized state.
|
||||||
|
|
||||||
*minimize-raise*: Bring the application into foreground or toggle its minimized state.
|
*minimize-raise*: Bring the application into foreground or toggle its minimized state.
|
||||||
|
|
||||||
*maximize*: Toggle application's maximized state.
|
*maximize*: Toggle application's maximized state.
|
||||||
|
|
||||||
*fullscreen*: Toggle application's fullscreen state.
|
*fullscreen*: Toggle application's fullscreen state.
|
||||||
|
|
||||||
*close*: Close the application.
|
*close*: Close the application.
|
||||||
|
|
||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
|
@ -52,6 +52,7 @@ Addressed by *wlr/workspaces*
|
|||||||
# CLICK ACTIONS
|
# CLICK ACTIONS
|
||||||
|
|
||||||
*activate*: Switch to workspace.
|
*activate*: Switch to workspace.
|
||||||
|
|
||||||
*close*: Close the workspace.
|
*close*: Close the workspace.
|
||||||
|
|
||||||
# ICONS
|
# ICONS
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
project(
|
project(
|
||||||
'waybar', 'cpp', 'c',
|
'waybar', 'cpp', 'c',
|
||||||
version: '0.9.9',
|
version: '0.9.12',
|
||||||
license: 'MIT',
|
license: 'MIT',
|
||||||
meson_version: '>= 0.49.0',
|
meson_version: '>= 0.49.0',
|
||||||
default_options : [
|
default_options : [
|
||||||
@ -142,6 +142,7 @@ src_files = files(
|
|||||||
'src/factory.cpp',
|
'src/factory.cpp',
|
||||||
'src/AModule.cpp',
|
'src/AModule.cpp',
|
||||||
'src/ALabel.cpp',
|
'src/ALabel.cpp',
|
||||||
|
'src/AIconLabel.cpp',
|
||||||
'src/modules/custom.cpp',
|
'src/modules/custom.cpp',
|
||||||
'src/modules/disk.cpp',
|
'src/modules/disk.cpp',
|
||||||
'src/modules/idle_inhibitor.cpp',
|
'src/modules/idle_inhibitor.cpp',
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
* {
|
* {
|
||||||
/* `otf-font-awesome` is required to be installed for icons */
|
/* `otf-font-awesome` is required to be installed for icons */
|
||||||
font-family: Roboto, Helvetica, Arial, sans-serif;
|
font-family: FontAwesome, Roboto, Helvetica, Arial, sans-serif;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
28
src/AIconLabel.cpp
Normal file
28
src/AIconLabel.cpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#include "AIconLabel.hpp"
|
||||||
|
|
||||||
|
#include <gdkmm/pixbuf.h>
|
||||||
|
|
||||||
|
namespace waybar {
|
||||||
|
|
||||||
|
AIconLabel::AIconLabel(const Json::Value &config, const std::string &name, const std::string &id,
|
||||||
|
const std::string &format, uint16_t interval, bool ellipsize,
|
||||||
|
bool enable_click, bool enable_scroll)
|
||||||
|
: ALabel(config, name, id, format, interval, ellipsize, enable_click, enable_scroll) {
|
||||||
|
event_box_.remove();
|
||||||
|
box_.set_orientation(Gtk::Orientation::ORIENTATION_HORIZONTAL);
|
||||||
|
box_.set_spacing(8);
|
||||||
|
box_.add(image_);
|
||||||
|
box_.add(label_);
|
||||||
|
event_box_.add(box_);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto AIconLabel::update() -> void {
|
||||||
|
image_.set_visible(image_.get_visible() && iconEnabled());
|
||||||
|
ALabel::update();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AIconLabel::iconEnabled() const {
|
||||||
|
return config_["icon"].isBool() ? config_["icon"].asBool() : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace waybar
|
@ -6,7 +6,9 @@ namespace waybar {
|
|||||||
|
|
||||||
AModule::AModule(const Json::Value& config, const std::string& name, const std::string& id,
|
AModule::AModule(const Json::Value& config, const std::string& name, const std::string& id,
|
||||||
bool enable_click, bool enable_scroll)
|
bool enable_click, bool enable_scroll)
|
||||||
: name_(std::move(name)), config_(std::move(config)) {
|
: name_(std::move(name)), config_(std::move(config))
|
||||||
|
, distance_scrolled_y_(0.0)
|
||||||
|
, distance_scrolled_x_(0.0) {
|
||||||
// configure events' user commands
|
// configure events' user commands
|
||||||
if (config_["on-click"].isString() || config_["on-click-middle"].isString() ||
|
if (config_["on-click"].isString() || config_["on-click-middle"].isString() ||
|
||||||
config_["on-click-backward"].isString() || config_["on-click-forward"].isString() ||
|
config_["on-click-backward"].isString() || config_["on-click-forward"].isString() ||
|
||||||
|
@ -750,7 +750,7 @@ void waybar::Bar::getModules(const Factory& factory, const std::string& pos, Gtk
|
|||||||
modules_right_.emplace_back(module_sp);
|
modules_right_.emplace_back(module_sp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
module->dp.connect([module, &name] {
|
module->dp.connect([module, name] {
|
||||||
try {
|
try {
|
||||||
module->update();
|
module->update();
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
|
@ -161,7 +161,7 @@ const std::tuple<uint8_t, float, std::string, float> waybar::modules::Battery::g
|
|||||||
uint32_t energy_now;
|
uint32_t energy_now;
|
||||||
uint32_t energy_full_design;
|
uint32_t energy_full_design;
|
||||||
std::string _status;
|
std::string _status;
|
||||||
std::ifstream(bat / "status") >> _status;
|
std::getline(std::ifstream(bat / "status"), _status);
|
||||||
|
|
||||||
// Some battery will report current and charge in μA/μAh.
|
// Some battery will report current and charge in μA/μAh.
|
||||||
// Scale these by the voltage to get μW/μWh.
|
// Scale these by the voltage to get μW/μWh.
|
||||||
|
@ -23,7 +23,8 @@ using waybar::waybar_time;
|
|||||||
waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
|
waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
|
||||||
: ALabel(config, "clock", id, "{:%H:%M}", 60, false, false, true),
|
: ALabel(config, "clock", id, "{:%H:%M}", 60, false, false, true),
|
||||||
current_time_zone_idx_(0),
|
current_time_zone_idx_(0),
|
||||||
is_calendar_in_tooltip_(false)
|
is_calendar_in_tooltip_(false),
|
||||||
|
is_timezoned_list_in_tooltip_(false)
|
||||||
{
|
{
|
||||||
if (config_["timezones"].isArray() && !config_["timezones"].empty()) {
|
if (config_["timezones"].isArray() && !config_["timezones"].empty()) {
|
||||||
for (const auto& zone_name: config_["timezones"]) {
|
for (const auto& zone_name: config_["timezones"]) {
|
||||||
@ -64,6 +65,9 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
|
|||||||
if (trimmed_format.find("{" + kCalendarPlaceholder + "}") != std::string::npos) {
|
if (trimmed_format.find("{" + kCalendarPlaceholder + "}") != std::string::npos) {
|
||||||
is_calendar_in_tooltip_ = true;
|
is_calendar_in_tooltip_ = true;
|
||||||
}
|
}
|
||||||
|
if (trimmed_format.find("{" + KTimezonedTimeListPlaceholder + "}") != std::string::npos) {
|
||||||
|
is_timezoned_list_in_tooltip_ = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config_["locale"].isString()) {
|
if (config_["locale"].isString()) {
|
||||||
@ -99,7 +103,7 @@ auto waybar::modules::Clock::update() -> void {
|
|||||||
// As date dep is not fully compatible, prefer fmt
|
// As date dep is not fully compatible, prefer fmt
|
||||||
tzset();
|
tzset();
|
||||||
auto localtime = fmt::localtime(std::chrono::system_clock::to_time_t(now));
|
auto localtime = fmt::localtime(std::chrono::system_clock::to_time_t(now));
|
||||||
text = fmt::format(format_, localtime);
|
text = fmt::format(locale_, format_, localtime);
|
||||||
} else {
|
} else {
|
||||||
text = fmt::format(format_, wtime);
|
text = fmt::format(format_, wtime);
|
||||||
}
|
}
|
||||||
@ -108,15 +112,19 @@ auto waybar::modules::Clock::update() -> void {
|
|||||||
if (tooltipEnabled()) {
|
if (tooltipEnabled()) {
|
||||||
if (config_["tooltip-format"].isString()) {
|
if (config_["tooltip-format"].isString()) {
|
||||||
std::string calendar_lines = "";
|
std::string calendar_lines = "";
|
||||||
|
std::string timezoned_time_lines = "";
|
||||||
if (is_calendar_in_tooltip_) {
|
if (is_calendar_in_tooltip_) {
|
||||||
calendar_lines = calendar_text(wtime);
|
calendar_lines = calendar_text(wtime);
|
||||||
}
|
}
|
||||||
|
if (is_timezoned_list_in_tooltip_) {
|
||||||
|
timezoned_time_lines = timezones_text(&now);
|
||||||
|
}
|
||||||
auto tooltip_format = config_["tooltip-format"].asString();
|
auto tooltip_format = config_["tooltip-format"].asString();
|
||||||
text = fmt::format(tooltip_format, wtime, fmt::arg(kCalendarPlaceholder.c_str(), calendar_lines));
|
text = fmt::format(tooltip_format, wtime, fmt::arg(kCalendarPlaceholder.c_str(), calendar_lines), fmt::arg(KTimezonedTimeListPlaceholder.c_str(), timezoned_time_lines));
|
||||||
|
label_.set_tooltip_markup(text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
label_.set_tooltip_markup(text);
|
|
||||||
// Call parent update
|
// Call parent update
|
||||||
ALabel::update();
|
ALabel::update();
|
||||||
}
|
}
|
||||||
@ -211,6 +219,26 @@ auto waybar::modules::Clock::weekdays_header(const date::weekday& first_dow, std
|
|||||||
os << "\n";
|
os << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto waybar::modules::Clock::timezones_text(std::chrono::_V2::system_clock::time_point *now) -> std::string {
|
||||||
|
if (time_zones_.size() == 1) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
std::stringstream os;
|
||||||
|
waybar_time wtime;
|
||||||
|
for (size_t time_zone_idx = 0; time_zone_idx < time_zones_.size(); ++time_zone_idx) {
|
||||||
|
if (static_cast<int>(time_zone_idx) == current_time_zone_idx_) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const date::time_zone* timezone = time_zones_[time_zone_idx];
|
||||||
|
if (!timezone) {
|
||||||
|
timezone = date::current_zone();
|
||||||
|
}
|
||||||
|
wtime = {locale_, date::make_zoned(timezone, date::floor<std::chrono::seconds>(*now))};
|
||||||
|
os << fmt::format(format_, wtime) << "\n";
|
||||||
|
}
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LANGINFO_1STDAY
|
#ifdef HAVE_LANGINFO_1STDAY
|
||||||
template <auto fn>
|
template <auto fn>
|
||||||
using deleter_from_fn = std::integral_constant<decltype(fn), fn>;
|
using deleter_from_fn = std::integral_constant<decltype(fn), fn>;
|
||||||
|
@ -62,7 +62,7 @@ auto waybar::modules::Cpu::update() -> void {
|
|||||||
double waybar::modules::Cpu::getCpuLoad() {
|
double waybar::modules::Cpu::getCpuLoad() {
|
||||||
double load[1];
|
double load[1];
|
||||||
if (getloadavg(load, 1) != -1) {
|
if (getloadavg(load, 1) != -1) {
|
||||||
return load[0];
|
return std::ceil(load[0] * 100.0) / 100.0;
|
||||||
}
|
}
|
||||||
throw std::runtime_error("Can't get Cpu load");
|
throw std::runtime_error("Can't get Cpu load");
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#include "modules/keyboard_state.hpp"
|
#include "modules/keyboard_state.hpp"
|
||||||
|
#include <errno.h>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
@ -8,6 +10,69 @@ extern "C" {
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class errno_error : public std::runtime_error {
|
||||||
|
public:
|
||||||
|
int code;
|
||||||
|
errno_error(int code, const std::string& msg)
|
||||||
|
: std::runtime_error(getErrorMsg(code, msg.c_str())),
|
||||||
|
code(code) {}
|
||||||
|
errno_error(int code, const char* msg)
|
||||||
|
: std::runtime_error(getErrorMsg(code, msg)),
|
||||||
|
code(code) {}
|
||||||
|
private:
|
||||||
|
static auto getErrorMsg(int err, const char* msg) -> std::string {
|
||||||
|
std::string error_msg{msg};
|
||||||
|
error_msg += ": ";
|
||||||
|
|
||||||
|
#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 32)
|
||||||
|
// strerrorname_np gets the error code's name; it's nice to have, but it's a recent GNU extension
|
||||||
|
const auto errno_name = strerrorname_np(err);
|
||||||
|
error_msg += errno_name;
|
||||||
|
error_msg += " ";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const auto errno_str = strerror(err);
|
||||||
|
error_msg += errno_str;
|
||||||
|
|
||||||
|
return error_msg;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto openFile(const std::string& path, int flags) -> int {
|
||||||
|
int fd = open(path.c_str(), flags);
|
||||||
|
if (fd < 0) {
|
||||||
|
if (errno == EACCES) {
|
||||||
|
throw errno_error(errno, "Can't open " + path + " (are you in the input group?)");
|
||||||
|
} else {
|
||||||
|
throw errno_error(errno, "Can't open " + path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto closeFile(int fd) -> void {
|
||||||
|
int res = close(fd);
|
||||||
|
if (res < 0) {
|
||||||
|
throw errno_error(errno, "Can't close file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto openDevice(int fd) -> libevdev* {
|
||||||
|
libevdev* dev;
|
||||||
|
int err = libevdev_new_from_fd(fd, &dev);
|
||||||
|
if (err < 0) {
|
||||||
|
throw errno_error(-err, "Can't create libevdev device");
|
||||||
|
}
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto supportsLockStates(const libevdev* dev) -> bool {
|
||||||
|
return libevdev_has_event_type(dev, EV_LED)
|
||||||
|
&& libevdev_has_event_code(dev, EV_LED, LED_NUML)
|
||||||
|
&& libevdev_has_event_code(dev, EV_LED, LED_CAPSL)
|
||||||
|
&& libevdev_has_event_code(dev, EV_LED, LED_SCROLLL);
|
||||||
|
}
|
||||||
|
|
||||||
waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Bar& bar, const Json::Value& config)
|
waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Bar& bar, const Json::Value& config)
|
||||||
: AModule(config, "keyboard-state", id, false, !config["disable-scroll"].asBool()),
|
: AModule(config, "keyboard-state", id, false, !config["disable-scroll"].asBool()),
|
||||||
box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0),
|
box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0),
|
||||||
@ -48,26 +113,36 @@ waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Bar&
|
|||||||
|
|
||||||
if (config_["device-path"].isString()) {
|
if (config_["device-path"].isString()) {
|
||||||
std::string dev_path = config_["device-path"].asString();
|
std::string dev_path = config_["device-path"].asString();
|
||||||
std::tie(fd_, dev_) = openDevice(dev_path);
|
fd_ = openFile(dev_path, O_NONBLOCK | O_CLOEXEC | O_RDONLY);
|
||||||
|
dev_ = openDevice(fd_);
|
||||||
} else {
|
} else {
|
||||||
DIR* dev_dir = opendir("/dev/input");
|
DIR* dev_dir = opendir("/dev/input");
|
||||||
if (dev_dir == nullptr) {
|
if (dev_dir == nullptr) {
|
||||||
throw std::runtime_error("Failed to open /dev/input");
|
throw errno_error(errno, "Failed to open /dev/input");
|
||||||
}
|
}
|
||||||
dirent *ep;
|
dirent *ep;
|
||||||
while ((ep = readdir(dev_dir))) {
|
while ((ep = readdir(dev_dir))) {
|
||||||
if (ep->d_type != DT_CHR) continue;
|
if (ep->d_type != DT_CHR) continue;
|
||||||
std::string dev_path = std::string("/dev/input/") + ep->d_name;
|
std::string dev_path = std::string("/dev/input/") + ep->d_name;
|
||||||
|
int fd = openFile(dev_path.c_str(), O_NONBLOCK | O_CLOEXEC | O_RDONLY);
|
||||||
try {
|
try {
|
||||||
std::tie(fd_, dev_) = openDevice(dev_path);
|
auto dev = openDevice(fd);
|
||||||
spdlog::info("Found device {} at '{}'", libevdev_get_name(dev_), dev_path);
|
if (supportsLockStates(dev)) {
|
||||||
|
spdlog::info("Found device {} at '{}'", libevdev_get_name(dev), dev_path);
|
||||||
|
fd_ = fd;
|
||||||
|
dev_ = dev;
|
||||||
break;
|
break;
|
||||||
} catch (const std::runtime_error& e) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
} catch (const errno_error& e) {
|
||||||
|
// ENOTTY just means the device isn't an evdev device, skip it
|
||||||
|
if (e.code != ENOTTY) {
|
||||||
|
spdlog::warn(e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closeFile(fd);
|
||||||
}
|
}
|
||||||
if (dev_ == nullptr) {
|
if (dev_ == nullptr) {
|
||||||
throw std::runtime_error("Failed to find keyboard device");
|
throw errno_error(errno, "Failed to find keyboard device");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,35 +154,13 @@ waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Bar&
|
|||||||
|
|
||||||
waybar::modules::KeyboardState::~KeyboardState() {
|
waybar::modules::KeyboardState::~KeyboardState() {
|
||||||
libevdev_free(dev_);
|
libevdev_free(dev_);
|
||||||
int err = close(fd_);
|
try {
|
||||||
if (err < 0) {
|
closeFile(fd_);
|
||||||
// Not much we can do, so ignore it.
|
} catch (const std::runtime_error& e) {
|
||||||
|
spdlog::warn(e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto waybar::modules::KeyboardState::openDevice(const std::string& path) -> std::pair<int, libevdev*> {
|
|
||||||
int fd = open(path.c_str(), O_NONBLOCK | O_CLOEXEC | O_RDONLY);
|
|
||||||
if (fd < 0) {
|
|
||||||
throw std::runtime_error("Can't open " + path);
|
|
||||||
}
|
|
||||||
|
|
||||||
libevdev* dev;
|
|
||||||
int err = libevdev_new_from_fd(fd, &dev);
|
|
||||||
if (err < 0) {
|
|
||||||
throw std::runtime_error("Can't create libevdev device");
|
|
||||||
}
|
|
||||||
if (!libevdev_has_event_type(dev, EV_LED)) {
|
|
||||||
throw std::runtime_error("Device doesn't support LED events");
|
|
||||||
}
|
|
||||||
if (!libevdev_has_event_code(dev, EV_LED, LED_NUML)
|
|
||||||
|| !libevdev_has_event_code(dev, EV_LED, LED_CAPSL)
|
|
||||||
|| !libevdev_has_event_code(dev, EV_LED, LED_SCROLLL)) {
|
|
||||||
throw std::runtime_error("Device doesn't support num lock, caps lock, or scroll lock events");
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_pair(fd, dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto waybar::modules::KeyboardState::update() -> void {
|
auto waybar::modules::KeyboardState::update() -> void {
|
||||||
int err = LIBEVDEV_READ_STATUS_SUCCESS;
|
int err = LIBEVDEV_READ_STATUS_SUCCESS;
|
||||||
while (err == LIBEVDEV_READ_STATUS_SUCCESS) {
|
while (err == LIBEVDEV_READ_STATUS_SUCCESS) {
|
||||||
@ -117,8 +170,8 @@ auto waybar::modules::KeyboardState::update() -> void {
|
|||||||
err = libevdev_next_event(dev_, LIBEVDEV_READ_FLAG_SYNC, &ev);
|
err = libevdev_next_event(dev_, LIBEVDEV_READ_FLAG_SYNC, &ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (err != -EAGAIN) {
|
if (-err != EAGAIN) {
|
||||||
throw std::runtime_error("Failed to sync evdev device");
|
throw errno_error(-err, "Failed to sync evdev device");
|
||||||
}
|
}
|
||||||
|
|
||||||
int numl = libevdev_get_event_value(dev_, EV_LED, LED_NUML);
|
int numl = libevdev_get_event_value(dev_, EV_LED, LED_NUML);
|
||||||
|
@ -12,7 +12,15 @@ auto waybar::modules::Memory::update() -> void {
|
|||||||
parseMeminfo();
|
parseMeminfo();
|
||||||
|
|
||||||
unsigned long memtotal = meminfo_["MemTotal"];
|
unsigned long memtotal = meminfo_["MemTotal"];
|
||||||
|
unsigned long swaptotal = 0;
|
||||||
|
if (meminfo_.count("SwapTotal")) {
|
||||||
|
swaptotal = meminfo_["SwapTotal"];
|
||||||
|
}
|
||||||
unsigned long memfree;
|
unsigned long memfree;
|
||||||
|
unsigned long swapfree = 0;
|
||||||
|
if (meminfo_.count("SwapFree")) {
|
||||||
|
swapfree = meminfo_["SwapFree"];
|
||||||
|
}
|
||||||
if (meminfo_.count("MemAvailable")) {
|
if (meminfo_.count("MemAvailable")) {
|
||||||
// New kernels (3.4+) have an accurate available memory field.
|
// New kernels (3.4+) have an accurate available memory field.
|
||||||
memfree = meminfo_["MemAvailable"] + meminfo_["zfs_size"];
|
memfree = meminfo_["MemAvailable"] + meminfo_["zfs_size"];
|
||||||
@ -24,9 +32,16 @@ auto waybar::modules::Memory::update() -> void {
|
|||||||
|
|
||||||
if (memtotal > 0 && memfree >= 0) {
|
if (memtotal > 0 && memfree >= 0) {
|
||||||
auto total_ram_gigabytes = memtotal / std::pow(1024, 2);
|
auto total_ram_gigabytes = memtotal / std::pow(1024, 2);
|
||||||
|
auto total_swap_gigabytes = swaptotal / std::pow(1024, 2);
|
||||||
int used_ram_percentage = 100 * (memtotal - memfree) / memtotal;
|
int used_ram_percentage = 100 * (memtotal - memfree) / memtotal;
|
||||||
|
int used_swap_percentage = 0;
|
||||||
|
if (swaptotal && swapfree) {
|
||||||
|
used_swap_percentage = 100 * (swaptotal - swapfree) / swaptotal;
|
||||||
|
}
|
||||||
auto used_ram_gigabytes = (memtotal - memfree) / std::pow(1024, 2);
|
auto used_ram_gigabytes = (memtotal - memfree) / std::pow(1024, 2);
|
||||||
|
auto used_swap_gigabytes = (swaptotal - swapfree) / std::pow(1024, 2);
|
||||||
auto available_ram_gigabytes = memfree / std::pow(1024, 2);
|
auto available_ram_gigabytes = memfree / std::pow(1024, 2);
|
||||||
|
auto available_swap_gigabytes = swapfree / std::pow(1024, 2);
|
||||||
|
|
||||||
auto format = format_;
|
auto format = format_;
|
||||||
auto state = getState(used_ram_percentage);
|
auto state = getState(used_ram_percentage);
|
||||||
@ -43,9 +58,13 @@ auto waybar::modules::Memory::update() -> void {
|
|||||||
used_ram_percentage,
|
used_ram_percentage,
|
||||||
fmt::arg("icon", getIcon(used_ram_percentage, icons)),
|
fmt::arg("icon", getIcon(used_ram_percentage, icons)),
|
||||||
fmt::arg("total", total_ram_gigabytes),
|
fmt::arg("total", total_ram_gigabytes),
|
||||||
|
fmt::arg("swapTotal", total_swap_gigabytes),
|
||||||
fmt::arg("percentage", used_ram_percentage),
|
fmt::arg("percentage", used_ram_percentage),
|
||||||
|
fmt::arg("swapPercentage", used_swap_percentage),
|
||||||
fmt::arg("used", used_ram_gigabytes),
|
fmt::arg("used", used_ram_gigabytes),
|
||||||
fmt::arg("avail", available_ram_gigabytes)));
|
fmt::arg("swapUsed", used_swap_gigabytes),
|
||||||
|
fmt::arg("avail", available_ram_gigabytes),
|
||||||
|
fmt::arg("swapAvail", available_swap_gigabytes)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tooltipEnabled()) {
|
if (tooltipEnabled()) {
|
||||||
@ -54,9 +73,13 @@ auto waybar::modules::Memory::update() -> void {
|
|||||||
label_.set_tooltip_text(fmt::format(tooltip_format,
|
label_.set_tooltip_text(fmt::format(tooltip_format,
|
||||||
used_ram_percentage,
|
used_ram_percentage,
|
||||||
fmt::arg("total", total_ram_gigabytes),
|
fmt::arg("total", total_ram_gigabytes),
|
||||||
|
fmt::arg("swapTotal", total_swap_gigabytes),
|
||||||
fmt::arg("percentage", used_ram_percentage),
|
fmt::arg("percentage", used_ram_percentage),
|
||||||
|
fmt::arg("swapPercentage", used_swap_percentage),
|
||||||
fmt::arg("used", used_ram_gigabytes),
|
fmt::arg("used", used_ram_gigabytes),
|
||||||
fmt::arg("avail", available_ram_gigabytes)));
|
fmt::arg("swapUsed", used_swap_gigabytes),
|
||||||
|
fmt::arg("avail", available_ram_gigabytes),
|
||||||
|
fmt::arg("swapAvail", available_swap_gigabytes)));
|
||||||
} else {
|
} else {
|
||||||
label_.set_tooltip_text(fmt::format("{:.{}f}GiB used", used_ram_gigabytes, 1));
|
label_.set_tooltip_text(fmt::format("{:.{}f}GiB used", used_ram_gigabytes, 1));
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,7 @@ void waybar::modules::MPD::setLabel() {
|
|||||||
album = getTag(MPD_TAG_ALBUM);
|
album = getTag(MPD_TAG_ALBUM);
|
||||||
title = getTag(MPD_TAG_TITLE);
|
title = getTag(MPD_TAG_TITLE);
|
||||||
date = getTag(MPD_TAG_DATE);
|
date = getTag(MPD_TAG_DATE);
|
||||||
song_pos = mpd_status_get_song_pos(status_.get());
|
song_pos = mpd_status_get_song_pos(status_.get()) + 1;
|
||||||
volume = mpd_status_get_volume(status_.get());
|
volume = mpd_status_get_volume(status_.get());
|
||||||
if (volume < 0) {
|
if (volume < 0) {
|
||||||
volume = 0;
|
volume = 0;
|
||||||
|
@ -106,7 +106,7 @@ waybar::modules::Network::Network(const std::string &id, const Json::Value &conf
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!config_["interface"].isString()) {
|
if (!config_["interface"].isString()) {
|
||||||
// "interface" isn't configure, then try to guess the external
|
// "interface" isn't configured, then try to guess the external
|
||||||
// interface currently used for internet.
|
// interface currently used for internet.
|
||||||
want_route_dump_ = true;
|
want_route_dump_ = true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -54,7 +54,9 @@ void waybar::modules::Pulseaudio::contextStateCb(pa_context *c, void *data) {
|
|||||||
c,
|
c,
|
||||||
static_cast<enum pa_subscription_mask>(static_cast<int>(PA_SUBSCRIPTION_MASK_SERVER) |
|
static_cast<enum pa_subscription_mask>(static_cast<int>(PA_SUBSCRIPTION_MASK_SERVER) |
|
||||||
static_cast<int>(PA_SUBSCRIPTION_MASK_SINK) |
|
static_cast<int>(PA_SUBSCRIPTION_MASK_SINK) |
|
||||||
static_cast<int>(PA_SUBSCRIPTION_MASK_SOURCE)),
|
static_cast<int>(PA_SUBSCRIPTION_MASK_SINK_INPUT) |
|
||||||
|
static_cast<int>(PA_SUBSCRIPTION_MASK_SOURCE) |
|
||||||
|
static_cast<int>(PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT)),
|
||||||
nullptr,
|
nullptr,
|
||||||
nullptr);
|
nullptr);
|
||||||
break;
|
break;
|
||||||
@ -121,8 +123,12 @@ void waybar::modules::Pulseaudio::subscribeCb(pa_context * conte
|
|||||||
pa_context_get_server_info(context, serverInfoCb, data);
|
pa_context_get_server_info(context, serverInfoCb, data);
|
||||||
} else if (facility == PA_SUBSCRIPTION_EVENT_SINK) {
|
} else if (facility == PA_SUBSCRIPTION_EVENT_SINK) {
|
||||||
pa_context_get_sink_info_by_index(context, idx, sinkInfoCb, data);
|
pa_context_get_sink_info_by_index(context, idx, sinkInfoCb, data);
|
||||||
|
} else if (facility == PA_SUBSCRIPTION_EVENT_SINK_INPUT) {
|
||||||
|
pa_context_get_sink_info_list(context, sinkInfoCb, data);
|
||||||
} else if (facility == PA_SUBSCRIPTION_EVENT_SOURCE) {
|
} else if (facility == PA_SUBSCRIPTION_EVENT_SOURCE) {
|
||||||
pa_context_get_source_info_by_index(context, idx, sourceInfoCb, data);
|
pa_context_get_source_info_by_index(context, idx, sourceInfoCb, data);
|
||||||
|
} else if (facility == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT) {
|
||||||
|
pa_context_get_source_info_list(context, sourceInfoCb, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,13 +8,7 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
template <>
|
#include "util/format.hpp"
|
||||||
struct fmt::formatter<Glib::ustring> : formatter<std::string> {
|
|
||||||
template <typename FormatContext>
|
|
||||||
auto format(const Glib::ustring& value, FormatContext& ctx) {
|
|
||||||
return formatter<std::string>::format(value, ctx);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct fmt::formatter<Glib::VariantBase> : formatter<std::string> {
|
struct fmt::formatter<Glib::VariantBase> : formatter<std::string> {
|
||||||
|
@ -25,7 +25,11 @@ Tray::Tray(const std::string& id, const Bar& bar, const Json::Value& config)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Tray::onAdd(std::unique_ptr<Item>& item) {
|
void Tray::onAdd(std::unique_ptr<Item>& item) {
|
||||||
|
if (config_["reverse-direction"].isBool() && config_["reverse-direction"].asBool()) {
|
||||||
|
box_.pack_end(item->event_box);
|
||||||
|
} else {
|
||||||
box_.pack_start(item->event_box);
|
box_.pack_start(item->event_box);
|
||||||
|
}
|
||||||
dp.emit();
|
dp.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,7 +154,10 @@ auto Language::init_layouts_map(const std::vector<std::string>& used_layouts) ->
|
|||||||
|
|
||||||
std::map<std::string, int> short_name_to_number_map;
|
std::map<std::string, int> short_name_to_number_map;
|
||||||
for (const auto& used_layout_name : used_layouts) {
|
for (const auto& used_layout_name : used_layouts) {
|
||||||
auto used_layout = &layouts_map_.find(used_layout_name)->second;
|
auto found = layouts_map_.find(used_layout_name);
|
||||||
|
if (found == layouts_map_.end())
|
||||||
|
continue;
|
||||||
|
auto used_layout = &found->second;
|
||||||
auto layouts_with_same_name_list = found_by_short_names[used_layout->short_name];
|
auto layouts_with_same_name_list = found_by_short_names[used_layout->short_name];
|
||||||
if (layouts_with_same_name_list.size() < 2) {
|
if (layouts_with_same_name_list.size() < 2) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -1,11 +1,20 @@
|
|||||||
#include "modules/sway/window.hpp"
|
#include "modules/sway/window.hpp"
|
||||||
|
|
||||||
|
#include <gdkmm/pixbuf.h>
|
||||||
|
#include <glibmm/fileutils.h>
|
||||||
|
#include <glibmm/keyfile.h>
|
||||||
|
#include <glibmm/miscutils.h>
|
||||||
|
#include <gtkmm/enums.h>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace waybar::modules::sway {
|
namespace waybar::modules::sway {
|
||||||
|
|
||||||
Window::Window(const std::string& id, const Bar& bar, const Json::Value& config)
|
Window::Window(const std::string& id, const Bar& bar, const Json::Value& config)
|
||||||
: ALabel(config, "window", id, "{}", 0, true), bar_(bar), windowId_(-1) {
|
: AIconLabel(config, "window", id, "{}", 0, true), bar_(bar), windowId_(-1) {
|
||||||
ipc_.subscribe(R"(["window","workspace"])");
|
ipc_.subscribe(R"(["window","workspace"])");
|
||||||
ipc_.signal_event.connect(sigc::mem_fun(*this, &Window::onEvent));
|
ipc_.signal_event.connect(sigc::mem_fun(*this, &Window::onEvent));
|
||||||
ipc_.signal_cmd.connect(sigc::mem_fun(*this, &Window::onCmd));
|
ipc_.signal_cmd.connect(sigc::mem_fun(*this, &Window::onCmd));
|
||||||
@ -29,12 +38,60 @@ void Window::onCmd(const struct Ipc::ipc_response& res) {
|
|||||||
auto payload = parser_.parse(res.payload);
|
auto payload = parser_.parse(res.payload);
|
||||||
auto output = payload["output"].isString() ? payload["output"].asString() : "";
|
auto output = payload["output"].isString() ? payload["output"].asString() : "";
|
||||||
std::tie(app_nb_, windowId_, window_, app_id_) = getFocusedNode(payload["nodes"], output);
|
std::tie(app_nb_, windowId_, window_, app_id_) = getFocusedNode(payload["nodes"], output);
|
||||||
|
updateAppIcon();
|
||||||
dp.emit();
|
dp.emit();
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
spdlog::error("Window: {}", e.what());
|
spdlog::error("Window: {}", e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> getDesktopFilePath(const std::string& app_id) {
|
||||||
|
const auto data_dirs = Glib::get_system_data_dirs();
|
||||||
|
for (const auto& data_dir : data_dirs) {
|
||||||
|
const auto desktop_file_path = data_dir + "applications/" + app_id + ".desktop";
|
||||||
|
if (std::filesystem::exists(desktop_file_path)) {
|
||||||
|
return desktop_file_path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Glib::ustring> getIconName(const std::string& app_id) {
|
||||||
|
const auto desktop_file_path = getDesktopFilePath(app_id);
|
||||||
|
if (!desktop_file_path.has_value()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Glib::KeyFile desktop_file;
|
||||||
|
desktop_file.load_from_file(desktop_file_path.value());
|
||||||
|
const auto icon_name = desktop_file.get_string("Desktop Entry", "Icon");
|
||||||
|
if (icon_name.empty()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return icon_name;
|
||||||
|
} catch (Glib::FileError& error) {
|
||||||
|
spdlog::warn(
|
||||||
|
"Error while loading desktop file {}: {}", desktop_file_path.value(), error.what().c_str());
|
||||||
|
} catch (Glib::KeyFileError& error) {
|
||||||
|
spdlog::warn(
|
||||||
|
"Error while loading desktop file {}: {}", desktop_file_path.value(), error.what().c_str());
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::updateAppIcon() {
|
||||||
|
if (!iconEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto icon_name = getIconName(app_id_);
|
||||||
|
if (icon_name.has_value()) {
|
||||||
|
image_.set_from_icon_name(icon_name.value(), Gtk::ICON_SIZE_LARGE_TOOLBAR);
|
||||||
|
image_.set_visible(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
image_.set_visible(false);
|
||||||
|
}
|
||||||
|
|
||||||
auto Window::update() -> void {
|
auto Window::update() -> void {
|
||||||
if (!old_app_id_.empty()) {
|
if (!old_app_id_.empty()) {
|
||||||
bar_.window.get_style_context()->remove_class(old_app_id_);
|
bar_.window.get_style_context()->remove_class(old_app_id_);
|
||||||
@ -63,7 +120,7 @@ auto Window::update() -> void {
|
|||||||
label_.set_tooltip_text(window_);
|
label_.set_tooltip_text(window_);
|
||||||
}
|
}
|
||||||
// Call parent update
|
// Call parent update
|
||||||
ALabel::update();
|
AIconLabel::update();
|
||||||
}
|
}
|
||||||
|
|
||||||
int leafNodesInWorkspace(const Json::Value& node) {
|
int leafNodesInWorkspace(const Json::Value& node) {
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "glibmm/fileutils.h"
|
#include "glibmm/fileutils.h"
|
||||||
#include "glibmm/refptr.h"
|
#include "glibmm/refptr.h"
|
||||||
#include "util/format.hpp"
|
#include "util/format.hpp"
|
||||||
|
#include "util/string.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
@ -26,27 +27,6 @@
|
|||||||
|
|
||||||
namespace waybar::modules::wlr {
|
namespace waybar::modules::wlr {
|
||||||
|
|
||||||
/* String manipulation methods */
|
|
||||||
const std::string WHITESPACE = " \n\r\t\f\v";
|
|
||||||
|
|
||||||
static std::string ltrim(const std::string& s)
|
|
||||||
{
|
|
||||||
size_t start = s.find_first_not_of(WHITESPACE);
|
|
||||||
return (start == std::string::npos) ? "" : s.substr(start);
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string rtrim(const std::string& s)
|
|
||||||
{
|
|
||||||
size_t end = s.find_last_not_of(WHITESPACE);
|
|
||||||
return (end == std::string::npos) ? "" : s.substr(0, end + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string trim(const std::string& s)
|
|
||||||
{
|
|
||||||
return rtrim(ltrim(s));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Icon loading functions */
|
/* Icon loading functions */
|
||||||
static std::vector<std::string> search_prefix()
|
static std::vector<std::string> search_prefix()
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user