hyprland-plugins/hyprwinwrap/main.cpp

240 lines
9.7 KiB
C++
Raw Normal View History

2023-11-24 21:13:34 +00:00
#define WLR_USE_UNSTABLE
#include <unistd.h>
#include <vector>
#include <hyprland/src/includes.hpp>
#include <any>
2024-07-21 13:40:40 +02:00
#include <sstream>
2023-11-24 21:13:34 +00:00
#define private public
#include <hyprland/src/Compositor.hpp>
2024-03-20 03:02:10 +00:00
#include <hyprland/src/desktop/Window.hpp>
2023-11-24 21:13:34 +00:00
#include <hyprland/src/config/ConfigManager.hpp>
#include <hyprland/src/render/Renderer.hpp>
2025-01-17 19:20:10 +01:00
#include <hyprland/src/managers/LayoutManager.hpp>
#include <hyprland/src/managers/input/InputManager.hpp>
2025-04-17 19:59:55 -04:00
#include <hyprland/src/helpers/time/Time.hpp>
2023-11-24 21:13:34 +00:00
#undef private
#include "globals.hpp"
// Do NOT change this function
2023-11-24 21:13:34 +00:00
APICALL EXPORT std::string PLUGIN_API_VERSION() {
return HYPRLAND_API_VERSION;
}
// hooks
2024-03-01 13:44:29 +00:00
inline CFunctionHook* subsurfaceHook = nullptr;
inline CFunctionHook* commitHook = nullptr;
typedef void (*origCommitSubsurface)(CSubsurface* thisptr);
2023-11-24 21:13:34 +00:00
typedef void (*origCommit)(void* owner, void* data);
2024-04-27 13:03:46 +01:00
std::vector<PHLWINDOWREF> bgWindows;
2023-11-24 21:13:34 +00:00
2024-04-27 13:03:46 +01:00
void onNewWindow(PHLWINDOW pWindow) {
static auto* const PCLASS = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprwinwrap:class")->getDataStaticPtr();
static auto* const PTITLE = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprwinwrap:title")->getDataStaticPtr();
static auto* const PSIZEX = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprwinwrap:size_x")->getDataStaticPtr();
static auto* const PSIZEY = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprwinwrap:size_y")->getDataStaticPtr();
static auto* const PPOSX = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprwinwrap:pos_x")->getDataStaticPtr();
static auto* const PPOSY = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprwinwrap:pos_y")->getDataStaticPtr();
2023-11-24 21:13:34 +00:00
const std::string classRule(*PCLASS);
const std::string titleRule(*PTITLE);
const bool classMatches = !classRule.empty() && pWindow->m_initialClass == classRule;
const bool titleMatches = !titleRule.empty() && pWindow->m_title == titleRule;
if (!classMatches && !titleMatches)
2023-11-24 21:13:34 +00:00
return;
2025-04-29 14:21:14 +01:00
const auto PMONITOR = pWindow->m_monitor.lock();
2023-11-24 21:13:34 +00:00
if (!PMONITOR)
return;
2025-04-29 14:21:14 +01:00
if (!pWindow->m_isFloating)
2023-11-24 21:13:34 +00:00
g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(pWindow);
float sx = 100.f, sy = 100.f, px = 0.f, py = 0.f;
try { sx = std::stof(*PSIZEX); } catch (...) {}
try { sy = std::stof(*PSIZEY); } catch (...) {}
try { px = std::stof(*PPOSX); } catch (...) {}
try { py = std::stof(*PPOSY); } catch (...) {}
sx = std::clamp(sx, 1.f, 100.f);
sy = std::clamp(sy, 1.f, 100.f);
px = std::clamp(px, 0.f, 100.f);
py = std::clamp(py, 0.f, 100.f);
if (px + sx > 100.f) {
Debug::log(WARN, "[hyprwinwrap] size_x (%d) + pos_x (%d) > 100, adjusting size_x to %d", sx, px, 100.f - px);
sx = 100.f - px;
}
if (py + sy > 100.f) {
Debug::log(WARN, "[hyprwinwrap] size_y (%d) + pos_y (%d) > 100, adjusting size_y to %d", sy, py, 100.f - py);
sy = 100.f - py;
}
const Vector2D monitorSize = PMONITOR->m_size;
const Vector2D monitorPos = PMONITOR->m_position;
const Vector2D newSize = {
static_cast<int>(monitorSize.x * (sx / 100.f)),
static_cast<int>(monitorSize.y * (sy / 100.f))
};
const Vector2D newPos = {
static_cast<int>(monitorPos.x + (monitorSize.x * (px / 100.f))),
static_cast<int>(monitorPos.y + (monitorSize.y * (py / 100.f)))
};
pWindow->m_realSize->setValueAndWarp(newSize);
pWindow->m_realPosition->setValueAndWarp(newPos);
pWindow->m_size = newSize;
pWindow->m_position = newPos;
pWindow->m_pinned = true;
2025-02-07 23:07:05 +01:00
pWindow->sendWindowSize(true);
2023-11-24 21:13:34 +00:00
bgWindows.push_back(pWindow);
pWindow->m_hidden = true;
2023-11-24 21:13:34 +00:00
g_pInputManager->refocus();
Debug::log(LOG, "[hyprwinwrap] new window moved to bg {}", pWindow);
}
2024-04-27 13:03:46 +01:00
void onCloseWindow(PHLWINDOW pWindow) {
std::erase_if(bgWindows, [pWindow](const auto& ref) { return ref.expired() || ref.lock() == pWindow; });
2023-11-24 21:13:34 +00:00
Debug::log(LOG, "[hyprwinwrap] closed window {}", pWindow);
}
void onRenderStage(eRenderStage stage) {
if (stage != RENDER_PRE_WINDOWS)
return;
2024-04-27 13:03:46 +01:00
for (auto& bg : bgWindows) {
const auto bgw = bg.lock();
if (bgw->m_monitor != g_pHyprOpenGL->m_renderData.pMonitor)
2023-11-24 21:13:34 +00:00
continue;
2024-02-06 16:11:46 +00:00
// cant use setHidden cuz that sends suspended and shit too that would be laggy
2025-04-29 14:21:14 +01:00
bgw->m_hidden = false;
2023-11-24 21:13:34 +00:00
g_pHyprRenderer->renderWindow(bgw, g_pHyprOpenGL->m_renderData.pMonitor.lock(), Time::steadyNow(), false, RENDER_PASS_ALL, false, true);
2023-11-24 21:13:34 +00:00
2025-04-29 14:21:14 +01:00
bgw->m_hidden = true;
2023-11-24 21:13:34 +00:00
}
}
2024-03-01 13:44:29 +00:00
void onCommitSubsurface(CSubsurface* thisptr) {
const auto PWINDOW = thisptr->m_wlSurface->getWindow();
2023-11-24 21:13:34 +00:00
2024-04-27 13:03:46 +01:00
if (!PWINDOW || std::find_if(bgWindows.begin(), bgWindows.end(), [PWINDOW](const auto& ref) { return ref.lock() == PWINDOW; }) == bgWindows.end()) {
((origCommitSubsurface)subsurfaceHook->m_original)(thisptr);
2023-11-24 21:13:34 +00:00
return;
}
2024-02-06 16:11:46 +00:00
// cant use setHidden cuz that sends suspended and shit too that would be laggy
2025-04-29 14:21:14 +01:00
PWINDOW->m_hidden = false;
2023-11-24 21:13:34 +00:00
((origCommitSubsurface)subsurfaceHook->m_original)(thisptr);
2025-04-29 14:21:14 +01:00
if (const auto MON = PWINDOW->m_monitor.lock(); MON)
g_pHyprOpenGL->markBlurDirtyForMonitor(MON);
2023-11-24 21:13:34 +00:00
2025-04-29 14:21:14 +01:00
PWINDOW->m_hidden = true;
2023-11-24 21:13:34 +00:00
}
void onCommit(void* owner, void* data) {
2025-04-29 14:21:14 +01:00
const auto PWINDOW = ((CWindow*)owner)->m_self.lock();
2023-11-24 21:13:34 +00:00
2024-04-27 13:03:46 +01:00
if (std::find_if(bgWindows.begin(), bgWindows.end(), [PWINDOW](const auto& ref) { return ref.lock() == PWINDOW; }) == bgWindows.end()) {
((origCommit)commitHook->m_original)(owner, data);
2023-11-24 21:13:34 +00:00
return;
}
2024-02-06 16:11:46 +00:00
// cant use setHidden cuz that sends suspended and shit too that would be laggy
2025-04-29 14:21:14 +01:00
PWINDOW->m_hidden = false;
2023-11-24 21:13:34 +00:00
((origCommit)commitHook->m_original)(owner, data);
2025-04-29 14:21:14 +01:00
if (const auto MON = PWINDOW->m_monitor.lock(); MON)
g_pHyprOpenGL->markBlurDirtyForMonitor(MON);
2023-11-24 21:13:34 +00:00
2025-04-29 14:21:14 +01:00
PWINDOW->m_hidden = true;
2023-11-24 21:13:34 +00:00
}
void onConfigReloaded() {
2024-02-18 15:30:21 +00:00
static auto* const PCLASS = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprwinwrap:class")->getDataStaticPtr();
const std::string classRule(*PCLASS);
if (!classRule.empty()) {
g_pConfigManager->parseKeyword("windowrulev2", std::string{"float, class:^("} + classRule + ")$");
g_pConfigManager->parseKeyword("windowrulev2", std::string{"size 100\% 100\%, class:^("} + classRule + ")$");
}
static auto* const PTITLE = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprwinwrap:title")->getDataStaticPtr();
const std::string titleRule(*PTITLE);
if (!titleRule.empty()) {
g_pConfigManager->parseKeyword("windowrulev2", std::string{"float, title:^("} + titleRule + ")$");
g_pConfigManager->parseKeyword("windowrulev2", std::string{"size 100\% 100\%, title:^("} + titleRule + ")$");
}
2023-11-24 21:13:34 +00:00
}
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
PHANDLE = handle;
const std::string HASH = __hyprland_api_get_hash();
if (HASH != GIT_COMMIT_HASH) {
HyprlandAPI::addNotification(PHANDLE, "[hyprwinwrap] Failure in initialization: Version mismatch (headers ver is not equal to running hyprland ver)",
2024-12-04 09:58:09 -05:00
CHyprColor{1.0, 0.2, 0.2, 1.0}, 5000);
throw std::runtime_error("[hww] Version mismatch");
}
2024-04-22 15:57:18 +01:00
// clang-format off
2024-04-27 13:03:46 +01:00
static auto P = HyprlandAPI::registerCallbackDynamic(PHANDLE, "openWindow", [&](void* self, SCallbackInfo& info, std::any data) { onNewWindow(std::any_cast<PHLWINDOW>(data)); });
static auto P2 = HyprlandAPI::registerCallbackDynamic(PHANDLE, "closeWindow", [&](void* self, SCallbackInfo& info, std::any data) { onCloseWindow(std::any_cast<PHLWINDOW>(data)); });
2024-04-22 15:57:18 +01:00
static auto P3 = HyprlandAPI::registerCallbackDynamic(PHANDLE, "render", [&](void* self, SCallbackInfo& info, std::any data) { onRenderStage(std::any_cast<eRenderStage>(data)); });
static auto P4 = HyprlandAPI::registerCallbackDynamic(PHANDLE, "configReloaded", [&](void* self, SCallbackInfo& info, std::any data) { onConfigReloaded(); });
// clang-format on
2023-11-24 21:13:34 +00:00
2024-03-01 13:44:29 +00:00
auto fns = HyprlandAPI::findFunctionsByName(PHANDLE, "onCommit");
2023-11-24 21:13:34 +00:00
if (fns.size() < 1)
2024-03-01 13:44:29 +00:00
throw std::runtime_error("hyprwinwrap: onCommit not found");
for (auto& fn : fns) {
if (!fn.demangled.contains("CSubsurface"))
continue;
subsurfaceHook = HyprlandAPI::createFunctionHook(PHANDLE, fn.address, (void*)&onCommitSubsurface);
2024-03-01 13:44:29 +00:00
}
2023-11-24 21:13:34 +00:00
fns = HyprlandAPI::findFunctionsByName(PHANDLE, "listener_commitWindow");
if (fns.size() < 1)
throw std::runtime_error("hyprwinwrap: listener_commitWindow not found");
commitHook = HyprlandAPI::createFunctionHook(PHANDLE, fns[0].address, (void*)&onCommit);
2024-03-01 13:44:29 +00:00
bool hkResult = subsurfaceHook->hook();
2023-11-24 21:13:34 +00:00
hkResult = hkResult && commitHook->hook();
if (!hkResult)
throw std::runtime_error("hyprwinwrap: hooks failed");
2024-02-18 15:30:21 +00:00
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprwinwrap:class", Hyprlang::STRING{"kitty-bg"});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprwinwrap:title", Hyprlang::STRING{""});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprwinwrap:size_x", Hyprlang::STRING{"100"});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprwinwrap:size_y", Hyprlang::STRING{"100"});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprwinwrap:pos_x", Hyprlang::STRING{"0"});
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprwinwrap:pos_y", Hyprlang::STRING{"0"});
2024-12-04 09:58:09 -05:00
HyprlandAPI::addNotification(PHANDLE, "[hyprwinwrap] Initialized successfully!", CHyprColor{0.2, 1.0, 0.2, 1.0}, 5000);
2023-11-24 21:13:34 +00:00
return {"hyprwinwrap", "A clone of xwinwrap for Hyprland", "Vaxry", "1.0"};
}
APICALL EXPORT void PLUGIN_EXIT() {
;
}