refactor: format && better output management

This commit is contained in:
Alex 2019-04-18 17:43:16 +02:00
parent 817c42841b
commit 807ef32357
13 changed files with 479 additions and 475 deletions

View File

@ -1,73 +1,63 @@
#pragma once #pragma once
#include <json/json.h>
#include <glibmm/refptr.h> #include <glibmm/refptr.h>
#include <gtkmm/main.h>
#include <gtkmm/cssprovider.h> #include <gtkmm/cssprovider.h>
#include <gtkmm/main.h>
#include <gtkmm/window.h> #include <gtkmm/window.h>
#include <json/json.h>
#include "IModule.hpp"
#include "idle-inhibit-unstable-v1-client-protocol.h"
#include "wlr-layer-shell-unstable-v1-client-protocol.h" #include "wlr-layer-shell-unstable-v1-client-protocol.h"
#include "xdg-output-unstable-v1-client-protocol.h" #include "xdg-output-unstable-v1-client-protocol.h"
#include "idle-inhibit-unstable-v1-client-protocol.h"
#include "IModule.hpp"
namespace waybar { namespace waybar {
class Client;
class Factory; class Factory;
struct waybar_output {
class Bar { struct wl_output *output;
public: std::string name;
Bar(const Client&, std::unique_ptr<struct wl_output *>&&, uint32_t); uint32_t wl_name;
Bar(const Bar&) = delete; struct zxdg_output_v1 *xdg_output;
~Bar() = default; Json::Value config;
auto toggle() -> void;
void handleSignal(int);
const Client& client;
Gtk::Window window;
struct wl_surface *surface;
struct zwlr_layer_surface_v1 *layer_surface;
std::unique_ptr<struct wl_output *> output;
std::string output_name;
uint32_t wl_name;
bool visible = true;
bool vertical = false;
private:
static void handleLogicalPosition(void *, struct zxdg_output_v1 *, int32_t,
int32_t);
static void handleLogicalSize(void *, struct zxdg_output_v1 *, int32_t,
int32_t);
static void handleDone(void *, struct zxdg_output_v1 *);
static void handleName(void *, struct zxdg_output_v1 *, const char *);
static void handleDescription(void *, struct zxdg_output_v1 *,
const char *);
static void layerSurfaceHandleConfigure(void *,
struct zwlr_layer_surface_v1 *, uint32_t, uint32_t, uint32_t);
static void layerSurfaceHandleClosed(void *,
struct zwlr_layer_surface_v1 *);
void initBar();
bool isValidOutput(const Json::Value &config);
void destroyOutput();
auto setupConfig() -> void;
auto setupWidgets() -> void;
auto setupCss() -> void;
void getModules(const Factory&, const std::string&);
uint32_t width_ = 0;
uint32_t height_ = 30;
Json::Value config_;
Glib::RefPtr<Gtk::StyleContext> style_context_;
Glib::RefPtr<Gtk::CssProvider> css_provider_;
struct zxdg_output_v1 *xdg_output_;
Gtk::Box left_;
Gtk::Box center_;
Gtk::Box right_;
Gtk::Box box_;
std::vector<std::unique_ptr<waybar::IModule>> modules_left_;
std::vector<std::unique_ptr<waybar::IModule>> modules_center_;
std::vector<std::unique_ptr<waybar::IModule>> modules_right_;
}; };
} class Bar {
public:
Bar(struct waybar_output* w_output);
Bar(const Bar &) = delete;
~Bar() = default;
auto toggle() -> void;
void handleSignal(int);
struct waybar_output* output;
Gtk::Window window;
struct wl_surface *surface;
struct zwlr_layer_surface_v1 *layer_surface;
bool visible = true;
bool vertical = false;
private:
static void layerSurfaceHandleConfigure(void *, struct zwlr_layer_surface_v1 *, uint32_t,
uint32_t, uint32_t);
static void layerSurfaceHandleClosed(void *, struct zwlr_layer_surface_v1 *);
void destroyOutput();
void onWindowRealize();
auto setupWidgets() -> void;
void getModules(const Factory &, const std::string &);
void setupAltFormatKeyForModule(const std::string &module_name);
void setupAltFormatKeyForModuleList(const char *module_list_name);
uint32_t width_ = 0;
uint32_t height_ = 30;
Gtk::Box left_;
Gtk::Box center_;
Gtk::Box right_;
Gtk::Box box_;
std::vector<std::unique_ptr<waybar::IModule>> modules_left_;
std::vector<std::unique_ptr<waybar::IModule>> modules_center_;
std::vector<std::unique_ptr<waybar::IModule>> modules_right_;
};
} // namespace waybar

View File

@ -1,41 +1,55 @@
#pragma once #pragma once
#include <unistd.h>
#include <wordexp.h>
#include <fmt/format.h> #include <fmt/format.h>
#include <gdk/gdk.h> #include <gdk/gdk.h>
#include <wayland-client.h>
#include <gdk/gdkwayland.h> #include <gdk/gdkwayland.h>
#include <unistd.h>
#include <wayland-client.h>
#include <wordexp.h>
#include "bar.hpp" #include "bar.hpp"
namespace waybar { namespace waybar {
class Client { class Client {
public: public:
Client(int argc, char *argv[]); static Client *inst();
int main(int argc, char *argv[]); int main(int argc, char *argv[]);
Glib::RefPtr<Gtk::Application> gtk_app; Glib::RefPtr<Gtk::Application> gtk_app;
std::string css_file; Glib::RefPtr<Gdk::Display> gdk_display;
std::string config_file; struct wl_display *wl_display = nullptr;
Glib::RefPtr<Gdk::Display> gdk_display; struct wl_registry *registry = nullptr;
struct wl_display *wl_display = nullptr; struct zwlr_layer_shell_v1 *layer_shell = nullptr;
struct wl_registry *registry = nullptr; struct zxdg_output_manager_v1 *xdg_output_manager = nullptr;
struct zwlr_layer_shell_v1 *layer_shell = nullptr; struct wl_seat *seat = nullptr;
struct zxdg_output_manager_v1 *xdg_output_manager = nullptr; struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager = nullptr;
struct wl_seat *seat = nullptr; std::vector<std::unique_ptr<Bar>> bars;
struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager = nullptr;
std::vector<std::unique_ptr<Bar>> bars;
private: private:
void setupConfigs(const std::string& config, const std::string& style); Client();
void bindInterfaces(); void setupConfigs(const std::string &config, const std::string &style);
const std::string getValidPath(std::vector<std::string> paths); void bindInterfaces();
const std::string getValidPath(std::vector<std::string> paths);
void handleOutput(std::unique_ptr<struct waybar_output> &output);
bool isValidOutput(const Json::Value &config, std::unique_ptr<struct waybar_output> &output);
auto setupConfig() -> void;
auto setupCss() -> void;
static void handleGlobal(void *data, struct wl_registry *registry, static void handleGlobal(void *data, struct wl_registry *registry, uint32_t name,
uint32_t name, const char *interface, uint32_t version); const char *interface, uint32_t version);
static void handleGlobalRemove(void *data, static void handleGlobalRemove(void *data, struct wl_registry *registry, uint32_t name);
struct wl_registry *registry, uint32_t name); static void handleLogicalPosition(void *, struct zxdg_output_v1 *, int32_t, int32_t);
static void handleLogicalSize(void *, struct zxdg_output_v1 *, int32_t, int32_t);
static void handleDone(void *, struct zxdg_output_v1 *);
static void handleName(void *, struct zxdg_output_v1 *, const char *);
static void handleDescription(void *, struct zxdg_output_v1 *, const char *);
Json::Value config_;
std::string css_file_;
std::string config_file_;
Glib::RefPtr<Gtk::StyleContext> style_context_;
Glib::RefPtr<Gtk::CssProvider> css_provider_;
std::vector<std::unique_ptr<struct waybar_output>> outputs_;
}; };
} } // namespace waybar

View File

@ -28,11 +28,10 @@
#endif #endif
#include "modules/temperature.hpp" #include "modules/temperature.hpp"
#include "modules/custom.hpp" #include "modules/custom.hpp"
#include "bar.hpp"
namespace waybar { namespace waybar {
class Bar;
class Factory { class Factory {
public: public:
Factory(const Bar& bar, const Json::Value& config); Factory(const Bar& bar, const Json::Value& config);

View File

@ -21,7 +21,7 @@ class Network : public ALabel {
auto update() -> void; auto update() -> void;
private: private:
static const uint8_t MAX_RETRY = 5; static const uint8_t MAX_RETRY = 5;
static const uint8_t EPOLL_MAX = 255; static const uint8_t EPOLL_MAX = 200;
static int handleEvents(struct nl_msg*, void*); static int handleEvents(struct nl_msg*, void*);
static int handleScan(struct nl_msg*, void*); static int handleScan(struct nl_msg*, void*);

View File

@ -14,6 +14,9 @@ struct JsonParser {
{ {
Json::Value root; Json::Value root;
std::string err; std::string err;
if (data.empty()) {
return root;
}
bool res = bool res =
reader_->parse(data.c_str(), data.c_str() + data.size(), &root, &err); reader_->parse(data.c_str(), data.c_str() + data.size(), &root, &err);
if (!res) if (!res)

View File

@ -1,32 +1,26 @@
#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(const Client& client, waybar::Bar::Bar(struct waybar_output* w_output)
std::unique_ptr<struct wl_output *> &&p_output, uint32_t p_wl_name) : output(w_output),
: client(client), window{Gtk::WindowType::WINDOW_TOPLEVEL}, window{Gtk::WindowType::WINDOW_TOPLEVEL},
surface(nullptr), layer_surface(nullptr), surface(nullptr),
output(std::move(p_output)), wl_name(p_wl_name), layer_surface(nullptr),
left_(Gtk::ORIENTATION_HORIZONTAL, 0), center_(Gtk::ORIENTATION_HORIZONTAL, 0), left_(Gtk::ORIENTATION_HORIZONTAL, 0),
right_(Gtk::ORIENTATION_HORIZONTAL, 0), box_(Gtk::ORIENTATION_HORIZONTAL, 0) center_(Gtk::ORIENTATION_HORIZONTAL, 0),
{ right_(Gtk::ORIENTATION_HORIZONTAL, 0),
static const struct zxdg_output_v1_listener xdgOutputListener = { box_(Gtk::ORIENTATION_HORIZONTAL, 0) {
.logical_position = handleLogicalPosition,
.logical_size = handleLogicalSize,
.done = handleDone,
.name = handleName,
.description = handleDescription,
};
xdg_output_ =
zxdg_output_manager_v1_get_xdg_output(client.xdg_output_manager, *output);
zxdg_output_v1_add_listener(xdg_output_, &xdgOutputListener, this);
window.set_title("waybar"); window.set_title("waybar");
window.set_name("waybar"); window.set_name("waybar");
window.set_decorated(false); window.set_decorated(false);
window.set_resizable(false); window.set_resizable(false);
setupConfig();
setupCss(); if (output->config["position"] == "right" || output->config["position"] == "left") {
height_ = 0;
width_ = 30;
}
window.set_size_request(width_, height_);
auto gtk_window = window.gobj(); auto gtk_window = window.gobj();
auto gtk_widget = GTK_WIDGET(gtk_window); auto gtk_widget = GTK_WIDGET(gtk_window);
@ -34,87 +28,37 @@ waybar::Bar::Bar(const Client& client,
auto gdk_window = window.get_window()->gobj(); auto gdk_window = window.get_window()->gobj();
gdk_wayland_window_set_use_custom_surface(gdk_window); gdk_wayland_window_set_use_custom_surface(gdk_window);
surface = gdk_wayland_window_get_wl_surface(gdk_window); surface = gdk_wayland_window_get_wl_surface(gdk_window);
}
void waybar::Bar::initBar()
{
// Converting string to button code rn as to avoid doing it later
auto setupAltFormatKeyForModule = [this](const std::string& module_name){
if (config_.isMember(module_name)) {
Json::Value& module = config_[module_name];
if (module.isMember("format-alt")) {
if (module.isMember("format-alt-click")) {
Json::Value& click = module["format-alt-click"];
if (click.isString()) {
std::string str_click = click.asString();
if (str_click == "click-right") {
module["format-alt-click"] = 3u;
} else if (str_click == "click-middle") {
module["format-alt-click"] = 2u;
} else if (str_click == "click-backward") {
module["format-alt-click"] = 8u;
} else if (str_click == "click-forward") {
module["format-alt-click"] = 9u;
} else {
module["format-alt-click"] = 1u; // default click-left
}
} else {
module["format-alt-click"] = 1u;
}
} else {
module["format-alt-click"] = 1u;
}
}
}
};
auto setupAltFormatKeyForModuleList = [this, &setupAltFormatKeyForModule](const char* module_list_name) {
if (config_.isMember(module_list_name)) {
Json::Value& modules = config_[module_list_name];
for (const Json::Value& module_name : modules) {
if (module_name.isString()) {
setupAltFormatKeyForModule(module_name.asString());
}
}
}
};
// Convert to button code for every module that is used. // Convert to button code for every module that is used.
setupAltFormatKeyForModuleList("modules-left"); setupAltFormatKeyForModuleList("modules-left");
setupAltFormatKeyForModuleList("modules-right"); setupAltFormatKeyForModuleList("modules-right");
setupAltFormatKeyForModuleList("modules-center"); setupAltFormatKeyForModuleList("modules-center");
std::size_t layer = config_["layer"] == "top" std::size_t layer = output->config["layer"] == "top" ? ZWLR_LAYER_SHELL_V1_LAYER_TOP
? ZWLR_LAYER_SHELL_V1_LAYER_TOP : ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM; : ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
layer_surface = zwlr_layer_shell_v1_get_layer_surface( layer_surface = zwlr_layer_shell_v1_get_layer_surface(waybar::Client::inst()->layer_shell,
client.layer_shell, surface, *output, layer, "waybar"); surface, output->output, layer, "waybar");
static const struct zwlr_layer_surface_v1_listener layer_surface_listener = { static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
.configure = layerSurfaceHandleConfigure, .configure = layerSurfaceHandleConfigure,
.closed = layerSurfaceHandleClosed, .closed = layerSurfaceHandleClosed,
}; };
zwlr_layer_surface_v1_add_listener(layer_surface, &layer_surface_listener, this); zwlr_layer_surface_v1_add_listener(layer_surface, &layer_surface_listener, this);
if (config_["position"] == "right" || config_["position"] == "left") { auto height = output->config["height"].isUInt() ? output->config["height"].asUInt() : height_;
height_ = 0; auto width = output->config["width"].isUInt() ? output->config["width"].asUInt() : width_;
width_ = 30;
}
auto height = config_["height"].isUInt() ? config_["height"].asUInt() : height_;
auto width = config_["width"].isUInt() ? config_["width"].asUInt() : width_;
std::size_t anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP; std::size_t anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP;
if (config_["position"] == "bottom") { if (output->config["position"] == "bottom") {
anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
} else if (config_["position"] == "left") { } else if (output->config["position"] == "left") {
anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT; anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT;
} else if (config_["position"] == "right") { } else if (output->config["position"] == "right") {
anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
} }
if (anchor == ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM || anchor == ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) { if (anchor == ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM || anchor == ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) {
anchor |= ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; anchor |= ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
} else if (anchor == ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT || anchor == ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) { } else if (anchor == ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT ||
anchor == ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) {
anchor |= ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; anchor |= ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
left_ = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0); left_ = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0);
center_ = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0); center_ = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0);
@ -132,98 +76,66 @@ void waybar::Bar::initBar()
setupWidgets(); setupWidgets();
} }
void waybar::Bar::handleLogicalPosition(void* /*data*/, // Converting string to button code rn as to avoid doing it later
struct zxdg_output_v1* /*zxdg_output_v1*/, int32_t /*x*/, int32_t /*y*/) void waybar::Bar::setupAltFormatKeyForModule(const std::string& module_name) {
{ if (output->config.isMember(module_name)) {
// Nothing here Json::Value& module = output->config[module_name];
} if (module.isMember("format-alt")) {
if (module.isMember("format-alt-click")) {
Json::Value& click = module["format-alt-click"];
if (click.isString()) {
std::string str_click = click.asString();
void waybar::Bar::handleLogicalSize(void* /*data*/, if (str_click == "click-right") {
struct zxdg_output_v1* /*zxdg_output_v1*/, int32_t /*width*/, module["format-alt-click"] = 3u;
int32_t /*height*/) } else if (str_click == "click-middle") {
{ module["format-alt-click"] = 2u;
// Nothing here } else if (str_click == "click-backward") {
} module["format-alt-click"] = 8u;
} else if (str_click == "click-forward") {
void waybar::Bar::handleDone(void* /*data*/, module["format-alt-click"] = 9u;
struct zxdg_output_v1* /*zxdg_output_v1*/) } else {
{ module["format-alt-click"] = 1u; // default click-left
// Nothing here }
} } else {
module["format-alt-click"] = 1u;
bool waybar::Bar::isValidOutput(const Json::Value &config) }
{ } else {
bool found = true; module["format-alt-click"] = 1u;
if (config["output"].isArray()) {
bool in_array = false;
for (auto const &output : config["output"]) {
if (output.isString() && output.asString() == output_name) {
in_array = true;
break;
} }
} }
found = in_array;
} }
if (config["output"].isString() && config["output"].asString() != output_name) {
found = false;
}
return found;
} }
void waybar::Bar::handleName(void* data, struct zxdg_output_v1* /*xdg_output*/, void waybar::Bar::setupAltFormatKeyForModuleList(const char* module_list_name) {
const char* name) if (output->config.isMember(module_list_name)) {
{ Json::Value& modules = output->config[module_list_name];
auto o = static_cast<waybar::Bar *>(data); for (const Json::Value& module_name : modules) {
o->output_name = name; if (module_name.isString()) {
bool found = true; setupAltFormatKeyForModule(module_name.asString());
if (o->config_.isArray()) {
bool in_array = false;
for (auto const &config : o->config_) {
if (config.isObject() && o->isValidOutput(config)) {
in_array = true;
o->config_ = config;
break;
} }
} }
found = in_array;
} else {
found = o->isValidOutput(o->config_);
}
if (!found) {
wl_output_destroy(*o->output);
zxdg_output_v1_destroy(o->xdg_output_);
} else {
o->initBar();
} }
} }
void waybar::Bar::handleDescription(void* /*data*/, void waybar::Bar::handleSignal(int signal) {
struct zxdg_output_v1* /*zxdg_output_v1*/, const char* /*description*/)
{
// Nothing here
}
void waybar::Bar::handleSignal(int signal)
{
for (auto& module : modules_left_) { for (auto& module : modules_left_) {
auto* custom = dynamic_cast<waybar::modules::Custom*>(module.get()); auto* custom = dynamic_cast<waybar::modules::Custom*>(module.get());
if(custom) custom->refresh(signal); if (custom) custom->refresh(signal);
} }
for (auto& module : modules_center_) { for (auto& module : modules_center_) {
auto* custom = dynamic_cast<waybar::modules::Custom*>(module.get()); auto* custom = dynamic_cast<waybar::modules::Custom*>(module.get());
if(custom) custom->refresh(signal); if (custom) custom->refresh(signal);
} }
for (auto& module : modules_right_) { for (auto& module : modules_right_) {
auto* custom = dynamic_cast<waybar::modules::Custom*>(module.get()); auto* custom = dynamic_cast<waybar::modules::Custom*>(module.get());
if(custom) custom->refresh(signal); if (custom) custom->refresh(signal);
} }
} }
void waybar::Bar::layerSurfaceHandleConfigure(void* data, void waybar::Bar::layerSurfaceHandleConfigure(void* data, struct zwlr_layer_surface_v1* surface,
struct zwlr_layer_surface_v1* surface, uint32_t serial, uint32_t width, uint32_t serial, uint32_t width, uint32_t height) {
uint32_t height) auto o = static_cast<waybar::Bar*>(data);
{
auto o = static_cast<waybar::Bar *>(data);
zwlr_layer_surface_v1_ack_configure(surface, serial); zwlr_layer_surface_v1_ack_configure(surface, serial);
if (width != o->width_ || height != o->height_) { if (width != o->width_ || height != o->height_) {
o->width_ = width; o->width_ = width;
@ -234,37 +146,38 @@ void waybar::Bar::layerSurfaceHandleConfigure(void* data,
int min_width, min_height; int min_width, min_height;
o->window.get_size(min_width, min_height); o->window.get_size(min_width, min_height);
if (o->height_ < static_cast<uint32_t>(min_height)) { if (o->height_ < static_cast<uint32_t>(min_height)) {
std::cout << fmt::format("Requested height: {} exceeds the minimum \ std::cout << fmt::format(
height: {} required by the modules", o->height_, min_height) << std::endl; "Requested height: {} exceeds the minimum \
height: {} required by the modules",
o->height_, min_height)
<< std::endl;
o->height_ = min_height; o->height_ = min_height;
} }
if (o->width_ < static_cast<uint32_t>(min_width)) { if (o->width_ < static_cast<uint32_t>(min_width)) {
std::cout << fmt::format("Requested width: {} exceeds the minimum \ std::cout << fmt::format(
width: {} required by the modules", o->height_, min_width) << std::endl; "Requested width: {} exceeds the minimum \
width: {} required by the modules",
o->height_, min_width)
<< std::endl;
o->width_ = min_width; o->width_ = min_width;
} }
std::cout << fmt::format( std::cout << fmt::format("Bar configured (width: {}, height: {}) for output: {}", o->width_,
"Bar configured (width: {}, height: {}) for output: {}", o->height_, o->output->name)
o->width_, o->height_, o->output_name) << std::endl; << std::endl;
wl_surface_commit(o->surface); wl_surface_commit(o->surface);
} }
} }
void waybar::Bar::layerSurfaceHandleClosed(void* data, void waybar::Bar::layerSurfaceHandleClosed(void* data, struct zwlr_layer_surface_v1* /*surface*/) {
struct zwlr_layer_surface_v1* /*surface*/) auto o = static_cast<waybar::Bar*>(data);
{
auto o = static_cast<waybar::Bar *>(data);
zwlr_layer_surface_v1_destroy(o->layer_surface); zwlr_layer_surface_v1_destroy(o->layer_surface);
wl_output_destroy(*o->output);
zxdg_output_v1_destroy(o->xdg_output_);
o->modules_left_.clear(); o->modules_left_.clear();
o->modules_center_.clear(); o->modules_center_.clear();
o->modules_right_.clear(); o->modules_right_.clear();
} }
auto waybar::Bar::toggle() -> void auto waybar::Bar::toggle() -> void {
{
visible = !visible; visible = !visible;
auto zone = visible ? height_ : 0; auto zone = visible ? height_ : 0;
if (!visible) { if (!visible) {
@ -276,35 +189,9 @@ auto waybar::Bar::toggle() -> void
wl_surface_commit(surface); wl_surface_commit(surface);
} }
auto waybar::Bar::setupConfig() -> void void waybar::Bar::getModules(const Factory& factory, const std::string& pos) {
{ if (output->config[pos].isArray()) {
std::ifstream file(client.config_file); for (const auto& name : output->config[pos]) {
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>());
util::JsonParser parser;
config_ = parser.parse(str);
}
auto waybar::Bar::setupCss() -> void
{
css_provider_ = Gtk::CssProvider::create();
style_context_ = Gtk::StyleContext::create();
// Load our css file, wherever that may be hiding
if (css_provider_->load_from_path(client.css_file)) {
Glib::RefPtr<Gdk::Screen> screen = window.get_screen();
style_context_->add_provider_for_screen(screen, css_provider_,
GTK_STYLE_PROVIDER_PRIORITY_USER);
}
}
void waybar::Bar::getModules(const Factory& factory, const std::string& pos)
{
if (config_[pos].isArray()) {
for (const auto &name : config_[pos]) {
try { try {
auto module = factory.makeModule(name.asString()); auto module = factory.makeModule(name.asString());
if (pos == "modules-left") { if (pos == "modules-left") {
@ -330,14 +217,13 @@ void waybar::Bar::getModules(const Factory& factory, const std::string& pos)
} }
} }
auto waybar::Bar::setupWidgets() -> void auto waybar::Bar::setupWidgets() -> void {
{
window.add(box_); window.add(box_);
box_.pack_start(left_, true, true); box_.pack_start(left_, true, true);
box_.set_center_widget(center_); box_.set_center_widget(center_);
box_.pack_end(right_, true, true); box_.pack_end(right_, true, true);
Factory factory(*this, config_); Factory factory(*this, output->config);
getModules(factory, "modules-left"); getModules(factory, "modules-left");
getModules(factory, "modules-center"); getModules(factory, "modules-center");
getModules(factory, "modules-right"); getModules(factory, "modules-right");

View File

@ -1,25 +1,20 @@
#include "client.hpp" #include "client.hpp"
#include "util/clara.hpp" #include <fstream>
#include <iostream> #include <iostream>
#include "util/clara.hpp"
#include "util/json.hpp"
waybar::Client::Client(int argc, char* argv[]) waybar::Client::Client() {}
: gtk_app(Gtk::Application::create(argc, argv, "fr.arouillard.waybar")),
gdk_display(Gdk::Display::get_default()) waybar::Client *waybar::Client::inst() {
{ static Client *c = new Client();
if (!gdk_display) { return c;
throw std::runtime_error("Can't find display");
}
if (!GDK_IS_WAYLAND_DISPLAY(gdk_display->gobj())) {
throw std::runtime_error("Bar need to run under Wayland");
}
wl_display = gdk_wayland_display_get_wl_display(gdk_display->gobj());
} }
const std::string waybar::Client::getValidPath(std::vector<std::string> paths) const std::string waybar::Client::getValidPath(std::vector<std::string> paths) {
{
wordexp_t p; wordexp_t p;
for (const std::string &path: paths) { for (const std::string &path : paths) {
if (wordexp(path.c_str(), &p, 0) == 0) { if (wordexp(path.c_str(), &p, 0) == 0) {
if (access(*p.we_wordv, F_OK) == 0) { if (access(*p.we_wordv, F_OK) == 0) {
std::string result = *p.we_wordv; std::string result = *p.we_wordv;
@ -33,77 +28,189 @@ const std::string waybar::Client::getValidPath(std::vector<std::string> paths)
return std::string(); return std::string();
} }
void waybar::Client::handleGlobal(void *data, struct wl_registry *registry, void waybar::Client::handleGlobal(void *data, struct wl_registry *registry, uint32_t name,
uint32_t name, const char *interface, uint32_t version) const char *interface, uint32_t version) {
{ auto client = static_cast<Client *>(data);
auto o = static_cast<waybar::Client *>(data);
if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) { if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
o->layer_shell = static_cast<struct zwlr_layer_shell_v1 *>( client->layer_shell = static_cast<struct zwlr_layer_shell_v1 *>(
wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, version)); wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, version));
} else if (strcmp(interface, wl_output_interface.name) == 0) { } else if (strcmp(interface, wl_output_interface.name) == 0) {
auto output = std::make_unique<struct wl_output *>(); auto wl_output = static_cast<struct wl_output *>(
*output = static_cast<struct wl_output *>(wl_registry_bind(registry, name, wl_registry_bind(registry, name, &wl_output_interface, version));
&wl_output_interface, version)); client->outputs_.emplace_back(new struct waybar_output({wl_output, "", name, nullptr}));
if (o->xdg_output_manager != nullptr) { client->handleOutput(client->outputs_.back());
o->bars.emplace_back(std::make_unique<Bar>(*o, std::move(output), name));
}
} else if (strcmp(interface, wl_seat_interface.name) == 0) { } else if (strcmp(interface, wl_seat_interface.name) == 0) {
o->seat = static_cast<struct wl_seat *>(wl_registry_bind(registry, name, client->seat = static_cast<struct wl_seat *>(
&wl_seat_interface, version)); wl_registry_bind(registry, name, &wl_seat_interface, version));
} else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0 } else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0 &&
&& version >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION) { version >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION) {
o->xdg_output_manager = static_cast<struct zxdg_output_manager_v1 *>( client->xdg_output_manager = static_cast<struct zxdg_output_manager_v1 *>(wl_registry_bind(
wl_registry_bind(registry, name, registry, name, &zxdg_output_manager_v1_interface, ZXDG_OUTPUT_V1_NAME_SINCE_VERSION));
&zxdg_output_manager_v1_interface, ZXDG_OUTPUT_V1_NAME_SINCE_VERSION));
} else if (strcmp(interface, zwp_idle_inhibit_manager_v1_interface.name) == 0) { } else if (strcmp(interface, zwp_idle_inhibit_manager_v1_interface.name) == 0) {
o->idle_inhibit_manager = static_cast<struct zwp_idle_inhibit_manager_v1 *>( waybar::Client::inst()->idle_inhibit_manager =
wl_registry_bind(registry, name, static_cast<struct zwp_idle_inhibit_manager_v1 *>(
&zwp_idle_inhibit_manager_v1_interface, 1)); wl_registry_bind(registry, name, &zwp_idle_inhibit_manager_v1_interface, 1));
} }
} }
void waybar::Client::handleGlobalRemove(void* data, void waybar::Client::handleGlobalRemove(void *data, struct wl_registry * /*registry*/,
struct wl_registry* /*registry*/, uint32_t name) uint32_t name) {
{ auto client = static_cast<Client *>(data);
auto o = static_cast<waybar::Client *>(data); for (auto it = client->bars.begin(); it != client->bars.end();) {
for (auto it = o->bars.begin(); it != o->bars.end(); ++it) { if ((*it)->output->wl_name == name) {
if ((*it)->wl_name == name) { auto output_name = (*it)->output->name;
auto output_name = (*it)->output_name; (*it)->window.close();
o->bars.erase(it); it = client->bars.erase(it);
std::cout << "Bar removed from output: " + output_name << std::endl; std::cout << "Bar removed from output: " + output_name << std::endl;
break; } else {
++it;
} }
} }
auto it = std::find_if(client->outputs_.begin(), client->outputs_.end(),
[&name](const auto &output) { return output->wl_name == name; });
if (it != client->outputs_.end()) {
zxdg_output_v1_destroy((*it)->xdg_output);
wl_output_destroy((*it)->output);
client->outputs_.erase(it);
}
} }
void waybar::Client::setupConfigs(const std::string& config, const std::string& style) void waybar::Client::handleOutput(std::unique_ptr<struct waybar_output> &output) {
{ static const struct zxdg_output_v1_listener xdgOutputListener = {
config_file = config.empty() ? getValidPath({ .logical_position = handleLogicalPosition,
"$XDG_CONFIG_HOME/waybar/config", .logical_size = handleLogicalSize,
"$HOME/.config/waybar/config", .done = handleDone,
"$HOME/waybar/config", .name = handleName,
"/etc/xdg/waybar/config", .description = handleDescription,
"./resources/config", };
}) : config; output->xdg_output = zxdg_output_manager_v1_get_xdg_output(xdg_output_manager, output->output);
css_file = style.empty() ? getValidPath({ zxdg_output_v1_add_listener(output->xdg_output, &xdgOutputListener, &output->wl_name);
"$XDG_CONFIG_HOME/waybar/style.css", }
"$HOME/.config/waybar/style.css",
"$HOME/waybar/style.css", void waybar::Client::handleLogicalPosition(void * /*data*/,
"/etc/xdg/waybar/style.css", struct zxdg_output_v1 * /*zxdg_output_v1*/,
"./resources/style.css", int32_t /*x*/, int32_t /*y*/) {
}) : style; // Nothing here
if (css_file.empty() || config_file.empty()) { }
void waybar::Client::handleLogicalSize(void * /*data*/, struct zxdg_output_v1 * /*zxdg_output_v1*/,
int32_t /*width*/, int32_t /*height*/) {
// Nothing here
}
void waybar::Client::handleDone(void * /*data*/, struct zxdg_output_v1 * /*zxdg_output_v1*/) {
// Nothing here
}
bool waybar::Client::isValidOutput(const Json::Value &config,
std::unique_ptr<struct waybar_output> &output) {
bool found = true;
if (config["output"].isArray()) {
bool in_array = false;
for (auto const &output_conf : config["output"]) {
if (output_conf.isString() && output_conf.asString() == output->name) {
in_array = true;
break;
}
}
found = in_array;
}
if (config["output"].isString() && config["output"].asString() != output->name) {
found = false;
}
return found;
}
void waybar::Client::handleName(void *data, struct zxdg_output_v1 * /*xdg_output*/,
const char *name) {
auto wl_name = *static_cast<uint32_t *>(data);
auto client = waybar::Client::inst();
auto it = std::find_if(client->outputs_.begin(), client->outputs_.end(),
[&wl_name](const auto &output) { return output->wl_name == wl_name; });
if (it == client->outputs_.end()) {
std::cerr << "Unable to find valid output" << std::endl;
return;
}
(*it)->name = name;
bool found = true;
if (client->config_.isArray()) {
bool in_array = false;
for (auto const &config : client->config_) {
if (config.isObject() && client->isValidOutput(config, *it)) {
in_array = true;
(*it)->config = config;
break;
}
}
found = in_array;
} else {
(*it)->config = client->config_;
found = client->isValidOutput((*it)->config, *it);
}
if (!found) {
wl_output_destroy((*it)->output);
zxdg_output_v1_destroy((*it)->xdg_output);
} else {
client->bars.emplace_back(std::make_unique<Bar>(it->get()));
Glib::RefPtr<Gdk::Screen> screen = client->bars.back()->window.get_screen();
client->style_context_->add_provider_for_screen(screen, client->css_provider_,
GTK_STYLE_PROVIDER_PRIORITY_USER);
}
}
void waybar::Client::handleDescription(void * /*data*/, struct zxdg_output_v1 * /*zxdg_output_v1*/,
const char * /*description*/) {
// Nothing here
}
void waybar::Client::setupConfigs(const std::string &config, const std::string &style) {
config_file_ = config.empty() ? getValidPath({
"$XDG_CONFIG_HOME/waybar/config",
"$HOME/.config/waybar/config",
"$HOME/waybar/config",
"/etc/xdg/waybar/config",
"./resources/config",
})
: config;
css_file_ = style.empty() ? getValidPath({
"$XDG_CONFIG_HOME/waybar/style.css",
"$HOME/.config/waybar/style.css",
"$HOME/waybar/style.css",
"/etc/xdg/waybar/style.css",
"./resources/style.css",
})
: style;
if (css_file_.empty() || config_file_.empty()) {
throw std::runtime_error("Missing required resources files"); throw std::runtime_error("Missing required resources files");
} }
std::cout << "Resources files: " + config_file + ", " + css_file << std::endl; std::cout << "Resources files: " + config_file_ + ", " + css_file_ << std::endl;
} }
void waybar::Client::bindInterfaces() auto waybar::Client::setupConfig() -> void {
{ std::ifstream file(config_file_);
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>());
util::JsonParser parser;
config_ = parser.parse(str);
}
auto waybar::Client::setupCss() -> void {
css_provider_ = Gtk::CssProvider::create();
style_context_ = Gtk::StyleContext::create();
// Load our css file, wherever that may be hiding
if (!css_provider_->load_from_path(css_file_)) {
throw std::runtime_error("Can't open style file");
}
}
void waybar::Client::bindInterfaces() {
registry = wl_display_get_registry(wl_display); registry = wl_display_get_registry(wl_display);
static const struct wl_registry_listener registry_listener = { static const struct wl_registry_listener registry_listener = {
.global = handleGlobal, .global = handleGlobal,
.global_remove = handleGlobalRemove, .global_remove = handleGlobalRemove,
}; };
wl_registry_add_listener(registry, &registry_listener, this); wl_registry_add_listener(registry, &registry_listener, this);
wl_display_roundtrip(wl_display); wl_display_roundtrip(wl_display);
@ -113,18 +220,26 @@ void waybar::Client::bindInterfaces()
wl_display_roundtrip(wl_display); wl_display_roundtrip(wl_display);
} }
int waybar::Client::main(int argc, char* argv[]) int waybar::Client::main(int argc, char *argv[]) {
{ gtk_app = Gtk::Application::create(argc, argv, "fr.arouillard.waybar");
gdk_display = Gdk::Display::get_default();
if (!gdk_display) {
throw std::runtime_error("Can't find display");
}
if (!GDK_IS_WAYLAND_DISPLAY(gdk_display->gobj())) {
throw std::runtime_error("Bar need to run under Wayland");
}
wl_display = gdk_wayland_display_get_wl_display(gdk_display->gobj());
bool show_help = false; bool show_help = false;
bool show_version = false; bool show_version = false;
std::string config; std::string config;
std::string style; std::string style;
std::string bar_id; std::string bar_id;
auto cli = clara::detail::Help(show_help) auto cli = clara::detail::Help(show_help) |
| clara::detail::Opt(show_version)["-v"]["--version"]("Show version") clara::detail::Opt(show_version)["-v"]["--version"]("Show version") |
| clara::detail::Opt(config, "config")["-c"]["--config"]("Config path") clara::detail::Opt(config, "config")["-c"]["--config"]("Config path") |
| clara::detail::Opt(style, "style")["-s"]["--style"]("Style path") clara::detail::Opt(style, "style")["-s"]["--style"]("Style path") |
| clara::detail::Opt(bar_id, "id")["-b"]["--bar"]("Bar id"); clara::detail::Opt(bar_id, "id")["-b"]["--bar"]("Bar id");
auto res = cli.parse(clara::detail::Args(argc, argv)); auto res = cli.parse(clara::detail::Args(argc, argv));
if (!res) { if (!res) {
std::cerr << "Error in command line: " << res.errorMessage() << std::endl; std::cerr << "Error in command line: " << res.errorMessage() << std::endl;
@ -139,6 +254,8 @@ int waybar::Client::main(int argc, char* argv[])
return 0; return 0;
} }
setupConfigs(config, style); setupConfigs(config, style);
setupConfig();
setupCss();
bindInterfaces(); bindInterfaces();
gtk_app->hold(); gtk_app->hold();
gtk_app->run(); gtk_app->run();

View File

@ -2,31 +2,26 @@
#include <iostream> #include <iostream>
#include "client.hpp" #include "client.hpp"
namespace waybar {
static Client* client;
} // namespace waybar
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
try { try {
waybar::Client c(argc, argv); auto client = waybar::Client::inst();
waybar::client = &c;
std::signal(SIGUSR1, [](int /*signal*/) { std::signal(SIGUSR1, [](int /*signal*/) {
for (auto& bar : waybar::client->bars) { for (auto& bar : waybar::Client::inst()->bars) {
bar->toggle(); bar->toggle();
} }
}); });
for (int sig = SIGRTMIN + 1; sig <= SIGRTMAX; ++sig) { for (int sig = SIGRTMIN + 1; sig <= SIGRTMAX; ++sig) {
std::signal(sig, [](int sig /*signal*/) { std::signal(sig, [](int sig) {
for (auto& bar : waybar::client->bars) { for (auto& bar : waybar::Client::inst()->bars) {
bar->handleSignal(sig); bar->handleSignal(sig);
} }
}); });
} }
return c.main(argc, argv); auto ret = client->main(argc, argv);
delete client;
return ret;
} catch (const std::exception& e) { } catch (const std::exception& e) {
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;
return 1; return 1;

View File

@ -1,9 +1,9 @@
#include "modules/idle_inhibitor.hpp" #include "modules/idle_inhibitor.hpp"
#include "util/command.hpp" #include "util/command.hpp"
waybar::modules::IdleInhibitor::IdleInhibitor(const std::string& id, const Bar& bar, const Json::Value& config) waybar::modules::IdleInhibitor::IdleInhibitor(const std::string& id, const Bar& bar,
: ALabel(config, "{status}"), bar_(bar), status_("deactivated"), idle_inhibitor_(nullptr) const Json::Value& config)
{ : ALabel(config, "{status}"), bar_(bar), status_("deactivated"), idle_inhibitor_(nullptr) {
label_.set_name("idle_inhibitor"); label_.set_name("idle_inhibitor");
if (!id.empty()) { if (!id.empty()) {
label_.get_style_context()->add_class(id); label_.get_style_context()->add_class(id);
@ -14,21 +14,18 @@ waybar::modules::IdleInhibitor::IdleInhibitor(const std::string& id, const Bar&
dp.emit(); dp.emit();
} }
waybar::modules::IdleInhibitor::~IdleInhibitor() waybar::modules::IdleInhibitor::~IdleInhibitor() {
{ if (idle_inhibitor_) {
if(idle_inhibitor_) {
zwp_idle_inhibitor_v1_destroy(idle_inhibitor_); zwp_idle_inhibitor_v1_destroy(idle_inhibitor_);
idle_inhibitor_ = nullptr; idle_inhibitor_ = nullptr;
} }
} }
auto waybar::modules::IdleInhibitor::update() -> void auto waybar::modules::IdleInhibitor::update() -> void {
{
label_.set_markup( label_.set_markup(
fmt::format(format_, fmt::arg("status", status_), fmt::format(format_, fmt::arg("status", status_), fmt::arg("icon", getIcon(0, status_))));
fmt::arg("icon", getIcon(0, status_))));
label_.get_style_context()->add_class(status_); label_.get_style_context()->add_class(status_);
if(tooltipEnabled()) { if (tooltipEnabled()) {
label_.set_tooltip_text(status_); label_.set_tooltip_text(status_);
} }
} }
@ -39,10 +36,10 @@ bool waybar::modules::IdleInhibitor::handleToggle(GdkEventButton* const& e) {
if (idle_inhibitor_) { if (idle_inhibitor_) {
zwp_idle_inhibitor_v1_destroy(idle_inhibitor_); zwp_idle_inhibitor_v1_destroy(idle_inhibitor_);
idle_inhibitor_ = nullptr; idle_inhibitor_ = nullptr;
status_ = "deactivated"; status_ = "deactivated";
} else { } else {
idle_inhibitor_ = zwp_idle_inhibit_manager_v1_create_inhibitor( idle_inhibitor_ = zwp_idle_inhibit_manager_v1_create_inhibitor(
bar_.client.idle_inhibit_manager, bar_.surface); waybar::Client::inst()->idle_inhibit_manager, bar_.surface);
status_ = "activated"; status_ = "activated";
} }
if (config_["on-click"].isString() && e->button == 1) { if (config_["on-click"].isString() && e->button == 1) {

View File

@ -72,7 +72,7 @@ void waybar::modules::Network::createInfoSocket()
} }
{ {
ev_fd_ = eventfd(0, EFD_NONBLOCK); ev_fd_ = eventfd(0, EFD_NONBLOCK);
struct epoll_event event; struct epoll_event event = {0};
event.events = EPOLLIN | EPOLLET; event.events = EPOLLIN | EPOLLET;
event.data.fd = ev_fd_; event.data.fd = ev_fd_;
if (epoll_ctl(efd_, EPOLL_CTL_ADD, ev_fd_, &event) == -1) { if (epoll_ctl(efd_, EPOLL_CTL_ADD, ev_fd_, &event) == -1) {
@ -81,7 +81,7 @@ void waybar::modules::Network::createInfoSocket()
} }
{ {
auto fd = nl_socket_get_fd(info_sock_); auto fd = nl_socket_get_fd(info_sock_);
struct epoll_event event; struct epoll_event event = {0};
event.events = EPOLLIN | EPOLLET | EPOLLRDHUP; event.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
event.data.fd = fd; event.data.fd = fd;
if (epoll_ctl(efd_, EPOLL_CTL_ADD, fd, &event) == -1) { if (epoll_ctl(efd_, EPOLL_CTL_ADD, fd, &event) == -1) {
@ -114,7 +114,7 @@ void waybar::modules::Network::worker()
} }
thread_timer_.sleep_for(interval_); thread_timer_.sleep_for(interval_);
}; };
struct epoll_event events[EPOLL_MAX]; struct epoll_event events[EPOLL_MAX] = {{0}};
thread_ = [this, &events] { thread_ = [this, &events] {
int ec = epoll_wait(efd_, events, EPOLL_MAX, -1); int ec = epoll_wait(efd_, events, EPOLL_MAX, -1);
if (ec > 0) { if (ec > 0) {

View File

@ -16,7 +16,19 @@ Host::Host(const std::size_t id, const Json::Value& config,
on_add_(on_add), on_add_(on_add),
on_remove_(on_remove) {} on_remove_(on_remove) {}
Host::~Host() { Gio::DBus::unwatch_name(bus_name_id_); } Host::~Host() {
if (bus_name_id_ > 0) {
Gio::DBus::unwatch_name(bus_name_id_);
bus_name_id_ = 0;
}
if (watcher_id_ > 0) {
Gio::DBus::unwatch_name(watcher_id_);
watcher_id_ = 0;
}
g_cancellable_cancel(cancellable_);
g_clear_object(&cancellable_);
g_clear_object(&watcher_);
}
void Host::busAcquired(const Glib::RefPtr<Gio::DBus::Connection>& conn, Glib::ustring name) { void Host::busAcquired(const Glib::RefPtr<Gio::DBus::Connection>& conn, Glib::ustring name) {
watcher_id_ = Gio::DBus::watch_name(conn, "org.kde.StatusNotifierWatcher", watcher_id_ = Gio::DBus::watch_name(conn, "org.kde.StatusNotifierWatcher",

View File

@ -8,7 +8,6 @@ waybar::modules::SNI::Tray::Tray(const std::string& id, const Bar& bar, const Js
watcher_(), watcher_(),
host_(nb_hosts_, config, std::bind(&Tray::onAdd, this, std::placeholders::_1), host_(nb_hosts_, config, std::bind(&Tray::onAdd, this, std::placeholders::_1),
std::bind(&Tray::onRemove, this, std::placeholders::_1)) { std::bind(&Tray::onRemove, this, std::placeholders::_1)) {
std::cout << "Tray is in beta, so there may be bugs or even be unusable." << std::endl;
if (config_["spacing"].isUInt()) { if (config_["spacing"].isUInt()) {
box_.set_spacing(config_["spacing"].asUInt()); box_.set_spacing(config_["spacing"].asUInt());
} }

View File

@ -1,11 +1,11 @@
#include "modules/sway/workspaces.hpp" #include "modules/sway/workspaces.hpp"
waybar::modules::sway::Workspaces::Workspaces(const std::string& id, const Bar& bar, waybar::modules::sway::Workspaces::Workspaces(const std::string &id, const Bar &bar,
const Json::Value& config) const Json::Value &config)
: bar_(bar), config_(config), : bar_(bar),
box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0), config_(config),
scrolling_(false) box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0),
{ scrolling_(false) {
box_.set_name("workspaces"); box_.set_name("workspaces");
if (!id.empty()) { if (!id.empty()) {
box_.get_style_context()->add_class(id); box_.get_style_context()->add_class(id);
@ -15,8 +15,7 @@ waybar::modules::sway::Workspaces::Workspaces(const std::string& id, const Bar&
worker(); worker();
} }
void waybar::modules::sway::Workspaces::worker() void waybar::modules::sway::Workspaces::worker() {
{
thread_ = [this] { thread_ = [this] {
try { try {
if (!workspaces_.empty()) { if (!workspaces_.empty()) {
@ -24,36 +23,35 @@ void waybar::modules::sway::Workspaces::worker()
} }
{ {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
auto res = ipc_.sendCmd(IPC_GET_WORKSPACES); auto res = ipc_.sendCmd(IPC_GET_WORKSPACES);
if (thread_.isRunning()) { if (thread_.isRunning()) {
workspaces_ = parser_.parse(res.payload); workspaces_ = parser_.parse(res.payload);
} }
} }
dp.emit(); dp.emit();
} catch (const std::exception& e) { } catch (const std::exception &e) {
std::cerr << "Workspaces: " << e.what() << std::endl; std::cerr << "Workspaces: " << e.what() << std::endl;
} }
}; };
} }
auto waybar::modules::sway::Workspaces::update() -> void auto waybar::modules::sway::Workspaces::update() -> void {
{ bool needReorder = false;
bool needReorder = false;
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
for (auto it = buttons_.begin(); it != buttons_.end();) { 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 {
[it](auto node) -> bool { return node["name"].asString() == it->first; }); return node["name"].asString() == it->first;
});
if (ws == workspaces_.end() || if (ws == workspaces_.end() ||
(!config_["all-outputs"].asBool() && (*ws)["output"].asString() != bar_.output_name)) { (!config_["all-outputs"].asBool() && (*ws)["output"].asString() != bar_.output->name)) {
it = buttons_.erase(it); it = buttons_.erase(it);
needReorder = true; needReorder = true;
} else { } else {
++it; ++it;
} }
} }
for (auto const& node : workspaces_) { for (auto const &node : workspaces_) {
if (!config_["all-outputs"].asBool() if (!config_["all-outputs"].asBool() && bar_.output->name != node["output"].asString()) {
&& bar_.output_name != node["output"].asString()) {
continue; continue;
} }
auto it = buttons_.find(node["name"].asString()); auto it = buttons_.find(node["name"].asString());
@ -80,16 +78,17 @@ auto waybar::modules::sway::Workspaces::update() -> void
if (needReorder) { if (needReorder) {
box_.reorder_child(button, getWorkspaceIndex(node["name"].asString())); box_.reorder_child(button, getWorkspaceIndex(node["name"].asString()));
} }
auto icon = getIcon(node["name"].asString(), node); auto icon = getIcon(node["name"].asString(), node);
std::string output = icon; std::string output = icon;
if (config_["format"].isString()) { if (config_["format"].isString()) {
auto format = config_["format"].asString(); auto format = config_["format"].asString();
output = fmt::format(format, fmt::arg("icon", icon), output = fmt::format(format,
fmt::arg("name", trimWorkspaceName(node["name"].asString())), fmt::arg("icon", icon),
fmt::arg("index", node["num"].asString())); fmt::arg("name", trimWorkspaceName(node["name"].asString())),
fmt::arg("index", node["num"].asString()));
} }
if (!config_["disable-markup"].asBool()) { if (!config_["disable-markup"].asBool()) {
static_cast<Gtk::Label*>(button.get_children()[0])->set_markup(output); static_cast<Gtk::Label *>(button.get_children()[0])->set_markup(output);
} else { } else {
button.set_label(output); button.set_label(output);
} }
@ -101,34 +100,33 @@ auto waybar::modules::sway::Workspaces::update() -> void
} }
} }
void waybar::modules::sway::Workspaces::addWorkspace(const Json::Value &node) void waybar::modules::sway::Workspaces::addWorkspace(const Json::Value &node) {
{ auto icon = getIcon(node["name"].asString(), node);
auto icon = getIcon(node["name"].asString(), node);
auto format = config_["format"].isString() auto format = config_["format"].isString()
? fmt::format(config_["format"].asString(), fmt::arg("icon", icon), ? fmt::format(config_["format"].asString(),
fmt::arg("name", trimWorkspaceName(node["name"].asString())), fmt::arg("icon", icon),
fmt::arg("index", node["num"].asString())) fmt::arg("name", trimWorkspaceName(node["name"].asString())),
: icon; fmt::arg("index", node["num"].asString()))
auto pair = buttons_.emplace(node["name"].asString(), format); : icon;
auto pair = buttons_.emplace(node["name"].asString(), format);
auto &button = pair.first->second; auto &button = pair.first->second;
if (!config_["disable-markup"].asBool()) { if (!config_["disable-markup"].asBool()) {
static_cast<Gtk::Label*>(button.get_children()[0])->set_markup(format); static_cast<Gtk::Label *>(button.get_children()[0])->set_markup(format);
} }
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_); std::lock_guard<std::mutex> lock(mutex_);
auto cmd = fmt::format("workspace \"{}\"", pair.first->first); auto cmd = fmt::format("workspace \"{}\"", pair.first->first);
ipc_.sendCmd(IPC_COMMAND, cmd); ipc_.sendCmd(IPC_COMMAND, cmd);
} catch (const std::exception& e) { } catch (const std::exception &e) {
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;
} }
}); });
if (!config_["disable-scroll"].asBool()) { if (!config_["disable-scroll"].asBool()) {
button.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK); button.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
button.signal_scroll_event() button.signal_scroll_event().connect(sigc::mem_fun(*this, &Workspaces::handleScroll));
.connect(sigc::mem_fun(*this, &Workspaces::handleScroll));
} }
box_.reorder_child(button, getWorkspaceIndex(node["name"].asString())); box_.reorder_child(button, getWorkspaceIndex(node["name"].asString()));
if (node["focused"].asBool()) { if (node["focused"].asBool()) {
@ -141,14 +139,13 @@ void waybar::modules::sway::Workspaces::addWorkspace(const Json::Value &node)
button.get_style_context()->add_class("urgent"); button.get_style_context()->add_class("urgent");
} }
onButtonReady(node, button); onButtonReady(node, button);
} }
std::string waybar::modules::sway::Workspaces::getIcon(const std::string &name, std::string waybar::modules::sway::Workspaces::getIcon(const std::string &name,
const Json::Value &node) const Json::Value &node) {
{ std::vector<std::string> keys = {name, "urgent", "focused", "visible", "default"};
std::vector<std::string> keys = { name, "urgent", "focused", "visible", "default" }; for (auto const &key : keys) {
for (auto const& key : keys) {
if (key == "focused" || key == "visible" || key == "urgent") { if (key == "focused" || key == "visible" || key == "urgent") {
if (config_["format-icons"][key].isString() && node[key].asBool()) { if (config_["format-icons"][key].isString() && node[key].asBool()) {
return config_["format-icons"][key].asString(); return config_["format-icons"][key].asString();
@ -160,14 +157,13 @@ std::string waybar::modules::sway::Workspaces::getIcon(const std::string &name,
return name; return name;
} }
bool waybar::modules::sway::Workspaces::handleScroll(GdkEventScroll *e) bool waybar::modules::sway::Workspaces::handleScroll(GdkEventScroll *e) {
{
// Avoid concurrent scroll event // Avoid concurrent scroll event
if (scrolling_) { if (scrolling_) {
return false; return false;
} }
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
uint8_t idx; uint8_t idx;
scrolling_ = true; scrolling_ = true;
for (idx = 0; idx < workspaces_.size(); idx += 1) { for (idx = 0; idx < workspaces_.size(); idx += 1) {
if (workspaces_[idx]["focused"].asBool()) { if (workspaces_[idx]["focused"].asBool()) {
@ -180,15 +176,14 @@ bool waybar::modules::sway::Workspaces::handleScroll(GdkEventScroll *e)
} }
std::string name; std::string name;
if (e->direction == GDK_SCROLL_UP) { if (e->direction == GDK_SCROLL_UP) {
name = getCycleWorkspace(idx, true); name = getCycleWorkspace(idx, true);
} }
if (e->direction == GDK_SCROLL_DOWN) { if (e->direction == GDK_SCROLL_DOWN) {
name = getCycleWorkspace(idx, false); name = getCycleWorkspace(idx, false);
} }
if (e->direction == GDK_SCROLL_SMOOTH) { if (e->direction == GDK_SCROLL_SMOOTH) {
gdouble delta_x, delta_y; gdouble delta_x, delta_y;
gdk_event_get_scroll_deltas(reinterpret_cast<const GdkEvent *>(e), gdk_event_get_scroll_deltas(reinterpret_cast<const GdkEvent *>(e), &delta_x, &delta_y);
&delta_x, &delta_y);
if (delta_y < 0) { if (delta_y < 0) {
name = getCycleWorkspace(idx, true); name = getCycleWorkspace(idx, true);
} else if (delta_y > 0) { } else if (delta_y > 0) {
@ -204,17 +199,17 @@ bool waybar::modules::sway::Workspaces::handleScroll(GdkEventScroll *e)
return true; return true;
} }
const std::string waybar::modules::sway::Workspaces::getCycleWorkspace( const std::string waybar::modules::sway::Workspaces::getCycleWorkspace(uint8_t focused_workspace,
uint8_t focused_workspace, bool prev) const bool prev) const {
{ auto inc = prev ? -1 : 1;
auto inc = prev ? -1 : 1; int size = workspaces_.size();
int size = workspaces_.size(); uint8_t idx = 0;
uint8_t idx = 0;
for (int i = focused_workspace; i < size && i >= 0; i += inc) { for (int i = focused_workspace; i < size && i >= 0; i += inc) {
bool same_output = (workspaces_[i]["output"].asString() == bar_.output_name bool same_output = (workspaces_[i]["output"].asString() == bar_.output->name &&
&& !config_["all-outputs"].asBool()) || config_["all-outputs"].asBool(); !config_["all-outputs"].asBool()) ||
config_["all-outputs"].asBool();
bool same_name = bool same_name =
workspaces_[i]["name"].asString() == workspaces_[focused_workspace]["name"].asString(); workspaces_[i]["name"].asString() == workspaces_[focused_workspace]["name"].asString();
if (same_output && !same_name) { if (same_output && !same_name) {
return workspaces_[i]["name"].asString(); return workspaces_[i]["name"].asString();
} }
@ -230,42 +225,39 @@ const std::string waybar::modules::sway::Workspaces::getCycleWorkspace(
return ""; return "";
} }
uint16_t waybar::modules::sway::Workspaces::getWorkspaceIndex(const std::string &name) const uint16_t waybar::modules::sway::Workspaces::getWorkspaceIndex(const std::string &name) const {
{
uint16_t idx = 0; uint16_t idx = 0;
for (const auto &workspace : workspaces_) { for (const auto &workspace : workspaces_) {
if (workspace["name"].asString() == name) { if (workspace["name"].asString() == name) {
return idx; return idx;
} }
if (!(!config_["all-outputs"].asBool() && workspace["output"].asString() != bar_.output_name)) { if (!(!config_["all-outputs"].asBool() &&
workspace["output"].asString() != bar_.output->name)) {
idx += 1; idx += 1;
} }
} }
return workspaces_.size(); return workspaces_.size();
} }
std::string waybar::modules::sway::Workspaces::trimWorkspaceName(std::string name) std::string waybar::modules::sway::Workspaces::trimWorkspaceName(std::string name) {
{
std::size_t found = name.find(":"); std::size_t found = name.find(":");
if (found!=std::string::npos) { if (found != std::string::npos) {
return name.substr(found+1); return name.substr(found + 1);
} }
return name; return name;
} }
void waybar::modules::sway::Workspaces::onButtonReady(const Json::Value& node, Gtk::Button& button) void waybar::modules::sway::Workspaces::onButtonReady(const Json::Value &node,
{ Gtk::Button & button) {
if (config_["current-only"].asBool()) { if (config_["current-only"].asBool()) {
if (node["focused"].asBool()) { if (node["focused"].asBool()) {
button.show(); button.show();
} else { } else {
button.hide(); button.hide();
} }
} else { } else {
button.show(); button.show();
} }
} }
waybar::modules::sway::Workspaces::operator Gtk::Widget &() { waybar::modules::sway::Workspaces::operator Gtk::Widget &() { return box_; }
return box_;
}