diff --git a/.gitignore b/.gitignore index 259148f..2cbc7ae 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,5 @@ *.exe *.out *.app + +.vscode/ \ No newline at end of file diff --git a/README.md b/README.md index fc50684..105f0e3 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,12 @@ # hyprland-plugins -Official plugins for Hyprland + +This repo houses official plugins for Hyprland. + +# Plugin list + - csgo-vulkan-fix -> fixes custom resolutions on CS:GO with `-vulkan` + +# Contributing + +Feel free to open issues and MRs with fixes. + +If you want your plugin added here, contact vaxry beforehand. \ No newline at end of file diff --git a/csgo-vulkan-fix/Makefile b/csgo-vulkan-fix/Makefile new file mode 100644 index 0000000..e5be73c --- /dev/null +++ b/csgo-vulkan-fix/Makefile @@ -0,0 +1,8 @@ +# compile with HYPRLAND_HEADERS= make all +# make sure that the path above is to the root hl repo directory, NOT src/ +# and that you have ran `make protocols` in the hl dir. + +all: + g++ -shared -fPIC --no-gnu-unique main.cpp -o csgo-vulkan-fix.so -g -I "/usr/include/pixman-1" -I "/usr/include/libdrm" -I "${HYPRLAND_HEADERS}" -std=c++23 +clean: + rm ./csgo-vulkan-fix.so diff --git a/csgo-vulkan-fix/README.md b/csgo-vulkan-fix/README.md new file mode 100644 index 0000000..8531d5e --- /dev/null +++ b/csgo-vulkan-fix/README.md @@ -0,0 +1,22 @@ +# csgo-vulkan-fix + +If you want to play CS:GO with `-vulkan`, you're locked to your native res. + +With this plugin, you aren't anymore. + +CSGO launch options: +``` +-window -w -h -vulkan +``` + +example plugin config: +``` +plugin { + csgo-vulkan-fix { + res_w = 1680 + res_h = 1050 + } +} +``` + +fullscreen the game manually and enjoy. \ No newline at end of file diff --git a/csgo-vulkan-fix/globals.hpp b/csgo-vulkan-fix/globals.hpp new file mode 100644 index 0000000..37e8363 --- /dev/null +++ b/csgo-vulkan-fix/globals.hpp @@ -0,0 +1,5 @@ +#pragma once + +#include + +inline HANDLE PHANDLE = nullptr; \ No newline at end of file diff --git a/csgo-vulkan-fix/main.cpp b/csgo-vulkan-fix/main.cpp new file mode 100644 index 0000000..681da5c --- /dev/null +++ b/csgo-vulkan-fix/main.cpp @@ -0,0 +1,96 @@ +#define WLR_USE_UNSTABLE + +#include + +#include +#include +#include + +#include "globals.hpp" + +// Methods +inline CFunctionHook* g_pMouseMotionHook = nullptr; +inline CFunctionHook* g_pSurfaceSizeHook = nullptr; +inline CFunctionHook* g_pSurfaceDamageHook = nullptr; +typedef void (*origMotion)(wlr_seat*, uint32_t, double, double); +typedef void (*origSurfaceSize)(wlr_xwayland_surface*, int16_t, int16_t, uint16_t, uint16_t); +typedef void (*origSurfaceDamage)(wlr_surface*, pixman_region32_t*); + +// store the surface for csgo. May be invalid, only compare against +inline wlr_surface* pCSGOSurface = nullptr; +inline wlr_xwayland_surface* pCSGOXWSurface = nullptr; +inline int csgoMonitor = 0; + +// Do NOT change this function. +APICALL EXPORT std::string PLUGIN_API_VERSION() { return HYPRLAND_API_VERSION; } + +void onNewWindow(void* self, std::any data) { + // data is guaranteed + auto* const PWINDOW = std::any_cast(data); + + if (g_pXWaylandManager->getAppIDClass(PWINDOW) == "csgo_linux64") { + pCSGOSurface = g_pXWaylandManager->getWindowSurface(PWINDOW); + pCSGOXWSurface = PWINDOW->m_uSurface.xwayland; + csgoMonitor = PWINDOW->m_iMonitorID; + } +} + +void hkNotifyMotion(wlr_seat* wlr_seat, uint32_t time_msec, double sx, double sy) { + static auto* const RESX = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:csgo-vulkan-fix:res_w")->intValue; + static auto* const RESY = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:csgo-vulkan-fix:res_h")->intValue; + + if (g_pCompositor->m_pLastFocus == pCSGOSurface && g_pCompositor->m_pLastMonitor) { + // fix the coords + sx *= *RESX / g_pCompositor->m_pLastMonitor->vecSize.x; + sy *= *RESY / g_pCompositor->m_pLastMonitor->vecSize.y; + } + + (*(origMotion)g_pMouseMotionHook->m_pOriginal)(wlr_seat, time_msec, sx, sy); +} + +void hkSetWindowSize(wlr_xwayland_surface* surface, int16_t x, int16_t y, uint16_t width, uint16_t height) { + static auto* const RESX = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:csgo-vulkan-fix:res_w")->intValue; + static auto* const RESY = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:csgo-vulkan-fix:res_h")->intValue; + + if (surface == pCSGOXWSurface) { + width = *RESX; + height = *RESY; + } + + (*(origSurfaceSize)g_pSurfaceSizeHook->m_pOriginal)(surface, x, y, width, height); +} + +void hkSurfaceDamage(wlr_surface* surface, pixman_region32_t* damage) { + (*(origSurfaceDamage)g_pSurfaceDamageHook->m_pOriginal)(surface, damage); + + if (surface == pCSGOSurface) { + const auto PMONITOR = g_pCompositor->getMonitorFromID(csgoMonitor); + + if (PMONITOR) pixman_region32_union_rect(damage, damage, 0, 0, PMONITOR->vecSize.x, PMONITOR->vecSize.y); + } +} + +APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { + PHANDLE = handle; + + HyprlandAPI::addConfigValue(PHANDLE, "plugin:csgo-vulkan-fix:res_w", SConfigValue{.intValue = 1680}); + HyprlandAPI::addConfigValue(PHANDLE, "plugin:csgo-vulkan-fix:res_h", SConfigValue{.intValue = 1050}); + + g_pMouseMotionHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&wlr_seat_pointer_notify_motion, (void*)&hkNotifyMotion); + g_pSurfaceSizeHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&wlr_xwayland_surface_configure, (void*)&hkSetWindowSize); + g_pSurfaceDamageHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&wlr_surface_get_effective_damage, (void*)&hkSurfaceDamage); + bool hkResult = g_pMouseMotionHook->hook(); + hkResult = hkResult && g_pSurfaceSizeHook->hook(); + hkResult = hkResult && g_pSurfaceDamageHook->hook(); + + HyprlandAPI::registerCallbackDynamic(PHANDLE, "openWindow", [&](void* self, std::any data) { onNewWindow(self, data); }); + + if (hkResult) + HyprlandAPI::addNotification(PHANDLE, "[csgo-vulkan-fix] Initialized successfully!", CColor{0.2, 1.0, 0.2, 1.0}, 5000); + else + HyprlandAPI::addNotification(PHANDLE, "[csgo-vulkan-fix] Failure in initialization (hook failed)!", CColor{1.0, 0.2, 0.2, 1.0}, 5000); + + return {"csgo-vulkan-fix", "A plugin to fix incorrect mouse offsets on csgo in Vulkan", "Vaxry", "1.0"}; +} + +APICALL EXPORT void PLUGIN_EXIT() { ; } \ No newline at end of file