Added creating / destroying outputs on a multi-backend + headless backend

See `hyprctl output`.
This commit is contained in:
vaxerski 2022-11-05 18:04:44 +00:00
parent a71f44baa5
commit 5a750b485a
9 changed files with 129 additions and 1 deletions

View file

@ -217,6 +217,21 @@ int setcursorRequest(int argc, char** argv) {
return 0; return 0;
} }
int outputRequest(int argc, char** argv) {
if (argc < 4) {
std::cout << "Usage: hyprctl output <mode> <name>\n\
creates / destroys a fake output\n\
with create, name is the backend name to use (available: auto, x11, wayland, headless)\n\
with destroy, name is the output name to destroy";
return 1;
}
std::string rq = "output " + std::string(argv[2]) + " " + std::string(argv[3]);
request(rq);
return 0;
}
void batchRequest(std::string arg) { void batchRequest(std::string arg) {
std::string rq = "[[BATCH]]" + arg.substr(arg.find_first_of(" ") + 1); std::string rq = "[[BATCH]]" + arg.substr(arg.find_first_of(" ") + 1);
@ -290,6 +305,7 @@ int main(int argc, char** argv) {
else if (fullRequest.contains("/reload")) request(fullRequest); else if (fullRequest.contains("/reload")) request(fullRequest);
else if (fullRequest.contains("/getoption")) request(fullRequest); else if (fullRequest.contains("/getoption")) request(fullRequest);
else if (fullRequest.contains("/cursorpos")) request(fullRequest); else if (fullRequest.contains("/cursorpos")) request(fullRequest);
else if (fullRequest.contains("/output")) exitStatus = outputRequest(argc, argv);
else if (fullRequest.contains("/setcursor")) exitStatus = setcursorRequest(argc, argv); else if (fullRequest.contains("/setcursor")) exitStatus = setcursorRequest(argc, argv);
else if (fullRequest.contains("/dispatch")) exitStatus = dispatchRequest(argc, argv); else if (fullRequest.contains("/dispatch")) exitStatus = dispatchRequest(argc, argv);
else if (fullRequest.contains("/keyword")) exitStatus = keywordRequest(argc, argv); else if (fullRequest.contains("/keyword")) exitStatus = keywordRequest(argc, argv);

View file

@ -180,6 +180,15 @@ CCompositor::CCompositor() {
m_sWLRIMEMgr = wlr_input_method_manager_v2_create(m_sWLDisplay); m_sWLRIMEMgr = wlr_input_method_manager_v2_create(m_sWLDisplay);
m_sWLRActivation = wlr_xdg_activation_v1_create(m_sWLDisplay); m_sWLRActivation = wlr_xdg_activation_v1_create(m_sWLDisplay);
m_sWLRHeadlessBackend = wlr_headless_backend_create(m_sWLDisplay);
if (!m_sWLRHeadlessBackend) {
Debug::log(CRIT, "Couldn't create the headless backend");
throw std::runtime_error("wlr_headless_backend_create() failed!");
}
wlr_multi_backend_add(m_sWLRBackend, m_sWLRHeadlessBackend);
} }
CCompositor::~CCompositor() { CCompositor::~CCompositor() {

View file

@ -71,6 +71,7 @@ public:
wlr_text_input_manager_v3* m_sWLRTextInputMgr; wlr_text_input_manager_v3* m_sWLRTextInputMgr;
wlr_xdg_activation_v1* m_sWLRActivation; wlr_xdg_activation_v1* m_sWLRActivation;
wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf; wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf;
wlr_backend* m_sWLRHeadlessBackend;
// ------------------------------------------------- // // ------------------------------------------------- //

View file

@ -743,6 +743,86 @@ R"#(
} }
} }
void createOutputIter(wlr_backend* backend, void* data) {
const auto DATA = (std::pair<std::string, bool>*)data;
if (DATA->second)
return;
if (DATA->first.empty() || DATA->first == "auto") {
if (wlr_backend_is_wl(backend)) {
wlr_wl_output_create(backend);
DATA->second = true;
} else if (wlr_backend_is_x11(backend)) {
wlr_x11_output_create(backend);
DATA->second = true;
} else if (wlr_backend_is_headless(backend)) {
wlr_headless_add_output(backend, 1920, 1080);
DATA->second = true;
}
} else {
if (wlr_backend_is_wl(backend) && DATA->first == "wayland") {
wlr_wl_output_create(backend);
DATA->second = true;
} else if (wlr_backend_is_x11(backend) && DATA->first == "x11") {
wlr_x11_output_create(backend);
DATA->second = true;
} else if (wlr_backend_is_headless(backend) && DATA->first == "headless") {
wlr_headless_add_output(backend, 1920, 1080);
DATA->second = true;
}
}
}
std::string dispatchOutput(std::string request) {
std::string curitem = "";
auto nextItem = [&]() {
auto idx = request.find_first_of(' ');
if (idx != std::string::npos) {
curitem = request.substr(0, idx);
request = request.substr(idx + 1);
} else {
curitem = request;
request = "";
}
curitem = removeBeginEndSpacesTabs(curitem);
};
nextItem();
nextItem();
const auto MODE = curitem;
nextItem();
const auto NAME = curitem;
if (MODE == "create" || MODE == "add") {
std::pair<std::string, bool> result = { NAME, false };
wlr_multi_for_each_backend(g_pCompositor->m_sWLRBackend, createOutputIter, &result);
if (!result.second)
return "no backend replied to the request";
} else if (MODE == "destroy" || MODE == "remove") {
const auto PMONITOR = g_pCompositor->getMonitorFromName(NAME);
if (!PMONITOR)
return "output not found";
if (!PMONITOR->createdByUser)
return "cannot remove a real display. Use the monitor keyword.";
wlr_output_destroy(PMONITOR->output);
}
return "ok";
}
std::string getReply(std::string request) { std::string getReply(std::string request) {
auto format = HyprCtl::FORMAT_NORMAL; auto format = HyprCtl::FORMAT_NORMAL;
@ -786,6 +866,8 @@ std::string getReply(std::string request) {
return splashRequest(); return splashRequest();
else if (request == "cursorpos") else if (request == "cursorpos")
return cursorPosRequest(format); return cursorPosRequest(format);
else if (request.find("output") == 0)
return dispatchOutput(request);
else if (request.find("dispatch") == 0) else if (request.find("dispatch") == 0)
return dispatchRequest(request); return dispatchRequest(request);
else if (request.find("keyword") == 0) else if (request.find("keyword") == 0)

View file

@ -8,6 +8,9 @@ void CMonitor::onConnect(bool noRule) {
szName = output->name; szName = output->name;
if (!wlr_backend_is_drm(output->backend))
createdByUser = true; // should be true. WL, X11 and Headless backends should be addable / removable
// get monitor rule that matches // get monitor rule that matches
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(output->name, output->description ? output->description : ""); SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(output->name, output->description ? output->description : "");

View file

@ -40,6 +40,7 @@ public:
bool dpmsStatus = true; bool dpmsStatus = true;
bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it. bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed. bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
bool createdByUser = false;
// mirroring // mirroring
CMonitor* pMirrorOf = nullptr; CMonitor* pMirrorOf = nullptr;

View file

@ -155,3 +155,7 @@ inline void wlr_xwayland_surface_close(wlr_xwayland_surface*) { }
inline void wlr_xwayland_surface_set_fullscreen(wlr_xwayland_surface*, bool) { } inline void wlr_xwayland_surface_set_fullscreen(wlr_xwayland_surface*, bool) { }
inline void wlr_xwayland_surface_set_minimized(wlr_xwayland_surface *, bool) { } inline void wlr_xwayland_surface_set_minimized(wlr_xwayland_surface *, bool) { }
inline bool wlr_backend_is_x11(void*) { return false; }
inline void wlr_x11_output_create(void*) { }

View file

@ -99,10 +99,15 @@ extern "C" {
#include <wlr/types/wlr_text_input_v3.h> #include <wlr/types/wlr_text_input_v3.h>
#include <wlr/types/wlr_touch.h> #include <wlr/types/wlr_touch.h>
#include <wlr/types/wlr_switch.h> #include <wlr/types/wlr_switch.h>
#include <wlr/config.h>
#include <wlr/backend/headless.h>
#include <wlr/backend/multi.h>
#include <wlr/backend/wayland.h>
#include <drm_fourcc.h> #include <drm_fourcc.h>
#ifndef NO_XWAYLAND #ifndef NO_XWAYLAND
#include <wlr/backend/x11.h>
#include <wlr/xwayland.h> #include <wlr/xwayland.h>
#include <X11/Xproto.h> #include <X11/Xproto.h>
#endif #endif

View file

@ -1347,6 +1347,13 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
pMonitor->vecSize = (Vector2D(x, y) / pMonitor->scale).floor(); pMonitor->vecSize = (Vector2D(x, y) / pMonitor->scale).floor();
pMonitor->vecTransformedSize = Vector2D(x,y); pMonitor->vecTransformedSize = Vector2D(x,y);
if (pMonitor->createdByUser) {
wlr_box transformedBox = { 0, 0, (int)pMonitor->vecTransformedSize.x, (int)pMonitor->vecTransformedSize.y };
wlr_box_transform(&transformedBox, &transformedBox, wlr_output_transform_invert(pMonitor->output->transform), (int)pMonitor->vecTransformedSize.x, (int)pMonitor->vecTransformedSize.y);
pMonitor->vecPixelSize = Vector2D(transformedBox.width, transformedBox.height);
}
if (pMonitorRule->offset == Vector2D(-1, -1) && pMonitor->vecPosition == Vector2D(-1, -1)) { if (pMonitorRule->offset == Vector2D(-1, -1) && pMonitor->vecPosition == Vector2D(-1, -1)) {
// let's find manually a sensible position for it, to the right. // let's find manually a sensible position for it, to the right.
Vector2D finalPos; Vector2D finalPos;