pax_global_header00006660000000000000000000000064152010533120014502gustar00rootroot0000000000000052 comment=90e66baf99c9025b1d5e9c9e58dd3c80d0911ea2 hyprwm-hyprland-plugins-3ba8bfb/000077500000000000000000000000001520105331200170775ustar00rootroot00000000000000hyprwm-hyprland-plugins-3ba8bfb/.clang-format000066400000000000000000000034161520105331200214560ustar00rootroot00000000000000--- Language: Cpp BasedOnStyle: LLVM AccessModifierOffset: -2 AlignAfterOpenBracket: Align AlignConsecutiveMacros: true AlignConsecutiveAssignments: true AlignEscapedNewlines: Right AlignOperands: false AlignTrailingComments: true AllowAllArgumentsOnNextLine: true AllowAllConstructorInitializersOnNextLine: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: true AllowShortCaseLabelsOnASingleLine: true AllowShortFunctionsOnASingleLine: Empty AllowShortIfStatementsOnASingleLine: Never AllowShortLambdasOnASingleLine: All AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: Yes BreakBeforeBraces: Attach BreakBeforeTernaryOperators: false BreakConstructorInitializers: AfterColon ColumnLimit: 180 CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: false ExperimentalAutoDetectBinPacking: false FixNamespaceComments: false IncludeBlocks: Preserve IndentCaseLabels: true IndentWidth: 4 PointerAlignment: Left ReflowComments: false SortIncludes: false SortUsingDeclarations: false SpaceAfterCStyleCast: false SpaceAfterLogicalNot: false SpaceAfterTemplateKeyword: true SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatements SpaceBeforeRangeBasedForLoopColon: true SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 1 SpacesInAngles: false SpacesInCStyleCastParentheses: false SpacesInContainerLiterals: false SpacesInParentheses: false SpacesInSquareBrackets: false Standard: Auto TabWidth: 4 UseTab: Never AllowShortEnumsOnASingleLine: false BraceWrapping: AfterEnum: false AlignConsecutiveDeclarations: AcrossEmptyLines NamespaceIndentation: All hyprwm-hyprland-plugins-3ba8bfb/.github/000077500000000000000000000000001520105331200204375ustar00rootroot00000000000000hyprwm-hyprland-plugins-3ba8bfb/.github/workflows/000077500000000000000000000000001520105331200224745ustar00rootroot00000000000000hyprwm-hyprland-plugins-3ba8bfb/.github/workflows/nix-build.yml000066400000000000000000000003161520105331200251120ustar00rootroot00000000000000on: workflow_call: jobs: build: uses: hyprwm/actions/.github/workflows/nix.yml@main secrets: inherit with: command: | nix flake update nix flake check -L --keep-going hyprwm-hyprland-plugins-3ba8bfb/.github/workflows/nix-ci.yml000066400000000000000000000001631520105331200244060ustar00rootroot00000000000000name: Nix on: [push, pull_request, workflow_dispatch] jobs: build: uses: ./.github/workflows/nix-build.yml hyprwm-hyprland-plugins-3ba8bfb/.gitignore000066400000000000000000000005121520105331200210650ustar00rootroot00000000000000# Prerequisites *.d # Compiled Object files *.slo *.lo *.o *.obj # Precompiled Headers *.gch *.pch # Compiled Dynamic libraries *.so *.dylib *.dll # Fortran module files *.mod *.smod # Compiled Static libraries *.lai *.la *.a *.lib # Executables *.exe *.out *.app # Editors .vscode/ # Nix result result-man build/ .cache/hyprwm-hyprland-plugins-3ba8bfb/CMakeLists.txt000066400000000000000000000005001520105331200216320ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.27) project(hyprland-plugins DESCRIPTION "Official plugins for Hyprland" LANGUAGES CXX ) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) add_subdirectory(borders-plus-plus) add_subdirectory(csgo-vulkan-fix) add_subdirectory(hyprbars) add_subdirectory(hyprfocus) hyprwm-hyprland-plugins-3ba8bfb/LICENSE000066400000000000000000000027371520105331200201150ustar00rootroot00000000000000BSD 3-Clause License Copyright (c) 2023, Hypr Development Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. hyprwm-hyprland-plugins-3ba8bfb/README.md000066400000000000000000000050411520105331200203560ustar00rootroot00000000000000## hyprland-plugins This repo houses official plugins for Hyprland. ## Plugin list - borders-plus-plus -> adds one or two additional borders to windows - csgo-vulkan-fix -> fixes custom resolutions on CS:GO with `-vulkan` - hyprbars -> adds title bars to windows - hyprfocus -> flashfocus for hyprland ## Install > [!IMPORTANT] > hyprland-plugins only officially supports installation via `hyprpm`. > `hyprpm` automatically detects your hyprland version & installs only > the corresponding "pinned" release of hyprland-plugins. > If you want the latest commits to hyprland-plugins, you need to use > `hyprland-git`. ### Install with `hyprpm` To install these plugins, from the command line run: ```bash hyprpm update ``` Then add this repository: ```bash hyprpm add https://github.com/hyprwm/hyprland-plugins ``` then enable the desired plugin with ```bash hyprpm enable ``` See the respective README's in the subdirectories for configuration options. See [the plugins wiki](https://wiki.hyprland.org/Plugins/Using-Plugins/#installing--using-plugins) and `hyprpm -h` for more details. ### Install on Nix To use these plugins, it's recommended that you are already using the [Hyprland flake](https://github.com/hyprwm/Hyprland). First, add this flake to your inputs: ```nix inputs = { # ... hyprland.url = "github:hyprwm/Hyprland"; hyprland-plugins = { url = "github:hyprwm/hyprland-plugins"; inputs.hyprland.follows = "hyprland"; }; # ... }; ``` The `inputs.hyprland.follows` guarantees the plugins will always be built using your locked Hyprland version, thus you will never get version mismatches that lead to errors. After that's done, you can use the plugins with the Home Manager module like this: ```nix {inputs, pkgs, ...}: { wayland.windowManager.hyprland = { enable = true; # ... plugins = [ inputs.hyprland-plugins.packages.${pkgs.stdenv.hostPlatform.system}.hyprbars # ... ]; }; } ``` If you don't use Home Manager: ```nix { lib, pkgs, inputs, ... }: with lib; let hyprPluginPkgs = inputs.hyprland-plugins.packages.${pkgs.stdenv.hostPlatform.system}; hypr-plugin-dir = pkgs.symlinkJoin { name = "hyrpland-plugins"; paths = with hyprPluginPkgs; [ hyprexpo #...plugins ]; }; in { environment.sessionVariables = { HYPR_PLUGIN_DIR = hypr-plugin-dir; }; } ``` And in `hyprland.conf` ```hyprlang # load all the plugins you installed exec-once = hyprctl plugin load "$HYPR_PLUGIN_DIR/lib/libhyprexpo.so" ``` ## Contributing Feel free to open issues and MRs with fixes. hyprwm-hyprland-plugins-3ba8bfb/borders-plus-plus/000077500000000000000000000000001520105331200225015ustar00rootroot00000000000000hyprwm-hyprland-plugins-3ba8bfb/borders-plus-plus/BorderppPassElement.cpp000066400000000000000000000010621520105331200271220ustar00rootroot00000000000000#include "BorderppPassElement.hpp" #include #include #include "borderDeco.hpp" CBorderPPPassElement::CBorderPPPassElement(const CBorderPPPassElement::SBorderPPData& data_) : data(data_) { ; } std::vector> CBorderPPPassElement::draw() { data.deco->drawPass(g_pHyprRenderer->m_renderData.pMonitor.lock(), data.a); return {}; } bool CBorderPPPassElement::needsLiveBlur() { return false; } bool CBorderPPPassElement::needsPrecomputeBlur() { return false; } hyprwm-hyprland-plugins-3ba8bfb/borders-plus-plus/BorderppPassElement.hpp000066400000000000000000000014371520105331200271350ustar00rootroot00000000000000#pragma once #include class CBordersPlusPlus; class CBorderPPPassElement : public IPassElement { public: struct SBorderPPData { CBordersPlusPlus* deco = nullptr; float a = 1.F; }; CBorderPPPassElement(const SBorderPPData& data_); virtual ~CBorderPPPassElement() = default; virtual std::vector> draw() override; virtual bool needsLiveBlur() override; virtual bool needsPrecomputeBlur() override; virtual const char* passName() override { return "CBorderPPPassElement"; } virtual ePassElementType type() override { return EK_CUSTOM; } private: SBorderPPData data; }; hyprwm-hyprland-plugins-3ba8bfb/borders-plus-plus/CMakeLists.txt000066400000000000000000000010361520105331200252410ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.27) project(borders-plus-plus DESCRIPTION "borders-plus-plus plugin for Hyprland" VERSION 0.1 ) set(CMAKE_CXX_STANDARD 23) file(GLOB_RECURSE SRC "*.cpp") add_library(borders-plus-plus SHARED ${SRC}) find_package(PkgConfig REQUIRED) pkg_check_modules(deps REQUIRED IMPORTED_TARGET hyprland libdrm libinput libudev pangocairo pixman-1 wayland-server xkbcommon ) target_link_libraries(borders-plus-plus PRIVATE rt PkgConfig::deps) install(TARGETS borders-plus-plus) hyprwm-hyprland-plugins-3ba8bfb/borders-plus-plus/Makefile000066400000000000000000000006561520105331200241500ustar00rootroot00000000000000# Else exist specifically for clang ifeq ($(CXX),g++) EXTRA_FLAGS = --no-gnu-unique else EXTRA_FLAGS = endif CXXFLAGS ?= -O2 CXXFLAGS += -shared -fPIC -std=c++2b all: $(CXX) $(CXXFLAGS) $(LDFLAGS) $(EXTRA_FLAGS) main.cpp borderDeco.cpp BorderppPassElement.cpp -o borders-plus-plus.so `pkg-config --cflags pixman-1 libdrm hyprland pangocairo libinput libudev wayland-server xkbcommon` clean: rm ./borders-plus-plus.so hyprwm-hyprland-plugins-3ba8bfb/borders-plus-plus/README.md000066400000000000000000000006111520105331200237560ustar00rootroot00000000000000# borders-plus-plus Allows you to add one or two additional borders to your windows. The borders added are static. Example Config: ```lua hl.config({ plugin = { borders_plus_plus = { add_borders = 1 natural_rounding = true col = { border_1 = "rgb(ffffff)" } border_size_1 = 10 } } }) ```hyprwm-hyprland-plugins-3ba8bfb/borders-plus-plus/borderDeco.cpp000066400000000000000000000137101520105331200252570ustar00rootroot00000000000000#include "borderDeco.hpp" #include #include #include #include #include using namespace Hyprutils::Memory; using namespace Render::GL; #include "BorderppPassElement.hpp" #include "globals.hpp" static size_t borderCount() { return std::clamp(vars.addBorders->value(), 0, static_cast(vars.borderSizes.size())); } CBordersPlusPlus::CBordersPlusPlus(PHLWINDOW pWindow) : IHyprWindowDecoration(pWindow), m_pWindow(pWindow) { m_lastWindowPos = pWindow->m_realPosition->value(); m_lastWindowSize = pWindow->m_realSize->value(); } CBordersPlusPlus::~CBordersPlusPlus() { damageEntire(); } SDecorationPositioningInfo CBordersPlusPlus::getPositioningInfo() { SDecorationPositioningInfo info; info.policy = DECORATION_POSITION_STICKY; info.reserved = true; info.priority = 9990; info.edges = DECORATION_EDGE_BOTTOM | DECORATION_EDGE_LEFT | DECORATION_EDGE_RIGHT | DECORATION_EDGE_TOP; if (m_fLastThickness == 0) { double size = 0; for (size_t i = 0; i < borderCount(); ++i) { size += vars.borderSizes[i]->value(); } info.desiredExtents = {{size, size}, {size, size}}; m_fLastThickness = size; } else info.desiredExtents = {{m_fLastThickness, m_fLastThickness}, {m_fLastThickness, m_fLastThickness}}; return info; } void CBordersPlusPlus::onPositioningReply(const SDecorationPositioningReply& reply) { m_bAssignedGeometry = reply.assignedGeometry; } uint64_t CBordersPlusPlus::getDecorationFlags() { return DECORATION_PART_OF_MAIN_WINDOW; } eDecorationLayer CBordersPlusPlus::getDecorationLayer() { return DECORATION_LAYER_OVER; } std::string CBordersPlusPlus::getDisplayName() { return "Borders++"; } void CBordersPlusPlus::draw(PHLMONITOR pMonitor, const float& a) { if (!validMapped(m_pWindow)) return; const auto PWINDOW = m_pWindow.lock(); if (!PWINDOW->m_ruleApplicator->decorate().valueOrDefault()) return; CBorderPPPassElement::SBorderPPData data; data.deco = this; g_pHyprRenderer->m_renderPass.add(makeUnique(data)); } void CBordersPlusPlus::drawPass(PHLMONITOR pMonitor, const float& a) { const auto PWINDOW = m_pWindow.lock(); static auto PROUNDING = CConfigValue("decoration:rounding"); static auto PBORDERSIZE = CConfigValue("general:border_size"); const auto BORDERS = borderCount(); const auto NATURALROUND = vars.naturalRounding->value(); if (BORDERS < 1) return; if (m_bAssignedGeometry.width < m_seExtents.topLeft.x + 1 || m_bAssignedGeometry.height < m_seExtents.topLeft.y + 1) return; const auto PWORKSPACE = PWINDOW->m_workspace; const auto WORKSPACEOFFSET = PWORKSPACE && !PWINDOW->m_pinned ? PWORKSPACE->m_renderOffset->value() : Vector2D(); auto rounding = PWINDOW->rounding() == 0 ? 0 : (PWINDOW->rounding() + *PBORDERSIZE) * pMonitor->m_scale; const auto ROUNDINGPOWER = PWINDOW->roundingPower(); const auto ORIGINALROUND = rounding == 0 ? 0 : (PWINDOW->rounding() + *PBORDERSIZE) * pMonitor->m_scale; CBox fullBox = m_bAssignedGeometry; fullBox.translate(g_pDecorationPositioner->getEdgeDefinedPoint(DECORATION_EDGE_BOTTOM | DECORATION_EDGE_LEFT | DECORATION_EDGE_RIGHT | DECORATION_EDGE_TOP, m_pWindow.lock())); fullBox.translate(PWINDOW->m_floatingOffset - pMonitor->m_position + WORKSPACEOFFSET); if (fullBox.width < 1 || fullBox.height < 1) return; double fullThickness = 0; for (size_t i = 0; i < BORDERS; ++i) { const int THISBORDERSIZE = vars.borderSizes[i]->value() == -1 ? *PBORDERSIZE : vars.borderSizes[i]->value(); fullThickness += THISBORDERSIZE; } fullBox.expand(-fullThickness).scale(pMonitor->m_scale).round(); for (size_t i = 0; i < BORDERS; ++i) { const int PREVBORDERSIZESCALED = i == 0 ? 0 : (vars.borderSizes[i - 1]->value() == -1 ? *PBORDERSIZE : vars.borderSizes[i - 1]->value()) * pMonitor->m_scale; const int THISBORDERSIZE = vars.borderSizes[i]->value() == -1 ? *PBORDERSIZE : vars.borderSizes[i]->value(); if (i != 0) { rounding += rounding == 0 ? 0 : PREVBORDERSIZESCALED; fullBox.x -= PREVBORDERSIZESCALED; fullBox.y -= PREVBORDERSIZESCALED; fullBox.width += PREVBORDERSIZESCALED * 2; fullBox.height += PREVBORDERSIZESCALED * 2; } if (fullBox.width < 1 || fullBox.height < 1) break; g_pHyprOpenGL->scissor(nullptr); g_pHyprOpenGL->renderBorder(fullBox, CHyprColor{static_cast(vars.borderColors[i]->value())}, {.round = NATURALROUND ? sc(ORIGINALROUND) : sc(rounding), .roundingPower = ROUNDINGPOWER, .borderSize = THISBORDERSIZE, .a = a, .outerRound = NATURALROUND ? sc(ORIGINALROUND) : -1}); } m_seExtents = {{fullThickness, fullThickness}, {fullThickness, fullThickness}}; m_bLastRelativeBox = CBox{0, 0, m_lastWindowSize.x, m_lastWindowSize.y}.addExtents(m_seExtents); if (fullThickness != m_fLastThickness) { m_fLastThickness = fullThickness; g_pDecorationPositioner->repositionDeco(this); } } eDecorationType CBordersPlusPlus::getDecorationType() { return DECORATION_CUSTOM; } void CBordersPlusPlus::updateWindow(PHLWINDOW pWindow) { m_lastWindowPos = pWindow->m_realPosition->value(); m_lastWindowSize = pWindow->m_realSize->value(); damageEntire(); } void CBordersPlusPlus::damageEntire() { CBox dm = m_bLastRelativeBox.copy().translate(m_lastWindowPos).expand(2); g_pHyprRenderer->damageBox(dm); } hyprwm-hyprland-plugins-3ba8bfb/borders-plus-plus/borderDeco.hpp000066400000000000000000000022601520105331200252620ustar00rootroot00000000000000#pragma once #define WLR_USE_UNSTABLE #include class CBordersPlusPlus : public IHyprWindowDecoration { public: CBordersPlusPlus(PHLWINDOW); virtual ~CBordersPlusPlus(); virtual SDecorationPositioningInfo getPositioningInfo(); virtual void onPositioningReply(const SDecorationPositioningReply& reply); virtual void draw(PHLMONITOR, float const& a); virtual eDecorationType getDecorationType(); virtual void updateWindow(PHLWINDOW); virtual void damageEntire(); virtual uint64_t getDecorationFlags(); virtual eDecorationLayer getDecorationLayer(); virtual std::string getDisplayName(); private: void drawPass(PHLMONITOR, float const& a); SBoxExtents m_seExtents; PHLWINDOWREF m_pWindow; CBox m_bLastRelativeBox; CBox m_bAssignedGeometry; Vector2D m_lastWindowPos; Vector2D m_lastWindowSize; double m_fLastThickness = 0; friend class CBorderPPPassElement; }; hyprwm-hyprland-plugins-3ba8bfb/borders-plus-plus/default.nix000066400000000000000000000006461520105331200246530ustar00rootroot00000000000000{ lib, hyprland, hyprlandPlugins, }: hyprlandPlugins.mkHyprlandPlugin { pluginName = "borders-plus-plus"; version = "0.1"; src = ./.; inherit (hyprland) nativeBuildInputs; meta = with lib; { homepage = "https://github.com/hyprwm/hyprland-plugins/tree/main/borders-plus-plus"; description = "Hyprland borders-plus-plus plugin"; license = licenses.bsd3; platforms = platforms.linux; }; } hyprwm-hyprland-plugins-3ba8bfb/borders-plus-plus/globals.hpp000066400000000000000000000011161520105331200246340ustar00rootroot00000000000000#pragma once #include #include #include #include #include inline HANDLE PHANDLE = nullptr; struct SVars { SP addBorders; SP naturalRounding; std::array, 9> borderColors; std::array, 9> borderSizes; }; inline SVars vars = {}; hyprwm-hyprland-plugins-3ba8bfb/borders-plus-plus/main.cpp000066400000000000000000000061031520105331200241310ustar00rootroot00000000000000#define WLR_USE_UNSTABLE #include #include #include #include #include #include #include #include #include "borderDeco.hpp" #include "globals.hpp" // Do NOT change this function. APICALL EXPORT std::string PLUGIN_API_VERSION() { return HYPRLAND_API_VERSION; } static void onNewWindow(PHLWINDOW window) { HyprlandAPI::addWindowDecoration(PHANDLE, window, makeUnique(window)); } APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { PHANDLE = handle; const std::string HASH = __hyprland_api_get_hash(); const std::string CLIENT_HASH = __hyprland_api_get_client_hash(); if (HASH != CLIENT_HASH) { HyprlandAPI::addNotification(PHANDLE, "[borders-plus-plus] Failure in initialization: Version mismatch (headers ver is not equal to running hyprland ver)", CHyprColor{1.0, 0.2, 0.2, 1.0}, 5000); throw std::runtime_error("[bpp] Version mismatch"); } vars.addBorders = makeShared("plugin:borders-plus-plus:add_borders", "How many extra borders to draw", 1, Config::Values::SIntValueOptions{.min = 0, .max = 9}); vars.naturalRounding = makeShared("plugin:borders-plus-plus:natural_rounding", "Use the window's original rounding", true); HyprlandAPI::addConfigValueV2(PHANDLE, vars.addBorders); HyprlandAPI::addConfigValueV2(PHANDLE, vars.naturalRounding); static std::array borderColorNames; static std::array borderSizeNames; for (size_t i = 0; i < 9; ++i) { borderColorNames[i] = "plugin:borders-plus-plus:col.border_" + std::to_string(i + 1); borderSizeNames[i] = "plugin:borders-plus-plus:border_size_" + std::to_string(i + 1); vars.borderColors[i] = makeShared(borderColorNames[i].c_str(), "Color of the extra border", 0xee000000); vars.borderSizes[i] = makeShared(borderSizeNames[i].c_str(), "Size of the extra border", -1); HyprlandAPI::addConfigValueV2(PHANDLE, vars.borderColors[i]); HyprlandAPI::addConfigValueV2(PHANDLE, vars.borderSizes[i]); } HyprlandAPI::reloadConfig(); static auto P = Event::bus()->m_events.window.open.listen([&](PHLWINDOW w) { onNewWindow(w); }); // add deco to existing windows for (auto& w : g_pCompositor->m_windows) { if (w->isHidden() || !w->m_isMapped) continue; HyprlandAPI::addWindowDecoration(PHANDLE, w, makeUnique(w)); } HyprlandAPI::addNotification(PHANDLE, "[borders-plus-plus] Initialized successfully!", CHyprColor{0.2, 1.0, 0.2, 1.0}, 5000); return {"borders-plus-plus", "A plugin to add more borders to windows.", "Vaxry", "1.0"}; } APICALL EXPORT void PLUGIN_EXIT() { g_pHyprRenderer->m_renderPass.removeAllOfType("CBorderPPPassElement"); } hyprwm-hyprland-plugins-3ba8bfb/borders-plus-plus/meson.build000066400000000000000000000016311520105331200246440ustar00rootroot00000000000000project('borders-plus-plus', 'cpp', version: '0.1', default_options: ['buildtype=release'], ) cpp_compiler = meson.get_compiler('cpp') if cpp_compiler.has_argument('-std=c++23') add_global_arguments('-std=c++23', language: 'cpp') elif cpp_compiler.has_argument('-std=c++2b') add_global_arguments('-std=c++2b', language: 'cpp') else error('Could not configure current C++ compiler (' + cpp_compiler.get_id() + ' ' + cpp_compiler.version() + ') with required C++ standard (C++23)') endif globber = run_command('find', '.', '-name', '*.cpp', check: true) src = globber.stdout().strip().split('\n') shared_module(meson.project_name(), src, dependencies: [ dependency('hyprland'), dependency('pixman-1'), dependency('libdrm'), dependency('pangocairo'), dependency('libinput'), dependency('libudev'), dependency('wayland-server'), dependency('xkbcommon'), ], install: true, ) hyprwm-hyprland-plugins-3ba8bfb/csgo-vulkan-fix/000077500000000000000000000000001520105331200221145ustar00rootroot00000000000000hyprwm-hyprland-plugins-3ba8bfb/csgo-vulkan-fix/CMakeLists.txt000066400000000000000000000010241520105331200246510ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.27) project(csgo-vulkan-fix DESCRIPTION "csgo-vulkan-fix plugin for Hyprland" VERSION 0.1 ) set(CMAKE_CXX_STANDARD 23) file(GLOB_RECURSE SRC "*.cpp") add_library(csgo-vulkan-fix SHARED ${SRC}) find_package(PkgConfig REQUIRED) pkg_check_modules(deps REQUIRED IMPORTED_TARGET hyprland libdrm libinput libudev pangocairo pixman-1 wayland-server xkbcommon ) target_link_libraries(csgo-vulkan-fix PRIVATE rt PkgConfig::deps) install(TARGETS csgo-vulkan-fix) hyprwm-hyprland-plugins-3ba8bfb/csgo-vulkan-fix/Makefile000066400000000000000000000006021520105331200235520ustar00rootroot00000000000000# Else exist specifically for clang ifeq ($(CXX),g++) EXTRA_FLAGS = --no-gnu-unique else EXTRA_FLAGS = endif CXXFLAGS ?= -O2 CXXFLAGS += -shared -fPIC -std=c++2b all: $(CXX) $(CXXFLAGS) $(LDFLAGS) $(EXTRA_FLAGS) main.cpp -o csgo-vulkan-fix.so `pkg-config --cflags pixman-1 libdrm hyprland pangocairo libinput libudev wayland-server xkbcommon` clean: rm ./csgo-vulkan-fix.so hyprwm-hyprland-plugins-3ba8bfb/csgo-vulkan-fix/README.md000066400000000000000000000021661520105331200234000ustar00rootroot00000000000000# csgo-vulkan-fix Originally meant for csgo / cs2, but can work with any app, really. csgo-vulkan-fix is a way to force apps to a fake resolution without them realizing it. If you want to play CS2, you're locked to your native res. Other resolutions (especially not 16:9) are wonky. With this plugin, you aren't anymore. This is also useful for when you are scaling and want to force any game to a custom resolution. CS2 launch options: ``` -vulkan -window -w -h -vulkan ``` example plugin config: ```ini plugin { csgo_vulkan_fix { # Whether to fix the mouse position. A select few apps might be wonky with this. fix_mouse = true # Add apps with vkfix-app = initialClass, width, height vkfix-app = cs2, 1650, 1050 vkfix-app = myapp, 1920, 1080 } } ``` Lua config: ```lua hl.config({ plugin = { csgo_vulkan_fix = { fix_mouse = true, }, }, }) hl.plugin.csgo_vulkan_fix.vkfix_app({ app = "cs2", w = 1650, h = 1050 }) hl.plugin.csgo_vulkan_fix.vkfix_app({ app = "myapp", w = 1920, h = 1080 }) ``` fullscreen the game manually and enjoy. hyprwm-hyprland-plugins-3ba8bfb/csgo-vulkan-fix/default.nix000066400000000000000000000006321520105331200242610ustar00rootroot00000000000000{ lib, hyprland, hyprlandPlugins, }: hyprlandPlugins.mkHyprlandPlugin { pluginName = "csgo-vulkan-fix"; version = "0.1"; src = ./.; inherit (hyprland) nativeBuildInputs; meta = with lib; { homepage = "https://github.com/hyprwm/hyprland-plugins/tree/main/csgo-vulkan-fix"; description = "Hyprland CS:GO Vulkan fix"; license = licenses.bsd3; platforms = platforms.linux; }; } hyprwm-hyprland-plugins-3ba8bfb/csgo-vulkan-fix/globals.hpp000066400000000000000000000001351520105331200242470ustar00rootroot00000000000000#pragma once #include inline HANDLE PHANDLE = nullptr;hyprwm-hyprland-plugins-3ba8bfb/csgo-vulkan-fix/main.cpp000066400000000000000000000222331520105331200235460ustar00rootroot00000000000000#define WLR_USE_UNSTABLE #include #include #include #include #include #include #include #include #include #include #include #include "globals.hpp" extern "C" { #include #include } #include using namespace Hyprutils::String; // Methods inline CFunctionHook* g_pMouseMotionHook = nullptr; inline CFunctionHook* g_pSurfaceSizeHook = nullptr; inline CFunctionHook* g_pWLSurfaceDamageHook = nullptr; typedef void (*origMotion)(CSeatManager*, uint32_t, const Vector2D&); typedef void (*origSurfaceSize)(CXWaylandSurface*, const CBox&); typedef CRegion (*origWLSurfaceDamage)(Desktop::View::CWLSurface*); static struct { SP fixMouse; } configValues; // Do NOT change this function. APICALL EXPORT std::string PLUGIN_API_VERSION() { return HYPRLAND_API_VERSION; } struct SAppConfig { std::string szClass; Vector2D res; }; std::vector g_appConfigs; static const SAppConfig* getAppConfig(const std::string& appClass) { for (const auto& ac : g_appConfigs) { if (ac.szClass != appClass) continue; return ∾ } return nullptr; } void hkNotifyMotion(CSeatManager* thisptr, uint32_t time_msec, const Vector2D& local) { Vector2D newCoords = local; auto focusState = Desktop::focusState(); auto window = focusState->window(); auto monitor = focusState->monitor(); const auto CONFIG = window && monitor ? getAppConfig(window->m_initialClass) : nullptr; if (configValues.fixMouse->value() && CONFIG) { // fix the coords newCoords.x *= (CONFIG->res.x / monitor->m_size.x) / window->m_X11SurfaceScaledBy; newCoords.y *= (CONFIG->res.y / monitor->m_size.y) / window->m_X11SurfaceScaledBy; } (*(origMotion)g_pMouseMotionHook->m_original)(thisptr, time_msec, newCoords); } void hkSetWindowSize(CXWaylandSurface* surface, const CBox& box) { if (!surface) { (*(origSurfaceSize)g_pSurfaceSizeHook->m_original)(surface, box); return; } const auto SURF = surface->m_surface.lock(); const auto PWINDOW = g_pCompositor->getWindowFromSurface(SURF); CBox newBox = box; if (!PWINDOW) { (*(origSurfaceSize)g_pSurfaceSizeHook->m_original)(surface, newBox); return; } if (const auto CONFIG = getAppConfig(PWINDOW->m_initialClass); CONFIG) { newBox.w = CONFIG->res.x; newBox.h = CONFIG->res.y; Desktop::View::CWLSurface::fromResource(SURF)->m_fillIgnoreSmall = true; } (*(origSurfaceSize)g_pSurfaceSizeHook->m_original)(surface, newBox); } CRegion hkWLSurfaceDamage(Desktop::View::CWLSurface* thisptr) { const auto RG = (*(origWLSurfaceDamage)g_pWLSurfaceDamageHook->m_original)(thisptr); if (thisptr->exists() && Desktop::View::CWindow::fromView(thisptr->view())) { const auto WINDOW = Desktop::View::CWindow::fromView(thisptr->view()); const auto CONFIG = getAppConfig(WINDOW->m_initialClass); if (CONFIG) { const auto PMONITOR = WINDOW->m_monitor.lock(); if (PMONITOR) g_pHyprRenderer->damageMonitor(PMONITOR); else g_pHyprRenderer->damageWindow(WINDOW); } } return RG; } int vkfixAppLua(lua_State* L) { if (!lua_istable(L, 1)) return Config::Lua::Bindings::Internal::configError(L, "vkfix_app: expected a table { app, w, h }"); SAppConfig config; { Hyprutils::Utils::CScopeGuard x([L] { lua_pop(L, 1); }); lua_getfield(L, 1, "app"); if (!lua_isstring(L, -1)) return Config::Lua::Bindings::Internal::configError(L, "vkfix_app: app must be a class string"); config.szClass = lua_tostring(L, -1); } { Hyprutils::Utils::CScopeGuard x([L] { lua_pop(L, 1); }); lua_getfield(L, 1, "w"); if (!lua_isinteger(L, -1)) return Config::Lua::Bindings::Internal::configError(L, "vkfix_app: w must be an integer"); config.res.x = lua_tointeger(L, -1); } { Hyprutils::Utils::CScopeGuard x([L] { lua_pop(L, 1); }); lua_getfield(L, 1, "h"); if (!lua_isinteger(L, -1)) return Config::Lua::Bindings::Internal::configError(L, "vkfix_app: h must be an integer"); config.res.y = lua_tointeger(L, -1); } g_appConfigs.emplace_back(std::move(config)); return 0; } APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { PHANDLE = handle; const std::string HASH = __hyprland_api_get_hash(); const std::string CLIENT_HASH = __hyprland_api_get_client_hash(); if (HASH != CLIENT_HASH) { HyprlandAPI::addNotification(PHANDLE, "[csgo-vulkan-fix] Failure in initialization: Version mismatch (headers ver is not equal to running hyprland ver)", CHyprColor{1.0, 0.2, 0.2, 1.0}, 5000); throw std::runtime_error("[vkfix] Version mismatch"); } static auto P = Event::bus()->m_events.config.preReload.listen([&] { g_appConfigs.clear(); }); if (Config::mgr()->type() == Config::CONFIG_LEGACY) { HyprlandAPI::addConfigKeyword( PHANDLE, "vkfix-app", [](const char* l, const char* r) -> Hyprlang::CParseResult { const std::string str = r; CConstVarList data(str, 0, ',', true); Hyprlang::CParseResult result; if (data.size() != 3) { result.setError("vkfix-app requires 3 params"); return result; } try { SAppConfig config; config.szClass = data[0]; config.res = Vector2D{std::stoi(std::string{data[1]}), std::stoi(std::string{data[2]})}; g_appConfigs.emplace_back(std::move(config)); } catch (std::exception& e) { result.setError("failed to parse line"); return result; } return result; }, Hyprlang::SHandlerOptions{}); } else if (Config::mgr()->type() == Config::CONFIG_LUA) { HyprlandAPI::addLuaFunction(PHANDLE, "csgo_vulkan_fix", "vkfix_app", ::vkfixAppLua); } else { HyprlandAPI::addNotification(PHANDLE, "[csgo-vulkan-fix] Failure in initialization: Failed to get a valid config manager", CHyprColor{1.0, 0.2, 0.2, 1.0}, 5000); throw std::runtime_error("[vkfix] Config manager bad"); } configValues.fixMouse = makeShared("plugin:csgo_vulkan_fix:fix_mouse", "Whether to fix the mouse position. A select few apps might be wonky with this.", true); HyprlandAPI::addConfigValueV2(PHANDLE, configValues.fixMouse); auto FNS = HyprlandAPI::findFunctionsByName(PHANDLE, "sendPointerMotion"); for (auto& fn : FNS) { if (!fn.demangled.contains("CSeatManager")) continue; g_pMouseMotionHook = HyprlandAPI::createFunctionHook(PHANDLE, fn.address, (void*)::hkNotifyMotion); break; } FNS = HyprlandAPI::findFunctionsByName(PHANDLE, "configure"); for (auto& fn : FNS) { if (!fn.demangled.contains("XWaylandSurface")) continue; g_pSurfaceSizeHook = HyprlandAPI::createFunctionHook(PHANDLE, fn.address, (void*)::hkSetWindowSize); break; } FNS = HyprlandAPI::findFunctionsByName(PHANDLE, "computeDamage"); for (auto& r : FNS) { if (!r.demangled.contains("CWLSurface")) continue; g_pWLSurfaceDamageHook = HyprlandAPI::createFunctionHook(PHANDLE, r.address, (void*)::hkWLSurfaceDamage); break; } bool success = g_pSurfaceSizeHook && g_pWLSurfaceDamageHook && g_pMouseMotionHook; if (!success) { HyprlandAPI::addNotification(PHANDLE, "[csgo-vulkan-fix] Failure in initialization: Failed to find required hook fns", CHyprColor{1.0, 0.2, 0.2, 1.0}, 5000); throw std::runtime_error("[vkfix] Hooks fn init failed"); } success = success && g_pWLSurfaceDamageHook->hook(); success = success && g_pMouseMotionHook->hook(); success = success && g_pSurfaceSizeHook->hook(); if (success) HyprlandAPI::addNotification(PHANDLE, "[csgo-vulkan-fix] Initialized successfully! (Anything version)", CHyprColor{0.2, 1.0, 0.2, 1.0}, 5000); else { HyprlandAPI::addNotification(PHANDLE, "[csgo-vulkan-fix] Failure in initialization (hook failed)!", CHyprColor{1.0, 0.2, 0.2, 1.0}, 5000); throw std::runtime_error("[csgo-vk-fix] Hooks failed"); } return {"csgo-vulkan-fix", "A plugin to force specific apps to a fake resolution", "Vaxry", "1.2"}; } APICALL EXPORT void PLUGIN_EXIT() { configValues = {}; } hyprwm-hyprland-plugins-3ba8bfb/csgo-vulkan-fix/meson.build000066400000000000000000000016271520105331200242640ustar00rootroot00000000000000project('csgo-vulkan-fix', 'cpp', version: '0.1', default_options: ['buildtype=release'], ) cpp_compiler = meson.get_compiler('cpp') if cpp_compiler.has_argument('-std=c++23') add_global_arguments('-std=c++23', language: 'cpp') elif cpp_compiler.has_argument('-std=c++2b') add_global_arguments('-std=c++2b', language: 'cpp') else error('Could not configure current C++ compiler (' + cpp_compiler.get_id() + ' ' + cpp_compiler.version() + ') with required C++ standard (C++23)') endif globber = run_command('find', '.', '-name', '*.cpp', check: true) src = globber.stdout().strip().split('\n') shared_module(meson.project_name(), src, dependencies: [ dependency('hyprland'), dependency('pixman-1'), dependency('libdrm'), dependency('pangocairo'), dependency('libinput'), dependency('libudev'), dependency('wayland-server'), dependency('xkbcommon'), ], install: true, ) hyprwm-hyprland-plugins-3ba8bfb/flake.lock000066400000000000000000000276161520105331200210470ustar00rootroot00000000000000{ "nodes": { "aquamarine": { "inputs": { "hyprutils": [ "hyprland", "hyprutils" ], "hyprwayland-scanner": [ "hyprland", "hyprwayland-scanner" ], "nixpkgs": [ "hyprland", "nixpkgs" ], "systems": [ "hyprland", "systems" ] }, "locked": { "lastModified": 1777499565, "narHash": "sha256-nU55VWk99Pn1QzQDDjFISocC4SgDZ3Xp+zb6ji3JclM=", "owner": "hyprwm", "repo": "aquamarine", "rev": "813c1e8981893c11e118b19c125d6bc282f51765", "type": "github" }, "original": { "owner": "hyprwm", "repo": "aquamarine", "type": "github" } }, "flake-compat": { "flake": false, "locked": { "lastModified": 1767039857, "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", "owner": "NixOS", "repo": "flake-compat", "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", "type": "github" }, "original": { "owner": "NixOS", "repo": "flake-compat", "type": "github" } }, "gitignore": { "inputs": { "nixpkgs": [ "hyprland", "pre-commit-hooks", "nixpkgs" ] }, "locked": { "lastModified": 1709087332, "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", "owner": "hercules-ci", "repo": "gitignore.nix", "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", "type": "github" }, "original": { "owner": "hercules-ci", "repo": "gitignore.nix", "type": "github" } }, "hyprcursor": { "inputs": { "hyprlang": [ "hyprland", "hyprlang" ], "nixpkgs": [ "hyprland", "nixpkgs" ], "systems": [ "hyprland", "systems" ] }, "locked": { "lastModified": 1776511930, "narHash": "sha256-fCpwFiTW0rT7oKJqr3cqHMnkwypSwQKpbtUEtxdkgrM=", "owner": "hyprwm", "repo": "hyprcursor", "rev": "39435900785d0c560c6ae8777d29f28617d031ef", "type": "github" }, "original": { "owner": "hyprwm", "repo": "hyprcursor", "type": "github" } }, "hyprgraphics": { "inputs": { "hyprutils": [ "hyprland", "hyprutils" ], "nixpkgs": [ "hyprland", "nixpkgs" ], "systems": [ "hyprland", "systems" ] }, "locked": { "lastModified": 1776426399, "narHash": "sha256-RUESLKNikIeEq9ymGJ6nmcDXiSFQpUW1IhJ245nL3xM=", "owner": "hyprwm", "repo": "hyprgraphics", "rev": "68d064434787cf1ed4a2fe257c03c5f52f33cf84", "type": "github" }, "original": { "owner": "hyprwm", "repo": "hyprgraphics", "type": "github" } }, "hyprland": { "inputs": { "aquamarine": "aquamarine", "hyprcursor": "hyprcursor", "hyprgraphics": "hyprgraphics", "hyprland-guiutils": "hyprland-guiutils", "hyprland-protocols": "hyprland-protocols", "hyprlang": "hyprlang", "hyprutils": "hyprutils", "hyprwayland-scanner": "hyprwayland-scanner", "hyprwire": "hyprwire", "nixpkgs": "nixpkgs", "pre-commit-hooks": "pre-commit-hooks", "systems": "systems", "xdph": "xdph" }, "locked": { "lastModified": 1778588655, "narHash": "sha256-7zcsu103YzjuBBx3ToFodHBQl8W3e5GBu8C915I538Y=", "owner": "hyprwm", "repo": "Hyprland", "rev": "d61c96913cbe3c3f9aacc198b1f1e6489349615d", "type": "github" }, "original": { "owner": "hyprwm", "repo": "Hyprland", "type": "github" } }, "hyprland-guiutils": { "inputs": { "aquamarine": [ "hyprland", "aquamarine" ], "hyprgraphics": [ "hyprland", "hyprgraphics" ], "hyprlang": [ "hyprland", "hyprlang" ], "hyprtoolkit": "hyprtoolkit", "hyprutils": [ "hyprland", "hyprutils" ], "hyprwayland-scanner": [ "hyprland", "hyprwayland-scanner" ], "nixpkgs": [ "hyprland", "nixpkgs" ], "systems": [ "hyprland", "systems" ] }, "locked": { "lastModified": 1776426575, "narHash": "sha256-KI6nIfVihn/DPaeB5Et46Xg3dkNHrrEtUd5LBBVomB0=", "owner": "hyprwm", "repo": "hyprland-guiutils", "rev": "a968d211048e3ed538e47b84cb3649299578f19d", "type": "github" }, "original": { "owner": "hyprwm", "repo": "hyprland-guiutils", "type": "github" } }, "hyprland-protocols": { "inputs": { "nixpkgs": [ "hyprland", "nixpkgs" ], "systems": [ "hyprland", "systems" ] }, "locked": { "lastModified": 1772460177, "narHash": "sha256-/6G/MsPvtn7bc4Y32pserBT/Z4SUUdBd4XYJpOEKVR4=", "owner": "hyprwm", "repo": "hyprland-protocols", "rev": "1cb6db5fd6bb8aee419f4457402fa18293ace917", "type": "github" }, "original": { "owner": "hyprwm", "repo": "hyprland-protocols", "type": "github" } }, "hyprlang": { "inputs": { "hyprutils": [ "hyprland", "hyprutils" ], "nixpkgs": [ "hyprland", "nixpkgs" ], "systems": [ "hyprland", "systems" ] }, "locked": { "lastModified": 1777320127, "narHash": "sha256-Qu+Wf2Bp5qUjyn2YpZNq8a7JyzTGowhT1knrwE38a9U=", "owner": "hyprwm", "repo": "hyprlang", "rev": "090117506ddc3d7f26e650ff344d378c2ec329cc", "type": "github" }, "original": { "owner": "hyprwm", "repo": "hyprlang", "type": "github" } }, "hyprtoolkit": { "inputs": { "aquamarine": [ "hyprland", "hyprland-guiutils", "aquamarine" ], "hyprgraphics": [ "hyprland", "hyprland-guiutils", "hyprgraphics" ], "hyprlang": [ "hyprland", "hyprland-guiutils", "hyprlang" ], "hyprutils": [ "hyprland", "hyprland-guiutils", "hyprutils" ], "hyprwayland-scanner": [ "hyprland", "hyprland-guiutils", "hyprwayland-scanner" ], "nixpkgs": [ "hyprland", "hyprland-guiutils", "nixpkgs" ], "systems": [ "hyprland", "hyprland-guiutils", "systems" ] }, "locked": { "lastModified": 1772462885, "narHash": "sha256-5pHXrQK9zasMnIo6yME6EOXmWGFMSnCITcfKshhKJ9I=", "owner": "hyprwm", "repo": "hyprtoolkit", "rev": "9af245a69fa6b286b88ddfc340afd288e00a6998", "type": "github" }, "original": { "owner": "hyprwm", "repo": "hyprtoolkit", "type": "github" } }, "hyprutils": { "inputs": { "nixpkgs": [ "hyprland", "nixpkgs" ], "systems": [ "hyprland", "systems" ] }, "locked": { "lastModified": 1778234770, "narHash": "sha256-jAcsogZwWMfXT9MfXxZzkwliAqIuZUV0p71h6Ba9ReE=", "owner": "hyprwm", "repo": "hyprutils", "rev": "a2dbd8a4cc51f7cbe4224732668392bb1aa79df2", "type": "github" }, "original": { "owner": "hyprwm", "repo": "hyprutils", "type": "github" } }, "hyprwayland-scanner": { "inputs": { "nixpkgs": [ "hyprland", "nixpkgs" ], "systems": [ "hyprland", "systems" ] }, "locked": { "lastModified": 1777159683, "narHash": "sha256-Jxixw6wZphUp+nHYxOKUYSckL17QMBx2d5Zp0rJHr1g=", "owner": "hyprwm", "repo": "hyprwayland-scanner", "rev": "b8632713a6beaf28b56f2a7b0ab2fb7088dbb404", "type": "github" }, "original": { "owner": "hyprwm", "repo": "hyprwayland-scanner", "type": "github" } }, "hyprwire": { "inputs": { "hyprutils": [ "hyprland", "hyprutils" ], "nixpkgs": [ "hyprland", "nixpkgs" ], "systems": [ "hyprland", "systems" ] }, "locked": { "lastModified": 1777388329, "narHash": "sha256-40YxVGF2rA9iH3D7am5fy4EOSBbMgpJtJ9yhl0Cx+qI=", "owner": "hyprwm", "repo": "hyprwire", "rev": "04be2897e05f9b271d532b5ae56ca088d2eeac02", "type": "github" }, "original": { "owner": "hyprwm", "repo": "hyprwire", "type": "github" } }, "nixpkgs": { "locked": { "lastModified": 1777954456, "narHash": "sha256-hGdgeU2Nk87RAuZyYjyDjFL6LK7dAZN5RE9+hrDTkDU=", "owner": "NixOS", "repo": "nixpkgs", "rev": "549bd84d6279f9852cae6225e372cc67fb91a4c1", "type": "github" }, "original": { "owner": "NixOS", "ref": "nixos-unstable", "repo": "nixpkgs", "type": "github" } }, "pre-commit-hooks": { "inputs": { "flake-compat": "flake-compat", "gitignore": "gitignore", "nixpkgs": [ "hyprland", "nixpkgs" ] }, "locked": { "lastModified": 1776796298, "narHash": "sha256-PcRvlWayisPSjd0UcRQbhG8Oqw78AcPE6x872cPRHN8=", "owner": "cachix", "repo": "git-hooks.nix", "rev": "3cfd774b0a530725a077e17354fbdb87ea1c4aad", "type": "github" }, "original": { "owner": "cachix", "repo": "git-hooks.nix", "type": "github" } }, "root": { "inputs": { "hyprland": "hyprland", "nixpkgs": [ "hyprland", "nixpkgs" ], "systems": [ "hyprland", "systems" ] } }, "systems": { "locked": { "lastModified": 1689347949, "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", "owner": "nix-systems", "repo": "default-linux", "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", "type": "github" }, "original": { "owner": "nix-systems", "repo": "default-linux", "type": "github" } }, "xdph": { "inputs": { "hyprland-protocols": [ "hyprland", "hyprland-protocols" ], "hyprlang": [ "hyprland", "hyprlang" ], "hyprutils": [ "hyprland", "hyprutils" ], "hyprwayland-scanner": [ "hyprland", "hyprwayland-scanner" ], "nixpkgs": [ "hyprland", "nixpkgs" ], "systems": [ "hyprland", "systems" ] }, "locked": { "lastModified": 1777585783, "narHash": "sha256-JTeWRy42VElroJ0rVdZuVXSoTLsx+NzQfGPKMbtn3SU=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", "rev": "fa50d6fbaff8f42c61071b87b034a90d82a33558", "type": "github" }, "original": { "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", "type": "github" } } }, "root": "root", "version": 7 } hyprwm-hyprland-plugins-3ba8bfb/flake.nix000066400000000000000000000032131520105331200207000ustar00rootroot00000000000000{ description = "Official Hyprland Plugins"; inputs = { hyprland.url = "github:hyprwm/Hyprland"; nixpkgs.follows = "hyprland/nixpkgs"; systems.follows = "hyprland/systems"; }; outputs = { self, hyprland, nixpkgs, systems, ... }: let inherit (nixpkgs) lib; eachSystem = lib.genAttrs (import systems); pkgsFor = eachSystem (system: import nixpkgs { localSystem.system = system; overlays = [ self.overlays.hyprland-plugins hyprland.overlays.hyprland-packages ]; }); in { packages = eachSystem (system: { inherit (pkgsFor.${system}.hyprlandPlugins) borders-plus-plus csgo-vulkan-fix hyprbars hyprfocus ; }); overlays = { default = self.overlays.hyprland-plugins; hyprland-plugins = final: prev: let inherit (final) callPackage; in { hyprlandPlugins = (prev.hyprlandPlugins or {}) // { borders-plus-plus = callPackage ./borders-plus-plus {}; csgo-vulkan-fix = callPackage ./csgo-vulkan-fix {}; hyprbars = callPackage ./hyprbars {}; hyprfocus = callPackage ./hyprfocus {}; }; }; }; checks = eachSystem (system: self.packages.${system}); devShells = eachSystem (system: with pkgsFor.${system}; { default = mkShell.override {stdenv = gcc14Stdenv;} { name = "hyprland-plugins"; buildInputs = [hyprland.packages.${system}.hyprland]; inputsFrom = [hyprland.packages.${system}.hyprland]; }; }); }; } hyprwm-hyprland-plugins-3ba8bfb/hyprbars/000077500000000000000000000000001520105331200207315ustar00rootroot00000000000000hyprwm-hyprland-plugins-3ba8bfb/hyprbars/BarPassElement.cpp000066400000000000000000000022341520105331200243030ustar00rootroot00000000000000#include "BarPassElement.hpp" #include #include #include "barDeco.hpp" using namespace Render::GL; CBarPassElement::CBarPassElement(const CBarPassElement::SBarData& data_) : data(data_) { ; } std::vector> CBarPassElement::draw() { data.deco->renderPass(g_pHyprRenderer->m_renderData.pMonitor.lock(), data.a); return {}; } bool CBarPassElement::needsLiveBlur() { static auto PENABLEBLURGLOBAL = CConfigValue("decoration:blur:enabled"); CHyprColor color = data.deco->m_bForcedBarColor.value_or(CHyprColor{static_cast(g_pGlobalState->config.barColor->value())}); color.a *= data.a; const bool SHOULDBLUR = g_pGlobalState->config.barBlur->value() && *PENABLEBLURGLOBAL && color.a < 1.F; return SHOULDBLUR; } std::optional CBarPassElement::boundingBox() { // Temporary fix: expand the bar bb a bit, otherwise occlusion gets too aggressive. return data.deco->assignedBoxGlobal().translate(-g_pHyprRenderer->m_renderData.pMonitor->m_position).expand(10); } bool CBarPassElement::needsPrecomputeBlur() { return false; } hyprwm-hyprland-plugins-3ba8bfb/hyprbars/BarPassElement.hpp000066400000000000000000000014451520105331200243130ustar00rootroot00000000000000#pragma once #include class CHyprBar; class CBarPassElement : public IPassElement { public: struct SBarData { CHyprBar* deco = nullptr; float a = 1.F; }; CBarPassElement(const SBarData& data_); virtual ~CBarPassElement() = default; virtual std::vector> draw() override; virtual bool needsLiveBlur() override; virtual bool needsPrecomputeBlur() override; virtual std::optional boundingBox() override; virtual const char* passName() override { return "CBarPassElement"; } virtual ePassElementType type() override { return EK_CUSTOM; } private: SBarData data; };hyprwm-hyprland-plugins-3ba8bfb/hyprbars/CMakeLists.txt000066400000000000000000000007421520105331200234740ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.27) project(hyprbars DESCRIPTION "hyprbars plugin for Hyprland" VERSION 0.1 ) set(CMAKE_CXX_STANDARD 23) file(GLOB_RECURSE SRC "*.cpp") add_library(hyprbars SHARED ${SRC}) find_package(PkgConfig REQUIRED) pkg_check_modules(deps REQUIRED IMPORTED_TARGET hyprland libdrm libinput libudev pixman-1 wayland-server xkbcommon ) target_link_libraries(hyprbars PRIVATE rt PkgConfig::deps) install(TARGETS hyprbars) hyprwm-hyprland-plugins-3ba8bfb/hyprbars/Makefile000066400000000000000000000011241520105331200223670ustar00rootroot00000000000000# Else exist specifically for clang ifeq ($(CXX),g++) EXTRA_FLAGS = --no-gnu-unique else EXTRA_FLAGS = endif CXXFLAGS ?= -O2 CXXFLAGS += -shared -fPIC -std=c++2b -Wno-c++11-narrowing INCLUDES = `pkg-config --cflags pixman-1 libdrm hyprland libinput libudev wayland-server xkbcommon` LIBS = SRC = main.cpp barDeco.cpp BarPassElement.cpp TARGET = hyprbars.so all: $(TARGET) $(TARGET): $(SRC) $(CXX) $(CXXFLAGS) $(LDFLAGS) $(EXTRA_FLAGS) $(INCLUDES) $^ $> -o $@ $(LIBS) clean: rm ./$(TARGET) meson-build: mkdir -p build cd build && meson .. && ninja .PHONY: all meson-build clean hyprwm-hyprland-plugins-3ba8bfb/hyprbars/README.md000066400000000000000000000063071520105331200222160ustar00rootroot00000000000000# hyprbars Adds simple title bars to windows. ![image](https://github.com/user-attachments/assets/184a66b9-eb91-4f6f-8953-b265a2735939) ## Config All config options are in `plugin:hyprbars`: ``` plugin { hyprbars { # example config bar_height = 20 # example buttons (R -> L) # hyprbars-button = color, size, on-click hyprbars-button = rgb(ff4040), 10, 󰖭, hyprctl dispatch killactive hyprbars-button = rgb(eeee11), 10, , hyprctl dispatch fullscreen 1 # cmd to run on double click of the bar on_double_click = hyprctl dispatch fullscreen 1 } } ``` | property | type | description | default | | --- | --- | --- | --- | `enabled` | bool | whether to enable the bars | `bar_color` | color | bar's background color `bar_height` | int | bar's height | `15` `bar_blur` | bool | whether to blur the bar. Also requires the global blur to be enabled. `col.text` | color | bar's title text color `bar_title_enabled` | bool | whether to render the title | `true` `bar_text_size` | int | bar's title text font size | `10` `bar_text_font` | str | bar's title text font | `Sans` `bar_text_align` | left, center | bar's title text alignment | `center` `bar_buttons_alignment` | right, left | bar's buttons alignment | `right` `bar_part_of_window` | bool | whether the bar is a part of the main window (if it is, stuff like shadows render around it) `bar_precedence_over_border` | bool | whether the bar should have a higher priority than the border (border will be around the bar) `bar_padding` | int | left / right edge padding | `7` `bar_button_padding` | int | padding between the buttons | `5` `icon_on_hover` | bool | whether the icons show on mouse hovering over the buttons | `false` `inactive_button_color` | col | buttons bg color when window isn't focused `on_double_click` | str | command to run on double click of the bar (not on a button) ## Buttons Config Use the `hyprbars-button` keyword. ```ini hyprbars-button = bgcolor, size, icon, on-click, fgcolor ``` Please note it _has_ to be inside `plugin { hyprbars { } }`. For Lua config, use `hl.config` for plugin options and `hl.plugin.hyprbars.add_button` for buttons: ```lua hl.config({ plugin = { hyprbars = { bar_height = 20, on_double_click = "hyprctl dispatch fullscreen 1", }, }, }) hl.plugin.hyprbars.add_button({ bg_color = "rgb(ff4040)", fg_color = "rgb(ffffff)", size = 10, icon = "X", action = "hyprctl dispatch killactive", }) hl.plugin.hyprbars.add_button({ bg_color = "rgb(eeee11)", fg_color = "rgb(000000)", size = 10, icon = "_", action = "hyprctl dispatch fullscreen 1", }) ``` ## Window rules Hyprbars supports the following _dynamic_ [window rules](https://wiki.hypr.land/Configuring/Window-Rules/): `hyprbars:no_bar` -> disables the bar on matching windows. `hyprbars:bar_color` -> sets the bar background color on matching windows. `hyprbars:title_color` -> sets the bar title color on matching windows. Example: ```bash # Sets the bar color in red for all windows that have 'myClass' as a class windowrule { name = myClass-red-bars match:class = ^(myClass)$ hyprbars:bar_color = rgb(ff0000) } ``` hyprwm-hyprland-plugins-3ba8bfb/hyprbars/barDeco.cpp000066400000000000000000000700221520105331200227750ustar00rootroot00000000000000#include "barDeco.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "globals.hpp" #include "BarPassElement.hpp" #include using namespace Render::GL; static CHyprColor configColor(Config::INTEGER color) { return CHyprColor{static_cast(color)}; } CHyprBar::CHyprBar(PHLWINDOW pWindow) : IHyprWindowDecoration(pWindow) { m_pWindow = pWindow; const auto PMONITOR = pWindow->m_monitor.lock(); PMONITOR->m_scheduledRecalc = true; // button events m_pMouseButtonCallback = Event::bus()->m_events.input.mouse.button.listen([&](IPointer::SButtonEvent e, Event::SCallbackInfo& info) { onMouseButton(info, e); }); m_pTouchDownCallback = Event::bus()->m_events.input.touch.down.listen([&](ITouch::SDownEvent e, Event::SCallbackInfo& info) { onTouchDown(info, e); }); m_pTouchUpCallback = Event::bus()->m_events.input.touch.up.listen([&](ITouch::SUpEvent e, Event::SCallbackInfo& info) { onTouchUp(info, e); }); // move events m_pTouchMoveCallback = Event::bus()->m_events.input.touch.motion.listen([&](ITouch::SMotionEvent e, Event::SCallbackInfo& info) { onTouchMove(info, e); }); m_pMouseMoveCallback = Event::bus()->m_events.input.mouse.move.listen([&](Vector2D c, Event::SCallbackInfo& info) { onMouseMove(c); }); g_pAnimationManager->createAnimation(configColor(g_pGlobalState->config.barColor->value()), m_cRealBarColor, Config::animationTree()->getAnimationPropertyConfig("border"), pWindow, AVARDAMAGE_NONE); m_cRealBarColor->setUpdateCallback([&](auto) { damageEntire(); }); } CHyprBar::~CHyprBar() { std::erase(g_pGlobalState->bars, m_self); } SDecorationPositioningInfo CHyprBar::getPositioningInfo() { const auto HEIGHT = g_pGlobalState->config.barHeight->value(); const auto ENABLED = g_pGlobalState->config.enabled->value(); const auto PRECEDENCE = g_pGlobalState->config.barPrecedenceOverBorder->value(); SDecorationPositioningInfo info; info.policy = m_hidden ? DECORATION_POSITION_ABSOLUTE : DECORATION_POSITION_STICKY; info.edges = DECORATION_EDGE_TOP; info.priority = PRECEDENCE ? 10005 : 5000; info.reserved = true; info.desiredExtents = {{0, m_hidden || !ENABLED ? 0 : HEIGHT}, {0, 0}}; return info; } void CHyprBar::onPositioningReply(const SDecorationPositioningReply& reply) { if (reply.assignedGeometry.size() != m_bAssignedBox.size()) m_bWindowSizeChanged = true; m_bAssignedBox = reply.assignedGeometry; } std::string CHyprBar::getDisplayName() { return "Hyprbar"; } bool CHyprBar::inputIsValid() { if (!g_pGlobalState->config.enabled->value()) return false; if (!m_pWindow->m_workspace || !m_pWindow->m_workspace->isVisible() || !g_pInputManager->m_exclusiveLSes.empty() || (g_pSeatManager->m_seatGrab && !g_pSeatManager->m_seatGrab->accepts(m_pWindow->wlSurface()->resource()))) return false; const auto WINDOWATCURSOR = g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), Desktop::View::RESERVED_EXTENTS | Desktop::View::INPUT_EXTENTS | Desktop::View::ALLOW_FLOATING); auto focusState = Desktop::focusState(); auto window = focusState->window(); auto monitor = focusState->monitor(); if (WINDOWATCURSOR != m_pWindow && m_pWindow != window) return false; // check if input is on top or overlay shell layers auto PMONITOR = monitor; PHLLS foundSurface = nullptr; Vector2D surfaceCoords; // check top layer g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_layerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &surfaceCoords, &foundSurface); if (foundSurface) return false; // check overlay layer g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_layerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &surfaceCoords, &foundSurface); if (foundSurface) return false; return true; } void CHyprBar::onMouseButton(Event::SCallbackInfo& info, IPointer::SButtonEvent e) { if (!inputIsValid()) return; if (e.state != WL_POINTER_BUTTON_STATE_PRESSED) { handleUpEvent(info); return; } handleDownEvent(info, std::nullopt); } void CHyprBar::onTouchDown(Event::SCallbackInfo& info, ITouch::SDownEvent e) { // Don't do anything if you're already grabbed a window with another finger if (!inputIsValid() || e.touchID != 0) return; handleDownEvent(info, e); } void CHyprBar::onTouchUp(Event::SCallbackInfo& info, ITouch::SUpEvent e) { if (!m_bDragPending || !m_bTouchEv || e.touchID != m_touchId) return; handleUpEvent(info); } void CHyprBar::onMouseMove(Vector2D coords) { // ensure proper redraws of button icons on hover when using hardware cursors if (g_pGlobalState->config.iconOnHover->value()) damageOnButtonHover(); if (!m_bDragPending || m_bTouchEv || !validMapped(m_pWindow) || m_touchId != 0) return; m_bDragPending = false; handleMovement(); } void CHyprBar::onTouchMove(Event::SCallbackInfo& info, ITouch::SMotionEvent e) { if (!m_bDragPending || !m_bTouchEv || !validMapped(m_pWindow) || e.touchID != m_touchId) return; auto PMONITOR = m_pWindow->m_monitor.lock(); PMONITOR = PMONITOR ? PMONITOR : Desktop::focusState()->monitor(); const auto COORDS = Vector2D(PMONITOR->m_position.x + e.pos.x * PMONITOR->m_size.x, PMONITOR->m_position.y + e.pos.y * PMONITOR->m_size.y); if (!m_bDraggingThis) { // Initial setup for dragging a window. g_pKeybindManager->m_dispatchers["setfloating"]("activewindow"); g_pKeybindManager->m_dispatchers["resizewindowpixel"]("exact 50% 50%,activewindow"); // pin it so you can change workspaces while dragging a window g_pKeybindManager->m_dispatchers["pin"]("activewindow"); } g_pKeybindManager->m_dispatchers["movewindowpixel"](std::format("exact {} {},activewindow", (int)(COORDS.x - (assignedBoxGlobal().w / 2)), (int)COORDS.y)); m_bDraggingThis = true; } void CHyprBar::handleDownEvent(Event::SCallbackInfo& info, std::optional touchEvent) { m_bTouchEv = touchEvent.has_value(); if (m_bTouchEv) m_touchId = touchEvent.value().touchID; const auto PWINDOW = m_pWindow.lock(); auto COORDS = cursorRelativeToBar(); if (m_bTouchEv) { ITouch::SDownEvent e = touchEvent.value(); auto PMONITOR = g_pCompositor->getMonitorFromName(!e.device->m_boundOutput.empty() ? e.device->m_boundOutput : ""); PMONITOR = PMONITOR ? PMONITOR : Desktop::focusState()->monitor(); COORDS = Vector2D(PMONITOR->m_position.x + e.pos.x * PMONITOR->m_size.x, PMONITOR->m_position.y + e.pos.y * PMONITOR->m_size.y) - assignedBoxGlobal().pos(); } const auto HEIGHT = g_pGlobalState->config.barHeight->value(); const auto BARBUTTONPADDING = g_pGlobalState->config.barButtonPadding->value(); const auto BARPADDING = g_pGlobalState->config.barPadding->value(); const auto ALIGNBUTTONS = g_pGlobalState->config.barButtonsAlignment->value(); const auto ON_DOUBLE_CLICK = g_pGlobalState->config.onDoubleClick->value(); const bool BUTTONSRIGHT = ALIGNBUTTONS != "left"; if (!VECINRECT(COORDS, 0, 0, assignedBoxGlobal().w, HEIGHT - 1)) { if (m_bDraggingThis) { if (m_bTouchEv) g_pKeybindManager->m_dispatchers["settiled"]("activewindow"); g_pKeybindManager->m_dispatchers["mouse"]("0movewindow"); Log::logger->log(Log::DEBUG, "[hyprbars] Dragging ended on {:x}", (uintptr_t)PWINDOW.get()); } m_bDraggingThis = false; m_bDragPending = false; m_bTouchEv = false; return; } if (Desktop::focusState()->window() != PWINDOW) Desktop::focusState()->fullWindowFocus(PWINDOW, Desktop::FOCUS_REASON_CLICK); if (PWINDOW->m_isFloating) g_pCompositor->changeWindowZOrder(PWINDOW, true); info.cancelled = true; m_bCancelledDown = true; if (doButtonPress(BARPADDING, BARBUTTONPADDING, HEIGHT, COORDS, BUTTONSRIGHT)) return; if (!ON_DOUBLE_CLICK.empty() && std::chrono::duration_cast(Time::steadyNow() - m_lastMouseDown).count() < 400 /* Arbitrary delay I found suitable */) { Config::Supplementary::executor()->spawn(ON_DOUBLE_CLICK); m_bDragPending = false; } else { m_lastMouseDown = Time::steadyNow(); m_bDragPending = true; } } void CHyprBar::handleUpEvent(Event::SCallbackInfo& info) { if (m_pWindow.lock() != Desktop::focusState()->window()) return; if (m_bCancelledDown) info.cancelled = true; m_bCancelledDown = false; if (m_bDraggingThis) { g_pKeybindManager->changeMouseBindMode(MBIND_INVALID); m_bDraggingThis = false; if (m_bTouchEv) Config::Actions::floatWindow(Config::Actions::eTogglableAction::TOGGLE_ACTION_DISABLE); Log::logger->log(Log::DEBUG, "[hyprbars] Dragging ended on {:x}", (uintptr_t)m_pWindow.lock().get()); } m_bDragPending = false; m_bTouchEv = false; m_touchId = 0; } void CHyprBar::handleMovement() { g_pKeybindManager->changeMouseBindMode(MBIND_MOVE); m_bDraggingThis = true; Log::logger->log(Log::DEBUG, "[hyprbars] Dragging initiated on {:x}", (uintptr_t)m_pWindow.lock().get()); return; } bool CHyprBar::doButtonPress(Config::INTEGER barPadding, Config::INTEGER barButtonPadding, Config::INTEGER barHeight, Vector2D COORDS, const bool BUTTONSRIGHT) { //check if on a button float offset = barPadding; for (auto& b : g_pGlobalState->buttons) { const auto BARBUF = Vector2D{(int)assignedBoxGlobal().w, barHeight}; Vector2D currentPos = Vector2D{(BUTTONSRIGHT ? BARBUF.x - barButtonPadding - b.size - offset : offset), (BARBUF.y - b.size) / 2.0}.floor(); if (VECINRECT(COORDS, currentPos.x, currentPos.y, currentPos.x + b.size + barButtonPadding, currentPos.y + b.size)) { // hit on close g_pKeybindManager->m_dispatchers["exec"](b.cmd); return true; } offset += barButtonPadding + b.size; } return false; } void CHyprBar::renderBarTitle(const Vector2D& bufferSize, const float scale) { const auto COLORVAL = g_pGlobalState->config.textColor->value(); const auto SIZE = g_pGlobalState->config.barTextSize->value(); const auto FONT = g_pGlobalState->config.barTextFont->value(); const auto ALIGN = g_pGlobalState->config.barTextAlign->value(); const auto BARPADDING = g_pGlobalState->config.barPadding->value(); const auto BARBUTTONPADDING = g_pGlobalState->config.barButtonPadding->value(); float buttonSizes = BARBUTTONPADDING; for (auto& b : g_pGlobalState->buttons) { buttonSizes += b.size + BARBUTTONPADDING; } const int scaledSize = std::round(SIZE * scale); const auto scaledButtonsSize = buttonSizes * scale; const auto scaledBarPadding = BARPADDING * scale; const int paddingTotal = scaledBarPadding * 2 + scaledButtonsSize + (ALIGN != "left" ? scaledButtonsSize : 0); const int maxWidth = std::clamp(static_cast(bufferSize.x - paddingTotal), 0, INT_MAX); if (m_szLastTitle.empty() || maxWidth < 1) { m_pTextTex = nullptr; return; } const CHyprColor COLOR = m_bForcedTitleColor.value_or(configColor(COLORVAL)); m_pTextTex = g_pHyprRenderer->renderText(m_szLastTitle, COLOR, scaledSize, false, FONT, maxWidth); } size_t CHyprBar::getVisibleButtonCount(Config::INTEGER barButtonPadding, Config::INTEGER barPadding, const Vector2D& bufferSize, const float scale) { float availableSpace = bufferSize.x - barPadding * scale * 2; size_t count = 0; for (const auto& button : g_pGlobalState->buttons) { const float buttonSpace = (button.size + barButtonPadding) * scale; if (availableSpace >= buttonSpace) { count++; availableSpace -= buttonSpace; } else break; } return count; } void CHyprBar::renderBarButtons(CBox* barBox, const float scale, const float a) { const auto BARBUTTONPADDING = g_pGlobalState->config.barButtonPadding->value(); const auto BARPADDING = g_pGlobalState->config.barPadding->value(); const auto ALIGNBUTTONS = g_pGlobalState->config.barButtonsAlignment->value(); const auto INACTIVECOLOR = g_pGlobalState->config.inactiveButtonColor->value(); const bool BUTTONSRIGHT = ALIGNBUTTONS != "left"; const auto visibleCount = getVisibleButtonCount(BARBUTTONPADDING, BARPADDING, Vector2D{barBox->w, barBox->h}, scale); const bool INVALIDATEICONS = m_bButtonsDirty || m_bWindowSizeChanged; int offset = BARPADDING * scale; for (size_t i = 0; i < visibleCount; ++i) { auto& button = g_pGlobalState->buttons[i]; const auto scaledButtonSize = button.size * scale; const auto scaledButtonsPad = BARBUTTONPADDING * scale; auto color = button.bgcol; if (INACTIVECOLOR > 0) { color = m_bWindowHasFocus ? color : configColor(INACTIVECOLOR); if (INVALIDATEICONS && button.userfg && button.iconTex) button.iconTex = nullptr; } color.a *= a; CBox buttonBox = {barBox->x + (BUTTONSRIGHT ? barBox->w - offset - scaledButtonSize : offset), barBox->y + (barBox->h - scaledButtonSize) / 2.0, scaledButtonSize, scaledButtonSize}; buttonBox.round(); g_pHyprOpenGL->renderRect(buttonBox, color, {.round = static_cast(std::round(scaledButtonSize / 2.0)), .roundingPower = 2.F}); offset += scaledButtonsPad + scaledButtonSize; } } void CHyprBar::renderBarButtonsText(CBox* barBox, const float scale, const float a) { const auto HEIGHT = g_pGlobalState->config.barHeight->value(); const auto BARBUTTONPADDING = g_pGlobalState->config.barButtonPadding->value(); const auto BARPADDING = g_pGlobalState->config.barPadding->value(); const auto ALIGNBUTTONS = g_pGlobalState->config.barButtonsAlignment->value(); const auto ICONONHOVER = g_pGlobalState->config.iconOnHover->value(); const bool BUTTONSRIGHT = ALIGNBUTTONS != "left"; const auto visibleCount = getVisibleButtonCount(BARBUTTONPADDING, BARPADDING, Vector2D{barBox->w, barBox->h}, scale); const auto COORDS = cursorRelativeToBar(); int offset = BARPADDING * scale; float noScaleOffset = BARPADDING; for (size_t i = 0; i < visibleCount; ++i) { auto& button = g_pGlobalState->buttons[i]; const auto scaledButtonSize = button.size * scale; const auto scaledButtonsPad = BARBUTTONPADDING * scale; // check if hovering here const auto BARBUF = Vector2D{(int)assignedBoxGlobal().w, HEIGHT}; Vector2D currentPos = Vector2D{(BUTTONSRIGHT ? BARBUF.x - BARBUTTONPADDING - button.size - noScaleOffset : noScaleOffset), (BARBUF.y - button.size) / 2.0}.floor(); bool hovering = VECINRECT(COORDS, currentPos.x, currentPos.y, currentPos.x + button.size + BARBUTTONPADDING, currentPos.y + button.size); noScaleOffset += BARBUTTONPADDING + button.size; if ((!button.iconTex || button.iconTex->m_texID == 0) && !button.icon.empty()) { // render icon auto fgcol = button.userfg ? button.fgcol : (button.bgcol.r + button.bgcol.g + button.bgcol.b < 1) ? CHyprColor(0xFFFFFFFF) : CHyprColor(0xFF000000); button.iconTex = g_pHyprRenderer->renderText(button.icon, fgcol, std::round(button.size * 0.62 * scale), false, "sans", scaledButtonSize); } if (!button.iconTex || button.iconTex->m_texID == 0) continue; const auto iconX = barBox->x + (BUTTONSRIGHT ? barBox->width - offset - scaledButtonSize / 2.0 : offset + scaledButtonSize / 2.0) - button.iconTex->m_size.x / 2.0; const auto iconY = barBox->y + barBox->height / 2.0 - button.iconTex->m_size.y / 2.0; CBox pos = {iconX, iconY, button.iconTex->m_size.x, button.iconTex->m_size.y}; if (!ICONONHOVER || (ICONONHOVER && m_iButtonHoverState > 0)) g_pHyprOpenGL->renderTexture(button.iconTex, pos, {.a = a}); offset += scaledButtonsPad + scaledButtonSize; bool currentBit = (m_iButtonHoverState & (1 << i)) != 0; if (hovering != currentBit) { m_iButtonHoverState ^= (1 << i); // damage to get rid of some artifacts when icons are "hidden" damageEntire(); } } } void CHyprBar::draw(PHLMONITOR pMonitor, const float& a) { const auto ENABLED = g_pGlobalState->config.enabled->value(); if (m_bLastEnabledState != ENABLED) { m_bLastEnabledState = ENABLED; g_pDecorationPositioner->repositionDeco(this); } if (m_hidden || !validMapped(m_pWindow) || !ENABLED) return; const auto PWINDOW = m_pWindow.lock(); if (!PWINDOW->m_ruleApplicator->decorate().valueOrDefault()) return; auto data = CBarPassElement::SBarData{this, a}; g_pHyprRenderer->m_renderPass.add(makeUnique(data)); } void CHyprBar::renderPass(PHLMONITOR pMonitor, const float& a) { const auto PWINDOW = m_pWindow.lock(); static auto PENABLEBLURGLOBAL = CConfigValue("decoration:blur:enabled"); const auto BARCOLOR = g_pGlobalState->config.barColor->value(); const auto HEIGHT = g_pGlobalState->config.barHeight->value(); const auto PRECEDENCE = g_pGlobalState->config.barPrecedenceOverBorder->value(); const auto ALIGNBUTTONS = g_pGlobalState->config.barButtonsAlignment->value(); const auto ENABLETITLE = g_pGlobalState->config.barTitleEnabled->value(); const auto ENABLEBLUR = g_pGlobalState->config.barBlur->value(); const auto INACTIVECOLOR = g_pGlobalState->config.inactiveButtonColor->value(); if (INACTIVECOLOR > 0) { bool currentWindowFocus = PWINDOW == Desktop::focusState()->window(); if (currentWindowFocus != m_bWindowHasFocus) { m_bWindowHasFocus = currentWindowFocus; m_bButtonsDirty = true; } } const CHyprColor DEST_COLOR = m_bForcedBarColor.value_or(configColor(BARCOLOR)); if (DEST_COLOR != m_cRealBarColor->goal()) *m_cRealBarColor = DEST_COLOR; CHyprColor color = m_cRealBarColor->value(); color.a *= a; const bool BUTTONSRIGHT = ALIGNBUTTONS != "left"; const bool SHOULDBLUR = ENABLEBLUR && *PENABLEBLURGLOBAL && color.a < 1.F; if (HEIGHT < 1) { m_iLastHeight = HEIGHT; return; } const auto PWORKSPACE = PWINDOW->m_workspace; const auto WORKSPACEOFFSET = PWORKSPACE && !PWINDOW->m_pinned ? PWORKSPACE->m_renderOffset->value() : Vector2D(); const auto ROUNDING = PWINDOW->rounding() + (PRECEDENCE ? 0 : PWINDOW->getRealBorderSize()); const auto scaledRounding = ROUNDING > 0 ? ROUNDING * pMonitor->m_scale - 2 /* idk why but otherwise it looks bad due to the gaps */ : 0; m_seExtents = {{0, HEIGHT}, {}}; const auto DECOBOX = assignedBoxGlobal(); const auto BARBUF = DECOBOX.size() * pMonitor->m_scale; CBox titleBarBox = {DECOBOX.x - pMonitor->m_position.x, DECOBOX.y - pMonitor->m_position.y, DECOBOX.w, DECOBOX.h + ROUNDING * 3 /* to fill the bottom cuz we can't disable rounding there */}; titleBarBox.translate(PWINDOW->m_floatingOffset).scale(pMonitor->m_scale).round(); if (titleBarBox.w < 1 || titleBarBox.h < 1) return; g_pHyprOpenGL->scissor(titleBarBox); if (ROUNDING) { // the +1 is a shit garbage temp fix until renderRect supports an alpha matte CBox windowBox = {PWINDOW->m_realPosition->value().x + PWINDOW->m_floatingOffset.x - pMonitor->m_position.x + 1, PWINDOW->m_realPosition->value().y + PWINDOW->m_floatingOffset.y - pMonitor->m_position.y + 1, PWINDOW->m_realSize->value().x - 2, PWINDOW->m_realSize->value().y - 2}; if (windowBox.w < 1 || windowBox.h < 1) return; glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT); g_pHyprOpenGL->setCapStatus(GL_STENCIL_TEST, true); glStencilFunc(GL_ALWAYS, 1, -1); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); windowBox.translate(WORKSPACEOFFSET).scale(pMonitor->m_scale).round(); g_pHyprOpenGL->renderRect(windowBox, CHyprColor(0, 0, 0, 0), {.round = scaledRounding, .roundingPower = m_pWindow->roundingPower()}); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glStencilFunc(GL_NOTEQUAL, 1, -1); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); } if (SHOULDBLUR) g_pHyprOpenGL->renderRect(titleBarBox, color, {.round = scaledRounding, .roundingPower = m_pWindow->roundingPower(), .blur = true, .blurA = a}); else g_pHyprOpenGL->renderRect(titleBarBox, color, {.round = scaledRounding, .roundingPower = m_pWindow->roundingPower()}); // render title if (ENABLETITLE && (m_szLastTitle != PWINDOW->m_title || m_bWindowSizeChanged || !m_pTextTex || m_pTextTex->m_texID == 0 || m_bTitleColorChanged)) { m_szLastTitle = PWINDOW->m_title; renderBarTitle(BARBUF, pMonitor->m_scale); } if (ROUNDING) { // cleanup stencil glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT); g_pHyprOpenGL->setCapStatus(GL_STENCIL_TEST, false); glStencilMask(-1); glStencilFunc(GL_ALWAYS, 1, 0xFF); } CBox textBox = {titleBarBox.x, titleBarBox.y, (int)BARBUF.x, (int)BARBUF.y}; if (ENABLETITLE && m_pTextTex) { const auto BARPADDING = g_pGlobalState->config.barPadding->value(); const auto BARBUTTONPADDING = g_pGlobalState->config.barButtonPadding->value(); const auto ALIGN = g_pGlobalState->config.barTextAlign->value(); float buttonSizes = BARBUTTONPADDING; for (auto& b : g_pGlobalState->buttons) { buttonSizes += b.size + BARBUTTONPADDING; } const auto scaledBorderSize = PWINDOW->getRealBorderSize() * pMonitor->m_scale; const auto scaledButtonsSize = buttonSizes * pMonitor->m_scale; const auto scaledBarPadding = BARPADDING * pMonitor->m_scale; const auto xOffset = ALIGN == "left" ? std::round(scaledBarPadding + (BUTTONSRIGHT ? 0 : scaledButtonsSize)) : std::round(((BARBUF.x - scaledBorderSize) / 2.0 - m_pTextTex->m_size.x / 2.0)); const auto yOffset = std::round((BARBUF.y - m_pTextTex->m_size.y) / 2.0); CBox titleBox = {textBox.x + xOffset, textBox.y + yOffset, m_pTextTex->m_size.x, m_pTextTex->m_size.y}; g_pHyprOpenGL->renderTexture(m_pTextTex, titleBox, {.a = a}); } renderBarButtons(&textBox, pMonitor->m_scale, a); m_bButtonsDirty = false; g_pHyprOpenGL->scissor(nullptr); renderBarButtonsText(&textBox, pMonitor->m_scale, a); m_bWindowSizeChanged = false; m_bTitleColorChanged = false; // dynamic updates change the extents if (m_iLastHeight != HEIGHT) { PWINDOW->layoutTarget()->recalc(); m_iLastHeight = HEIGHT; } } eDecorationType CHyprBar::getDecorationType() { return DECORATION_CUSTOM; } void CHyprBar::updateWindow(PHLWINDOW pWindow) { damageEntire(); } void CHyprBar::onConfigReloaded() { m_bButtonsDirty = true; m_bTitleColorChanged = true; m_pTextTex = nullptr; g_pDecorationPositioner->repositionDeco(this); damageEntire(); } void CHyprBar::damageEntire() { g_pHyprRenderer->damageBox(assignedBoxGlobal()); } Vector2D CHyprBar::cursorRelativeToBar() { return g_pInputManager->getMouseCoordsInternal() - assignedBoxGlobal().pos(); } eDecorationLayer CHyprBar::getDecorationLayer() { return DECORATION_LAYER_UNDER; } uint64_t CHyprBar::getDecorationFlags() { return DECORATION_ALLOWS_MOUSE_INPUT | (g_pGlobalState->config.barPartOfWindow->value() ? DECORATION_PART_OF_MAIN_WINDOW : 0); } CBox CHyprBar::assignedBoxGlobal() { if (!validMapped(m_pWindow)) return {}; CBox box = m_bAssignedBox; box.translate(g_pDecorationPositioner->getEdgeDefinedPoint(DECORATION_EDGE_TOP, m_pWindow.lock())); const auto PWORKSPACE = m_pWindow->m_workspace; const auto WORKSPACEOFFSET = PWORKSPACE && !m_pWindow->m_pinned ? PWORKSPACE->m_renderOffset->value() : Vector2D(); return box.translate(WORKSPACEOFFSET); } PHLWINDOW CHyprBar::getOwner() { return m_pWindow.lock(); } void CHyprBar::updateRules() { const auto PWINDOW = m_pWindow.lock(); auto prevHidden = m_hidden; auto prevForcedTitleColor = m_bForcedTitleColor; m_bForcedBarColor = std::nullopt; m_bForcedTitleColor = std::nullopt; m_hidden = false; if (PWINDOW->m_ruleApplicator->m_otherProps.props.contains(g_pGlobalState->nobarRuleIdx)) m_hidden = truthy(PWINDOW->m_ruleApplicator->m_otherProps.props.at(g_pGlobalState->nobarRuleIdx)->effect); if (PWINDOW->m_ruleApplicator->m_otherProps.props.contains(g_pGlobalState->barColorRuleIdx)) m_bForcedBarColor = CHyprColor(Config::ParserUtils::parseColor(PWINDOW->m_ruleApplicator->m_otherProps.props.at(g_pGlobalState->barColorRuleIdx)->effect).value_or(0)); if (PWINDOW->m_ruleApplicator->m_otherProps.props.contains(g_pGlobalState->titleColorRuleIdx)) m_bForcedTitleColor = CHyprColor(Config::ParserUtils::parseColor(PWINDOW->m_ruleApplicator->m_otherProps.props.at(g_pGlobalState->titleColorRuleIdx)->effect).value_or(0)); if (prevHidden != m_hidden) g_pDecorationPositioner->repositionDeco(this); if (prevForcedTitleColor != m_bForcedTitleColor) m_bTitleColorChanged = true; } void CHyprBar::damageOnButtonHover() { const auto BARPADDING = g_pGlobalState->config.barPadding->value(); const auto BARBUTTONPADDING = g_pGlobalState->config.barButtonPadding->value(); const auto HEIGHT = g_pGlobalState->config.barHeight->value(); const auto ALIGNBUTTONS = g_pGlobalState->config.barButtonsAlignment->value(); const bool BUTTONSRIGHT = ALIGNBUTTONS != "left"; float offset = BARPADDING; const auto COORDS = cursorRelativeToBar(); for (auto& b : g_pGlobalState->buttons) { const auto BARBUF = Vector2D{(int)assignedBoxGlobal().w, HEIGHT}; Vector2D currentPos = Vector2D{(BUTTONSRIGHT ? BARBUF.x - BARBUTTONPADDING - b.size - offset : offset), (BARBUF.y - b.size) / 2.0}.floor(); bool hover = VECINRECT(COORDS, currentPos.x, currentPos.y, currentPos.x + b.size + BARBUTTONPADDING, currentPos.y + b.size); if (hover != m_bButtonHovered) { m_bButtonHovered = hover; damageEntire(); } offset += BARBUTTONPADDING + b.size; } } hyprwm-hyprland-plugins-3ba8bfb/hyprbars/barDeco.hpp000066400000000000000000000104701520105331200230030ustar00rootroot00000000000000#pragma once #define WLR_USE_UNSTABLE #include #include #include #include #include #include #include #include #include #include "globals.hpp" #define private public #include #undef private namespace Event { struct SCallbackInfo; } class CHyprBar : public IHyprWindowDecoration { public: CHyprBar(PHLWINDOW); virtual ~CHyprBar(); virtual SDecorationPositioningInfo getPositioningInfo(); virtual void onPositioningReply(const SDecorationPositioningReply& reply); virtual void draw(PHLMONITOR, float const& a); virtual eDecorationType getDecorationType(); virtual void updateWindow(PHLWINDOW); virtual void damageEntire(); virtual eDecorationLayer getDecorationLayer(); virtual uint64_t getDecorationFlags(); bool m_bButtonsDirty = true; virtual std::string getDisplayName(); PHLWINDOW getOwner(); void updateRules(); void onConfigReloaded(); WP m_self; private: SBoxExtents m_seExtents; PHLWINDOWREF m_pWindow; CBox m_bAssignedBox; SP m_pTextTex; bool m_bWindowSizeChanged = false; bool m_hidden = false; bool m_bTitleColorChanged = false; bool m_bButtonHovered = false; bool m_bLastEnabledState = false; bool m_bWindowHasFocus = false; std::optional m_bForcedBarColor; std::optional m_bForcedTitleColor; Time::steady_tp m_lastMouseDown = Time::steadyNow(); PHLANIMVAR m_cRealBarColor; Vector2D cursorRelativeToBar(); void renderPass(PHLMONITOR, float const& a); void renderBarTitle(const Vector2D& bufferSize, const float scale); void renderBarButtons(CBox* barBox, const float scale, const float a); void renderBarButtonsText(CBox* barBox, const float scale, const float a); void damageOnButtonHover(); bool inputIsValid(); void onMouseButton(Event::SCallbackInfo& info, IPointer::SButtonEvent e); void onTouchDown(Event::SCallbackInfo& info, ITouch::SDownEvent e); void onTouchUp(Event::SCallbackInfo& info, ITouch::SUpEvent e); void onMouseMove(Vector2D coords); void onTouchMove(Event::SCallbackInfo& info, ITouch::SMotionEvent e); void handleDownEvent(Event::SCallbackInfo& info, std::optional touchEvent); void handleUpEvent(Event::SCallbackInfo& info); void handleMovement(); bool doButtonPress(Config::INTEGER barPadding, Config::INTEGER barButtonPadding, Config::INTEGER barHeight, Vector2D COORDS, bool BUTTONSRIGHT); CBox assignedBoxGlobal(); CHyprSignalListener m_pMouseButtonCallback; CHyprSignalListener m_pTouchDownCallback; CHyprSignalListener m_pTouchUpCallback; CHyprSignalListener m_pTouchMoveCallback; CHyprSignalListener m_pMouseMoveCallback; std::string m_szLastTitle; bool m_bDraggingThis = false; bool m_bTouchEv = false; bool m_bDragPending = false; bool m_bCancelledDown = false; int m_touchId = 0; // store hover state for buttons as a bitfield unsigned int m_iButtonHoverState = 0; // for dynamic updates int m_iLastHeight = 0; size_t getVisibleButtonCount(Config::INTEGER barButtonPadding, Config::INTEGER barPadding, const Vector2D& bufferSize, const float scale); friend class CBarPassElement; }; hyprwm-hyprland-plugins-3ba8bfb/hyprbars/default.nix000066400000000000000000000006171520105331200231010ustar00rootroot00000000000000{ lib, hyprland, hyprlandPlugins, }: hyprlandPlugins.mkHyprlandPlugin { pluginName = "hyprbars"; version = "0.1"; src = ./.; inherit (hyprland) nativeBuildInputs; meta = with lib; { homepage = "https://github.com/hyprwm/hyprland-plugins/tree/main/hyprbars"; description = "Hyprland window title plugin"; license = licenses.bsd3; platforms = platforms.linux; }; } hyprwm-hyprland-plugins-3ba8bfb/hyprbars/globals.hpp000066400000000000000000000030651520105331200230710ustar00rootroot00000000000000#pragma once #include #include #include #include #include #include inline HANDLE PHANDLE = nullptr; struct SHyprButton { std::string cmd = ""; bool userfg = false; CHyprColor fgcol = CHyprColor(0, 0, 0, 0); CHyprColor bgcol = CHyprColor(0, 0, 0, 0); float size = 10; std::string icon = ""; SP iconTex; }; class CHyprBar; struct SGlobalState { std::vector buttons; std::vector> bars; uint32_t nobarRuleIdx = 0; uint32_t barColorRuleIdx = 0; uint32_t titleColorRuleIdx = 0; struct { SP barColor, textColor, inactiveButtonColor; SP barHeight; SP barTextSize; SP barPadding; SP barButtonPadding; SP barBlur, barTitleEnabled, barPartOfWindow, barPrecedenceOverBorder, enabled, iconOnHover; SP barTextFont, barTextAlign, barButtonsAlignment, onDoubleClick; } config; }; inline UP g_pGlobalState; hyprwm-hyprland-plugins-3ba8bfb/hyprbars/main.cpp000066400000000000000000000271421520105331200223670ustar00rootroot00000000000000#define WLR_USE_UNSTABLE #include #include #include #include #include #include #include #include #include #include #include #include #include #include "barDeco.hpp" #include "globals.hpp" extern "C" { #include #include } // Do NOT change this function. APICALL EXPORT std::string PLUGIN_API_VERSION() { return HYPRLAND_API_VERSION; } static void onNewWindow(PHLWINDOW window) { if (!window->m_X11DoesntWantBorders) { if (std::ranges::any_of(window->m_windowDecorations, [](const auto& d) { return d->getDisplayName() == "Hyprbar"; })) return; auto bar = makeUnique(window); g_pGlobalState->bars.emplace_back(bar); bar->m_self = bar; HyprlandAPI::addWindowDecoration(PHANDLE, window, std::move(bar)); } } static void onPreConfigReload() { g_pGlobalState->buttons.clear(); } static void onConfigReloaded() { for (auto& b : g_pGlobalState->bars) { if (!b) continue; b->onConfigReloaded(); } } static void onUpdateWindowRules(PHLWINDOW window) { const auto BARIT = std::find_if(g_pGlobalState->bars.begin(), g_pGlobalState->bars.end(), [window](const auto& bar) { return bar->getOwner() == window; }); if (BARIT == g_pGlobalState->bars.end()) return; (*BARIT)->updateRules(); window->updateWindowDecos(); } Hyprlang::CParseResult onNewButton(const char* K, const char* V) { std::string v = V; Hyprutils::String::CVarList vars(v); Hyprlang::CParseResult result; // hyprbars-button = bgcolor, size, icon, action, fgcolor if (vars[0].empty() || vars[1].empty()) { result.setError("bgcolor and size cannot be empty"); return result; } float size = 10; try { size = std::stof(vars[1]); } catch (std::exception& e) { result.setError("failed to parse size"); return result; } bool userfg = false; auto fgcolor = Config::ParserUtils::parseColor("rgb(ffffff)"); auto bgcolor = Config::ParserUtils::parseColor(vars[0]); if (!bgcolor) { result.setError("invalid bgcolor"); return result; } if (vars.size() == 5) { userfg = true; fgcolor = Config::ParserUtils::parseColor(vars[4]); } if (!fgcolor) { result.setError("invalid fgcolor"); return result; } g_pGlobalState->buttons.push_back(SHyprButton{vars[3], userfg, *fgcolor, *bgcolor, size, vars[2]}); for (auto& b : g_pGlobalState->bars) { b->m_bButtonsDirty = true; } return result; } int newLuaButton(lua_State* L) { if (!lua_istable(L, 1)) return Config::Lua::Bindings::Internal::configError(L, "add_button: expected a table { bg_color, fg_color, size, icon, action }"); SHyprButton button; { Hyprutils::Utils::CScopeGuard x([L] { lua_pop(L, 1); }); lua_getfield(L, 1, "bg_color"); Config::Lua::CLuaConfigColor parser(0); auto err = parser.parse(L); if (err.errorCode != Config::Lua::PARSE_ERROR_OK) return Config::Lua::Bindings::Internal::configError(L, "add_button: failed to parse bg_color"); button.bgcol = parser.parsed(); } { Hyprutils::Utils::CScopeGuard x([L] { lua_pop(L, 1); }); lua_getfield(L, 1, "fg_color"); Config::Lua::CLuaConfigColor parser(0); auto err = parser.parse(L); if (err.errorCode != Config::Lua::PARSE_ERROR_OK) return Config::Lua::Bindings::Internal::configError(L, "add_button: failed to parse fg_color"); button.fgcol = parser.parsed(); } { Hyprutils::Utils::CScopeGuard x([L] { lua_pop(L, 1); }); lua_getfield(L, 1, "size"); if (!lua_isnumber(L, -1)) return Config::Lua::Bindings::Internal::configError(L, "add_button: size must be an integer"); button.size = lua_tointeger(L, -1); } { Hyprutils::Utils::CScopeGuard x([L] { lua_pop(L, 1); }); lua_getfield(L, 1, "icon"); if (!lua_isstring(L, -1)) return Config::Lua::Bindings::Internal::configError(L, "add_button: icon must be a string"); button.icon = lua_tostring(L, -1); } { Hyprutils::Utils::CScopeGuard x([L] { lua_pop(L, 1); }); lua_getfield(L, 1, "action"); if (!lua_isstring(L, -1)) return Config::Lua::Bindings::Internal::configError(L, "add_button: action must be a string"); button.cmd = lua_tostring(L, -1); } g_pGlobalState->buttons.push_back(std::move(button)); for (auto& b : g_pGlobalState->bars) { b->m_bButtonsDirty = true; } return 0; } APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { PHANDLE = handle; const std::string HASH = __hyprland_api_get_hash(); const std::string CLIENT_HASH = __hyprland_api_get_client_hash(); if (HASH != CLIENT_HASH) { HyprlandAPI::addNotification(PHANDLE, "[hyprbars] Failure in initialization: Version mismatch (headers ver is not equal to running hyprland ver)", CHyprColor{1.0, 0.2, 0.2, 1.0}, 5000); throw std::runtime_error("[hb] Version mismatch"); } g_pGlobalState = makeUnique(); g_pGlobalState->nobarRuleIdx = Desktop::Rule::windowEffects()->registerEffect("hyprbars:no_bar"); g_pGlobalState->barColorRuleIdx = Desktop::Rule::windowEffects()->registerEffect("hyprbars:bar_color"); g_pGlobalState->titleColorRuleIdx = Desktop::Rule::windowEffects()->registerEffect("hyprbars:title_color"); static auto P = Event::bus()->m_events.window.open.listen([&](PHLWINDOW w) { onNewWindow(w); }); static auto P3 = Event::bus()->m_events.window.updateRules.listen([&](PHLWINDOW w) { onUpdateWindowRules(w); }); g_pGlobalState->config.barColor = makeShared("plugin:hyprbars:bar_color", "Change the bar color", 0x88333333); g_pGlobalState->config.textColor = makeShared("plugin:hyprbars:col.text", "Change the text color", 0xffffffff); g_pGlobalState->config.inactiveButtonColor = makeShared( "plugin:hyprbars:inactive_button_color", "Change the inactive button's color. 0x00000000 means unset", 0x00000000); g_pGlobalState->config.barHeight = makeShared("plugin:hyprbars:bar_height", "Change the bar's height", 15); g_pGlobalState->config.barTextSize = makeShared("plugin:hyprbars:bar_text_size", "Change the bar's text size", 10); g_pGlobalState->config.barTitleEnabled = makeShared("plugin:hyprbars:bar_title_enabled", "Whether to enable titles in the bar", true); g_pGlobalState->config.barBlur = makeShared("plugin:hyprbars:bar_blur", "Whether to enable blur of the bar", false); g_pGlobalState->config.barTextFont = makeShared("plugin:hyprbars:bar_text_font", "Bar's text font", "Sans"); g_pGlobalState->config.barTextAlign = makeShared("plugin:hyprbars:bar_text_align", "Bar's text alignment", "center"); g_pGlobalState->config.barPartOfWindow = makeShared("plugin:hyprbars:bar_part_of_window", "Whether the bar is a part of the window (reserves space)", true); g_pGlobalState->config.barPrecedenceOverBorder = makeShared("plugin:hyprbars:bar_precedence_over_border", "Whether the bar is before, or after the border", false); g_pGlobalState->config.barButtonsAlignment = makeShared("plugin:hyprbars:bar_buttons_alignment", "Alignment of the bar buttons", "right"); g_pGlobalState->config.barPadding = makeShared("plugin:hyprbars:bar_padding", "Padding of the bar", 7); g_pGlobalState->config.barButtonPadding = makeShared("plugin:hyprbars:bar_button_padding", "Padding of the bar buttons", 5); g_pGlobalState->config.enabled = makeShared("plugin:hyprbars:enabled", "Whether bars are enabled", true); g_pGlobalState->config.iconOnHover = makeShared("plugin:hyprbars:icon_on_hover", "Whether to use an icon on hover of the buttons", false); g_pGlobalState->config.onDoubleClick = makeShared("plugin:hyprbars:on_double_click", "Action to execute on double click of the bar", ""); HyprlandAPI::addConfigValueV2(PHANDLE, g_pGlobalState->config.barColor); HyprlandAPI::addConfigValueV2(PHANDLE, g_pGlobalState->config.textColor); HyprlandAPI::addConfigValueV2(PHANDLE, g_pGlobalState->config.inactiveButtonColor); HyprlandAPI::addConfigValueV2(PHANDLE, g_pGlobalState->config.barHeight); HyprlandAPI::addConfigValueV2(PHANDLE, g_pGlobalState->config.barTextSize); HyprlandAPI::addConfigValueV2(PHANDLE, g_pGlobalState->config.barTitleEnabled); HyprlandAPI::addConfigValueV2(PHANDLE, g_pGlobalState->config.barBlur); HyprlandAPI::addConfigValueV2(PHANDLE, g_pGlobalState->config.barTextFont); HyprlandAPI::addConfigValueV2(PHANDLE, g_pGlobalState->config.barTextAlign); HyprlandAPI::addConfigValueV2(PHANDLE, g_pGlobalState->config.barPartOfWindow); HyprlandAPI::addConfigValueV2(PHANDLE, g_pGlobalState->config.barPrecedenceOverBorder); HyprlandAPI::addConfigValueV2(PHANDLE, g_pGlobalState->config.barButtonsAlignment); HyprlandAPI::addConfigValueV2(PHANDLE, g_pGlobalState->config.barPadding); HyprlandAPI::addConfigValueV2(PHANDLE, g_pGlobalState->config.barButtonPadding); HyprlandAPI::addConfigValueV2(PHANDLE, g_pGlobalState->config.enabled); HyprlandAPI::addConfigValueV2(PHANDLE, g_pGlobalState->config.iconOnHover); HyprlandAPI::addConfigValueV2(PHANDLE, g_pGlobalState->config.onDoubleClick); if (Config::mgr()->type() == Config::CONFIG_LEGACY) HyprlandAPI::addConfigKeyword(PHANDLE, "plugin:hyprbars:hyprbars-button", onNewButton, Hyprlang::SHandlerOptions{}); else HyprlandAPI::addLuaFunction(PHANDLE, "hyprbars", "add_button", ::newLuaButton); static auto P4 = Event::bus()->m_events.config.preReload.listen([&] { onPreConfigReload(); }); static auto P5 = Event::bus()->m_events.config.reloaded.listen([&] { onConfigReloaded(); }); // add deco to existing windows for (auto& w : g_pCompositor->m_windows) { if (w->isHidden() || !w->m_isMapped) continue; onNewWindow(w); } HyprlandAPI::reloadConfig(); return {"hyprbars", "A plugin to add title bars to windows.", "Vaxry", "1.0"}; } APICALL EXPORT void PLUGIN_EXIT() { for (auto& m : g_pCompositor->m_monitors) m->m_scheduledRecalc = true; g_pHyprRenderer->m_renderPass.removeAllOfType("CBarPassElement"); Desktop::Rule::windowEffects()->unregisterEffect(g_pGlobalState->barColorRuleIdx); Desktop::Rule::windowEffects()->unregisterEffect(g_pGlobalState->titleColorRuleIdx); Desktop::Rule::windowEffects()->unregisterEffect(g_pGlobalState->nobarRuleIdx); } hyprwm-hyprland-plugins-3ba8bfb/hyprbars/meson.build000066400000000000000000000017371520105331200231030ustar00rootroot00000000000000project('hyprbars', 'cpp', version: '0.1', default_options: ['buildtype=release'], ) cpp_compiler = meson.get_compiler('cpp') if cpp_compiler.has_argument('-std=c++23') add_global_arguments('-std=c++23', language: 'cpp') elif cpp_compiler.has_argument('-std=c++2b') add_global_arguments('-std=c++2b', language: 'cpp') else error('Could not configure current C++ compiler (' + cpp_compiler.get_id() + ' ' + cpp_compiler.version() + ') with required C++ standard (C++23)') endif add_project_arguments( [ '-Wno-narrowing', ], language: 'cpp') globber = run_command('find', '.', '-name', '*.cpp', check: true) src = globber.stdout().strip().split('\n') hyprland = dependency('hyprland') shared_module(meson.project_name(), src, dependencies: [ dependency('hyprland'), dependency('pixman-1'), dependency('libdrm'), dependency('libinput'), dependency('libudev'), dependency('wayland-server'), dependency('xkbcommon'), ], install: true, ) hyprwm-hyprland-plugins-3ba8bfb/hyprfocus/000077500000000000000000000000001520105331200211215ustar00rootroot00000000000000hyprwm-hyprland-plugins-3ba8bfb/hyprfocus/CMakeLists.txt000066400000000000000000000007601520105331200236640ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.27) project(hyprfocus DESCRIPTION "flashfocus for Hyprland" VERSION 0.1 ) set(CMAKE_CXX_STANDARD 23) file(GLOB_RECURSE SRC "*.cpp") add_library(hyprfocus SHARED ${SRC}) find_package(PkgConfig REQUIRED) pkg_check_modules(deps REQUIRED IMPORTED_TARGET hyprland libdrm libinput libudev pangocairo pixman-1 wayland-server xkbcommon ) target_link_libraries(hyprfocus PRIVATE rt PkgConfig::deps) install(TARGETS hyprfocus) hyprwm-hyprland-plugins-3ba8bfb/hyprfocus/Makefile000066400000000000000000000005661520105331200225700ustar00rootroot00000000000000# Else exist specifically for clang ifeq ($(CXX),g++) EXTRA_FLAGS = --no-gnu-unique else EXTRA_FLAGS = endif CXXFLAGS ?= -O2 CXXFLAGS += -shared -fPIC -std=c++2b all: $(CXX) $(CXXFLAGS) $(LDFLAGS) $(EXTRA_FLAGS) main.cpp -o hyprfocus.so `pkg-config --cflags pixman-1 libdrm hyprland pangocairo libinput libudev wayland-server xkbcommon` clean: rm ./hyprfocus.so hyprwm-hyprland-plugins-3ba8bfb/hyprfocus/README.md000066400000000000000000000021101520105331200223720ustar00rootroot00000000000000# hyprfocus Flashfocus for Hyprland. ## Configuring ### Animations Hyprfocus exposes two animation leaves: `hyprfocusIn` and `hyprfocusOut`: ```ini animation = hyprfocusIn, 1, 1.7, myCurve animation = hyprfocusOut, 1, 1.7, myCurve2 ``` ### Variables | name | description | type | default | |--------------------------|----------------------------------------------------------------------|---------|---------| | `mode` | which mode to use (flash / bounce / slide) | str | flash | | `only_on_monitor_change` | whether to only perform the animation when changing between monitors | boolean | false | | `fade_opacity` | for flash, what opacity to flash to | float | 0.8 | | `bounce_strength` | for bounce, what fraction of the window's size to jump to | float | 0.95 | | `slide_height` | for slide, how far up to slide | float | 20 | hyprwm-hyprland-plugins-3ba8bfb/hyprfocus/default.nix000066400000000000000000000006171520105331200232710ustar00rootroot00000000000000{ lib, hyprland, hyprlandPlugins, }: hyprlandPlugins.mkHyprlandPlugin { pluginName = "hyprfocus"; version = "0.1"; src = ./.; inherit (hyprland) nativeBuildInputs; meta = with lib; { homepage = "https://github.com/hyprwm/hyprland-plugins/tree/main/hyprfocus"; description = "Hyprland flashfocus plugin"; license = licenses.bsd3; platforms = platforms.linux; }; } hyprwm-hyprland-plugins-3ba8bfb/hyprfocus/globals.hpp000066400000000000000000000001351520105331200232540ustar00rootroot00000000000000#pragma once #include inline HANDLE PHANDLE = nullptr;hyprwm-hyprland-plugins-3ba8bfb/hyprfocus/main.cpp000066400000000000000000000155511520105331200225600ustar00rootroot00000000000000#define WLR_USE_UNSTABLE #include #include #include #include #include #define private public #include #include #include #include #include #include #include #include #include #include #include #include #undef private #include "globals.hpp" #include #include using namespace Hyprutils::String; using namespace Hyprutils::Animation; static struct { SP onlyOnMonitorChange; SP fadeOpacity, slideHeight, bounceStrength; SP mode; } configValues; // Do NOT change this function. APICALL EXPORT std::string PLUGIN_API_VERSION() { return HYPRLAND_API_VERSION; } static void onFocusChange(PHLWINDOW window) { if (!window) return; static PHLWINDOWREF lastWindow; if (lastWindow == window) return; if (configValues.onlyOnMonitorChange->value() && lastWindow && lastWindow->m_monitor == window->m_monitor) return; lastWindow = window; const auto PIN = Config::animationTree()->getAnimationPropertyConfig("hyprfocusIn"); const auto POUT = Config::animationTree()->getAnimationPropertyConfig("hyprfocusOut"); if (configValues.mode->value() == "flash") { const auto ORIGINAL = window->alpha(Desktop::View::WINDOW_ALPHA_ACTIVE)->goal(); window->alpha(Desktop::View::WINDOW_ALPHA_ACTIVE)->setConfig(PIN); *window->alpha(Desktop::View::WINDOW_ALPHA_ACTIVE) = configValues.fadeOpacity->value(); window->alpha(Desktop::View::WINDOW_ALPHA_ACTIVE)->setCallbackOnEnd([w = PHLWINDOWREF{window}, POUT, ORIGINAL](WP pav) { if (!w) return; w->alpha(Desktop::View::WINDOW_ALPHA_ACTIVE)->setConfig(POUT); *w->alpha(Desktop::View::WINDOW_ALPHA_ACTIVE) = ORIGINAL; w->alpha(Desktop::View::WINDOW_ALPHA_ACTIVE)->setCallbackOnEnd(nullptr); }); } else if (configValues.mode->value() == "bounce") { const auto ORIGINAL = CBox{window->m_realPosition->goal(), window->m_realSize->goal()}; window->m_realPosition->setConfig(PIN); window->m_realSize->setConfig(PIN); auto box = ORIGINAL.copy().scaleFromCenter(configValues.bounceStrength->value()); *window->m_realPosition = box.pos(); *window->m_realSize = box.size(); window->m_realSize->setCallbackOnEnd([w = PHLWINDOWREF{window}, POUT, ORIGINAL](WP pav) { if (!w) return; w->m_realSize->setConfig(POUT); w->m_realPosition->setConfig(POUT); if (w->m_isFloating || w->isFullscreen()) { *w->m_realPosition = ORIGINAL.pos(); *w->m_realSize = ORIGINAL.size(); } else w->layoutTarget()->recalc(); w->m_realSize->setCallbackOnEnd(nullptr); }); } else if (configValues.mode->value() == "slide") { const auto ORIGINAL = window->m_realPosition->goal(); window->m_realPosition->setConfig(PIN); *window->m_realPosition = ORIGINAL - Vector2D{0.F, configValues.slideHeight->value()}; window->m_realPosition->setCallbackOnEnd([w = PHLWINDOWREF{window}, POUT, ORIGINAL](WP pav) { if (!w) return; w->m_realPosition->setConfig(POUT); if (w->m_isFloating || w->isFullscreen()) *w->m_realPosition = ORIGINAL; else w->layoutTarget()->recalc(); w->m_realPosition->setCallbackOnEnd(nullptr); }); } } APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { PHANDLE = handle; const std::string HASH = __hyprland_api_get_hash(); const std::string CLIENT_HASH = __hyprland_api_get_client_hash(); if (HASH != CLIENT_HASH) { HyprlandAPI::addNotification(PHANDLE, "[hyprwinwrap] Failure in initialization: Version mismatch (headers ver is not equal to running hyprland ver)", CHyprColor{1.0, 0.2, 0.2, 1.0}, 5000); throw std::runtime_error("[hww] Version mismatch"); } static auto P = Event::bus()->m_events.window.active.listen([&](PHLWINDOW w, Desktop::eFocusReason r) { onFocusChange(w); }); configValues.mode = makeShared("plugin:hyprfocus:mode", "mode to use", "flash"); configValues.onlyOnMonitorChange = makeShared("plugin:hyprfocus:only_on_monitor_change", "whether to fire the animation only on monitor change", false); configValues.fadeOpacity = makeShared("plugin:hyprfocus:fade_opacity", "fade opacity", 0.8F, Config::Values::SFloatValueOptions{.min = 0.F, .max = 1.F} ); configValues.slideHeight = makeShared("plugin:hyprfocus:slide_height", "slide height", 20.F, Config::Values::SFloatValueOptions{.min = 0.F, .max = 150.F} ); configValues.bounceStrength = makeShared("plugin:hyprfocus:bounce_strength", "bounce strength", 0.95F, Config::Values::SFloatValueOptions{.min = 0.F, .max = 1.F} ); HyprlandAPI::addConfigValueV2(PHANDLE, configValues.mode); HyprlandAPI::addConfigValueV2(PHANDLE, configValues.onlyOnMonitorChange); HyprlandAPI::addConfigValueV2(PHANDLE, configValues.fadeOpacity); HyprlandAPI::addConfigValueV2(PHANDLE, configValues.slideHeight); HyprlandAPI::addConfigValueV2(PHANDLE, configValues.bounceStrength); // this will not be cleaned up after we are unloaded but it doesn't really matter, // as if we create this again it will just overwrite the old one. Config::animationTree()->m_animationTree.createNode("hyprfocusIn", "windowsIn"); Config::animationTree()->m_animationTree.createNode("hyprfocusOut", "windowsOut"); return {"hyprfocus", "Flashfocus for Hyprland", "Vaxry", "1.0"}; } APICALL EXPORT void PLUGIN_EXIT() { // reset the callbacks to avoid crashes for (const auto& w : g_pCompositor->m_windows) { if (!validMapped(w)) continue; w->m_realSize->setCallbackOnEnd(nullptr); w->m_realPosition->setCallbackOnEnd(nullptr); w->alpha(Desktop::View::WINDOW_ALPHA_ACTIVE)->setCallbackOnEnd(nullptr); } } hyprwm-hyprland-plugins-3ba8bfb/hyprfocus/meson.build000066400000000000000000000016211520105331200232630ustar00rootroot00000000000000project('hyprfocus', 'cpp', version: '0.1', default_options: ['buildtype=release'], ) cpp_compiler = meson.get_compiler('cpp') if cpp_compiler.has_argument('-std=c++23') add_global_arguments('-std=c++23', language: 'cpp') elif cpp_compiler.has_argument('-std=c++2b') add_global_arguments('-std=c++2b', language: 'cpp') else error('Could not configure current C++ compiler (' + cpp_compiler.get_id() + ' ' + cpp_compiler.version() + ') with required C++ standard (C++23)') endif globber = run_command('find', '.', '-name', '*.cpp', check: true) src = globber.stdout().strip().split('\n') shared_module(meson.project_name(), src, dependencies: [ dependency('hyprland'), dependency('libdrm'), dependency('libinput'), dependency('libudev'), dependency('pangocairo'), dependency('pixman-1'), dependency('wayland-server'), dependency('xkbcommon'), ], install: true, ) hyprwm-hyprland-plugins-3ba8bfb/hyprpm.toml000066400000000000000000000125751520105331200213250ustar00rootroot00000000000000[repository] name = "hyprland-plugins" authors = ["Vaxry"] commit_pins = [ ["3bb9c7c5cf4f2ee30bf821501499f2308d616f94", "efee74a7404495dbda70205824d6e9fc923ccdae"], ["d74607e414dcd16911089a6d4b6aeb661c880923", "efee74a7404495dbda70205824d6e9fc923ccdae"], ["03ebbe18ed8517ee22591eac82cd54322f42cb7d", "f7853b9cc6aab627b37b7be6575628e788ad6d1d"], ["84ab8d11e8951a6551d1e1bf87796a8589da6d47", "8af29f09c5b132d5087c2931fe9bd34f63923ba1"], ["1c460e98f870676b15871fe4e5bfeb1a32a3d6d8", "f99822818ec8276cfd6ec99ab60c4708c9884e3d"], ["c5e28ebcfe00a510922779b2c568cfa52a317445", "4c9d83b981ad4668b89b8a3dc24d6f3ea7ad08fd"], # 0.37.0 ["19c90048d65a5660384d2fb865926a366696d6be", "4c9d83b981ad4668b89b8a3dc24d6f3ea7ad08fd"], # 0.37.1 ["3875679755014997776e091ff8903acfb311dd2f", "e45066d0741a1a4b9298a4c5ec43a5e57b059a4e"], # 0.38.0 ["360ede79d124ffdeebbe8401f1ac4bc0dbec2c91", "e45066d0741a1a4b9298a4c5ec43a5e57b059a4e"], # 0.38.1 ["e93fbd7c4f991cb8ef03e433ccc4d43587923e15", "e9457e08ca3ff16dc5a815be62baf9e18b539197"], # 0.39.0 ["fe7b748eb668136dd0558b7c8279bfcd7ab4d759", "e9457e08ca3ff16dc5a815be62baf9e18b539197"], # 0.39.1 ["cba1ade848feac44b2eda677503900639581c3f4", "18daf37b7c4e6e51ca2bf8953ce4cff1c38ca725"], # 0.40.0 ["ea2501d4556f84d3de86a4ae2f4b22a474555b9f", "8571aa9badf7db9c4911018a5611c038cc776256"], # 0.41.0 ["9e781040d9067c2711ec2e9f5b47b76ef70762b3", "8571aa9badf7db9c4911018a5611c038cc776256"], # 0.41.1 ["918d8340afd652b011b937d29d5eea0be08467f5", "135de7b88649dbe5fea8c997447bdc9d6f15ad86"], # 0.41.2 ["9a09eac79b85c846e3a865a9078a3f8ff65a9259", "4fcb4038f23e5273af9a5684f3ee10b0652b3bab"], # 0.42.0 ["0f594732b063a90d44df8c5d402d658f27471dfe", "b73d7b901d8cb1172dd25c7b7159f0242c625a77"], # 0.43.0 ["0c7a7e2d569eeed9d6025f3eef4ea0690d90845d", "9215288eb2ded9d0c08d468ea90ba68f43162c67"], # 0.44.0 ["4520b30d498daca8079365bdb909a8dea38e8d55", "9215288eb2ded9d0c08d468ea90ba68f43162c67"], # 0.44.1 ["a425fbebe4cf4238e48a42f724ef2208959d66cf", "44859f877739c05d031fcab4a2991ec004fa9bc4"], # 0.45.0 ["500d2a3580388afc8b620b0a3624147faa34f98b", "344a69db96fa8c6dc3b8f1f8f5a75f6eb441cbf2"], # 0.45.1 ["12f9a0d0b93f691d4d9923716557154d74777b0a", "344a69db96fa8c6dc3b8f1f8f5a75f6eb441cbf2"], # 0.45.2 ["788ae588979c2a1ff8a660f16e3c502ef5796755", "17ef806444fee729d00b3ba5cb8c623b7fbb699b"], # 0.46.0 ["254fc2bc6000075f660b4b8ed818a6af544d1d64", "17ef806444fee729d00b3ba5cb8c623b7fbb699b"], # 0.46.1 ["0bd541f2fd902dbfa04c3ea2ccf679395e316887", "17ef806444fee729d00b3ba5cb8c623b7fbb699b"], # 0.46.2 ["04ac46c54357278fc68f0a95d26347ea0db99496", "3e51162d83b0cd9ee35acbd3b91e6d7ba856f5eb"], # 0.47.0 ["75dff7205f6d2bd437abfb4196f700abee92581a", "3e51162d83b0cd9ee35acbd3b91e6d7ba856f5eb"], # 0.47.1 ["5ee35f914f921e5696030698e74fb5566a804768", "1f332c09a2382cb23da0f69a6f504f8b33433831"], # 0.48.0 ["29e2e59fdbab8ed2cc23a20e3c6043d5decb5cdc", "1f332c09a2382cb23da0f69a6f504f8b33433831"], # 0.48.1 ["9958d297641b5c84dcff93f9039d80a5ad37ab00", "c491d2831448645f24a1597a17f564aa52691ac6"], # 0.49.0 ["c4a4c341568944bd4fb9cd503558b2de602c0213", "bf310cda4a09b79725c2919688881959ebf3229e"], # 0.50.0 ["4e242d086e20b32951fdc0ebcbfb4d41b5be8dcc", "bf310cda4a09b79725c2919688881959ebf3229e"], # 0.50.1 ["46174f78b374b6cea669c48880877a8bdcf7802f", "a5a6f93d72d5fb37e78b98c756cfd8b340e71a19"], # 0.51.0 ["71a1216abcc7031776630a6d88f105605c4dc1c9", "a5a6f93d72d5fb37e78b98c756cfd8b340e71a19"], # 0.51.1 ["f56ec180d3a03a5aa978391249ff8f40f949fb73", "8c1212e96b81aa5f11fe21ca27defa2aad5b3cf3"], # 0.52.0 ["967c3c7404d4fa00234e29c70df3e263386d2597", "8c1212e96b81aa5f11fe21ca27defa2aad5b3cf3"], # 0.52.1 ["386376400119dd46a767c9f8c8791fd22c7b6e61", "8c1212e96b81aa5f11fe21ca27defa2aad5b3cf3"], # 0.52.2 ["ea444c35bb23b6e34505ab6753e069de7801cc25", "64b7c2dff7e5e1fcb4cb7e5db078947744070e1a"], # 0.53.0 ["ab1d80f3d6aebd57a0971b53a1993b1c1dfe0b09", "64b7c2dff7e5e1fcb4cb7e5db078947744070e1a"], # 0.53.1 ["39f3feddbee4a66be9608ed1eb7e73878d596b50", "64b7c2dff7e5e1fcb4cb7e5db078947744070e1a"], # 0.53.2 ["dd220efe7b1e292415bd0ea7161f63df9c95bfd3", "64b7c2dff7e5e1fcb4cb7e5db078947744070e1a"], # 0.53.3 ["0002f148c9a4fe421a9d33c0faa5528cdc411e62", "6acc0738f298f5efe40a99db2c12449112d65633"], # 0.54.0 ["4b07770b9ef1cceb2e6f56d33538aaffb9186b9c", "6acc0738f298f5efe40a99db2c12449112d65633"], # 0.54.1 ["59f9f2688ac508a0584d1462151195a6c4992f99", "6acc0738f298f5efe40a99db2c12449112d65633"], # 0.54.2 ["521ece463c4a9d3d128670688a34756805a4328f", "6acc0738f298f5efe40a99db2c12449112d65633"], # 0.54.3 ["af923e30d1d24f1f4a4f5cb8308065173c1d9539", "3aa21f2e0ca72412f1b434c3126f8f1fec3c716c"] # 0.55.0 ] [borders-plus-plus] description = "A plugin to add more borders to windows." authors = ["Vaxry"] output = "borders-plus-plus/borders-plus-plus.so" build = [ "make -C borders-plus-plus all", ] [csgo-vulkan-fix] description = "A plugin to fix incorrect mouse offsets on csgo in Vulkan" authors = ["Vaxry"] output = "csgo-vulkan-fix/csgo-vulkan-fix.so" build = [ "make -C csgo-vulkan-fix all", ] [hyprbars] description = "A plugin to add title bars to windows" authors = ["Vaxry"] output = "hyprbars/hyprbars.so" build = [ "make -C hyprbars all", ] [hyprfocus] description = "Flashfocus for Hyprland" authors = ["Vaxry"] output = "hyprfocus/hyprfocus.so" build = [ "make -C hyprfocus all", ] since_hyprland = 6066