Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Save restore dwindle layout #9054

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/debug/HyprCtl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,17 @@ static std::string layoutsRequest(eHyprCtlOutputFormat format, std::string reque
return result;
}

static std::string layoutDataRequest(eHyprCtlOutputFormat format, std::string request) {
const auto CURRENT_LAYOUT = g_pLayoutManager->getCurrentLayout();

if (!CURRENT_LAYOUT) {
Debug::log(ERR, "No current layout?!!");
return "";
}

return CURRENT_LAYOUT->layoutDataRequest(format, request);
}

static std::string configErrorsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = "";
std::string currErrors = g_pConfigManager->getErrors();
Expand Down Expand Up @@ -1648,6 +1659,7 @@ CHyprCtl::CHyprCtl() {
registerCommand(SHyprCtlCommand{"descriptions", true, getDescriptions});
registerCommand(SHyprCtlCommand{"submap", true, submapRequest});

registerCommand(SHyprCtlCommand{"layoutdata", false, layoutDataRequest});
registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest});
registerCommand(SHyprCtlCommand{"reload", false, reloadRequest});
registerCommand(SHyprCtlCommand{"plugin", false, dispatchPlugin});
Expand Down
168 changes: 166 additions & 2 deletions src/layout/DwindleLayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include <format>

void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverride, bool verticalOverride) {
if (children[0]) {
Expand Down Expand Up @@ -244,8 +245,13 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir
const auto MOUSECOORDS = m_vOverrideFocalPoint.value_or(g_pInputManager->getMouseCoordsInternal());
const auto MONFROMCURSOR = g_pCompositor->getMonitorFromVector(MOUSECOORDS);

if (PMONITOR->ID == MONFROMCURSOR->ID &&
(PNODE->workspaceID == PMONITOR->activeWorkspaceID() || (g_pCompositor->isWorkspaceSpecial(PNODE->workspaceID) && PMONITOR->activeSpecialWorkspace)) && !*PUSEACTIVE) {
if (m_pOpenNextOn && m_pOpenNextOn->valid && m_pOpenNextOn->workspaceID == pWindow->workspaceID()) {
OPENINGON = m_pOpenNextOn;
m_pOpenNextOn = nullptr;

} else if (PMONITOR->ID == MONFROMCURSOR->ID &&
(PNODE->workspaceID == PMONITOR->activeWorkspaceID() || (g_pCompositor->isWorkspaceSpecial(PNODE->workspaceID) && PMONITOR->activeSpecialWorkspace)) &&
!*PUSEACTIVE) {
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS));

if (!OPENINGON && g_pCompositor->isPointOnReservedArea(MOUSECOORDS, PMONITOR))
Expand Down Expand Up @@ -455,6 +461,7 @@ void CHyprDwindleLayout::onWindowRemovedTiling(PHLWINDOW pWindow) {
if (!PPARENT) {
Debug::log(LOG, "Removing last node (dwindle)");
m_lDwindleNodesData.remove(*PNODE);
m_pOpenNextOn = nullptr;
return;
}

Expand All @@ -479,6 +486,9 @@ void CHyprDwindleLayout::onWindowRemovedTiling(PHLWINDOW pWindow) {
else
PSIBLING->recalcSizePosRecursive();

if (PPARENT == m_pOpenNextOn || PNODE == m_pOpenNextOn)
m_pOpenNextOn = nullptr;

m_lDwindleNodesData.remove(*PPARENT);
m_lDwindleNodesData.remove(*PNODE);
}
Expand Down Expand Up @@ -968,11 +978,164 @@ std::any CHyprDwindleLayout::layoutMessage(SLayoutMessageHeader header, std::str
break;
}
}
} else if (ARGS[0] == "opennexton") {
const auto RELATION = ARGS[1];
const auto WINDOW = ARGS[2].empty() ? header.pWindow : g_pCompositor->getWindowByRegex(ARGS[2]);
auto pNode = getNodeFromWindow(WINDOW);
for (const auto c : RELATION) {
if (!pNode || !pNode->valid)
break;

switch (c) {
case '^': {
// Step to the parent of the current node
pNode = pNode->pParent;
break;
}

case 'c': {
// Clear anything previously set
m_pOpenNextOn = nullptr;
return "";
}

case '.': {
// Steps nowhere (if you simply want to use the second argument)
break;
}

case '0': {
// Step to the first child
pNode = pNode->children[0];
break;
}

case '1': {
// Step to the second child
pNode = pNode->children[1];
break;
}

case '/': {
// Step to the root of the current node's workspace
pNode = getMasterNodeOnWorkspace(pNode->workspaceID);
break;
}

default: {
Debug::log(ERR, "Unknown relation operator");
return "";
}
}
}

if (pNode && pNode->valid)
m_pOpenNextOn = pNode;
else
Debug::log(ERR, "Invalid dwindle node");
}

return "";
}

static bool printNodeTree(const SDwindleNodeData* const node, eHyprCtlOutputFormat format, std::string& indent, std::string& out) {
if (!node || !node->valid) {
Debug::log(ERR, "Invalid dwindle Node");
return false;
}

const auto INDENTLVL = indent.length();
indent += format == eHyprCtlOutputFormat::FORMAT_JSON ? " " : "\t";

if (node->children[0] && node->children[0]->valid) {
if (format == eHyprCtlOutputFormat::FORMAT_JSON)
out += std::format("\n{}\"{}\": {{", indent, (node->splitTop ? "top" : "left"));
else
out += std::format("\n{}{}:", indent, (node->splitTop ? "top" : "left"));

if (!printNodeTree(node->children[0], format, indent, out)) {
indent.erase(INDENTLVL);
return false;
}

if (format == eHyprCtlOutputFormat::FORMAT_JSON)
out += std::format("\n{}}},", indent);

if (node->children[1] && node->children[1]->valid) {
if (format == eHyprCtlOutputFormat::FORMAT_JSON)
out += std::format("\n{}\"{}\": {{", indent, (node->splitTop ? "bottom" : "right"));
else
out += std::format("\n{}{}:", indent, (node->splitTop ? "bottom" : "right"));

if (!printNodeTree(node->children[1], format, indent, out)) {
indent.erase(INDENTLVL);
return false;
}

if (format == eHyprCtlOutputFormat::FORMAT_JSON)
out += std::format("\n{}}},", indent);
}

if (format == eHyprCtlOutputFormat::FORMAT_JSON)
out += std::format("\n{}\"splitRatio\": {}", indent, node->splitRatio);
else
out += std::format("\n{}splitRatio: {}", indent, node->splitRatio);

} else if (node->pWindow) {
if (format == eHyprCtlOutputFormat::FORMAT_JSON)
out += std::format("\n{}\"address\": \"0x{:x}\","
"\n{}\"class\": \"{}\","
"\n{}\"title\": \"{}\","
"\n{}\"initialClass\": \"{}\","
"\n{}\"initialTitle\": \"{}\","
"\n{}\"pid\": \"{}\"",
indent, (uintptr_t)node->pWindow.get(), indent, escapeJSONStrings(node->pWindow->m_szClass), indent, escapeJSONStrings(node->pWindow->m_szTitle),
indent, escapeJSONStrings(node->pWindow->m_szInitialClass), indent, escapeJSONStrings(node->pWindow->m_szInitialTitle), indent,
node->pWindow->getPID());
else
out += std::format("\n{}address: 0x{:x}"
"\n{}class: {}"
"\n{}title: {}"
"\n{}initialClass: {}"
"\n{}initialTitle: {}"
"\n{}pid: {}",
indent, (uintptr_t)node->pWindow.get(), indent, escapeJSONStrings(node->pWindow->m_szClass), indent, escapeJSONStrings(node->pWindow->m_szTitle),
indent, escapeJSONStrings(node->pWindow->m_szInitialClass), indent, escapeJSONStrings(node->pWindow->m_szInitialTitle), indent,
node->pWindow->getPID());
}

indent.erase(INDENTLVL);
return true;
}

std::string CHyprDwindleLayout::layoutDataRequest(eHyprCtlOutputFormat format, std::string request) {
const auto ARGS = CVarList(request, 0, ' ');
std::string result = "";

if (ARGS[1] == "workspaceinfo") {
const auto& [WORKSPACEID, workspaceName] = getWorkspaceIDNameFromString(ARGS[2]);
if (WORKSPACEID == WORKSPACE_INVALID) {
Debug::log(ERR, "Invalid workspace in layoutdata workspaceinfo");
}

auto PHEAD_NODE = getMasterNodeOnWorkspace(WORKSPACEID);
std::string indent = "";

if (format == eHyprCtlOutputFormat::FORMAT_JSON)
result += "{";
else
result += "root:";
printNodeTree(PHEAD_NODE, format, indent, result);
if (format == eHyprCtlOutputFormat::FORMAT_JSON)
result += "\n}";

} else {
Debug::log(LOG, "Unknown layoutdata request");
}

return result;
}

void CHyprDwindleLayout::toggleSplit(PHLWINDOW pWindow) {
const auto PNODE = getNodeFromWindow(pWindow);

Expand Down Expand Up @@ -1065,6 +1228,7 @@ void CHyprDwindleLayout::onEnable() {

void CHyprDwindleLayout::onDisable() {
m_lDwindleNodesData.clear();
m_pOpenNextOn = nullptr;
}

Vector2D CHyprDwindleLayout::predictSizeForNewWindowTiled() {
Expand Down
2 changes: 2 additions & 0 deletions src/layout/DwindleLayout.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class CHyprDwindleLayout : public IHyprLayout {
virtual void resizeActiveWindow(const Vector2D&, eRectCorner corner = CORNER_NONE, PHLWINDOW pWindow = nullptr);
virtual void fullscreenRequestForWindow(PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE);
virtual std::any layoutMessage(SLayoutMessageHeader, std::string);
virtual std::string layoutDataRequest(eHyprCtlOutputFormat format, std::string request);
virtual SWindowRenderLayoutHints requestRenderHints(PHLWINDOW);
virtual void switchWindows(PHLWINDOW, PHLWINDOW);
virtual void moveWindowTo(PHLWINDOW, const std::string& dir, bool silent);
Expand Down Expand Up @@ -89,6 +90,7 @@ class CHyprDwindleLayout : public IHyprLayout {
void moveToRoot(PHLWINDOW, bool stable = true);

eDirection overrideDirection = DIRECTION_DEFAULT;
SDwindleNodeData* m_pOpenNextOn = nullptr;

friend struct SDwindleNodeData;
};
Expand Down
7 changes: 7 additions & 0 deletions src/layout/IHyprLayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -945,4 +945,11 @@ Vector2D IHyprLayout::predictSizeForNewWindow(PHLWINDOW pWindow) {
return sizePredicted;
}

std::string IHyprLayout::layoutDataRequest(eHyprCtlOutputFormat format, std::string request) {
if (format == eHyprCtlOutputFormat::FORMAT_JSON)
return "\"Not implemented for the current layout\"";
else
return "Not implemented for the current layout";
}

IHyprLayout::~IHyprLayout() = default;
5 changes: 5 additions & 0 deletions src/layout/IHyprLayout.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,11 @@ class IHyprLayout {
virtual Vector2D predictSizeForNewWindow(PHLWINDOW pWindow);
virtual Vector2D predictSizeForNewWindowFloating(PHLWINDOW pWindow);

/*
Like 'dispatch layoutmsg' but with possible return values for use with hyprctl.
*/
virtual std::string layoutDataRequest(eHyprCtlOutputFormat format, std::string request);

private:
int m_iMouseMoveEventCount;
Vector2D m_vBeginDragXY;
Expand Down
Loading