Fix merge conflict with #2930

This commit is contained in:
alttabber
2024-02-25 22:27:10 +01:00
69 changed files with 1331 additions and 1401 deletions

View File

@@ -53,8 +53,8 @@ waybar::modules::Cava::Cava(const std::string& id, const Json::Value& config)
if (config_["method"].isString())
prm_.input = cava::input_method_by_name(config_["method"].asString().c_str());
if (config_["source"].isString()) prm_.audio_source = config_["source"].asString().data();
if (config_["sample_rate"].isNumeric()) prm_.fifoSample = config_["sample_rate"].asLargestInt();
if (config_["sample_bits"].isInt()) prm_.fifoSampleBits = config_["sample_bits"].asInt();
if (config_["sample_rate"].isNumeric()) prm_.samplerate = config_["sample_rate"].asLargestInt();
if (config_["sample_bits"].isInt()) prm_.samplebits = config_["sample_bits"].asInt();
if (config_["stereo"].isBool()) prm_.stereo = config_["stereo"].asBool();
if (config_["reverse"].isBool()) prm_.reverse = config_["reverse"].asBool();
if (config_["bar_delimiter"].isInt()) prm_.bar_delim = config_["bar_delimiter"].asInt();

View File

@@ -2,8 +2,10 @@
#include <spdlog/spdlog.h>
#include <chrono>
#include <iomanip>
#include <regex>
#include <sstream>
#include "util/ustring_clen.hpp"
@@ -20,7 +22,8 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
tlpFmt_{(config_["tooltip-format"].isString()) ? config_["tooltip-format"].asString() : ""},
cldInTooltip_{tlpFmt_.find("{" + kCldPlaceholder + "}") != std::string::npos},
tzInTooltip_{tlpFmt_.find("{" + kTZPlaceholder + "}") != std::string::npos},
tzCurrIdx_{0} {
tzCurrIdx_{0},
ordInTooltip_{tlpFmt_.find("{" + kOrdPlaceholder + "}") != std::string::npos} {
tlpText_ = tlpFmt_;
if (config_["timezones"].isArray() && !config_["timezones"].empty()) {
@@ -127,7 +130,7 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
}
auto waybar::modules::Clock::update() -> void {
auto tz{tzList_[tzCurrIdx_] ?: current_zone()};
const auto* tz = tzList_[tzCurrIdx_] != nullptr ? tzList_[tzCurrIdx_] : current_zone();
const zoned_time now{tz, floor<seconds>(system_clock::now())};
label_.set_markup(fmt_lib::vformat(locale_, format_, fmt_lib::make_format_args(now)));
@@ -140,11 +143,14 @@ auto waybar::modules::Clock::update() -> void {
if (tzInTooltip_) tzText_ = getTZtext(now.get_sys_time());
if (cldInTooltip_) cldText_ = get_calendar(today, shiftedDay, tz);
if (tzInTooltip_ || cldInTooltip_) {
if (ordInTooltip_) ordText_ = get_ordinal_date(shiftedDay);
if (tzInTooltip_ || cldInTooltip_ || ordInTooltip_) {
// std::vformat doesn't support named arguments.
tlpText_ = std::regex_replace(tlpFmt_, std::regex("\\{" + kTZPlaceholder + "\\}"), tzText_);
tlpText_ =
std::regex_replace(tlpText_, std::regex("\\{" + kCldPlaceholder + "\\}"), cldText_);
tlpText_ =
std::regex_replace(tlpText_, std::regex("\\{" + kOrdPlaceholder + "\\}"), ordText_);
}
tlpText_ = fmt_lib::vformat(locale_, tlpText_, fmt_lib::make_format_args(shiftedNow));
@@ -161,7 +167,8 @@ auto waybar::modules::Clock::getTZtext(sys_seconds now) -> std::string {
std::stringstream os;
for (size_t tz_idx{0}; tz_idx < tzList_.size(); ++tz_idx) {
if (static_cast<int>(tz_idx) == tzCurrIdx_) continue;
auto zt{zoned_time{tzList_[tz_idx], now}};
const auto* tz = tzList_[tz_idx] != nullptr ? tzList_[tz_idx] : current_zone();
auto zt{zoned_time{tz, now}};
os << fmt_lib::vformat(locale_, format_, fmt_lib::make_format_args(zt)) << '\n';
}
@@ -214,22 +221,22 @@ auto getCalendarLine(const year_month_day& currDate, const year_month ym, const
}
// Print first week prefixed with spaces if necessary
case 2: {
auto d{day{1}};
auto wd{weekday{ym / 1}};
os << std::string((wd - firstdow).count() * 3, ' ');
if (currDate != ym / 1d)
os << date::format(*locale_, "{:L%e}", 1d);
if (currDate != ym / d)
os << date::format(*locale_, "{:L%e}", d);
else
os << "{today}";
auto d{2d};
while (++wd != firstdow) {
++d;
if (currDate != ym / d)
os << date::format(*locale_, " {:L%e}", d);
else
os << " {today}";
++d;
}
break;
}
@@ -437,3 +444,28 @@ auto waybar::modules::Clock::first_day_of_week() -> weekday {
#endif
return Sunday;
}
auto waybar::modules::Clock::get_ordinal_date(const year_month_day& today) -> std::string {
auto day = static_cast<unsigned int>(today.day());
std::stringstream res;
res << day;
if (day >= 11 && day <= 13) {
res << "th";
return res.str();
}
switch (day % 10) {
case 1:
res << "st";
break;
case 2:
res << "nd";
break;
case 3:
res << "rd";
break;
default:
res << "th";
}
return res.str();
}

View File

@@ -1,15 +1,27 @@
#include <spdlog/spdlog.h>
#include <cmath> // NAN
#include <sys/sysctl.h>
#include "modules/cpu_frequency.hpp"
std::vector<float> waybar::modules::CpuFrequency::parseCpuFrequencies() {
static std::vector<float> frequencies;
std::vector<float> frequencies;
char buffer[256];
size_t len;
int32_t freq;
uint32_t i = 0;
while (true) {
len = 4;
snprintf(buffer, 256, "dev.cpu.%u.freq", i);
if (sysctlbyname(buffer, &freq, &len, NULL, 0) == -1 || len <= 0) break;
frequencies.push_back(freq);
++i;
}
if (frequencies.empty()) {
spdlog::warn(
"cpu/bsd: parseCpuFrequencies is not implemented, expect garbage in {*_frequency}");
spdlog::warn("cpu/bsd: parseCpuFrequencies failed, not found in sysctl");
frequencies.push_back(NAN);
}
return frequencies;
}

View File

@@ -170,22 +170,30 @@ auto waybar::modules::Custom::update() -> void {
if (label_.get_tooltip_markup() != str) {
label_.set_tooltip_markup(str);
}
} else if (config_["tooltip-format"].isString()) {
auto tooltip = config_["tooltip-format"].asString();
tooltip = fmt::format(fmt::runtime(tooltip), text_, fmt::arg("alt", alt_),
fmt::arg("icon", getIcon(percentage_, alt_)),
fmt::arg("percentage", percentage_));
label_.set_tooltip_markup(tooltip);
} else {
if (label_.get_tooltip_markup() != tooltip_) {
label_.set_tooltip_markup(tooltip_);
}
}
}
auto classes = label_.get_style_context()->list_classes();
auto style = label_.get_style_context();
auto classes = style->list_classes();
for (auto const& c : classes) {
if (c == id_) continue;
label_.get_style_context()->remove_class(c);
style->remove_class(c);
}
for (auto const& c : class_) {
label_.get_style_context()->add_class(c);
style->add_class(c);
}
label_.get_style_context()->add_class("flat");
label_.get_style_context()->add_class("text-button");
style->add_class("flat");
style->add_class("text-button");
style->add_class(MODULE_CLASS);
event_box_.show();
}
}

View File

@@ -93,7 +93,7 @@ Tags::Tags(const std::string &id, const waybar::Bar &bar, const Json::Value &con
status_manager_{nullptr},
seat_{nullptr},
bar_(bar),
box_{bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0},
box_{bar.orientation, 0},
output_status_{nullptr} {
struct wl_display *display = Client::inst()->wl_display;
struct wl_registry *registry = wl_display_get_registry(display);
@@ -113,6 +113,7 @@ Tags::Tags(const std::string &id, const waybar::Bar &bar, const Json::Value &con
if (!id.empty()) {
box_.get_style_context()->add_class(id);
}
box_.get_style_context()->add_class(MODULE_CLASS);
event_box_.add(box_);
// Default to 9 tags, cap at 32

View File

@@ -54,22 +54,22 @@ void IPC::startIPC() {
return;
}
auto file = fdopen(socketfd, "r");
auto* file = fdopen(socketfd, "r");
while (true) {
char buffer[1024]; // Hyprland socket2 events are max 1024 bytes
std::array<char, 1024> buffer; // Hyprland socket2 events are max 1024 bytes
auto recievedCharPtr = fgets(buffer, 1024, file);
auto* receivedCharPtr = fgets(buffer.data(), buffer.size(), file);
if (!recievedCharPtr) {
if (receivedCharPtr == nullptr) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
continue;
}
std::string messageRecieved(buffer);
messageRecieved = messageRecieved.substr(0, messageRecieved.find_first_of('\n'));
spdlog::debug("hyprland IPC received {}", messageRecieved);
parseIPC(messageRecieved);
std::string messageReceived(buffer.data());
messageReceived = messageReceived.substr(0, messageReceived.find_first_of('\n'));
spdlog::debug("hyprland IPC received {}", messageReceived);
parseIPC(messageReceived);
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
@@ -78,9 +78,9 @@ void IPC::startIPC() {
void IPC::parseIPC(const std::string& ev) {
std::string request = ev.substr(0, ev.find_first_of('>'));
std::unique_lock lock(m_callbackMutex);
std::unique_lock lock(callbackMutex_);
for (auto& [eventname, handler] : m_callbacks) {
for (auto& [eventname, handler] : callbacks_) {
if (eventname == request) {
handler->onEvent(ev);
}
@@ -88,25 +88,25 @@ void IPC::parseIPC(const std::string& ev) {
}
void IPC::registerForIPC(const std::string& ev, EventHandler* ev_handler) {
if (!ev_handler) {
if (ev_handler == nullptr) {
return;
}
std::unique_lock lock(m_callbackMutex);
m_callbacks.emplace_back(ev, ev_handler);
std::unique_lock lock(callbackMutex_);
callbacks_.emplace_back(ev, ev_handler);
}
void IPC::unregisterForIPC(EventHandler* ev_handler) {
if (!ev_handler) {
if (ev_handler == nullptr) {
return;
}
std::unique_lock lock(m_callbackMutex);
std::unique_lock lock(callbackMutex_);
for (auto it = m_callbacks.begin(); it != m_callbacks.end();) {
for (auto it = callbacks_.begin(); it != callbacks_.end();) {
auto& [eventname, handler] = *it;
if (handler == ev_handler) {
m_callbacks.erase(it++);
callbacks_.erase(it++);
} else {
++it;
}
@@ -135,9 +135,9 @@ std::string IPC::getSocket1Reply(const std::string& rq) {
}
// get the instance signature
auto instanceSig = getenv("HYPRLAND_INSTANCE_SIGNATURE");
auto* instanceSig = getenv("HYPRLAND_INSTANCE_SIGNATURE");
if (!instanceSig) {
if (instanceSig == nullptr) {
spdlog::error("Hyprland IPC: HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)");
return "";
}
@@ -169,18 +169,18 @@ std::string IPC::getSocket1Reply(const std::string& rq) {
return "";
}
char buffer[8192] = {0};
std::array<char, 8192> buffer = {0};
std::string response;
do {
sizeWritten = read(serverSocket, buffer, 8192);
sizeWritten = read(serverSocket, buffer.data(), 8192);
if (sizeWritten < 0) {
spdlog::error("Hyprland IPC: Couldn't read (5)");
close(serverSocket);
return "";
}
response.append(buffer, sizeWritten);
response.append(buffer.data(), sizeWritten);
} while (sizeWritten > 0);
close(serverSocket);
@@ -188,7 +188,7 @@ std::string IPC::getSocket1Reply(const std::string& rq) {
}
Json::Value IPC::getSocket1JsonReply(const std::string& rq) {
return m_parser.parse(getSocket1Reply("j/" + rq));
return parser_.parse(getSocket1Reply("j/" + rq));
}
} // namespace waybar::modules::hyprland

View File

@@ -13,7 +13,7 @@ Language::Language(const std::string& id, const Bar& bar, const Json::Value& con
: ALabel(config, "language", id, "{}", 0, true), bar_(bar) {
modulesReady = true;
if (!gIPC.get()) {
if (!gIPC) {
gIPC = std::make_unique<IPC>();
}
@@ -102,11 +102,11 @@ void Language::initLanguage() {
}
auto Language::getLayout(const std::string& fullName) -> Layout {
const auto CONTEXT = rxkb_context_new(RXKB_CONTEXT_LOAD_EXOTIC_RULES);
rxkb_context_parse_default_ruleset(CONTEXT);
auto* const context = rxkb_context_new(RXKB_CONTEXT_LOAD_EXOTIC_RULES);
rxkb_context_parse_default_ruleset(context);
rxkb_layout* layout = rxkb_layout_first(CONTEXT);
while (layout) {
rxkb_layout* layout = rxkb_layout_first(context);
while (layout != nullptr) {
std::string nameOfLayout = rxkb_layout_get_description(layout);
if (nameOfLayout != fullName) {
@@ -115,21 +115,20 @@ auto Language::getLayout(const std::string& fullName) -> Layout {
}
auto name = std::string(rxkb_layout_get_name(layout));
auto variant_ = rxkb_layout_get_variant(layout);
std::string variant = variant_ == nullptr ? "" : std::string(variant_);
const auto* variantPtr = rxkb_layout_get_variant(layout);
std::string variant = variantPtr == nullptr ? "" : std::string(variantPtr);
auto short_description_ = rxkb_layout_get_brief(layout);
std::string short_description =
short_description_ == nullptr ? "" : std::string(short_description_);
const auto* descriptionPtr = rxkb_layout_get_brief(layout);
std::string description = descriptionPtr == nullptr ? "" : std::string(descriptionPtr);
Layout info = Layout{nameOfLayout, name, variant, short_description};
Layout info = Layout{nameOfLayout, name, variant, description};
rxkb_context_unref(CONTEXT);
rxkb_context_unref(context);
return info;
}
rxkb_context_unref(CONTEXT);
rxkb_context_unref(context);
spdlog::debug("hyprland language didn't find matching layout");

View File

@@ -12,7 +12,7 @@ Submap::Submap(const std::string& id, const Bar& bar, const Json::Value& config)
parseConfig(config);
if (!gIPC.get()) {
if (!gIPC) {
gIPC = std::make_unique<IPC>();
}

View File

@@ -17,9 +17,9 @@ namespace waybar::modules::hyprland {
Window::Window(const std::string& id, const Bar& bar, const Json::Value& config)
: AAppIconLabel(config, "window", id, "{title}", 0, true), bar_(bar) {
modulesReady = true;
separate_outputs = config["separate-outputs"].asBool();
separateOutputs_ = config["separate-outputs"].asBool();
if (!gIPC.get()) {
if (!gIPC) {
gIPC = std::make_unique<IPC>();
}
@@ -45,18 +45,18 @@ auto Window::update() -> void {
// fix ampersands
std::lock_guard<std::mutex> lg(mutex_);
std::string window_name = waybar::util::sanitize_string(workspace_.last_window_title);
std::string window_address = workspace_.last_window;
std::string windowName = waybar::util::sanitize_string(workspace_.last_window_title);
std::string windowAddress = workspace_.last_window;
window_data_.title = window_name;
windowData_.title = windowName;
if (!format_.empty()) {
label_.show();
label_.set_markup(waybar::util::rewriteString(
fmt::format(fmt::runtime(format_), fmt::arg("title", window_name),
fmt::arg("initialTitle", window_data_.initial_title),
fmt::arg("class", window_data_.class_name),
fmt::arg("initialClass", window_data_.initial_class_name)),
fmt::format(fmt::runtime(format_), fmt::arg("title", windowName),
fmt::arg("initialTitle", windowData_.initial_title),
fmt::arg("class", windowData_.class_name),
fmt::arg("initialClass", windowData_.initial_class_name)),
config_["rewrite"]));
} else {
label_.hide();
@@ -64,22 +64,22 @@ auto Window::update() -> void {
setClass("empty", workspace_.windows == 0);
setClass("solo", solo_);
setClass("floating", all_floating_);
setClass("floating", allFloating_);
setClass("swallowing", swallowing_);
setClass("fullscreen", fullscreen_);
if (!last_solo_class_.empty() && solo_class_ != last_solo_class_) {
if (bar_.window.get_style_context()->has_class(last_solo_class_)) {
bar_.window.get_style_context()->remove_class(last_solo_class_);
spdlog::trace("Removing solo class: {}", last_solo_class_);
if (!lastSoloClass_.empty() && soloClass_ != lastSoloClass_) {
if (bar_.window.get_style_context()->has_class(lastSoloClass_)) {
bar_.window.get_style_context()->remove_class(lastSoloClass_);
spdlog::trace("Removing solo class: {}", lastSoloClass_);
}
}
if (!solo_class_.empty() && solo_class_ != last_solo_class_) {
bar_.window.get_style_context()->add_class(solo_class_);
spdlog::trace("Adding solo class: {}", solo_class_);
if (!soloClass_.empty() && soloClass_ != lastSoloClass_) {
bar_.window.get_style_context()->add_class(soloClass_);
spdlog::trace("Adding solo class: {}", soloClass_);
}
last_solo_class_ = solo_class_;
lastSoloClass_ = soloClass_;
AAppIconLabel::update();
}
@@ -113,8 +113,12 @@ auto Window::getActiveWorkspace(const std::string& monitorName) -> Workspace {
}
auto Window::Workspace::parse(const Json::Value& value) -> Window::Workspace {
return Workspace{value["id"].asInt(), value["windows"].asInt(), value["lastwindow"].asString(),
value["lastwindowtitle"].asString()};
return Workspace{
value["id"].asInt(),
value["windows"].asInt(),
value["lastwindow"].asString(),
value["lastwindowtitle"].asString(),
};
}
auto Window::WindowData::parse(const Json::Value& value) -> Window::WindowData {
@@ -127,7 +131,7 @@ auto Window::WindowData::parse(const Json::Value& value) -> Window::WindowData {
void Window::queryActiveWorkspace() {
std::lock_guard<std::mutex> lg(mutex_);
if (separate_outputs) {
if (separateOutputs_) {
workspace_ = getActiveWorkspace(this->bar_.output->name);
} else {
workspace_ = getActiveWorkspace();
@@ -136,31 +140,33 @@ void Window::queryActiveWorkspace() {
if (workspace_.windows > 0) {
const auto clients = gIPC->getSocket1JsonReply("clients");
assert(clients.isArray());
auto active_window = std::find_if(clients.begin(), clients.end(), [&](Json::Value window) {
auto activeWindow = std::find_if(clients.begin(), clients.end(), [&](Json::Value window) {
return window["address"] == workspace_.last_window;
});
if (active_window == std::end(clients)) {
if (activeWindow == std::end(clients)) {
return;
}
window_data_ = WindowData::parse(*active_window);
updateAppIconName(window_data_.class_name, window_data_.initial_class_name);
std::vector<Json::Value> workspace_windows;
std::copy_if(clients.begin(), clients.end(), std::back_inserter(workspace_windows),
windowData_ = WindowData::parse(*activeWindow);
updateAppIconName(windowData_.class_name, windowData_.initial_class_name);
std::vector<Json::Value> workspaceWindows;
std::copy_if(clients.begin(), clients.end(), std::back_inserter(workspaceWindows),
[&](Json::Value window) {
return window["workspace"]["id"] == workspace_.id && window["mapped"].asBool();
});
swallowing_ = std::any_of(workspace_windows.begin(), workspace_windows.end(),
[&](Json::Value window) { return !window["swallowing"].isNull(); });
std::vector<Json::Value> visible_windows;
std::copy_if(workspace_windows.begin(), workspace_windows.end(),
std::back_inserter(visible_windows),
swallowing_ =
std::any_of(workspaceWindows.begin(), workspaceWindows.end(), [&](Json::Value window) {
return !window["swallowing"].isNull() && window["swallowing"].asString() != "0x0";
});
std::vector<Json::Value> visibleWindows;
std::copy_if(workspaceWindows.begin(), workspaceWindows.end(),
std::back_inserter(visibleWindows),
[&](Json::Value window) { return !window["hidden"].asBool(); });
solo_ = 1 == std::count_if(visible_windows.begin(), visible_windows.end(),
solo_ = 1 == std::count_if(visibleWindows.begin(), visibleWindows.end(),
[&](Json::Value window) { return !window["floating"].asBool(); });
all_floating_ = std::all_of(visible_windows.begin(), visible_windows.end(),
[&](Json::Value window) { return window["floating"].asBool(); });
fullscreen_ = window_data_.fullscreen;
allFloating_ = std::all_of(visibleWindows.begin(), visibleWindows.end(),
[&](Json::Value window) { return window["floating"].asBool(); });
fullscreen_ = windowData_.fullscreen;
// Fullscreen windows look like they are solo
if (fullscreen_) {
@@ -168,23 +174,23 @@ void Window::queryActiveWorkspace() {
}
// Grouped windows have a tab bar and therefore don't look fullscreen or solo
if (window_data_.grouped) {
if (windowData_.grouped) {
fullscreen_ = false;
solo_ = false;
}
if (solo_) {
solo_class_ = window_data_.class_name;
soloClass_ = windowData_.class_name;
} else {
solo_class_ = "";
soloClass_ = "";
}
} else {
window_data_ = WindowData{};
all_floating_ = false;
windowData_ = WindowData{};
allFloating_ = false;
swallowing_ = false;
fullscreen_ = false;
solo_ = false;
solo_class_ = "";
soloClass_ = "";
}
}

View File

@@ -34,9 +34,7 @@ int Workspaces::windowRewritePriorityFunction(std::string const &window_rule) {
}
Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value &config)
: AModule(config, "workspaces", id, false, false),
m_bar(bar),
m_box(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0) {
: AModule(config, "workspaces", id, false, false), m_bar(bar), m_box(bar.orientation, 0) {
modulesReady = true;
parseConfig(config);
@@ -44,12 +42,14 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value
if (!id.empty()) {
m_box.get_style_context()->add_class(id);
}
m_box.get_style_context()->add_class(MODULE_CLASS);
event_box_.add(m_box);
if (!gIPC) {
gIPC = std::make_unique<IPC>();
}
setCurrentMonitorId();
init();
registerIpc();
}
@@ -65,7 +65,6 @@ auto Workspaces::parseConfig(const Json::Value &config) -> void {
for (std::string &name : formatIcons.getMemberNames()) {
m_iconsMap.emplace(name, formatIcons[name].asString());
}
m_iconsMap.emplace("", "");
}
@@ -113,11 +112,26 @@ auto Workspaces::parseConfig(const Json::Value &config) -> void {
}
}
if (config_["persistent_workspaces"].isObject()) {
spdlog::warn(
"persistent_workspaces is deprecated. Please change config to use persistent-workspaces.");
}
if (config_["persistent-workspaces"].isObject() || config_["persistent_workspaces"].isObject()) {
m_persistentWorkspaceConfig = config_["persistent-workspaces"].isObject()
? config_["persistent-workspaces"]
: config_["persistent_workspaces"];
}
const Json::Value &formatWindowSeparator = config["format-window-separator"];
m_formatWindowSeparator =
formatWindowSeparator.isString() ? formatWindowSeparator.asString() : " ";
const Json::Value &windowRewrite = config["window-rewrite"];
if (!windowRewrite.isObject()) {
spdlog::debug("window-rewrite is not defined or is not an object, using default rules.");
return;
}
const Json::Value &windowRewriteDefaultConfig = config["window-rewrite-default"];
std::string windowRewriteDefault =
@@ -128,14 +142,15 @@ auto Workspaces::parseConfig(const Json::Value &config) -> void {
[this](std::string &window_rule) { return windowRewritePriorityFunction(window_rule); });
}
void Workspaces::registerOrphanWindow(WindowCreationPayload create_window_paylod) {
if (!create_window_paylod.isEmpty(*this)) {
m_orphanWindowMap[create_window_paylod.getAddress()] = create_window_paylod.repr(*this);
void Workspaces::registerOrphanWindow(WindowCreationPayload create_window_payload) {
if (!create_window_payload.isEmpty(*this)) {
m_orphanWindowMap[create_window_payload.getAddress()] = create_window_payload.repr(*this);
}
}
auto Workspaces::registerIpc() -> void {
gIPC->registerForIPC("workspace", this);
gIPC->registerForIPC("activespecial", this);
gIPC->registerForIPC("createworkspace", this);
gIPC->registerForIPC("destroyworkspace", this);
gIPC->registerForIPC("focusedmon", this);
@@ -145,6 +160,7 @@ auto Workspaces::registerIpc() -> void {
gIPC->registerForIPC("closewindow", this);
gIPC->registerForIPC("movewindow", this);
gIPC->registerForIPC("urgent", this);
gIPC->registerForIPC("configreloaded", this);
if (windowRewriteConfigUsesTitle()) {
spdlog::info(
@@ -176,6 +192,7 @@ void Workspaces::doUpdate() {
m_workspacesToCreate.clear();
// get all active workspaces
spdlog::trace("Getting active workspaces");
auto monitors = gIPC->getSocket1JsonReply("monitors");
std::vector<std::string> visibleWorkspaces;
for (Json::Value &monitor : monitors) {
@@ -183,11 +200,18 @@ void Workspaces::doUpdate() {
if (ws.isObject() && (ws["name"].isString())) {
visibleWorkspaces.push_back(ws["name"].asString());
}
auto sws = monitor["specialWorkspace"];
auto name = sws["name"].asString();
if (sws.isObject() && (sws["name"].isString()) && !name.empty()) {
visibleWorkspaces.push_back(!name.starts_with("special:") ? name : name.substr(8));
}
}
spdlog::trace("Updating workspace states");
for (auto &workspace : m_workspaces) {
// active
workspace->setActive(workspace->name() == m_activeWorkspaceName);
workspace->setActive(workspace->name() == m_activeWorkspaceName ||
workspace->name() == m_activeSpecialWorkspaceName);
// disable urgency if workspace is active
if (workspace->name() == m_activeWorkspaceName && workspace->isUrgent()) {
workspace->setUrgent(false);
@@ -205,6 +229,7 @@ void Workspaces::doUpdate() {
workspace->update(m_format, workspaceIcon);
}
spdlog::trace("Updating window count");
bool anyWindowCreated = false;
std::vector<WindowCreationPayload> notCreated;
@@ -266,6 +291,8 @@ void Workspaces::onEvent(const std::string &ev) {
if (eventName == "workspace") {
onWorkspaceActivated(payload);
} else if (eventName == "activespecial") {
onSpecialWorkspaceActivated(payload);
} else if (eventName == "destroyworkspace") {
onWorkspaceDestroyed(payload);
} else if (eventName == "createworkspace") {
@@ -286,6 +313,8 @@ void Workspaces::onEvent(const std::string &ev) {
onWorkspaceRenamed(payload);
} else if (eventName == "windowtitle") {
onWindowTitleEvent(payload);
} else if (eventName == "configreloaded") {
onConfigReloaded();
}
dp.emit();
@@ -295,6 +324,11 @@ void Workspaces::onWorkspaceActivated(std::string const &payload) {
m_activeWorkspaceName = payload;
}
void Workspaces::onSpecialWorkspaceActivated(std::string const &payload) {
std::string name(begin(payload), begin(payload) + payload.find_first_of(','));
m_activeSpecialWorkspaceName = (!name.starts_with("special:") ? name : name.substr(8));
}
void Workspaces::onWorkspaceDestroyed(std::string const &payload) {
if (!isDoubleSpecial(payload)) {
m_workspacesToRemove.push_back(payload);
@@ -303,22 +337,37 @@ void Workspaces::onWorkspaceDestroyed(std::string const &payload) {
void Workspaces::onWorkspaceCreated(std::string const &workspaceName,
Json::Value const &clientsData) {
const Json::Value workspacesJson = gIPC->getSocket1JsonReply("workspaces");
spdlog::debug("Workspace created: {}", workspaceName);
auto const workspacesJson = gIPC->getSocket1JsonReply("workspaces");
if (!isWorkspaceIgnored(workspaceName)) {
auto const workspaceRules = gIPC->getSocket1JsonReply("workspacerules");
for (Json::Value workspaceJson : workspacesJson) {
std::string name = workspaceJson["name"].asString();
if (name == workspaceName &&
(allOutputs() || m_bar.output->name == workspaceJson["monitor"].asString()) &&
(showSpecial() || !name.starts_with("special")) && !isDoubleSpecial(workspaceName)) {
m_workspacesToCreate.emplace_back(workspaceJson, clientsData);
break;
if (name == workspaceName) {
if ((allOutputs() || m_bar.output->name == workspaceJson["monitor"].asString()) &&
(showSpecial() || !name.starts_with("special")) && !isDoubleSpecial(workspaceName)) {
for (Json::Value const &rule : workspaceRules) {
if (rule["workspaceString"].asString() == workspaceName) {
workspaceJson["persistent"] = rule["persistent"].asBool();
break;
}
}
m_workspacesToCreate.emplace_back(workspaceJson, clientsData);
break;
}
} else {
extendOrphans(workspaceJson["id"].asInt(), clientsData);
}
}
} else {
spdlog::trace("Not creating workspace because it is ignored: {}", workspaceName);
}
}
void Workspaces::onWorkspaceMoved(std::string const &payload) {
spdlog::debug("Workspace moved: {}", payload);
std::string workspaceName = payload.substr(0, payload.find(','));
std::string monitorName = payload.substr(payload.find(',') + 1);
@@ -326,11 +375,13 @@ void Workspaces::onWorkspaceMoved(std::string const &payload) {
Json::Value clientsData = gIPC->getSocket1JsonReply("clients");
onWorkspaceCreated(workspaceName, clientsData);
} else {
spdlog::debug("Removing workspace because it was moved to another monitor: {}");
onWorkspaceDestroyed(workspaceName);
}
}
void Workspaces::onWorkspaceRenamed(std::string const &payload) {
spdlog::debug("Workspace renamed: {}", payload);
std::string workspaceIdStr = payload.substr(0, payload.find(','));
int workspaceId = workspaceIdStr == "special" ? -99 : std::stoi(workspaceIdStr);
std::string newName = payload.substr(payload.find(',') + 1);
@@ -347,10 +398,19 @@ void Workspaces::onWorkspaceRenamed(std::string const &payload) {
}
void Workspaces::onMonitorFocused(std::string const &payload) {
spdlog::trace("Monitor focused: {}", payload);
m_activeWorkspaceName = payload.substr(payload.find(',') + 1);
for (Json::Value &monitor : gIPC->getSocket1JsonReply("monitors")) {
if (monitor["name"].asString() == payload.substr(0, payload.find(','))) {
auto name = monitor["specialWorkspace"]["name"].asString();
m_activeSpecialWorkspaceName = !name.starts_with("special:") ? name : name.substr(8);
}
}
}
void Workspaces::onWindowOpened(std::string const &payload) {
spdlog::trace("Window opened: {}", payload);
updateWindowCount();
size_t lastCommaIdx = 0;
size_t nextCommaIdx = payload.find(',');
@@ -370,6 +430,7 @@ void Workspaces::onWindowOpened(std::string const &payload) {
}
void Workspaces::onWindowClosed(std::string const &addr) {
spdlog::trace("Window closed: {}", addr);
updateWindowCount();
for (auto &workspace : m_workspaces) {
if (workspace->closeWindow(addr)) {
@@ -379,6 +440,7 @@ void Workspaces::onWindowClosed(std::string const &addr) {
}
void Workspaces::onWindowMoved(std::string const &payload) {
spdlog::trace("Window moved: {}", payload);
updateWindowCount();
size_t lastCommaIdx = 0;
size_t nextCommaIdx = payload.find(',');
@@ -417,6 +479,7 @@ void Workspaces::onWindowMoved(std::string const &payload) {
}
void Workspaces::onWindowTitleEvent(std::string const &payload) {
spdlog::trace("Window title changed: {}", payload);
std::optional<std::function<void(WindowCreationPayload)>> inserter;
// If the window was an orphan, rename it at the orphan's vector
@@ -460,12 +523,19 @@ void Workspaces::onWindowTitleEvent(std::string const &payload) {
}
}
void Workspaces::onConfigReloaded() {
spdlog::info("Hyprland config reloaded, reinitializing hyprland/workspaces module...");
init();
}
void Workspaces::updateWindowCount() {
const Json::Value workspacesJson = gIPC->getSocket1JsonReply("workspaces");
for (auto &workspace : m_workspaces) {
auto workspaceJson = std::find_if(
workspacesJson.begin(), workspacesJson.end(),
[&](Json::Value const &x) { return x["name"].asString() == workspace->name(); });
auto workspaceJson =
std::find_if(workspacesJson.begin(), workspacesJson.end(), [&](Json::Value const &x) {
return x["name"].asString() == workspace->name() ||
(workspace->isSpecial() && x["name"].asString() == "special:" + workspace->name());
});
uint32_t count = 0;
if (workspaceJson != workspacesJson.end()) {
try {
@@ -516,8 +586,11 @@ std::optional<std::string> Workspace::closeWindow(WindowAddress const &addr) {
void Workspaces::createWorkspace(Json::Value const &workspace_data,
Json::Value const &clients_data) {
// avoid recreating existing workspaces
auto workspaceName = workspace_data["name"].asString();
spdlog::debug("Creating workspace {}, persistent: {}", workspaceName,
workspace_data["persistent"].asBool() ? "true" : "false");
// avoid recreating existing workspaces
auto workspace = std::find_if(
m_workspaces.begin(), m_workspaces.end(),
[workspaceName](std::unique_ptr<Workspace> const &w) {
@@ -526,9 +599,8 @@ void Workspaces::createWorkspace(Json::Value const &workspace_data,
});
if (workspace != m_workspaces.end()) {
if (workspace_data["persistent"].asBool() and !(*workspace)->isPersistent()) {
(*workspace)->setPersistent();
}
// don't recreate workspace, but update persistency if necessary
(*workspace)->setPersistent(workspace_data["persistent"].asBool());
return;
}
@@ -541,6 +613,7 @@ void Workspaces::createWorkspace(Json::Value const &workspace_data,
}
void Workspaces::removeWorkspace(std::string const &name) {
spdlog::debug("Removing workspace {}", name);
auto workspace =
std::find_if(m_workspaces.begin(), m_workspaces.end(), [&](std::unique_ptr<Workspace> &x) {
return (name.starts_with("special:") && name.substr(8) == x->name()) || name == x->name();
@@ -552,7 +625,7 @@ void Workspaces::removeWorkspace(std::string const &name) {
}
if ((*workspace)->isPersistent()) {
// don't remove persistent workspaces, createWorkspace will take care of replacement
spdlog::trace("Not removing persistent workspace {}", name);
return;
}
@@ -560,94 +633,106 @@ void Workspaces::removeWorkspace(std::string const &name) {
m_workspaces.erase(workspace);
}
void Workspaces::fillPersistentWorkspaces() {
if (config_["persistent_workspaces"].isObject()) {
spdlog::warn(
"persistent_workspaces is deprecated. Please change config to use persistent-workspaces.");
Json::Value createPersistentWorkspaceData(std::string const &name, std::string const &monitor) {
spdlog::trace("Creating persistent workspace: {} on monitor {}", name, monitor);
Json::Value workspaceData;
try {
// numbered persistent workspaces get the name as ID
workspaceData["id"] = name == "special" ? -99 : std::stoi(name);
} catch (const std::exception &e) {
// named persistent workspaces start with ID=0
workspaceData["id"] = 0;
}
workspaceData["name"] = name;
workspaceData["monitor"] = monitor;
workspaceData["windows"] = 0;
workspaceData["persistent"] = true;
return workspaceData;
}
if (config_["persistent-workspaces"].isObject() || config_["persistent_workspaces"].isObject()) {
const Json::Value persistentWorkspaces = config_["persistent-workspaces"].isObject()
? config_["persistent-workspaces"]
: config_["persistent_workspaces"];
const std::vector<std::string> keys = persistentWorkspaces.getMemberNames();
void Workspaces::loadPersistentWorkspacesFromConfig(Json::Value const &clientsJson) {
spdlog::info("Loading persistent workspaces from Waybar config");
const std::vector<std::string> keys = m_persistentWorkspaceConfig.getMemberNames();
std::vector<std::string> persistentWorkspacesToCreate;
for (const std::string &key : keys) {
// only add if either:
// 1. key is "*" and this monitor is not already defined in the config
// 2. key is the current monitor name
bool canCreate =
(key == "*" && std::find(keys.begin(), keys.end(), m_bar.output->name) == keys.end()) ||
key == m_bar.output->name;
const Json::Value &value = persistentWorkspaces[key];
const std::string currentMonitor = m_bar.output->name;
const bool monitorInConfig = std::find(keys.begin(), keys.end(), currentMonitor) != keys.end();
for (const std::string &key : keys) {
// only add if either:
// 1. key is the current monitor name
// 2. key is "*" and this monitor is not already defined in the config
bool canCreate = key == currentMonitor || (key == "*" && !monitorInConfig);
const Json::Value &value = m_persistentWorkspaceConfig[key];
spdlog::trace("Parsing persistent workspace config: {} => {}", key, value.toStyledString());
if (value.isInt()) {
// value is a number => create that many workspaces for this monitor
if (canCreate) {
int amount = value.asInt();
spdlog::debug("Creating {} persistent workspaces for monitor {}", amount,
m_bar.output->name);
for (int i = 0; i < amount; i++) {
m_persistentWorkspacesToCreate.emplace_back(
std::to_string(m_monitorId * amount + i + 1));
}
if (value.isInt()) {
// value is a number => create that many workspaces for this monitor
if (canCreate) {
int amount = value.asInt();
spdlog::debug("Creating {} persistent workspaces for monitor {}", amount, currentMonitor);
for (int i = 0; i < amount; i++) {
persistentWorkspacesToCreate.emplace_back(std::to_string(m_monitorId * amount + i + 1));
}
} else if (value.isArray() && !value.empty()) {
// value is an array => create defined workspaces for this monitor
if (canCreate) {
for (const Json::Value &workspace : value) {
if (workspace.isInt()) {
spdlog::debug("Creating workspace {} on monitor {}", workspace, m_bar.output->name);
m_persistentWorkspacesToCreate.emplace_back(std::to_string(workspace.asInt()));
}
}
} else {
// key is the workspace and value is array of monitors to create on
for (const Json::Value &monitor : value) {
if (monitor.isString() && monitor.asString() == m_bar.output->name) {
m_persistentWorkspacesToCreate.emplace_back(key);
break;
}
}
} else if (value.isArray() && !value.empty()) {
// value is an array => create defined workspaces for this monitor
if (canCreate) {
for (const Json::Value &workspace : value) {
if (workspace.isInt()) {
spdlog::debug("Creating workspace {} on monitor {}", workspace, currentMonitor);
persistentWorkspacesToCreate.emplace_back(std::to_string(workspace.asInt()));
}
}
} else {
// this workspace should be displayed on all monitors
m_persistentWorkspacesToCreate.emplace_back(key);
// key is the workspace and value is array of monitors to create on
for (const Json::Value &monitor : value) {
if (monitor.isString() && monitor.asString() == currentMonitor) {
persistentWorkspacesToCreate.emplace_back(currentMonitor);
break;
}
}
}
} else {
// this workspace should be displayed on all monitors
persistentWorkspacesToCreate.emplace_back(key);
}
}
for (auto const &workspace : persistentWorkspacesToCreate) {
auto const workspaceData = createPersistentWorkspaceData(workspace, m_bar.output->name);
m_workspacesToCreate.emplace_back(workspaceData, clientsJson);
}
}
void Workspaces::loadPersistentWorkspacesFromWorkspaceRules(const Json::Value &clientsJson) {
spdlog::info("Loading persistent workspaces from Hyprland workspace rules");
auto const workspaceRules = gIPC->getSocket1JsonReply("workspacerules");
for (Json::Value const &rule : workspaceRules) {
if (!rule["workspaceString"].isString()) {
spdlog::warn("Workspace rules: invalid workspaceString, skipping: {}", rule);
continue;
}
if (!rule["persistent"].asBool()) {
continue;
}
auto const &workspace = rule["workspaceString"].asString();
auto const &monitor = rule["monitor"].asString();
// create this workspace persistently if:
// 1. the allOutputs config option is enabled
// 2. the rule's monitor is the current monitor
// 3. no monitor is specified in the rule => assume it needs to be persistent on every monitor
if (allOutputs() || m_bar.output->name == monitor || monitor.empty()) {
// => persistent workspace should be shown on this monitor
auto workspaceData = createPersistentWorkspaceData(workspace, m_bar.output->name);
m_workspacesToCreate.emplace_back(workspaceData, clientsJson);
} else {
m_workspacesToRemove.emplace_back(workspace);
}
}
}
void Workspaces::createPersistentWorkspaces() {
for (const std::string &workspaceName : m_persistentWorkspacesToCreate) {
Json::Value newWorkspace;
try {
// numbered persistent workspaces get the name as ID
newWorkspace["id"] = workspaceName == "special" ? -99 : std::stoi(workspaceName);
} catch (const std::exception &e) {
// named persistent workspaces start with ID=0
newWorkspace["id"] = 0;
}
newWorkspace["name"] = workspaceName;
newWorkspace["monitor"] = m_bar.output->name;
newWorkspace["windows"] = 0;
newWorkspace["persistent"] = true;
createWorkspace(newWorkspace);
}
}
void Workspaces::extendOrphans(int workspaceId, Json::Value const &clientsJson) {
for (const auto &client : clientsJson) {
if (client["workspace"]["id"].asInt() == workspaceId) {
registerOrphanWindow({client});
}
}
}
void Workspaces::init() {
m_activeWorkspaceName = (gIPC->getSocket1JsonReply("activeworkspace"))["name"].asString();
void Workspaces::setCurrentMonitorId() {
// get monitor ID from name (used by persistent workspaces)
m_monitorId = 0;
auto monitors = gIPC->getSocket1JsonReply("monitors");
@@ -658,29 +743,58 @@ void Workspaces::init() {
spdlog::error("Monitor '{}' does not have an ID? Using 0", m_bar.output->name);
} else {
m_monitorId = (*currentMonitor)["id"].asInt();
spdlog::trace("Current monitor ID: {}", m_monitorId);
}
}
void Workspaces::initializeWorkspaces() {
spdlog::debug("Initializing workspaces");
// if the workspace rules changed since last initialization, make sure we reset everything:
for (auto &workspace : m_workspaces) {
m_workspacesToRemove.push_back(workspace->name());
}
const Json::Value workspacesJson = gIPC->getSocket1JsonReply("workspaces");
const Json::Value clientsJson = gIPC->getSocket1JsonReply("clients");
// get all current workspaces
auto const workspacesJson = gIPC->getSocket1JsonReply("workspaces");
auto const clientsJson = gIPC->getSocket1JsonReply("clients");
for (Json::Value workspaceJson : workspacesJson) {
std::string workspaceName = workspaceJson["name"].asString();
if ((allOutputs() || m_bar.output->name == workspaceJson["monitor"].asString()) &&
(!workspaceName.starts_with("special") || showSpecial()) &&
!isWorkspaceIgnored(workspaceName)) {
createWorkspace(workspaceJson, clientsJson);
m_workspacesToCreate.emplace_back(workspaceJson, clientsJson);
} else {
extendOrphans(workspaceJson["id"].asInt(), clientsJson);
}
}
fillPersistentWorkspaces();
createPersistentWorkspaces();
spdlog::debug("Initializing persistent workspaces");
if (m_persistentWorkspaceConfig.isObject()) {
// a persistent workspace config is defined, so use that instead of workspace rules
loadPersistentWorkspacesFromConfig(clientsJson);
} else {
// no persistent workspaces config defined, use Hyprland's workspace rules
loadPersistentWorkspacesFromWorkspaceRules(clientsJson);
}
}
void Workspaces::extendOrphans(int workspaceId, Json::Value const &clientsJson) {
spdlog::trace("Extending orphans with workspace {}", workspaceId);
for (const auto &client : clientsJson) {
if (client["workspace"]["id"].asInt() == workspaceId) {
registerOrphanWindow({client});
}
}
}
void Workspaces::init() {
m_activeWorkspaceName = (gIPC->getSocket1JsonReply("activeworkspace"))["name"].asString();
initializeWorkspaces();
updateWindowCount();
sortWorkspaces();
dp.emit();
}
@@ -697,7 +811,8 @@ Workspace::Workspace(const Json::Value &workspace_data, Workspaces &workspace_ma
m_name(workspace_data["name"].asString()),
m_output(workspace_data["monitor"].asString()), // TODO:allow using monitor desc
m_windows(workspace_data["windows"].asInt()),
m_active(true) {
m_isActive(true),
m_isPersistent(workspace_data["persistent"].asBool()) {
if (m_name.starts_with("name:")) {
m_name = m_name.substr(5);
} else if (m_name.starts_with("special")) {
@@ -705,10 +820,6 @@ Workspace::Workspace(const Json::Value &workspace_data, Workspaces &workspace_ma
m_isSpecial = true;
}
if (workspace_data.isMember("persistent")) {
m_isPersistent = workspace_data["persistent"].asBool();
}
m_button.add_events(Gdk::BUTTON_PRESS_MASK);
m_button.signal_button_press_event().connect(sigc::mem_fun(*this, &Workspace::handleClicked),
false);
@@ -814,8 +925,7 @@ void Workspaces::sortWorkspaces() {
if (a->id() == -99 || b->id() == -99) {
return b->id() == -99;
}
// both are 0 (not yet named persistents) / both are named specials (-98 <= ID
// <=-1)
// both are 0 (not yet named persistents) / named specials (-98 <= ID <= -1)
return isNameLess;
}
@@ -834,6 +944,7 @@ void Workspaces::sortWorkspaces() {
}
std::string &Workspace::selectIcon(std::map<std::string, std::string> &icons_map) {
spdlog::trace("Selecting icon for workspace {}", name());
if (isUrgent()) {
auto urgentIconIt = icons_map.find("urgent");
if (urgentIconIt != icons_map.end()) {
@@ -892,9 +1003,9 @@ std::string &Workspace::selectIcon(std::map<std::string, std::string> &icons_map
bool Workspace::handleClicked(GdkEventButton *bt) const {
if (bt->type == GDK_BUTTON_PRESS) {
try {
if (id() > 0) { // normal or numbered persistent
if (id() > 0) { // normal
gIPC->getSocket1Reply("dispatch workspace " + std::to_string(id()));
} else if (!isSpecial()) { // named
} else if (!isSpecial()) { // named (this includes persistent)
gIPC->getSocket1Reply("dispatch workspace name:" + name());
} else if (id() != -99) { // named special
gIPC->getSocket1Reply("dispatch togglespecialworkspace " + name());

View File

@@ -7,6 +7,7 @@ waybar::modules::Image::Image(const std::string& id, const Json::Value& config)
if (!id.empty()) {
box_.get_style_context()->add_class(id);
}
box_.get_style_context()->add_class(MODULE_CLASS);
event_box_.add(box_);
dp.emit();

View File

@@ -81,7 +81,7 @@ auto supportsLockStates(const libevdev* dev) -> bool {
waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Bar& bar,
const Json::Value& config)
: AModule(config, "keyboard-state", id, false, !config["disable-scroll"].asBool()),
box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0),
box_(bar.orientation, 0),
numlock_label_(""),
capslock_label_(""),
numlock_format_(config_["format"].isString() ? config_["format"].asString()
@@ -132,6 +132,7 @@ waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Bar&
if (!id.empty()) {
box_.get_style_context()->add_class(id);
}
box_.get_style_context()->add_class(MODULE_CLASS);
event_box_.add(box_);
if (config_["device-path"].isString()) {

View File

@@ -87,7 +87,7 @@ Tags::Tags(const std::string &id, const waybar::Bar &bar, const Json::Value &con
control_{nullptr},
seat_{nullptr},
bar_(bar),
box_{bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0},
box_{bar.orientation, 0},
output_status_{nullptr} {
struct wl_display *display = Client::inst()->wl_display;
struct wl_registry *registry = wl_display_get_registry(display);
@@ -111,6 +111,7 @@ Tags::Tags(const std::string &id, const waybar::Bar &bar, const Json::Value &con
if (!id.empty()) {
box_.get_style_context()->add_class(id);
}
box_.get_style_context()->add_class(MODULE_CLASS);
event_box_.add(box_);
// Default to 9 tags, cap at 32

View File

@@ -6,7 +6,7 @@ namespace waybar::modules::SNI {
Tray::Tray(const std::string& id, const Bar& bar, const Json::Value& config)
: AModule(config, "tray", id),
box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0),
box_(bar.orientation, 0),
watcher_(SNI::Watcher::getInstance()),
host_(nb_hosts_, config, bar, std::bind(&Tray::onAdd, this, std::placeholders::_1),
std::bind(&Tray::onRemove, this, std::placeholders::_1)) {
@@ -15,6 +15,7 @@ Tray::Tray(const std::string& id, const Bar& bar, const Json::Value& config)
if (!id.empty()) {
box_.get_style_context()->add_class(id);
}
box_.get_style_context()->add_class(MODULE_CLASS);
if (config_["spacing"].isUInt()) {
box_.set_spacing(config_["spacing"].asUInt());
}

View File

@@ -19,6 +19,7 @@ const std::string Language::XKB_ACTIVE_LAYOUT_NAME_KEY = "xkb_active_layout_name
Language::Language(const std::string& id, const Json::Value& config)
: ALabel(config, "language", id, "{}", 0, true) {
hide_single_ = config["hide-single-layout"].isBool() && config["hide-single-layout"].asBool();
is_variant_displayed = format_.find("{variant}") != std::string::npos;
if (format_.find("{}") != std::string::npos || format_.find("{short}") != std::string::npos) {
displayed_short_flag |= static_cast<std::byte>(DispayedShortFlag::ShortName);
@@ -95,6 +96,10 @@ void Language::onEvent(const struct Ipc::ipc_response& res) {
auto Language::update() -> void {
std::lock_guard<std::mutex> lock(mutex_);
if (hide_single_ && layouts_map_.size() <= 1) {
event_box_.hide();
return;
}
auto display_layout = trim(fmt::format(
fmt::runtime(format_), fmt::arg("short", layout_.short_name),
fmt::arg("shortDescription", layout_.short_description), fmt::arg("long", layout_.full_name),

View File

@@ -24,10 +24,28 @@ int Workspaces::convertWorkspaceNameToNum(std::string name) {
return -1;
}
int Workspaces::windowRewritePriorityFunction(std::string const &window_rule) {
// Rules that match against title are prioritized
// Rules that don't specify if they're matching against either title or class are deprioritized
bool const hasTitle = window_rule.find("title") != std::string::npos;
bool const hasClass = window_rule.find("class") != std::string::npos;
if (hasTitle && hasClass) {
return 3;
}
if (hasTitle) {
return 2;
}
if (hasClass) {
return 1;
}
return 0;
}
Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value &config)
: AModule(config, "workspaces", id, false, !config["disable-scroll"].asBool()),
bar_(bar),
box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0) {
box_(bar.orientation, 0) {
if (config["format-icons"]["high-priority-named"].isArray()) {
for (auto &it : config["format-icons"]["high-priority-named"]) {
high_priority_named_.push_back(it.asString());
@@ -37,11 +55,27 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value
if (!id.empty()) {
box_.get_style_context()->add_class(id);
}
box_.get_style_context()->add_class(MODULE_CLASS);
event_box_.add(box_);
if (config_["format-window-separator"].isString()) {
m_formatWindowSeperator = config_["format-window-separator"].asString();
} else {
m_formatWindowSeperator = " ";
}
const Json::Value &windowRewrite = config["window-rewrite"];
const Json::Value &windowRewriteDefaultConfig = config["window-rewrite-default"];
m_windowRewriteDefault =
windowRewriteDefaultConfig.isString() ? windowRewriteDefaultConfig.asString() : "?";
m_windowRewriteRules = waybar::util::RegexCollection(
windowRewrite, m_windowRewriteDefault,
[this](std::string &window_rule) { return windowRewritePriorityFunction(window_rule); });
ipc_.subscribe(R"(["workspace"])");
ipc_.subscribe(R"(["window"])");
ipc_.signal_event.connect(sigc::mem_fun(*this, &Workspaces::onEvent));
ipc_.signal_cmd.connect(sigc::mem_fun(*this, &Workspaces::onCmd));
ipc_.sendCmd(IPC_GET_WORKSPACES);
ipc_.sendCmd(IPC_GET_TREE);
if (config["enable-bar-scroll"].asBool()) {
auto &window = const_cast<Bar &>(bar_).window;
window.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
@@ -59,26 +93,33 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value
void Workspaces::onEvent(const struct Ipc::ipc_response &res) {
try {
ipc_.sendCmd(IPC_GET_WORKSPACES);
ipc_.sendCmd(IPC_GET_TREE);
} catch (const std::exception &e) {
spdlog::error("Workspaces: {}", e.what());
}
}
void Workspaces::onCmd(const struct Ipc::ipc_response &res) {
if (res.type == IPC_GET_WORKSPACES) {
if (res.type == IPC_GET_TREE) {
try {
{
std::lock_guard<std::mutex> lock(mutex_);
auto payload = parser_.parse(res.payload);
workspaces_.clear();
std::copy_if(payload.begin(), payload.end(), std::back_inserter(workspaces_),
std::vector<Json::Value> outputs;
std::copy_if(payload["nodes"].begin(), payload["nodes"].end(), std::back_inserter(outputs),
[&](const auto &workspace) {
return !config_["all-outputs"].asBool()
? workspace["output"].asString() == bar_.output->name
? workspace["name"].asString() == bar_.output->name
: true;
});
for (auto &output : outputs) {
std::copy(output["nodes"].begin(), output["nodes"].end(),
std::back_inserter(workspaces_));
std::copy(output["floating_nodes"].begin(), output["floating_nodes"].end(),
std::back_inserter(workspaces_));
}
if (config_["persistent_workspaces"].isObject()) {
spdlog::warn(
"persistent_workspaces is deprecated. Please change config to use "
@@ -203,6 +244,40 @@ bool Workspaces::filterButtons() {
return needReorder;
}
bool Workspaces::hasFlag(const Json::Value &node, const std::string &flag) {
if (node[flag].asBool()) {
return true;
}
if (std::any_of(node["nodes"].begin(), node["nodes"].end(),
[&](auto const &e) { return hasFlag(e, flag); })) {
return true;
}
return false;
}
void Workspaces::updateWindows(const Json::Value &node, std::string &windows) {
auto format = config_["window-format"].asString();
if ((node["type"].asString() == "con" || node["type"].asString() == "floating_con") &&
node["name"].isString()) {
std::string title = g_markup_escape_text(node["name"].asString().c_str(), -1);
std::string windowClass = node["app_id"].asString();
std::string windowReprKey = fmt::format("class<{}> title<{}>", windowClass, title);
std::string window = m_windowRewriteRules.get(windowReprKey);
// allow result to have formatting
window =
fmt::format(fmt::runtime(window), fmt::arg("name", title), fmt::arg("class", windowClass));
windows.append(window);
windows.append(m_formatWindowSeperator);
}
for (const Json::Value &child : node["nodes"]) {
updateWindows(child, windows);
}
for (const Json::Value &child : node["floating_nodes"]) {
updateWindows(child, windows);
}
}
auto Workspaces::update() -> void {
std::lock_guard<std::mutex> lock(mutex_);
bool needReorder = filterButtons();
@@ -212,22 +287,25 @@ auto Workspaces::update() -> void {
needReorder = true;
}
auto &button = bit == buttons_.end() ? addButton(*it) : bit->second;
if ((*it)["focused"].asBool()) {
if (needReorder) {
box_.reorder_child(button, it - workspaces_.begin());
}
if (hasFlag((*it), "focused")) {
button.get_style_context()->add_class("focused");
} else {
button.get_style_context()->remove_class("focused");
}
if ((*it)["visible"].asBool()) {
if (hasFlag((*it), "visible")) {
button.get_style_context()->add_class("visible");
} else {
button.get_style_context()->remove_class("visible");
}
if ((*it)["urgent"].asBool()) {
if (hasFlag((*it), "urgent")) {
button.get_style_context()->add_class("urgent");
} else {
button.get_style_context()->remove_class("urgent");
}
if ((*it)["target_output"].isString()) {
if (hasFlag((*it), "target_output")) {
button.get_style_context()->add_class("persistent");
} else {
button.get_style_context()->remove_class("persistent");
@@ -241,16 +319,19 @@ auto Workspaces::update() -> void {
} else {
button.get_style_context()->remove_class("current_output");
}
if (needReorder) {
box_.reorder_child(button, it - workspaces_.begin());
}
std::string output = (*it)["name"].asString();
std::string windows = "";
if (config_["window-format"].isString()) {
updateWindows((*it), windows);
}
if (config_["format"].isString()) {
auto format = config_["format"].asString();
output = fmt::format(fmt::runtime(format), fmt::arg("icon", getIcon(output, *it)),
fmt::arg("value", output), fmt::arg("name", trimWorkspaceName(output)),
fmt::arg("index", (*it)["num"].asString()),
fmt::arg("output", (*it)["output"].asString()));
output = fmt::format(
fmt::runtime(format), fmt::arg("icon", getIcon(output, *it)), fmt::arg("value", output),
fmt::arg("name", trimWorkspaceName(output)), fmt::arg("index", (*it)["num"].asString()),
fmt::arg("windows",
windows.substr(0, windows.length() - m_formatWindowSeperator.length())),
fmt::arg("output", (*it)["output"].asString()));
}
if (!config_["disable-markup"].asBool()) {
static_cast<Gtk::Label *>(button.get_children()[0])->set_markup(output);

View File

@@ -24,11 +24,16 @@ waybar::modules::Temperature::Temperature(const std::string& id, const Json::Val
}
}
} else if (config_["hwmon-path-abs"].isString() && config_["input-filename"].isString()) {
file_path_ = (*std::filesystem::directory_iterator(config_["hwmon-path-abs"].asString()))
.path()
.string() +
"/" + config_["input-filename"].asString();
} else {
for (const auto& hwmon :
std::filesystem::directory_iterator(config_["hwmon-path-abs"].asString())) {
if (hwmon.path().filename().string().starts_with("hwmon")) {
file_path_ = hwmon.path().string() + "/" + config_["input-filename"].asString();
break;
}
}
}
if (file_path_.empty()) {
auto zone = config_["thermal-zone"].isInt() ? config_["thermal-zone"].asInt() : 0;
file_path_ = fmt::format("/sys/class/thermal/thermal_zone{}/temp", zone);
}

View File

@@ -277,7 +277,7 @@ Task::Task(const waybar::Bar &bar, const Json::Value &config, Taskbar *tbar,
handle_{tl_handle},
seat_{seat},
id_{global_id++},
content_{bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0} {
content_{bar.orientation, 0} {
zwlr_foreign_toplevel_handle_v1_add_listener(handle_, &toplevel_handle_impl, this);
button.set_relief(Gtk::RELIEF_NONE);
@@ -730,13 +730,14 @@ static const wl_registry_listener registry_listener_impl = {.global = handle_glo
Taskbar::Taskbar(const std::string &id, const waybar::Bar &bar, const Json::Value &config)
: waybar::AModule(config, "taskbar", id, false, false),
bar_(bar),
box_{bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0},
box_{bar.orientation, 0},
manager_{nullptr},
seat_{nullptr} {
box_.set_name("taskbar");
if (!id.empty()) {
box_.get_style_context()->add_class(id);
}
box_.get_style_context()->add_class(MODULE_CLASS);
box_.get_style_context()->add_class("empty");
event_box_.add(box_);

View File

@@ -21,9 +21,7 @@ std::map<std::string, std::string> Workspace::icons_map_;
WorkspaceManager::WorkspaceManager(const std::string &id, const waybar::Bar &bar,
const Json::Value &config)
: waybar::AModule(config, "workspaces", id, false, false),
bar_(bar),
box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0) {
: waybar::AModule(config, "workspaces", id, false, false), bar_(bar), box_(bar.orientation, 0) {
auto config_sort_by_name = config_["sort-by-name"];
if (config_sort_by_name.isBool()) {
sort_by_name_ = config_sort_by_name.asBool();
@@ -54,6 +52,7 @@ WorkspaceManager::WorkspaceManager(const std::string &id, const waybar::Bar &bar
if (!id.empty()) {
box_.get_style_context()->add_class(id);
}
box_.get_style_context()->add_class(MODULE_CLASS);
event_box_.add(box_);
add_registry_listener(this);