Решил написать пет проект, time tracker, просто по фану.
Столкнулся с проблемой кодировки, раньше как-то удавалось обходить.
Проблема заключается в том что в консоли я вижу «кракозябры», подскажите какие изменения я могу внести в код, чтобы кирилица заработала?
Вот пример вывода программы:
konsole
        cmake-build-debug : att : 14s
        cmake-build-debug : zsh : 3s
        home : zsh : 3s
spotify
        Curtis Waters - Stunnin' : 9s
        Joji - Daylight : 8s
        Kino - Ðвезда по имени СолнÑе : 1s
        Kino - ÐаÑка ÑигаÑÐµÑ : 5s
        Kino - ХоÑÑ Ð¿ÐµÑемен : 5s
#include <X11/Xlib.h>
#include <X11/Xmu/WinUtil.h>
#include <iostream>
#include <chrono>
#include <thread>
#include <set>
struct ApplicationInfo
{
	struct TabInfo
	{
		friend bool operator<(const TabInfo& lhs, const TabInfo& rhs)
		{
			return lhs.m_title < rhs.m_title;
		}
		std::string m_title;
		std::chrono::seconds m_total = std::chrono::seconds{0};
	};
	static std::chrono::seconds GetTotal(const ApplicationInfo& windowInfo)
	{
		std::chrono::seconds total = std::chrono::seconds{0};
		for (const auto& tab : windowInfo.m_tabs)
		{
			total += tab.m_total;
		}
		return total;
	}
	friend bool operator<(const ApplicationInfo& lhs, const ApplicationInfo& rhs)
	{
		return lhs.m_name < rhs.m_name;
	}
	std::string m_name;
	std::set<TabInfo> m_tabs;
};
Display* open_display()
{
	return XOpenDisplay(nullptr);
}
std::optional<Window> get_focus_window(Display* pDisplay)
{
	int revert_to = 0;
	Window window;
	XGetInputFocus(pDisplay, &window, &revert_to);
	return window;
}
std::optional<Window> get_top_window(Display* pDisplay, Window start)
{
	Window current = start;
	Window parent = start;
	Window root = None;
	Window* pChildren;
	unsigned int nChildren;
	Status s;
	while (parent != root)
	{
		current = parent;
		s = XQueryTree(pDisplay, current, &root, &parent, &pChildren, &nChildren);
		if (s)
		{
			XFree(pChildren);
		}
	}
	return current;
}
std::optional<Window> get_named_window(Display* pDisplay, Window start)
{
	Window window;
	window = XmuClientWindow(pDisplay, start);
	return window;
}
std::optional<std::string> get_window_name(Display* pDisplay, Window window)
{
	XTextProperty prop;
	auto status = XGetWMName(pDisplay, window, &prop); // see man
	int count = 0, result;
	char** list = nullptr;
	Xutf8TextPropertyToTextList(pDisplay, &prop, &list, &count);
	return list[0];
}
std::optional<std::string> get_window_application(Display* d, Window w)
{
	auto x = XAllocClassHint();
	auto status = XGetClassHint(d, w, x);
	return x->res_name;
}
std::pair<std::string, std::string> get_window_info(Display* d, Window w)
{
	return {*get_window_application(d, w), *get_window_name(d, w)};
}
std::optional<std::pair<std::string, std::string>> get_active_window_info()
{
	auto pDisplay = open_display();
	auto window = get_focus_window(pDisplay);
	window = get_top_window(pDisplay, *window);
	window = get_named_window(pDisplay, *window);
	return get_window_info(pDisplay, *window);
}
int main()
{
	setlocale(LC_ALL, "");
	std::set<ApplicationInfo> applications;
	ApplicationInfo previous;
	auto find_window = [](const std::string& application_name)
	{
		return [&app_name = application_name](const ApplicationInfo& w) -> bool
		{
			return w.m_name == app_name;
		};
	};
#pragma clang diagnostic push
#pragma ide diagnostic ignored "EndlessLoop"
	while (true)
	{
		auto window_info = get_active_window_info();
		if (window_info)
		{
			auto it = std::find_if(
					std::begin(applications)
					, std::end(applications)
					, find_window(window_info->first));
			if (it == applications.end())
			{
				ApplicationInfo info;
				info.m_name = window_info->first;
				info.m_tabs.emplace(ApplicationInfo::TabInfo{window_info->second});
				applications.emplace(info);
			}
			else
			{
				auto itTab = std::find_if(
						std::begin(it->m_tabs)
						, std::end(it->m_tabs)
						, [&title = window_info->second](const ApplicationInfo::TabInfo& tabInfo)
						{
							return tabInfo.m_title == title;
						});
				if (itTab == it->m_tabs.end())
				{
					it._M_const_cast()->m_tabs.emplace(ApplicationInfo::TabInfo{window_info->second, std::chrono::seconds{1}});
				}
				else
				{
					itTab._M_const_cast()->m_total += std::chrono::seconds{1};
				}
			}
		}
		std::system("clear");
		for (const auto& application : applications)
		{
			std::cout
					<< "\n"
					<< application.m_name;
			for (const auto& tab : application.m_tabs)
			{
				std::cout << "\n\t" << tab.m_title << " : " << tab.m_total.count() << "s";
			}
			std::cout << "\n\n";
		}
		std::this_thread::sleep_for(std::chrono::seconds{1});
	}
#pragma clang diagnostic pop
	return EXIT_SUCCESS;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.17)
project(att)
set(CMAKE_CXX_STANDARD 20)
find_package(X11 REQUIRED)
set(INCLUDE_DIRECTORIES
        ${X11_Xmu_INCLUDE_PATH}
        ${X11_INCLUDE_DIR}
        )
set(LIBRARIES
        ${X11_Xmu_LIB}
        ${X11_LIBRARIES}
        )
add_executable(att main.cpp)
target_include_directories(att PRIVATE ${INCLUDE_DIRECTORIES})
target_link_libraries(att ${LIBRARIES})
UPD Причём для Brave всё работает нормально:
total time spent: 0 minutes
brave-browser : 29s
        Input/output with files - C++ Tutorials - Brave : 4s
        SQLite Documentation - Brave : 3s
        c++ 20 write to file - Поиск в Google - Brave : 14s
        nomeata/arbtt: arbtt, the automatic rule-based time-tracker - Brave : 2s
        тест тест тест - Поиск в Google - Brave : 6s
konsole : 22s
        cmake-build-debug : att : 15s
        cmake-build-debug : tail : 7s
        cmake-build-debug : zsh : 0s



