Compare commits

...

97 Commits

Author SHA1 Message Date
vaxerski
c02bfc3897 fix extents in shadow deco 2022-11-16 15:35:36 +00:00
vaxerski
878a20741b fix slide calcs for windows outside the viewport 2022-11-16 15:35:36 +00:00
vaxerski
d5eafe1926 set cursor to hand1 when moving a window 2022-11-15 10:39:05 +00:00
Mihai Fufezan
e2da4ff257 Nix CI: update actions (#1014) 2022-11-15 10:23:46 +00:00
Jef
dbb6732743 apply some rules dynamically when state of window changes (#1020)
Co-authored-by: Jef Steelant <jef.steelant_ext@softathome.com>
2022-11-15 10:21:26 +00:00
Jef
4034aa2c60 possible crash when current workspace does not exist (#1023)
Co-authored-by: Jef Steelant <jef.steelant_ext@softathome.com>
2022-11-15 10:18:04 +00:00
vaxerski
fcb5037a1d guard lastwindow in circlenext 2022-11-14 12:12:13 +00:00
vaxerski
0634abf168 remove quotes from commit messages in build 2022-11-13 20:01:30 +00:00
vaxerski
478fa7cafe Revert "Set child stdout and stderr to /dev/null (#1000)"
This reverts commit 1e5cab1ee7.

Breaks a bunch of stuff, e.g. Waybar.
2022-11-13 19:53:27 +00:00
Jef
549fdf63f6 Add bordercolor windowrule (#992)
* Add bordercolor windowrule

* remove spaces form bordercolor rule + typo

Co-authored-by: Jef Steelant <jef.steelant_ext@softathome.com>
2022-11-13 19:33:13 +00:00
Mihai Fufezan
1a14841a75 Nix: add hwdata overlay (#1010) 2022-11-13 19:32:15 +00:00
vaxerski
a7ed3a5e47 fix arch ci 2022-11-13 14:41:26 +00:00
vaxerski
884fc4f89c fix master window finding on closed 2022-11-13 14:31:12 +00:00
Thomas Voss
1e5cab1ee7 Set child stdout and stderr to /dev/null (#1000)
Some scripts or utilities check to see if stdout or stderr are connected
to a TTY or not to determine certain behaviors (for example, you might
want to prompt a user for input with fzf(1) if in a terminal but tofi(1)
or wofi(1) when spawned from your WM).  Since hyprland never closes
these output streams for spawned processes, they end up just spewing
their output onto the TTY while giving the user no real way to have a
script detect if it's being run from the shell or WM.

Instead of just closing stdout and stderr though, we close them and then
proceed to reopen them but connect them to /dev/null.  This allows
scripts and processes to not fail when attempting to write, but for that
writing to simply have no effect.
2022-11-13 11:58:20 +00:00
vaxerski
5a00f0c657 fix trailing comma in hyprctl activewindow 2022-11-13 11:12:11 +00:00
vaxerski
2cbb10d850 [gha] bump flake inputs 2022-11-13 11:05:51 +00:00
vaxerski
23cd1b8c66 update wlroots dep 2022-11-13 11:04:28 +00:00
vaxerski
be6f5ce831 fix commit message parsing in cmake 2022-11-13 10:58:46 +00:00
Jef
78a545112a streamline hypctl output of windows (#983)
Co-authored-by: Jef Steelant <jef.steelant_ext@softathome.com>
2022-11-13 00:39:21 +00:00
Vaxry
2cdabf581e Merge pull request #997 from leftas/main
Add keyboards' leds update on Key/Mod press
2022-11-12 21:00:38 +00:00
Leftas
34a7f17956 Add keyboard led update after keys/mod update 2022-11-12 13:12:37 +02:00
vaxerski
dd11434e90 notify idle on touch down 2022-11-11 23:41:04 +00:00
vaxerski
61995e3b4e guard empty str in isNumber 2022-11-11 14:04:35 +00:00
sioodmy
13befbd266 fix(nix): missing dependency 2022-11-11 14:43:45 +02:00
vaxerski
a5ffd44caf guard empty str in removeBeginEndSpacesTabs 2022-11-10 21:51:46 +00:00
vaxerski
0208dff574 fix invalid master slave pos calc on y != 0 2022-11-10 19:39:16 +00:00
vaxerski
3157bebed7 fix warning 2022-11-10 17:07:26 +00:00
vaxerski
c0bb4db15c add move cursor windowrule 2022-11-10 16:59:08 +00:00
Philip Jones
27cada2a02 Allow arguments to hyprctl dispatch exec commands. (#990) 2022-11-10 15:36:36 +00:00
vaxerski
153c99217d use spawn in config exec 2022-11-10 13:50:16 +00:00
vaxerski
851df11eb5 Added exec rules 2022-11-10 13:39:23 +00:00
vaxerski
5f2c741f49 remove spammy ime logs 2022-11-10 12:24:41 +00:00
vaxerski
9a9ecc25db added monitor cycling 2022-11-10 12:22:19 +00:00
vaxerski
34b145ee65 Added resizing individual master windows 2022-11-10 12:05:22 +00:00
vaxerski
f41fe59cb6 fix shadow extent & offset calculations 2022-11-09 22:39:19 +00:00
vaxerski
7ff1fd9d69 use goal values in changeWindowFloatingMode 2022-11-09 22:02:02 +00:00
vaxerski
d0b3cdc835 Fix crashes with DS and mirrors 2022-11-09 10:56:49 +00:00
vaxerski
1cf829c889 minor loose focus fixes 2022-11-08 20:28:41 +00:00
vaxerski
17992b633d minor fixes for follow_mouse 3 2022-11-08 14:48:17 +00:00
vaxerski
c545ab4993 Added multiple master layoutmsgs 2022-11-08 12:39:52 +00:00
vaxerski
1d2e4243dc clamp shadow scale to 1 2022-11-07 22:51:26 +00:00
vaxerski
aefc34b405 Minor fixes for virtual input devices 2022-11-07 22:22:13 +00:00
vaxerski
2a20cf5379 Added decoration:shadow_scale 2022-11-07 21:27:28 +00:00
vaxerski
e3a3837164 fix up formatting 2022-11-07 20:31:56 +00:00
Jan Beich
c86ab4694c meson: explicitly specify path for find(1) (#971)
src/meson.build:1:0: ERROR: Command "/usr/bin/find -name *.cpp" failed with status 1.
2022-11-07 20:27:06 +00:00
Jan Beich
5d5066570c helpers: implement getPPIDof on BSDs (#972)
Get PPID from `struct kinfo_proc` via sysctl for the specified PID.
Adjusted for minor differences between each BSD kernel.
2022-11-07 20:26:23 +00:00
abbadanor
1a55fb4170 Dispatcher to center floating window (#961)
Co-authored-by: Adam Nord <adam.nord@abbgymnasiet.se>
Co-authored-by: vaxerski <vaxry@vaxry.net>
2022-11-07 12:16:30 +00:00
vaxerski
efbc3f8194 resize transition fixes + default transitions to false 2022-11-06 18:10:53 +00:00
vaxerski
f755351511 Fix resize transitions on multimon + transformed 2022-11-06 18:04:30 +00:00
vaxerski
57817f7252 Added resize transitions 2022-11-06 17:52:09 +00:00
vaxerski
b4c45aa2e3 fix compiler warning 2022-11-06 14:28:15 +00:00
vaxerski
5295244026 Revert adding toggle for drm scanout flags
This reverts commit 12697d2b72.

Stupid idea.
2022-11-06 14:25:53 +00:00
vaxerski
082f439db2 fix issues with direct scanout's lack of surface frame feedback 2022-11-06 14:20:03 +00:00
vaxerski
12697d2b72 added toggle for drm scanout flags 2022-11-06 14:11:37 +00:00
vaxerski
976b44443a ignore constraints on exclusiveClient create 2022-11-05 18:34:26 +00:00
vaxerski
6553fb5a40 fix fullscreen maximize size 2022-11-05 18:25:32 +00:00
vaxerski
bee06f3507 add more wlroots flags for faster compile 2022-11-05 18:05:15 +00:00
vaxerski
5a750b485a Added creating / destroying outputs on a multi-backend + headless backend
See `hyprctl output`.
2022-11-05 18:04:44 +00:00
vaxerski
a71f44baa5 fix compiler warning 2022-11-05 13:49:55 +00:00
vaxerski
65db3a7bd3 fix relative protocol paths
CI fix
2022-11-05 13:46:58 +00:00
vaxerski
22384869a6 fix unregistering avars on sethidden 2022-11-05 13:37:57 +00:00
vaxerski
ff76fbe763 prevent double-registering of avars 2022-11-05 13:37:29 +00:00
vaxerski
cfbab453e8 move no_direct_scanout to misc 2022-11-05 13:22:18 +00:00
vaxerski
6a59b57ef8 remove spammy logs for DS 2022-11-05 13:06:48 +00:00
vaxerski
f50c786640 Added direct scanout 2022-11-05 12:50:47 +00:00
vaxerski
70aece8522 constraint focus simplifications 2022-11-04 18:09:40 +00:00
vaxerski
c9eb0f3aab fix missing stub for xwayland 2022-11-04 16:10:10 +00:00
vaxerski
206360177f Multiple animation optimization and xwayland wine fixes 2022-11-04 15:56:31 +00:00
vaxerski
34ad837fd9 don't update the env in session-less hl 2022-11-04 11:30:25 +00:00
vaxerski
e796157672 fix passing input to constrained windows without relative 2022-11-04 11:09:34 +00:00
vaxerski
b51222c004 fix ordering in mouse connect 2022-11-04 10:48:42 +00:00
vaxerski
9aad352789 automatically update dbus environment on start 2022-11-04 10:37:14 +00:00
vaxerski
ce8c20c1ed fix raw exec in configmanager 2022-11-04 10:33:05 +00:00
vaxerski
349afa0e7a guard header windows in layout messages 2022-11-03 22:55:44 +00:00
vaxerski
748a6965ca include utility in defines 2022-11-03 19:55:20 +00:00
vaxerski
97af7c416e added unset rules 2022-11-03 19:52:43 +00:00
vaxerski
47512dd6db remove redundant includes 2022-11-03 19:52:34 +00:00
vaxerski
653b9ed0e4 Fix missing focusedmon event on focusmonitor dispatcher 2022-11-03 19:34:26 +00:00
vaxerski
d0e47d9fe0 added workspace_swipe_forever 2022-11-03 13:35:34 +00:00
Mihai Fufezan
f978368a4e Nix HM: Fix invalid escapes
Fixes #949
2022-11-03 13:21:51 +02:00
vaxerski
c47581fc5a handle transforming displays in outputMgr 2022-11-03 09:06:44 +00:00
vaxerski
31aa357c17 fix safety over ls outputs 2022-11-03 08:56:47 +00:00
vaxerski
6ddfae0a07 remove ensureFDsValid, legacy 2022-11-02 21:28:08 +00:00
Mihai Fufezan
0d7176792b Nix HM: prevent race condition between dbus and systemd
Fixes #940
2022-11-02 21:36:07 +02:00
vaxerski
c1542da18a fix typo in focus 2022-11-02 18:54:41 +00:00
vaxerski
5b548f5bc3 update window values after map finish 2022-11-02 15:15:39 +00:00
vaxerski
5ac2005318 remove old comments 2022-11-02 14:52:36 +00:00
vaxerski
a2b8e3b34e fix the damageBox in damageMonitor 2022-11-02 11:04:17 +00:00
vaxerski
d78b53968f render the debug overlay only on visible monitors 2022-11-02 10:24:43 +00:00
abbadanor
61b950d942 Add focusmaster dispatcher (#942)
* added focusmaster dispatcher

* format

Co-authored-by: Adam Nord <adam.nord@abbgymnasiet.se>
Co-authored-by: vaxerski <43317083+vaxerski@users.noreply.github.com>
2022-11-02 10:15:11 +00:00
vaxerski
a16073a87b deprecate general:damage_tracking 2022-11-02 10:12:33 +00:00
vaxerski
603a90886f fix swipe on 2 detached workspaces 2022-11-02 10:01:13 +00:00
vaxerski
95bbac8791 remove redundant check in CShader 2022-11-01 18:46:51 +00:00
vaxerski
a69fd21a1a Add an idleinhibit windowrule 2022-10-31 12:26:07 +00:00
Mihai Fufezan
b6e33830af Nix & meson: 0.16.0 -> 0.17.0
Nix: make xwayland dependencies optional
2022-10-31 12:41:31 +02:00
wael
2c67c1c4f8 meson: use gl instead of GL
`/usr/lib/pkgconfig/gl.pc`
2022-10-31 12:39:04 +02:00
vaxerski
989deafd5e use lld instead of i in hyprctl getopt for accurate int reads 2022-10-30 22:45:03 +00:00
61 changed files with 1558 additions and 452 deletions

View File

@@ -41,7 +41,7 @@ jobs:
cp ./LICENSE hyprland/
cp build/Hyprland hyprland/
cp hyprctl/hyprctl hyprland/
cp subprojects/wlroots/build/libwlroots.so.11032 hyprland/
cp subprojects/wlroots/build/libwlroots.so.12032 hyprland/
cp build/Hyprland hyprland/
cp -r example/ hyprland/
cp -r assets/ hyprland/

View File

@@ -16,13 +16,13 @@ jobs:
with:
submodules: recursive
- name: Install nix
uses: cachix/install-nix-action@v17
uses: cachix/install-nix-action@v18
with:
install_url: https://releases.nixos.org/nix/nix-2.10.3/install
install_url: https://nixos.org/nix/install
extra_nix_config: |
auto-optimise-store = true
experimental-features = nix-command flakes
- uses: cachix/cachix-action@v10
- uses: cachix/cachix-action@v12
with:
name: hyprland
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'

View File

@@ -9,9 +9,9 @@ jobs:
- name: Clone repository
uses: actions/checkout@v3
- name: Install nix
uses: cachix/install-nix-action@v17
uses: cachix/install-nix-action@v18
with:
install_url: https://releases.nixos.org/nix/nix-2.8.0/install
install_url: https://nixos.org/nix/install
extra_nix_config: |
auto-optimise-store = true
experimental-features = nix-command flakes

View File

@@ -22,7 +22,7 @@ execute_process(
OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(
COMMAND sh -c "git show ${GIT_COMMIT_HASH} | head -n 5 | tail -n 1"
COMMAND sh -c "git show ${GIT_COMMIT_HASH} | head -n 5 | tail -n 1 | sed -s 's/#|\"//g'"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_MESSAGE
OUTPUT_STRIP_TRAILING_WHITESPACE)
@@ -89,7 +89,7 @@ message(STATUS "Setting link libraries")
target_link_libraries(Hyprland PkgConfig::deps)
target_link_libraries(Hyprland
${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.11032 # wlroots is provided by us
${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.12032 # wlroots is provided by us
pixman-1
OpenGL
GLESv2

View File

@@ -91,6 +91,16 @@ wlr-output-power-management-unstable-v1-protocol.c:
wlr-output-power-management-unstable-v1-protocol.o: wlr-output-power-management-unstable-v1-protocol.h
linux-dmabuf-unstable-v1-protocol.h:
$(WAYLAND_SCANNER) server-header \
$(WAYLAND_PROTOCOLS)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml $@
linux-dmabuf-unstable-v1-protocol.c:
$(WAYLAND_SCANNER) private-code \
$(WAYLAND_PROTOCOLS)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml $@
linux-dmabuf-unstable-v1-protocol.o: linux-dmabuf-unstable-v1-protocol.h
legacyrenderer:
mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DLEGACY_RENDERER:STRING=true -H./ -B./build -G Ninja
cmake --build ./build --config Release --target all -j$(shell nproc)
@@ -121,7 +131,7 @@ all:
install:
make clear
make fixwlr
cd ./subprojects/wlroots && meson build/ --buildtype=release && ninja -C build/ && cp ./build/libwlroots.so.11032 /usr/lib/ && cd ../..
cd ./subprojects/wlroots && meson build/ --buildtype=release && ninja -C build/ && cp ./build/libwlroots.so.12032 /usr/lib/ && cd ../..
make protocols
make release
cd hyprctl && make all && cd ..
@@ -141,7 +151,7 @@ install:
cleaninstall:
make clear
make fixwlr
cd ./subprojects/wlroots && meson build/ --buildtype=release && ninja -C build/ && cp ./build/libwlroots.so.11032 /usr/lib/ && cd ../..
cd ./subprojects/wlroots && meson build/ --buildtype=release && ninja -C build/ && cp ./build/libwlroots.so.12032 /usr/lib/ && cd ../..
make protocols
make release
cd hyprctl && make all && cd ..
@@ -161,15 +171,15 @@ uninstall:
rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop
rm -f ${PREFIX}/bin/Hyprland
rm -f ${PREFIX}/bin/hyprctl
rm -f /usr/lib/libwlroots.so.11032
rm -f /usr/lib/libwlroots.so.12032
rm -rf ${PREFIX}/share/hyprland
rm -f ${PREFIX}/share/man/man1/Hyprland.1
rm -f ${PREFIX}/share/man/man1/hyprctl.1
protocols: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o wlr-screencopy-unstable-v1-protocol.o idle-protocol.o ext-workspace-unstable-v1-protocol.o pointer-constraints-unstable-v1-protocol.o tablet-unstable-v2-protocol.o wlr-output-power-management-unstable-v1-protocol.o
protocols: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o wlr-screencopy-unstable-v1-protocol.o idle-protocol.o ext-workspace-unstable-v1-protocol.o pointer-constraints-unstable-v1-protocol.o tablet-unstable-v2-protocol.o wlr-output-power-management-unstable-v1-protocol.o linux-dmabuf-unstable-v1-protocol.o
fixwlr:
sed -i -E 's/(soversion = 11)([^032]|$$)/soversion = 11032/g' subprojects/wlroots/meson.build
sed -i -E 's/(soversion = 12)([^032]|$$)/soversion = 12032/g' subprojects/wlroots/meson.build
rm -rf ./subprojects/wlroots/build
@@ -178,7 +188,7 @@ config:
make fixwlr
cd subprojects/wlroots && meson ./build --prefix=/usr --buildtype=release
cd subprojects/wlroots && meson ./build --prefix=/usr --buildtype=release -Dwerror=false -Dexamples=false
cd subprojects/wlroots && ninja -C build/
cd subprojects/wlroots && ninja -C build/ install

12
flake.lock generated
View File

@@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1666377499,
"narHash": "sha256-dZZCGvWcxc7oGnUgFVf0UeNHsJ4VhkTM0v5JRe8EwR8=",
"lastModified": 1668087632,
"narHash": "sha256-T/cUx44aYDuLMFfaiVpMdTjL4kpG7bh0VkN6JEM78/E=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "301aada7a64812853f2e2634a530ef5d34505048",
"rev": "5f588eb4a958f1a526ed8da02d6ea1bea0047b9f",
"type": "github"
},
"original": {
@@ -26,11 +26,11 @@
"flake": false,
"locked": {
"host": "gitlab.freedesktop.org",
"lastModified": 1666466001,
"narHash": "sha256-ZjxAnqtcGmHQHKL1Z9sIraDnzIqrJleWcJXfPtzAm74=",
"lastModified": 1668292512,
"narHash": "sha256-lCMnIguyZgAGq7W2IwIVPoQS8fAfZ/XFwz/1TQ53eI8=",
"owner": "wlroots",
"repo": "wlroots",
"rev": "c2d2773df57750081b16d56da13b5015d752cbd7",
"rev": "627a5c511278e67c3c308cdc6a639cbb490f48c3",
"type": "gitlab"
},
"original": {

View File

@@ -24,13 +24,7 @@
pkgsFor = genSystems (system: import nixpkgs {
inherit system;
overlays = [(_: prev: {
wayland-protocols = prev.wayland-protocols.overrideAttrs (old: rec {
version = "1.27";
src = prev.fetchurl {
url = "https://gitlab.freedesktop.org/wayland/${old.pname}/-/releases/${version}/downloads/${old.pname}-${version}.tar.xz";
hash = "sha256-kEbxCkJdTioAlloDrPtrP7V1pWUDrHLCuGghxpZTN1w=";
};
});
hwdata = prev.callPackage ./nix/hwdata.nix {};
})];
});
@@ -47,7 +41,7 @@
};
hyprland = prev.callPackage ./nix/default.nix {
stdenv = prev.gcc12Stdenv;
version = "0.16.0beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty");
version = "0.17.0beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty");
wlroots = wlroots-hyprland;
};
hyprland-debug = hyprland.override {debug = true;};

View File

@@ -168,8 +168,11 @@ int dispatchRequest(int argc, char** argv) {
std::string rq = "/dispatch";
for(int i = 2; i < argc; i++)
for(int i = 2; i < argc; i++) {
if (!strcmp(argv[i], "--"))
continue;
rq += " " + std::string(argv[i]);
}
request(rq);
return 0;
@@ -217,6 +220,21 @@ int setcursorRequest(int argc, char** argv) {
return 0;
}
int outputRequest(int argc, char** argv) {
if (argc < 4) {
std::cout << "Usage: hyprctl output <mode> <name>\n\
creates / destroys a fake output\n\
with create, name is the backend name to use (available: auto, x11, wayland, headless)\n\
with destroy, name is the output name to destroy";
return 1;
}
std::string rq = "output " + std::string(argv[2]) + " " + std::string(argv[3]);
request(rq);
return 0;
}
void batchRequest(std::string arg) {
std::string rq = "[[BATCH]]" + arg.substr(arg.find_first_of(" ") + 1);
@@ -233,11 +251,14 @@ std::deque<std::string> splitArgs(int argc, char** argv) {
}
bool isNumber(const std::string& str, bool allowfloat) {
if (str.empty())
return false;
return std::ranges::all_of(str.begin(), str.end(), [&](char c) { return isdigit(c) != 0 || c == '-' || (allowfloat && c == '.'); });
}
int main(int argc, char** argv) {
int bflag = 0, sflag = 0, index, c;
bool parseArgs = true;
if (argc < 2) {
printf("%s\n", USAGE.c_str());
@@ -249,7 +270,12 @@ int main(int argc, char** argv) {
const auto ARGS = splitArgs(argc, argv);
for (auto i = 0; i < ARGS.size(); ++i) {
if (ARGS[i][0] == '-' && !isNumber(ARGS[i], true) /* For stuff like -2 */) {
if (ARGS[i] == "--") {
// Stop parsing arguments after --
parseArgs = false;
continue;
}
if (parseArgs && (ARGS[i][0] == '-') && !isNumber(ARGS[i], true) /* For stuff like -2 */) {
// parse
if (ARGS[i] == "-j" && !fullArgs.contains("j")) {
fullArgs += "j";
@@ -290,6 +316,7 @@ int main(int argc, char** argv) {
else if (fullRequest.contains("/reload")) request(fullRequest);
else if (fullRequest.contains("/getoption")) request(fullRequest);
else if (fullRequest.contains("/cursorpos")) request(fullRequest);
else if (fullRequest.contains("/output")) exitStatus = outputRequest(argc, argv);
else if (fullRequest.contains("/setcursor")) exitStatus = setcursorRequest(argc, argv);
else if (fullRequest.contains("/dispatch")) exitStatus = dispatchRequest(argc, argv);
else if (fullRequest.contains("/keyword")) exitStatus = keywordRequest(argc, argv);

View File

@@ -1,5 +1,5 @@
project('Hyprland', 'cpp', 'c',
version : '0.16.0beta',
version : '0.17.0beta',
default_options : [
'warning_level=2',
'default_library=static',

View File

@@ -14,6 +14,7 @@
mesa,
mount,
pango,
pciutils,
wayland,
wayland-protocols,
wayland-scanner,
@@ -62,17 +63,16 @@ in
git
libdrm
libinput
libxcb
libxkbcommon
mesa
pango
wayland
wayland-protocols
wayland-scanner
pciutils
(wlroots.override {inherit enableXWayland hidpiXWayland nvidiaPatches;})
xcbutilwm
]
++ lib.optional enableXWayland xwayland;
++ lib.optionals enableXWayland [libxcb xcbutilwm xwayland];
mesonBuildType =
if debug

View File

@@ -102,8 +102,7 @@ in {
xdg.configFile."hypr/hyprland.conf" = {
text =
(lib.optionalString cfg.systemdIntegration ''
exec-once=${pkgs.dbus}/bin/dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP
exec-once=systemctl --user start hyprland-session.target
exec-once=${pkgs.dbus}/bin/dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP && systemctl --user start hyprland-session.target
'')
+ cfg.extraConfig;

28
nix/hwdata.nix Normal file
View File

@@ -0,0 +1,28 @@
{ lib, stdenv, fetchFromGitHub }:
stdenv.mkDerivation rec {
pname = "hwdata";
version = "0.363";
src = fetchFromGitHub {
owner = "vcrhonek";
repo = "hwdata";
rev = "v${version}";
sha256 = "sha256-A6GNrHc/t2SVyAyJWmzQTa+pD9wGESsz7DNruW2kH4s=";
};
postPatch = ''
patchShebangs ./configure
'';
configureFlags = [ "--datadir=${placeholder "out"}/share" ];
doCheck = false; # this does build machine-specific checks (e.g. enumerates PCI bus)
meta = {
homepage = "https://github.com/vcrhonek/hwdata";
description = "Hardware Database, including Monitors, pci.ids, usb.ids, and video cards";
license = lib.licenses.gpl2Plus;
platforms = lib.platforms.all;
};
}

View File

@@ -6,6 +6,7 @@
xwayland,
fetchpatch,
lib,
hwdata,
hidpiXWayland ? true,
enableXWayland ? true,
nvidiaPatches ? false,
@@ -51,6 +52,7 @@ assert (lib.assertMsg (hidpiXWayland -> enableXWayland) ''
''
else ""
);
buildInputs = old.buildInputs ++ [hwdata];
}))
.override {
xwayland = xwayland.overrideAttrs (old: {

View File

@@ -13,6 +13,7 @@ wayland_scanner = find_program(
protocols = [
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
[wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'],
['wlr-layer-shell-unstable-v1.xml'],
['wlr-output-power-management-unstable-v1.xml'],
['ext-workspace-unstable-v1.xml'],

View File

@@ -73,7 +73,15 @@ CCompositor::CCompositor() {
throw std::runtime_error("wlr_gles2_renderer_create_with_drm_fd() failed!");
}
wlr_renderer_init_wl_display(m_sWLRRenderer, m_sWLDisplay);
wlr_renderer_init_wl_shm(m_sWLRRenderer, m_sWLDisplay);
if (wlr_renderer_get_dmabuf_texture_formats(m_sWLRRenderer)) {
if (wlr_renderer_get_drm_fd(m_sWLRRenderer) >= 0) {
wlr_drm_create(m_sWLDisplay, m_sWLRRenderer);
}
m_sWLRLinuxDMABuf = wlr_linux_dmabuf_v1_create(m_sWLDisplay, m_sWLRRenderer);
}
m_sWLRAllocator = wlr_allocator_autocreate(m_sWLRBackend, m_sWLRRenderer);
@@ -172,6 +180,15 @@ CCompositor::CCompositor() {
m_sWLRIMEMgr = wlr_input_method_manager_v2_create(m_sWLDisplay);
m_sWLRActivation = wlr_xdg_activation_v1_create(m_sWLDisplay);
m_sWLRHeadlessBackend = wlr_headless_backend_create(m_sWLDisplay);
if (!m_sWLRHeadlessBackend) {
Debug::log(CRIT, "Couldn't create the headless backend");
throw std::runtime_error("wlr_headless_backend_create() failed!");
}
wlr_multi_backend_add(m_sWLRBackend, m_sWLRHeadlessBackend);
}
CCompositor::~CCompositor() {
@@ -340,6 +357,9 @@ void CCompositor::startCompositor() {
signal(SIGPIPE, SIG_IGN);
if (m_sWLRSession /* Session-less Hyprland usually means a nest, don't update the env in that case */ && fork() == 0)
execl("/bin/sh", "/bin/sh", "-c", "dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE", nullptr);
Debug::log(LOG, "Running on WAYLAND_DISPLAY: %s", m_szWLDisplaySocket);
if (!wlr_backend_start(m_sWLRBackend)) {
@@ -728,6 +748,8 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
g_pLayoutManager->getCurrentLayout()->onWindowFocusChange(nullptr);
m_pLastFocus = nullptr;
g_pInputManager->recheckIdleInhibitorStatus();
return;
}
@@ -787,7 +809,8 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
if (PCONSTRAINT)
g_pInputManager->constrainMouse(m_sSeat.mouse, PCONSTRAINT);
}
g_pInputManager->recheckIdleInhibitorStatus();
}
void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) {
@@ -828,7 +851,7 @@ void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) {
else
Debug::log(LOG, "Set keyboard focus to surface %x", pSurface);
g_pXWaylandManager->activateSurface(pSurface, false);
g_pXWaylandManager->activateSurface(pSurface, true);
m_pLastFocus = pSurface;
}
@@ -1392,7 +1415,9 @@ void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
if (RENDERDATA.isBorderColor)
pWindow->m_cRealBorderColor = RENDERDATA.borderColor;
else
pWindow->m_cRealBorderColor = CColor(pWindow == m_pLastWindow ? *ACTIVECOL : *INACTIVECOL);
pWindow->m_cRealBorderColor = CColor(pWindow == m_pLastWindow ?
(pWindow->m_sSpecialRenderData.activeBorderColor >= 0 ? pWindow->m_sSpecialRenderData.activeBorderColor : *ACTIVECOL) :
(pWindow->m_sSpecialRenderData.inactiveBorderColor >= 0 ? pWindow->m_sSpecialRenderData.inactiveBorderColor : *INACTIVECOL));
// opacity
@@ -1513,7 +1538,40 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
}
CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
if (isNumber(name)) {
if (name[0] == '+' || name[0] == '-') {
// relative
const auto OFFSET = name[0] == '-' ? name : name.substr(1);
if (!isNumber(OFFSET)) {
Debug::log(ERR, "Error in getMonitorFromString: Not a number in relative.");
return nullptr;
}
int offsetLeft = std::stoi(OFFSET) % m_vMonitors.size(); // no need to cycle more
int currentPlace = 0;
for (int i = 0; i < (int)m_vMonitors.size(); i++) {
if (m_vMonitors[i].get() == m_pLastMonitor) {
currentPlace = i;
break;
}
}
currentPlace += offsetLeft;
if (currentPlace < 0) {
currentPlace = m_vMonitors.size() - currentPlace;
} else {
currentPlace = currentPlace % m_vMonitors.size();
}
if (currentPlace != std::clamp(currentPlace, 0, (int)m_vMonitors.size())) {
Debug::log(WARN, "Error in getMonitorFromString: Vaxry's code sucks.");
currentPlace = std::clamp(currentPlace, 0, (int)m_vMonitors.size());
}
return m_vMonitors[currentPlace].get();
} else if (isNumber(name)) {
// change by ID
int monID = -1;
try {
@@ -1674,6 +1732,9 @@ void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode
g_pXWaylandManager->setWindowFullscreen(pWindow, pWindow->m_bIsFullscreen && mode == FULLSCREEN_FULL);
pWindow->updateDynamicRules();
g_pCompositor->updateWindowAnimatedDecorationValues(pWindow);
// make all windows on the same workspace under the fullscreen window
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID) {
@@ -1691,6 +1752,11 @@ void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv(), true);
forceReportSizesToWindowsOnWorkspace(pWindow->m_iWorkspaceID);
g_pInputManager->recheckIdleInhibitorStatus();
// DMAbuf stuff for direct scanout
g_pHyprRenderer->setWindowScanoutMode(pWindow);
}
void CCompositor::moveUnmanagedX11ToWindows(CWindow* pWindow) {

View File

@@ -70,6 +70,8 @@ public:
wlr_input_method_manager_v2* m_sWLRIMEMgr;
wlr_text_input_manager_v3* m_sWLRTextInputMgr;
wlr_xdg_activation_v1* m_sWLRActivation;
wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf;
wlr_backend* m_sWLRHeadlessBackend;
// ------------------------------------------------- //

View File

@@ -3,7 +3,7 @@
#include "render/decorations/CHyprDropShadowDecoration.hpp"
CWindow::CWindow() {
m_vRealPosition.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*) this, AVARDAMAGE_ENTIRE);
m_vRealPosition.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE);
m_vRealSize.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE);
m_cRealBorderColor.create(AVARTYPE_COLOR, g_pConfigManager->getAnimationPropertyConfig("border"), (void*)this, AVARDAMAGE_BORDER);
m_fAlpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), (void*)this, AVARDAMAGE_ENTIRE);
@@ -245,19 +245,120 @@ void CWindow::removeDecorationByType(eDecorationType type) {
updateWindowDecos();
}
void unregisterVar(void* ptr) {
((CAnimatedVariable*)ptr)->unregister();
}
void CWindow::onUnmap() {
if (g_pCompositor->m_pLastWindow == this)
g_pCompositor->m_pLastWindow = nullptr;
m_vRealPosition.setCallbackOnEnd(unregisterVar);
m_vRealSize.setCallbackOnEnd(unregisterVar);
m_cRealBorderColor.setCallbackOnEnd(unregisterVar);
m_fActiveInactiveAlpha.setCallbackOnEnd(unregisterVar);
m_fAlpha.setCallbackOnEnd(unregisterVar);
m_cRealShadowColor.setCallbackOnEnd(unregisterVar);
m_fDimPercent.setCallbackOnEnd(unregisterVar);
m_vRealSize.setCallbackOnBegin(nullptr);
}
void CWindow::onMap() {
m_vRealPosition.registerVar();
m_vRealSize.registerVar();
m_cRealBorderColor.registerVar();
m_fActiveInactiveAlpha.registerVar();
m_fAlpha.registerVar();
m_cRealShadowColor.registerVar();
m_fDimPercent.registerVar();
m_vRealSize.setCallbackOnEnd([&] (void* ptr) {
g_pHyprOpenGL->onWindowResizeEnd(this);
}, false);
m_vRealSize.setCallbackOnBegin([&] (void* ptr) {
g_pHyprOpenGL->onWindowResizeStart(this);
}, false);
}
void CWindow::setHidden(bool hidden) {
m_bHidden = hidden;
if (hidden) {
onUnmap();
if (hidden && g_pCompositor->m_pLastWindow == this) {
g_pCompositor->m_pLastWindow = nullptr;
}
}
bool CWindow::isHidden() {
return m_bHidden;
}
}
void CWindow::applyDynamicRule(const SWindowRule& r) {
if (r.szRule == "noblur") {
m_sAdditionalConfigData.forceNoBlur = true;
} else if (r.szRule == "noborder") {
m_sAdditionalConfigData.forceNoBorder = true;
} else if (r.szRule == "noshadow") {
m_sAdditionalConfigData.forceNoShadow = true;
} else if (r.szRule == "opaque") {
m_sAdditionalConfigData.forceOpaque = true;
} else if (r.szRule.find("rounding") == 0) {
try {
m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
} catch (std::exception& e) {
Debug::log(ERR, "Rounding rule \"%s\" failed with: %s", r.szRule.c_str(), e.what());
}
} else if (r.szRule.find("opacity") == 0) {
try {
std::string alphaPart = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
if (alphaPart.contains(' ')) {
// we have a space, 2 values
m_sSpecialRenderData.alpha = std::stof(alphaPart.substr(0, alphaPart.find_first_of(' ')));
m_sSpecialRenderData.alphaInactive = std::stof(alphaPart.substr(alphaPart.find_first_of(' ') + 1));
} else {
m_sSpecialRenderData.alpha = std::stof(alphaPart);
}
} catch(std::exception& e) {
Debug::log(ERR, "Opacity rule \"%s\" failed with: %s", r.szRule.c_str(), e.what());
}
} else if (r.szRule == "noanim") {
m_sAdditionalConfigData.forceNoAnims = true;
} else if (r.szRule.find("animation") == 0) {
auto STYLE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
m_sAdditionalConfigData.animationStyle = STYLE;
} else if (r.szRule.find("bordercolor") == 0) {
try {
std::string colorPart = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
if (colorPart.contains(' ')) {
// we have a space, 2 values
m_sSpecialRenderData.activeBorderColor = configStringToInt(colorPart.substr(0, colorPart.find_first_of(' ')));
m_sSpecialRenderData.inactiveBorderColor = configStringToInt(colorPart.substr(colorPart.find_first_of(' ') + 1));
} else {
m_sSpecialRenderData.activeBorderColor = configStringToInt(colorPart);
}
} catch(std::exception& e) {
Debug::log(ERR, "BorderColor rule \"%s\" failed with: %s", r.szRule.c_str(), e.what());
}
}
}
void CWindow::updateDynamicRules() {
m_sSpecialRenderData.activeBorderColor = -1;
m_sSpecialRenderData.inactiveBorderColor = -1;
m_sSpecialRenderData.alpha = 1.f;
m_sSpecialRenderData.alphaInactive = -1.f;
m_sAdditionalConfigData.forceNoBlur = false;
m_sAdditionalConfigData.forceNoBorder = false;
m_sAdditionalConfigData.forceNoShadow = false;
m_sAdditionalConfigData.forceOpaque = false;
m_sAdditionalConfigData.forceNoAnims = false;
m_sAdditionalConfigData.animationStyle = "";
m_sAdditionalConfigData.rounding = -1;
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(this);
for (auto& r : WINDOWRULES) {
applyDynamicRule(r);
}
}

View File

@@ -7,10 +7,20 @@
#include "render/decorations/IHyprWindowDecoration.hpp"
#include <deque>
enum eIdleInhibitMode {
IDLEINHIBIT_NONE = 0,
IDLEINHIBIT_ALWAYS,
IDLEINHIBIT_FULLSCREEN,
IDLEINHIBIT_FOCUS
};
struct SWindowSpecialRenderData {
float alpha = 1.f;
float alphaInactive = -1.f; // -1 means unset
int64_t activeBorderColor = -1; // -1 means unset
int64_t inactiveBorderColor = -1; // -1 means unset
// set by the layout
bool rounding = true;
bool border = true;
@@ -29,6 +39,19 @@ struct SWindowAdditionalConfigData {
bool windowDanceCompat = false;
};
struct SWindowRule {
std::string szRule;
std::string szValue;
bool v2 = false;
std::string szTitle;
std::string szClass;
int bX11 = -1; // -1 means "ANY"
int bFloating = -1;
int bFullscreen = -1;
int bPinned = -1;
};
class CWindow {
public:
CWindow();
@@ -154,6 +177,9 @@ public:
uint64_t m_iLastToplevelMonitorID = -1;
uint64_t m_iLastSurfaceMonitorID = -1;
// for idle inhibiting windows
eIdleInhibitMode m_eIdleInhibitMode = IDLEINHIBIT_NONE;
// For the list lookup
bool operator==(const CWindow& rhs) {
return m_uSurface.xdg == rhs.m_uSurface.xdg && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && m_bFadingOut == rhs.m_bFadingOut;
@@ -173,8 +199,11 @@ public:
void moveToWorkspace(int);
CWindow* X11TransientFor();
void onUnmap();
void onMap();
void setHidden(bool hidden);
bool isHidden();
void applyDynamicRule(const SWindowRule& r);
void updateDynamicRules();
private:
// For hidden windows and stuff

View File

@@ -35,9 +35,6 @@ void CConfigManager::setDefaultVars() {
configValues["general:main_mod"].strValue = "SUPER"; // exposed to the user for easier configuring
configValues["general:main_mod_internal"].intValue = g_pKeybindManager->stringToModMask("SUPER"); // actually used and automatically calculated
configValues["general:damage_tracking"].strValue = "full";
configValues["general:damage_tracking_internal"].intValue = DAMAGE_TRACKING_FULL;
configValues["general:border_size"].intValue = 1;
configValues["general:no_border_on_floating"].intValue = 0;
configValues["general:gaps_in"].intValue = 5;
@@ -61,6 +58,7 @@ void CConfigManager::setDefaultVars() {
configValues["misc:enable_swallow"].intValue = 0;
configValues["misc:swallow_regex"].strValue = STRVAL_EMPTY;
configValues["misc:focus_on_activate"].intValue = 0;
configValues["misc:no_direct_scanout"].intValue = 0;
configValues["debug:int"].intValue = 0;
configValues["debug:log_damage"].intValue = 0;
@@ -68,6 +66,7 @@ void CConfigManager::setDefaultVars() {
configValues["debug:damage_blink"].intValue = 0;
configValues["debug:disable_logs"].intValue = 0;
configValues["debug:disable_time"].intValue = 1;
configValues["debug:damage_tracking"].intValue = DAMAGE_TRACKING_FULL;
configValues["decoration:rounding"].intValue = 0;
configValues["decoration:blur"].intValue = 1;
@@ -85,6 +84,7 @@ void CConfigManager::setDefaultVars() {
configValues["decoration:shadow_render_power"].intValue = 3;
configValues["decoration:shadow_ignore_window"].intValue = 1;
configValues["decoration:shadow_offset"].vecValue = Vector2D();
configValues["decoration:shadow_scale"].floatValue = 1.f;
configValues["decoration:col.shadow"].intValue = 0xee1a1a1a;
configValues["decoration:col.shadow_inactive"].intValue = INT_MAX;
configValues["decoration:dim_inactive"].intValue = 0;
@@ -106,6 +106,7 @@ void CConfigManager::setDefaultVars() {
configValues["master:no_gaps_when_only"].intValue = 0;
configValues["animations:enabled"].intValue = 1;
configValues["animations:use_resize_transitions"].intValue = 0;
configValues["animations:speed"].floatValue = 7.f;
configValues["animations:curve"].strValue = "default";
configValues["animations:windows_style"].strValue = STRVAL_EMPTY;
@@ -163,6 +164,7 @@ void CConfigManager::setDefaultVars() {
configValues["gestures:workspace_swipe_min_speed_to_force"].intValue = 30;
configValues["gestures:workspace_swipe_cancel_ratio"].floatValue = 0.5f;
configValues["gestures:workspace_swipe_create_new"].intValue = 1;
configValues["gestures:workspace_swipe_forever"].intValue = 0;
configValues["input:follow_mouse"].intValue = 1;
@@ -310,45 +312,10 @@ void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::s
if (CONFIGENTRY->intValue != -INT64_MAX) {
try {
if (VALUE.find("0x") == 0) {
// Values with 0x are hex
const auto VALUEWITHOUTHEX = VALUE.substr(2);
CONFIGENTRY->intValue = stol(VALUEWITHOUTHEX, nullptr, 16);
} else if (VALUE.find("rgba(") == 0 && VALUE.find(")") == VALUE.length() - 1) {
const auto VALUEWITHOUTFUNC = VALUE.substr(5, VALUE.length() - 6);
if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 8) {
Debug::log(WARN, "invalid length %i for rgba", VALUEWITHOUTFUNC.length());
parseError = "rgba() expects length of 8 characters (4 bytes)";
return;
}
const auto RGBA = std::stol(VALUEWITHOUTFUNC, nullptr, 16);
// now we need to RGBA -> ARGB. The config holds ARGB only.
CONFIGENTRY->intValue = (RGBA >> 8) + 0x1000000 * (RGBA & 0xFF);
} else if (VALUE.find("rgb(") == 0 && VALUE.find(")") == VALUE.length() - 1) {
const auto VALUEWITHOUTFUNC = VALUE.substr(4, VALUE.length() - 5);
if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 6) {
Debug::log(WARN, "invalid length %i for rgb", VALUEWITHOUTFUNC.length());
parseError = "rgb() expects length of 6 characters (3 bytes)";
return;
}
const auto RGB = std::stol(VALUEWITHOUTFUNC, nullptr, 16);
CONFIGENTRY->intValue = RGB + 0xFF000000; // 0xFF for opaque
} else if (VALUE.find("true") == 0 || VALUE.find("on") == 0 || VALUE.find("yes") == 0) {
CONFIGENTRY->intValue = 1;
} else if (VALUE.find("false") == 0 || VALUE.find("off") == 0 || VALUE.find("no") == 0) {
CONFIGENTRY->intValue = 0;
}
else
CONFIGENTRY->intValue = stol(VALUE);
} catch (...) {
CONFIGENTRY->intValue = configStringToInt(VALUE);
} catch (std::exception& e) {
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">. " + e.what();
}
} else if (CONFIGENTRY->floatValue != -__FLT_MAX__) {
try {
@@ -386,62 +353,7 @@ void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::s
void CConfigManager::handleRawExec(const std::string& command, const std::string& args) {
// Exec in the background dont wait for it.
std::string toExec = args;
if (g_pXWaylandManager->m_sWLRXWayland)
toExec = std::string("WAYLAND_DISPLAY=") + std::string(g_pCompositor->m_szWLDisplaySocket) + " DISPLAY=" + std::string(g_pXWaylandManager->m_sWLRXWayland->display_name) + " " + toExec;
else
toExec = std::string("WAYLAND_DISPLAY=") + std::string(g_pCompositor->m_szWLDisplaySocket) + " " + toExec;
Debug::log(LOG, "Config executing %s", toExec.c_str());
int socket[2];
if (pipe(socket) != 0) {
Debug::log(LOG, "Unable to create pipe for fork");
}
pid_t child, grandchild;
child = fork();
if (child < 0) {
close(socket[0]);
close(socket[1]);
Debug::log(LOG, "Fail to create the first fork");
return;
}
if (child == 0) {
// run in child
grandchild = fork();
sigset_t set;
sigemptyset(&set);
sigprocmask(SIG_SETMASK, &set, NULL);
if (grandchild == 0) {
// run in grandchild
close(socket[0]);
close(socket[1]);
execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr);
// exit grandchild
_exit(0);
}
close(socket[0]);
write(socket[1], &grandchild, sizeof(grandchild));
close(socket[1]);
// exit child
_exit(0);
}
// run in parent
close(socket[1]);
read(socket[0], &grandchild, sizeof(grandchild));
close(socket[0]);
// clear child and leave child to init
waitpid(child, NULL, 0);
if (child < 0) {
Debug::log(LOG, "Fail to create the second fork");
return;
}
Debug::log(LOG, "Process created with pid %d", grandchild);
g_pKeybindManager->spawn(args);
}
void CConfigManager::handleMonitor(const std::string& command, const std::string& args) {
@@ -756,6 +668,7 @@ bool windowRuleValid(const std::string& RULE) {
&& RULE.find("maxsize") != 0
&& RULE.find("pseudo") != 0
&& RULE.find("monitor") != 0
&& RULE.find("idleinhibit") != 0
&& RULE != "nofocus"
&& RULE != "noblur"
&& RULE != "noshadow"
@@ -769,7 +682,8 @@ bool windowRuleValid(const std::string& RULE) {
&& RULE != "windowdance"
&& RULE.find("animation") != 0
&& RULE.find("rounding") != 0
&& RULE.find("workspace") != 0);
&& RULE.find("workspace") != 0
&& RULE.find("bordercolor") != 0);
}
void CConfigManager::handleWindowRule(const std::string& command, const std::string& value) {
@@ -781,6 +695,13 @@ void CConfigManager::handleWindowRule(const std::string& command, const std::str
return;
}
if (RULE == "unset") {
std::erase_if(m_dWindowRules, [&] (const SWindowRule& other) {
return other.szValue == VALUE;
});
return;
}
// verify we support a rule
if (!windowRuleValid(RULE)) {
Debug::log(ERR, "Invalid rule found: %s", RULE.c_str());
@@ -795,7 +716,7 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
const auto RULE = value.substr(0, value.find_first_of(","));
const auto VALUE = value.substr(value.find_first_of(",") + 1);
if (!windowRuleValid(RULE)) {
if (!windowRuleValid(RULE) && RULE != "unset") {
Debug::log(ERR, "Invalid rulev2 found: %s", RULE.c_str());
parseError = "Invalid rulev2 found: " + RULE;
return;
@@ -811,8 +732,12 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
const auto CLASSPOS = VALUE.find("class:");
const auto X11POS = VALUE.find("xwayland:");
const auto FLOATPOS = VALUE.find("floating:");
const auto FULLSCREENPOS = VALUE.find("fullscreen:");
const auto PINNEDPOS = VALUE.find("pinned:");
if (TITLEPOS == std::string::npos && CLASSPOS == std::string::npos && X11POS == std::string::npos && FLOATPOS == std::string::npos) {
if (TITLEPOS == std::string::npos && CLASSPOS == std::string::npos &&
X11POS == std::string::npos && FLOATPOS == std::string::npos &&
FULLSCREENPOS == std::string::npos && PINNEDPOS == std::string::npos) {
Debug::log(ERR, "Invalid rulev2 syntax: %s", VALUE.c_str());
parseError = "Invalid rulev2 syntax: " + VALUE;
return;
@@ -827,6 +752,8 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
if (CLASSPOS > pos && CLASSPOS < min) min = CLASSPOS;
if (X11POS > pos && X11POS < min) min = X11POS;
if (FLOATPOS > pos && FLOATPOS < min) min = FLOATPOS;
if (FULLSCREENPOS > pos && FULLSCREENPOS < min) min = FULLSCREENPOS;
if (PINNEDPOS > pos && PINNEDPOS < min) min = PINNEDPOS;
result = result.substr(0, min - pos);
@@ -854,6 +781,49 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
rule.bFloating = extract(FLOATPOS + 9) == "1" ? 1 : 0;
}
if (FULLSCREENPOS != std::string::npos) {
rule.bFullscreen = extract(FULLSCREENPOS + 11) == "1" ? 1 : 0;
}
if (PINNEDPOS != std::string::npos) {
rule.bPinned = extract(PINNEDPOS + 7) == "1" ? 1 : 0;
}
if (RULE == "unset") {
std::erase_if(m_dWindowRules, [&](const SWindowRule& other) {
if (!other.v2) {
return other.szClass == rule.szClass && !rule.szClass.empty();
} else {
if (!rule.szClass.empty() && rule.szClass != other.szClass) {
return false;
}
if (!rule.szTitle.empty() && rule.szTitle != other.szTitle) {
return false;
}
if (rule.bX11 != -1 && rule.bX11 != other.bX11) {
return false;
}
if (rule.bFloating != -1 && rule.bFloating != other.bFloating) {
return false;
}
if (rule.bFullscreen != -1 && rule.bFullscreen != other.bFullscreen) {
return false;
}
if (rule.bPinned != -1 && rule.bPinned != other.bPinned) {
return false;
}
return true;
}
});
return;
}
m_dWindowRules.push_back(rule);
}
@@ -1036,7 +1006,7 @@ void CConfigManager::parseLine(std::string& line) {
}
size_t startPos = 0;
while ((startPos = line.find("##", startPos)) != std::string::npos) {
while ((startPos = line.find("##", startPos)) != std::string::npos && startPos < line.length() - 1 && startPos > 0) {
line.replace(startPos, 2, "#");
startPos++;
}
@@ -1196,13 +1166,6 @@ void CConfigManager::loadConfigLoadVars() {
// Calculate the internal vars
configValues["general:main_mod_internal"].intValue = g_pKeybindManager->stringToModMask(configValues["general:main_mod"].strValue);
const auto DAMAGETRACKINGMODE = g_pHyprRenderer->damageTrackingModeFromStr(configValues["general:damage_tracking"].strValue);
if (DAMAGETRACKINGMODE != DAMAGE_TRACKING_INVALID)
configValues["general:damage_tracking_internal"].intValue = DAMAGETRACKINGMODE;
else {
parseError = "invalid value for general:damage_tracking, supported: full, monitor, none";
configValues["general:damage_tracking_internal"].intValue = DAMAGE_TRACKING_NONE;
}
// parseError will be displayed next frame
if (parseError != "")
@@ -1448,6 +1411,16 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
if (pWindow->m_bIsFloating != rule.bFloating)
continue;
}
if (rule.bFullscreen != -1) {
if (pWindow->m_bIsFullscreen != rule.bFullscreen)
continue;
}
if (rule.bPinned != -1) {
if (pWindow->m_bPinned != rule.bPinned)
continue;
}
} catch (...) {
Debug::log(ERR, "Regex error at %s", rule.szValue.c_str());
continue;
@@ -1460,6 +1433,19 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
returns.push_back(rule);
}
const uint64_t PID = pWindow->getPID();
bool anyExecFound = false;
for (auto& er : execRequestedRules) {
if (er.iPid == PID) {
returns.push_back({er.szRule, "execRule"});
anyExecFound = true;
}
}
if (anyExecFound) // remove exec rules to unclog searches in the future, why have the garbage here.
execRequestedRules.erase(std::remove_if(execRequestedRules.begin(), execRequestedRules.end(), [&](const SExecRequestedRule& other) { return other.iPid == PID; }));
return returns;
}
@@ -1616,3 +1602,7 @@ CMonitor* CConfigManager::getBoundMonitorForWS(std::string wsname) {
return nullptr;
}
void CConfigManager::addExecRule(SExecRequestedRule rule) {
execRequestedRules.push_back(rule);
}

View File

@@ -48,17 +48,6 @@ struct SMonitorAdditionalReservedArea {
int right = 0;
};
struct SWindowRule {
std::string szRule;
std::string szValue;
bool v2 = false;
std::string szTitle;
std::string szClass;
int bX11 = -1; // -1 means "ANY"
int bFloating = -1;
};
struct SAnimationPropertyConfig {
bool overriden = true;
@@ -71,14 +60,19 @@ struct SAnimationPropertyConfig {
SAnimationPropertyConfig* pParentAnimation = nullptr;
};
struct SExecRequestedRule {
std::string szRule = "";
uint64_t iPid = 0;
};
class CVarList {
public:
CVarList(const std::string& in, long unsigned int lastArgNo = 0) {
CVarList(const std::string& in, long unsigned int lastArgNo = 0, const char separator = ',') {
std::string curitem = "";
std::string argZ = in;
auto nextItem = [&]() {
auto idx = lastArgNo != 0 && m_vArgs.size() >= lastArgNo - 1 ? std::string::npos : argZ.find_first_of(',');
auto idx = lastArgNo != 0 && m_vArgs.size() >= lastArgNo - 1 ? std::string::npos : argZ.find_first_of(separator);
if (idx != std::string::npos) {
curitem = argZ.substr(0, idx);
@@ -109,7 +103,13 @@ public:
return m_vArgs[idx];
}
private:
// for range-based loops
std::vector<std::string>::iterator begin() { return m_vArgs.begin(); }
std::vector<std::string>::const_iterator begin() const { return m_vArgs.begin(); }
std::vector<std::string>::iterator end() { return m_vArgs.end(); }
std::vector<std::string>::const_iterator end() const { return m_vArgs.end(); }
private:
std::vector<std::string> m_vArgs;
};
@@ -160,6 +160,8 @@ public:
SAnimationPropertyConfig* getAnimationPropertyConfig(const std::string&);
void addExecRule(SExecRequestedRule);
std::string configCurrentPath;
private:
@@ -179,6 +181,8 @@ private:
std::vector<std::pair<std::string, std::string>> boundWorkspaces;
std::vector<SExecRequestedRule> execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty
bool isFirstLaunch = true; // For exec-once
std::deque<SMonitorRule> m_dMonitorRules;

View File

@@ -68,14 +68,9 @@ R"#({
return result;
}
std::string clientsRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string result = "";
static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat format) {
if (format == HyprCtl::FORMAT_JSON) {
result += "[";
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bIsMapped) {
result += getFormat(
return getFormat(
R"#({
"address": "0x%x",
"at": [%i, %i],
@@ -94,20 +89,34 @@ R"#({
"fullscreen": %s,
"fullscreenMode": %i
},)#",
w.get(),
w,
(int)w->m_vRealPosition.goalv().x, (int)w->m_vRealPosition.goalv().y,
(int)w->m_vRealSize.goalv().x, (int)w->m_vRealSize.goalv().y,
w->m_iWorkspaceID, escapeJSONStrings(w->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName : std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID))).c_str(),
((int)w->m_bIsFloating == 1 ? "true" : "false"),
w->m_iMonitorID,
escapeJSONStrings(g_pXWaylandManager->getAppIDClass(w.get())).c_str(),
escapeJSONStrings(g_pXWaylandManager->getTitle(w.get())).c_str(),
escapeJSONStrings(g_pXWaylandManager->getAppIDClass(w)).c_str(),
escapeJSONStrings(g_pXWaylandManager->getTitle(w)).c_str(),
w->getPID(),
((int)w->m_bIsX11 == 1 ? "true" : "false"),
(w->m_bPinned ? "true" : "false"),
(w->m_bIsFullscreen ? "true" : "false"),
(w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0)
);
} else {
return getFormat("Window %x -> %s:\n\tat: %i,%i\n\tsize: %i,%i\n\tworkspace: %i (%s)\n\tfloating: %i\n\tmonitor: %i\n\tclass: %s\n\ttitle: %s\n\tpid: %i\n\txwayland: %i\n\tpinned: %i\n\tfullscreen: %i\n\tfullscreenmode: %i\n\n",
w, w->m_szTitle.c_str(), (int)w->m_vRealPosition.goalv().x, (int)w->m_vRealPosition.goalv().y, (int)w->m_vRealSize.goalv().x, (int)w->m_vRealSize.goalv().y, w->m_iWorkspaceID, (w->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName.c_str() : std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID)).c_str()), (int)w->m_bIsFloating, w->m_iMonitorID, g_pXWaylandManager->getAppIDClass(w).c_str(), g_pXWaylandManager->getTitle(w).c_str(), w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen, (w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0));
}
}
std::string clientsRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string result = "";
if (format == HyprCtl::FORMAT_JSON) {
result += "[";
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bIsMapped) {
result += getWindowData(w.get(), format);
}
}
@@ -119,9 +128,7 @@ R"#({
} else {
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bIsMapped) {
result += getFormat("Window %x -> %s:\n\tat: %i,%i\n\tsize: %i,%i\n\tworkspace: %i (%s)\n\tfloating: %i\n\tmonitor: %i\n\tclass: %s\n\ttitle: %s\n\tpid: %i\n\txwayland: %i\n\tpinned: %i\n\tfullscreen: %i\n\tfullscreenmode: %i\n\n",
w.get(), w->m_szTitle.c_str(), (int)w->m_vRealPosition.goalv().x, (int)w->m_vRealPosition.goalv().y, (int)w->m_vRealSize.goalv().x, (int)w->m_vRealSize.goalv().y, w->m_iWorkspaceID, (w->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName.c_str() : std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID)).c_str()), (int)w->m_bIsFloating, w->m_iMonitorID, g_pXWaylandManager->getAppIDClass(w.get()).c_str(), g_pXWaylandManager->getTitle(w.get()).c_str(), w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen, (w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0));
result += getWindowData(w.get(), format);
}
}
}
@@ -176,38 +183,12 @@ std::string activeWindowRequest(HyprCtl::eHyprCtlOutputFormat format) {
if (!g_pCompositor->windowValidMapped(PWINDOW))
return format == HyprCtl::FORMAT_JSON ? "{}" : "Invalid";
if (format == HyprCtl::FORMAT_JSON) {
return getFormat(
R"#({
"address": "0x%x",
"at": [%i, %i],
"size": [%i, %i],
"workspace": {
"id": %i,
"name": "%s"
},
"floating": %s,
"monitor": %i,
"class": "%s",
"title": "%s",
"pid": %i,
"xwayland": %s
})#",
PWINDOW,
(int)PWINDOW->m_vRealPosition.vec().x, (int)PWINDOW->m_vRealPosition.vec().y,
(int)PWINDOW->m_vRealSize.vec().x, (int)PWINDOW->m_vRealSize.vec().y,
PWINDOW->m_iWorkspaceID, escapeJSONStrings(PWINDOW->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_szName).c_str(),
((int)PWINDOW->m_bIsFloating == 1 ? "true" : "false"),
PWINDOW->m_iMonitorID,
escapeJSONStrings(g_pXWaylandManager->getAppIDClass(PWINDOW)).c_str(),
escapeJSONStrings(g_pXWaylandManager->getTitle(PWINDOW)).c_str(),
PWINDOW->getPID(),
((int)PWINDOW->m_bIsX11 == 1 ? "true" : "false")
);
} else {
return getFormat("Window %x -> %s:\n\tat: %i,%i\n\tsize: %i,%i\n\tworkspace: %i (%s)\n\tfloating: %i\n\tmonitor: %i\n\tclass: %s\n\ttitle: %s\n\tpid: %i\n\txwayland: %i\n\n",
PWINDOW, PWINDOW->m_szTitle.c_str(), (int)PWINDOW->m_vRealPosition.vec().x, (int)PWINDOW->m_vRealPosition.vec().y, (int)PWINDOW->m_vRealSize.vec().x, (int)PWINDOW->m_vRealSize.vec().y, PWINDOW->m_iWorkspaceID, (PWINDOW->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_szName.c_str()), (int)PWINDOW->m_bIsFloating, (int)PWINDOW->m_iMonitorID, g_pXWaylandManager->getAppIDClass(PWINDOW).c_str(), g_pXWaylandManager->getTitle(PWINDOW).c_str(), PWINDOW->getPID(), (int)PWINDOW->m_bIsX11);
}
auto result = getWindowData(PWINDOW, format);
if (format == HyprCtl::FORMAT_JSON)
result.pop_back();
return result;
}
std::string layersRequest(HyprCtl::eHyprCtlOutputFormat format) {
@@ -728,13 +709,13 @@ std::string dispatchGetOption(std::string request, HyprCtl::eHyprCtlOutputFormat
return "no such option";
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL)
return getFormat("option %s\n\tint: %i\n\tfloat: %f\n\tstr: \"%s\"", curitem.c_str(), PCFGOPT->intValue, PCFGOPT->floatValue, PCFGOPT->strValue.c_str());
return getFormat("option %s\n\tint: %lld\n\tfloat: %f\n\tstr: \"%s\"", curitem.c_str(), PCFGOPT->intValue, PCFGOPT->floatValue, PCFGOPT->strValue.c_str());
else {
return getFormat(
R"#(
{
"option": "%s",
"int": %i,
"int": %lld,
"float": %f,
"str": "%s"
}
@@ -743,6 +724,86 @@ R"#(
}
}
void createOutputIter(wlr_backend* backend, void* data) {
const auto DATA = (std::pair<std::string, bool>*)data;
if (DATA->second)
return;
if (DATA->first.empty() || DATA->first == "auto") {
if (wlr_backend_is_wl(backend)) {
wlr_wl_output_create(backend);
DATA->second = true;
} else if (wlr_backend_is_x11(backend)) {
wlr_x11_output_create(backend);
DATA->second = true;
} else if (wlr_backend_is_headless(backend)) {
wlr_headless_add_output(backend, 1920, 1080);
DATA->second = true;
}
} else {
if (wlr_backend_is_wl(backend) && DATA->first == "wayland") {
wlr_wl_output_create(backend);
DATA->second = true;
} else if (wlr_backend_is_x11(backend) && DATA->first == "x11") {
wlr_x11_output_create(backend);
DATA->second = true;
} else if (wlr_backend_is_headless(backend) && DATA->first == "headless") {
wlr_headless_add_output(backend, 1920, 1080);
DATA->second = true;
}
}
}
std::string dispatchOutput(std::string request) {
std::string curitem = "";
auto nextItem = [&]() {
auto idx = request.find_first_of(' ');
if (idx != std::string::npos) {
curitem = request.substr(0, idx);
request = request.substr(idx + 1);
} else {
curitem = request;
request = "";
}
curitem = removeBeginEndSpacesTabs(curitem);
};
nextItem();
nextItem();
const auto MODE = curitem;
nextItem();
const auto NAME = curitem;
if (MODE == "create" || MODE == "add") {
std::pair<std::string, bool> result = { NAME, false };
wlr_multi_for_each_backend(g_pCompositor->m_sWLRBackend, createOutputIter, &result);
if (!result.second)
return "no backend replied to the request";
} else if (MODE == "destroy" || MODE == "remove") {
const auto PMONITOR = g_pCompositor->getMonitorFromName(NAME);
if (!PMONITOR)
return "output not found";
if (!PMONITOR->createdByUser)
return "cannot remove a real display. Use the monitor keyword.";
wlr_output_destroy(PMONITOR->output);
}
return "ok";
}
std::string getReply(std::string request) {
auto format = HyprCtl::FORMAT_NORMAL;
@@ -786,6 +847,8 @@ std::string getReply(std::string request) {
return splashRequest();
else if (request == "cursorpos")
return cursorPosRequest(format);
else if (request.find("output") == 0)
return dispatchOutput(request);
else if (request.find("dispatch") == 0)
return dispatchRequest(request);
else if (request.find("keyword") == 0)

View File

@@ -6,6 +6,8 @@
#include "wlrunstable/wlr_ext_workspace_v1.hpp"
#include <utility>
#ifndef NDEBUG
#ifdef HYPRLAND_DEBUG
#define ISDEBUG true

View File

@@ -31,15 +31,17 @@ void Events::listener_newLayerSurface(wl_listener* listener, void* data) {
WLRLAYERSURFACE->output = PMONITOR->output;
}
const auto PMONITOR = (CMonitor*)g_pCompositor->getMonitorFromOutput(WLRLAYERSURFACE->output);
auto PMONITOR = (CMonitor*)g_pCompositor->getMonitorFromOutput(WLRLAYERSURFACE->output);
if (!WLRLAYERSURFACE->output || !PMONITOR || PMONITOR->pMirrorOf) {
PMONITOR = g_pCompositor->m_vMonitors.front().get();
WLRLAYERSURFACE->output = PMONITOR->output; // TODO: current mon
}
SLayerSurface* layerSurface = PMONITOR->m_aLayerSurfaceLists[WLRLAYERSURFACE->pending.layer].emplace_back(std::make_unique<SLayerSurface>()).get();
layerSurface->szNamespace = WLRLAYERSURFACE->_namespace;
if (!WLRLAYERSURFACE->output) {
WLRLAYERSURFACE->output = g_pCompositor->m_vMonitors.front()->output; // TODO: current mon
}
layerSurface->hyprListener_commitLayerSurface.initCallback(&WLRLAYERSURFACE->surface->events.commit, &Events::listener_commitLayerSurface, layerSurface, "layerSurface");
layerSurface->hyprListener_destroyLayerSurface.initCallback(&WLRLAYERSURFACE->events.destroy, &Events::listener_destroyLayerSurface, layerSurface, "layerSurface");
layerSurface->hyprListener_mapLayerSurface.initCallback(&WLRLAYERSURFACE->events.map, &Events::listener_mapLayerSurface, layerSurface, "layerSurface");

View File

@@ -106,9 +106,10 @@ void Events::listener_monitorFrame(void* owner, void* data) {
static std::chrono::high_resolution_clock::time_point endRenderOverlay = std::chrono::high_resolution_clock::now();
static auto *const PDEBUGOVERLAY = &g_pConfigManager->getConfigValuePtr("debug:overlay")->intValue;
static auto *const PDAMAGETRACKINGMODE = &g_pConfigManager->getConfigValuePtr("general:damage_tracking_internal")->intValue;
static auto *const PDAMAGETRACKINGMODE = &g_pConfigManager->getConfigValuePtr("debug:damage_tracking")->intValue;
static auto *const PDAMAGEBLINK = &g_pConfigManager->getConfigValuePtr("debug:damage_blink")->intValue;
static auto *const PNOVFR = &g_pConfigManager->getConfigValuePtr("misc:no_vfr")->intValue;
static auto *const PNODIRECTSCANOUT = &g_pConfigManager->getConfigValuePtr("misc:no_direct_scanout")->intValue;
static int damageBlinkCleanup = 0; // because double-buffered
@@ -154,6 +155,16 @@ void Events::listener_monitorFrame(void* owner, void* data) {
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
}
// Direct scanout first
if (!*PNODIRECTSCANOUT) {
if (g_pHyprRenderer->attemptDirectScanout(PMONITOR)) {
return;
} else if (g_pHyprRenderer->m_pLastScanout) {
Debug::log(LOG, "Left a direct scanout.");
g_pHyprRenderer->m_pLastScanout = nullptr;
}
}
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
@@ -232,11 +243,11 @@ void Events::listener_monitorFrame(void* owner, void* data) {
g_pHyprRenderer->renderAllClientsForMonitor(PMONITOR->ID, &now);
// if correct monitor draw hyprerror
if (PMONITOR->ID == 0)
if (PMONITOR == g_pCompositor->m_vMonitors.front().get())
g_pHyprError->draw();
// for drawing the debug overlay
if (PMONITOR->ID == 0 && *PDEBUGOVERLAY == 1) {
if (PMONITOR == g_pCompositor->m_vMonitors.front().get() && *PDEBUGOVERLAY == 1) {
startRenderOverlay = std::chrono::high_resolution_clock::now();
g_pDebugOverlay->draw();
endRenderOverlay = std::chrono::high_resolution_clock::now();
@@ -291,7 +302,7 @@ void Events::listener_monitorFrame(void* owner, void* data) {
if (*PDEBUGOVERLAY == 1) {
const float µs = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - startRender).count() / 1000.f;
g_pDebugOverlay->renderData(PMONITOR, µs);
if (PMONITOR->ID == 0) {
if (PMONITOR == g_pCompositor->m_vMonitors.front().get()) {
const float µsNoOverlay = µs - std::chrono::duration_cast<std::chrono::nanoseconds>(endRenderOverlay - startRenderOverlay).count() / 1000.f;
g_pDebugOverlay->renderDataNoOverlay(PMONITOR, µsNoOverlay);
} else {

View File

@@ -65,8 +65,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (PWINDOW->m_iX11Type == 2)
g_pCompositor->moveUnmanagedX11ToWindows(PWINDOW);
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
// Set all windows tiled regardless of anything
g_pXWaylandManager->setWindowStyleTiled(PWINDOW, WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP | WLR_EDGE_BOTTOM);
@@ -76,6 +74,9 @@ void Events::listener_mapWindow(void* owner, void* data) {
// checks if the window wants borders and sets the appriopriate flag
g_pXWaylandManager->checkBorders(PWINDOW);
// registers the animated vars and stuff
PWINDOW->onMap();
const auto PWINDOWSURFACE = g_pXWaylandManager->getWindowSurface(PWINDOW);
if (!PWINDOWSURFACE) {
@@ -112,7 +113,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(PWINDOW);
std::string requestedWorkspace = "";
bool workspaceSilent = false;
bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen || (!PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xdg->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL && PWINDOW->m_uSurface.xdg->toplevel->requested.fullscreen);
bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen || (!PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xdg->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL && PWINDOW->m_uSurface.xdg->toplevel->requested.fullscreen) || (PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xwayland->fullscreen);
bool shouldFocus = true;
bool workspaceSpecial = false;
@@ -160,48 +161,30 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_bIsPseudotiled = true;
} else if (r.szRule.find("nofocus") == 0) {
PWINDOW->m_bNoFocus = true;
} else if (r.szRule == "noblur") {
PWINDOW->m_sAdditionalConfigData.forceNoBlur = true;
} else if (r.szRule == "noborder") {
PWINDOW->m_sAdditionalConfigData.forceNoBorder = true;
} else if (r.szRule == "noshadow") {
PWINDOW->m_sAdditionalConfigData.forceNoShadow = true;
} else if (r.szRule == "fullscreen") {
requestsFullscreen = true;
} else if (r.szRule == "opaque") {
PWINDOW->m_sAdditionalConfigData.forceOpaque = true;
} else if (r.szRule == "windowdance") {
PWINDOW->m_sAdditionalConfigData.windowDanceCompat = true;
} else if (r.szRule == "forceinput") {
PWINDOW->m_sAdditionalConfigData.forceAllowsInput = true;
} else if (r.szRule == "pin") {
PWINDOW->m_bPinned = true;
} else if (r.szRule == "noanim") {
PWINDOW->m_sAdditionalConfigData.forceNoAnims = true;
} else if (r.szRule.find("rounding") == 0) {
try {
PWINDOW->m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
} catch (std::exception& e) {
Debug::log(ERR, "Rounding rule \"%s\" failed with: %s", r.szRule.c_str(), e.what());
}
} else if (r.szRule.find("opacity") == 0) {
try {
std::string alphaPart = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
} else if (r.szRule.find("idleinhibit") == 0) {
auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
if (alphaPart.contains(' ')) {
// we have a comma, 2 values
PWINDOW->m_sSpecialRenderData.alpha = std::stof(alphaPart.substr(0, alphaPart.find_first_of(' ')));
PWINDOW->m_sSpecialRenderData.alphaInactive = std::stof(alphaPart.substr(alphaPart.find_first_of(' ') + 1));
} else {
PWINDOW->m_sSpecialRenderData.alpha = std::stof(alphaPart);
}
} catch(std::exception& e) {
Debug::log(ERR, "Opacity rule \"%s\" failed with: %s", r.szRule.c_str(), e.what());
if (IDLERULE == "none") {
PWINDOW->m_eIdleInhibitMode = IDLEINHIBIT_NONE;
} else if (IDLERULE == "always") {
PWINDOW->m_eIdleInhibitMode = IDLEINHIBIT_ALWAYS;
} else if (IDLERULE == "focus") {
PWINDOW->m_eIdleInhibitMode = IDLEINHIBIT_FOCUS;
} else if (IDLERULE == "fullscreen") {
PWINDOW->m_eIdleInhibitMode = IDLEINHIBIT_FULLSCREEN;
} else {
Debug::log(ERR, "Rule idleinhibit: unknown mode %s", IDLERULE.c_str());
}
} else if (r.szRule.find("animation") == 0) {
auto STYLE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
PWINDOW->m_sAdditionalConfigData.animationStyle = STYLE;
}
PWINDOW->applyDynamicRule(r);
}
// disallow tiled pinned
@@ -244,7 +227,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (!PWORKSPACE) {
std::string workspaceName = "";
int workspaceID = 0;
if (requestedWorkspace.find("name:") == 0) {
workspaceName = requestedWorkspace.substr(5);
workspaceID = g_pCompositor->getNextAvailableNamedWorkspace();
@@ -332,9 +315,15 @@ void Events::listener_mapWindow(void* owner, void* data) {
}
} else if (r.szRule.find("move") == 0) {
try {
const auto VALUE = r.szRule.substr(r.szRule.find(" ") + 1);
const auto POSXSTR = VALUE.substr(0, VALUE.find(" "));
const auto POSYSTR = VALUE.substr(VALUE.find(" ") + 1);
auto value = r.szRule.substr(r.szRule.find(" ") + 1);
const bool CURSOR = value.find("cursor") == 0;
if (CURSOR)
value = value.substr(value.find_first_of(' ') + 1);
const auto POSXSTR = value.substr(0, value.find(" "));
const auto POSYSTR = value.substr(value.find(" ") + 1);
int posX = 0;
int posY = 0;
@@ -343,16 +332,36 @@ void Events::listener_mapWindow(void* owner, void* data) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
const auto POSXRAW = POSXSTR.substr(5);
posX = PMONITOR->vecSize.x - (!POSXRAW.contains('%') ? std::stoi(POSXRAW) : std::stoi(POSXRAW.substr(0, POSXRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.x);
} else {
if (CURSOR)
Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!");
} else if (!CURSOR) {
posX = !POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stoi(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.x;
} else {
// cursor
if (POSXSTR == "cursor") {
posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x;
} else {
posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x + (!POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stoi(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goalv().x);
}
}
if (POSYSTR.find("100%-") == 0) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
const auto POSYRAW = POSYSTR.substr(5);
posY = PMONITOR->vecSize.y - (!POSYRAW.contains('%') ? std::stoi(POSYRAW) : std::stoi(POSYRAW.substr(0, POSYRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.y);
} else {
if (CURSOR)
Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!");
} else if (!CURSOR) {
posY = !POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stoi(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.y;
} else {
// cursor
if (POSYSTR == "cursor") {
posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y;
} else {
posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y + (!POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stoi(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goalv().y);
}
}
Debug::log(LOG, "Rule move, applying to window %x", PWINDOW);
@@ -524,6 +533,9 @@ void Events::listener_mapWindow(void* owner, void* data) {
auto workspaceID = requestedWorkspace != "" ? requestedWorkspace : PWORKSPACE->m_szName;
g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", getFormat("%x,%s,%s,%s", PWINDOW, workspaceID.c_str(), g_pXWaylandManager->getAppIDClass(PWINDOW).c_str(), PWINDOW->m_szTitle.c_str())});
// recalc the values for this window
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
}
void Events::listener_unmapWindow(void* owner, void* data) {
@@ -607,9 +619,6 @@ void Events::listener_unmapWindow(void* owner, void* data) {
Debug::log(LOG, "Unmapped was not focused, ignoring a refocus.");
}
// update lastwindow after focus
PWINDOW->onUnmap();
Debug::log(LOG, "Destroying the SubSurface tree of unmapped window %x", PWINDOW);
SubsurfaceTree::destroySurfaceTree(PWINDOW->m_pSurfaceTree);
@@ -642,6 +651,9 @@ void Events::listener_unmapWindow(void* owner, void* data) {
// force report all sizes (QT sometimes has an issue with this)
g_pCompositor->forceReportSizesToWindowsOnWorkspace(PWINDOW->m_iWorkspaceID);
// update lastwindow after focus
PWINDOW->onUnmap();
}
void Events::listener_commitWindow(void* owner, void* data) {
@@ -694,6 +706,8 @@ void Events::listener_setTitleWindow(void* owner, void* data) {
if (PWINDOW == g_pCompositor->m_pLastWindow) // if it's the active, let's post an event to update others
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", g_pXWaylandManager->getAppIDClass(PWINDOW) + "," + PWINDOW->m_szTitle});
PWINDOW->updateDynamicRules();
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
PWINDOW->updateToplevel();
Debug::log(LOG, "Window %x set title to %s", PWINDOW, PWINDOW->m_szTitle.c_str());
@@ -774,7 +788,7 @@ void Events::listener_configureX11(void* owner, void* data) {
g_pHyprRenderer->damageWindow(PWINDOW);
if (!PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen) {
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.vec());
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv(), true);
g_pInputManager->refocus();
g_pHyprRenderer->damageWindow(PWINDOW);
return;
@@ -825,6 +839,12 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
else
PWINDOW->setHidden(true);
if (PWINDOW->m_bIsFullscreen || !PWINDOW->m_bIsFloating) {
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv(), true);
g_pHyprRenderer->damageWindow(PWINDOW);
return;
}
if (abs(std::floor(POS.x) - PWINDOW->m_uSurface.xwayland->x) > 2 || abs(std::floor(POS.y) - PWINDOW->m_uSurface.xwayland->y) > 2 || abs(std::floor(SIZ.x) - PWINDOW->m_uSurface.xwayland->width) > 2 || abs(std::floor(SIZ.y) - PWINDOW->m_uSurface.xwayland->height) > 2) {
Debug::log(LOG, "Unmanaged window %x requests geometry update to %i %i %i %i", PWINDOW, (int)PWINDOW->m_uSurface.xwayland->x, (int)PWINDOW->m_uSurface.xwayland->y, (int)PWINDOW->m_uSurface.xwayland->width, (int)PWINDOW->m_uSurface.xwayland->height);
@@ -908,14 +928,14 @@ void Events::listener_requestMinimize(void* owner, void* data) {
Debug::log(LOG, "Minimize request for %x", PWINDOW);
// if (PWINDOW->m_bIsX11) {
// if (!PWINDOW->m_bMappedX11 || PWINDOW->m_iX11Type != 1)
// return;
if (PWINDOW->m_bIsX11) {
if (!PWINDOW->m_bMappedX11 || PWINDOW->m_iX11Type != 1)
return;
// const auto E = (wlr_xwayland_minimize_event*)data;
const auto E = (wlr_xwayland_minimize_event*)data;
// wlr_xwayland_surface_set_minimized(PWINDOW->m_uSurface.xwayland, E->minimize && g_pCompositor->m_pLastWindow != PWINDOW); // fucking DXVK
// }
wlr_xwayland_surface_set_minimized(PWINDOW->m_uSurface.xwayland, E->minimize && g_pCompositor->m_pLastWindow != PWINDOW); // fucking DXVK
}
}
void Events::listener_requestMove(void* owner, void* data) {

View File

@@ -12,8 +12,6 @@ void CAnimatedVariable::create(ANIMATEDVARTYPE type, SAnimationPropertyConfig* p
m_pConfig = pAnimConfig;
m_pWindow = pWindow;
g_pAnimationManager->m_lAnimatedVariables.push_back(this);
m_bDummy = false;
}
@@ -56,8 +54,20 @@ CAnimatedVariable::~CAnimatedVariable() {
void CAnimatedVariable::unregister() {
g_pAnimationManager->m_lAnimatedVariables.remove(this);
m_bIsRegistered = false;
}
void CAnimatedVariable::registerVar() {
if (!m_bIsRegistered)
g_pAnimationManager->m_lAnimatedVariables.push_back(this);
m_bIsRegistered = true;
}
int CAnimatedVariable::getDurationLeftMs() {
return std::max((int)(m_pConfig->pValues->internalSpeed * 100) - (int)std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - animationBegin).count(), 0);
}
float CAnimatedVariable::getPercent() {
const auto DURATIONPASSED = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - animationBegin).count();
return std::clamp((DURATIONPASSED / 100.f) / m_pConfig->pValues->internalSpeed, 0.f, 1.f);
}

View File

@@ -21,6 +21,7 @@ class CAnimationManager;
class CWorkspace;
struct SLayerSurface;
struct SAnimationPropertyConfig;
class CHyprRenderer;
class CAnimatedVariable {
public:
@@ -32,6 +33,7 @@ public:
~CAnimatedVariable();
void unregister();
void registerVar();
// gets the current vector value (real time)
const Vector2D& vec() const {
@@ -67,18 +69,24 @@ public:
m_vGoal = v;
animationBegin = std::chrono::system_clock::now();
m_vBegun = m_vValue;
onAnimationBegin();
}
void operator=(const float& v) {
m_fGoal = v;
animationBegin = std::chrono::system_clock::now();
m_fBegun = m_fValue;
onAnimationBegin();
}
void operator=(const CColor& v) {
m_cGoal = v;
animationBegin = std::chrono::system_clock::now();
m_cBegun = m_cValue;
onAnimationBegin();
}
// Sets the actual stored value, without affecting the goal, but resets the timer
@@ -86,6 +94,8 @@ public:
m_vValue = v;
animationBegin = std::chrono::system_clock::now();
m_vBegun = m_vValue;
onAnimationBegin();
}
// Sets the actual stored value, without affecting the goal, but resets the timer
@@ -93,6 +103,8 @@ public:
m_fValue = v;
animationBegin = std::chrono::system_clock::now();
m_vBegun = m_vValue;
onAnimationBegin();
}
// Sets the actual stored value, without affecting the goal, but resets the timer
@@ -100,6 +112,8 @@ public:
m_cValue = v;
animationBegin = std::chrono::system_clock::now();
m_vBegun = m_vValue;
onAnimationBegin();
}
// Sets the actual value and goal
@@ -138,7 +152,7 @@ public:
return false; // just so that the warning is suppressed
}
void warp() {
void warp(bool endCallback = true) {
switch (m_eVarType) {
case AVARTYPE_FLOAT: {
m_fValue = m_fGoal;
@@ -155,6 +169,9 @@ public:
default:
UNREACHABLE();
}
if (endCallback)
onAnimationEnd();
}
void setConfig(SAnimationPropertyConfig* pConfig) {
@@ -167,6 +184,27 @@ public:
int getDurationLeftMs();
/* returns the spent (completion) % */
float getPercent();
/* sets a function to be ran when the animation finishes.
if an animation is not running, runs instantly.
if "remove" is set to true, will remove the callback when ran. */
void setCallbackOnEnd(std::function<void(void* thisptr)> func, bool remove = true) {
m_fEndCallback = func;
m_bRemoveEndAfterRan = remove;
if (!isBeingAnimated())
onAnimationEnd();
}
/* sets a function to be ran when an animation is started.
if "remove" is set to true, will remove the callback when ran. */
void setCallbackOnBegin(std::function<void(void* thisptr)> func, bool remove = true) {
m_fBeginCallback = func;
m_bRemoveBeginAfterRan = remove;
}
private:
Vector2D m_vValue = Vector2D(0,0);
@@ -189,13 +227,37 @@ private:
SAnimationPropertyConfig* m_pConfig = nullptr;
bool m_bDummy = true;
bool m_bIsRegistered = false;
std::chrono::system_clock::time_point animationBegin;
ANIMATEDVARTYPE m_eVarType = AVARTYPE_INVALID;
AVARDAMAGEPOLICY m_eDamagePolicy = AVARDAMAGE_INVALID;
bool m_bRemoveEndAfterRan = true;
bool m_bRemoveBeginAfterRan = true;
std::function<void(void* thisptr)> m_fEndCallback;
std::function<void(void* thisptr)> m_fBeginCallback;
// methods
void onAnimationEnd() {
if (m_fEndCallback) {
m_fEndCallback(this);
if (m_bRemoveEndAfterRan)
m_fEndCallback = nullptr; // reset
}
}
void onAnimationBegin() {
if (m_fBeginCallback) {
m_fBeginCallback(this);
if (m_bRemoveBeginAfterRan)
m_fBeginCallback = nullptr; // reset
}
}
friend class CAnimationManager;
friend class CWorkspace;
friend struct SLayerSurface;
friend class CHyprRenderer;
};

View File

@@ -5,6 +5,31 @@
#include <sys/utsname.h>
#include <iomanip>
#if defined(__DragonFly__) || defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
# include <sys/sysctl.h>
# if defined(__DragonFly__)
# include <sys/kinfo.h> // struct kinfo_proc
# elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
# include <sys/user.h> // struct kinfo_proc
# endif
# if defined(__NetBSD__)
# undef KERN_PROC
# define KERN_PROC KERN_PROC2
# define KINFO_PROC struct kinfo_proc2
# else
# define KINFO_PROC struct kinfo_proc
# endif
# if defined(__DragonFly__)
# define KP_PPID(kp) kp.kp_ppid
# elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
# define KP_PPID(kp) kp.ki_ppid
# else
# define KP_PPID(kp) kp.p_ppid
# endif
#endif
static const float transforms[][9] = {{
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
@@ -120,6 +145,9 @@ void scaleBox(wlr_box* box, float scale) {
}
std::string removeBeginEndSpacesTabs(std::string str) {
if (str.empty())
return str;
int countBefore = 0;
while (str[countBefore] == ' ' || str[countBefore] == '\t') {
countBefore++;
@@ -369,6 +397,25 @@ void matrixProjection(float mat[9], int w, int h, wl_output_transform tr) {
}
int64_t getPPIDof(int64_t pid) {
#if defined(KERN_PROC_PID)
int mib[] = {
CTL_KERN,
KERN_PROC,
KERN_PROC_PID,
(int)pid,
# if defined(__NetBSD__) || defined(__OpenBSD__)
sizeof(KINFO_PROC),
1,
# endif
};
u_int miblen = sizeof(mib) / sizeof(mib[0]);
KINFO_PROC kp;
size_t sz = sizeof(KINFO_PROC);
if (sysctl(mib, miblen, &kp, &sz, NULL, 0) != -1)
return KP_PPID(kp);
return 0;
#else
std::string dir = "/proc/" + std::to_string(pid) + "/status";
FILE* infile;
@@ -401,4 +448,41 @@ int64_t getPPIDof(int64_t pid) {
} catch (std::exception& e) {
return 0;
}
#endif
}
int64_t configStringToInt(const std::string& VALUE) {
if (VALUE.find("0x") == 0) {
// Values with 0x are hex
const auto VALUEWITHOUTHEX = VALUE.substr(2);
return stol(VALUEWITHOUTHEX, nullptr, 16);
} else if (VALUE.find("rgba(") == 0 && VALUE.find(")") == VALUE.length() - 1) {
const auto VALUEWITHOUTFUNC = VALUE.substr(5, VALUE.length() - 6);
if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 8) {
Debug::log(WARN, "invalid length %i for rgba", VALUEWITHOUTFUNC.length());
throw std::invalid_argument("rgba() expects length of 8 characters (4 bytes)");
}
const auto RGBA = std::stol(VALUEWITHOUTFUNC, nullptr, 16);
// now we need to RGBA -> ARGB. The config holds ARGB only.
return (RGBA >> 8) + 0x1000000 * (RGBA & 0xFF);
} else if (VALUE.find("rgb(") == 0 && VALUE.find(")") == VALUE.length() - 1) {
const auto VALUEWITHOUTFUNC = VALUE.substr(4, VALUE.length() - 5);
if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 6) {
Debug::log(WARN, "invalid length %i for rgb", VALUEWITHOUTFUNC.length());
throw std::invalid_argument("rgb() expects length of 6 characters (3 bytes)");
}
const auto RGB = std::stol(VALUEWITHOUTFUNC, nullptr, 16);
return RGB + 0xFF000000; // 0xFF for opaque
} else if (VALUE.find("true") == 0 || VALUE.find("on") == 0 || VALUE.find("yes") == 0) {
return 1;
} else if (VALUE.find("false") == 0 || VALUE.find("off") == 0 || VALUE.find("no") == 0) {
return 0;
}
return stol(VALUE);
}

View File

@@ -15,6 +15,7 @@ float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Ve
void logSystemInfo();
std::string execAndGet(const char*);
int64_t getPPIDof(int64_t pid);
int64_t configStringToInt(const std::string&);
float getPlusMinusKeywordResult(std::string in, float relative);

View File

@@ -8,6 +8,9 @@ void CMonitor::onConnect(bool noRule) {
szName = output->name;
if (!wlr_backend_is_drm(output->backend))
createdByUser = true; // should be true. WL, X11 and Headless backends should be addable / removable
// get monitor rule that matches
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(output->name, output->description ? output->description : "");

View File

@@ -40,6 +40,7 @@ public:
bool dpmsStatus = true;
bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
bool createdByUser = false;
// mirroring
CMonitor* pMirrorOf = nullptr;

View File

@@ -4,4 +4,5 @@
SLayerSurface::SLayerSurface() {
alpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), nullptr, AVARDAMAGE_ENTIRE);
alpha.m_pLayer = this;
alpha.registerVar();
}

View File

@@ -31,6 +31,9 @@ CWorkspace::CWorkspace(int monitorID, std::string name, bool special) {
m_fAlpha.create(AVARTYPE_FLOAT, special ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspace") : g_pConfigManager->getAnimationPropertyConfig("workspaces"), nullptr, AVARDAMAGE_ENTIRE);
m_fAlpha.setValueAndWarp(255.f);
m_vRenderOffset.registerVar();
m_fAlpha.registerVar();
g_pEventManager->postEvent({"createworkspace", m_szName}, true);
}

View File

@@ -133,6 +133,11 @@ struct wlr_xwayland_surface_configure_event {
uint16_t mask; // xcb_config_window_t
};
struct wlr_xwayland_minimize_event {
struct wlr_xwayland_surface *surface;
bool minimize;
};
inline void wlr_xwayland_destroy(wlr_xwayland*) { }
inline void wlr_xwayland_surface_configure(wlr_xwayland_surface*, int, int, int, int) { }
@@ -149,4 +154,8 @@ inline void wlr_xwayland_surface_close(wlr_xwayland_surface*) { }
inline void wlr_xwayland_surface_set_fullscreen(wlr_xwayland_surface*, bool) { }
inline void wlr_xwayland_surface_set_minimized(wlr_xwayland_surface *, bool) {}
inline void wlr_xwayland_surface_set_minimized(wlr_xwayland_surface *, bool) { }
inline bool wlr_backend_is_x11(void*) { return false; }
inline void wlr_x11_output_create(void*) { }

View File

@@ -67,10 +67,10 @@ void CHyprError::createQueued() {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
#ifndef GLES2
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
#endif
#ifndef GLES2
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
#endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);

View File

@@ -99,10 +99,15 @@ extern "C" {
#include <wlr/types/wlr_text_input_v3.h>
#include <wlr/types/wlr_touch.h>
#include <wlr/types/wlr_switch.h>
#include <wlr/config.h>
#include <wlr/backend/headless.h>
#include <wlr/backend/multi.h>
#include <wlr/backend/wayland.h>
#include <drm_fourcc.h>
#ifndef NO_XWAYLAND
#include <wlr/backend/x11.h>
#include <wlr/xwayland.h>
#include <X11/Xproto.h>
#endif
@@ -133,7 +138,4 @@ extern "C" {
#include "helpers/Vector2D.hpp"
#include "ext-workspace-unstable-v1-protocol.h"
#include <algorithm>
#include <utility>
#include "ext-workspace-unstable-v1-protocol.h"

View File

@@ -134,6 +134,8 @@ void IHyprLayout::onBeginDragWindow() {
return;
}
g_pInputManager->setCursorImageUntilUnset("hand1");
DRAGGINGWINDOW->m_vRealPosition.setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsMove"));
DRAGGINGWINDOW->m_vRealSize.setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsMove"));
@@ -181,12 +183,17 @@ void IHyprLayout::onEndDragWindow() {
if (!g_pCompositor->windowValidMapped(DRAGGINGWINDOW))
return;
g_pInputManager->unsetCursorImage();
if (DRAGGINGWINDOW->m_bDraggingTiled) {
DRAGGINGWINDOW->m_bIsFloating = false;
g_pInputManager->refocus();
changeWindowFloatingMode(DRAGGINGWINDOW);
}
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
g_pCompositor->focusWindow(DRAGGINGWINDOW);
}
void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
@@ -296,11 +303,11 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
pWindow->moveToWorkspace(PNEWMON->activeWorkspace);
// save real pos cuz the func applies the default 5,5 mid
const auto PSAVEDPOS = pWindow->m_vRealPosition.vec();
const auto PSAVEDSIZE = pWindow->m_vRealSize.vec();
const auto PSAVEDPOS = pWindow->m_vRealPosition.goalv();
const auto PSAVEDSIZE = pWindow->m_vRealSize.goalv();
// if the window is pseudo, update its size
pWindow->m_vPseudoSize = pWindow->m_vRealSize.vec();
pWindow->m_vPseudoSize = pWindow->m_vRealSize.goalv();
pWindow->m_vLastFloatingSize = PSAVEDSIZE;
@@ -318,16 +325,16 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
if (pWindow == g_pCompositor->m_pLastWindow)
m_pLastTiledWindow = pWindow;
} else {
pWindow->m_vSize = pWindow->m_vRealSize.vec();
pWindow->m_vPosition = pWindow->m_vRealPosition.vec();
onWindowRemovedTiling(pWindow);
g_pCompositor->moveWindowToTop(pWindow);
pWindow->m_vRealPosition = pWindow->m_vRealPosition.vec() + (pWindow->m_vRealSize.vec() - pWindow->m_vLastFloatingSize) / 2.f;
pWindow->m_vRealPosition = pWindow->m_vRealPosition.goalv() + (pWindow->m_vRealSize.goalv() - pWindow->m_vLastFloatingSize) / 2.f;
pWindow->m_vRealSize = pWindow->m_vLastFloatingSize;
pWindow->m_vSize = pWindow->m_vRealSize.goalv();
pWindow->m_vPosition = pWindow->m_vRealPosition.goalv();
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID));
pWindow->m_sSpecialRenderData.rounding = true;

View File

@@ -20,6 +20,16 @@ int CHyprMasterLayout::getNodesOnWorkspace(const int& ws) {
return no;
}
int CHyprMasterLayout::getMastersOnWorkspace(const int& ws) {
int no = 0;
for (auto& n : m_lMasterNodesData) {
if (n.workspaceID == ws && n.isMaster)
no++;
}
return no;
}
std::string CHyprMasterLayout::getLayoutName() {
return "Master";
}
@@ -104,10 +114,12 @@ void CHyprMasterLayout::onWindowRemovedTiling(CWindow* pWindow) {
if (pWindow->m_bIsFullscreen)
g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL);
if (PNODE->isMaster) {
const auto MASTERSLEFT = getMastersOnWorkspace(PNODE->workspaceID);
if (PNODE->isMaster && MASTERSLEFT < 2) {
// find new one
for (auto& nd : m_lMasterNodesData) {
if (!nd.isMaster) {
if (!nd.isMaster && nd.workspaceID == PNODE->workspaceID) {
nd.isMaster = true;
break;
}
@@ -116,6 +128,15 @@ void CHyprMasterLayout::onWindowRemovedTiling(CWindow* pWindow) {
m_lMasterNodesData.remove(*PNODE);
if (getMastersOnWorkspace(PNODE->workspaceID) == getNodesOnWorkspace(PNODE->workspaceID) && MASTERSLEFT > 1) {
for (auto it = m_lMasterNodesData.rbegin(); it != m_lMasterNodesData.rend(); it++) {
if (it->workspaceID == PNODE->workspaceID) {
it->isMaster = false;
break;
}
}
}
recalculateMonitor(pWindow->m_iMonitorID);
}
@@ -169,32 +190,52 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
if (!PMASTERNODE)
return;
const auto MASTERS = getMastersOnWorkspace(PWORKSPACE->m_iID);
if (getNodesOnWorkspace(PWORKSPACE->m_iID) < 2) {
PMASTERNODE->position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition;
PMASTERNODE->size = Vector2D(PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x, PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y);
applyNodeDataToWindow(PMASTERNODE);
return;
} else {
PMASTERNODE->position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition;
PMASTERNODE->size = Vector2D((PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x) * PMASTERNODE->percMaster, PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y);
float heightLeft = PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y;
int nodesLeft = MASTERS;
float nextY = 0;
for (auto& n : m_lMasterNodesData) {
if (n.workspaceID == PWORKSPACE->m_iID && n.isMaster) {
n.position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition + Vector2D(0, nextY);
float HEIGHT = nodesLeft > 1 ? heightLeft / nodesLeft * n.percSize : heightLeft;
if (HEIGHT > heightLeft * 0.9f && nodesLeft > 1)
HEIGHT = heightLeft * 0.9f;
n.size = Vector2D((PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x) * PMASTERNODE->percMaster, HEIGHT);
nodesLeft--;
heightLeft -= HEIGHT;
nextY += HEIGHT;
applyNodeDataToWindow(&n);
}
}
}
const auto SLAVESIZE = 1.f / (getNodesOnWorkspace(PWORKSPACE->m_iID) - 1) * (PMASTERNODE->size.y);
int slavesDone = 0;
float heightLeft = PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y;
int slavesLeft = getNodesOnWorkspace(PWORKSPACE->m_iID) - MASTERS;
float nextY = 0;
for (auto& nd : m_lMasterNodesData) {
if (nd.workspaceID != PWORKSPACE->m_iID)
if (nd.workspaceID != PWORKSPACE->m_iID || nd.isMaster)
continue;
if (nd == *PMASTERNODE) {
applyNodeDataToWindow(PMASTERNODE);
continue;
}
nd.position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition + Vector2D(PMASTERNODE->percMaster * PMONITOR->vecSize.x, nextY);
float HEIGHT = slavesLeft > 1 ? heightLeft / slavesLeft * nd.percSize : heightLeft;
if (HEIGHT > heightLeft * 0.9f && slavesLeft > 1)
HEIGHT = heightLeft * 0.9f;
nd.size = Vector2D(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PMONITOR->vecReservedTopLeft.x - PMASTERNODE->size.x, HEIGHT);
nd.position = Vector2D(PMASTERNODE->size.x + PMASTERNODE->position.x, slavesDone * SLAVESIZE + PMASTERNODE->position.y);
nd.size = Vector2D(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PMONITOR->vecReservedTopLeft.x - PMASTERNODE->size.x, SLAVESIZE);
slavesDone++;
slavesLeft--;
heightLeft -= HEIGHT;
nextY += HEIGHT;
applyNodeDataToWindow(&nd);
}
@@ -309,13 +350,12 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow* p
const auto PNODE = getNodeFromWindow(PWINDOW);
if (!PNODE) {
PWINDOW->m_vRealSize = Vector2D(std::max((PWINDOW->m_vRealSize.goalv() + pixResize).x, 20.0), std::max((PWINDOW->m_vRealSize.goalv() + pixResize).y, 20.0));
PWINDOW->m_vRealSize = Vector2D(std::max((PWINDOW->m_vRealSize.goalv() + pixResize).x, 20.0), std::max((PWINDOW->m_vRealSize.goalv() + pixResize).y, 20.0));
PWINDOW->updateWindowDecos();
return;
}
// get master
const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID);
// get monitor
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
if (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) < 2)
@@ -323,11 +363,24 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow* p
m_bForceWarps = true;
float delta = pixResize.x / PMONITOR->vecSize.x;
double delta = pixResize.x / PMONITOR->vecSize.x;
PMASTER->percMaster += delta;
for (auto& n : m_lMasterNodesData) {
if (n.isMaster)
n.percMaster = std::clamp(n.percMaster + delta, 0.05, 0.95);
}
std::clamp(PMASTER->percMaster, 0.05f, 0.95f);
// check the up/down resize
if (pixResize.y != 0) {
if (PNODE->isMaster && getMastersOnWorkspace(PNODE->workspaceID) > 1) {
// check master size
const auto SIZEY = (PMONITOR->vecSize.y - PMONITOR->vecReservedTopLeft.y - PMONITOR->vecReservedBottomRight.y) / getMastersOnWorkspace(PNODE->workspaceID);
PNODE->percSize = std::clamp(PNODE->percSize + pixResize.y / SIZEY, 0.05, 1.95);
} else if (!PNODE->isMaster && (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) - getMastersOnWorkspace(PNODE->workspaceID)) > 1) {
const auto SIZEY = (PMONITOR->vecSize.y - PMONITOR->vecReservedTopLeft.y - PMONITOR->vecReservedBottomRight.y) / getNodesOnWorkspace(PNODE->workspaceID);
PNODE->percSize = std::clamp(PNODE->percSize + pixResize.y / SIZEY, 0.05, 1.95);
}
}
recalculateMonitor(PMONITOR->ID);
@@ -542,9 +595,11 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
};
if (message == "swapwithmaster") {
const auto PWINDOW = header.pWindow;
if (!PWINDOW)
return 0;
if (!isWindowTiled(PWINDOW))
return 0;
@@ -557,14 +612,34 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
switchToWindow(PWINDOW);
return 0;
} else if (message == "focusmaster") {
const auto PWINDOW = header.pWindow;
if (!PWINDOW)
return 0;
const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID);
if (!PMASTER || PMASTER->pWindow == PWINDOW)
return 0;
switchToWindow(PMASTER->pWindow);
return 0;
} else if (message == "cyclenext") {
const auto PWINDOW = header.pWindow;
if (!PWINDOW)
return 0;
switchToWindow(getNextWindow(PWINDOW, true));
} else if (message == "cycleprev") {
const auto PWINDOW = header.pWindow;
if (!PWINDOW)
return 0;
switchToWindow(getNextWindow(PWINDOW, false));
} else if (message == "swapnext") {
if (!g_pCompositor->windowValidMapped(header.pWindow))
@@ -596,6 +671,64 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
switchWindows(header.pWindow, PWINDOWTOSWAPWITH);
g_pCompositor->focusWindow(header.pWindow);
}
} else if (message == "addmaster") {
if (!g_pCompositor->windowValidMapped(header.pWindow))
return 0;
if (header.pWindow->m_bIsFloating)
return 0;
const auto PNODE = getNodeFromWindow(header.pWindow);
const auto WINDOWS = getNodesOnWorkspace(header.pWindow->m_iWorkspaceID);
const auto MASTERS = getMastersOnWorkspace(header.pWindow->m_iWorkspaceID);
if (MASTERS + 2 > WINDOWS)
return 0;
if (!PNODE || PNODE->isMaster) {
// first non-master node
for (auto& n : m_lMasterNodesData) {
if (n.workspaceID == header.pWindow->m_iWorkspaceID && !n.isMaster) {
n.isMaster = true;
break;
}
}
} else {
PNODE->isMaster = true;
}
recalculateMonitor(header.pWindow->m_iMonitorID);
} else if (message == "removemaster") {
if (!g_pCompositor->windowValidMapped(header.pWindow))
return 0;
if (header.pWindow->m_bIsFloating)
return 0;
const auto PNODE = getNodeFromWindow(header.pWindow);
const auto WINDOWS = getNodesOnWorkspace(header.pWindow->m_iWorkspaceID);
const auto MASTERS = getMastersOnWorkspace(header.pWindow->m_iWorkspaceID);
if (WINDOWS < 2 || MASTERS < 2)
return 0;
if (!PNODE || !PNODE->isMaster) {
// first non-master node
for (auto it = m_lMasterNodesData.rbegin(); it != m_lMasterNodesData.rend(); it++) {
if (it->workspaceID == header.pWindow->m_iWorkspaceID && it->isMaster) {
it->isMaster = false;
break;
}
}
} else {
PNODE->isMaster = false;
}
recalculateMonitor(header.pWindow->m_iMonitorID);
}
return 0;

View File

@@ -15,6 +15,8 @@ struct SMasterNodeData {
Vector2D position;
Vector2D size;
float percSize = 1.f; // size multiplier for resizing children
int workspaceID = -1;
bool operator==(const SMasterNodeData& rhs) {
@@ -52,6 +54,7 @@ private:
SMasterNodeData* getMasterNodeOnWorkspace(const int&);
void calculateWorkspace(const int&);
CWindow* getNextWindow(CWindow*, bool);
int getMastersOnWorkspace(const int&);
friend struct SMasterNodeData;
};

View File

@@ -33,6 +33,8 @@ void CAnimationManager::tick() {
const auto DEFAULTBEZIER = m_mBezierCurves.find("default");
std::vector<CAnimatedVariable*> animationEndedVars;
for (auto& av : m_lAnimatedVariables) {
// first of all, check if we need to update it at all
@@ -40,16 +42,12 @@ void CAnimationManager::tick() {
continue;
if (av->m_eDamagePolicy == AVARDAMAGE_SHADOW && !*PSHADOWSENABLED) {
av->warp();
av->warp(false);
continue;
}
// get speed
const auto SPEED = av->m_pConfig->pValues->internalSpeed;
// get the spent % (0 - 1)
const auto DURATIONPASSED = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - av->animationBegin).count();
const float SPENT = std::clamp((DURATIONPASSED / 100.f) / SPEED, 0.f, 1.f);
const float SPENT = av->getPercent();
// window stuff
const auto PWINDOW = (CWindow*)av->m_pWindow;
@@ -78,12 +76,12 @@ void CAnimationManager::tick() {
case AVARTYPE_FLOAT: {
// for disabled anims just warp
if (av->m_pConfig->pValues->internalEnabled == 0 || animationsDisabled) {
av->warp();
av->warp(false);
break;
}
if (SPENT >= 1.f) {
av->warp();
av->warp(false);
break;
}
@@ -99,12 +97,12 @@ void CAnimationManager::tick() {
case AVARTYPE_VECTOR: {
// for disabled anims just warp
if (av->m_pConfig->pValues->internalEnabled == 0 || animationsDisabled) {
av->warp();
av->warp(false);
break;
}
if (SPENT >= 1.f) {
av->warp();
av->warp(false);
break;
}
@@ -120,12 +118,12 @@ void CAnimationManager::tick() {
case AVARTYPE_COLOR: {
// for disabled anims just warp
if (av->m_pConfig->pValues->internalEnabled == 0 || animationsDisabled) {
av->warp();
av->warp(false);
break;
}
if (SPENT >= 1.f) {
av->warp();
av->warp(false);
break;
}
@@ -166,8 +164,7 @@ void CAnimationManager::tick() {
g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR);
}
break;
}
case AVARDAMAGE_BORDER: {
} case AVARDAMAGE_BORDER: {
RASSERT(PWINDOW, "Tried to AVARDAMAGE_BORDER a non-window AVAR!");
// damage only the border.
@@ -225,13 +222,21 @@ void CAnimationManager::tick() {
}
}
// set size and pos if valid, but only if damage policy entire (dont if border for example)
if (g_pCompositor->windowValidMapped(PWINDOW) && av->m_eDamagePolicy == AVARDAMAGE_ENTIRE && PWINDOW->m_iX11Type != 2)
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
// manually schedule a frame
g_pCompositor->scheduleFrameForMonitor(PMONITOR);
// check if we did not finish animating. If so, trigger onAnimationEnd.
if (!av->isBeingAnimated())
animationEndedVars.push_back(av);
}
// do it here, because if this alters the animation vars deque we would be in trouble above.
for (auto& ave : animationEndedVars) {
ave->onAnimationEnd();
}
}
@@ -287,7 +292,7 @@ void CAnimationManager::animationPopin(CWindow* pWindow, bool close, float minPe
}
void CAnimationManager::animationSlide(CWindow* pWindow, std::string force, bool close) {
pWindow->m_vRealSize.warp(); // size we preserve in slide
pWindow->m_vRealSize.warp(false); // size we preserve in slide
const auto GOALPOS = pWindow->m_vRealPosition.goalv();
const auto GOALSIZE = pWindow->m_vRealSize.goalv();

View File

@@ -72,8 +72,6 @@ void CEventManager::startThread() {
// add to event loop so we can close it when we need to
m_dAcceptedSocketFDs.push_back({ACCEPTEDCONNECTION, wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, ACCEPTEDCONNECTION, WL_EVENT_READABLE, fdHandleWrite, &m_dAcceptedSocketFDs)});
}
ensureFDsValid();
}
close(SOCKET);
@@ -82,28 +80,7 @@ void CEventManager::startThread() {
m_tThread.detach();
}
void CEventManager::ensureFDsValid() {
static char readBuf[1024] = {0};
// pong if all FDs valid
for (auto it = m_dAcceptedSocketFDs.begin(); it != m_dAcceptedSocketFDs.end();) {
auto sizeRead = recv(it->first, &readBuf, 1024, 0);
if (sizeRead != 0) {
it++;
continue;
}
// invalid!
Debug::log(LOG, "Removed invalid socket (2) FD: %d", *it);
it = m_dAcceptedSocketFDs.erase(it);
}
}
void CEventManager::flushEvents() {
ensureFDsValid();
eventQueueMutex.lock();
for (auto& ev : m_dQueuedEvents) {

View File

@@ -26,7 +26,6 @@ public:
private:
void flushEvents();
void ensureFDsValid();
std::mutex eventQueueMutex;
std::deque<SHyprIPCEvent> m_dQueuedEvents;

View File

@@ -16,6 +16,7 @@ CKeybindManager::CKeybindManager() {
m_mDispatchers["pseudo"] = toggleActivePseudo;
m_mDispatchers["movefocus"] = moveFocusTo;
m_mDispatchers["movewindow"] = moveActiveTo;
m_mDispatchers["centerwindow"] = centerWindow;
m_mDispatchers["togglegroup"] = toggleGroup;
m_mDispatchers["changegroupactive"] = changeGroupActive;
m_mDispatchers["togglesplit"] = toggleSplit;
@@ -164,7 +165,7 @@ bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard
return true;
}
if (pKeyboard->isVirtual)
if (pKeyboard->isVirtual && g_pInputManager->shouldIgnoreVirtualKeyboard(pKeyboard))
return true;
if (!m_pXKBTranslationState) {
@@ -482,6 +483,17 @@ bool CKeybindManager::handleInternalKeybinds(xkb_keysym_t keysym) {
// Dispatchers
void CKeybindManager::spawn(std::string args) {
args = removeBeginEndSpacesTabs(args);
std::string RULES = "";
if (args[0] == '[') {
// we have exec rules
RULES = args.substr(1, args.substr(1).find_first_of(']'));
args = args.substr(args.find_first_of(']') + 1);
}
if (g_pXWaylandManager->m_sWLRXWayland)
args = "WAYLAND_DISPLAY=" + std::string(g_pCompositor->m_szWLDisplaySocket) + " DISPLAY=" + std::string(g_pXWaylandManager->m_sWLRXWayland->display_name) + " " + args;
else
@@ -534,7 +546,18 @@ void CKeybindManager::spawn(std::string args) {
Debug::log(LOG, "Fail to create the second fork");
return;
}
Debug::log(LOG, "Process Created with pid %d", grandchild);
if (!RULES.empty()) {
const auto RULESLIST = CVarList(RULES, 0, ';');
for (auto& r : RULESLIST) {
g_pConfigManager->addExecRule({r, (unsigned long)grandchild});
}
Debug::log(LOG, "Applied %i rule arguments for exec.", RULESLIST.size());
}
}
void CKeybindManager::killActive(std::string args) {
@@ -576,9 +599,23 @@ void CKeybindManager::toggleActiveFloating(std::string args) {
PWINDOW->m_bIsFloating = !PWINDOW->m_bIsFloating;
PWINDOW->updateDynamicRules();
g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(PWINDOW);
}
void CKeybindManager::centerWindow(std::string args) {
const auto PWINDOW = g_pCompositor->m_pLastWindow;
if (!PWINDOW || !PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen)
return;
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
PWINDOW->m_vRealPosition = PMONITOR->vecPosition + PMONITOR->vecSize / 2.f - PWINDOW->m_vRealSize.goalv() / 2.f;
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goalv();
}
void CKeybindManager::toggleActivePseudo(std::string args) {
const auto ACTIVEWINDOW = g_pCompositor->m_pLastWindow;
@@ -617,7 +654,7 @@ void CKeybindManager::changeworkspace(std::string args) {
return;
} else {
workspaceToChangeTo = PCURRENTWORKSPACE->m_iPrevWorkspaceID;
if (const auto PWORKSPACETOCHANGETO = g_pCompositor->getWorkspaceByID(workspaceToChangeTo); PWORKSPACETOCHANGETO)
workspaceName = PWORKSPACETOCHANGETO->m_szName;
else
@@ -645,12 +682,12 @@ void CKeybindManager::changeworkspace(std::string args) {
const auto PCURRENTWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace);
static auto *const PBACKANDFORTH = &g_pConfigManager->getConfigValuePtr("binds:workspace_back_and_forth")->intValue;
if (*PBACKANDFORTH && PCURRENTWORKSPACE->m_iID == workspaceToChangeTo && PCURRENTWORKSPACE->m_iPrevWorkspaceID != -1 && !internal) {
if (*PBACKANDFORTH && PCURRENTWORKSPACE && PCURRENTWORKSPACE->m_iID == workspaceToChangeTo && PCURRENTWORKSPACE->m_iPrevWorkspaceID != -1 && !internal) {
const auto PPREVWORKSPACE = g_pCompositor->getWorkspaceByID(PCURRENTWORKSPACE->m_iPrevWorkspaceID);
workspaceToChangeTo = PCURRENTWORKSPACE->m_iPrevWorkspaceID;
if (PPREVWORKSPACE)
workspaceName = PPREVWORKSPACE->m_szName;
else
@@ -664,7 +701,7 @@ void CKeybindManager::changeworkspace(std::string args) {
if (!*PALLOWWORKSPACECYCLES)
PCURRENTWORKSPACE->m_iPrevWorkspaceID = -1;
} else if (PCURRENTWORKSPACE->m_iID == workspaceToChangeTo && !internal)
} else if (PCURRENTWORKSPACE && PCURRENTWORKSPACE->m_iID == workspaceToChangeTo && !internal)
return;
// remove constraints
@@ -722,6 +759,10 @@ void CKeybindManager::changeworkspace(std::string args) {
if (anotherMonitor) {
Vector2D middle = PMONITOR->vecPosition + PMONITOR->vecSize / 2.f;
g_pCompositor->warpCursorTo(middle);
// event for focusedmon, as we changed.
g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", PMONITOR->szName + "," + PWORKSPACETOCHANGETO->m_szName});
g_pCompositor->m_pLastMonitor = PMONITOR;
}
// set active and deactivate all other in wlr
@@ -1135,7 +1176,7 @@ void CKeybindManager::alterSplitRatio(std::string args) {
void CKeybindManager::focusMonitor(std::string arg) {
const auto PMONITOR = g_pCompositor->getMonitorFromString(arg);
if (!PMONITOR)
if (!PMONITOR || PMONITOR == g_pCompositor->m_pLastMonitor)
return;
changeworkspace("[internal]" + std::to_string(PMONITOR->activeWorkspace));
@@ -1426,7 +1467,7 @@ void CKeybindManager::circleNext(std::string arg) {
if (PWINDOWTOCHANGETO == g_pCompositor->m_pLastWindow || !PWINDOWTOCHANGETO)
return;
if (g_pCompositor->m_pLastWindow->m_iWorkspaceID == PWINDOWTOCHANGETO->m_iWorkspaceID && g_pCompositor->m_pLastWindow->m_bIsFullscreen) {
if (g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->m_iWorkspaceID == PWINDOWTOCHANGETO->m_iWorkspaceID && g_pCompositor->m_pLastWindow->m_bIsFullscreen) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastWindow->m_iWorkspaceID);
const auto FSMODE = PWORKSPACE->m_efFullscreenMode;
@@ -1668,6 +1709,9 @@ void CKeybindManager::pinActive(std::string args) {
g_pCompositor->m_pLastWindow->m_bPinned = !g_pCompositor->m_pLastWindow->m_bPinned;
g_pCompositor->m_pLastWindow->m_iWorkspaceID = g_pCompositor->getMonitorFromID(g_pCompositor->m_pLastWindow->m_iMonitorID)->activeWorkspace;
g_pCompositor->m_pLastWindow->updateDynamicRules();
g_pCompositor->updateWindowAnimatedDecorationValues(g_pCompositor->m_pLastWindow);
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastWindow->m_iWorkspaceID);
PWORKSPACE->m_pLastFocusedWindow = g_pCompositor->vectorToWindowTiled(g_pInputManager->getMouseCoordsInternal());

View File

@@ -7,6 +7,7 @@
#include <functional>
class CInputManager;
class CConfigManager;
struct SKeybind {
std::string key = "";
@@ -92,6 +93,7 @@ private:
static void moveActiveToWorkspace(std::string);
static void moveActiveToWorkspaceSilent(std::string);
static void moveFocusTo(std::string);
static void centerWindow(std::string);
static void moveActiveTo(std::string);
static void toggleGroup(std::string);
static void changeGroupActive(std::string);
@@ -124,6 +126,7 @@ private:
friend class CCompositor;
friend class CInputManager;
friend class CConfigManager;
};
inline std::unique_ptr<CKeybindManager> g_pKeybindManager;

View File

@@ -49,6 +49,27 @@ void CInputManager::recheckIdleInhibitorStatus() {
}
}
// check manual user-set inhibitors
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_eIdleInhibitMode == IDLEINHIBIT_NONE)
continue;
if (w->m_eIdleInhibitMode == IDLEINHIBIT_ALWAYS) {
wlr_idle_set_enabled(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat, false);
return;
}
if (w->m_eIdleInhibitMode == IDLEINHIBIT_FOCUS && g_pCompositor->isWindowActive(w.get())) {
wlr_idle_set_enabled(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat, false);
return;
}
if (w->m_eIdleInhibitMode == IDLEINHIBIT_FULLSCREEN && w->m_bIsFullscreen && g_pCompositor->isWorkspaceVisible(w->m_iWorkspaceID)) {
wlr_idle_set_enabled(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat, false);
return;
}
}
wlr_idle_set_enabled(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat, true);
return;
}

View File

@@ -38,6 +38,11 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
m_pFoundSurfaceToFocus = nullptr;
m_pFoundLSToFocus = nullptr;
m_pFoundWindowToFocus = nullptr;
wlr_surface* foundSurface = nullptr;
Vector2D surfaceCoords;
Vector2D surfacePos = Vector2D(-1337, -1337);
CWindow* pFoundWindow = nullptr;
SLayerSurface* pFoundLayerSurface = nullptr;
if (!g_pCompositor->m_bReadyToProcess || g_pCompositor->m_bIsShuttingDown)
return;
@@ -47,9 +52,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
return;
}
if (g_pCompositor->m_sSeat.mouse->virt)
return; // don't refocus on virt
if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS) {
// enable dpms
g_pKeybindManager->dpms("on");
@@ -65,11 +67,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
const auto PMONITOR = g_pCompositor->getMonitorFromCursor();
bool didConstraintOnCursor = false;
// constraints
// All constraints TODO: multiple mice?
if (g_pCompositor->m_sSeat.mouse->currentConstraint) {
if (g_pCompositor->m_sSeat.mouse->currentConstraint && !g_pCompositor->m_sSeat.exclusiveClient) {
// XWayland windows sometimes issue constraints weirdly.
// TODO: We probably should search their parent. wlr_xwayland_surface->parent
const auto CONSTRAINTWINDOW = g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse);
@@ -99,15 +99,21 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
wlr_cursor_warp_closest(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, newConstrainedCoords.x, newConstrainedCoords.y);
mouseCoords = newConstrainedCoords;
didConstraintOnCursor = true;
}
} else {
if ((!CONSTRAINTWINDOW->m_bIsX11 && PMONITOR && CONSTRAINTWINDOW->m_iWorkspaceID == PMONITOR->activeWorkspace) || (CONSTRAINTWINDOW->m_bIsX11)) {
g_pCompositor->m_sSeat.mouse->constraintActive = true;
didConstraintOnCursor = true;
}
}
if (CONSTRAINTWINDOW->m_bIsX11) {
foundSurface = g_pXWaylandManager->getWindowSurface(CONSTRAINTWINDOW);
surfacePos = CONSTRAINTWINDOW->m_vRealPosition.vec();
} else {
g_pCompositor->vectorWindowToSurface(mouseCoords, CONSTRAINTWINDOW, surfaceCoords);
}
pFoundWindow = CONSTRAINTWINDOW;
}
}
@@ -116,12 +122,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
g_pLayoutManager->getCurrentLayout()->onMouseMove(getMouseCoordsInternal());
// focus
wlr_surface* foundSurface = nullptr;
if (didConstraintOnCursor)
return; // don't process when cursor constrained
if (PMONITOR && PMONITOR != g_pCompositor->m_pLastMonitor) {
g_pCompositor->m_pLastMonitor = PMONITOR;
@@ -134,11 +134,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", PMONITOR->szName + "," + ACTIVEWORKSPACE->m_szName});
}
Vector2D surfaceCoords;
Vector2D surfacePos = Vector2D(-1337, -1337);
CWindow* pFoundWindow = nullptr;
SLayerSurface* pFoundLayerSurface = nullptr;
// overlay is above fullscreen
if (!foundSurface)
foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &surfaceCoords, &pFoundLayerSurface);
@@ -278,7 +273,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (*PFOLLOWMOUSE != 3 && allowKeyboardRefocus)
g_pCompositor->focusWindow(pFoundWindow, foundSurface);
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
} else if (*PFOLLOWMOUSE == 2) {
} else if (*PFOLLOWMOUSE == 2 || *PFOLLOWMOUSE == 3) {
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
}
@@ -344,6 +339,10 @@ void CInputManager::processMouseRequest(wlr_seat_pointer_request_set_cursor_even
g_pHyprRenderer->m_bWindowRequestedCursorHide = false;
}
if (m_bCursorImageOverriden) {
return;
}
if (m_ecbClickBehavior == CLICKMODE_KILL) {
wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "crosshair", g_pCompositor->m_sWLRCursor);
return;
@@ -392,12 +391,16 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
// notify the keybind manager
static auto *const PPASSMOUSE = &g_pConfigManager->getConfigValuePtr("binds:pass_mouse_when_bound")->intValue;
const auto PASS = g_pKeybindManager->onMouseEvent(e);
static auto *const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
if (!PASS && !*PPASSMOUSE)
return;
switch (e->state) {
case WLR_BUTTON_PRESSED:
if (*PFOLLOWMOUSE == 3) // don't refocus on full loose
break;
if (!g_pCompositor->m_sSeat.mouse->currentConstraint)
refocus();
@@ -673,14 +676,14 @@ void CInputManager::newMouse(wlr_input_device* mouse, bool virt) {
Debug::log(LOG, "New mouse has libinput sens %.2f (%.2f) with accel profile %i (%i)", libinput_device_config_accel_get_speed(LIBINPUTDEV), libinput_device_config_accel_get_default_speed(LIBINPUTDEV), libinput_device_config_accel_get_profile(LIBINPUTDEV), libinput_device_config_accel_get_default_profile(LIBINPUTDEV));
}
setPointerConfigs();
PMOUSE->hyprListener_destroyMouse.initCallback(&mouse->events.destroy, &Events::listener_destroyMouse, PMOUSE, "Mouse");
wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, mouse);
PMOUSE->connected = true;
setPointerConfigs();
PMOUSE->hyprListener_destroyMouse.initCallback(&mouse->events.destroy, &Events::listener_destroyMouse, PMOUSE, "Mouse");
g_pCompositor->m_sSeat.mouse = PMOUSE;
m_tmrLastCursorMovement.reset();
@@ -819,6 +822,31 @@ void CInputManager::destroyMouse(wlr_input_device* mouse) {
unconstrainMouse();
}
void CInputManager::updateKeyboardsLeds(wlr_input_device* pKeyboard) {
auto keyboard = wlr_keyboard_from_input_device(pKeyboard);
if (keyboard->xkb_state == NULL) {
return;
}
uint32_t leds = 0;
for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) {
if (xkb_state_led_index_is_active(keyboard->xkb_state,
keyboard->led_indexes[i])) {
leds |= (1 << i);
}
}
for (auto& kb : m_lKeyboards) {
if ((kb.isVirtual && shouldIgnoreVirtualKeyboard(&kb)) || kb.keyboard == pKeyboard)
continue;
wlr_keyboard_led_update(wlr_keyboard_from_input_device(kb.keyboard), leds);
}
}
void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboard) {
bool passEvent = g_pKeybindManager->onKeyEvent(e, pKeyboard);
@@ -835,6 +863,8 @@ void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboar
wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, wlr_keyboard_from_input_device(pKeyboard->keyboard));
wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, e->time_msec, e->keycode, e->state);
}
updateKeyboardsLeds(pKeyboard->keyboard);
}
}
@@ -854,6 +884,8 @@ void CInputManager::onKeyboardMod(void* data, SKeyboard* pKeyboard) {
wlr_seat_keyboard_notify_modifiers(g_pCompositor->m_sSeat.seat, &MODS);
}
updateKeyboardsLeds(pKeyboard->keyboard);
const auto PWLRKB = wlr_keyboard_from_input_device(pKeyboard->keyboard);
if (PWLRKB->modifiers.group != pKeyboard->activeLayout) {
@@ -863,6 +895,10 @@ void CInputManager::onKeyboardMod(void* data, SKeyboard* pKeyboard) {
}
}
bool CInputManager::shouldIgnoreVirtualKeyboard(SKeyboard* pKeyboard) {
return !pKeyboard || (m_sIMERelay.m_pKeyboardGrab && wl_resource_get_client(m_sIMERelay.m_pKeyboardGrab->pWlrKbGrab->resource) == wl_resource_get_client(wlr_input_device_get_virtual_keyboard(pKeyboard->keyboard)->resource));
}
void CInputManager::refocus() {
mouseMoveUnified(0, true);
}
@@ -1004,7 +1040,7 @@ uint32_t CInputManager::accumulateModsFromAllKBs() {
uint32_t finalMask = 0;
for (auto& kb : m_lKeyboards) {
if (kb.isVirtual)
if (kb.isVirtual && shouldIgnoreVirtualKeyboard(&kb))
continue;
finalMask |= wlr_keyboard_get_modifiers(wlr_keyboard_from_input_device(kb.keyboard));
@@ -1152,3 +1188,17 @@ void CInputManager::newSwitch(wlr_input_device* pDevice) {
void CInputManager::destroySwitch(SSwitchDevice* pDevice) {
m_lSwitches.remove(*pDevice);
}
void CInputManager::setCursorImageUntilUnset(std::string name) {
wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, name.c_str(), g_pCompositor->m_sWLRCursor);
m_bCursorImageOverriden = true;
}
void CInputManager::unsetCursorImage() {
if (!m_bCursorImageOverriden)
return;
m_bCursorImageOverriden = false;
if (!g_pHyprRenderer->m_bWindowRequestedCursorHide)
wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", g_pCompositor->m_sWLRCursor);
}

View File

@@ -115,13 +115,24 @@ public:
CInputMethodRelay m_sIMERelay;
void updateKeyboardsLeds(wlr_input_device* pKeyboard);
// for shared mods
uint32_t accumulateModsFromAllKBs();
CWindow* m_pFollowOnDnDBegin = nullptr;
// for virtual keyboards: whether we should respect them as normal ones
bool shouldIgnoreVirtualKeyboard(SKeyboard*);
// for special cursors that we choose
void setCursorImageUntilUnset(std::string);
void unsetCursorImage();
private:
bool m_bCursorImageOverriden = false;
// for click behavior override
eClickBehaviorMode m_ecbClickBehavior = CLICKMODE_DEFAULT;
bool m_bEmptyFocusCursorSet = false;
@@ -147,6 +158,9 @@ private:
wlr_surface* m_pFoundSurfaceToFocus = nullptr;
SLayerSurface* m_pFoundLSToFocus = nullptr;
CWindow* m_pFoundWindowToFocus = nullptr;
// swipe
void beginWorkspaceSwipe();
};
inline std::unique_ptr<CInputManager> g_pInputManager;

View File

@@ -301,7 +301,7 @@ void CInputMethodRelay::createNewTextInput(wlr_text_input_v3* pInput) {
const auto PINPUT = (STextInput*)owner;
if (!g_pInputManager->m_sIMERelay.m_pWLRIME) {
Debug::log(WARN, "Enabling TextInput on no IME!");
// Debug::log(WARN, "Enabling TextInput on no IME!");
return;
}
@@ -317,7 +317,7 @@ void CInputMethodRelay::createNewTextInput(wlr_text_input_v3* pInput) {
const auto PINPUT = (STextInput*)owner;
if (!g_pInputManager->m_sIMERelay.m_pWLRIME) {
Debug::log(WARN, "Committing TextInput on no IME!");
// Debug::log(WARN, "Committing TextInput on no IME!");
return;
}
@@ -335,7 +335,7 @@ void CInputMethodRelay::createNewTextInput(wlr_text_input_v3* pInput) {
const auto PINPUT = (STextInput*)owner;
if (!g_pInputManager->m_sIMERelay.m_pWLRIME) {
Debug::log(WARN, "Disabling TextInput on no IME!");
// Debug::log(WARN, "Disabling TextInput on no IME!");
return;
}
@@ -352,7 +352,7 @@ void CInputMethodRelay::createNewTextInput(wlr_text_input_v3* pInput) {
const auto PINPUT = (STextInput*)owner;
if (!g_pInputManager->m_sIMERelay.m_pWLRIME) {
Debug::log(WARN, "Disabling TextInput on no IME!");
// Debug::log(WARN, "Disabling TextInput on no IME!");
return;
}

View File

@@ -3,6 +3,8 @@
#include "../../defines.hpp"
#include "../../helpers/WLClasses.hpp"
class CInputManager;
class CInputMethodRelay {
public:
CInputMethodRelay();
@@ -45,4 +47,5 @@ private:
void createNewTextInput(wlr_text_input_v3*);
friend class CHyprRenderer;
friend class CInputManager;
};

View File

@@ -19,6 +19,10 @@ void CInputManager::onSwipeBegin(wlr_pointer_swipe_begin_event* e) {
if (onMonitor < 2 && !*PSWIPENEW)
return; // disallow swiping when there's 1 workspace on a monitor
beginWorkspaceSwipe();
}
void CInputManager::beginWorkspaceSwipe() {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace);
Debug::log(LOG, "Starting a swipe from %s", PWORKSPACE->m_szName.c_str());
@@ -51,7 +55,7 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
auto workspaceIDLeft = getWorkspaceIDFromString("m-1", wsname);
auto workspaceIDRight = getWorkspaceIDFromString("m+1", wsname);
if ((workspaceIDRight <= m_sActiveSwipe.pWorkspaceBegin->m_iID || workspaceIDRight == workspaceIDLeft) && *PSWIPENEW) {
if ((workspaceIDRight <= m_sActiveSwipe.pWorkspaceBegin->m_iID || (workspaceIDRight == workspaceIDLeft && workspaceIDLeft == m_sActiveSwipe.pWorkspaceBegin->m_iID)) && *PSWIPENEW) {
workspaceIDRight = m_sActiveSwipe.pWorkspaceBegin->m_iID > 0 ? m_sActiveSwipe.pWorkspaceBegin->m_iID + 1 : 1;
}
@@ -162,6 +166,7 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
static auto *const PSWIPEDIST = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_distance")->intValue;
static auto *const PSWIPEINVR = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_invert")->intValue;
static auto *const PSWIPENEW = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_create_new")->intValue;
static auto *const PSWIPEFOREVER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_forever")->intValue;
const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert";
@@ -258,4 +263,11 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor);
g_pCompositor->updateWorkspaceWindowDecos(m_sActiveSwipe.pWorkspaceBegin->m_iID);
if (*PSWIPEFOREVER) {
if (abs(m_sActiveSwipe.delta) >= *PSWIPEDIST) {
onSwipeEnd(nullptr);
beginWorkspaceSwipe();
}
}
}

View File

@@ -38,6 +38,8 @@ void CInputManager::onTouchDown(wlr_touch_down_event* e) {
}
wlr_seat_touch_notify_down(g_pCompositor->m_sSeat.seat, m_sTouchData.touchFocusSurface, e->time_msec, e->touch_id, local.x, local.y);
wlr_idle_notify_activity(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat);
}
void CInputManager::onTouchUp(wlr_touch_up_event* e){

View File

@@ -1,4 +1,4 @@
globber = run_command('find', '-name', '*.cpp', check: true)
globber = run_command('find', '.', '-name', '*.cpp', check: true)
src = globber.stdout().strip().split('\n')
executable('Hyprland', src,
@@ -18,7 +18,7 @@ executable('Hyprland', src,
xcb_dep,
dependency('pixman-1'),
dependency('GL', 'opengl'),
dependency('gl', 'opengl'),
dependency('threads')
],
install : true

View File

@@ -27,7 +27,6 @@ bool CFramebuffer::alloc(int w, int h) {
glBindFramebuffer(GL_FRAMEBUFFER, m_iFb);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_cTex.m_iTexID, 0);
// TODO: Allow this with gles2
#ifndef GLES2
if (m_pStencilTex) {
@@ -80,3 +79,7 @@ void CFramebuffer::release() {
CFramebuffer::~CFramebuffer() {
release();
}
bool CFramebuffer::isAllocated() {
return m_iFb != (GLuint)-1;
}

View File

@@ -12,6 +12,7 @@ public:
void bind();
void release();
void reset();
bool isAllocated();
Vector2D m_Position;
Vector2D m_Size;

View File

@@ -25,15 +25,9 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
Debug::log(WARN, "!RENDERER: Using the legacy GLES2 renderer!");
#endif
// End shaders
pixman_region32_init(&m_rOriginalDamageRegion);
// End
RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!");
// Done!
}
GLuint CHyprOpenGLImpl::createProgram(const std::string& vert, const std::string& frag) {
@@ -911,6 +905,61 @@ void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int round) {
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
void CHyprOpenGLImpl::makeRawWindowSnapshot(CWindow* pWindow, CFramebuffer* pFramebuffer) {
// we trust the window is valid.
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
wlr_output_attach_render(PMONITOR->output, nullptr);
// we need to "damage" the entire monitor
// so that we render the entire window
// this is temporary, doesnt mess with the actual wlr damage
pixman_region32_t fakeDamage;
pixman_region32_init(&fakeDamage);
pixman_region32_union_rect(&fakeDamage, &fakeDamage, 0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y);
begin(PMONITOR, &fakeDamage, true);
clear(CColor(0, 0, 0, 0)); // JIC
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
// this is a hack but it works :P
// we need to disable blur or else we will get a black background, as the shader
// will try to copy the bg to apply blur.
// this isn't entirely correct, but like, oh well.
// small todo: maybe make this correct? :P
const auto BLURVAL = g_pConfigManager->getInt("decoration:blur");
g_pConfigManager->setInt("decoration:blur", 0);
// TODO: how can we make this the size of the window? setting it to window's size makes the entire screen render with the wrong res forever more. odd.
glViewport(0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
pFramebuffer->m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex;
pFramebuffer->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
pFramebuffer->bind();
clear(CColor(0, 0, 0, 0)); // JIC
g_pHyprRenderer->renderWindow(pWindow, PMONITOR, &now, false, RENDER_PASS_ALL, true);
g_pConfigManager->setInt("decoration:blur", BLURVAL);
// restore original fb
#ifndef GLES2
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_iCurrentOutputFb);
#else
glBindFramebuffer(GL_FRAMEBUFFER, m_iCurrentOutputFb);
#endif
end();
pixman_region32_fini(&fakeDamage);
wlr_output_rollback(PMONITOR->output);
}
void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
// we trust the window is valid.
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
@@ -925,7 +974,7 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
begin(PMONITOR, &fakeDamage, true);
clear(CColor(0,0,0,0)); // JIC
clear(CColor(0, 0, 0, 0)); // JIC
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
@@ -938,10 +987,9 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
const auto BLURVAL = g_pConfigManager->getInt("decoration:blur");
g_pConfigManager->setInt("decoration:blur", 0);
// render onto the window fb
const auto PFRAMEBUFFER = &m_mWindowFramebuffers[pWindow];
glViewport(0, 0, m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y);
glViewport(0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.y);
const auto PFRAMEBUFFER = &m_mWindowFramebuffers[pWindow];
PFRAMEBUFFER->m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex;
@@ -955,12 +1003,12 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
g_pConfigManager->setInt("decoration:blur", BLURVAL);
// restore original fb
#ifndef GLES2
// restore original fb
#ifndef GLES2
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_iCurrentOutputFb);
#else
#else
glBindFramebuffer(GL_FRAMEBUFFER, m_iCurrentOutputFb);
#endif
#endif
end();
pixman_region32_fini(&fakeDamage);
@@ -1020,6 +1068,32 @@ void CHyprOpenGLImpl::makeLayerSnapshot(SLayerSurface* pLayer) {
wlr_output_rollback(PMONITOR->output);
}
void CHyprOpenGLImpl::onWindowResizeStart(CWindow* pWindow) {
static auto *const PTRANSITIONS = &g_pConfigManager->getConfigValuePtr("animations:use_resize_transitions")->intValue;
static auto *const PENABLED = &g_pConfigManager->getConfigValuePtr("animations:enabled")->intValue;
if (!*PTRANSITIONS || !*PENABLED)
return;
if (pWindow->m_vRealSize.vec().x < 5 || pWindow->m_vRealSize.vec().y < 5)
return;
// make a fb and render a snapshot
const auto PFRAMEBUFFER = &m_mWindowResizeFramebuffers[pWindow];
makeRawWindowSnapshot(pWindow, PFRAMEBUFFER);
}
void CHyprOpenGLImpl::onWindowResizeEnd(CWindow* pWindow) {
static auto *const PTRANSITIONS = &g_pConfigManager->getConfigValuePtr("animations:use_resize_transitions")->intValue;
static auto *const PENABLED = &g_pConfigManager->getConfigValuePtr("animations:enabled")->intValue;
if (!*PTRANSITIONS || !*PENABLED)
return;
// remove the fb
m_mWindowResizeFramebuffers.erase(pWindow);
}
void CHyprOpenGLImpl::renderSnapshot(CWindow** pWindow) {
RASSERT(m_RenderData.pMonitor, "Tried to render snapshot rect without begin()!");
const auto PWINDOW = *pWindow;
@@ -1162,13 +1236,13 @@ void CHyprOpenGLImpl::renderRoundedShadow(wlr_box* box, int round, int range, fl
}
}
pixman_region32_fini(&damageClip);
pixman_region32_fini(&damageClip);
} else {
PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) {
const auto RECT = RECTSARR[i];
scissor(&RECT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) {
const auto RECT = RECTSARR[i];
scissor(&RECT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
}
glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shSHADOW.posAttrib);

View File

@@ -12,6 +12,8 @@
#include "Texture.hpp"
#include "Framebuffer.hpp"
class CHyprRenderer;
inline const float fullVerts[] = {
1, 0, // top right
0, 0, // top left
@@ -83,6 +85,7 @@ public:
void renderBorder(wlr_box*, const CColor&, int round);
void makeWindowSnapshot(CWindow*);
void makeRawWindowSnapshot(CWindow*, CFramebuffer*);
void makeLayerSnapshot(SLayerSurface*);
void renderSnapshot(CWindow**);
void renderSnapshot(SLayerSurface**);
@@ -103,6 +106,9 @@ public:
void saveBufferForMirror();
void renderMirrored();
void onWindowResizeStart(CWindow*);
void onWindowResizeEnd(CWindow*);
SCurrentRenderData m_RenderData;
GLint m_iCurrentOutputFb = 0;
@@ -113,6 +119,7 @@ public:
pixman_region32_t m_rOriginalDamageRegion; // used for storing the pre-expanded region
std::unordered_map<CWindow*, CFramebuffer> m_mWindowFramebuffers;
std::unordered_map<CWindow*, CFramebuffer> m_mWindowResizeFramebuffers;
std::unordered_map<SLayerSurface*, CFramebuffer> m_mLayerFramebuffers;
std::unordered_map<CMonitor*, SMonitorRenderData> m_mMonitorRenderResources;
std::unordered_map<CMonitor*, CTexture> m_mMonitorBGTextures;
@@ -139,6 +146,8 @@ private:
void renderSplash(cairo_t *const, cairo_surface_t *const, double);
void preBlurForCurrentMonitor();
friend class CHyprRenderer;
};
inline std::unique_ptr<CHyprOpenGLImpl> g_pHyprOpenGL;

View File

@@ -1,5 +1,6 @@
#include "Renderer.hpp"
#include "../Compositor.hpp"
#include "linux-dmabuf-unstable-v1-protocol.h"
void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
const auto TEXTURE = wlr_surface_get_texture(surface);
@@ -214,7 +215,7 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(CMonitor* pMonitor, CWor
g_pHyprError->draw();
}
void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec* time, bool decorate, eRenderPassMode mode) {
void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec* time, bool decorate, eRenderPassMode mode, bool ignorePosition) {
if (pWindow->isHidden())
return;
@@ -226,9 +227,15 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
const auto REALPOS = pWindow->m_vRealPosition.vec() + (pWindow->m_bPinned ? Vector2D{} : PWORKSPACE->m_vRenderOffset.vec());
static const auto PNOFLOATINGBORDERS = &g_pConfigManager->getConfigValuePtr("general:no_border_on_floating")->intValue;
static auto *const PNOFLOATINGBORDERS = &g_pConfigManager->getConfigValuePtr("general:no_border_on_floating")->intValue;
static auto *const PTRANSITIONS = &g_pConfigManager->getConfigValuePtr("animations:use_resize_transitions")->intValue;
SRenderData renderdata = {pMonitor->output, time, REALPOS.x, REALPOS.y};
if (ignorePosition) {
renderdata.x = pMonitor->vecPosition.x;
renderdata.y = pMonitor->vecPosition.y;
}
renderdata.surface = g_pXWaylandManager->getWindowSurface(pWindow);
renderdata.w = std::max(pWindow->m_vRealSize.vec().x, 5.0); // clamp the size to min 5,
renderdata.h = std::max(pWindow->m_vRealSize.vec().y, 5.0); // otherwise we'll have issues later with invalid boxes
@@ -254,39 +261,59 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
// clip box for animated offsets
Vector2D offset;
if (PWORKSPACE->m_vRenderOffset.vec().x != 0) {
const auto PWSMON = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
const auto PROGRESS = PWORKSPACE->m_vRenderOffset.vec().x / PWSMON->vecSize.x;
const auto WINBB = pWindow->getFullWindowBoundingBox();
if (!ignorePosition && pWindow->m_bIsFloating) {
if (PWORKSPACE->m_vRenderOffset.vec().x != 0) {
const auto PWSMON = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
const auto PROGRESS = PWORKSPACE->m_vRenderOffset.vec().x / PWSMON->vecSize.x;
const auto WINBB = pWindow->getFullWindowBoundingBox();
if (WINBB.x < PWSMON->vecPosition.x) {
offset.x = (PWSMON->vecPosition.x - WINBB.x) * PROGRESS;
} else if (WINBB.x > PWSMON->vecPosition.x + PWSMON->vecSize.x) {
offset.x = (WINBB.x - PWSMON->vecPosition.x + PWSMON->vecSize.x) * PROGRESS;
}
} else if (PWORKSPACE->m_vRenderOffset.vec().y) {
const auto PWSMON = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
const auto PROGRESS = PWORKSPACE->m_vRenderOffset.vec().y / PWSMON->vecSize.y;
const auto WINBB = pWindow->getFullWindowBoundingBox();
if (WINBB.x < PWSMON->vecPosition.x) {
offset.x = (PWSMON->vecPosition.x - WINBB.x) * PROGRESS;
} else if (WINBB.x + WINBB.width > PWSMON->vecPosition.x + PWSMON->vecSize.x) {
offset.x = (WINBB.x + WINBB.width - PWSMON->vecPosition.x - PWSMON->vecSize.x) * PROGRESS;
}
} else if (PWORKSPACE->m_vRenderOffset.vec().y) {
const auto PWSMON = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
const auto PROGRESS = PWORKSPACE->m_vRenderOffset.vec().y / PWSMON->vecSize.y;
const auto WINBB = pWindow->getFullWindowBoundingBox();
if (WINBB.y < PWSMON->vecPosition.y) {
offset.y = (PWSMON->vecPosition.y - WINBB.y) * PROGRESS;
} else if (WINBB.y > PWSMON->vecPosition.y + PWSMON->vecSize.y) {
offset.y = (WINBB.y - PWSMON->vecPosition.y + PWSMON->vecSize.y) * PROGRESS;
if (WINBB.y < PWSMON->vecPosition.y) {
offset.y = (PWSMON->vecPosition.y - WINBB.y) * PROGRESS;
} else if (WINBB.y + WINBB.height > PWSMON->vecPosition.y + PWSMON->vecSize.y) {
offset.y = (WINBB.y + WINBB.width - PWSMON->vecPosition.y - PWSMON->vecSize.y) * PROGRESS;
}
}
renderdata.x += offset.x;
renderdata.y += offset.y;
}
renderdata.x += offset.x;
renderdata.y += offset.y;
// render window decorations first, if not fullscreen full
if (mode == RENDER_PASS_ALL || mode == RENDER_PASS_MAIN) {
if (!pWindow->m_bIsFullscreen || PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL) for (auto& wd : pWindow->m_dWindowDecorations)
wd->draw(pMonitor, renderdata.alpha * renderdata.fadeAlpha / 255.f, offset);
wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(pWindow), renderSurface, &renderdata);
if (*PTRANSITIONS && !ignorePosition /* ignorePosition probably means we are rendering the snapshot rn */) {
const auto PFB = g_pHyprOpenGL->m_mWindowResizeFramebuffers.find(pWindow);
if (PFB != g_pHyprOpenGL->m_mWindowResizeFramebuffers.end() && PFB->second.isAllocated()) {
wlr_box box = {renderdata.x - pMonitor->vecPosition.x, renderdata.y - pMonitor->vecPosition.y, renderdata.w, renderdata.h};
// adjust UV (remove when I figure out how to change the size of the fb)
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = {0, 0};
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = { pWindow->m_vRealSize.m_vBegun.x / pMonitor->vecPixelSize.x, pWindow->m_vRealSize.m_vBegun.y / pMonitor->vecPixelSize.y};
g_pHyprOpenGL->m_bEndFrame = true;
g_pHyprOpenGL->renderTexture(PFB->second.m_cTex, &box, (1.f - pWindow->m_vRealSize.getPercent()) * 84.f, 0, false, true);
g_pHyprOpenGL->m_bEndFrame = false;
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
}
}
if (renderdata.decorate && pWindow->m_sSpecialRenderData.border) {
static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
@@ -533,6 +560,154 @@ void CHyprRenderer::calculateUVForWindowSurface(CWindow* pWindow, wlr_surface* p
}
}
void countSubsurfacesIter(wlr_surface* pSurface, int x, int y, void* data) {
*(int*)data += 1;
}
bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) {
if (!pMonitor->mirrors.empty())
return false; // do not DS if this monitor is being mirrored. Will break the functionality.
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pMonitor->activeWorkspace);
if (!PWORKSPACE || !PWORKSPACE->m_bHasFullscreenWindow || g_pInputManager->m_sDrag.drag || g_pCompositor->m_sSeat.exclusiveClient)
return false;
const auto PCANDIDATE = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
if (!PCANDIDATE)
return false; // ????
if (PCANDIDATE->m_fAlpha.fl() != 255.f || PCANDIDATE->m_fActiveInactiveAlpha.fl() != 1.f || PWORKSPACE->m_fAlpha.fl() != 255.f)
return false;
if (PCANDIDATE->m_vRealSize.vec() != pMonitor->vecSize || PCANDIDATE->m_vRealPosition.vec() != pMonitor->vecPosition || PCANDIDATE->m_vRealPosition.isBeingAnimated() || PCANDIDATE->m_vRealSize.isBeingAnimated())
return false;
if (!pMonitor->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY].empty())
return false;
for (auto& topls : pMonitor->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
if (topls->alpha.fl() != 0.f)
return false;
}
// check if it did not open any subsurfaces or shit
int surfaceCount = 0;
if (PCANDIDATE->m_bIsX11) {
surfaceCount = 1;
// check opaque
if (PCANDIDATE->m_uSurface.xwayland->has_alpha)
return false;
} else {
wlr_xdg_surface_for_each_surface(PCANDIDATE->m_uSurface.xdg, countSubsurfacesIter, &surfaceCount);
wlr_xdg_surface_for_each_popup_surface(PCANDIDATE->m_uSurface.xdg, countSubsurfacesIter, &surfaceCount);
if (!PCANDIDATE->m_uSurface.xdg->surface->opaque)
return false;
}
if (surfaceCount != 1)
return false;
const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE);
if (!PSURFACE || PSURFACE->current.scale != pMonitor->output->scale || PSURFACE->current.transform != pMonitor->output->transform)
return false;
// finally, we should be GTG.
wlr_output_attach_buffer(pMonitor->output, &PSURFACE->buffer->base);
if (!wlr_output_test(pMonitor->output)) {
return false;
}
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
wlr_surface_send_frame_done(PSURFACE, &now);
wlr_presentation_surface_sampled_on_output(g_pCompositor->m_sWLRPresentation, PSURFACE, pMonitor->output);
if (wlr_output_commit(pMonitor->output)) {
if (!m_pLastScanout) {
m_pLastScanout = PCANDIDATE;
Debug::log(LOG, "Entered a direct scanout to %x: \"%s\"", PCANDIDATE, PCANDIDATE->m_szTitle.c_str());
}
} else {
m_pLastScanout = nullptr;
return false;
}
return true;
}
void CHyprRenderer::setWindowScanoutMode(CWindow* pWindow) {
if (!g_pCompositor->m_sWLRLinuxDMABuf)
return;
if (!pWindow->m_bIsFullscreen) {
wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, g_pXWaylandManager->getWindowSurface(pWindow), nullptr);
Debug::log(LOG, "Scanout mode OFF set for %x", pWindow);
return;
}
const auto RENDERERDRMFD = wlr_renderer_get_drm_fd(g_pCompositor->m_sWLRRenderer);
const auto BACKENDDRMFD = wlr_backend_get_drm_fd(g_pCompositor->m_sWLRBackend);
if (RENDERERDRMFD < 0 || BACKENDDRMFD < 0)
return;
auto deviceIDFromFD = [](int fd, unsigned long* deviceID) -> bool {
struct stat stat;
if (fstat(fd, &stat) != 0) {
return false;
}
*deviceID = stat.st_rdev;
return true;
};
unsigned long rendererDevice, scanoutDevice;
if (!deviceIDFromFD(RENDERERDRMFD, &rendererDevice) || !deviceIDFromFD(BACKENDDRMFD, &scanoutDevice))
return;
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
const auto POUTPUTFORMATS = wlr_output_get_primary_formats(PMONITOR->output, WLR_BUFFER_CAP_DMABUF);
if (!POUTPUTFORMATS)
return;
const auto PRENDERERFORMATS = wlr_renderer_get_dmabuf_texture_formats(g_pCompositor->m_sWLRRenderer);
wlr_drm_format_set scanoutFormats = { 0 };
if (!wlr_drm_format_set_intersect(&scanoutFormats, POUTPUTFORMATS, PRENDERERFORMATS))
return;
const wlr_linux_dmabuf_feedback_v1_tranche TRANCHES[] = {
{
.target_device = scanoutDevice,
.flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT,
.formats = &scanoutFormats
}, {
.target_device = rendererDevice,
.formats = PRENDERERFORMATS
}
};
const wlr_linux_dmabuf_feedback_v1 FEEDBACK = {
.main_device = rendererDevice,
.tranches_len = sizeof(TRANCHES) / sizeof(TRANCHES[0]),
.tranches = TRANCHES
};
if (!wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, g_pXWaylandManager->getWindowSurface(pWindow), &FEEDBACK)) {
Debug::log(ERR, "Error in scanout mode setting: wlr_linux_dmabuf_v1_set_surface_feedback returned false.");
}
wlr_drm_format_set_finish(&scanoutFormats);
Debug::log(LOG, "Scanout mode ON set for %x", pWindow);
}
void CHyprRenderer::outputMgrApplyTest(wlr_output_configuration_v1* config, bool test) {
wlr_output_configuration_head_v1* head;
bool noError = true;
@@ -560,9 +735,17 @@ void CHyprRenderer::outputMgrApplyTest(wlr_output_configuration_v1* config, bool
commandForCfg += std::to_string(head->state.x) + "x" + std::to_string(head->state.y) + "," + std::to_string(head->state.scale);
if (!test)
if (!test) {
g_pConfigManager->parseKeyword("monitor", commandForCfg, true);
std::string transformStr = std::string(OUTPUT->name) + ",transform," + std::to_string((int)OUTPUT->transform);
const auto PMONITOR = g_pCompositor->getMonitorFromName(OUTPUT->name);
if (!PMONITOR || OUTPUT->transform != PMONITOR->transform)
g_pConfigManager->parseKeyword("monitor", transformStr);
}
noError = wlr_output_test(OUTPUT);
if (!noError)
@@ -846,7 +1029,7 @@ void CHyprRenderer::damageMonitor(CMonitor* pMonitor) {
if (g_pCompositor->m_bUnsafeState || pMonitor->isMirror())
return;
wlr_box damageBox = {0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y};
wlr_box damageBox = { 0, 0, INT16_MAX, INT16_MAX };
pMonitor->addDamage(&damageBox);
static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
@@ -1196,6 +1379,13 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
pMonitor->vecSize = (Vector2D(x, y) / pMonitor->scale).floor();
pMonitor->vecTransformedSize = Vector2D(x,y);
if (pMonitor->createdByUser) {
wlr_box transformedBox = { 0, 0, (int)pMonitor->vecTransformedSize.x, (int)pMonitor->vecTransformedSize.y };
wlr_box_transform(&transformedBox, &transformedBox, wlr_output_transform_invert(pMonitor->output->transform), (int)pMonitor->vecTransformedSize.x, (int)pMonitor->vecTransformedSize.y);
pMonitor->vecPixelSize = Vector2D(transformedBox.width, transformedBox.height);
}
if (pMonitorRule->offset == Vector2D(-1, -1) && pMonitor->vecPosition == Vector2D(-1, -1)) {
// let's find manually a sensible position for it, to the right.
Vector2D finalPos;

View File

@@ -44,13 +44,17 @@ public:
void calculateUVForWindowSurface(CWindow*, wlr_surface*, bool main = false);
bool m_bWindowRequestedCursorHide = false;
CWindow* m_pLastScanout = nullptr;
DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&);
bool attemptDirectScanout(CMonitor*);
void setWindowScanoutMode(CWindow*);
private:
void arrangeLayerArray(CMonitor*, const std::vector<std::unique_ptr<SLayerSurface>>&, bool, wlr_box*);
void renderWorkspaceWithFullscreenWindow(CMonitor*, CWorkspace*, timespec*);
void renderWindow(CWindow*, CMonitor*, timespec*, bool, eRenderPassMode);
void renderWindow(CWindow*, CMonitor*, timespec*, bool, eRenderPassMode, bool ignorePosition = false);
void renderLayer(SLayerSurface*, CMonitor*, timespec*);
void renderDragIcon(CMonitor*, timespec*);
void renderIMEPopup(SIMEPopup*, CMonitor*, timespec*);

View File

@@ -14,7 +14,5 @@ GLint CShader::getUniformLocation(const std::string& unif) {
CShader::~CShader() {
// destroy shader
if (program) {
glDeleteProgram(program);
}
glDeleteProgram(program);
}

View File

@@ -66,6 +66,7 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a, const Vector2D
static auto *const PSHADOWSIZE = &g_pConfigManager->getConfigValuePtr("decoration:shadow_range")->intValue;
static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
static auto *const PSHADOWIGNOREWINDOW = &g_pConfigManager->getConfigValuePtr("decoration:shadow_ignore_window")->intValue;
static auto *const PSHADOWSCALE = &g_pConfigManager->getConfigValuePtr("decoration:shadow_scale")->floatValue;
static auto *const PSHADOWOFFSET = &g_pConfigManager->getConfigValuePtr("decoration:shadow_offset")->vecValue;
if (*PSHADOWS != 1)
@@ -73,22 +74,48 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a, const Vector2D
const auto ROUNDING = !m_pWindow->m_sSpecialRenderData.rounding ? 0 : (m_pWindow->m_sAdditionalConfigData.rounding == -1 ? *PROUNDING : m_pWindow->m_sAdditionalConfigData.rounding);
// update the extents
m_seExtents = {{*PSHADOWSIZE + 2 - PSHADOWOFFSET->x, *PSHADOWSIZE + 2 - PSHADOWOFFSET->y}, {*PSHADOWSIZE + 2 + PSHADOWOFFSET->x, *PSHADOWSIZE + 2 + PSHADOWOFFSET->y}};
// draw the shadow
wlr_box fullBox = {m_vLastWindowPos.x - m_seExtents.topLeft.x + 2, m_vLastWindowPos.y - m_seExtents.topLeft.y + 2, m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x - 4, m_vLastWindowSize.y + m_seExtents.topLeft.y + m_seExtents.bottomRight.y - 4};
wlr_box fullBox = { m_vLastWindowPos.x - *PSHADOWSIZE, m_vLastWindowPos.y - *PSHADOWSIZE,
m_vLastWindowSize.x + 2.0 * *PSHADOWSIZE, m_vLastWindowSize.y + 2.0 * *PSHADOWSIZE };
fullBox.x -= pMonitor->vecPosition.x;
fullBox.y -= pMonitor->vecPosition.y;
const float SHADOWSCALE = std::clamp(*PSHADOWSCALE, 0.f, 1.f);
// scale the box in relation to the center of the box
const Vector2D NEWSIZE = Vector2D { fullBox.width, fullBox.height } * SHADOWSCALE;
fullBox.width = NEWSIZE.x;
fullBox.height = NEWSIZE.y;
if (PSHADOWOFFSET->x < 0) {
fullBox.x += PSHADOWOFFSET->x;
} else if (PSHADOWOFFSET->x > 0) {
fullBox.x = m_vLastWindowPos.x + m_vLastWindowSize.x - fullBox.width + (SHADOWSCALE * *PSHADOWSIZE) + PSHADOWOFFSET->x - pMonitor->vecPosition.x;
} else {
fullBox.x += ((m_vLastWindowSize.x + 2.0 * *PSHADOWSIZE) - NEWSIZE.x) / 2.0;
}
if (PSHADOWOFFSET->y < 0) {
fullBox.y += PSHADOWOFFSET->y;
} else if (PSHADOWOFFSET->y > 0) {
fullBox.y = m_vLastWindowPos.y + m_vLastWindowSize.y - fullBox.height + (SHADOWSCALE * *PSHADOWSIZE) + PSHADOWOFFSET->y - pMonitor->vecPosition.y;
} else {
fullBox.y += ((m_vLastWindowSize.y + 2.0 * *PSHADOWSIZE) - NEWSIZE.y) / 2.0;
}
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
return; // don't draw invisible shadows
g_pHyprOpenGL->scissor((wlr_box *)nullptr);
g_pHyprOpenGL->scissor((wlr_box*)nullptr);
if (*PSHADOWIGNOREWINDOW) {
glEnable(GL_STENCIL_TEST);