Решил написать пет проект, 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