init: WiggleWobble

This commit is contained in:
Matias 2025-06-16 13:27:18 +02:00
parent 15602acda6
commit 4840855ee0
No known key found for this signature in database
GPG Key ID: ED35A6AC65A06B69
14 changed files with 263 additions and 343 deletions

1
.envrc Normal file
View File

@ -0,0 +1 @@
use flake

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
compile_flags.txt compile_flags.txt
compile_commands.json compile_commands.json
/.direnv
/build /build

View File

@ -1,25 +1,4 @@
# Hyprland Plugin Template # WiggleWobble - Wobbly windows for Hyprland
This is a fork of [hyprland-community/hyprland-plugin-template](https://github.com/hyprland-community/hyprland-plugin-template/fork),
with more opinionated build tools (meson and optionally nix).
The goal of this repository is to create a robust `Hyprland` plugin template, with
- nix
- A working, extensible `meson.build`
- [`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 ### Setting up a development environment
@ -41,20 +20,6 @@ Run this command to setup the build directory and generate a **clangd** compatib
meson setup build && sed -e 's/c++23/c++2b/g' ./build/compile_commands.json > ./compile_commands.json meson setup build && sed -e 's/c++23/c++2b/g' ./build/compile_commands.json > ./compile_commands.json
``` ```
#### Making it Your Own
To change your plugin name, version, and author (that's you!) there are a few things 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.
- `meson.build`: At the top of the file, the project name `example` should be changed.
- `src/meson.build`: The name of the `shared_library` (first argument) should be changed. The
resulting library will be changed to `build/src/libYOUR_PLUGIN.so` so you should change the
`[examplePlugin.build.output]` entry as well
- `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)
- `plugin.nix`: Change `pname` and the `meta` section.
## Building and testing ## Building and testing
After `nix develop`, the steps to build are simple After `nix develop`, the steps to build are simple
@ -77,24 +42,9 @@ Do note that if you only load/unload from the same path, Hyprland can ignore you
You don't need this that often for development but you can build directly without `nix develop` You don't need this that often for development but you can build directly without `nix develop`
with `nix build`. with `nix build`.
### Using `hyprload`
TODO: update
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
This doesn't have the issue of ignoring changes, because of how `hyprload` handles its loaded
plugins.
### Nested Hyprland ### Nested Hyprland
Developing a plugin may be tough. You might crash Hyprland a couple times. For this reason, 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 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! 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) Refer to the [Hyprland wiki](http://wiki.hyprland.org/Plugins/Development/Getting-Started/#setting-up-a-development-environment)
for more info. 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!

View File

@ -20,11 +20,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1734906446, "lastModified": 1747864449,
"narHash": "sha256-6OWluVE2A8xi+8V3jN9KA72RCgJjYdyyuLBUjxZ2q2U=", "narHash": "sha256-PIjVAWghZhr3L0EFM2UObhX84UQxIACbON0IC0zzSKA=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "aquamarine", "repo": "aquamarine",
"rev": "eecb74dc79bb6752a2a507e6edee3042390a6091", "rev": "389372c5f4dc1ac0e7645ed29a35fd6d71672ef5",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -87,11 +87,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1734906540, "lastModified": 1745948457,
"narHash": "sha256-vQ/L9hZFezC0LquLo4TWXkyniWtYBlFHAKIsDc7PYJE=", "narHash": "sha256-lzTV10FJTCGNtMdgW5YAhCAqezeAzKOd/97HbQK8GTU=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprcursor", "repo": "hyprcursor",
"rev": "69270ba8f057d55b0e6c2dca0e165d652856e613", "rev": "ac903e80b33ba6a88df83d02232483d99f327573",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -116,11 +116,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1734906236, "lastModified": 1745015490,
"narHash": "sha256-vH/ysV2ONGQgYZPtcJKwc8jJivzyVxru2aaOxC20ZOE=", "narHash": "sha256-apEJ9zoSzmslhJ2vOKFcXTMZLUFYzh1ghfB6Rbw3Low=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprgraphics", "repo": "hyprgraphics",
"rev": "6dea3fba08fd704dd624b6d4b261638fb4003c9c", "rev": "60754910946b4e2dc1377b967b7156cb989c5873",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -145,11 +145,11 @@
"xdph": "xdph" "xdph": "xdph"
}, },
"locked": { "locked": {
"lastModified": 1735585949, "lastModified": 1748696522,
"narHash": "sha256-0nT9kNyyQlhpMHakQLyINZoJAjRAui4WsbxrRev6Gwc=", "narHash": "sha256-YnKypsotSvrJEEHo+DQQkgtzfBwFmGqtkz3J6c0gw74=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "Hyprland", "repo": "Hyprland",
"rev": "1989b0049f7fb714a2417dfb14d6b4f3d2a079d3", "rev": "4078e1d17c0fb1439ee5a0ba1e539f06a8f47aab",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -170,11 +170,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1728345020, "lastModified": 1743714874,
"narHash": "sha256-xGbkc7U/Roe0/Cv3iKlzijIaFBNguasI31ynL2IlEoM=", "narHash": "sha256-yt8F7NhMFCFHUHy/lNjH/pjZyIDFNk52Q4tivQ31WFo=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprland-protocols", "repo": "hyprland-protocols",
"rev": "a7c183800e74f337753de186522b9017a07a8cee", "rev": "3a5c2bda1c1a4e55cc1330c782547695a93f05b2",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -183,10 +183,49 @@
"type": "github" "type": "github"
} }
}, },
"hyprland-qt-support": {
"inputs": {
"hyprlang": [
"hyprland",
"hyprland-qtutils",
"hyprlang"
],
"nixpkgs": [
"hyprland",
"hyprland-qtutils",
"nixpkgs"
],
"systems": [
"hyprland",
"hyprland-qtutils",
"systems"
]
},
"locked": {
"lastModified": 1737634706,
"narHash": "sha256-nGCibkfsXz7ARx5R+SnisRtMq21IQIhazp6viBU8I/A=",
"owner": "hyprwm",
"repo": "hyprland-qt-support",
"rev": "8810df502cdee755993cb803eba7b23f189db795",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprland-qt-support",
"type": "github"
}
},
"hyprland-qtutils": { "hyprland-qtutils": {
"inputs": { "inputs": {
"hyprland-qt-support": "hyprland-qt-support",
"hyprlang": [
"hyprland",
"hyprlang"
],
"hyprutils": [ "hyprutils": [
"hyprland", "hyprland",
"hyprland-qtutils",
"hyprlang",
"hyprutils" "hyprutils"
], ],
"nixpkgs": [ "nixpkgs": [
@ -199,11 +238,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1734906472, "lastModified": 1745951494,
"narHash": "sha256-pWPRv/GA/X/iAwoE6gMNUqn/ZeJX1IeLPRpZI0tTPK0=", "narHash": "sha256-2dModE32doiyQMmd6EDAQeZnz+5LOs6KXyE0qX76WIg=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprland-qtutils", "repo": "hyprland-qtutils",
"rev": "c77109d7e1ddbcdb87cafd32ce411f76328ae152", "rev": "4be1d324faf8d6e82c2be9f8510d299984dfdd2e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -228,11 +267,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1734906259, "lastModified": 1747484975,
"narHash": "sha256-P79t/7HbACO4/PuJBroGpTptvCWJtXTv+gWsF+sM6MI=", "narHash": "sha256-+LAQ81HBwG0lwshHlWe0kfWg4KcChIPpnwtnwqmnoEU=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprlang", "repo": "hyprlang",
"rev": "0404833ea18d543df44df935ebf1b497310eb046", "rev": "163c83b3db48a17c113729c220a60b94596c9291",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -253,11 +292,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1735316583, "lastModified": 1746635225,
"narHash": "sha256-AiiUwHWHfEdpFzXy7l1x3zInCUa1xcRMrbZ1XRSkzwU=", "narHash": "sha256-W9G9bb0zRYDBRseHbVez0J8qVpD5QbizX67H/vsudhM=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprutils", "repo": "hyprutils",
"rev": "8f15d45b120b33712f6db477fe5ffb18034d0ea8", "rev": "674ea57373f08b7609ce93baff131117a0dfe70d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -278,11 +317,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1734793513, "lastModified": 1747584298,
"narHash": "sha256-rrrHcXapXJvGFqX+L/Bb0182L25jofAZ0fm1FInvrTQ=", "narHash": "sha256-PH9qZqWLHvSBQiUnA0NzAyQA3tu2no2z8kz0ZeHWj4w=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprwayland-scanner", "repo": "hyprwayland-scanner",
"rev": "4d7367b6eee87397e2dbca2e78078dd0a4ef4c61", "rev": "e511882b9c2e1d7a75d45d8fddd2160daeafcbc3",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -293,11 +332,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1735291276, "lastModified": 1748460289,
"narHash": "sha256-NYVcA06+blsLG6wpAbSPTCyLvxD/92Hy4vlY9WxFI1M=", "narHash": "sha256-7doLyJBzCllvqX4gszYtmZUToxKvMUrg45EUWaUYmBg=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "634fd46801442d760e09493a794c4f15db2d0cbb", "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -307,22 +346,6 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs-stable": {
"locked": {
"lastModified": 1730741070,
"narHash": "sha256-edm8WG19kWozJ/GqyYx2VjW99EdhjKwbY3ZwdlPAAlo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d063c1dd113c91ab27959ba540c0d9753409edf3",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-24.05",
"repo": "nixpkgs",
"type": "github"
}
},
"pre-commit-hooks": { "pre-commit-hooks": {
"inputs": { "inputs": {
"flake-compat": "flake-compat", "flake-compat": "flake-compat",
@ -330,15 +353,14 @@
"nixpkgs": [ "nixpkgs": [
"hyprland", "hyprland",
"nixpkgs" "nixpkgs"
], ]
"nixpkgs-stable": "nixpkgs-stable"
}, },
"locked": { "locked": {
"lastModified": 1734797603, "lastModified": 1747372754,
"narHash": "sha256-ulZN7ps8nBV31SE+dwkDvKIzvN6hroRY8sYOT0w+E28=", "narHash": "sha256-2Y53NGIX2vxfie1rOW0Qb86vjRZ7ngizoo+bnXU9D9k=",
"owner": "cachix", "owner": "cachix",
"repo": "git-hooks.nix", "repo": "git-hooks.nix",
"rev": "f0f0dc4920a903c3e08f5bdb9246bb572fcae498", "rev": "80479b6ec16fefd9c1db3ea13aeb038c60530f46",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -395,11 +417,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1734907020, "lastModified": 1745871725,
"narHash": "sha256-p6HxwpRKVl1KIiY5xrJdjcEeK3pbmc///UOyV6QER+w=", "narHash": "sha256-M24SNc2flblWGXFkGQfqSlEOzAGZnMc9QG3GH4K/KbE=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland", "repo": "xdg-desktop-portal-hyprland",
"rev": "d7f18dda5e511749fa1511185db3536208fb1a63", "rev": "76bbf1a6b1378e4ab5230bad00ad04bc287c969e",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@ -10,7 +10,7 @@
in { in {
packages = genPerSystem (system: pkgs: { packages = genPerSystem (system: pkgs: {
default = pkgs.callPackage ./plugin.nix { default = pkgs.callPackage ./plugin.nix {
inherit (hyprland.packages.${system}) hyprland; inherit (hyprland.packages.${system}) hyprland-debug;
}; };
}); });
@ -26,9 +26,9 @@
# Note: gcc needs to be specified or else an older version might be used # Note: gcc needs to be specified or else an older version might be used
# TODO: maybe using gcc13Stdenv.mkShell would fix this? # TODO: maybe using gcc13Stdenv.mkShell would fix this?
nativeBuildInputs = with pkgs; [gcc14 meson pkg-config ninja]; nativeBuildInputs = with pkgs; [gcc14 meson pkg-config ninja];
buildInputs = [hyprland.packages.${system}.hyprland]; buildInputs = [hyprland.packages.${system}.hyprland-debug];
inputsFrom = [ inputsFrom = [
hyprland.packages.${system}.hyprland hyprland.packages.${system}.hyprland-debug
self.packages.${system}.default self.packages.${system}.default
]; ];
}; };

151
hyprlandd.conf Normal file
View File

@ -0,0 +1,151 @@
monitor=,preferred,auto,auto
# exec_once=kitty --hold sh -c "hyprctl plugin load $(pwd)/build/src/libhyprwiggle.so"
general {
gaps_in = 5
gaps_out = 20
border_size = 2
col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg
col.inactive_border = rgba(595959aa)
resize_on_border = false
allow_tearing = false
layout = dwindle
}
decoration {
rounding = 10
rounding_power = 2
active_opacity = 1.0
inactive_opacity = 1.0
shadow {
enabled = true
range = 4
render_power = 3
color = rgba(1a1a1aee)
}
blur {
enabled = true
size = 3
passes = 1
vibrancy = 0.1696
}
}
animations {
enabled = yes, please :)
bezier = easeOutQuint,0.23,1,0.32,1
bezier = easeInOutCubic,0.65,0.05,0.36,1
bezier = linear,0,0,1,1
bezier = almostLinear,0.5,0.5,0.75,1.0
bezier = quick,0.15,0,0.1,1
animation = global, 1, 10, default
animation = border, 1, 5.39, easeOutQuint
animation = windows, 1, 4.79, easeOutQuint
animation = windowsIn, 1, 4.1, easeOutQuint, popin 87%
animation = windowsOut, 1, 1.49, linear, popin 87%
animation = fadeIn, 1, 1.73, almostLinear
animation = fadeOut, 1, 1.46, almostLinear
animation = fade, 1, 3.03, quick
animation = layers, 1, 3.81, easeOutQuint
animation = layersIn, 1, 4, easeOutQuint, fade
animation = layersOut, 1, 1.5, linear, fade
animation = fadeLayersIn, 1, 1.79, almostLinear
animation = fadeLayersOut, 1, 1.39, almostLinear
animation = workspaces, 1, 1.94, almostLinear, fade
animation = workspacesIn, 1, 1.21, almostLinear, fade
animation = workspacesOut, 1, 1.94, almostLinear, fade
}
dwindle {
pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
preserve_split = true # You probably want this
}
master {
new_status = master
}
misc {
force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
disable_hyprland_logo = false # If true disables the random hyprland logo / anime girl background. :(
}
input {
kb_layout = us
kb_variant =
kb_model =
kb_options =
kb_rules =
follow_mouse = 1
sensitivity = 0 # -1.0 - 1.0, 0 means no modification.
touchpad {
natural_scroll = false
}
}
gestures {
workspace_swipe = false
}
###################
### KEYBINDINGS ###
###################
$mainMod = ALT
# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
bind = $mainMod, return, exec, kitty
bind = $mainMod, X, killactive,
bind = $mainMod, F4, exit,
bind = $mainMod, space, togglefloating,
bind = $mainMod, left, movefocus, l
bind = $mainMod, right, movefocus, r
bind = $mainMod, up, movefocus, u
bind = $mainMod, down, movefocus, d
# Switch workspaces with mainMod + [0-9]
bind = $mainMod, 1, workspace, 1
bind = $mainMod, 2, workspace, 2
bind = $mainMod, 3, workspace, 3
bind = $mainMod, 4, workspace, 4
bind = $mainMod, 5, workspace, 5
bind = $mainMod, 6, workspace, 6
bind = $mainMod, 7, workspace, 7
bind = $mainMod, 8, workspace, 8
bind = $mainMod, 9, workspace, 9
bind = $mainMod, 0, workspace, 10
# Move active window to a workspace with mainMod + SHIFT + [0-9]
bind = $mainMod SHIFT, 1, movetoworkspace, 1
bind = $mainMod SHIFT, 2, movetoworkspace, 2
bind = $mainMod SHIFT, 3, movetoworkspace, 3
bind = $mainMod SHIFT, 4, movetoworkspace, 4
bind = $mainMod SHIFT, 5, movetoworkspace, 5
bind = $mainMod SHIFT, 6, movetoworkspace, 6
bind = $mainMod SHIFT, 7, movetoworkspace, 7
bind = $mainMod SHIFT, 8, movetoworkspace, 8
bind = $mainMod SHIFT, 9, movetoworkspace, 9
bind = $mainMod SHIFT, 0, movetoworkspace, 10
# Example special workspace (scratchpad)
bind = $mainMod, S, togglespecialworkspace, magic
bind = $mainMod SHIFT, S, movetoworkspace, special:magic
bindm = $mainMod, mouse:272, movewindow
bindm = $mainMod SHIFT, mouse:272, resizewindow
bindm = $mainMod, mouse:273, resizewindow
# vim: set ft=hyprlang :

View File

@ -1,13 +1,13 @@
[example] [wigglewobble]
description = "Example plugin" description = "Wobbly windows for Hyprland"
author = "YOU" author = "All-Purpose Mat"
## NOTE: version is omitted here because I don't like having multiple places ## NOTE: version is omitted here because I don't like having multiple places
## to update the version string. Feel free to add it back in. ## to update the version string. Feel free to add it back in.
# #
# version = "v0.0.0" # version = "v0.0.0"
[example.build] [wigglewobble.build]
output = "build/src/example.so" output = "build/src/wigglewobble.so"
steps = [ steps = [
"meson setup build", "meson setup build",
"meson compile -Cbuild" "meson compile -Cbuild"

View File

@ -1,4 +1,4 @@
project('example', 'cpp', 'c', project('wigglewobble', 'cpp', 'c',
# we always take the VERSION file as the single source of truth # we always take the VERSION file as the single source of truth
version: run_command('cat', join_paths(meson.project_source_root(), 'VERSION'), check: true).stdout().strip(), version: run_command('cat', join_paths(meson.project_source_root(), 'VERSION'), check: true).stdout().strip(),
default_options: ['buildtype=release'], default_options: ['buildtype=release'],

View File

@ -4,24 +4,24 @@
meson, meson,
ninja, ninja,
pkg-config, pkg-config,
hyprland, hyprland-debug,
}: let }: let
version = builtins.readFile ./VERSION; version = builtins.readFile ./VERSION;
in in
gcc13Stdenv.mkDerivation { gcc13Stdenv.mkDerivation {
pname = "example"; pname = "wigglewobble";
inherit version; inherit version;
src = ./.; src = ./.;
nativeBuildInputs = nativeBuildInputs =
hyprland.nativeBuildInputs hyprland-debug.nativeBuildInputs
++ [ninja meson pkg-config]; ++ [ninja meson pkg-config];
buildInputs = [hyprland] ++ hyprland.buildInputs; buildInputs = [hyprland-debug] ++ hyprland-debug.buildInputs;
meta = with lib; { meta = with lib; {
homepage = "https://example.com"; homepage = "https://git.allpurposem.at/mat/WiggleWobble";
description = "Example hyprland plugin"; description = "Wobbly windows for hyprland";
license = licenses.bsd3; license = licenses.bsd3;
platforms = platforms.linux; platforms = platforms.linux;
}; };

6
run.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/env bash
set -e
meson compile -Cbuild
Hyprland -c hyprlandd.conf

View File

@ -1,74 +0,0 @@
#include "customDecoration.hpp"
#include <hyprland/src/Window.hpp>
#include <hyprland/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);
}

View File

@ -1,80 +0,0 @@
#include "customLayout.hpp"
#include <hyprland/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();
}

View File

@ -4,92 +4,35 @@
// version.hpp will be generated by meson // version.hpp will be generated by meson
#include "version.hpp" #include "version.hpp"
#include <hyprland/src/Window.hpp> // #include <hyprland/src/Window.hpp>
#include <hyprland/src/Compositor.hpp> #include <hyprland/src/Compositor.hpp>
#include "customLayout.hpp"
#include "customDecoration.hpp"
#include <unistd.h> #include <unistd.h>
#include <thread> #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. // Do NOT change this function.
APICALL EXPORT std::string PLUGIN_API_VERSION() { APICALL EXPORT std::string PLUGIN_API_VERSION() {
return HYPRLAND_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) { APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
PHANDLE = handle; PHANDLE = handle;
HyprlandAPI::addNotification(PHANDLE, "Hello World from an example plugin!", CColor{0.f, 1.f, 1.f, 1.f}, 5000); const std::string HASH = __hyprland_api_get_hash();
HyprlandAPI::registerCallbackDynamic(PHANDLE, "activeWindow", [&](void* self, std::any data) { onActiveWindowChange(self, data); }); // ALWAYS add this to your plugins. It will prevent random crashes coming from
HyprlandAPI::registerCallbackDynamic(PHANDLE, "openWindow", [&](void* self, std::any data) { onNewWindow(self, data); }); // mismatched header versions.
if (HASH != GIT_COMMIT_HASH) {
HyprlandAPI::addNotification(PHANDLE, "[WiggleWobble] Mismatched headers! Can't proceed.",
CHyprColor{1.0, 0.2, 0.2, 1.0}, 5000);
throw std::runtime_error("[WiggleWobble] Version mismatch");
}
g_pCustomLayout = std::make_unique<CHyprCustomLayout>(); HyprlandAPI::addNotification(PHANDLE, "WiggleWobble loaded!", CHyprColor{0.f, 1.f, 1.f, 1.f}, 5000);
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(); HyprlandAPI::reloadConfig();
return {"example", "An example plugin", "YOU", PLUGIN_VERSION}; return {"wigglewobble", "Wobbly windows for Hyprland", "All-Purpose Mat", PLUGIN_VERSION};
} }
APICALL EXPORT void PLUGIN_EXIT() { APICALL EXPORT void PLUGIN_EXIT() {

View File

@ -1,4 +1,4 @@
shared_module('example', shared_module('wigglewobble',
'main.cpp', 'main.cpp',
cpp_args: ['-DWLR_USE_UNSTABLE'], cpp_args: ['-DWLR_USE_UNSTABLE'],
include_directories: incdir, include_directories: incdir,