mirror of
https://git.allpurposem.at/mat/WiggleWobble.git
synced 2025-12-23 21:11:29 +01:00
Initial Commit
This commit is contained in:
commit
673c9e995a
65
.clang-format
Normal file
65
.clang-format
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
---
|
||||||
|
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
|
||||||
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
compile_flags.txt
|
||||||
|
obj/
|
||||||
72
Makefile
Normal file
72
Makefile
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
# compile with HYPRLAND_HEADERS=<path_to_hl> make all
|
||||||
|
# make sure that the path above is to the root hl repo directory, NOT src/
|
||||||
|
# and that you have ran `make protocols` in the hl dir.
|
||||||
|
|
||||||
|
# This Makefile is not intended to be used directly, but rather as a template for your own plugin
|
||||||
|
# Change the PLUGIN_NAME variable to the name of your plugin
|
||||||
|
PLUGIN_NAME=example
|
||||||
|
|
||||||
|
# Enable parallel builds
|
||||||
|
MAKEFLAGS := --jobs=$(shell nproc)
|
||||||
|
MAKEFLAGS += --output-sync=target
|
||||||
|
|
||||||
|
# Source files
|
||||||
|
SOURCE_FILES=$(wildcard src/*.cpp)
|
||||||
|
# Add any new source file directories to the SOURCE_FILES variable
|
||||||
|
# SOURCE_FILES+=<new_source_dir>/*.cpp
|
||||||
|
|
||||||
|
# Header files, used to check if they have changed
|
||||||
|
INCLUDE_FILES=$(wildcard include/*.hpp)
|
||||||
|
INCLUDE_FILES+=$(wildcard include/*.h)
|
||||||
|
# Add any new header file directories to the INCLUDE_FILES variable
|
||||||
|
# INCLUDE_FILES+=<new_header_dir>/*.hpp
|
||||||
|
|
||||||
|
# Intermediate object files
|
||||||
|
OBJECT_DIR=obj
|
||||||
|
|
||||||
|
# Compiler flags
|
||||||
|
COMPILE_FLAGS=-g -fPIC --no-gnu-unique -std=c++23
|
||||||
|
COMPILE_FLAGS+=-I "/usr/include/pixman-1"
|
||||||
|
COMPILE_FLAGS+=-I "/usr/include/libdrm"
|
||||||
|
COMPILE_FLAGS+=-I "${HYPRLAND_HEADERS}"
|
||||||
|
COMPILE_FLAGS+=-I "${HYPRLAND_HEADERS}/subprojects/wlroots/include"
|
||||||
|
COMPILE_FLAGS+=-I "${HYPRLAND_HEADERS}/subprojects/wlroots/build/include"
|
||||||
|
COMPILE_FLAGS+=-Iinclude
|
||||||
|
|
||||||
|
# Linker flags, set to shared library (plugin)
|
||||||
|
LINK_FLAGS=-shared
|
||||||
|
|
||||||
|
# Phony targets (i.e. targets that don't actually build anything, and don't track dependencies)
|
||||||
|
# These will always be run when called
|
||||||
|
.PHONY: clean clangd
|
||||||
|
|
||||||
|
# build
|
||||||
|
all: check_env $(PLUGIN_NAME).so
|
||||||
|
|
||||||
|
# install to ~/.local/share/hyprload/plugins/bin, assuming that hyprload is installed
|
||||||
|
install: all
|
||||||
|
cp $(PLUGIN_NAME).so ${HOME}/.local/share/hyprload/plugins/bin
|
||||||
|
|
||||||
|
# ensure that HYPRLAND_HEADERS is set, otherwise error. Gives a more helpful error message than just include errors
|
||||||
|
check_env:
|
||||||
|
mkdir -p $(OBJECT_DIR)
|
||||||
|
ifndef HYPRLAND_HEADERS
|
||||||
|
$(error HYPRLAND_HEADERS is undefined! Please set it to the path to the root of the configured Hyprland repo)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# build the plugin, using the headers from the configured Hyprland repo
|
||||||
|
$(OBJECT_DIR)/%.o: src/%.cpp $(INCLUDE_FILES)
|
||||||
|
g++ -c -o $@ $< $(COMPILE_FLAGS)
|
||||||
|
|
||||||
|
$(PLUGIN_NAME).so: $(addprefix $(OBJECT_DIR)/, $(notdir $(SOURCE_FILES:.cpp=.o)))
|
||||||
|
g++ $(LINK_FLAGS) -o $@ $^ $(COMPILE_FLAGS)
|
||||||
|
|
||||||
|
# clean up
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJECT_DIR)/*.o
|
||||||
|
rm -f ./$(PLUGIN_NAME).so
|
||||||
|
|
||||||
|
# generate compile_flags.txt for clangd, if you use it. This is not necessary for building the plugin
|
||||||
|
# the alternative is to use the compile_commands.json file generated by eg. bear
|
||||||
|
clangd:
|
||||||
|
echo "$(COMPILE_FLAGS)" | sed 's/ -/\n-/g' | sed 's/--no-gnu-unique//g' | sed 's/-I \//-I\//g' | sed 's/std=c++23/std=c++2b/g' > compile_flags.txt
|
||||||
92
README.md
Normal file
92
README.md
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
# Hyprland Plugin Template
|
||||||
|
The goal of this repository is to create a robust `Hyprland` plugin template, with
|
||||||
|
- A working, extensible `Makefile`
|
||||||
|
- [`hyprload`](https://github.com/Duckonaut/hyprload) support out of the box
|
||||||
|
- Environment set up guide
|
||||||
|
- Clangd flags set up for autocomplete and error checking
|
||||||
|
|
||||||
|
It is highly recommended to read the [Plugin development](https://wiki.hyprland.org/Plugins/Development/Getting-Started/)
|
||||||
|
section of the Hyprland Wiki first. Some stuff will be different in this template, but it gives
|
||||||
|
you a general idea about what's going on
|
||||||
|
|
||||||
|
## Support
|
||||||
|
If you have any issues setting this up, open an issue in this repository. I will try to help.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
This is a github template repository. To use it, use the green **Use this template** button
|
||||||
|
at the top of the repository file view.
|
||||||
|
|
||||||
|
### Setting up a development environment
|
||||||
|
#### Text editor and autocompletion
|
||||||
|
For a code editor, I recommend VS Code or Neovim, but anything that can use Clangd will work
|
||||||
|
If you use Clangd, `make clangd` will generate a simple `compile_flags.txt` file with the proper
|
||||||
|
include paths and flags, which will make Clangd recognize the includes etc.
|
||||||
|
|
||||||
|
> **Warning**: Compiling the plugin should still be done using GCC 12+. Clang does not properly
|
||||||
|
> build Hyprland, and is very fussy about the hook system. You will most likely encounter errors
|
||||||
|
> like `cannot cast from type 'void (CCompositor::*)(CWindow *, wlr_surface *)' to pointer type 'void *'`
|
||||||
|
> This won't happen when building with GCC and can be ignored.
|
||||||
|
|
||||||
|
#### HYPRLAND_HEADERS
|
||||||
|
The most important part of setting up plugin builds is the `HYPRLAND_HEADERS` variable.
|
||||||
|
Plugins can hook directly into Hyprland's C++ code, which is what makes them so powerful.
|
||||||
|
Because of that, they need to be able to *see* the Hyprland source. `HYPRLAND_HEADERS` ensures
|
||||||
|
that.
|
||||||
|
|
||||||
|
When building your own plugins for testing, you will need to manually define it using
|
||||||
|
`export HYPRLAND_HEADERS=(PATH_TO_HYPRLAND_SOURCE_ROOT)` before running `make` commands. You
|
||||||
|
can use a local path if you keep `Hyprland` source anyway, but I'd definitely recomment using
|
||||||
|
`hyprload`. If you use your local source different from the `hyprload` one, make sure to
|
||||||
|
run `make pluginenv` in the Hyprland folder.
|
||||||
|
|
||||||
|
And here, excuse me, but I will go on a tangent about why `hyprload` is great:
|
||||||
|
|
||||||
|
#### Hyprload, and why it's useful for plugin development
|
||||||
|
If you use `hyprload`, it will keep a copy of Hyprland source code up to date with the Hyprland
|
||||||
|
version you're running in `$HOME/.local/share/hyprload/hyprland`, and you can use that as your
|
||||||
|
`HYPRLAND_HEADERS` path.
|
||||||
|
|
||||||
|
When installing your plugin on other people's computers, `hyprload` will automatically define
|
||||||
|
`HYPRLAND_HEADERS` to that path to ensure maximum compatibility.
|
||||||
|
|
||||||
|
When developing plugins and frequently changing them, the `make install` command will
|
||||||
|
automatically place your plugin build in the directory `hyprload` automatically loads. You can
|
||||||
|
reload plugins when testing using the `hyprload,reload` dispatcher (bind it in your
|
||||||
|
`hyprland.conf`
|
||||||
|
|
||||||
|
#### Making it Your Own
|
||||||
|
To change your plugin name, version, and author (that's you!) there are 3 variables that need
|
||||||
|
changing (I would like to streamline it somehow, but it's manageable for now)
|
||||||
|
- `main.cpp`: The `PLUGIN_INIT` function returns a struct with the plugin name, description,
|
||||||
|
author and version. Change those.
|
||||||
|
- `Makefile`: At the top of the file, the variable `PLUGIN_NAME` contains the name of the plugin
|
||||||
|
`.so` that will be built. This should generally match your plugin name.
|
||||||
|
- `hyprload.toml`: The `[examplePlugin]` and `[examplePlugin.build]` should be changed to match
|
||||||
|
the name of your plugin. `hyprload` will look at these dictionaries for info about the plugin.
|
||||||
|
For more info, see [hyprload docs](https://github.com/Duckonaut/hyprload#format)
|
||||||
|
|
||||||
|
## Building and testing
|
||||||
|
After making sure you have defined `HYPRLAND_HEADERS` (you might need to do this *every time
|
||||||
|
you open a new terminal* if you don't put it in your `.bashrc` or `.zshrc` or whatever), the
|
||||||
|
steps to build are simple
|
||||||
|
|
||||||
|
### Manual way of doing things
|
||||||
|
- `make`: This will build the `PLUGIN_NAME.so` file.
|
||||||
|
- `hyprctl plugin unload $PWD/PLUGIN_NAME.so`: If you have an old version loaded, unload it
|
||||||
|
- `hyprctl plugin load $PWD/PLUGIN_NAME.so`: Load the plugin
|
||||||
|
|
||||||
|
### The `hyprload` way
|
||||||
|
This works rather well in nested Hyprland sessions, since `hyprload` keeps sessions separate.
|
||||||
|
- `make install`: This will build and copy the plugin to the `hyprload` plugin directory.
|
||||||
|
- Reload `hyprload` for the changes to take effect
|
||||||
|
|
||||||
|
### Nested Hyprland
|
||||||
|
Developing a plugin may be tough. You might crash Hyprland a couple times. For this reason,
|
||||||
|
it's a good idea to develop them in a nested Hyprland session. If you run `Hyprland` from an
|
||||||
|
existing Hyprland session, it'll open in a window. If this window crashes, it's pretty much fine!
|
||||||
|
Refer to the [Hyprland wiki](http://wiki.hyprland.org/Plugins/Development/Getting-Started/#setting-up-a-development-environment)
|
||||||
|
for more info.
|
||||||
|
|
||||||
|
## ""Publishing""
|
||||||
|
If you haven't messed up your `hyprload.toml` manifest too badly, anyone should be able to use
|
||||||
|
your plugin by just adding `'YOUR_GITHUB_NAME/YOUR_PLUGIN'` to their own `hyprload.toml` config!
|
||||||
29
include/customDecoration.hpp
Normal file
29
include/customDecoration.hpp
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define WLR_USE_UNSTABLE
|
||||||
|
|
||||||
|
#include <src/render/decorations/IHyprWindowDecoration.hpp>
|
||||||
|
|
||||||
|
class CCustomDecoration : public IHyprWindowDecoration {
|
||||||
|
public:
|
||||||
|
CCustomDecoration(CWindow*);
|
||||||
|
virtual ~CCustomDecoration();
|
||||||
|
|
||||||
|
virtual SWindowDecorationExtents getWindowDecorationExtents();
|
||||||
|
|
||||||
|
virtual void draw(CMonitor*, float a, const Vector2D& offset);
|
||||||
|
|
||||||
|
virtual eDecorationType getDecorationType();
|
||||||
|
|
||||||
|
virtual void updateWindow(CWindow*);
|
||||||
|
|
||||||
|
virtual void damageEntire();
|
||||||
|
|
||||||
|
private:
|
||||||
|
SWindowDecorationExtents m_seExtents;
|
||||||
|
|
||||||
|
CWindow* m_pWindow = nullptr;
|
||||||
|
|
||||||
|
Vector2D m_vLastWindowPos;
|
||||||
|
Vector2D m_vLastWindowSize;
|
||||||
|
};
|
||||||
32
include/customLayout.hpp
Normal file
32
include/customLayout.hpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define WLR_USE_UNSTABLE
|
||||||
|
|
||||||
|
#include <src/layout/IHyprLayout.hpp>
|
||||||
|
|
||||||
|
struct SWindowData {
|
||||||
|
CWindow* pWindow = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CHyprCustomLayout : public IHyprLayout {
|
||||||
|
public:
|
||||||
|
virtual void onWindowCreatedTiling(CWindow*);
|
||||||
|
virtual void onWindowRemovedTiling(CWindow*);
|
||||||
|
virtual bool isWindowTiled(CWindow*);
|
||||||
|
virtual void recalculateMonitor(const int&);
|
||||||
|
virtual void recalculateWindow(CWindow*);
|
||||||
|
virtual void resizeActiveWindow(const Vector2D&, CWindow* pWindow = nullptr);
|
||||||
|
virtual void fullscreenRequestForWindow(CWindow*, eFullscreenMode, bool);
|
||||||
|
virtual std::any layoutMessage(SLayoutMessageHeader, std::string);
|
||||||
|
virtual SWindowRenderLayoutHints requestRenderHints(CWindow*);
|
||||||
|
virtual void switchWindows(CWindow*, CWindow*);
|
||||||
|
virtual void alterSplitRatio(CWindow*, float, bool);
|
||||||
|
virtual std::string getLayoutName();
|
||||||
|
virtual void replaceWindowDataWith(CWindow* from, CWindow* to);
|
||||||
|
|
||||||
|
virtual void onEnable();
|
||||||
|
virtual void onDisable();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<SWindowData> m_vWindowData;
|
||||||
|
};
|
||||||
5
include/globals.hpp
Normal file
5
include/globals.hpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <src/plugins/PluginAPI.hpp>
|
||||||
|
|
||||||
|
inline HANDLE PHANDLE = nullptr;
|
||||||
74
src/customDecoration.cpp
Normal file
74
src/customDecoration.cpp
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#include "customDecoration.hpp"
|
||||||
|
#include <src/Window.hpp>
|
||||||
|
#include <src/Compositor.hpp>
|
||||||
|
#include "globals.hpp"
|
||||||
|
|
||||||
|
CCustomDecoration::CCustomDecoration(CWindow* pWindow) {
|
||||||
|
m_pWindow = pWindow;
|
||||||
|
m_vLastWindowPos = pWindow->m_vRealPosition.vec();
|
||||||
|
m_vLastWindowSize = pWindow->m_vRealSize.vec();
|
||||||
|
}
|
||||||
|
|
||||||
|
CCustomDecoration::~CCustomDecoration() {
|
||||||
|
damageEntire();
|
||||||
|
}
|
||||||
|
|
||||||
|
SWindowDecorationExtents CCustomDecoration::getWindowDecorationExtents() {
|
||||||
|
return m_seExtents;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCustomDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& offset) {
|
||||||
|
if (!g_pCompositor->windowValidMapped(m_pWindow))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!m_pWindow->m_sSpecialRenderData.decorate)
|
||||||
|
return;
|
||||||
|
|
||||||
|
static auto* const PCOLOR = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:example:border_color")->intValue;
|
||||||
|
static auto* const PROUNDING = &HyprlandAPI::getConfigValue(PHANDLE, "decoration:rounding")->intValue;
|
||||||
|
static auto* const PBORDERSIZE = &HyprlandAPI::getConfigValue(PHANDLE, "general:border_size")->intValue;
|
||||||
|
|
||||||
|
const auto ROUNDING = !m_pWindow->m_sSpecialRenderData.rounding ?
|
||||||
|
0 :
|
||||||
|
(m_pWindow->m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_pWindow->m_sAdditionalConfigData.rounding.toUnderlying());
|
||||||
|
|
||||||
|
// draw the border
|
||||||
|
wlr_box fullBox = {(int)(m_vLastWindowPos.x - *PBORDERSIZE), (int)(m_vLastWindowPos.y - *PBORDERSIZE), (int)(m_vLastWindowSize.x + 2.0 * *PBORDERSIZE),
|
||||||
|
(int)(m_vLastWindowSize.y + 2.0 * *PBORDERSIZE)};
|
||||||
|
|
||||||
|
fullBox.x -= pMonitor->vecPosition.x;
|
||||||
|
fullBox.y -= pMonitor->vecPosition.y;
|
||||||
|
|
||||||
|
m_seExtents = {{m_vLastWindowPos.x - fullBox.x - pMonitor->vecPosition.x + 2, m_vLastWindowPos.y - fullBox.y - pMonitor->vecPosition.y + 2},
|
||||||
|
{fullBox.x + fullBox.width + pMonitor->vecPosition.x - m_vLastWindowPos.x - m_vLastWindowSize.x + 2,
|
||||||
|
fullBox.y + fullBox.height + pMonitor->vecPosition.y - m_vLastWindowPos.y - m_vLastWindowSize.y + 2}};
|
||||||
|
|
||||||
|
fullBox.x += offset.x;
|
||||||
|
fullBox.y += offset.y;
|
||||||
|
|
||||||
|
if (fullBox.width < 1 || fullBox.height < 1)
|
||||||
|
return; // don't draw invisible shadows
|
||||||
|
|
||||||
|
g_pHyprOpenGL->scissor((wlr_box*)nullptr);
|
||||||
|
|
||||||
|
scaleBox(&fullBox, pMonitor->scale);
|
||||||
|
g_pHyprOpenGL->renderBorder(&fullBox, CColor(*PCOLOR), *PROUNDING * pMonitor->scale + *PBORDERSIZE * 2, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
eDecorationType CCustomDecoration::getDecorationType() {
|
||||||
|
return DECORATION_CUSTOM;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCustomDecoration::updateWindow(CWindow* pWindow) {
|
||||||
|
|
||||||
|
m_vLastWindowPos = pWindow->m_vRealPosition.vec();
|
||||||
|
m_vLastWindowSize = pWindow->m_vRealSize.vec();
|
||||||
|
|
||||||
|
damageEntire();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCustomDecoration::damageEntire() {
|
||||||
|
wlr_box dm = {(int)(m_vLastWindowPos.x - m_seExtents.topLeft.x), (int)(m_vLastWindowPos.y - m_seExtents.topLeft.y),
|
||||||
|
(int)(m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x), (int)m_seExtents.topLeft.y};
|
||||||
|
g_pHyprRenderer->damageBox(&dm);
|
||||||
|
}
|
||||||
80
src/customLayout.cpp
Normal file
80
src/customLayout.cpp
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
#include "customLayout.hpp"
|
||||||
|
#include <src/Compositor.hpp>
|
||||||
|
#include "globals.hpp"
|
||||||
|
|
||||||
|
void CHyprCustomLayout::onWindowCreatedTiling(CWindow* pWindow) {
|
||||||
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
|
||||||
|
const auto SIZE = PMONITOR->vecSize;
|
||||||
|
|
||||||
|
// these are used for focus and move calculations, and are *required* to touch for moving focus to work properly.
|
||||||
|
pWindow->m_vPosition = Vector2D{(SIZE.x / 2.0) * (m_vWindowData.size() % 2), (SIZE.y / 2.0) * (int)(m_vWindowData.size() > 1)};
|
||||||
|
pWindow->m_vSize = SIZE / 2.0;
|
||||||
|
|
||||||
|
// this is the actual pos and size of the window (where it's rendered)
|
||||||
|
pWindow->m_vRealPosition = pWindow->m_vPosition + Vector2D{10, 10};
|
||||||
|
pWindow->m_vRealSize = pWindow->m_vSize - Vector2D{20, 20};
|
||||||
|
|
||||||
|
const auto PDATA = &m_vWindowData.emplace_back();
|
||||||
|
PDATA->pWindow = pWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprCustomLayout::onWindowRemovedTiling(CWindow* pWindow) {
|
||||||
|
std::erase_if(m_vWindowData, [&](const auto& other) { return other.pWindow == pWindow; });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CHyprCustomLayout::isWindowTiled(CWindow* pWindow) {
|
||||||
|
return std::find_if(m_vWindowData.begin(), m_vWindowData.end(), [&](const auto& other) { return other.pWindow == pWindow; }) != m_vWindowData.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprCustomLayout::recalculateMonitor(const int& eIdleInhibitMode) {
|
||||||
|
; // empty
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprCustomLayout::recalculateWindow(CWindow* pWindow) {
|
||||||
|
; // empty
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprCustomLayout::resizeActiveWindow(const Vector2D& delta, CWindow* pWindow) {
|
||||||
|
; // empty
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprCustomLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode mode, bool on) {
|
||||||
|
; // empty
|
||||||
|
}
|
||||||
|
|
||||||
|
std::any CHyprCustomLayout::layoutMessage(SLayoutMessageHeader header, std::string content) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
SWindowRenderLayoutHints CHyprCustomLayout::requestRenderHints(CWindow* pWindow) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprCustomLayout::switchWindows(CWindow* pWindowA, CWindow* pWindowB) {
|
||||||
|
; // empty
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprCustomLayout::alterSplitRatio(CWindow* pWindow, float delta, bool exact) {
|
||||||
|
; // empty
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CHyprCustomLayout::getLayoutName() {
|
||||||
|
return "custom";
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprCustomLayout::replaceWindowDataWith(CWindow* from, CWindow* to) {
|
||||||
|
; // empty
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprCustomLayout::onEnable() {
|
||||||
|
for (auto& w : g_pCompositor->m_vWindows) {
|
||||||
|
if (w->isHidden() || !w->m_bIsMapped || w->m_bFadingOut || w->m_bIsFloating)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
onWindowCreatedTiling(w.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHyprCustomLayout::onDisable() {
|
||||||
|
m_vWindowData.clear();
|
||||||
|
}
|
||||||
95
src/main.cpp
Normal file
95
src/main.cpp
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#define WLR_USE_UNSTABLE
|
||||||
|
|
||||||
|
#include "globals.hpp"
|
||||||
|
|
||||||
|
#include <src/Window.hpp>
|
||||||
|
#include <src/Compositor.hpp>
|
||||||
|
#include "customLayout.hpp"
|
||||||
|
#include "customDecoration.hpp"
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
inline std::unique_ptr<CHyprCustomLayout> g_pCustomLayout;
|
||||||
|
inline CFunctionHook* g_pFocusHook = nullptr;
|
||||||
|
inline CFunctionHook* g_pMotionHook = nullptr;
|
||||||
|
inline CFunctionHook* g_pMouseDownHook = nullptr;
|
||||||
|
typedef void (*origFocusWindow)(void*, CWindow*, wlr_surface*);
|
||||||
|
typedef void (*origMotion)(wlr_seat*, uint32_t, double, double);
|
||||||
|
typedef void (*origMouseDownNormal)(void*, wlr_pointer_button_event*);
|
||||||
|
|
||||||
|
// Do NOT change this function.
|
||||||
|
APICALL EXPORT std::string PLUGIN_API_VERSION() {
|
||||||
|
return HYPRLAND_API_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void onActiveWindowChange(void* self, std::any data) {
|
||||||
|
try {
|
||||||
|
auto* const PWINDOW = std::any_cast<CWindow*>(data);
|
||||||
|
|
||||||
|
HyprlandAPI::addNotification(PHANDLE, "[ExamplePlugin] Active window: " + (PWINDOW ? PWINDOW->m_szTitle : "None"), CColor{0.f, 0.5f, 1.f, 1.f}, 5000);
|
||||||
|
} catch (std::bad_any_cast& e) { HyprlandAPI::addNotification(PHANDLE, "[ExamplePlugin] Active window: None", CColor{0.f, 0.5f, 1.f, 1.f}, 5000); }
|
||||||
|
}
|
||||||
|
|
||||||
|
static void onNewWindow(void* self, std::any data) {
|
||||||
|
auto* const PWINDOW = std::any_cast<CWindow*>(data);
|
||||||
|
|
||||||
|
HyprlandAPI::addWindowDecoration(PHANDLE, PWINDOW, new CCustomDecoration(PWINDOW));
|
||||||
|
}
|
||||||
|
|
||||||
|
void hkFocusWindow(void* thisptr, CWindow* pWindow, wlr_surface* pSurface) {
|
||||||
|
// HyprlandAPI::addNotification(PHANDLE, getFormat("FocusWindow with %lx %lx", pWindow, pSurface), CColor{0.f, 1.f, 1.f, 1.f}, 5000);
|
||||||
|
(*(origFocusWindow)g_pFocusHook->m_pOriginal)(thisptr, pWindow, pSurface);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hkNotifyMotion(wlr_seat* wlr_seat, uint32_t time_msec, double sx, double sy) {
|
||||||
|
// HyprlandAPI::addNotification(PHANDLE, getFormat("NotifyMotion with %lf %lf", sx, sy), CColor{0.f, 1.f, 1.f, 1.f}, 5000);
|
||||||
|
(*(origMotion)g_pMotionHook->m_pOriginal)(wlr_seat, time_msec, sx, sy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hkProcessMouseDownNormal(void* thisptr, wlr_pointer_button_event* e) {
|
||||||
|
// HyprlandAPI::addNotification(PHANDLE, "Mouse down normal!", CColor{0.8f, 0.2f, 0.5f, 1.0f}, 5000);
|
||||||
|
(*(origMouseDownNormal)g_pMouseDownHook->m_pOriginal)(thisptr, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
||||||
|
PHANDLE = handle;
|
||||||
|
|
||||||
|
HyprlandAPI::addNotification(PHANDLE, "Hello World from an example plugin!", CColor{0.f, 1.f, 1.f, 1.f}, 5000);
|
||||||
|
|
||||||
|
HyprlandAPI::registerCallbackDynamic(PHANDLE, "activeWindow", [&](void* self, std::any data) { onActiveWindowChange(self, data); });
|
||||||
|
HyprlandAPI::registerCallbackDynamic(PHANDLE, "openWindow", [&](void* self, std::any data) { onNewWindow(self, data); });
|
||||||
|
|
||||||
|
g_pCustomLayout = std::make_unique<CHyprCustomLayout>();
|
||||||
|
|
||||||
|
HyprlandAPI::addLayout(PHANDLE, "custom", g_pCustomLayout.get());
|
||||||
|
|
||||||
|
HyprlandAPI::addConfigValue(PHANDLE, "plugin:example:border_color", SConfigValue{.intValue = configStringToInt("rgb(44ee44)")});
|
||||||
|
|
||||||
|
HyprlandAPI::addDispatcher(PHANDLE, "example", [](std::string arg) { HyprlandAPI::addNotification(PHANDLE, "Arg passed: " + arg, CColor{0.5f, 0.5f, 0.7f, 1.0f}, 5000); });
|
||||||
|
|
||||||
|
// Hook a public member
|
||||||
|
g_pFocusHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CCompositor::focusWindow, (void*)&hkFocusWindow);
|
||||||
|
// Hook a public non-member
|
||||||
|
g_pMotionHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&wlr_seat_pointer_notify_motion, (void*)&hkNotifyMotion);
|
||||||
|
// Hook a private member
|
||||||
|
static const auto METHODS = HyprlandAPI::findFunctionsByName(PHANDLE, "processMouseDownNormal");
|
||||||
|
g_pMouseDownHook = HyprlandAPI::createFunctionHook(PHANDLE, METHODS[0].address, (void*)&hkProcessMouseDownNormal);
|
||||||
|
|
||||||
|
// fancy notifications
|
||||||
|
HyprlandAPI::addNotificationV2(PHANDLE, {{"text", "Example hint"}, {"time", (uint64_t)10000}, {"color", CColor(0.2, 0.2, 0.9, 1.0)}, {"icon", ICON_HINT}});
|
||||||
|
|
||||||
|
// Enable our hooks
|
||||||
|
g_pFocusHook->hook();
|
||||||
|
g_pMotionHook->hook();
|
||||||
|
g_pMouseDownHook->hook();
|
||||||
|
|
||||||
|
HyprlandAPI::reloadConfig();
|
||||||
|
|
||||||
|
return {"ExamplePlugin", "An example plugin", "Vaxry", "1.0"};
|
||||||
|
}
|
||||||
|
|
||||||
|
APICALL EXPORT void PLUGIN_EXIT() {
|
||||||
|
HyprlandAPI::invokeHyprctlCommand("seterror", "disable");
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user