mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-07 15:25:59 +01:00
Added dynamic monitor rules
This commit is contained in:
parent
1eec8c3741
commit
08ee14b4a0
7 changed files with 116 additions and 53 deletions
|
@ -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));
|
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
|
else
|
||||||
g_pHyprError->destroy();
|
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() {
|
void CConfigManager::tick() {
|
||||||
|
@ -526,4 +533,13 @@ void CConfigManager::dispatchExecOnce() {
|
||||||
}
|
}
|
||||||
|
|
||||||
firstExecRequests.clear(); // free some kb of memory :P
|
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;
|
||||||
}
|
}
|
|
@ -55,6 +55,9 @@ public:
|
||||||
// no-op when done.
|
// no-op when done.
|
||||||
void dispatchExecOnce();
|
void dispatchExecOnce();
|
||||||
|
|
||||||
|
void performMonitorReload();
|
||||||
|
bool m_bWantsMonitorReload = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<std::string, SConfigValue> configValues;
|
std::unordered_map<std::string, SConfigValue> configValues;
|
||||||
time_t lastModifyTime = 0; // for reloading the config if changed
|
time_t lastModifyTime = 0; // for reloading the config if changed
|
||||||
|
|
|
@ -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_output_coords returns invalid values, I think...
|
||||||
wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, OUTPUT, monitorRule.offset.x, monitorRule.offset.y);
|
wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, OUTPUT, monitorRule.offset.x, monitorRule.offset.y);
|
||||||
|
|
||||||
// loop over modes and choose an appropriate one.
|
// set mode, also applies
|
||||||
if (!wl_list_empty(&OUTPUT->modes)) {
|
g_pHyprRenderer->applyMonitorRule(PNEWMONITOR, &monitorRule, true);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
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
|
// add a WLR workspace group
|
||||||
PNEWMONITOR->pWLRWorkspaceGroupHandle = wlr_ext_workspace_group_handle_v1_create(g_pCompositor->m_sWLREXTWorkspaceMgr);
|
PNEWMONITOR->pWLRWorkspaceGroupHandle = wlr_ext_workspace_group_handle_v1_create(g_pCompositor->m_sWLREXTWorkspaceMgr);
|
||||||
|
|
||||||
// add damage
|
|
||||||
PNEWMONITOR->damage = wlr_output_damage_create(OUTPUT);
|
|
||||||
|
|
||||||
// Workspace
|
// 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;
|
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);
|
g_pCompositor->m_lWorkspaces.emplace_back(newMonitor.ID);
|
||||||
|
@ -179,6 +131,9 @@ void Events::listener_monitorFrame(void* owner, void* data) {
|
||||||
g_pCompositor->cleanupWindows();
|
g_pCompositor->cleanupWindows();
|
||||||
|
|
||||||
g_pConfigManager->dispatchExecOnce(); // We exec-once when at least one monitor starts refreshing, meaning stuff has init'd
|
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;
|
timespec now;
|
||||||
|
|
|
@ -685,4 +685,15 @@ void CHyprOpenGLImpl::clearWithTex() {
|
||||||
wlr_box box = {0, 0, m_RenderData.pMonitor->vecSize.x, m_RenderData.pMonitor->vecSize.y};
|
wlr_box box = {0, 0, m_RenderData.pMonitor->vecSize.x, m_RenderData.pMonitor->vecSize.y};
|
||||||
|
|
||||||
renderTexture(m_mMonitorBGTextures[m_RenderData.pMonitor], &box, 255, 0);
|
renderTexture(m_mMonitorBGTextures[m_RenderData.pMonitor], &box, 255, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
|
@ -60,6 +60,8 @@ public:
|
||||||
void scissor(const wlr_box*);
|
void scissor(const wlr_box*);
|
||||||
void scissor(const pixman_box32*);
|
void scissor(const pixman_box32*);
|
||||||
|
|
||||||
|
void destroyMonitorResources(SMonitor*);
|
||||||
|
|
||||||
SCurrentRenderData m_RenderData;
|
SCurrentRenderData m_RenderData;
|
||||||
|
|
||||||
GLint m_iCurrentOutputFb = 0;
|
GLint m_iCurrentOutputFb = 0;
|
||||||
|
|
|
@ -490,4 +490,77 @@ DAMAGETRACKINGMODES CHyprRenderer::damageTrackingModeFromStr(const std::string&
|
||||||
return DAMAGE_TRACKING_NONE;
|
return DAMAGE_TRACKING_NONE;
|
||||||
|
|
||||||
return DAMAGE_TRACKING_INVALID;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -7,6 +7,8 @@
|
||||||
#include "../Window.hpp"
|
#include "../Window.hpp"
|
||||||
#include "OpenGL.hpp"
|
#include "OpenGL.hpp"
|
||||||
|
|
||||||
|
struct SMonitorRule;
|
||||||
|
|
||||||
// TODO: add fuller damage tracking for updating only parts of a window
|
// TODO: add fuller damage tracking for updating only parts of a window
|
||||||
enum DAMAGETRACKINGMODES {
|
enum DAMAGETRACKINGMODES {
|
||||||
DAMAGE_TRACKING_INVALID = -1,
|
DAMAGE_TRACKING_INVALID = -1,
|
||||||
|
@ -25,6 +27,7 @@ public:
|
||||||
void damageWindow(CWindow*);
|
void damageWindow(CWindow*);
|
||||||
void damageBox(wlr_box*);
|
void damageBox(wlr_box*);
|
||||||
void damageMonitor(SMonitor*);
|
void damageMonitor(SMonitor*);
|
||||||
|
void applyMonitorRule(SMonitor*, SMonitorRule*, bool force = false);
|
||||||
|
|
||||||
DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&);
|
DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue