Merge pull request #4898 from khaneliman/memory

perf(memory): optimize string operations; remove deep copies, memdup, and icon theme rescanning
This commit is contained in:
Alexis Rouillard
2026-03-04 22:40:55 +01:00
committed by GitHub
33 changed files with 75 additions and 69 deletions

View File

@@ -71,6 +71,7 @@ CFFI::CFFI(const std::string& name, const std::string& id, const Json::Value& co
// Prepare config_entries array
std::vector<ffi::wbcffi_config_entry> config_entries;
config_entries.reserve(keys.size());
for (size_t i = 0; i < keys.size(); i++) {
config_entries.push_back({keys[i].c_str(), config_entries_stringstor[i].c_str()});
}

View File

@@ -26,7 +26,7 @@ std::vector<float> waybar::modules::CpuFrequency::parseCpuFrequencies() {
if (std::filesystem::exists(cpufreq_dir)) {
std::vector<std::string> frequency_files = {"/cpuinfo_min_freq", "/cpuinfo_max_freq"};
for (auto& p : std::filesystem::directory_iterator(cpufreq_dir)) {
for (auto freq_file : frequency_files) {
for (const auto& freq_file : frequency_files) {
std::string freq_file_path = p.path().string() + freq_file;
if (std::filesystem::exists(freq_file_path)) {
std::string freq_value;

View File

@@ -92,7 +92,7 @@ auto waybar::modules::Disk::update() -> void {
ALabel::update();
}
float waybar::modules::Disk::calc_specific_divisor(std::string divisor) {
float waybar::modules::Disk::calc_specific_divisor(const std::string& divisor) {
if (divisor == "kB") {
return 1000.0;
} else if (divisor == "kiB") {

View File

@@ -124,7 +124,7 @@ auto Window::getActiveWorkspace(const std::string& monitorName) -> Workspace {
const auto monitors = IPC::inst().getSocket1JsonReply("monitors");
if (monitors.isArray()) {
auto monitor = std::ranges::find_if(
monitors, [&](Json::Value monitor) { return monitor["name"] == monitorName; });
monitors, [&](const Json::Value& monitor) { return monitor["name"] == monitorName; });
if (monitor == std::end(monitors)) {
spdlog::warn("Monitor not found: {}", monitorName);
return Workspace{
@@ -139,7 +139,7 @@ auto Window::getActiveWorkspace(const std::string& monitorName) -> Workspace {
const auto workspaces = IPC::inst().getSocket1JsonReply("workspaces");
if (workspaces.isArray()) {
auto workspace = std::ranges::find_if(
workspaces, [&](Json::Value workspace) { return workspace["id"] == id; });
workspaces, [&](const Json::Value& workspace) { return workspace["id"] == id; });
if (workspace == std::end(workspaces)) {
spdlog::warn("No workspace with id {}", id);
return Workspace{
@@ -190,7 +190,7 @@ void Window::queryActiveWorkspace() {
const auto clients = m_ipc.getSocket1JsonReply("clients");
if (clients.isArray()) {
auto activeWindow = std::ranges::find_if(
clients, [&](Json::Value window) { return window["address"] == workspace_.last_window; });
clients, [&](const Json::Value& window) { return window["address"] == workspace_.last_window; });
if (activeWindow == std::end(clients)) {
focused_ = false;
@@ -200,19 +200,19 @@ void Window::queryActiveWorkspace() {
windowData_ = WindowData::parse(*activeWindow);
updateAppIconName(windowData_.class_name, windowData_.initial_class_name);
std::vector<Json::Value> workspaceWindows;
std::ranges::copy_if(clients, std::back_inserter(workspaceWindows), [&](Json::Value window) {
std::ranges::copy_if(clients, std::back_inserter(workspaceWindows), [&](const Json::Value& window) {
return window["workspace"]["id"] == workspace_.id && window["mapped"].asBool();
});
swallowing_ = std::ranges::any_of(workspaceWindows, [&](Json::Value window) {
swallowing_ = std::ranges::any_of(workspaceWindows, [&](const Json::Value& window) {
return !window["swallowing"].isNull() && window["swallowing"].asString() != "0x0";
});
std::vector<Json::Value> visibleWindows;
std::ranges::copy_if(workspaceWindows, std::back_inserter(visibleWindows),
[&](Json::Value window) { return !window["hidden"].asBool(); });
[&](const Json::Value& window) { return !window["hidden"].asBool(); });
solo_ = 1 == std::count_if(visibleWindows.begin(), visibleWindows.end(),
[&](Json::Value window) { return !window["floating"].asBool(); });
[&](const Json::Value& window) { return !window["floating"].asBool(); });
allFloating_ = std::ranges::all_of(
visibleWindows, [&](Json::Value window) { return window["floating"].asBool(); });
visibleWindows, [&](const Json::Value& window) { return window["floating"].asBool(); });
fullscreen_ = windowData_.fullscreen;
// Fullscreen windows look like they are solo

View File

@@ -79,7 +79,7 @@ auto WindowCount::getActiveWorkspace(const std::string& monitorName) -> Workspac
const auto monitors = m_ipc.getSocket1JsonReply("monitors");
if (monitors.isArray()) {
auto monitor = std::ranges::find_if(
monitors, [&](Json::Value monitor) { return monitor["name"] == monitorName; });
monitors, [&](const Json::Value& monitor) { return monitor["name"] == monitorName; });
if (monitor == std::end(monitors)) {
spdlog::warn("Monitor not found: {}", monitorName);
return Workspace{
@@ -93,7 +93,7 @@ auto WindowCount::getActiveWorkspace(const std::string& monitorName) -> Workspac
const auto workspaces = m_ipc.getSocket1JsonReply("workspaces");
if (workspaces.isArray()) {
auto workspace = std::ranges::find_if(
workspaces, [&](Json::Value workspace) { return workspace["id"] == id; });
workspaces, [&](const Json::Value& workspace) { return workspace["id"] == id; });
if (workspace == std::end(workspaces)) {
spdlog::warn("No workspace with id {}", id);
return Workspace{

View File

@@ -19,7 +19,7 @@ WindowCreationPayload::WindowCreationPayload(Json::Value const& client_data)
clearWorkspaceName();
}
WindowCreationPayload::WindowCreationPayload(std::string workspace_name,
WindowCreationPayload::WindowCreationPayload(const std::string& workspace_name,
WindowAddress window_address, WindowRepr window_repr)
: m_window(std::move(window_repr)),
m_windowAddress(std::move(window_address)),
@@ -28,9 +28,10 @@ WindowCreationPayload::WindowCreationPayload(std::string workspace_name,
clearWorkspaceName();
}
WindowCreationPayload::WindowCreationPayload(std::string workspace_name,
WindowAddress window_address, std::string window_class,
std::string window_title, bool is_active)
WindowCreationPayload::WindowCreationPayload(const std::string& workspace_name,
WindowAddress window_address,
const std::string& window_class,
const std::string& window_title, bool is_active)
: m_window(std::make_pair(std::move(window_class), std::move(window_title))),
m_windowAddress(std::move(window_address)),
m_workspaceName(std::move(workspace_name)),

View File

@@ -96,7 +96,7 @@ bool Workspace::handleClicked(GdkEventButton* bt) const {
void Workspace::initializeWindowMap(const Json::Value& clients_data) {
m_windowMap.clear();
for (auto client : clients_data) {
for (const auto& client : clients_data) {
if (client["workspace"]["id"].asInt() == id()) {
insertWindow({client});
}

View File

@@ -155,7 +155,8 @@ void Workspaces::extendOrphans(int workspaceId, Json::Value const& clientsJson)
}
}
std::string Workspaces::getRewrite(std::string window_class, std::string window_title) {
std::string Workspaces::getRewrite(const std::string& window_class,
const std::string& window_title) {
std::string windowReprKey;
if (windowRewriteConfigUsesTitle()) {
windowReprKey = fmt::format("class<{}> title<{}>", window_class, window_title);
@@ -196,7 +197,7 @@ void Workspaces::initializeWorkspaces() {
auto const workspacesJson = m_ipc.getSocket1JsonReply("workspaces");
auto const clientsJson = m_ipc.getSocket1JsonReply("clients");
for (Json::Value workspaceJson : workspacesJson) {
for (const auto& workspaceJson : workspacesJson) {
std::string workspaceName = workspaceJson["name"].asString();
if ((allOutputs() || m_bar.output->name == workspaceJson["monitor"].asString()) &&
(!workspaceName.starts_with("special") || showSpecial()) &&
@@ -400,7 +401,7 @@ void Workspaces::onWorkspaceCreated(std::string const& payload, Json::Value cons
auto const workspaceRules = m_ipc.getSocket1JsonReply("workspacerules");
auto const workspacesJson = m_ipc.getSocket1JsonReply("workspaces");
for (Json::Value workspaceJson : workspacesJson) {
for (auto workspaceJson : workspacesJson) {
const auto currentId = workspaceJson["id"].asInt();
if (currentId == *workspaceId) {
std::string workspaceName = workspaceJson["name"].asString();
@@ -1003,7 +1004,7 @@ void Workspaces::setUrgentWorkspace(std::string const& windowaddress) {
const Json::Value clientsJson = m_ipc.getSocket1JsonReply("clients");
int workspaceId = -1;
for (Json::Value clientJson : clientsJson) {
for (const auto& clientJson : clientsJson) {
if (clientJson["address"].asString().ends_with(windowaddress)) {
workspaceId = clientJson["workspace"]["id"].asInt();
break;

View File

@@ -85,7 +85,8 @@ auto getInhibitors(const Json::Value& config) -> std::string {
if (config["what"].isArray()) {
inhibitors = checkInhibitor(config["what"][0].asString());
for (decltype(config["what"].size()) i = 1; i < config["what"].size(); ++i) {
inhibitors += ":" + checkInhibitor(config["what"][i].asString());
inhibitors.append(":");
inhibitors.append(checkInhibitor(config["what"][i].asString()));
}
return inhibitors;
}

View File

@@ -239,7 +239,8 @@ std::string waybar::modules::MPD::getStateIcon() const {
}
}
std::string waybar::modules::MPD::getOptionIcon(std::string optionName, bool activated) const {
std::string waybar::modules::MPD::getOptionIcon(const std::string& optionName,
bool activated) const {
if (!config_[optionName + "-icons"].isObject()) {
return "";
}

View File

@@ -109,6 +109,7 @@ Mpris::Mpris(const std::string& id, const Json::Value& config)
player_ = config_["player"].asString();
}
if (config_["ignored-players"].isArray()) {
ignored_players_.reserve(config_["ignored-players"].size());
for (const auto& item : config_["ignored-players"]) {
if (item.isString()) {
ignored_players_.push_back(item.asString());

View File

@@ -321,6 +321,7 @@ auto waybar::modules::Network::update() -> void {
} else if (addr_pref_ == ip_addr_pref::IPV6) {
final_ipaddr_ = ipaddr6_;
} else if (addr_pref_ == ip_addr_pref::IPV4_6) {
final_ipaddr_.reserve(ipaddr_.length() + ipaddr6_.length() + 1);
final_ipaddr_ = ipaddr_;
final_ipaddr_ += '\n';
final_ipaddr_ += ipaddr6_;

View File

@@ -32,6 +32,7 @@ void Language::updateFromIPC() {
auto ipcLock = gIPC->lockData();
layouts_.clear();
layouts_.reserve(gIPC->keyboardLayoutNames().size());
for (const auto& fullName : gIPC->keyboardLayoutNames()) layouts_.push_back(getLayout(fullName));
current_idx_ = gIPC->keyboardLayoutCurrent();

View File

@@ -132,7 +132,7 @@ std::tuple<std::string, std::string> Host::getBusNameAndObjectPath(const std::st
return {service, "/StatusNotifierItem"};
}
void Host::addRegisteredItem(std::string service) {
void Host::addRegisteredItem(const std::string& service) {
std::string bus_name, object_path;
std::tie(bus_name, object_path) = getBusNameAndObjectPath(service);
auto it = std::find_if(items_.begin(), items_.end(), [&bus_name, &object_path](const auto& item) {

View File

@@ -336,11 +336,20 @@ Glib::RefPtr<Gdk::Pixbuf> Item::extractPixBuf(GVariant* variant) {
if (array != nullptr) {
g_free(array);
}
#if GLIB_MAJOR_VERSION >= 2 && GLIB_MINOR_VERSION >= 68
array = static_cast<guchar*>(g_memdup2(data, size));
#else
array = static_cast<guchar*>(g_memdup(data, size));
#endif
// We must allocate our own array because the data from GVariant is read-only
// and we need to modify it to convert ARGB to RGBA.
array = static_cast<guchar*>(g_malloc(size));
// Copy and convert ARGB to RGBA in one pass to avoid g_memdup2 overhead
const guchar* src = static_cast<const guchar*>(data);
for (gsize i = 0; i < size; i += 4) {
guchar alpha = src[i];
array[i] = src[i + 1];
array[i + 1] = src[i + 2];
array[i + 2] = src[i + 3];
array[i + 3] = alpha;
}
lwidth = width;
lheight = height;
}
@@ -349,14 +358,6 @@ Glib::RefPtr<Gdk::Pixbuf> Item::extractPixBuf(GVariant* variant) {
}
g_variant_iter_free(it);
if (array != nullptr) {
/* argb to rgba */
for (uint32_t i = 0; i < 4U * lwidth * lheight; i += 4) {
guchar alpha = array[i];
array[i] = array[i + 1];
array[i + 1] = array[i + 2];
array[i + 2] = array[i + 3];
array[i + 3] = alpha;
}
return Gdk::Pixbuf::create_from_data(array, Gdk::Colorspace::COLORSPACE_RGB, true, 8, lwidth,
lheight, 4 * lwidth, &pixbuf_data_deleter);
}
@@ -422,8 +423,6 @@ Glib::RefPtr<Gdk::Pixbuf> Item::getIconPixbuf() {
}
Glib::RefPtr<Gdk::Pixbuf> Item::getIconByName(const std::string& name, int request_size) {
icon_theme->rescan_if_needed();
if (!icon_theme_path.empty()) {
auto icon_info = icon_theme->lookup_icon(name.c_str(), request_size,
Gtk::IconLookupFlags::ICON_LOOKUP_FORCE_SIZE);

View File

@@ -60,7 +60,7 @@ BarIpcClient::BarIpcClient(waybar::Bar& bar) : bar_{bar} {
});
}
bool BarIpcClient::isModuleEnabled(std::string name) {
bool BarIpcClient::isModuleEnabled(const std::string& name) {
for (const auto& section : {"modules-left", "modules-center", "modules-right"}) {
if (const auto& modules = bar_.config.get(section, {}); modules.isArray()) {
for (const auto& module : modules) {

View File

@@ -124,7 +124,7 @@ auto Language::update() -> void {
ALabel::update();
}
auto Language::set_current_layout(std::string current_layout) -> void {
auto Language::set_current_layout(const std::string& current_layout) -> void {
label_.get_style_context()->remove_class(layout_.short_name);
layout_ = layouts_map_[current_layout];
label_.get_style_context()->add_class(layout_.short_name);

View File

@@ -184,9 +184,9 @@ std::tuple<std::string, std::string, std::string, std::string> getWindowInfo(
continue;
}
if (!marks.empty()) {
marks += ',';
marks.append(",");
}
marks += m.asString();
marks.append(m.asString());
}
}
return {app_id, app_class, shell, marks};

View File

@@ -10,7 +10,7 @@ namespace waybar::modules::sway {
// Helper function to assign a number to a workspace, just like sway. In fact
// this is taken quite verbatim from `sway/ipc-json.c`.
int Workspaces::convertWorkspaceNameToNum(std::string name) {
int Workspaces::convertWorkspaceNameToNum(const std::string& name) {
if (isdigit(name[0]) != 0) {
errno = 0;
char* endptr = nullptr;
@@ -487,7 +487,7 @@ std::string Workspaces::getCycleWorkspace(std::vector<Json::Value>::iterator it,
return (*it)["name"].asString();
}
std::string Workspaces::trimWorkspaceName(std::string name) {
std::string Workspaces::trimWorkspaceName(const std::string& name) {
std::size_t found = name.find(':');
if (found != std::string::npos) {
return name.substr(found + 1);

View File

@@ -95,7 +95,7 @@ UPower::~UPower() {
removeDevices();
}
static const std::string getDeviceStatus(UpDeviceState& state) {
static std::string_view getDeviceStatus(UpDeviceState& state) {
switch (state) {
case UP_DEVICE_STATE_CHARGING:
case UP_DEVICE_STATE_PENDING_CHARGE:
@@ -112,7 +112,7 @@ static const std::string getDeviceStatus(UpDeviceState& state) {
}
}
static const std::string getDeviceIcon(UpDeviceKind& kind) {
static std::string_view getDeviceIcon(UpDeviceKind& kind) {
switch (kind) {
case UP_DEVICE_KIND_LINE_POWER:
return "ac-adapter-symbolic";
@@ -212,7 +212,8 @@ auto UPower::update() -> void {
// Remove last status if it exists
if (!lastStatus_.empty() && box_.get_style_context()->has_class(lastStatus_))
box_.get_style_context()->remove_class(lastStatus_);
if (!box_.get_style_context()->has_class(status)) box_.get_style_context()->add_class(status);
if (!box_.get_style_context()->has_class(std::string(status)))
box_.get_style_context()->add_class(std::string(status));
lastStatus_ = status;
if (devices_.size() == 0 && !upDeviceValid && hideIfEmpty_) {

View File

@@ -21,7 +21,6 @@ Glib::RefPtr<Gdk::Pixbuf> DefaultGtkIconThemeWrapper::load_icon(
const std::lock_guard<std::mutex> lock(default_theme_mutex);
auto default_theme = Gtk::IconTheme::get_default();
default_theme->rescan_if_needed();
auto icon_info = default_theme->lookup_icon(name, tmp_size, flags);