mirror of
https://github.com/rad4day/Waybar.git
synced 2023-12-21 10:22:59 +01:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
c3bd6da1d0 | |||
e3e099f836 | |||
767d9dd5b4 | |||
d1d51b76aa | |||
cee031d2fa | |||
18c7ad0026 | |||
1555cb71e1 | |||
ea9a08d473 | |||
68f9ea3065 | |||
a423f7032d | |||
01894f18cd |
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtkmm.h>
|
||||
|
||||
namespace waybar {
|
||||
class IModule {
|
||||
public:
|
||||
|
@ -3,16 +3,11 @@
|
||||
#include <unistd.h>
|
||||
#include <wordexp.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gtkmm.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
|
||||
|
||||
#include <gdk/gdkwayland.h>
|
||||
|
||||
#include "bar.hpp"
|
||||
@ -26,11 +21,12 @@ namespace waybar {
|
||||
Gtk::Main gtk_main;
|
||||
|
||||
Glib::RefPtr<Gdk::Display> gdk_display;
|
||||
struct wl_display *wlDisplay;
|
||||
struct wl_registry *registry;
|
||||
struct zwlr_layer_shell_v1 *layer_shell;
|
||||
struct zxdg_output_manager_v1 *xdg_output_manager;
|
||||
struct wl_seat *seat;
|
||||
struct wl_display *wlDisplay = nullptr;
|
||||
struct wl_registry *registry = nullptr;
|
||||
struct zwlr_layer_shell_v1 *layer_shell = nullptr;
|
||||
struct zxdg_output_manager_v1 *xdg_output_manager = nullptr;
|
||||
struct wl_seat *seat = nullptr;
|
||||
struct wl_output *wlOutput = nullptr;
|
||||
std::vector<std::unique_ptr<Bar>> bars;
|
||||
|
||||
Client(int argc, char* argv[]);
|
||||
|
@ -15,7 +15,7 @@ namespace waybar {
|
||||
class Factory {
|
||||
public:
|
||||
Factory(Bar &bar, Json::Value config);
|
||||
IModule &makeModule(std::string name);
|
||||
IModule *makeModule(std::string name);
|
||||
private:
|
||||
Bar &_bar;
|
||||
Json::Value _config;
|
||||
|
@ -3,9 +3,10 @@
|
||||
#include <json/json.h>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <gtkmm.h>
|
||||
#include <iostream>
|
||||
#include <fmt/format.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <algorithm>
|
||||
#include "util/chrono.hpp"
|
||||
#include "IModule.hpp"
|
||||
|
||||
@ -19,7 +20,7 @@ namespace waybar::modules {
|
||||
auto update() -> void;
|
||||
operator Gtk::Widget&();
|
||||
private:
|
||||
std::string _getIcon(uint32_t percentage);
|
||||
std::string _getIcon(uint16_t percentage);
|
||||
static inline const fs::path _data_dir = "/sys/class/power_supply/";
|
||||
std::vector<fs::path> _batteries;
|
||||
util::SleeperThread _thread;
|
||||
|
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <json/json.h>
|
||||
#include <gtkmm.h>
|
||||
#include <fmt/format.h>
|
||||
#include "util/chrono.hpp"
|
||||
#include "IModule.hpp"
|
||||
|
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <json/json.h>
|
||||
#include <gtkmm.h>
|
||||
#include <fmt/format.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include "util/chrono.hpp"
|
||||
|
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <json/json.h>
|
||||
#include <gtkmm.h>
|
||||
#include <fmt/format.h>
|
||||
#include "util/chrono.hpp"
|
||||
#include "IModule.hpp"
|
||||
|
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <json/json.h>
|
||||
#include <gtkmm.h>
|
||||
#include <fmt/format.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include "util/chrono.hpp"
|
||||
|
@ -5,9 +5,7 @@
|
||||
#include <netlink/genl/genl.h>
|
||||
#include <netlink/genl/ctrl.h>
|
||||
#include <linux/nl80211.h>
|
||||
#include <iwlib.h> // TODO
|
||||
#include <json/json.h>
|
||||
#include <gtkmm.h>
|
||||
#include <fmt/format.h>
|
||||
#include "util/chrono.hpp"
|
||||
#include "IModule.hpp"
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
#include <pulse/pulseaudio.h>
|
||||
#include <json/json.h>
|
||||
#include <gtkmm.h>
|
||||
#include <fmt/format.h>
|
||||
#include <algorithm>
|
||||
#include "IModule.hpp"
|
||||
|
||||
namespace waybar::modules {
|
||||
@ -14,6 +14,7 @@ namespace waybar::modules {
|
||||
auto update() -> void;
|
||||
operator Gtk::Widget &();
|
||||
private:
|
||||
std::string _getIcon(uint16_t percentage);
|
||||
static void _subscribeCb(pa_context *context,
|
||||
pa_subscription_event_type_t type, uint32_t idx, void *data);
|
||||
static void _contextStateCb(pa_context *c, void *data);
|
||||
|
@ -4,24 +4,34 @@
|
||||
#include "bar.hpp"
|
||||
#include "client.hpp"
|
||||
#include "util/chrono.hpp"
|
||||
#include "util/json.hpp"
|
||||
#include "IModule.hpp"
|
||||
|
||||
namespace waybar::modules {
|
||||
|
||||
class Workspaces : public IModule {
|
||||
public:
|
||||
Workspaces(waybar::Bar &bar);
|
||||
Workspaces(waybar::Bar &bar, Json::Value config);
|
||||
auto update() -> void;
|
||||
operator Gtk::Widget &();
|
||||
private:
|
||||
void _addWorkspace(Json::Value node);
|
||||
Json::Value _getWorkspaces();
|
||||
std::string _getIcon(std::string name);
|
||||
Json::Value _getWorkspaces(const std::string data);
|
||||
bool _handleScroll(GdkEventScroll *e);
|
||||
int _getPrevWorkspace();
|
||||
int _getNextWorkspace();
|
||||
Bar &_bar;
|
||||
Json::Value _config;
|
||||
waybar::util::SleeperThread _thread;
|
||||
Gtk::Box _box;
|
||||
util::JsonParser _parser;
|
||||
std::mutex _mutex;
|
||||
bool _scrolling;
|
||||
std::unordered_map<int, Gtk::Button> _buttons;
|
||||
int _ipcSocketfd;
|
||||
int _ipcEventSocketfd;
|
||||
Json::Value _workspaces;
|
||||
int _ipcfd;
|
||||
int _ipcEventfd;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -39,7 +39,9 @@ namespace waybar::util {
|
||||
func();
|
||||
} while (do_run);
|
||||
}}
|
||||
{}
|
||||
{
|
||||
defined = true;
|
||||
}
|
||||
|
||||
SleeperThread& operator=(std::function<void()> func)
|
||||
{
|
||||
@ -48,6 +50,7 @@ namespace waybar::util {
|
||||
func();
|
||||
} while (do_run);
|
||||
});
|
||||
defined = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -72,14 +75,17 @@ namespace waybar::util {
|
||||
~SleeperThread()
|
||||
{
|
||||
do_run = false;
|
||||
if (defined) {
|
||||
condvar.notify_all();
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::thread thread;
|
||||
std::condition_variable condvar;
|
||||
std::mutex mutex;
|
||||
bool defined = false;
|
||||
bool do_run = true;
|
||||
};
|
||||
|
||||
|
34
include/util/json.hpp
Normal file
34
include/util/json.hpp
Normal file
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <json/json.h>
|
||||
|
||||
namespace waybar::util {
|
||||
|
||||
struct JsonParser {
|
||||
|
||||
JsonParser()
|
||||
: _reader(_builder.newCharReader())
|
||||
{}
|
||||
|
||||
Json::Value parse(const std::string data)
|
||||
{
|
||||
Json::Value root;
|
||||
std::string err;
|
||||
bool res =
|
||||
_reader->parse(data.c_str(), data.c_str() + data.size(), &root, &err);
|
||||
if (!res)
|
||||
throw std::runtime_error(err);
|
||||
return root;
|
||||
}
|
||||
|
||||
~JsonParser()
|
||||
{
|
||||
delete _reader;
|
||||
}
|
||||
|
||||
private:
|
||||
Json::CharReaderBuilder _builder;
|
||||
Json::CharReader *_reader;
|
||||
};
|
||||
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
project(
|
||||
'waybar', 'cpp', 'c',
|
||||
version: '0.0.2',
|
||||
version: '0.0.3',
|
||||
license: 'MIT',
|
||||
default_options : ['cpp_std=c++17'],
|
||||
)
|
||||
|
@ -7,6 +7,15 @@
|
||||
"modules-left": ["workspaces", "custom/spotify"],
|
||||
"modules-right": ["pulseaudio", "network", "cpu", "memory", "battery", "clock"],
|
||||
// Modules configuration
|
||||
"workspaces": {
|
||||
"format-icons": {
|
||||
"1": "",
|
||||
"2": "",
|
||||
"3": "",
|
||||
"4": "",
|
||||
"5": ""
|
||||
}
|
||||
},
|
||||
"cpu": {
|
||||
"format": "{}% "
|
||||
},
|
||||
@ -14,7 +23,7 @@
|
||||
"format": "{}% "
|
||||
},
|
||||
"battery": {
|
||||
"format": "{value}% {icon}",
|
||||
"format": "{capacity}% {icon}",
|
||||
"format-icons": ["", "", "", "", ""]
|
||||
},
|
||||
"network": {
|
||||
@ -22,8 +31,9 @@
|
||||
"format": "{essid} ({signalStrength}%) "
|
||||
},
|
||||
"pulseaudio": {
|
||||
"format": "{}% ",
|
||||
"format-muted": ""
|
||||
"format": "{volume}% {icon}",
|
||||
"format-muted": "",
|
||||
"format-icons": ["", ""]
|
||||
},
|
||||
"custom/spotify": {
|
||||
"format": " {}",
|
||||
|
@ -11,33 +11,37 @@ window {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.workspaces button {
|
||||
padding: 0 5px;
|
||||
#workspaces button {
|
||||
padding: 0 8px;
|
||||
background: transparent;
|
||||
color: white;
|
||||
border-bottom: 3px solid transparent;
|
||||
}
|
||||
|
||||
.workspaces button.current {
|
||||
#workspaces button label {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
#workspaces button.current {
|
||||
background: #64727D;
|
||||
border-bottom: 3px solid white;
|
||||
}
|
||||
|
||||
.clock, .battery, .cpu, .memory, .network, .pulseaudio, .custom-spotify {
|
||||
#clock, #battery, #cpu, #memory, #network, #pulseaudio, #custom-spotify {
|
||||
padding: 0 10px;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.clock {
|
||||
#clock {
|
||||
background-color: #64727D;
|
||||
}
|
||||
|
||||
.battery {
|
||||
#battery {
|
||||
background-color: #ffffff;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.battery.charging {
|
||||
#battery.charging {
|
||||
color: white;
|
||||
background-color: #26A65B;
|
||||
}
|
||||
@ -49,7 +53,7 @@ window {
|
||||
}
|
||||
}
|
||||
|
||||
.battery.warning {
|
||||
#battery.warning {
|
||||
background: #f53c3c;
|
||||
color: white;
|
||||
animation-name: blink;
|
||||
@ -59,30 +63,30 @@ window {
|
||||
animation-direction: alternate;
|
||||
}
|
||||
|
||||
.cpu {
|
||||
#cpu {
|
||||
background: #2ecc71;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.memory {
|
||||
#memory {
|
||||
background: #9b59b6;
|
||||
}
|
||||
|
||||
.network {
|
||||
#network {
|
||||
background: #2980b9;
|
||||
}
|
||||
|
||||
.pulseaudio {
|
||||
#pulseaudio {
|
||||
background: #f1c40f;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.pulseaudio.muted {
|
||||
#pulseaudio.muted {
|
||||
background: #90b1b1;
|
||||
color: #2a5c45;
|
||||
}
|
||||
|
||||
.custom-spotify {
|
||||
#custom-spotify {
|
||||
background: #66cc99;
|
||||
color: #2a5c45;
|
||||
}
|
||||
|
30
src/bar.cpp
30
src/bar.cpp
@ -1,10 +1,7 @@
|
||||
#include <condition_variable>
|
||||
#include <gdk/gdkwayland.h>
|
||||
#include <thread>
|
||||
#include <fstream>
|
||||
#include "bar.hpp"
|
||||
#include "client.hpp"
|
||||
#include "factory.hpp"
|
||||
#include "util/json.hpp"
|
||||
|
||||
waybar::Bar::Bar(Client &client, std::unique_ptr<struct wl_output *> &&p_output)
|
||||
: client(client), window{Gtk::WindowType::WINDOW_TOPLEVEL},
|
||||
@ -129,19 +126,13 @@ auto waybar::Bar::toggle() -> void
|
||||
|
||||
auto waybar::Bar::_setupConfig() -> void
|
||||
{
|
||||
Json::Value root;
|
||||
Json::CharReaderBuilder builder;
|
||||
Json::CharReader* reader = builder.newCharReader();
|
||||
std::string err;
|
||||
util::JsonParser parser;
|
||||
std::ifstream file(client.configFile);
|
||||
if (!file.is_open())
|
||||
throw std::runtime_error("Can't open config file");
|
||||
std::string str((std::istreambuf_iterator<char>(file)),
|
||||
std::istreambuf_iterator<char>());
|
||||
bool res = reader->parse(str.c_str(), str.c_str() + str.size(), &_config, &err);
|
||||
delete reader;
|
||||
if (!res)
|
||||
throw std::runtime_error(err);
|
||||
_config = parser.parse(str);
|
||||
}
|
||||
|
||||
auto waybar::Bar::_setupCss() -> void
|
||||
@ -174,21 +165,24 @@ auto waybar::Bar::_setupWidgets() -> void
|
||||
|
||||
if (_config["modules-left"]) {
|
||||
for (auto name : _config["modules-left"]) {
|
||||
auto &module = factory.makeModule(name.asString());
|
||||
left.pack_start(module, false, true, 0);
|
||||
auto module = factory.makeModule(name.asString());
|
||||
if (module)
|
||||
left.pack_start(*module, false, true, 0);
|
||||
}
|
||||
}
|
||||
if (_config["modules-center"]) {
|
||||
for (auto name : _config["modules-center"]) {
|
||||
auto &module = factory.makeModule(name.asString());
|
||||
center.pack_start(module, true, false, 10);
|
||||
auto module = factory.makeModule(name.asString());
|
||||
if (module)
|
||||
center.pack_start(*module, true, false, 10);
|
||||
}
|
||||
}
|
||||
if (_config["modules-right"]) {
|
||||
std::reverse(_config["modules-right"].begin(), _config["modules-right"].end());
|
||||
for (auto name : _config["modules-right"]) {
|
||||
auto &module = factory.makeModule(name.asString());
|
||||
right.pack_end(module, false, false, 0);
|
||||
auto module = factory.makeModule(name.asString());
|
||||
if (module)
|
||||
right.pack_end(*module, false, false, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,9 +46,11 @@ void waybar::Client::_handle_global(void *data, struct wl_registry *registry,
|
||||
o->layer_shell = (zwlr_layer_shell_v1 *)wl_registry_bind(registry, name,
|
||||
&zwlr_layer_shell_v1_interface, version);
|
||||
} else if (!strcmp(interface, wl_output_interface.name)) {
|
||||
auto output = std::make_unique<struct wl_output *>();
|
||||
*output = (struct wl_output *)wl_registry_bind(registry, name,
|
||||
o->wlOutput = (struct wl_output *)wl_registry_bind(registry, name,
|
||||
&wl_output_interface, version);
|
||||
auto output = std::make_unique<struct wl_output *>();
|
||||
*output = o->wlOutput;
|
||||
if (o->xdg_output_manager)
|
||||
o->bars.emplace_back(std::make_unique<Bar>(*o, std::move(output)));
|
||||
} else if (!strcmp(interface, wl_seat_interface.name)) {
|
||||
o->seat = (struct wl_seat *)wl_registry_bind(registry, name,
|
||||
@ -58,6 +60,11 @@ void waybar::Client::_handle_global(void *data, struct wl_registry *registry,
|
||||
o->xdg_output_manager =
|
||||
(struct zxdg_output_manager_v1 *)wl_registry_bind(registry, name,
|
||||
&zxdg_output_manager_v1_interface, ZXDG_OUTPUT_V1_NAME_SINCE_VERSION);
|
||||
if (o->wlOutput) {
|
||||
auto output = std::make_unique<struct wl_output *>();
|
||||
*output = o->wlOutput;
|
||||
o->bars.emplace_back(std::make_unique<Bar>(*o, std::move(output)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,23 +4,32 @@ waybar::Factory::Factory(Bar &bar, Json::Value config)
|
||||
: _bar(bar), _config(config)
|
||||
{}
|
||||
|
||||
waybar::IModule &waybar::Factory::makeModule(std::string name)
|
||||
waybar::IModule *waybar::Factory::makeModule(std::string name)
|
||||
{
|
||||
try {
|
||||
if (name == "battery")
|
||||
return *new waybar::modules::Battery(_config[name]);
|
||||
return new waybar::modules::Battery(_config[name]);
|
||||
if (name == "workspaces")
|
||||
return *new waybar::modules::Workspaces(_bar);
|
||||
return new waybar::modules::Workspaces(_bar, _config[name]);
|
||||
if (name == "memory")
|
||||
return *new waybar::modules::Memory(_config[name]);
|
||||
return new waybar::modules::Memory(_config[name]);
|
||||
if (name == "cpu")
|
||||
return *new waybar::modules::Cpu(_config[name]);
|
||||
return new waybar::modules::Cpu(_config[name]);
|
||||
if (name == "clock")
|
||||
return *new waybar::modules::Clock(_config[name]);
|
||||
return new waybar::modules::Clock(_config[name]);
|
||||
if (name == "network")
|
||||
return *new waybar::modules::Network(_config[name]);
|
||||
return new waybar::modules::Network(_config[name]);
|
||||
if (name == "pulseaudio")
|
||||
return *new waybar::modules::Pulseaudio(_config[name]);
|
||||
return new waybar::modules::Pulseaudio(_config[name]);
|
||||
if (!name.compare(0, 7, "custom/") && name.size() > 7)
|
||||
return *new waybar::modules::Custom(name.substr(7), _config[name]);
|
||||
throw std::runtime_error("Unknown module: " + name);
|
||||
return new waybar::modules::Custom(name.substr(7), _config[name]);
|
||||
std::cerr << "Unknown module: " + name << std::endl;
|
||||
} catch (const std::exception& e) {
|
||||
auto err = fmt::format("Disabling module \"{}\", {}", name, e.what());
|
||||
std::cerr << err << std::endl;
|
||||
} catch (...) {
|
||||
auto err = fmt::format("Disabling module \"{}\", Unknown reason", name);
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -48,10 +48,11 @@ int ipc_open_socket(std::string socket_path) {
|
||||
}
|
||||
|
||||
struct ipc_response ipc_recv_response(int socketfd) {
|
||||
struct ipc_response response;
|
||||
char data[ipc_header_size];
|
||||
uint32_t *data32 = (uint32_t *)(data + sizeof(ipc_magic));
|
||||
|
||||
size_t total = 0;
|
||||
|
||||
while (total < ipc_header_size) {
|
||||
ssize_t received = recv(socketfd, data + total, ipc_header_size - total, 0);
|
||||
if (received <= 0) {
|
||||
@ -60,8 +61,6 @@ struct ipc_response ipc_recv_response(int socketfd) {
|
||||
total += received;
|
||||
}
|
||||
|
||||
struct ipc_response response;
|
||||
|
||||
total = 0;
|
||||
response.size = data32[0];
|
||||
response.type = data32[1];
|
||||
@ -86,14 +85,10 @@ std::string ipc_single_command(int socketfd, uint32_t type, const char *payload,
|
||||
data32[0] = *len;
|
||||
data32[1] = type;
|
||||
|
||||
if (send(socketfd, data, ipc_header_size, 0) == -1) {
|
||||
if (send(socketfd, data, ipc_header_size, 0) == -1)
|
||||
throw std::runtime_error("Unable to send IPC header");
|
||||
}
|
||||
|
||||
if (send(socketfd, payload, *len, 0) == -1) {
|
||||
if (send(socketfd, payload, *len, 0) == -1)
|
||||
throw std::runtime_error("Unable to send IPC payload");
|
||||
}
|
||||
|
||||
struct ipc_response resp = ipc_recv_response(socketfd);
|
||||
*len = resp.size;
|
||||
return resp.payload;
|
||||
|
@ -1,7 +1,5 @@
|
||||
#include <gtkmm.h>
|
||||
#include <wayland-client.hpp>
|
||||
#include <gdk/gdkwayland.h>
|
||||
#include <csignal>
|
||||
#include <iostream>
|
||||
#include "client.hpp"
|
||||
|
||||
namespace waybar {
|
||||
|
@ -6,65 +6,73 @@ waybar::modules::Battery::Battery(Json::Value config)
|
||||
try {
|
||||
for (auto &node : fs::directory_iterator(_data_dir)) {
|
||||
if (fs::is_directory(node) && fs::exists(node / "capacity")
|
||||
&& fs::exists(node / "status")) {
|
||||
&& fs::exists(node / "status") && fs::exists(node / "uevent"))
|
||||
_batteries.push_back(node);
|
||||
}
|
||||
}
|
||||
} catch (fs::filesystem_error &e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
throw std::runtime_error(e.what());
|
||||
}
|
||||
|
||||
if (!_batteries.size()) {
|
||||
std::cerr << "No batteries." << std::endl;
|
||||
if (!_batteries.size())
|
||||
throw std::runtime_error("No batteries.");
|
||||
|
||||
auto fd = inotify_init();
|
||||
if (fd == -1)
|
||||
throw std::runtime_error("Unable to listen batteries.");
|
||||
for (auto &bat : _batteries)
|
||||
inotify_add_watch(fd, (bat / "uevent").c_str(), IN_ACCESS);
|
||||
// Trigger first value
|
||||
update();
|
||||
_label.set_name("battery");
|
||||
_thread = [this, fd] {
|
||||
struct inotify_event event;
|
||||
int nbytes = read(fd, &event, sizeof(event));
|
||||
if (nbytes != sizeof(event))
|
||||
return;
|
||||
}
|
||||
|
||||
_label.get_style_context()->add_class("battery");
|
||||
int interval = _config["interval"] ? _config["inveral"].asInt() : 1;
|
||||
_thread = [this, interval] {
|
||||
Glib::signal_idle().connect_once(sigc::mem_fun(*this, &Battery::update));
|
||||
_thread.sleep_for(chrono::seconds(interval));
|
||||
};
|
||||
}
|
||||
|
||||
auto waybar::modules::Battery::update() -> void
|
||||
{
|
||||
try {
|
||||
int total = 0;
|
||||
uint16_t total = 0;
|
||||
bool charging = false;
|
||||
for (auto &bat : _batteries) {
|
||||
int capacity;
|
||||
std::string status;
|
||||
for (auto &bat : _batteries) {
|
||||
uint16_t capacity;
|
||||
std::ifstream(bat / "capacity") >> capacity;
|
||||
total += capacity;
|
||||
std::ifstream(bat / "status") >> status;
|
||||
if (status == "Charging") {
|
||||
if (status == "Charging")
|
||||
charging = true;
|
||||
total += capacity;
|
||||
}
|
||||
}
|
||||
auto format = _config["format"] ? _config["format"].asString() : "{}%";
|
||||
auto value = total / _batteries.size();
|
||||
_label.set_text(fmt::format(format, fmt::arg("value", value),
|
||||
fmt::arg("icon", _getIcon(value))));
|
||||
_label.set_tooltip_text(charging ? "Charging" : "Discharging");
|
||||
uint16_t capacity = total / _batteries.size();
|
||||
auto format = _config["format"]
|
||||
? _config["format"].asString() : "{capacity}%";
|
||||
_label.set_text(fmt::format(format, fmt::arg("capacity", capacity),
|
||||
fmt::arg("icon", _getIcon(capacity))));
|
||||
_label.set_tooltip_text(status);
|
||||
if (charging)
|
||||
_label.get_style_context()->add_class("charging");
|
||||
else
|
||||
_label.get_style_context()->remove_class("charging");
|
||||
if (value < 16 && !charging)
|
||||
auto critical = _config["critical"] ? _config["critical"].asUInt() : 15;
|
||||
if (capacity <= critical && !charging)
|
||||
_label.get_style_context()->add_class("warning");
|
||||
else
|
||||
_label.get_style_context()->remove_class("warning");
|
||||
} catch (std::exception &e) {
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::string waybar::modules::Battery::_getIcon(uint32_t percentage)
|
||||
std::string waybar::modules::Battery::_getIcon(uint16_t percentage)
|
||||
{
|
||||
if (!_config["format-icons"] || !_config["format-icons"].isArray()) return "";
|
||||
auto step = 100 / _config["format-icons"].size();
|
||||
return _config["format-icons"][percentage / step].asString();
|
||||
auto size = _config["format-icons"].size();
|
||||
auto idx = std::clamp(percentage / (100 / size), 0U, size - 1);
|
||||
return _config["format-icons"][idx].asString();
|
||||
}
|
||||
|
||||
waybar::modules::Battery::operator Gtk::Widget &()
|
||||
|
@ -3,7 +3,7 @@
|
||||
waybar::modules::Clock::Clock(Json::Value config)
|
||||
: _config(config)
|
||||
{
|
||||
_label.get_style_context()->add_class("clock");
|
||||
_label.set_name("clock");
|
||||
_thread = [this] {
|
||||
Glib::signal_idle().connect_once(sigc::mem_fun(*this, &Clock::update));
|
||||
auto now = waybar::chrono::clock::now();
|
||||
|
@ -3,7 +3,7 @@
|
||||
waybar::modules::Cpu::Cpu(Json::Value config)
|
||||
: _config(config)
|
||||
{
|
||||
_label.get_style_context()->add_class("cpu");
|
||||
_label.set_name("cpu");
|
||||
int interval = _config["interval"] ? _config["inveral"].asInt() : 10;
|
||||
_thread = [this, interval] {
|
||||
Glib::signal_idle().connect_once(sigc::mem_fun(*this, &Cpu::update));
|
||||
|
@ -4,10 +4,8 @@
|
||||
waybar::modules::Custom::Custom(std::string name, Json::Value config)
|
||||
: _name(name), _config(config)
|
||||
{
|
||||
if (!_config["exec"]) {
|
||||
std::cerr << name + " has no exec path." << std::endl;
|
||||
return;
|
||||
}
|
||||
if (!_config["exec"])
|
||||
throw std::runtime_error(name + " has no exec path.");
|
||||
int interval = _config["interval"] ? _config["inveral"].asInt() : 30;
|
||||
_thread = [this, interval] {
|
||||
Glib::signal_idle().connect_once(sigc::mem_fun(*this, &Custom::update));
|
||||
@ -36,10 +34,10 @@ auto waybar::modules::Custom::update() -> void
|
||||
|
||||
// Hide label if output is empty
|
||||
if (output.empty()) {
|
||||
_label.get_style_context()->remove_class("custom-" + _name);
|
||||
_label.set_name("");
|
||||
_label.hide();
|
||||
} else {
|
||||
_label.get_style_context()->add_class("custom-" + _name);
|
||||
_label.set_name("custom-" + _name);
|
||||
auto format = _config["format"] ? _config["format"].asString() : "{}";
|
||||
_label.set_text(fmt::format(format, output));
|
||||
_label.show();
|
||||
|
@ -3,7 +3,7 @@
|
||||
waybar::modules::Memory::Memory(Json::Value config)
|
||||
: _config(config)
|
||||
{
|
||||
_label.get_style_context()->add_class("memory");
|
||||
_label.set_name("memory");
|
||||
int interval = _config["interval"] ? _config["inveral"].asInt() : 30;
|
||||
_thread = [this, interval] {
|
||||
Glib::signal_idle().connect_once(sigc::mem_fun(*this, &Memory::update));
|
||||
|
@ -1,9 +1,11 @@
|
||||
#include "modules/network.hpp"
|
||||
|
||||
waybar::modules::Network::Network(Json::Value config)
|
||||
: _config(config), _ifid(if_nametoindex(config["interface"].asString().c_str()))
|
||||
: _config(config), _ifid(if_nametoindex(config["interface"].asCString()))
|
||||
{
|
||||
_label.get_style_context()->add_class("network");
|
||||
if (_ifid == 0)
|
||||
throw std::runtime_error("Can't found network interface");
|
||||
_label.set_name("network");
|
||||
int interval = _config["interval"] ? _config["inveral"].asInt() : 30;
|
||||
_thread = [this, interval] {
|
||||
Glib::signal_idle().connect_once(sigc::mem_fun(*this, &Network::update));
|
||||
@ -14,7 +16,7 @@ waybar::modules::Network::Network(Json::Value config)
|
||||
auto waybar::modules::Network::update() -> void
|
||||
{
|
||||
_getInfo();
|
||||
auto format = _config["format"] ? _config["format"].asString() : "{}";
|
||||
auto format = _config["format"] ? _config["format"].asString() : "{essid}";
|
||||
_label.set_text(fmt::format(format,
|
||||
fmt::arg("essid", _essid),
|
||||
fmt::arg("signaldBm", _signalStrengthdBm),
|
||||
@ -103,8 +105,6 @@ bool waybar::modules::Network::_associatedOrJoined(struct nlattr** bss)
|
||||
|
||||
auto waybar::modules::Network::_getInfo() -> void
|
||||
{
|
||||
if (_ifid == 0)
|
||||
return;
|
||||
struct nl_sock *sk = nl_socket_alloc();
|
||||
if (genl_connect(sk) != 0) {
|
||||
nl_socket_free(sk);
|
||||
|
@ -4,7 +4,7 @@ waybar::modules::Pulseaudio::Pulseaudio(Json::Value config)
|
||||
: _config(config), _mainloop(nullptr), _mainloop_api(nullptr),
|
||||
_context(nullptr), _sinkIdx(0), _volume(0), _muted(false)
|
||||
{
|
||||
_label.get_style_context()->add_class("pulseaudio");
|
||||
_label.set_name("pulseaudio");
|
||||
_mainloop = pa_threaded_mainloop_new();
|
||||
if (!_mainloop)
|
||||
throw std::runtime_error("pa_mainloop_new() failed.");
|
||||
@ -97,17 +97,27 @@ void waybar::modules::Pulseaudio::_serverInfoCb(pa_context *context,
|
||||
|
||||
auto waybar::modules::Pulseaudio::update() -> void
|
||||
{
|
||||
auto format = _config["format"] ? _config["format"].asString() : "{}%";
|
||||
auto format = _config["format"] ? _config["format"].asString() : "{volume}%";
|
||||
if (_muted) {
|
||||
format =
|
||||
_config["format-muted"] ? _config["format-muted"].asString() : format;
|
||||
_label.get_style_context()->add_class("muted");
|
||||
} else
|
||||
_label.get_style_context()->remove_class("muted");
|
||||
_label.set_label(fmt::format(format, _volume));
|
||||
_label.set_label(fmt::format(format,
|
||||
fmt::arg("volume", _volume),
|
||||
fmt::arg("icon", _getIcon(_volume))));
|
||||
_label.set_tooltip_text(_desc);
|
||||
}
|
||||
|
||||
std::string waybar::modules::Pulseaudio::_getIcon(uint16_t percentage)
|
||||
{
|
||||
if (!_config["format-icons"] || !_config["format-icons"].isArray()) return "";
|
||||
auto size = _config["format-icons"].size();
|
||||
auto idx = std::clamp(percentage / (100 / size), 0U, size - 1);
|
||||
return _config["format-icons"][idx].asString();
|
||||
}
|
||||
|
||||
waybar::modules::Pulseaudio::operator Gtk::Widget &() {
|
||||
return _label;
|
||||
}
|
||||
|
@ -1,104 +1,182 @@
|
||||
#include "modules/workspaces.hpp"
|
||||
#include "ipc/client.hpp"
|
||||
|
||||
waybar::modules::Workspaces::Workspaces(Bar &bar)
|
||||
: _bar(bar)
|
||||
waybar::modules::Workspaces::Workspaces(Bar &bar, Json::Value config)
|
||||
: _bar(bar), _config(config), _scrolling(false)
|
||||
{
|
||||
_box.get_style_context()->add_class("workspaces");
|
||||
try {
|
||||
_box.set_name("workspaces");
|
||||
std::string socketPath = get_socketpath();
|
||||
_ipcSocketfd = ipc_open_socket(socketPath);
|
||||
_ipcEventSocketfd = ipc_open_socket(socketPath);
|
||||
const char *subscribe = "[ \"workspace\", \"mode\" ]";
|
||||
_ipcfd = ipc_open_socket(socketPath);
|
||||
_ipcEventfd = ipc_open_socket(socketPath);
|
||||
const char *subscribe = "[ \"workspace\" ]";
|
||||
uint32_t len = strlen(subscribe);
|
||||
ipc_single_command(_ipcEventSocketfd, IPC_SUBSCRIBE, subscribe, &len);
|
||||
ipc_single_command(_ipcEventfd, IPC_SUBSCRIBE, subscribe, &len);
|
||||
_thread = [this] {
|
||||
try {
|
||||
if (_bar.outputName.empty()) {
|
||||
// Wait for the name of the output
|
||||
while (_bar.outputName.empty())
|
||||
_thread.sleep_for(chrono::milliseconds(150));
|
||||
} else
|
||||
ipc_recv_response(_ipcEventfd);
|
||||
uint32_t len = 0;
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
auto str = ipc_single_command(_ipcfd, IPC_GET_WORKSPACES, nullptr, &len);
|
||||
_workspaces = _getWorkspaces(str);
|
||||
Glib::signal_idle().connect_once(sigc::mem_fun(*this, &Workspaces::update));
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
return;
|
||||
}
|
||||
_thread = [this] {
|
||||
Glib::signal_idle().connect_once(sigc::mem_fun(*this, &Workspaces::update));
|
||||
_thread.sleep_for(chrono::milliseconds(250));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
auto waybar::modules::Workspaces::update() -> void
|
||||
{
|
||||
if (_bar.outputName.empty()) return;
|
||||
Json::Value workspaces = _getWorkspaces();
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
bool needReorder = false;
|
||||
for (auto it = _buttons.begin(); it != _buttons.end(); ++it) {
|
||||
auto ws = std::find_if(workspaces.begin(), workspaces.end(),
|
||||
for (auto it = _buttons.begin(); it != _buttons.end();) {
|
||||
auto ws = std::find_if(_workspaces.begin(), _workspaces.end(),
|
||||
[it](auto node) -> bool { return node["num"].asInt() == it->first; });
|
||||
if (ws == workspaces.end()) {
|
||||
if (ws == _workspaces.end()) {
|
||||
it = _buttons.erase(it);
|
||||
needReorder = true;
|
||||
} else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
for (auto node : workspaces) {
|
||||
for (auto node : _workspaces) {
|
||||
if (_bar.outputName != node["output"].asString())
|
||||
continue;
|
||||
auto it = _buttons.find(node["num"].asInt());
|
||||
if (it == _buttons.end() && _bar.outputName == node["output"].asString()) {
|
||||
if (it == _buttons.end()) {
|
||||
_addWorkspace(node);
|
||||
needReorder = true;
|
||||
} else {
|
||||
auto styleContext = it->second.get_style_context();
|
||||
bool isCurrent = node["focused"].asBool();
|
||||
if (!isCurrent) {
|
||||
styleContext->remove_class("current");
|
||||
} else if (isCurrent) {
|
||||
styleContext->add_class("current");
|
||||
}
|
||||
auto &button = it->second;
|
||||
if (node["focused"].asBool())
|
||||
button.get_style_context()->add_class("current");
|
||||
else
|
||||
button.get_style_context()->remove_class("current");
|
||||
if (needReorder)
|
||||
_box.reorder_child(it->second, node["num"].asInt() - 1);
|
||||
it->second.show();
|
||||
_box.reorder_child(button, node["num"].asInt());
|
||||
button.show();
|
||||
}
|
||||
}
|
||||
if (_scrolling)
|
||||
_scrolling = false;
|
||||
}
|
||||
|
||||
void waybar::modules::Workspaces::_addWorkspace(Json::Value node)
|
||||
{
|
||||
auto pair = _buttons.emplace(node["num"].asInt(), node["name"].asString());
|
||||
auto pair = _buttons.emplace(node["num"].asInt(),
|
||||
_getIcon(node["name"].asString()));
|
||||
auto &button = pair.first->second;
|
||||
_box.pack_start(button, false, false, 0);
|
||||
button.set_relief(Gtk::RELIEF_NONE);
|
||||
button.signal_clicked().connect([this, pair] {
|
||||
try {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
auto value = fmt::format("workspace \"{}\"", pair.first->first);
|
||||
uint32_t size = value.size();
|
||||
ipc_single_command(_ipcSocketfd, IPC_COMMAND, value.c_str(), &size);
|
||||
ipc_single_command(_ipcfd, IPC_COMMAND, value.c_str(), &size);
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
});
|
||||
_box.reorder_child(button, node["num"].asInt() - 1);
|
||||
if (node["focused"].asBool()) {
|
||||
button.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
|
||||
button.signal_scroll_event()
|
||||
.connect(sigc::mem_fun(*this, &Workspaces::_handleScroll));
|
||||
_box.reorder_child(button, node["num"].asInt());
|
||||
if (node["focused"].asBool())
|
||||
button.get_style_context()->add_class("current");
|
||||
}
|
||||
button.show();
|
||||
}
|
||||
|
||||
Json::Value waybar::modules::Workspaces::_getWorkspaces()
|
||||
std::string waybar::modules::Workspaces::_getIcon(std::string name)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
Json::Value root;
|
||||
Json::CharReaderBuilder builder;
|
||||
Json::CharReader* reader = builder.newCharReader();
|
||||
try {
|
||||
std::string str = ipc_single_command(_ipcSocketfd, IPC_GET_WORKSPACES,
|
||||
nullptr, &len);
|
||||
std::string err;
|
||||
bool res =
|
||||
reader->parse(str.c_str(), str.c_str() + str.size(), &root, &err);
|
||||
delete reader;
|
||||
if (!res) {
|
||||
std::cerr << err << std::endl;
|
||||
return root;
|
||||
if (_config["format-icons"][name])
|
||||
return _config["format-icons"][name].asString();
|
||||
if (_config["format-icons"]["default"])
|
||||
return _config["format-icons"]["default"].asString();
|
||||
return name;
|
||||
}
|
||||
|
||||
bool waybar::modules::Workspaces::_handleScroll(GdkEventScroll *e)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
// Avoid concurrent scroll event
|
||||
if (_scrolling)
|
||||
return false;
|
||||
_scrolling = true;
|
||||
int id = -1;
|
||||
uint16_t idx = 0;
|
||||
for (; idx < _workspaces.size(); idx += 1)
|
||||
if (_workspaces[idx]["focused"].asBool()) {
|
||||
id = _workspaces[idx]["num"].asInt();
|
||||
break;
|
||||
}
|
||||
if (id == -1) {
|
||||
_scrolling = false;
|
||||
return false;
|
||||
}
|
||||
if (e->direction == GDK_SCROLL_UP)
|
||||
id = _getNextWorkspace();
|
||||
if (e->direction == GDK_SCROLL_DOWN)
|
||||
id = _getPrevWorkspace();
|
||||
if (e->direction == GDK_SCROLL_SMOOTH) {
|
||||
gdouble delta_x, delta_y;
|
||||
gdk_event_get_scroll_deltas ((const GdkEvent *) e, &delta_x, &delta_y);
|
||||
if (delta_y < 0)
|
||||
id = _getNextWorkspace();
|
||||
else if (delta_y > 0)
|
||||
id = _getPrevWorkspace();
|
||||
}
|
||||
if (id == _workspaces[idx]["num"].asInt()) {
|
||||
_scrolling = false;
|
||||
return false;
|
||||
}
|
||||
auto value = fmt::format("workspace \"{}\"", id);
|
||||
uint32_t size = value.size();
|
||||
ipc_single_command(_ipcfd, IPC_COMMAND, value.c_str(), &size);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(150));
|
||||
return true;
|
||||
}
|
||||
|
||||
int waybar::modules::Workspaces::_getPrevWorkspace()
|
||||
{
|
||||
int current = -1;
|
||||
for (uint16_t i = 0; i != _workspaces.size(); i += 1)
|
||||
if (_workspaces[i]["focused"].asBool()) {
|
||||
current = _workspaces[i]["num"].asInt();
|
||||
if (i > 0)
|
||||
return _workspaces[i - 1]["num"].asInt();
|
||||
return _workspaces[_workspaces.size() - 1]["num"].asInt();
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
int waybar::modules::Workspaces::_getNextWorkspace()
|
||||
{
|
||||
int current = -1;
|
||||
for (uint16_t i = 0; i != _workspaces.size(); i += 1)
|
||||
if (_workspaces[i]["focused"].asBool()) {
|
||||
current = _workspaces[i]["num"].asInt();
|
||||
if (i + 1U < _workspaces.size())
|
||||
return _workspaces[i + 1]["num"].asInt();
|
||||
return _workspaces[0]["num"].asInt();
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
Json::Value waybar::modules::Workspaces::_getWorkspaces(const std::string data)
|
||||
{
|
||||
Json::Value res;
|
||||
try {
|
||||
std::string err;
|
||||
res = _parser.parse(data);
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
return root;
|
||||
return res;
|
||||
}
|
||||
|
||||
waybar::modules::Workspaces::operator Gtk::Widget &() {
|
||||
|
Reference in New Issue
Block a user