mirror of
https://github.com/ItsDrike/hyprland-dwindle-autogroup.git
synced 2025-04-18 09:12:28 +00:00
167 lines
5.7 KiB
C++
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);
|
|
}
|