From 29308b94ca2d95597b3c4e3ac1d3edbcd2f23cdd Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 23 Apr 2024 01:28:20 +0100 Subject: [PATCH] windows: add misc:initial_workspace_tracking By default enabled, will track the initial opened workspace of a window spawned for 2 minutes or until it's moved to a different workspace. For example: you run a launcher and open an app on workspace 1, but quickly switch to workspace 2. The app will now open on workspace 1 regardless of your switch. --- src/config/ConfigManager.cpp | 1 + src/desktop/Window.cpp | 45 +++++++++++++++++++++++++++++++++ src/desktop/Window.hpp | 6 +++++ src/events/Windows.cpp | 44 ++++++++++++++++++++++++-------- src/managers/KeybindManager.cpp | 26 ++++++++++++++++++- 5 files changed, 110 insertions(+), 12 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 05694832..eaaed1f7 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -350,6 +350,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("misc:new_window_takes_over_fullscreen", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:enable_hyprcursor", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:hide_cursor_on_key_press", Hyprlang::INT{0}); + m_pConfig->addConfigValue("misc:initial_workspace_tracking", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1}); diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 5310ecae..29a41976 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -5,6 +5,7 @@ #include "../render/decorations/CHyprBorderDecoration.hpp" #include "../config/ConfigValue.hpp" #include +#include "../managers/TokenManager.hpp" CWindow::CWindow() { m_vRealPosition.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), this, AVARDAMAGE_ENTIRE); @@ -384,6 +385,11 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { if (m_pWorkspace == pWorkspace) return; + if (!m_szInitialWorkspaceToken.empty()) { + g_pTokenManager->removeToken(g_pTokenManager->getToken(m_szInitialWorkspaceToken)); + m_szInitialWorkspaceToken = ""; + } + static auto PCLOSEONLASTSPECIAL = CConfigValue("misc:close_special_on_empty"); const auto OLDWORKSPACE = m_pWorkspace; @@ -1241,3 +1247,42 @@ int CWindow::workspaceID() { bool CWindow::onSpecialWorkspace() { return m_pWorkspace ? m_pWorkspace->m_bIsSpecialWorkspace : g_pCompositor->isWorkspaceSpecial(m_iLastWorkspace); } + +std::unordered_map CWindow::getEnv() { + + const auto PID = getPID(); + + if (PID <= 1) + return {}; + + std::unordered_map results; + + // + std::string environFile = "/proc/" + std::to_string(PID) + "/environ"; + std::ifstream ifs(environFile, std::ios::binary); + + if (!ifs.good()) + return {}; + + std::vector buffer; + size_t needle = 0; + buffer.resize(512, '\0'); + while (ifs.read(buffer.data() + needle, 512)) { + buffer.resize(buffer.size() + 512, '\0'); + needle += 512; + } + + std::replace(buffer.begin(), buffer.end() - 1, '\0', '\n'); + + CVarList envs(std::string{buffer.data(), needle - 1}, 0, '\n', true); + + for (auto& e : envs) { + if (!e.contains('=')) + continue; + + const auto EQ = e.find_first_of('='); + results[e.substr(0, EQ)] = e.substr(EQ + 1); + } + + return results; +} diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 5007cef4..cc4d1757 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -357,6 +357,9 @@ class CWindow { // for idle inhibiting windows eIdleInhibitMode m_eIdleInhibitMode = IDLEINHIBIT_NONE; + // initial token. Will be unregistered on workspace change or timeout of 2 minutes + std::string m_szInitialWorkspaceToken = ""; + // for groups struct SGroupData { CWindow* pNextWindow = nullptr; // nullptr means no grouping. Self means single group. @@ -437,6 +440,9 @@ class CWindow { void setAnimationsToMove(); void onWorkspaceAnimUpdate(); + // + std::unordered_map getEnv(); + private: // For hidden windows and stuff bool m_bHidden = false; diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index a351ef67..cb67af2f 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -3,6 +3,7 @@ #include "../Compositor.hpp" #include "../helpers/WLClasses.hpp" #include "../managers/input/InputManager.hpp" +#include "../managers/TokenManager.hpp" #include "../render/Renderer.hpp" #include "../config/ConfigValue.hpp" @@ -44,13 +45,14 @@ void setAnimToMove(void* data) { void Events::listener_mapWindow(void* owner, void* data) { CWindow* PWINDOW = (CWindow*)owner; - static auto PINACTIVEALPHA = CConfigValue("decoration:inactive_opacity"); - static auto PACTIVEALPHA = CConfigValue("decoration:active_opacity"); - static auto PDIMSTRENGTH = CConfigValue("decoration:dim_strength"); - static auto PSWALLOW = CConfigValue("misc:enable_swallow"); - static auto PSWALLOWREGEX = CConfigValue("misc:swallow_regex"); - static auto PSWALLOWEXREGEX = CConfigValue("misc:swallow_exception_regex"); - static auto PNEWTAKESOVERFS = CConfigValue("misc:new_window_takes_over_fullscreen"); + static auto PINACTIVEALPHA = CConfigValue("decoration:inactive_opacity"); + static auto PACTIVEALPHA = CConfigValue("decoration:active_opacity"); + static auto PDIMSTRENGTH = CConfigValue("decoration:dim_strength"); + static auto PSWALLOW = CConfigValue("misc:enable_swallow"); + static auto PSWALLOWREGEX = CConfigValue("misc:swallow_regex"); + static auto PSWALLOWEXREGEX = CConfigValue("misc:swallow_exception_regex"); + static auto PNEWTAKESOVERFS = CConfigValue("misc:new_window_takes_over_fullscreen"); + static auto PINITIALWSTRACKING = CConfigValue("misc:initial_workspace_tracking"); auto PMONITOR = g_pCompositor->m_pLastMonitor; if (!g_pCompositor->m_pLastMonitor) { @@ -67,6 +69,28 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_iX11Type = PWINDOW->m_bIsX11 ? (PWINDOW->m_uSurface.xwayland->override_redirect ? 2 : 1) : 1; PWINDOW->m_bFirstMap = true; + // check for token + std::string requestedWorkspace = ""; + bool workspaceSilent = false; + + if (*PINITIALWSTRACKING) { + const auto WINDOWENV = PWINDOW->getEnv(); + if (WINDOWENV.contains("HL_INITIAL_WORKSPACE_TOKEN")) { + const auto SZTOKEN = WINDOWENV.at("HL_INITIAL_WORKSPACE_TOKEN"); + Debug::log(LOG, "New window contains HL_INITIAL_WORKSPACE_TOKEN: {}", SZTOKEN); + const auto TOKEN = g_pTokenManager->getToken(SZTOKEN); + if (TOKEN) { + // find workspace and use it + std::string WS = std::any_cast(TOKEN->data); + + Debug::log(LOG, "HL_INITIAL_WORKSPACE_TOKEN {} -> {}", SZTOKEN, WS); + + requestedWorkspace = WS; + workspaceSilent = true; + } + } + } + if (g_pInputManager->m_bLastFocusOnLS) // waybar fix g_pInputManager->releaseAllMouseButtons(); @@ -108,10 +132,8 @@ void Events::listener_mapWindow(void* owner, void* data) { } // window rules - const auto WINDOWRULES = g_pConfigManager->getMatchingRules(PWINDOW, false); - std::string requestedWorkspace = ""; - bool workspaceSilent = false; - bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen || + const auto WINDOWRULES = g_pConfigManager->getMatchingRules(PWINDOW, false); + bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen || (!PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xdg->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL && PWINDOW->m_uSurface.xdg->toplevel->requested.fullscreen) || (PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xwayland->fullscreen); bool requestsFakeFullscreen = false; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 34e2f85b..040ae245 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -3,8 +3,10 @@ #include "debug/Log.hpp" #include "helpers/VarList.hpp" #include "../config/ConfigValue.hpp" +#include "TokenManager.hpp" #include +#include #include #include @@ -17,6 +19,23 @@ #include #endif +static std::vector> getHyprlandLaunchEnv() { + static auto PINITIALWSTRACKING = CConfigValue("misc:initial_workspace_tracking"); + + if (!*PINITIALWSTRACKING) + return {}; + + const auto PMONITOR = g_pCompositor->m_pLastMonitor; + if (!PMONITOR || !PMONITOR->activeWorkspace) + return {}; + + std::vector> result; + + result.push_back(std::make_pair<>("HL_INITIAL_WORKSPACE_TOKEN", g_pTokenManager->registerNewToken(PMONITOR->activeWorkspace->getConfigName(), std::chrono::minutes(2)))); + + return result; +} + CKeybindManager::CKeybindManager() { // initialize all dispatchers @@ -774,7 +793,9 @@ void CKeybindManager::spawn(std::string args) { uint64_t CKeybindManager::spawnRaw(std::string args) { Debug::log(LOG, "Executing {}", args); - int socket[2]; + const auto HLENV = getHyprlandLaunchEnv(); + + int socket[2]; if (pipe(socket) != 0) { Debug::log(LOG, "Unable to create pipe for fork"); } @@ -797,6 +818,9 @@ uint64_t CKeybindManager::spawnRaw(std::string args) { grandchild = fork(); if (grandchild == 0) { // run in grandchild + for (auto& e : HLENV) { + setenv(e.first.c_str(), e.second.c_str(), 1); + } close(socket[0]); close(socket[1]); execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr);