hyprland-dwindle-autogroup/src/main.cpp

167 lines
5.7 KiB
C++

#define WLR_USE_UNSTABLE
#include "globals.hpp"
#include <src/Window.hpp>
#include <src/layout/DwindleLayout.hpp>
#include <src/managers/KeybindManager.hpp>
#include <src/managers/LayoutManager.hpp>
const CColor s_pluginColor = {0x61 / 255.0f, 0xAF / 255.0f, 0xEF / 255.0f, 1.0f};
inline std::function<void(std::string)> originalToggleGroup = nullptr;
typedef SDwindleNodeData* (*nodeFromWindowT)(void*, CWindow*);
inline nodeFromWindowT g_pNodeFromWindow = nullptr;
void addChildNodesToDequeRecursive(std::deque<SDwindleNodeData*>* pDeque, std::deque<SDwindleNodeData*>* pParents, SDwindleNodeData* node)
{
if (node->isNode) {
pParents->push_back(node);
addChildNodesToDequeRecursive(pDeque, pParents, node->children[0]);
addChildNodesToDequeRecursive(pDeque, pParents, node->children[1]);
}
else {
pDeque->emplace_back(node);
}
}
void groupDissolve(const SDwindleNodeData* PNODE, CHyprDwindleLayout* layout)
{
CWindow* PWINDOW = PNODE->pWindow;
// This group only has this single winodw
if (PWINDOW->m_sGroupData.pNextWindow == PWINDOW) {
Debug::log(LOG, "Ignoring autogroup on single window dissolve");
originalToggleGroup("");
return;
}
Debug::log(LOG, "Dissolving group");
// We currently don't need any special logic for dissolving, just call the original func
originalToggleGroup("");
}
void groupCreate(const SDwindleNodeData* PNODE, CHyprDwindleLayout* layout)
{
const auto PWINDOW = PNODE->pWindow;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PNODE->workspaceID);
if (PWORKSPACE->m_bHasFullscreenWindow) {
Debug::log(LOG, "Ignoring autogroup on a fullscreen window");
originalToggleGroup("");
return;
}
if (!PNODE->pParent) {
Debug::log(LOG, "Ignoring autogroup for a solitary window");
originalToggleGroup("");
return;
}
Debug::log(LOG, "Creating group");
// Call the original toggleGroup function, and only do extra things afterwards
originalToggleGroup("");
std::deque<SDwindleNodeData*> newGroupMembers;
std::deque<SDwindleNodeData*> parentNodes;
addChildNodesToDequeRecursive(
&newGroupMembers, &parentNodes, PNODE->pParent->children[0] == PNODE ? PNODE->pParent->children[1] : PNODE->pParent->children[0]);
// Make sure one of the child nodes isn't itself a group
for (auto& n : newGroupMembers) {
if (n->pWindow->m_sGroupData.pNextWindow) {
Debug::log(LOG, "Ignoring autogroup for nested groups");
return;
}
}
// Add all of the children nodes into the group
for (auto& n : newGroupMembers) {
auto window = n->pWindow;
layout->onWindowRemoved(window);
PWINDOW->insertWindowToGroup(window);
window->m_dWindowDecorations.emplace_back(std::make_unique<CHyprGroupBarDecoration>(window));
PWINDOW->setGroupCurrent(PWINDOW);
}
}
void toggleGroup(std::string args)
{
// We only care about group creations, not group disolves
const auto PWINDOW = g_pCompositor->m_pLastWindow;
if (!PWINDOW || !g_pCompositor->windowValidMapped(PWINDOW))
return;
// Don't do anything if we're not on "dwindle" layout
IHyprLayout* layout = g_pLayoutManager->getCurrentLayout();
if (layout->getLayoutName() != "dwindle") {
Debug::log(LOG, "Ignoring autogroup for non-dinwle layout");
originalToggleGroup(args);
return;
}
CHyprDwindleLayout* cur_dwindle = (CHyprDwindleLayout*)layout;
const auto PNODE = g_pNodeFromWindow(cur_dwindle, PWINDOW);
if (!PNODE) {
Debug::log(LOG, "Ignoring autogroup for floating window");
originalToggleGroup(args);
return;
}
if (PWINDOW->m_sGroupData.pNextWindow) {
groupDissolve(PNODE, cur_dwindle);
} else {
groupCreate(PNODE, cur_dwindle);
}
}
// Do NOT change this function.
APICALL EXPORT std::string PLUGIN_API_VERSION()
{
return HYPRLAND_API_VERSION;
}
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle)
{
PHANDLE = handle;
// Get address of the private CHyprDwindleLayout::getNodeFromWindow member function, we'll need it in toggleGroup
static const auto METHODS = HyprlandAPI::findFunctionsByName(PHANDLE, "getNodeFromWindow");
g_pNodeFromWindow = (nodeFromWindowT)METHODS[1].address;
for (auto& method : METHODS) {
if (method.demangled == "CHyprDwindleLayout::getNodeFromWindow(CWindow*)") {
g_pNodeFromWindow = (nodeFromWindowT)method.address;
break;
}
}
if (g_pNodeFromWindow == nullptr) {
Debug::log(ERR, "getNodeFromWindow funnction for dwindle layout wasn't found! This function's signature probably changed, report this");
HyprlandAPI::addNotification(
PHANDLE, "[dwindle-autogroup] Initialization failed!! getNodeFromWindow functio not found", s_pluginColor, 10000);
}
else {
originalToggleGroup = g_pKeybindManager->m_mDispatchers["togglegroup"];
HyprlandAPI::addDispatcher(PHANDLE, "togglegroup", toggleGroup);
HyprlandAPI::reloadConfig();
HyprlandAPI::addNotification(PHANDLE, "[dwindle-autogroup] Initialized successfully!", s_pluginColor, 5000);
}
return {"dwindle-autogroup", "Dwindle Autogroup", "ItsDrike", "1.0"};
}
APICALL EXPORT void PLUGIN_EXIT()
{
// Since we added the "togglegroup" dispatcher ourselves, by default, the cleanup would just remove it
// but we want to restore it back to the original function instead
HyprlandAPI::removeDispatcher(PHANDLE, "togglegroup");
g_pKeybindManager->m_mDispatchers["togglegroup"] = originalToggleGroup;
HyprlandAPI::addNotification(PHANDLE, "[dwindle-autogroup] Unloaded successfully!", s_pluginColor, 5000);
}