mirror of
https://github.com/hyprwm/Hyprland
synced 2026-05-07 06:58:04 +02:00
Merge branch 'hyprwm:main' into main
This commit is contained in:
commit
f4249c192b
22 changed files with 492 additions and 391 deletions
|
|
@ -588,6 +588,28 @@ TEST_CASE(issue14038) {
|
|||
// this should not crash hyprland. If we are alive, we good.
|
||||
}
|
||||
|
||||
TEST_CASE(specialFloatRecenters) {
|
||||
if (!spawnKitty("kitty_special_float_recenter"))
|
||||
FAIL_TEST("Could not spawn kitty");
|
||||
|
||||
OK(getFromSocket("/dispatch hl.dsp.window.float({ action = 'set', window = 'class:kitty_special_float_recenter' })"));
|
||||
OK(getFromSocket("/dispatch hl.dsp.window.resize({ x = 10, y = 10, window = 'class:kitty_special_float_recenter' })"));
|
||||
OK(getFromSocket("/dispatch hl.dsp.window.move({ workspace = 'special:recenter', follow = false, window = 'class:kitty_special_float_recenter' })"));
|
||||
OK(getFromSocket("/dispatch hl.dsp.window.move({ x = 50000, y = 50000, window = 'class:kitty_special_float_recenter' })"));
|
||||
|
||||
OK(getFromSocket("/dispatch hl.dsp.workspace.toggle_special('recenter')"));
|
||||
OK(getFromSocket("/dispatch hl.dsp.focus({ window = 'class:kitty_special_float_recenter' })"));
|
||||
|
||||
const auto active = getFromSocket("/activewindow");
|
||||
EXPECT_CONTAINS(active, "class: kitty_special_float_recenter");
|
||||
EXPECT_CONTAINS(active, "size: 10,10");
|
||||
EXPECT_CONTAINS(active, "at: 955,535");
|
||||
|
||||
OK(getFromSocket("/dispatch hl.dsp.workspace.toggle_special('recenter')"));
|
||||
Tests::killAllWindows();
|
||||
ASSERT(Tests::windowCount(), 0);
|
||||
}
|
||||
|
||||
// TODO: decompose this into multiple test cases
|
||||
TEST_CASE(windows) {
|
||||
// test on workspace "window"
|
||||
|
|
|
|||
|
|
@ -793,6 +793,7 @@ local __HL_API = {}
|
|||
---@field force_renderer_reload fun(...): any
|
||||
---@field global fun(...): any
|
||||
---@field layout fun(...): any
|
||||
---@field no_op fun(...): any
|
||||
---@field pass fun(...): any
|
||||
---@field send_key_state fun(...): any
|
||||
---@field send_shortcut fun(...): any
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "desktop/history/WorkspaceHistoryTracker.hpp"
|
||||
#include "desktop/view/Group.hpp"
|
||||
#include "helpers/Splashes.hpp"
|
||||
#include "helpers/SystemInfo.hpp"
|
||||
#include "config/ConfigValue.hpp"
|
||||
#include "config/legacy/ConfigManager.hpp"
|
||||
#include "config/shared/inotify/ConfigWatcher.hpp"
|
||||
|
|
@ -232,26 +233,7 @@ CCompositor::CCompositor(bool onlyConfig) : m_onlyConfigVerification(onlyConfig)
|
|||
|
||||
Log::logger->initIS(m_instancePath);
|
||||
|
||||
Log::logger->log(Log::DEBUG, "Instance Signature: {}", m_instanceSignature);
|
||||
|
||||
Log::logger->log(Log::DEBUG, "Runtime directory: {}", m_instancePath);
|
||||
|
||||
Log::logger->log(Log::DEBUG, "Hyprland PID: {}", m_hyprlandPID);
|
||||
|
||||
Log::logger->log(Log::DEBUG, "===== SYSTEM INFO: =====");
|
||||
|
||||
logSystemInfo();
|
||||
|
||||
Log::logger->log(Log::DEBUG, "========================");
|
||||
|
||||
Log::logger->log(Log::DEBUG, "\n\n"); // pad
|
||||
|
||||
Log::logger->log(Log::INFO, "If you are crashing, or encounter any bugs, please consult https://wiki.hypr.land/Crashes-and-Bugs/\n\n");
|
||||
|
||||
setRandomSplash();
|
||||
|
||||
Log::logger->log(Log::DEBUG, "\nCurrent splash: {}\n\n", m_currentSplash);
|
||||
|
||||
bumpNofile();
|
||||
}
|
||||
|
||||
|
|
@ -365,6 +347,16 @@ void CCompositor::initServer(std::string socketName, int socketFd) {
|
|||
|
||||
m_initialized = true;
|
||||
|
||||
Log::logger->log(Log::DEBUG, "Instance Signature: {}", m_instanceSignature);
|
||||
Log::logger->log(Log::DEBUG, "Runtime directory: {}", m_instancePath);
|
||||
Log::logger->log(Log::DEBUG, "Hyprland PID: {}", m_hyprlandPID);
|
||||
Log::logger->log(Log::DEBUG, "===== SYSTEM INFO: =====");
|
||||
Log::logger->log(Log::DEBUG, "{}", Helpers::SystemInfo::getSystemInfo());
|
||||
Log::logger->log(Log::DEBUG, "========================");
|
||||
Log::logger->log(Log::DEBUG, "\n\n"); // pad
|
||||
Log::logger->log(Log::INFO, "If you are crashing, or encounter any bugs, please consult https://wiki.hypr.land/Crashes-and-Bugs/\n\n");
|
||||
Log::logger->log(Log::DEBUG, "\nCurrent splash: {}\n\n", m_currentSplash);
|
||||
|
||||
m_drm.fd = m_aqBackend->drmFD();
|
||||
Log::logger->log(Log::DEBUG, "Running on DRMFD: {}", m_drm.fd);
|
||||
|
||||
|
|
@ -1699,7 +1691,7 @@ WORKSPACEID CCompositor::getNextAvailableNamedWorkspace() {
|
|||
|
||||
// Give priority to persistent workspaces to avoid any conflicts between them.
|
||||
for (auto const& rule : Config::workspaceRuleMgr()->getAllWorkspaceRules()) {
|
||||
if (!rule.m_isPersistent)
|
||||
if (!rule.m_isPersistent.value_or(false))
|
||||
continue;
|
||||
if (rule.m_workspaceId < -1 && rule.m_workspaceId < lowest)
|
||||
lowest = rule.m_workspaceId;
|
||||
|
|
@ -3096,7 +3088,7 @@ void CCompositor::ensurePersistentWorkspacesPresent(const std::vector<Config::CW
|
|||
std::vector<PHLWORKSPACE> persistentFound;
|
||||
|
||||
for (const auto& rule : rules) {
|
||||
if (!rule.m_isPersistent)
|
||||
if (!rule.m_isPersistent.value_or(false))
|
||||
continue;
|
||||
|
||||
PHLWORKSPACE PWORKSPACE = nullptr;
|
||||
|
|
|
|||
|
|
@ -1093,6 +1093,15 @@ static int hlFocus(lua_State* L) {
|
|||
return Internal::configError(L, "hl.focus: unrecognized arguments. Expected one of: direction, monitor, window, urgent_or_last, last");
|
||||
}
|
||||
|
||||
static int dsp_noop(lua_State* L) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hlNoop(lua_State* L) {
|
||||
lua_pushcclosure(L, dsp_noop, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dsp_toggleSpecial(lua_State* L) {
|
||||
std::string name = lua_isnil(L, lua_upvalueindex(1)) ? "" : lua_tostring(L, lua_upvalueindex(1));
|
||||
const auto& [workspaceID, workspaceName, isAutoID] = getWorkspaceIDNameFromString("special:" + name);
|
||||
|
|
@ -1266,6 +1275,7 @@ void Internal::registerDispatcherBindings(lua_State* L) {
|
|||
Internal::setFn(L, "force_renderer_reload", hlForceRendererReload);
|
||||
Internal::setFn(L, "force_idle", hlForceIdle);
|
||||
Internal::setFn(L, "focus", hlFocus);
|
||||
Internal::setFn(L, "no_op", hlNoop);
|
||||
}
|
||||
|
||||
lua_setfield(L, -2, "dsp");
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
using namespace Config;
|
||||
|
||||
void CWorkspaceRule::mergeLeft(const CWorkspaceRule& other) {
|
||||
if (m_monitor.empty())
|
||||
if (!other.m_monitor.empty())
|
||||
m_monitor = other.m_monitor;
|
||||
if (m_workspaceString.empty())
|
||||
m_workspaceString = other.m_workspaceString;
|
||||
|
|
@ -12,10 +12,10 @@ void CWorkspaceRule::mergeLeft(const CWorkspaceRule& other) {
|
|||
if (m_workspaceId == WORKSPACE_INVALID)
|
||||
m_workspaceId = other.m_workspaceId;
|
||||
|
||||
if (other.m_isDefault)
|
||||
m_isDefault = true;
|
||||
if (other.m_isPersistent)
|
||||
m_isPersistent = true;
|
||||
if (other.m_isDefault.has_value())
|
||||
m_isDefault = other.m_isDefault;
|
||||
if (other.m_isPersistent.has_value())
|
||||
m_isPersistent = other.m_isPersistent;
|
||||
if (other.m_gapsIn.has_value())
|
||||
m_gapsIn = other.m_gapsIn;
|
||||
if (other.m_gapsOut.has_value())
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ namespace Config {
|
|||
std::string m_workspaceString = "";
|
||||
std::string m_workspaceName = "";
|
||||
WORKSPACEID m_workspaceId = -1;
|
||||
bool m_isDefault = false;
|
||||
bool m_isPersistent = false;
|
||||
std::optional<bool> m_isDefault;
|
||||
std::optional<bool> m_isPersistent;
|
||||
std::optional<CCssGapData> m_gapsIn;
|
||||
std::optional<CCssGapData> m_gapsOut;
|
||||
std::optional<CCssGapData> m_floatGaps = m_gapsOut;
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ std::string CWorkspaceRuleManager::getDefaultWorkspaceFor(const std::string& nam
|
|||
if (!other->m_enabled)
|
||||
continue;
|
||||
|
||||
if (other->m_isDefault) {
|
||||
if (other->m_isDefault.value_or(false)) {
|
||||
if (other->m_monitor == name)
|
||||
return other->m_workspaceString;
|
||||
if (other->m_monitor.starts_with("desc:")) {
|
||||
|
|
|
|||
|
|
@ -49,9 +49,10 @@ using namespace Hyprutils::OS;
|
|||
#include "../devices/ITouch.hpp"
|
||||
#include "../devices/Tablet.hpp"
|
||||
#include "../protocols/GlobalShortcuts.hpp"
|
||||
#include "debug/log/RollingLogFollow.hpp"
|
||||
#include "config/ConfigManager.hpp"
|
||||
#include "helpers/MiscFunctions.hpp"
|
||||
#include "../debug/log/RollingLogFollow.hpp"
|
||||
#include "../config/ConfigManager.hpp"
|
||||
#include "../helpers/MiscFunctions.hpp"
|
||||
#include "../helpers/SystemInfo.hpp"
|
||||
#include "../desktop/view/LayerSurface.hpp"
|
||||
#include "../desktop/view/Group.hpp"
|
||||
#include "../desktop/rule/Engine.hpp"
|
||||
|
|
@ -507,8 +508,8 @@ static std::string getWorkspaceRuleData(const Config::CWorkspaceRule& r, eHyprCt
|
|||
const auto boolToString = [](const bool b) -> std::string { return b ? "true" : "false"; };
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
|
||||
const std::string monitor = r.m_monitor.empty() ? "" : std::format(",\n \"monitor\": \"{}\"", escapeJSONStrings(r.m_monitor));
|
||||
const std::string default_ = sc<bool>(r.m_isDefault) ? std::format(",\n \"default\": {}", boolToString(r.m_isDefault)) : "";
|
||||
const std::string persistent = sc<bool>(r.m_isPersistent) ? std::format(",\n \"persistent\": {}", boolToString(r.m_isPersistent)) : "";
|
||||
const std::string default_ = sc<bool>(r.m_isDefault) ? std::format(",\n \"default\": {}", boolToString(r.m_isDefault.value())) : "";
|
||||
const std::string persistent = sc<bool>(r.m_isPersistent) ? std::format(",\n \"persistent\": {}", boolToString(r.m_isPersistent.value())) : "";
|
||||
const std::string gapsIn = sc<bool>(r.m_gapsIn) ?
|
||||
std::format(",\n \"gapsIn\": [{}, {}, {}, {}]", r.m_gapsIn.value().m_top, r.m_gapsIn.value().m_right, r.m_gapsIn.value().m_bottom, r.m_gapsIn.value().m_left) :
|
||||
"";
|
||||
|
|
@ -531,8 +532,8 @@ static std::string getWorkspaceRuleData(const Config::CWorkspaceRule& r, eHyprCt
|
|||
return result;
|
||||
} else {
|
||||
const std::string monitor = std::format("\tmonitor: {}\n", r.m_monitor.empty() ? "<unset>" : escapeJSONStrings(r.m_monitor));
|
||||
const std::string default_ = std::format("\tdefault: {}\n", sc<bool>(r.m_isDefault) ? boolToString(r.m_isDefault) : "<unset>");
|
||||
const std::string persistent = std::format("\tpersistent: {}\n", sc<bool>(r.m_isPersistent) ? boolToString(r.m_isPersistent) : "<unset>");
|
||||
const std::string default_ = std::format("\tdefault: {}\n", sc<bool>(r.m_isDefault) ? boolToString(r.m_isDefault.value()) : "<unset>");
|
||||
const std::string persistent = std::format("\tpersistent: {}\n", sc<bool>(r.m_isPersistent) ? boolToString(r.m_isPersistent.value()) : "<unset>");
|
||||
const std::string gapsIn = sc<bool>(r.m_gapsIn) ?
|
||||
std::format("\tgapsIn: {} {} {} {}\n", std::to_string(r.m_gapsIn.value().m_top), std::to_string(r.m_gapsIn.value().m_right),
|
||||
std::to_string(r.m_gapsIn.value().m_bottom), std::to_string(r.m_gapsIn.value().m_left)) :
|
||||
|
|
@ -1061,193 +1062,19 @@ static std::string bindsRequest(eHyprCtlOutputFormat format, std::string request
|
|||
}
|
||||
|
||||
std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
return Helpers::SystemInfo::getVersion(format);
|
||||
}
|
||||
|
||||
auto commitMsg = trim(GIT_COMMIT_MESSAGE);
|
||||
std::ranges::replace(commitMsg, '#', ' ');
|
||||
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
|
||||
std::string result = std::format("Hyprland {} built from branch {} at commit {} {} ({}).\n"
|
||||
"Date: {}\n"
|
||||
"Tag: {}, commits: {}\n",
|
||||
HYPRLAND_VERSION, GIT_BRANCH, GIT_COMMIT_HASH, GIT_DIRTY, commitMsg, GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS);
|
||||
|
||||
result += "\n";
|
||||
result += getBuiltSystemLibraryNames();
|
||||
result += "\n";
|
||||
result += "Version ABI string: ";
|
||||
result += __hyprland_api_get_hash();
|
||||
result += "\n";
|
||||
|
||||
#if (!ISDEBUG && !defined(NO_XWAYLAND) && !defined(BUILT_WITH_NIX))
|
||||
result += "no flags were set\n";
|
||||
#else
|
||||
result += "flags set:\n";
|
||||
#if ISDEBUG
|
||||
result += "debug\n";
|
||||
#endif
|
||||
#ifdef NO_XWAYLAND
|
||||
result += "no xwayland\n";
|
||||
#endif
|
||||
#ifdef BUILT_WITH_NIX
|
||||
result += "nix\n";
|
||||
#endif
|
||||
#endif
|
||||
return result;
|
||||
} else {
|
||||
std::string result = std::format(
|
||||
R"#({{
|
||||
"branch": "{}",
|
||||
"commit": "{}",
|
||||
"version": "{}",
|
||||
"dirty": {},
|
||||
"commit_message": "{}",
|
||||
"commit_date": "{}",
|
||||
"tag": "{}",
|
||||
"commits": "{}",
|
||||
"buildAquamarine": "{}",
|
||||
"buildHyprlang": "{}",
|
||||
"buildHyprutils": "{}",
|
||||
"buildHyprcursor": "{}",
|
||||
"buildHyprgraphics": "{}",
|
||||
"systemAquamarine": "{}",
|
||||
"systemHyprlang": "{}",
|
||||
"systemHyprutils": "{}",
|
||||
"systemHyprcursor": "{}",
|
||||
"systemHyprgraphics": "{}",
|
||||
"abiHash": "{}",
|
||||
"flags": [)#",
|
||||
GIT_BRANCH, GIT_COMMIT_HASH, HYPRLAND_VERSION, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG,
|
||||
GIT_COMMITS, AQUAMARINE_VERSION, HYPRLANG_VERSION, HYPRUTILS_VERSION, HYPRCURSOR_VERSION, HYPRGRAPHICS_VERSION, getSystemLibraryVersion("aquamarine"),
|
||||
getSystemLibraryVersion("hyprlang"), getSystemLibraryVersion("hyprutils"), getSystemLibraryVersion("hyprcursor"), getSystemLibraryVersion("hyprgraphics"),
|
||||
__hyprland_api_get_hash());
|
||||
|
||||
#if ISDEBUG
|
||||
result += "\"debug\",";
|
||||
#endif
|
||||
#ifdef NO_XWAYLAND
|
||||
result += "\"no xwayland\",";
|
||||
#endif
|
||||
#ifdef BUILT_WITH_NIX
|
||||
result += "\"nix\",";
|
||||
#endif
|
||||
|
||||
trimTrailingComma(result);
|
||||
|
||||
result += "]\n}";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return ""; // make the compiler happy
|
||||
static std::string statusRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
return Helpers::SystemInfo::getStatus(format);
|
||||
}
|
||||
|
||||
std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string result = versionRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, "");
|
||||
|
||||
static auto check = [](bool y) -> std::string { return y ? "✔️" : "❌"; };
|
||||
static auto backend = [](Aquamarine::eBackendType t) -> std::string {
|
||||
switch (t) {
|
||||
case Aquamarine::AQ_BACKEND_DRM: return "drm";
|
||||
case Aquamarine::AQ_BACKEND_HEADLESS: return "headless";
|
||||
case Aquamarine::AQ_BACKEND_WAYLAND: return "wayland";
|
||||
default: break;
|
||||
}
|
||||
return "?";
|
||||
};
|
||||
|
||||
result += "\n\nSystem Information:\n";
|
||||
|
||||
struct utsname unameInfo;
|
||||
|
||||
uname(&unameInfo);
|
||||
|
||||
result += "System name: " + std::string{unameInfo.sysname} + "\n";
|
||||
result += "Node name: " + std::string{unameInfo.nodename} + "\n";
|
||||
result += "Release: " + std::string{unameInfo.release} + "\n";
|
||||
result += "Version: " + std::string{unameInfo.version} + "\n";
|
||||
result += "\n";
|
||||
result += getBuiltSystemLibraryNames();
|
||||
result += "\n";
|
||||
|
||||
result += "\n\n";
|
||||
|
||||
#if defined(__DragonFly__) || defined(__FreeBSD__)
|
||||
const std::string GPUINFO = execAndGet("pciconf -lv | grep -F -A4 vga");
|
||||
#elif defined(__arm__) || defined(__aarch64__)
|
||||
std::string GPUINFO;
|
||||
const std::filesystem::path dev_tree = "/proc/device-tree";
|
||||
try {
|
||||
if (std::filesystem::exists(dev_tree) && std::filesystem::is_directory(dev_tree)) {
|
||||
std::for_each(std::filesystem::directory_iterator(dev_tree), std::filesystem::directory_iterator{}, [&](const std::filesystem::directory_entry& entry) {
|
||||
if (std::filesystem::is_directory(entry) && entry.path().filename().string().starts_with("soc")) {
|
||||
std::for_each(std::filesystem::directory_iterator(entry.path()), std::filesystem::directory_iterator{}, [&](const std::filesystem::directory_entry& sub_entry) {
|
||||
if (std::filesystem::is_directory(sub_entry) && sub_entry.path().filename().string().starts_with("gpu")) {
|
||||
std::filesystem::path file_path = sub_entry.path() / "compatible";
|
||||
std::ifstream file(file_path);
|
||||
if (file)
|
||||
GPUINFO.append(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (...) { GPUINFO = "error"; }
|
||||
#else
|
||||
const std::string GPUINFO = execAndGet("lspci -vnn | grep -E '(VGA|Display|3D)'");
|
||||
#endif
|
||||
result += "GPU information: \n" + GPUINFO;
|
||||
if (GPUINFO.contains("NVIDIA") && std::filesystem::exists("/proc/driver/nvidia/version")) {
|
||||
std::ifstream file("/proc/driver/nvidia/version");
|
||||
std::string line;
|
||||
if (file.is_open()) {
|
||||
while (std::getline(file, line)) {
|
||||
if (!line.contains("NVRM"))
|
||||
continue;
|
||||
result += line;
|
||||
result += "\n";
|
||||
}
|
||||
} else
|
||||
result += "error";
|
||||
}
|
||||
result += "\n\n";
|
||||
|
||||
if (std::ifstream file("/etc/os-release"); file.is_open()) {
|
||||
std::stringstream buffer;
|
||||
buffer << file.rdbuf();
|
||||
result += "os-release: " + buffer.str() + "\n\n";
|
||||
} else
|
||||
result += "os-release: error\n\n";
|
||||
|
||||
result += "plugins:\n";
|
||||
if (g_pPluginSystem) {
|
||||
for (auto const& pl : g_pPluginSystem->getAllPlugins()) {
|
||||
result += std::format(" {} by {} ver {}\n", pl->m_name, pl->m_author, pl->m_version);
|
||||
}
|
||||
} else
|
||||
result += "\tunknown: not runtime\n";
|
||||
|
||||
if (g_pHyprOpenGL) {
|
||||
result += std::format("\nExplicit sync: {}", g_pHyprOpenGL->m_exts.EGL_ANDROID_native_fence_sync_ext ? "supported" : "missing");
|
||||
result += std::format("\nGL ver: {}", g_pHyprOpenGL->m_eglContextVersion == CHyprOpenGLImpl::EGL_CONTEXT_GLES_3_2 ? "3.2" : "3.0");
|
||||
}
|
||||
|
||||
if (g_pCompositor) {
|
||||
result += std::format("\nBackend: {}", g_pCompositor->m_aqBackend->hasSession() ? "drm" : "sessionless");
|
||||
|
||||
result += "\n\nMonitor info:";
|
||||
|
||||
for (const auto& m : g_pCompositor->m_monitors) {
|
||||
result += std::format("\n\tPanel {}: {}x{}, {} {} {} {} -> backend {}\n\t\texplicit {}\n\t\tedid:\n\t\t\thdr {}\n\t\t\tchroma {}\n\t\t\tbt2020 {}\n\t\tvrr capable "
|
||||
"{}\n\t\tnon-desktop {}\n\t\t",
|
||||
m->m_name, sc<int>(m->m_pixelSize.x), sc<int>(m->m_pixelSize.y), m->m_output->name, m->m_output->make, m->m_output->model, m->m_output->serial,
|
||||
backend(m->m_output->getBackend()->type()), check(m->m_output->supportsExplicit), check(m->m_output->parsedEDID.hdrMetadata.has_value()),
|
||||
check(m->m_output->parsedEDID.chromaticityCoords.has_value()), check(m->m_output->parsedEDID.supportsBT2020), check(m->m_output->vrrCapable),
|
||||
check(m->m_output->nonDesktop));
|
||||
}
|
||||
}
|
||||
auto result = Helpers::SystemInfo::getSystemInfo();
|
||||
|
||||
if (g_pHyprCtl && g_pHyprCtl->m_currentRequestParams.sysInfoConfig) {
|
||||
result += "\n======Config-Start======\n";
|
||||
result += "\n\n======Config-Start======\n";
|
||||
result += Config::mgr()->getConfigString();
|
||||
result += "\n======Config-End========\n";
|
||||
}
|
||||
|
|
@ -2097,43 +1924,6 @@ static std::string submapRequest(eHyprCtlOutputFormat format, std::string reques
|
|||
return format == FORMAT_JSON ? std::format("\"{}\"\n", escapeJSONStrings(submap)) : (submap + "\n");
|
||||
}
|
||||
|
||||
static std::string statusRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
Aquamarine::eBackendType backendType = Aquamarine::eBackendType::AQ_BACKEND_NULL;
|
||||
|
||||
for (const auto& i : g_pCompositor->m_aqBackend->getImplementations()) {
|
||||
if (i->type() == Aquamarine::eBackendType::AQ_BACKEND_NULL || i->type() == Aquamarine::eBackendType::AQ_BACKEND_HEADLESS)
|
||||
continue;
|
||||
|
||||
backendType = i->type();
|
||||
break;
|
||||
}
|
||||
|
||||
std::string backendStr;
|
||||
|
||||
switch (backendType) {
|
||||
case Aquamarine::AQ_BACKEND_DRM: backendStr = "drm"; break;
|
||||
case Aquamarine::AQ_BACKEND_WAYLAND: backendStr = "wayland"; break;
|
||||
default: backendStr = "error"; break;
|
||||
}
|
||||
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
|
||||
|
||||
return std::format(R"#(
|
||||
{{
|
||||
"configProvider": "{}",
|
||||
"backend": "{}"
|
||||
}}
|
||||
)#",
|
||||
Config::typeToString(Config::mgr()->type()), backendStr);
|
||||
}
|
||||
|
||||
return std::format(R"#(
|
||||
configProvider: {}
|
||||
backend: {}
|
||||
)#",
|
||||
Config::typeToString(Config::mgr()->type()), backendStr);
|
||||
}
|
||||
|
||||
static std::string reloadShaders(eHyprCtlOutputFormat format, std::string request) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ void CWorkspace::init(PHLWORKSPACE self) {
|
|||
m_inert = false;
|
||||
|
||||
const auto WORKSPACERULE = Config::workspaceRuleMgr()->getWorkspaceRuleFor(self).value_or(Config::CWorkspaceRule{});
|
||||
setPersistent(WORKSPACERULE.m_isPersistent);
|
||||
setPersistent(WORKSPACERULE.m_isPersistent.value_or(false));
|
||||
|
||||
if (self->m_wasCreatedEmpty)
|
||||
if (auto cmd = WORKSPACERULE.m_onCreatedEmptyRunCmd)
|
||||
|
|
@ -517,9 +517,9 @@ void CWorkspace::rename(const std::string& name) {
|
|||
m_name = name;
|
||||
|
||||
const auto WORKSPACERULE = Config::workspaceRuleMgr()->getWorkspaceRuleFor(m_self.lock()).value_or(Config::CWorkspaceRule{});
|
||||
setPersistent(WORKSPACERULE.m_isPersistent);
|
||||
setPersistent(WORKSPACERULE.m_isPersistent.value_or(false));
|
||||
|
||||
if (WORKSPACERULE.m_isPersistent)
|
||||
if (WORKSPACERULE.m_isPersistent.value_or(false))
|
||||
g_pCompositor->ensurePersistentWorkspacesPresent(std::vector<Config::CWorkspaceRule>{WORKSPACERULE}, m_self.lock());
|
||||
|
||||
g_pEventManager->postEvent({.event = "renameworkspace", .data = std::to_string(m_id) + "," + m_name});
|
||||
|
|
|
|||
|
|
@ -523,54 +523,6 @@ std::string execAndGet(const char* cmd) {
|
|||
return proc.stdOut();
|
||||
}
|
||||
|
||||
void logSystemInfo() {
|
||||
struct utsname unameInfo;
|
||||
|
||||
uname(&unameInfo);
|
||||
|
||||
Log::logger->log(Log::DEBUG, "System name: {}", std::string{unameInfo.sysname});
|
||||
Log::logger->log(Log::DEBUG, "Node name: {}", std::string{unameInfo.nodename});
|
||||
Log::logger->log(Log::DEBUG, "Release: {}", std::string{unameInfo.release});
|
||||
Log::logger->log(Log::DEBUG, "Version: {}", std::string{unameInfo.version});
|
||||
|
||||
Log::logger->log(Log::DEBUG, "\n");
|
||||
|
||||
#if defined(__DragonFly__) || defined(__FreeBSD__)
|
||||
const std::string GPUINFO = execAndGet("pciconf -lv | grep -F -A4 vga");
|
||||
#elif defined(__arm__) || defined(__aarch64__)
|
||||
std::string GPUINFO;
|
||||
const std::filesystem::path dev_tree = "/proc/device-tree";
|
||||
try {
|
||||
if (std::filesystem::exists(dev_tree) && std::filesystem::is_directory(dev_tree)) {
|
||||
std::for_each(std::filesystem::directory_iterator(dev_tree), std::filesystem::directory_iterator{}, [&](const std::filesystem::directory_entry& entry) {
|
||||
if (std::filesystem::is_directory(entry) && entry.path().filename().string().starts_with("soc")) {
|
||||
std::for_each(std::filesystem::directory_iterator(entry.path()), std::filesystem::directory_iterator{}, [&](const std::filesystem::directory_entry& sub_entry) {
|
||||
if (std::filesystem::is_directory(sub_entry) && sub_entry.path().filename().string().starts_with("gpu")) {
|
||||
std::filesystem::path file_path = sub_entry.path() / "compatible";
|
||||
std::ifstream file(file_path);
|
||||
if (file)
|
||||
GPUINFO.append(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (...) { GPUINFO = "error"; }
|
||||
#else
|
||||
const std::string GPUINFO = execAndGet("lspci -vnn | grep -E '(VGA|Display|3D)'");
|
||||
#endif
|
||||
Log::logger->log(Log::DEBUG, "GPU information:\n{}\n", GPUINFO);
|
||||
|
||||
if (GPUINFO.contains("NVIDIA")) {
|
||||
Log::logger->log(Log::WARN, "Warning: you're using an NVIDIA GPU. Make sure you follow the instructions on the wiki if anything is amiss.\n");
|
||||
}
|
||||
|
||||
// log etc
|
||||
Log::logger->log(Log::DEBUG, "os-release:");
|
||||
|
||||
Log::logger->log(Log::DEBUG, "{}", NFsUtils::readFileAsString("/etc/os-release").value_or("error"));
|
||||
}
|
||||
|
||||
int64_t getPPIDof(int64_t pid) {
|
||||
#if defined(KERN_PROC_PID)
|
||||
int mib[] = {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ bool isDirection(const char&);
|
|||
SWorkspaceIDName getWorkspaceIDNameFromString(const std::string&);
|
||||
std::optional<std::string> cleanCmdForWorkspace(const std::string&, std::string);
|
||||
float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2);
|
||||
void logSystemInfo();
|
||||
std::string execAndGet(const char*);
|
||||
int64_t getPPIDof(int64_t pid);
|
||||
std::expected<int64_t, std::string> configStringToInt(const std::string&);
|
||||
|
|
|
|||
|
|
@ -1564,7 +1564,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
|
|||
if (VECNOTINRECT(MIDDLE, PMONFROMMIDDLE->m_position.x, PMONFROMMIDDLE->m_position.y, PMONFROMMIDDLE->m_position.x + PMONFROMMIDDLE->m_size.x,
|
||||
PMONFROMMIDDLE->m_position.y + PMONFROMMIDDLE->m_size.y)) {
|
||||
// not on any monitor, center
|
||||
pos = middle() / 2.f - w->m_realSize->goal() / 2.f;
|
||||
pos = middle() - w->m_realSize->goal() / 2.f;
|
||||
} else
|
||||
pos = pos - PMONFROMMIDDLE->m_position + m_position;
|
||||
|
||||
|
|
|
|||
|
|
@ -58,49 +58,22 @@ namespace NSplashes {
|
|||
"Thanks ThatOneCalculator!",
|
||||
"The AUR packages always work, except for the times they don't.",
|
||||
"Funny animation compositor woo",
|
||||
"3 years!",
|
||||
"4 years!",
|
||||
"Beauty will save the world", // 4th ricing comp winner - zacoons' choice
|
||||
// music reference / quote section
|
||||
"J'remue le ciel, le jour, la nuit.",
|
||||
"aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi!",
|
||||
"Wir sind schon sehr lang zusammen...",
|
||||
"I see a red door and I want it painted black.",
|
||||
"Take on me, take me on...",
|
||||
"You spin me right round baby right round",
|
||||
"Stayin' alive, stayin' alive",
|
||||
"Say no way, say no way ya, no way!",
|
||||
"Ground control to Major Tom...",
|
||||
"Alors on danse",
|
||||
"And all that I can see, is just a yellow lemon tree.",
|
||||
"Got a one-way ticket to the blues",
|
||||
"Is this the real life, is this just fantasy",
|
||||
"What's in your head, in your head?",
|
||||
"We're all living in America, America, America.",
|
||||
"I'm still standing, better than I ever did",
|
||||
"Here comes the sun, bringing you love and shining on everyone",
|
||||
"Two trailer park girls go round the outside",
|
||||
"With the lights out, it's less dangerous",
|
||||
"Here we go back, this is the moment, tonight is the night",
|
||||
"Now you're just somebody that I used to know...",
|
||||
"Black bird, black moon, black sky",
|
||||
"Some legends are told, some turn to dust or to gold",
|
||||
"Your brain gets smart, but your head gets dumb.",
|
||||
"Save your mercy for someone who needs it more",
|
||||
"You're gonna hear my voice when I shout it out loud",
|
||||
"Ding ding pch n daa, bam-ba-ba-re-bam baram bom bom baba-bam-bam-bommm",
|
||||
"Súbeme la radio que esta es mi canción",
|
||||
"I'm beggin', beggin' you",
|
||||
"Never gonna let you down (I am trying!)",
|
||||
"Hier kommt die Sonne",
|
||||
"Kickstart my heart, give it a start",
|
||||
"Fear of the dark, I have a constant fear that something's always near",
|
||||
"Komm mit, reih dich ein.",
|
||||
"I wish I had an angel for one moment of love",
|
||||
"We're the children of the dark",
|
||||
"You float like a feather, in a beautiful world",
|
||||
"Demons come at night and they bring the end",
|
||||
"All I wanna say is that they don't really care about us",
|
||||
"Has he lost his mind? Can he see or is he blind?",
|
||||
"Configration",
|
||||
"RIP hyprlang",
|
||||
"better call vaxry",
|
||||
"i hypr therefore i land",
|
||||
"five. hundred. config errors.",
|
||||
"bundled with anime girls for your convenience",
|
||||
"now with 200% more hypr and land",
|
||||
"daily dose of rice",
|
||||
"Removed Herobrine",
|
||||
"You should try quickshell!",
|
||||
"He was an X11 boy, she was a Wayland girl...",
|
||||
"How do I exit vim????",
|
||||
"Now with lua, it might as well be awesome.",
|
||||
"Have you ran your daily fastfetch yet?"
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
|
|
|
|||
257
src/helpers/SystemInfo.cpp
Normal file
257
src/helpers/SystemInfo.cpp
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
#include "SystemInfo.hpp"
|
||||
|
||||
#include "../Compositor.hpp"
|
||||
#include "../version.h"
|
||||
#include "../plugins/PluginAPI.hpp"
|
||||
#include "../plugins/PluginSystem.hpp"
|
||||
#include "../render/OpenGL.hpp"
|
||||
#include "../config/ConfigManager.hpp"
|
||||
|
||||
#include <hyprutils/string/String.hpp>
|
||||
|
||||
#include <sys/utsname.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <format>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace Helpers::SystemInfo;
|
||||
using namespace Helpers;
|
||||
using namespace Hyprutils::String;
|
||||
using namespace Render::GL;
|
||||
|
||||
static void trimTrailingComma(std::string& str) {
|
||||
if (!str.empty() && str.back() == ',')
|
||||
str.pop_back();
|
||||
}
|
||||
|
||||
std::string SystemInfo::getStatus(eHyprCtlOutputFormat fmt) {
|
||||
Aquamarine::eBackendType backendType = Aquamarine::eBackendType::AQ_BACKEND_NULL;
|
||||
|
||||
for (const auto& i : g_pCompositor->m_aqBackend->getImplementations()) {
|
||||
if (i->type() == Aquamarine::eBackendType::AQ_BACKEND_NULL || i->type() == Aquamarine::eBackendType::AQ_BACKEND_HEADLESS)
|
||||
continue;
|
||||
|
||||
backendType = i->type();
|
||||
break;
|
||||
}
|
||||
|
||||
std::string backendStr;
|
||||
|
||||
switch (backendType) {
|
||||
case Aquamarine::AQ_BACKEND_DRM: backendStr = "drm"; break;
|
||||
case Aquamarine::AQ_BACKEND_WAYLAND: backendStr = "wayland"; break;
|
||||
default: backendStr = "error"; break;
|
||||
}
|
||||
|
||||
if (fmt == eHyprCtlOutputFormat::FORMAT_JSON) {
|
||||
|
||||
return std::format(R"#(
|
||||
{{
|
||||
"configProvider": "{}",
|
||||
"backend": "{}"
|
||||
}}
|
||||
)#",
|
||||
Config::typeToString(Config::mgr()->type()), backendStr);
|
||||
}
|
||||
|
||||
return std::format(R"#(
|
||||
configProvider: {}
|
||||
backend: {}
|
||||
)#",
|
||||
Config::typeToString(Config::mgr()->type()), backendStr);
|
||||
}
|
||||
|
||||
std::string SystemInfo::getVersion(eHyprCtlOutputFormat fmt) {
|
||||
|
||||
auto commitMsg = trim(GIT_COMMIT_MESSAGE);
|
||||
std::ranges::replace(commitMsg, '#', ' ');
|
||||
|
||||
if (fmt == eHyprCtlOutputFormat::FORMAT_NORMAL) {
|
||||
std::string result = std::format("Hyprland {} built from branch {} at commit {} {} ({}).\n"
|
||||
"Date: {}\n"
|
||||
"Tag: {}, commits: {}\n",
|
||||
HYPRLAND_VERSION, GIT_BRANCH, GIT_COMMIT_HASH, GIT_DIRTY, commitMsg, GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS);
|
||||
|
||||
result += "\n";
|
||||
result += getBuiltSystemLibraryNames();
|
||||
result += "\n";
|
||||
result += "Version ABI string: ";
|
||||
result += __hyprland_api_get_hash();
|
||||
result += "\n";
|
||||
|
||||
#if (!ISDEBUG && !defined(NO_XWAYLAND) && !defined(BUILT_WITH_NIX))
|
||||
result += "no flags were set\n";
|
||||
#else
|
||||
result += "flags set:\n";
|
||||
#if ISDEBUG
|
||||
result += "debug\n";
|
||||
#endif
|
||||
#ifdef NO_XWAYLAND
|
||||
result += "no xwayland\n";
|
||||
#endif
|
||||
#ifdef BUILT_WITH_NIX
|
||||
result += "nix\n";
|
||||
#endif
|
||||
#endif
|
||||
return result;
|
||||
} else {
|
||||
std::string result = std::format(
|
||||
R"#({{
|
||||
"branch": "{}",
|
||||
"commit": "{}",
|
||||
"version": "{}",
|
||||
"dirty": {},
|
||||
"commit_message": "{}",
|
||||
"commit_date": "{}",
|
||||
"tag": "{}",
|
||||
"commits": "{}",
|
||||
"buildAquamarine": "{}",
|
||||
"buildHyprlang": "{}",
|
||||
"buildHyprutils": "{}",
|
||||
"buildHyprcursor": "{}",
|
||||
"buildHyprgraphics": "{}",
|
||||
"systemAquamarine": "{}",
|
||||
"systemHyprlang": "{}",
|
||||
"systemHyprutils": "{}",
|
||||
"systemHyprcursor": "{}",
|
||||
"systemHyprgraphics": "{}",
|
||||
"abiHash": "{}",
|
||||
"flags": [)#",
|
||||
GIT_BRANCH, GIT_COMMIT_HASH, HYPRLAND_VERSION, (GIT_DIRTY == std::string_view{"dirty"} ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG,
|
||||
GIT_COMMITS, AQUAMARINE_VERSION, HYPRLANG_VERSION, HYPRUTILS_VERSION, HYPRCURSOR_VERSION, HYPRGRAPHICS_VERSION, getSystemLibraryVersion("aquamarine"),
|
||||
getSystemLibraryVersion("hyprlang"), getSystemLibraryVersion("hyprutils"), getSystemLibraryVersion("hyprcursor"), getSystemLibraryVersion("hyprgraphics"),
|
||||
__hyprland_api_get_hash());
|
||||
|
||||
#if ISDEBUG
|
||||
result += "\"debug\",";
|
||||
#endif
|
||||
#ifdef NO_XWAYLAND
|
||||
result += "\"no xwayland\",";
|
||||
#endif
|
||||
#ifdef BUILT_WITH_NIX
|
||||
result += "\"nix\",";
|
||||
#endif
|
||||
|
||||
trimTrailingComma(result);
|
||||
|
||||
result += "]\n}";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return ""; // make the compiler happy
|
||||
}
|
||||
|
||||
std::string SystemInfo::getSystemInfo() {
|
||||
std::string result = getVersion(eHyprCtlOutputFormat::FORMAT_NORMAL);
|
||||
|
||||
static auto check = [](bool y) -> std::string { return y ? "✔️" : "❌"; };
|
||||
static auto backend = [](Aquamarine::eBackendType t) -> std::string {
|
||||
switch (t) {
|
||||
case Aquamarine::AQ_BACKEND_DRM: return "drm";
|
||||
case Aquamarine::AQ_BACKEND_HEADLESS: return "headless";
|
||||
case Aquamarine::AQ_BACKEND_WAYLAND: return "wayland";
|
||||
default: break;
|
||||
}
|
||||
return "?";
|
||||
};
|
||||
|
||||
result += "\n\nSystem Information:\n";
|
||||
|
||||
struct utsname unameInfo;
|
||||
|
||||
uname(&unameInfo);
|
||||
|
||||
result += "System name: " + std::string{unameInfo.sysname} + "\n";
|
||||
result += "Node name: " + std::string{unameInfo.nodename} + "\n";
|
||||
result += "Release: " + std::string{unameInfo.release} + "\n";
|
||||
result += "Version: " + std::string{unameInfo.version} + "\n";
|
||||
result += "\n";
|
||||
result += getBuiltSystemLibraryNames();
|
||||
result += "\n";
|
||||
|
||||
result += "\n\n";
|
||||
|
||||
#if defined(__DragonFly__) || defined(__FreeBSD__)
|
||||
const std::string GPUINFO = execAndGet("pciconf -lv | grep -F -A4 vga");
|
||||
#elif defined(__arm__) || defined(__aarch64__)
|
||||
std::string GPUINFO;
|
||||
const std::filesystem::path dev_tree = "/proc/device-tree";
|
||||
try {
|
||||
if (std::filesystem::exists(dev_tree) && std::filesystem::is_directory(dev_tree)) {
|
||||
std::for_each(std::filesystem::directory_iterator(dev_tree), std::filesystem::directory_iterator{}, [&](const std::filesystem::directory_entry& entry) {
|
||||
if (std::filesystem::is_directory(entry) && entry.path().filename().string().starts_with("soc")) {
|
||||
std::for_each(std::filesystem::directory_iterator(entry.path()), std::filesystem::directory_iterator{}, [&](const std::filesystem::directory_entry& sub_entry) {
|
||||
if (std::filesystem::is_directory(sub_entry) && sub_entry.path().filename().string().starts_with("gpu")) {
|
||||
std::filesystem::path file_path = sub_entry.path() / "compatible";
|
||||
std::ifstream file(file_path);
|
||||
if (file)
|
||||
GPUINFO.append(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (...) { GPUINFO = "error"; }
|
||||
#else
|
||||
const std::string GPUINFO = execAndGet("lspci -vnn | grep -E '(VGA|Display|3D)'");
|
||||
#endif
|
||||
result += "GPU information: \n" + GPUINFO;
|
||||
if (GPUINFO.contains("NVIDIA") && std::filesystem::exists("/proc/driver/nvidia/version")) {
|
||||
std::ifstream file("/proc/driver/nvidia/version");
|
||||
std::string line;
|
||||
if (file.is_open()) {
|
||||
while (std::getline(file, line)) {
|
||||
if (!line.contains("NVRM"))
|
||||
continue;
|
||||
result += line;
|
||||
result += "\n";
|
||||
}
|
||||
} else
|
||||
result += "error";
|
||||
}
|
||||
result += "\n\n";
|
||||
|
||||
if (std::ifstream file("/etc/os-release"); file.is_open()) {
|
||||
std::stringstream buffer;
|
||||
buffer << file.rdbuf();
|
||||
result += "os-release: " + buffer.str() + "\n\n";
|
||||
} else
|
||||
result += "os-release: error\n\n";
|
||||
|
||||
result += "plugins:\n";
|
||||
if (g_pPluginSystem) {
|
||||
for (auto const& pl : g_pPluginSystem->getAllPlugins()) {
|
||||
result += std::format(" {} by {} ver {}\n", pl->m_name, pl->m_author, pl->m_version);
|
||||
}
|
||||
} else
|
||||
result += "\tunknown: not runtime\n";
|
||||
|
||||
if (g_pHyprOpenGL) {
|
||||
result += std::format("\nExplicit sync: {}", g_pHyprOpenGL->m_exts.EGL_ANDROID_native_fence_sync_ext ? "supported" : "missing");
|
||||
result += std::format("\nGL ver: {}", g_pHyprOpenGL->m_eglContextVersion == CHyprOpenGLImpl::EGL_CONTEXT_GLES_3_2 ? "3.2" : "3.0");
|
||||
}
|
||||
|
||||
if (g_pCompositor) {
|
||||
result += std::format("\nBackend: {}", g_pCompositor->m_aqBackend->hasSession() ? "drm" : "sessionless");
|
||||
|
||||
result += "\n\nMonitor info:";
|
||||
|
||||
for (const auto& m : g_pCompositor->m_monitors) {
|
||||
result += std::format("\n\tPanel {}: {}x{}, {} {} {} {} -> backend {}\n\t\texplicit {}\n\t\tedid:\n\t\t\thdr {}\n\t\t\tchroma {}\n\t\t\tbt2020 {}\n\t\tvrr capable "
|
||||
"{}\n\t\tnon-desktop {}\n\t\t",
|
||||
m->m_name, sc<int>(m->m_pixelSize.x), sc<int>(m->m_pixelSize.y), m->m_output->name, m->m_output->make, m->m_output->model, m->m_output->serial,
|
||||
backend(m->m_output->getBackend()->type()), check(m->m_output->supportsExplicit), check(m->m_output->parsedEDID.hdrMetadata.has_value()),
|
||||
check(m->m_output->parsedEDID.chromaticityCoords.has_value()), check(m->m_output->parsedEDID.supportsBT2020), check(m->m_output->vrrCapable),
|
||||
check(m->m_output->nonDesktop));
|
||||
}
|
||||
}
|
||||
|
||||
result += "\n\nState:\n";
|
||||
result += getStatus(FORMAT_NORMAL);
|
||||
|
||||
result += "\n\n";
|
||||
|
||||
return result;
|
||||
}
|
||||
11
src/helpers/SystemInfo.hpp
Normal file
11
src/helpers/SystemInfo.hpp
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "../SharedDefs.hpp"
|
||||
|
||||
namespace Helpers::SystemInfo {
|
||||
std::string getSystemInfo();
|
||||
std::string getVersion(eHyprCtlOutputFormat fmt);
|
||||
std::string getStatus(eHyprCtlOutputFormat fmt);
|
||||
};
|
||||
|
|
@ -476,10 +476,12 @@ Config::ErrorResult CMasterAlgorithm::layoutMsg(const std::string_view& sv) {
|
|||
return stateErr("no master node");
|
||||
|
||||
const auto NEWCHILD = PMASTER->pTarget.lock();
|
||||
if (!NEWCHILD)
|
||||
return stateErr("master target expired");
|
||||
|
||||
const bool IGNORE_IF_MASTER = vars.size() >= 2 && std::ranges::any_of(vars, [](const auto& e) { return e == "ignoremaster"; });
|
||||
|
||||
if (PMASTER->pTarget.lock() != PWINDOW->layoutTarget()) {
|
||||
if (NEWCHILD != PWINDOW->layoutTarget()) {
|
||||
const auto& NEWMASTER = PWINDOW->layoutTarget();
|
||||
const bool newFocusToChild = vars.size() >= 2 && vars[1] == "child";
|
||||
g_layoutManager->switchTargets(NEWMASTER, NEWCHILD);
|
||||
|
|
@ -516,8 +518,12 @@ Config::ErrorResult CMasterAlgorithm::layoutMsg(const std::string_view& sv) {
|
|||
|
||||
const auto& ARG = vars[1]; // returns empty string if out of bounds
|
||||
|
||||
if (PMASTER->pTarget.lock() != PWINDOW->layoutTarget()) {
|
||||
switchToWindow(PMASTER->pTarget.lock());
|
||||
const auto TARGET = PMASTER->pTarget.lock();
|
||||
if (!TARGET)
|
||||
return stateErr("master target expired");
|
||||
|
||||
if (TARGET != PWINDOW->layoutTarget()) {
|
||||
switchToWindow(TARGET);
|
||||
// save previously focused window (only for `previous` mode)
|
||||
if (ARG == "previous")
|
||||
m_workspaceData.focusMasterPrev = PWINDOW->layoutTarget();
|
||||
|
|
|
|||
35
src/main.cpp
35
src/main.cpp
|
|
@ -202,8 +202,41 @@ int main(int argc, char** argv) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (!verifyConfig)
|
||||
if (!verifyConfig) {
|
||||
std::println("Welcome to Hyprland!");
|
||||
std::println(R"#(
|
||||
|
||||
YY UJ
|
||||
YYY UUJ
|
||||
XXXY UUUU
|
||||
zXXXX UUUUU
|
||||
zzzzX UUUUJ
|
||||
cczzz UUUUJ
|
||||
vccccz UUUUUJ
|
||||
vvcccc UUUUUJ
|
||||
vvvvv UUUUJ
|
||||
uuuvv UUUUJ
|
||||
uuuuu UUUUU
|
||||
nnnuu UUUUU
|
||||
nnnnn YUUUU
|
||||
xxnn YUUU
|
||||
xxxn YYUU
|
||||
xxxx YYUU
|
||||
rxxx YYYY
|
||||
rrrx YYYY
|
||||
rrrx XXXY
|
||||
rrrr XXXX
|
||||
rrrr zzXX
|
||||
rrrr zzzz
|
||||
rrrrr ccczz
|
||||
rrrrrx vccccc
|
||||
rrrrxxxx uuvvvvvc
|
||||
rrxxxxxxnnnnuuuuuv
|
||||
xxxxxnnnnu
|
||||
|
||||
|
||||
)#");
|
||||
}
|
||||
|
||||
// let's init the compositor.
|
||||
// it initializes basic Wayland stuff in the constructor.
|
||||
|
|
|
|||
|
|
@ -16,6 +16,17 @@ using namespace Hyprutils::OS;
|
|||
|
||||
#define TIMESPEC_NSEC_PER_SEC 1000000000L
|
||||
|
||||
static uint64_t LAST_DO_LATER_SEQ = 1;
|
||||
|
||||
SEventLoopDoLaterLock::SEventLoopDoLaterLock(uint64_t seq_) : seq(seq_) {
|
||||
;
|
||||
}
|
||||
|
||||
SEventLoopDoLaterLock::~SEventLoopDoLaterLock() {
|
||||
if (g_pEventLoopManager && seq > 0)
|
||||
g_pEventLoopManager->removeDoLater(seq);
|
||||
}
|
||||
|
||||
CEventLoopManager::CEventLoopManager(wl_display* display, wl_event_loop* wlEventLoop) {
|
||||
m_timers.timerfd = CFileDescriptor{timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC)};
|
||||
m_wayland.loop = wlEventLoop;
|
||||
|
|
@ -201,11 +212,13 @@ void CEventLoopManager::nudgeTimers() {
|
|||
timerfd_settime(m_timers.timerfd.get(), TFD_TIMER_ABSTIME, &ts, nullptr);
|
||||
}
|
||||
|
||||
void CEventLoopManager::doLater(const std::function<void()>& fn) {
|
||||
m_idle.fns.emplace_back(fn);
|
||||
uint64_t CEventLoopManager::doLater(const std::function<void()>& fn) {
|
||||
const uint64_t NEW_SEQ = ++LAST_DO_LATER_SEQ;
|
||||
|
||||
m_idle.fns.emplace_back(std::make_pair<>(NEW_SEQ, fn));
|
||||
|
||||
if (m_idle.eventSource)
|
||||
return;
|
||||
return NEW_SEQ;
|
||||
|
||||
m_idle.eventSource = wl_event_loop_add_idle(
|
||||
m_wayland.loop,
|
||||
|
|
@ -215,11 +228,26 @@ void CEventLoopManager::doLater(const std::function<void()>& fn) {
|
|||
IDLE->fns.clear();
|
||||
IDLE->eventSource = nullptr;
|
||||
for (auto& f : fns) {
|
||||
if (f)
|
||||
f();
|
||||
if (f.second)
|
||||
f.second();
|
||||
}
|
||||
},
|
||||
&m_idle);
|
||||
|
||||
return NEW_SEQ;
|
||||
}
|
||||
|
||||
void CEventLoopManager::removeDoLater(uint64_t seq) {
|
||||
std::erase_if(m_idle.fns, [&seq](const auto& e) { return e.first == seq; });
|
||||
|
||||
if (m_idle.fns.empty() && m_idle.eventSource) {
|
||||
wl_event_source_remove(m_idle.eventSource);
|
||||
m_idle.eventSource = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
UP<SEventLoopDoLaterLock> CEventLoopManager::doLaterLock(const std::function<void()>& fn) {
|
||||
return makeUnique<SEventLoopDoLaterLock>(doLater(fn));
|
||||
}
|
||||
|
||||
void CEventLoopManager::doOnReadable(CFileDescriptor fd, std::function<void()>&& fn) {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,13 @@ namespace Aquamarine {
|
|||
struct SPollFD;
|
||||
};
|
||||
|
||||
struct SEventLoopDoLaterLock {
|
||||
SEventLoopDoLaterLock(uint64_t seq);
|
||||
~SEventLoopDoLaterLock();
|
||||
|
||||
uint64_t seq = 0;
|
||||
};
|
||||
|
||||
class CEventLoopManager {
|
||||
public:
|
||||
CEventLoopManager(wl_display* display, wl_event_loop* wlEventLoop);
|
||||
|
|
@ -30,12 +37,16 @@ class CEventLoopManager {
|
|||
// schedules a recalc of the timers
|
||||
void scheduleRecalc();
|
||||
|
||||
// schedules a function to run later, aka in a wayland idle event.
|
||||
void doLater(const std::function<void()>& fn);
|
||||
// schedules a function to run later, aka in a wayland idle event. Returns a sequence which can be used to remove it.
|
||||
uint64_t doLater(const std::function<void()>& fn);
|
||||
void removeDoLater(uint64_t seq);
|
||||
|
||||
// automatically cleaned up doLater instance
|
||||
[[nodiscard]] UP<SEventLoopDoLaterLock> doLaterLock(const std::function<void()>& fn);
|
||||
|
||||
struct SIdleData {
|
||||
wl_event_source* eventSource = nullptr;
|
||||
std::vector<std::function<void()>> fns;
|
||||
wl_event_source* eventSource = nullptr;
|
||||
std::vector<std::pair<uint64_t, std::function<void()>>> fns;
|
||||
};
|
||||
|
||||
struct SReadableWaiter {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "../Compositor.hpp"
|
||||
#include "../managers/SeatManager.hpp"
|
||||
#include "../managers/ANRManager.hpp"
|
||||
#include "../managers/eventLoop/EventLoopManager.hpp"
|
||||
#include "../helpers/Monitor.hpp"
|
||||
#include "core/Seat.hpp"
|
||||
#include "core/Compositor.hpp"
|
||||
|
|
@ -286,7 +287,7 @@ bool CXDGToplevelResource::anyChildModal() {
|
|||
|
||||
uint32_t CXDGToplevelResource::setSize(const Vector2D& size) {
|
||||
m_pendingApply.size = size;
|
||||
applyState();
|
||||
scheduleStateApplication();
|
||||
return m_owner->scheduleConfigure();
|
||||
}
|
||||
|
||||
|
|
@ -300,7 +301,9 @@ uint32_t CXDGToplevelResource::setMaximized(bool maximized) {
|
|||
m_pendingApply.states.push_back(XDG_TOPLEVEL_STATE_MAXIMIZED);
|
||||
else if (!maximized && set)
|
||||
std::erase(m_pendingApply.states, XDG_TOPLEVEL_STATE_MAXIMIZED);
|
||||
applyState();
|
||||
|
||||
scheduleStateApplication();
|
||||
|
||||
return m_owner->scheduleConfigure();
|
||||
}
|
||||
|
||||
|
|
@ -314,7 +317,9 @@ uint32_t CXDGToplevelResource::setFullscreen(bool fullscreen) {
|
|||
m_pendingApply.states.push_back(XDG_TOPLEVEL_STATE_FULLSCREEN);
|
||||
else if (!fullscreen && set)
|
||||
std::erase(m_pendingApply.states, XDG_TOPLEVEL_STATE_FULLSCREEN);
|
||||
applyState();
|
||||
|
||||
scheduleStateApplication();
|
||||
|
||||
return m_owner->scheduleConfigure();
|
||||
}
|
||||
|
||||
|
|
@ -328,7 +333,9 @@ uint32_t CXDGToplevelResource::setActive(bool active) {
|
|||
m_pendingApply.states.push_back(XDG_TOPLEVEL_STATE_ACTIVATED);
|
||||
else if (!active && set)
|
||||
std::erase(m_pendingApply.states, XDG_TOPLEVEL_STATE_ACTIVATED);
|
||||
applyState();
|
||||
|
||||
scheduleStateApplication();
|
||||
|
||||
return m_owner->scheduleConfigure();
|
||||
}
|
||||
|
||||
|
|
@ -345,22 +352,32 @@ uint32_t CXDGToplevelResource::setSuspeneded(bool sus) {
|
|||
m_pendingApply.states.push_back(XDG_TOPLEVEL_STATE_SUSPENDED);
|
||||
else if (!sus && set)
|
||||
std::erase(m_pendingApply.states, XDG_TOPLEVEL_STATE_SUSPENDED);
|
||||
applyState();
|
||||
|
||||
scheduleStateApplication();
|
||||
|
||||
return m_owner->scheduleConfigure();
|
||||
}
|
||||
|
||||
void CXDGToplevelResource::applyState() {
|
||||
wl_array arr;
|
||||
wl_array_init(&arr);
|
||||
void CXDGToplevelResource::scheduleStateApplication() {
|
||||
|
||||
if (!m_pendingApply.states.empty()) {
|
||||
wl_array_add(&arr, m_pendingApply.states.size() * sizeof(int));
|
||||
memcpy(arr.data, m_pendingApply.states.data(), m_pendingApply.states.size() * sizeof(int));
|
||||
}
|
||||
if (m_stateUpdate)
|
||||
return;
|
||||
|
||||
m_resource->sendConfigure(m_pendingApply.size.x, m_pendingApply.size.y, &arr);
|
||||
m_stateUpdate = g_pEventLoopManager->doLaterLock([this] {
|
||||
wl_array arr;
|
||||
wl_array_init(&arr);
|
||||
|
||||
wl_array_release(&arr);
|
||||
if (!m_pendingApply.states.empty()) {
|
||||
wl_array_add(&arr, m_pendingApply.states.size() * sizeof(int));
|
||||
memcpy(arr.data, m_pendingApply.states.data(), m_pendingApply.states.size() * sizeof(int));
|
||||
}
|
||||
|
||||
m_resource->sendConfigure(m_pendingApply.size.x, m_pendingApply.size.y, &arr);
|
||||
|
||||
wl_array_release(&arr);
|
||||
|
||||
m_stateUpdate.reset();
|
||||
});
|
||||
}
|
||||
|
||||
void CXDGToplevelResource::close() {
|
||||
|
|
@ -516,8 +533,6 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP<CXdgSurface> resource_, SP<CXDGWMBas
|
|||
|
||||
CXDGSurfaceResource::~CXDGSurfaceResource() {
|
||||
m_events.destroy.emit();
|
||||
if (m_configureSource)
|
||||
wl_event_source_remove(m_configureSource);
|
||||
if (m_surface)
|
||||
m_surface->resetRole();
|
||||
}
|
||||
|
|
@ -531,22 +546,19 @@ SP<CXDGSurfaceResource> CXDGSurfaceResource::fromResource(wl_resource* res) {
|
|||
return data ? data->m_self.lock() : nullptr;
|
||||
}
|
||||
|
||||
static void onConfigure(void* data) {
|
||||
sc<CXDGSurfaceResource*>(data)->configure();
|
||||
}
|
||||
|
||||
uint32_t CXDGSurfaceResource::scheduleConfigure() {
|
||||
if (m_configureSource)
|
||||
if (m_stateUpdate)
|
||||
return m_scheduledSerial;
|
||||
|
||||
m_configureSource = wl_event_loop_add_idle(g_pCompositor->m_wlEventLoop, onConfigure, this);
|
||||
m_stateUpdate = g_pEventLoopManager->doLaterLock([this] { configure(); });
|
||||
|
||||
m_scheduledSerial = wl_display_next_serial(g_pCompositor->m_wlDisplay);
|
||||
|
||||
return m_scheduledSerial;
|
||||
}
|
||||
|
||||
void CXDGSurfaceResource::configure() {
|
||||
m_configureSource = nullptr;
|
||||
m_stateUpdate.reset();
|
||||
m_resource->sendConfigure(m_scheduledSerial);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ class CXDGPopupResource;
|
|||
class CSeatGrab;
|
||||
class CWLSurfaceResource;
|
||||
class CXDGDialogV1Resource;
|
||||
struct SEventLoopDoLaterLock;
|
||||
|
||||
struct SXDGPositionerState {
|
||||
Vector2D requestedSize;
|
||||
|
|
@ -149,8 +150,11 @@ class CXDGToplevelResource {
|
|||
std::vector<WP<CXDGToplevelResource>> m_children;
|
||||
|
||||
private:
|
||||
SP<CXdgToplevel> m_resource;
|
||||
void applyState();
|
||||
SP<CXdgToplevel> m_resource;
|
||||
|
||||
UP<SEventLoopDoLaterLock> m_stateUpdate;
|
||||
|
||||
void scheduleStateApplication();
|
||||
};
|
||||
|
||||
class CXDGSurfaceRole : public ISurfaceRole {
|
||||
|
|
@ -202,12 +206,12 @@ class CXDGSurfaceResource {
|
|||
void configure();
|
||||
|
||||
private:
|
||||
SP<CXdgSurface> m_resource;
|
||||
SP<CXdgSurface> m_resource;
|
||||
|
||||
uint32_t m_lastConfigureSerial = 0;
|
||||
uint32_t m_scheduledSerial = 0;
|
||||
UP<SEventLoopDoLaterLock> m_stateUpdate;
|
||||
|
||||
wl_event_source* m_configureSource = nullptr;
|
||||
uint32_t m_lastConfigureSerial = 0;
|
||||
uint32_t m_scheduledSerial = 0;
|
||||
|
||||
//
|
||||
std::vector<WP<CXDGPopupResource>> m_popups;
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ TEST(ConfigLuaValueTypes, boolBadType) {
|
|||
|
||||
CLuaConfigBool value(false);
|
||||
|
||||
lua_pushinteger(L, 1);
|
||||
lua_pushinteger(L, 2);
|
||||
const auto err = value.parse(L);
|
||||
lua_pop(L, 1);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue