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