Skip to content

Instantly share code, notes, and snippets.

@technic
Created February 5, 2022 20:36
Show Gist options
  • Save technic/c14b01da6642fe7ad4b5e705e793db1e to your computer and use it in GitHub Desktop.
Save technic/c14b01da6642fe7ad4b5e705e793db1e to your computer and use it in GitHub Desktop.
AppInfo hacks
#pragma once
#include <filesystem>
#include <fstream>
#include <giomm/desktopappinfo.h>
#include <glibmm/keyfile.h>
#include <fmt/core.h>
#include <spdlog/spdlog.h>
#include "util/string.hpp"
#include "util/format.hpp"
/** Utilities for
*
*/
namespace waybar::AppInfoProvider {
using AppInfo = Glib::RefPtr<Gio::DesktopAppInfo>;
// snap logic taken from
// https://gitlab.gnome.org/GNOME/mutter/-/blob/main/src/core/window.c#L867-L915
// BAMF_DESKTOP_FILE_HINT logic taken from
// https://invent.kde.org/plasma/plasma-workspace/-/blob/master/libnotificationmanager/utils.cpp#L82-99
// flatpak logic taken from
// https://gitlab.com/carbonOS/gde/gde-panel/-/blob/master/panel/appsys.vala#L59-L76
// https://invent.kde.org/plasma/plasma-workspace/-/blob/master/libnotificationmanager/utils.cpp#L69-80
/**
* @brief Find desktop file for process running in snap container
*
* Tries to read profile name from the security attributes of the process and find a .dekstop file with the matching name
* @param pid process id
* @return info from the matched desktop file, null when not found
*/
AppInfo get_app_info_from_snap(uint32_t pid) {
using namespace std::literals;
// Example of the content for firefox snap on ubuntu 21.10:
// snap.firefox.firefox (enforce)
// We want to lookup:
// firefox_firefox.desktop
std::ifstream f{fmt::format("/proc/{}/attr/current", pid)};
std::string data;
if(!std::getline(f, data)) {
return {};
};
constexpr auto SNAP_PREFIX = "snap."sv;
if (!starts_with(data, SNAP_PREFIX)) {
return {};
}
data = data.substr(SNAP_PREFIX.size(), data.find(' ') - SNAP_PREFIX.size());
std::replace(data.begin(), data.end(), '.', '_');
return Gio::DesktopAppInfo::create(data + ".desktop");
}
/**
* @brief Find desktop file for process based on BAMF_DESKTOP_FILE_HINT environment variable
* @param pid process id
* @return info from matched desktop file, null when not found
*/
AppInfo get_app_info_from_bamf_env(uint32_t pid) {
using namespace std::literals;
constexpr auto ENV_PREFIX = "BAMF_DESKTOP_FILE_HINT="sv;
std::ifstream f{fmt::format("/proc/{}/environ", pid)};
std::string data;
while (std::getline(f, data, '\0')) {
if (starts_with(data, ENV_PREFIX)) {
data = data.substr(ENV_PREFIX.size());
return Gio::DesktopAppInfo::create_from_filename(data);
}
}
return {};
}
/**
* @brief Find desktop file for process by looking for .flatpak-info file in the process's root
* @param pid process id
* @return info from matched desktop file, null when not found
*/
AppInfo get_app_info_from_flatpak(uint32_t pid) {
namespace fs = std::filesystem;
fs::path flatpakInfo{fmt::format("/proc/{}/root/.flatpak-info", pid)};
try {
if (!fs::is_regular_file(flatpakInfo)) {
return {};
}
} catch (const std::exception&e) {
spdlog::error("fs error: {}", e.what());
}
Glib::KeyFile keyFile;
try {
keyFile.load_from_file(flatpakInfo);
auto appName = keyFile.get_string("Application", "name");
return Gio::DesktopAppInfo::create(appName + ".desktop");
} catch (const Glib::Error& e) {
spdlog::error("Keyfile load failed {}", e.what());
return {};
}
}
}; // namespace waybar::AppInfoProvider
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment