Hyprland/src/helpers/Monitor.cpp

371 lines
12 KiB
C++
Raw Normal View History

2022-07-27 12:32:00 +02:00
#include "Monitor.hpp"
#include "../Compositor.hpp"
void CMonitor::onConnect(bool noRule) {
2022-11-19 14:14:55 +01:00
hyprListener_monitorDestroy.removeCallback();
hyprListener_monitorFrame.removeCallback();
2022-11-19 17:28:04 +01:00
hyprListener_monitorStateRequest.removeCallback();
2022-11-19 14:14:55 +01:00
hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this);
hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this);
2022-11-19 17:28:04 +01:00
hyprListener_monitorStateRequest.initCallback(&output->events.request_state, &Events::listener_monitorStateRequest, this);
2022-11-19 14:14:55 +01:00
if (m_bEnabled) {
wlr_output_enable(output, 1);
wlr_output_commit(output);
2022-08-03 16:05:25 +02:00
return;
2022-11-19 14:14:55 +01:00
}
2022-08-03 16:05:25 +02:00
szName = output->name;
if (!wlr_backend_is_drm(output->backend))
createdByUser = true; // should be true. WL, X11 and Headless backends should be addable / removable
2022-07-27 12:32:00 +02:00
// get monitor rule that matches
2022-10-05 11:22:33 +02:00
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(output->name, output->description ? output->description : "");
2022-07-27 12:32:00 +02:00
// if it's disabled, disable and ignore
if (monitorRule.disabled) {
wlr_output_set_scale(output, 1);
wlr_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL);
auto PREFSTATE = wlr_output_preferred_mode(output);
if (!PREFSTATE) {
wlr_output_mode* mode;
wl_list_for_each(mode, &output->modes, link) {
wlr_output_set_mode(output, PREFSTATE);
if (!wlr_output_test(output))
continue;
2022-09-25 20:07:48 +02:00
PREFSTATE = mode;
break;
}
}
if (PREFSTATE)
wlr_output_set_mode(output, PREFSTATE);
else
2022-08-10 13:45:20 +02:00
Debug::log(WARN, "No mode found for disabled output %s", output->name);
2022-07-27 12:32:00 +02:00
wlr_output_enable(output, 0);
2022-09-25 20:07:48 +02:00
if (!wlr_output_commit(output)) {
Debug::log(ERR, "Couldn't commit disabled state on output %s", output->name);
}
Events::listener_change(nullptr, nullptr);
2022-07-27 12:32:00 +02:00
m_bEnabled = false;
2022-07-27 12:32:00 +02:00
hyprListener_monitorFrame.removeCallback();
return;
}
if (output->non_desktop) {
Debug::log(LOG, "Not configuring non-desktop output");
if (g_pCompositor->m_sWRLDRMLeaseMgr) {
wlr_drm_lease_v1_manager_offer_output(g_pCompositor->m_sWRLDRMLeaseMgr, output);
}
return;
}
if (!m_bRenderingInitPassed) {
2022-09-19 21:45:00 +02:00
output->allocator = nullptr;
output->renderer = nullptr;
wlr_output_init_render(output, g_pCompositor->m_sWLRAllocator, g_pCompositor->m_sWLRRenderer);
m_bRenderingInitPassed = true;
}
2022-08-03 17:42:19 +02:00
if (!m_pThisWrap) {
// find the wrap
for (auto& m : g_pCompositor->m_vRealMonitors) {
if (m->ID == ID) {
m_pThisWrap = &m;
break;
}
}
}
2022-07-27 12:32:00 +02:00
if (std::find_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& other) { return other.get() == this; }) == g_pCompositor->m_vMonitors.end()){
g_pCompositor->m_vMonitors.push_back(*m_pThisWrap);
}
2022-09-25 20:07:48 +02:00
2022-07-27 12:32:00 +02:00
m_bEnabled = true;
2022-11-18 15:15:19 +01:00
2022-07-27 12:32:00 +02:00
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, monitorRule.scale);
// create it in the arr
vecPosition = monitorRule.offset;
vecSize = monitorRule.resolution;
refreshRate = monitorRule.refreshRate;
wlr_output_enable(output, 1);
// set mode, also applies
if (!noRule)
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
2022-08-10 18:27:57 +02:00
Debug::log(LOG, "Added new monitor with name %s at %i,%i with size %ix%i, pointer %x", output->name, (int)vecPosition.x, (int)vecPosition.y, (int)vecPixelSize.x, (int)vecPixelSize.y, output);
2022-07-27 12:32:00 +02:00
damage = wlr_output_damage_create(output);
// add a WLR workspace group
if (!pWLRWorkspaceGroupHandle) {
pWLRWorkspaceGroupHandle = wlr_ext_workspace_group_handle_v1_create(g_pCompositor->m_sWLREXTWorkspaceMgr);
}
2022-09-25 20:07:48 +02:00
2022-07-27 12:32:00 +02:00
wlr_ext_workspace_group_handle_v1_output_enter(pWLRWorkspaceGroupHandle, output);
2022-09-25 20:07:48 +02:00
2022-09-13 15:25:42 +02:00
setupDefaultWS(monitorRule);
2022-07-27 12:32:00 +02:00
scale = monitorRule.scale;
2022-08-03 17:42:19 +02:00
m_pThisWrap = nullptr;
2022-07-27 12:32:00 +02:00
forceFullFrames = 3; // force 3 full frames to make sure there is no blinking due to double-buffering.
//
2022-11-19 17:41:36 +01:00
g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName});
2022-07-27 12:32:00 +02:00
if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet
2022-11-19 17:41:36 +01:00
g_pCompositor->setActiveMonitor(this);
2022-07-27 12:32:00 +02:00
2022-08-10 21:22:11 +02:00
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, scale);
2022-08-10 21:54:09 +02:00
g_pHyprRenderer->arrangeLayersForMonitor(ID);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
2022-10-22 22:45:17 +02:00
// ensure VRR (will enable if necessary)
g_pConfigManager->ensureVRR(this);
2022-07-27 12:32:00 +02:00
}
void CMonitor::onDisconnect() {
2022-08-03 16:05:25 +02:00
2022-10-06 19:43:50 +02:00
if (!m_bEnabled || g_pCompositor->m_bIsShuttingDown)
2022-08-03 16:05:25 +02:00
return;
Debug::log(LOG, "onDisconnect called for %s", output->name);
2022-07-27 12:32:00 +02:00
// Cleanup everything. Move windows back, snap cursor, shit.
CMonitor* BACKUPMON = nullptr;
for (auto& m : g_pCompositor->m_vMonitors) {
if (m.get() != this) {
BACKUPMON = m.get();
break;
}
}
2022-10-29 23:45:01 +02:00
if (g_pCompositor->m_pLastMonitor == this)
2022-11-19 17:41:36 +01:00
g_pCompositor->setActiveMonitor(BACKUPMON);
2022-10-29 23:45:01 +02:00
2022-09-13 15:25:42 +02:00
// remove mirror
if (pMirrorOf) {
pMirrorOf->mirrors.erase(std::find_if(pMirrorOf->mirrors.begin(), pMirrorOf->mirrors.end(), [&](const auto& other) { return other == this; }));
pMirrorOf = nullptr;
}
if (!mirrors.empty()) {
for (auto& m : mirrors) {
m->setMirror("");
}
g_pConfigManager->m_bWantsMonitorReload = true;
}
2022-07-27 12:32:00 +02:00
m_bEnabled = false;
2022-08-10 23:19:15 +02:00
m_bRenderingInitPassed = false;
2022-07-27 12:32:00 +02:00
hyprListener_monitorFrame.removeCallback();
2022-08-10 21:54:09 +02:00
if (!BACKUPMON) {
Debug::log(WARN, "Unplugged last monitor, entering an unsafe state. Good luck my friend.");
2022-11-19 17:28:04 +01:00
hyprListener_monitorStateRequest.removeCallback();
2022-08-10 21:54:09 +02:00
hyprListener_monitorDestroy.removeCallback();
g_pCompositor->m_bUnsafeState = true;
return;
}
2022-07-27 12:32:00 +02:00
// snap cursor
2022-11-17 22:52:45 +01:00
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, BACKUPMON->vecPosition.x + BACKUPMON->vecTransformedSize.x / 2.f, BACKUPMON->vecPosition.y + BACKUPMON->vecTransformedSize.y / 2.f);
2022-07-27 12:32:00 +02:00
// move workspaces
std::deque<CWorkspace*> wspToMove;
for (auto& w : g_pCompositor->m_vWorkspaces) {
if (w->m_iMonitorID == ID) {
wspToMove.push_back(w.get());
}
}
for (auto& w : wspToMove) {
g_pCompositor->moveWorkspaceToMonitor(w, BACKUPMON);
w->startAnim(true, true, true);
}
activeWorkspace = -1;
wlr_output_damage_destroy(damage);
wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output);
wlr_output_enable(output, false);
wlr_output_commit(output);
2022-11-17 22:52:45 +01:00
std::erase_if(g_pCompositor->m_vWorkspaces, [&](std::unique_ptr<CWorkspace>& el) { return el->m_iMonitorID == ID; });
2022-07-27 12:32:00 +02:00
Debug::log(LOG, "Removed monitor %s!", szName.c_str());
g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName});
2022-11-17 22:52:45 +01:00
std::erase_if(g_pCompositor->m_vMonitors, [&](std::shared_ptr<CMonitor>& el) { return el.get() == this; });
2022-07-27 12:32:00 +02:00
}
2022-08-23 16:07:47 +02:00
void CMonitor::addDamage(pixman_region32_t* rg) {
wlr_output_damage_add(damage, rg);
}
void CMonitor::addDamage(wlr_box* box) {
wlr_output_damage_add_box(damage, box);
}
2022-09-13 15:25:42 +02:00
bool CMonitor::isMirror() {
return pMirrorOf != nullptr;
}
void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) {
// Workspace
std::string newDefaultWorkspaceName = "";
auto WORKSPACEID = monitorRule.defaultWorkspace == "" ? g_pCompositor->m_vWorkspaces.size() + 1 : getWorkspaceIDFromString(monitorRule.defaultWorkspace, newDefaultWorkspaceName);
if (WORKSPACEID == INT_MAX || WORKSPACEID == (long unsigned int)SPECIAL_WORKSPACE_ID) {
WORKSPACEID = g_pCompositor->m_vWorkspaces.size() + 1;
newDefaultWorkspaceName = std::to_string(WORKSPACEID);
Debug::log(LOG, "Invalid workspace= directive name in monitor parsing, workspace name \"%s\" is invalid.", monitorRule.defaultWorkspace.c_str());
}
auto PNEWWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);
Debug::log(LOG, "New monitor: WORKSPACEID %d, exists: %d", WORKSPACEID, (int)(PNEWWORKSPACE != nullptr));
if (PNEWWORKSPACE) {
// workspace exists, move it to the newly connected monitor
g_pCompositor->moveWorkspaceToMonitor(PNEWWORKSPACE, this);
activeWorkspace = PNEWWORKSPACE->m_iID;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
PNEWWORKSPACE->startAnim(true, true, true);
} else {
if (newDefaultWorkspaceName == "")
newDefaultWorkspaceName = std::to_string(WORKSPACEID);
PNEWWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(ID, newDefaultWorkspaceName)).get();
// We are required to set the name here immediately
wlr_ext_workspace_handle_v1_set_name(PNEWWORKSPACE->m_pWlrHandle, newDefaultWorkspaceName.c_str());
PNEWWORKSPACE->m_iID = WORKSPACEID;
}
activeWorkspace = PNEWWORKSPACE->m_iID;
g_pCompositor->deactivateAllWLRWorkspaces(PNEWWORKSPACE->m_pWlrHandle);
PNEWWORKSPACE->setActive(true);
}
void CMonitor::setMirror(const std::string& mirrorOf) {
const auto PMIRRORMON = g_pCompositor->getMonitorFromString(mirrorOf);
if (PMIRRORMON == pMirrorOf)
return;
if (PMIRRORMON && PMIRRORMON->isMirror()) {
Debug::log(ERR, "Cannot mirror a mirror!");
return;
}
if (PMIRRORMON == this) {
Debug::log(ERR, "Cannot mirror self!");
return;
}
if (!PMIRRORMON) {
// disable mirroring
if (pMirrorOf) {
pMirrorOf->mirrors.erase(std::find_if(pMirrorOf->mirrors.begin(), pMirrorOf->mirrors.end(), [&](const auto& other) { return other == this; }));
}
pMirrorOf = nullptr;
// set rule
2022-10-05 11:22:33 +02:00
const auto RULE = g_pConfigManager->getMonitorRuleFor(this->szName, this->output->description ? this->output->description : "");
2022-09-13 15:25:42 +02:00
vecPosition = RULE.offset;
// push to mvmonitors
if (!m_pThisWrap) {
// find the wrap
for (auto& m : g_pCompositor->m_vRealMonitors) {
if (m->ID == ID) {
m_pThisWrap = &m;
break;
}
}
}
if (std::find_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& other) { return other.get() == this; }) == g_pCompositor->m_vMonitors.end()) {
g_pCompositor->m_vMonitors.push_back(*m_pThisWrap);
}
setupDefaultWS(RULE);
g_pHyprRenderer->applyMonitorRule(this, (SMonitorRule*)&RULE, true); // will apply the offset and stuff
2022-09-13 15:25:42 +02:00
} else {
CMonitor* BACKUPMON = nullptr;
for (auto& m : g_pCompositor->m_vMonitors) {
if (m.get() != this) {
BACKUPMON = m.get();
break;
}
}
// move all the WS
std::deque<CWorkspace*> wspToMove;
for (auto& w : g_pCompositor->m_vWorkspaces) {
if (w->m_iMonitorID == ID) {
wspToMove.push_back(w.get());
}
}
for (auto& w : wspToMove) {
g_pCompositor->moveWorkspaceToMonitor(w, BACKUPMON);
w->startAnim(true, true, true);
}
activeWorkspace = -1;
wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output);
vecPosition = Vector2D(-1337420, -1337420);
pMirrorOf = PMIRRORMON;
pMirrorOf->mirrors.push_back(this);
// remove from mvmonitors
if (std::find_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& other) { return other.get() == this; }) != g_pCompositor->m_vMonitors.end()) {
g_pCompositor->m_vMonitors.erase(std::remove_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](const auto& other) { return other.get() == this; }));
}
2022-11-19 17:41:36 +01:00
g_pCompositor->setActiveMonitor(g_pCompositor->m_vMonitors.front().get());
2022-09-13 15:25:42 +02:00
}
}