diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 30585502..b2af4eea 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -396,6 +396,13 @@ void CConfigManager::loadConfigLoadVars() { g_pHyprError->queueCreate("Warning: You're using an autogenerated config! (config file: " + CONFIGPATH + " )\nSUPER+Enter -> kitty\nSUPER+T -> Alacritty\nSUPER+M -> exit Hyprland", CColor(255, 255, 70, 255)); else g_pHyprError->destroy(); + + // Set the modes for all monitors as we configured them + // not on first launch because monitors might not exist yet + // and they'll be taken care of in the newMonitor event + if (!isFirstLaunch) { + m_bWantsMonitorReload = true; + } } void CConfigManager::tick() { @@ -526,4 +533,13 @@ void CConfigManager::dispatchExecOnce() { } firstExecRequests.clear(); // free some kb of memory :P +} + +void CConfigManager::performMonitorReload() { + for (auto& m : g_pCompositor->m_lMonitors) { + auto rule = getMonitorRuleFor(m.szName); + g_pHyprRenderer->applyMonitorRule(&m, &rule); + } + + m_bWantsMonitorReload = false; } \ No newline at end of file diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index ae61ba44..314592a9 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -55,6 +55,9 @@ public: // no-op when done. void dispatchExecOnce(); + void performMonitorReload(); + bool m_bWantsMonitorReload = false; + private: std::unordered_map configValues; time_t lastModifyTime = 0; // for reloading the config if changed diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp index c8c0bb5d..4369af45 100644 --- a/src/events/Monitors.cpp +++ b/src/events/Monitors.cpp @@ -87,64 +87,16 @@ void Events::listener_newOutput(wl_listener* listener, void* data) { // wlr_output_layout_output_coords returns invalid values, I think... wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, OUTPUT, monitorRule.offset.x, monitorRule.offset.y); - // loop over modes and choose an appropriate one. - if (!wl_list_empty(&OUTPUT->modes)) { - wlr_output_mode* mode; - bool found = false; - - wl_list_for_each(mode, &OUTPUT->modes, link) { - // if delta of refresh rate, w and h chosen and mode is < 1 we accept it - if (DELTALESSTHAN(mode->width, monitorRule.resolution.x, 1) && DELTALESSTHAN(mode->height, monitorRule.resolution.y, 1) && DELTALESSTHAN(mode->refresh / 1000.f, monitorRule.refreshRate, 1)) { - wlr_output_set_mode(OUTPUT, mode); - - if (!wlr_output_test(OUTPUT)) { - Debug::log(LOG, "Monitor %s: REJECTED available mode: %ix%i@%2f!", - OUTPUT->name, (int)monitorRule.resolution.x, (int)monitorRule.resolution.y, (float)monitorRule.refreshRate, - mode->width, mode->height, mode->refresh / 1000.f); - continue; - } - - Debug::log(LOG, "Monitor %s: requested %ix%i@%2f, found available mode: %ix%i@%imHz, applying.", - OUTPUT->name, (int)monitorRule.resolution.x, (int)monitorRule.resolution.y, (float)monitorRule.refreshRate, - mode->width, mode->height, mode->refresh); - - found = true; - - break; - } - } - - if (!found) { - const auto PREFERREDMODE = wlr_output_preferred_mode(OUTPUT); - - if (!PREFERREDMODE) { - Debug::log(ERR, "Monitor %s has NO PREFERRED MODE, and an INVALID one was requested: %ix%i@%2f", - (int)monitorRule.resolution.x, (int)monitorRule.resolution.y, (float)monitorRule.refreshRate); - return; - } - - // Preferred is valid - wlr_output_set_mode(OUTPUT, PREFERREDMODE); - - Debug::log(ERR, "Monitor %s got an invalid requested mode: %ix%i@%2f, using the preferred one instead: %ix%i@%2f", - OUTPUT->name, (int)monitorRule.resolution.x, (int)monitorRule.resolution.y, (float)monitorRule.refreshRate, - PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f); - } - } - - if (!wlr_output_commit(OUTPUT)) { - Debug::log(ERR, "Couldn't commit output named %s", OUTPUT->name); - return; - } + // set mode, also applies + g_pHyprRenderer->applyMonitorRule(PNEWMONITOR, &monitorRule, true); Debug::log(LOG, "Added new monitor with name %s at %i,%i with size %ix%i, pointer %x", OUTPUT->name, (int)monitorRule.offset.x, (int)monitorRule.offset.y, (int)monitorRule.resolution.x, (int)monitorRule.resolution.y, OUTPUT); + PNEWMONITOR->damage = wlr_output_damage_create(PNEWMONITOR->output); + // add a WLR workspace group PNEWMONITOR->pWLRWorkspaceGroupHandle = wlr_ext_workspace_group_handle_v1_create(g_pCompositor->m_sWLREXTWorkspaceMgr); - // add damage - PNEWMONITOR->damage = wlr_output_damage_create(OUTPUT); - // Workspace const auto WORKSPACEID = monitorRule.defaultWorkspaceID == -1 ? g_pCompositor->m_lWorkspaces.size() + 1 /* Cuz workspaces doesnt have the new one yet and we start with 1 */ : monitorRule.defaultWorkspaceID; g_pCompositor->m_lWorkspaces.emplace_back(newMonitor.ID); @@ -179,6 +131,9 @@ void Events::listener_monitorFrame(void* owner, void* data) { g_pCompositor->cleanupWindows(); g_pConfigManager->dispatchExecOnce(); // We exec-once when at least one monitor starts refreshing, meaning stuff has init'd + + if (g_pConfigManager->m_bWantsMonitorReload) + g_pConfigManager->performMonitorReload(); } timespec now; diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 02909e36..32e30e7a 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -685,4 +685,15 @@ void CHyprOpenGLImpl::clearWithTex() { wlr_box box = {0, 0, m_RenderData.pMonitor->vecSize.x, m_RenderData.pMonitor->vecSize.y}; renderTexture(m_mMonitorBGTextures[m_RenderData.pMonitor], &box, 255, 0); -} \ No newline at end of file +} + +void CHyprOpenGLImpl::destroyMonitorResources(SMonitor* pMonitor) { + g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].mirrorFB.release(); + g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].primaryFB.release(); + g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].stencilTex.destroyTexture(); + g_pHyprOpenGL->m_mMonitorBGTextures[pMonitor].destroyTexture(); + g_pHyprOpenGL->m_mMonitorRenderResources.erase(pMonitor); + g_pHyprOpenGL->m_mMonitorBGTextures.erase(pMonitor); + + Debug::log(LOG, "Monitor %s -> destroyed all render data", pMonitor->szName.c_str()); +} diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index deaa1b2e..75d8e9c7 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -60,6 +60,8 @@ public: void scissor(const wlr_box*); void scissor(const pixman_box32*); + void destroyMonitorResources(SMonitor*); + SCurrentRenderData m_RenderData; GLint m_iCurrentOutputFb = 0; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index a764c38c..3969b7b4 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -490,4 +490,77 @@ DAMAGETRACKINGMODES CHyprRenderer::damageTrackingModeFromStr(const std::string& return DAMAGE_TRACKING_NONE; return DAMAGE_TRACKING_INVALID; +} + +void CHyprRenderer::applyMonitorRule(SMonitor* pMonitor, SMonitorRule* pMonitorRule, bool force) { + + // Check if the rule isn't already applied + if (!force && DELTALESSTHAN(pMonitor->vecSize.x, pMonitorRule->resolution.x, 1) && DELTALESSTHAN(pMonitor->vecSize.y, pMonitorRule->resolution.y, 1) && DELTALESSTHAN(pMonitor->refreshRate, pMonitorRule->refreshRate, 1) && pMonitor->scale == pMonitorRule->scale) { + Debug::log(LOG, "Not applying a new rule to %s because it's already applied!", pMonitor->szName.c_str()); + return; + } + + wlr_output_set_scale(pMonitor->output, pMonitorRule->scale); + pMonitor->scale = pMonitorRule->scale; + + // loop over modes and choose an appropriate one. + if (!wl_list_empty(&pMonitor->output->modes)) { + wlr_output_mode* mode; + bool found = false; + + wl_list_for_each(mode, &pMonitor->output->modes, link) { + // if delta of refresh rate, w and h chosen and mode is < 1 we accept it + if (DELTALESSTHAN(mode->width, pMonitorRule->resolution.x, 1) && DELTALESSTHAN(mode->height, pMonitorRule->resolution.y, 1) && DELTALESSTHAN(mode->refresh / 1000.f, pMonitorRule->refreshRate, 1)) { + wlr_output_set_mode(pMonitor->output, mode); + + if (!wlr_output_test(pMonitor->output)) { + Debug::log(LOG, "Monitor %s: REJECTED available mode: %ix%i@%2f!", + pMonitor->output->name, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate, + mode->width, mode->height, mode->refresh / 1000.f); + continue; + } + + Debug::log(LOG, "Monitor %s: requested %ix%i@%2f, found available mode: %ix%i@%imHz, applying.", + pMonitor->output->name, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate, + mode->width, mode->height, mode->refresh); + + found = true; + + pMonitor->refreshRate = mode->refresh / 1000.f; + pMonitor->vecSize = Vector2D(mode->width, mode->height); + + break; + } + } + + if (!found) { + const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output); + + if (!PREFERREDMODE) { + Debug::log(ERR, "Monitor %s has NO PREFERRED MODE, and an INVALID one was requested: %ix%i@%2f", + (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate); + return; + } + + // Preferred is valid + wlr_output_set_mode(pMonitor->output, PREFERREDMODE); + + Debug::log(ERR, "Monitor %s got an invalid requested mode: %ix%i@%2f, using the preferred one instead: %ix%i@%2f", + pMonitor->output->name, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate, + PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f); + + pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f; + pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height); + } + } else { + wlr_output_set_custom_mode(pMonitor->output, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (int)pMonitorRule->refreshRate * 1000); + } + + // update renderer + g_pHyprOpenGL->destroyMonitorResources(pMonitor); + + if (!wlr_output_commit(pMonitor->output)) { + Debug::log(ERR, "Couldn't commit output named %s", pMonitor->output->name); + return; + } } \ No newline at end of file diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 27fe9cf6..ee95e121 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -7,6 +7,8 @@ #include "../Window.hpp" #include "OpenGL.hpp" +struct SMonitorRule; + // TODO: add fuller damage tracking for updating only parts of a window enum DAMAGETRACKINGMODES { DAMAGE_TRACKING_INVALID = -1, @@ -25,6 +27,7 @@ public: void damageWindow(CWindow*); void damageBox(wlr_box*); void damageMonitor(SMonitor*); + void applyMonitorRule(SMonitor*, SMonitorRule*, bool force = false); DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&);