diff --git a/hyprtester/src/tests/main/window.cpp b/hyprtester/src/tests/main/window.cpp index 4a4da0ccb..fab4ab767 100644 --- a/hyprtester/src/tests/main/window.cpp +++ b/hyprtester/src/tests/main/window.cpp @@ -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" diff --git a/meta/hl.meta.lua b/meta/hl.meta.lua index 96092e91e..e0fd096ae 100644 --- a/meta/hl.meta.lua +++ b/meta/hl.meta.lua @@ -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 diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 14a7843ec..ab371df22 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -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 persistentFound; for (const auto& rule : rules) { - if (!rule.m_isPersistent) + if (!rule.m_isPersistent.value_or(false)) continue; PHLWORKSPACE PWORKSPACE = nullptr; diff --git a/src/config/lua/bindings/LuaBindingsDispatchers.cpp b/src/config/lua/bindings/LuaBindingsDispatchers.cpp index fc84895ac..0b6ca07a0 100644 --- a/src/config/lua/bindings/LuaBindingsDispatchers.cpp +++ b/src/config/lua/bindings/LuaBindingsDispatchers.cpp @@ -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"); diff --git a/src/config/shared/workspace/WorkspaceRule.cpp b/src/config/shared/workspace/WorkspaceRule.cpp index 28d5fcab7..dfd77d429 100644 --- a/src/config/shared/workspace/WorkspaceRule.cpp +++ b/src/config/shared/workspace/WorkspaceRule.cpp @@ -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()) diff --git a/src/config/shared/workspace/WorkspaceRule.hpp b/src/config/shared/workspace/WorkspaceRule.hpp index 5d63e4349..e56a13663 100644 --- a/src/config/shared/workspace/WorkspaceRule.hpp +++ b/src/config/shared/workspace/WorkspaceRule.hpp @@ -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 m_isDefault; + std::optional m_isPersistent; std::optional m_gapsIn; std::optional m_gapsOut; std::optional m_floatGaps = m_gapsOut; diff --git a/src/config/shared/workspace/WorkspaceRuleManager.cpp b/src/config/shared/workspace/WorkspaceRuleManager.cpp index 4c2c2b909..04b94a533 100644 --- a/src/config/shared/workspace/WorkspaceRuleManager.cpp +++ b/src/config/shared/workspace/WorkspaceRuleManager.cpp @@ -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:")) { diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index b334a26e3..278e92c6a 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -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(r.m_isDefault) ? std::format(",\n \"default\": {}", boolToString(r.m_isDefault)) : ""; - const std::string persistent = sc(r.m_isPersistent) ? std::format(",\n \"persistent\": {}", boolToString(r.m_isPersistent)) : ""; + const std::string default_ = sc(r.m_isDefault) ? std::format(",\n \"default\": {}", boolToString(r.m_isDefault.value())) : ""; + const std::string persistent = sc(r.m_isPersistent) ? std::format(",\n \"persistent\": {}", boolToString(r.m_isPersistent.value())) : ""; const std::string gapsIn = sc(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() ? "" : escapeJSONStrings(r.m_monitor)); - const std::string default_ = std::format("\tdefault: {}\n", sc(r.m_isDefault) ? boolToString(r.m_isDefault) : ""); - const std::string persistent = std::format("\tpersistent: {}\n", sc(r.m_isPersistent) ? boolToString(r.m_isPersistent) : ""); + const std::string default_ = std::format("\tdefault: {}\n", sc(r.m_isDefault) ? boolToString(r.m_isDefault.value()) : ""); + const std::string persistent = std::format("\tpersistent: {}\n", sc(r.m_isPersistent) ? boolToString(r.m_isPersistent.value()) : ""); const std::string gapsIn = sc(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(file), std::istreambuf_iterator()); - } - }); - } - }); - } - } 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(m->m_pixelSize.x), sc(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, ' '); diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index 6d8e6cb49..60d8d9853 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -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{WORKSPACERULE}, m_self.lock()); g_pEventManager->postEvent({.event = "renameworkspace", .data = std::to_string(m_id) + "," + m_name}); diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 5e37f19fb..5aa58a2c8 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -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(file), std::istreambuf_iterator()); - } - }); - } - }); - } - } 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[] = { diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index 26c5c7adc..0528be58c 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -27,7 +27,6 @@ bool isDirection(const char&); SWorkspaceIDName getWorkspaceIDNameFromString(const std::string&); std::optional 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 configStringToInt(const std::string&); diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 657a8c11b..a5195a94f 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -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; diff --git a/src/helpers/Splashes.hpp b/src/helpers/Splashes.hpp index 4bc2814b9..64da47eea 100644 --- a/src/helpers/Splashes.hpp +++ b/src/helpers/Splashes.hpp @@ -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 }; diff --git a/src/helpers/SystemInfo.cpp b/src/helpers/SystemInfo.cpp new file mode 100644 index 000000000..3ebdd16da --- /dev/null +++ b/src/helpers/SystemInfo.cpp @@ -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 + +#include +#include +#include +#include +#include + +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(file), std::istreambuf_iterator()); + } + }); + } + }); + } + } 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(m->m_pixelSize.x), sc(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; +} \ No newline at end of file diff --git a/src/helpers/SystemInfo.hpp b/src/helpers/SystemInfo.hpp new file mode 100644 index 000000000..5eec45c24 --- /dev/null +++ b/src/helpers/SystemInfo.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include + +#include "../SharedDefs.hpp" + +namespace Helpers::SystemInfo { + std::string getSystemInfo(); + std::string getVersion(eHyprCtlOutputFormat fmt); + std::string getStatus(eHyprCtlOutputFormat fmt); +}; \ No newline at end of file diff --git a/src/layout/algorithm/tiled/master/MasterAlgorithm.cpp b/src/layout/algorithm/tiled/master/MasterAlgorithm.cpp index 46506391c..a6849d2ac 100644 --- a/src/layout/algorithm/tiled/master/MasterAlgorithm.cpp +++ b/src/layout/algorithm/tiled/master/MasterAlgorithm.cpp @@ -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(); diff --git a/src/main.cpp b/src/main.cpp index faf780832..b85146f60 100644 --- a/src/main.cpp +++ b/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. diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index 03a8d7c92..6c661a6fc 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -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& fn) { - m_idle.fns.emplace_back(fn); +uint64_t CEventLoopManager::doLater(const std::function& 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& 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 CEventLoopManager::doLaterLock(const std::function& fn) { + return makeUnique(doLater(fn)); } void CEventLoopManager::doOnReadable(CFileDescriptor fd, std::function&& fn) { diff --git a/src/managers/eventLoop/EventLoopManager.hpp b/src/managers/eventLoop/EventLoopManager.hpp index 7999dc595..646734555 100644 --- a/src/managers/eventLoop/EventLoopManager.hpp +++ b/src/managers/eventLoop/EventLoopManager.hpp @@ -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& 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& fn); + void removeDoLater(uint64_t seq); + + // automatically cleaned up doLater instance + [[nodiscard]] UP doLaterLock(const std::function& fn); struct SIdleData { - wl_event_source* eventSource = nullptr; - std::vector> fns; + wl_event_source* eventSource = nullptr; + std::vector>> fns; }; struct SReadableWaiter { diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 774346d4b..3c7029503 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -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 resource_, SPresetRole(); } @@ -531,22 +546,19 @@ SP CXDGSurfaceResource::fromResource(wl_resource* res) { return data ? data->m_self.lock() : nullptr; } -static void onConfigure(void* data) { - sc(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); } diff --git a/src/protocols/XDGShell.hpp b/src/protocols/XDGShell.hpp index 3d94d2829..79f154326 100644 --- a/src/protocols/XDGShell.hpp +++ b/src/protocols/XDGShell.hpp @@ -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> m_children; private: - SP m_resource; - void applyState(); + SP m_resource; + + UP m_stateUpdate; + + void scheduleStateApplication(); }; class CXDGSurfaceRole : public ISurfaceRole { @@ -202,12 +206,12 @@ class CXDGSurfaceResource { void configure(); private: - SP m_resource; + SP m_resource; - uint32_t m_lastConfigureSerial = 0; - uint32_t m_scheduledSerial = 0; + UP m_stateUpdate; - wl_event_source* m_configureSource = nullptr; + uint32_t m_lastConfigureSerial = 0; + uint32_t m_scheduledSerial = 0; // std::vector> m_popups; diff --git a/tests/config/lua/ConfigValueTypes.cpp b/tests/config/lua/ConfigValueTypes.cpp index 76de98bf9..4ee818761 100644 --- a/tests/config/lua/ConfigValueTypes.cpp +++ b/tests/config/lua/ConfigValueTypes.cpp @@ -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);