mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-08-15 20:13:49 -07:00
Compare commits
113 Commits
v0.18.0bet
...
v0.19.1bet
Author | SHA1 | Date | |
---|---|---|---|
|
e1d7a13333 | ||
|
bf5844d607 | ||
|
5b7fec481b | ||
|
73b3bbe49b | ||
|
d8dcf670da | ||
|
87b9313034 | ||
|
993c382e74 | ||
|
3c9a7811b8 | ||
|
6c8d993477 | ||
|
dfa9277867 | ||
|
50e37419e9 | ||
|
22978aa31e | ||
|
7ed401e5e0 | ||
|
da76a1ed9e | ||
|
9c67e08dbd | ||
|
6cf716f182 | ||
|
9fb24ac1e9 | ||
|
66fb083003 | ||
|
20b91f58f8 | ||
|
ac0e675f3b | ||
|
f71f04db9e | ||
|
9e4e98acfb | ||
|
826e35f7a4 | ||
|
ffc580dda9 | ||
|
4557d13a32 | ||
|
215c7bd3cb | ||
|
ea2ef63de5 | ||
|
d9998f2ca5 | ||
|
686d6fc6d1 | ||
|
9e8df888eb | ||
|
409ac12f23 | ||
|
6aa26582f6 | ||
|
056a45d035 | ||
|
fbc839e8d9 | ||
|
cb85eea261 | ||
|
439b827a08 | ||
|
d39d6cc1e3 | ||
|
d6b3bfc48e | ||
|
70d4fadc39 | ||
|
a2a12018d9 | ||
|
10d34ef818 | ||
|
bf52545a91 | ||
|
c012e3d66b | ||
|
39a4f82460 | ||
|
7b020ffa84 | ||
|
b8ccf3dc3a | ||
|
869f0a0238 | ||
|
ff4ea1a13a | ||
|
51aebb2845 | ||
|
212f599412 | ||
|
55776df685 | ||
|
3dd06b674a | ||
|
12df799572 | ||
|
c341792092 | ||
|
afe12dc90b | ||
|
45d2d1e97d | ||
|
0a302901d2 | ||
|
49063f949d | ||
|
7699d657d9 | ||
|
b2cb3b8bf2 | ||
|
6cbaad896c | ||
|
9247f88d0c | ||
|
92f2e342a3 | ||
|
e2f3f5fe63 | ||
|
0db75852f3 | ||
|
afe688e6ab | ||
|
493fc00953 | ||
|
c709dc5e8e | ||
|
684c59e5bc | ||
|
0948b078e1 | ||
|
52c0356900 | ||
|
1c9a0be8c4 | ||
|
f45ec24977 | ||
|
75b7e661e7 | ||
|
381d7a4300 | ||
|
0e6e8461eb | ||
|
141456dd89 | ||
|
9616dc7bd8 | ||
|
379597e78f | ||
|
f6067816fb | ||
|
750eb76df3 | ||
|
79a9bc9076 | ||
|
dcb6a0425c | ||
|
e15a9f3d7d | ||
|
b0f95c63c9 | ||
|
5327565b33 | ||
|
95047fb083 | ||
|
f00b2fd509 | ||
|
eb86e7967f | ||
|
88874fcfe2 | ||
|
d504c1e5ab | ||
|
c78db1212b | ||
|
be03a6186c | ||
|
41a8975bd1 | ||
|
254c3d166f | ||
|
137cf9e582 | ||
|
11e841580f | ||
|
f8b9138383 | ||
|
c03e4c36b0 | ||
|
5530cf6e79 | ||
|
1f72237291 | ||
|
e427d9f622 | ||
|
f88feec02b | ||
|
df132e5ff3 | ||
|
0ffaa8d667 | ||
|
e887149f25 | ||
|
250d61e0b3 | ||
|
ba05c43ae3 | ||
|
82fe530045 | ||
|
f91f3d1c81 | ||
|
5d39223239 | ||
|
d2a7e22efd | ||
|
724e411ffc |
2
.github/workflows/release.yaml
vendored
2
.github/workflows/release.yaml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
|
||||
- name: Create tarball with submodules
|
||||
id: tar
|
||||
run: tar -czv --owner=0 --group=0 --no-same-owner --no-same-permissions -f source.tar.gz *
|
||||
run: mkdir hyprland-source; mv ./* ./hyprland-source || tar -czv --owner=0 --group=0 --no-same-owner --no-same-permissions -f source.tar.gz *
|
||||
|
||||
- id: whatrelease
|
||||
name: Get latest release
|
||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +1,6 @@
|
||||
[submodule "wlroots"]
|
||||
path = subprojects/wlroots
|
||||
url = https://gitlab.freedesktop.org/wlroots/wlroots.git
|
||||
[submodule "subprojects/hyprland-protocols"]
|
||||
path = subprojects/hyprland-protocols
|
||||
url = https://github.com/hyprwm/hyprland-protocols
|
||||
|
@@ -45,7 +45,8 @@ ENDIF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||
|
||||
include_directories(. PRIVATE "subprojects/wlroots/include/")
|
||||
include_directories(. PRIVATE "subprojects/wlroots/build/include/")
|
||||
add_compile_options(-std=c++23 -DWLR_USE_UNSTABLE )
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
add_compile_options(-DWLR_USE_UNSTABLE)
|
||||
add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing)
|
||||
|
||||
message(STATUS "Checking deps...")
|
||||
@@ -96,6 +97,7 @@ target_link_libraries(Hyprland
|
||||
pthread
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${CMAKE_SOURCE_DIR}/ext-workspace-unstable-v1-protocol.o
|
||||
${CMAKE_SOURCE_DIR}/hyprland-toplevel-export-v1-protocol.o
|
||||
)
|
||||
|
||||
IF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||
|
19
Makefile
19
Makefile
@@ -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
|
||||
|
||||
hyprland-toplevel-export-v1-protocol.h:
|
||||
$(WAYLAND_SCANNER) server-header \
|
||||
subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml $@
|
||||
|
||||
hyprland-toplevel-export-v1-protocol.c:
|
||||
$(WAYLAND_SCANNER) private-code \
|
||||
subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml $@
|
||||
|
||||
hyprland-toplevel-export-v1-protocol.o: hyprland-toplevel-export-v1-protocol.h
|
||||
|
||||
linux-dmabuf-unstable-v1-protocol.h:
|
||||
$(WAYLAND_SCANNER) server-header \
|
||||
$(WAYLAND_PROTOCOLS)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml $@
|
||||
@@ -124,9 +134,12 @@ clear:
|
||||
rm -rf ./subprojects/wlroots/build
|
||||
|
||||
all:
|
||||
make config
|
||||
make clear
|
||||
make fixwlr
|
||||
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 ..
|
||||
cd hyprctl && make all && cd ..
|
||||
|
||||
install:
|
||||
make clear
|
||||
@@ -176,7 +189,7 @@ uninstall:
|
||||
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 linux-dmabuf-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 hyprland-toplevel-export-v1-protocol.o
|
||||
|
||||
fixwlr:
|
||||
sed -i -E 's/(soversion = 12)([^032]|$$)/soversion = 12032/g' subprojects/wlroots/meson.build
|
||||
|
20
README.md
20
README.md
@@ -6,7 +6,6 @@
|
||||
|
||||
![Badge Workflow]
|
||||
[![Badge License]][License]
|
||||
![Badge Lines]
|
||||
![Badge Language]
|
||||
[![Badge Pull Requests]][Pull Requests]
|
||||
[![Badge Issues]][Issues]
|
||||
@@ -40,31 +39,28 @@ Hyprland is still in pretty early development compared to some other Wayland com
|
||||
|
||||
Although Hyprland is pretty stable, it may have some bugs.
|
||||
|
||||
### Help Wanted
|
||||
|
||||
Hyprland needs testers! <br/>
|
||||
Try it out and report bugs / suggestions!
|
||||
|
||||
# Features
|
||||
|
||||
- Easily expandable and readable codebase
|
||||
- Config reloaded instantly upon saving
|
||||
- Custom bezier curve based animations
|
||||
- `wlr_ext` workspaces protocol support
|
||||
- Dual Kawase blur
|
||||
- Drop shadows
|
||||
- Rounded corners
|
||||
- Gradient borders
|
||||
- Fully dynamic workspaces
|
||||
- Closely follows `wlroots-git`
|
||||
- Global keybinds passed to your apps of choice
|
||||
- A lot of customization
|
||||
- Bundled wlroots
|
||||
- Window/layer fade in/out
|
||||
- Tiling/pseudotiling/floating/fullscreen windows
|
||||
- Switching workspaces between window modes on the fly
|
||||
- Special workspace (scratchpad)
|
||||
- Special workspaces (scratchpads)
|
||||
- Window/monitor rules
|
||||
- Socket-based IPC
|
||||
- `wlr_ext` workspaces protocol support
|
||||
- Event system for bash scripts
|
||||
- Rounded corners
|
||||
- Full damage tracking
|
||||
- Docks support
|
||||
- Drawing tablet support
|
||||
@@ -150,9 +146,9 @@ Try it out and report bugs / suggestions!
|
||||
<!----------------------------------{ Images }--------------------------------->
|
||||
|
||||
[Stars Preview]: https://starchart.cc/vaxerski/Hyprland.svg
|
||||
[Preview A]: https://i.imgur.com/pC6YF1Y.png
|
||||
[Preview B]: https://i.imgur.com/NbrTnZH.png
|
||||
[Preview C]: https://i.imgur.com/sCafdKQ.png
|
||||
[Preview A]: https://i.ibb.co/B3GJg28/20221126-20h53m26s-grim.png
|
||||
[Preview B]: https://i.imgur.com/pC6YF1Y.png
|
||||
[Preview C]: https://i.imgur.com/NbrTnZH.png
|
||||
|
||||
|
||||
<!----------------------------------{ Badges }--------------------------------->
|
||||
|
@@ -1,10 +1,10 @@
|
||||
.\" Automatically generated by Pandoc 2.5
|
||||
.\" Automatically generated by Pandoc 2.9.2.1
|
||||
.\"
|
||||
.TH "Hyprland" "1" "11 Oct 2022" "" "Hyprland User Manual"
|
||||
.TH "Hyprland" "1" "02 Dec 2022" "" "Hyprland User Manual"
|
||||
.hy
|
||||
.SH NAME
|
||||
.PP
|
||||
Hyprland \- Dynamic tiling Wayland compositor
|
||||
Hyprland - Dynamic tiling Wayland compositor
|
||||
.SH SYNOPSIS
|
||||
.PP
|
||||
\f[B]Hyprland\f[R] [\f[I]arg [...]\f[R]].
|
||||
@@ -27,14 +27,14 @@ For configuration information please see
|
||||
<\f[I]https://github.com/hyprwm/Hyprland/wiki\f[R]>.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \f[B]\-h\f[R], \f[B]\-\-help\f[R]
|
||||
\f[B]-h\f[R], \f[B]--help\f[R]
|
||||
Show command usage.
|
||||
.TP
|
||||
.B \f[B]\-c\f[R], \f[B]\-\-config\f[R]
|
||||
\f[B]-c\f[R], \f[B]--config\f[R]
|
||||
Specify config file to use.
|
||||
.SH BUGS
|
||||
.TP
|
||||
.B Submit bug reports and request features online at:
|
||||
Submit bug reports and request features online at:
|
||||
<\f[I]https://github.com/hyprwm/Hyprland/issues\f[R]>
|
||||
.SH SEE ALSO
|
||||
.PP
|
||||
|
@@ -1,10 +1,10 @@
|
||||
.\" Automatically generated by Pandoc 2.5
|
||||
.\" Automatically generated by Pandoc 2.9.2.1
|
||||
.\"
|
||||
.TH "hyprctl" "1" "11 Oct 2022" "" "hyprctl User Manual"
|
||||
.TH "hyprctl" "1" "02 Dec 2022" "" "hyprctl User Manual"
|
||||
.hy
|
||||
.SH NAME
|
||||
.PP
|
||||
hyprctl \- Utility for controlling parts of Hyprland from a CLI or a
|
||||
hyprctl - Utility for controlling parts of Hyprland from a CLI or a
|
||||
script
|
||||
.SH SYNOPSIS
|
||||
.PP
|
||||
@@ -26,7 +26,7 @@ For dispatchers without parameters it can be anything.
|
||||
.PP
|
||||
Returns: \f[I]ok\f[R] on success, and an error message on failure.
|
||||
.TP
|
||||
.B Examples:
|
||||
Examples:
|
||||
\f[B]hyprctl\f[R] \f[I]dispatch exec kitty\f[R]
|
||||
.RS
|
||||
.PP
|
||||
@@ -41,7 +41,7 @@ Set a config keyword dynamically.
|
||||
.PP
|
||||
Returns: \f[I]ok\f[R] on success, and an error message on failure.
|
||||
.TP
|
||||
.B Examples:
|
||||
Examples:
|
||||
\f[B]hyprctl\f[R] \f[I]keyword bind SUPER,0,pseudo\f[R]
|
||||
.RS
|
||||
.PP
|
||||
@@ -112,13 +112,13 @@ Returns the current random splash.
|
||||
.RE
|
||||
.SH OPTIONS
|
||||
.PP
|
||||
\f[B]\-\-batch\f[R]
|
||||
\f[B]--batch\f[R]
|
||||
.RS
|
||||
.PP
|
||||
Specify a batch of commands to execute.
|
||||
.TP
|
||||
.B Example:
|
||||
\f[B]hyprctl\f[R] \f[I]\-\-batch \[dq]keyword general:border_size 2 ;
|
||||
Example:
|
||||
\f[B]hyprctl\f[R] \f[I]--batch \[dq]keyword general:border_size 2 ;
|
||||
keyword general:gaps_out 20\[dq]\f[R]
|
||||
.RS
|
||||
.PP
|
||||
@@ -126,14 +126,14 @@ keyword general:gaps_out 20\[dq]\f[R]
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\f[B]\-j\f[R]
|
||||
\f[B]-j\f[R]
|
||||
.RS
|
||||
.PP
|
||||
Outputs information in JSON.
|
||||
.RE
|
||||
.SH BUGS
|
||||
.TP
|
||||
.B Submit bug reports and request features online at:
|
||||
Submit bug reports and request features online at:
|
||||
<\f[I]https://github.com/hyprwm/Hyprland/issues\f[R]>
|
||||
.SH SEE ALSO
|
||||
.PP
|
||||
|
@@ -42,7 +42,7 @@ general {
|
||||
gaps_in = 5
|
||||
gaps_out = 20
|
||||
border_size = 2
|
||||
col.active_border = rgba(1affffee)
|
||||
col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg
|
||||
col.inactive_border = rgba(595959aa)
|
||||
|
||||
layout = dwindle
|
||||
|
16
example/screenShader.frag
Normal file
16
example/screenShader.frag
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Example blue light filter shader.
|
||||
//
|
||||
|
||||
precision mediump float;
|
||||
varying vec2 v_texcoord;
|
||||
uniform sampler2D tex;
|
||||
|
||||
void main() {
|
||||
|
||||
vec4 pixColor = texture2D(tex, v_texcoord);
|
||||
|
||||
pixColor[2] *= 0.8;
|
||||
|
||||
gl_FragColor = pixColor;
|
||||
}
|
69
flake.lock
generated
69
flake.lock
generated
@@ -1,12 +1,44 @@
|
||||
{
|
||||
"nodes": {
|
||||
"hyprland-protocols": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1670258048,
|
||||
"narHash": "sha256-Lm2sXnDVZNE+taHqsqVibvPmSdu65VHvXI507KVX4lg=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-protocols",
|
||||
"rev": "0dcff94fc10df2bbb66d3e1b5a1d6cfd3ada5515",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-protocols",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprland-protocols_2": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1670185345,
|
||||
"narHash": "sha256-hxWGqlPecqEsE6nOHDV29KFBKePbY2Ipeac6lrChMKY=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-protocols",
|
||||
"rev": "4623a404c091e64743ba310199bb380ec52f1936",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-protocols",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1668087632,
|
||||
"narHash": "sha256-T/cUx44aYDuLMFfaiVpMdTjL4kpG7bh0VkN6JEM78/E=",
|
||||
"lastModified": 1670064435,
|
||||
"narHash": "sha256-+ELoY30UN+Pl3Yn7RWRPabykwebsVK/kYE9JsIsUMxQ=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5f588eb4a958f1a526ed8da02d6ea1bea0047b9f",
|
||||
"rev": "61a8a98e6d557e6dd7ed0cdb54c3a3e3bbc5e25c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -18,19 +50,21 @@
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"hyprland-protocols": "hyprland-protocols",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"wlroots": "wlroots"
|
||||
"wlroots": "wlroots",
|
||||
"xdph": "xdph"
|
||||
}
|
||||
},
|
||||
"wlroots": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"host": "gitlab.freedesktop.org",
|
||||
"lastModified": 1668292512,
|
||||
"narHash": "sha256-lCMnIguyZgAGq7W2IwIVPoQS8fAfZ/XFwz/1TQ53eI8=",
|
||||
"lastModified": 1669925104,
|
||||
"narHash": "sha256-xMHfW+/G9MieN/5tXHUA5/ztE8dkE093cNFTEUgcwxI=",
|
||||
"owner": "wlroots",
|
||||
"repo": "wlroots",
|
||||
"rev": "627a5c511278e67c3c308cdc6a639cbb490f48c3",
|
||||
"rev": "c8eb24d30e18c165728b8788a10716611c3b633d",
|
||||
"type": "gitlab"
|
||||
},
|
||||
"original": {
|
||||
@@ -39,6 +73,27 @@
|
||||
"repo": "wlroots",
|
||||
"type": "gitlab"
|
||||
}
|
||||
},
|
||||
"xdph": {
|
||||
"inputs": {
|
||||
"hyprland-protocols": "hyprland-protocols_2",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1670202338,
|
||||
"narHash": "sha256-StTfshdAoSxO+t0wRbq1I3YESLFIQWFjGJse5ICV8rk=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "xdg-desktop-portal-hyprland",
|
||||
"rev": "af840a9e0947a79a37a95a9f62062653721e43fa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "xdg-desktop-portal-hyprland",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
|
49
flake.nix
49
flake.nix
@@ -7,6 +7,16 @@
|
||||
url = "gitlab:wlroots/wlroots?host=gitlab.freedesktop.org";
|
||||
flake = false;
|
||||
};
|
||||
|
||||
xdph = {
|
||||
url = "github:hyprwm/xdg-desktop-portal-hyprland";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
hyprland-protocols = {
|
||||
url = "github:hyprwm/hyprland-protocols";
|
||||
flake = false;
|
||||
};
|
||||
};
|
||||
|
||||
outputs = inputs @ {
|
||||
@@ -21,12 +31,28 @@
|
||||
"x86_64-linux"
|
||||
];
|
||||
|
||||
pkgsFor = genSystems (system: import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [(_: prev: {
|
||||
hwdata = prev.callPackage ./nix/hwdata.nix {};
|
||||
})];
|
||||
});
|
||||
pkgsFor = genSystems (system:
|
||||
import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [
|
||||
(_: prev: {
|
||||
libdrm = prev.libdrm.overrideAttrs (old: rec {
|
||||
version = "2.4.114";
|
||||
src = prev.fetchurl {
|
||||
url = "https://dri.freedesktop.org/${old.pname}/${old.pname}-${version}.tar.xz";
|
||||
sha256 = "sha256-MEnPhDpH0S5e7vvDvjSW14L6CfQjRr8Lfe/j0eWY0CY=";
|
||||
};
|
||||
});
|
||||
wayland-protocols = prev.wayland-protocols.overrideAttrs (old: rec {
|
||||
version = "1.29";
|
||||
src = prev.fetchurl {
|
||||
url = "https://gitlab.freedesktop.org/wayland/${old.pname}/-/releases/${version}/downloads/${old.pname}-${version}.tar.xz";
|
||||
hash = "sha256-4l6at1rHNnBN3v6S6PmshzC+q29WTbYvetaVu6T/ntg=";
|
||||
};
|
||||
});
|
||||
})
|
||||
];
|
||||
});
|
||||
|
||||
mkDate = longDate: (lib.concatStringsSep "-" [
|
||||
(builtins.substring 0 4 longDate)
|
||||
@@ -41,8 +67,9 @@
|
||||
};
|
||||
hyprland = prev.callPackage ./nix/default.nix {
|
||||
stdenv = prev.gcc12Stdenv;
|
||||
version = "0.17.0beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty");
|
||||
version = "0.18.0beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty");
|
||||
wlroots = wlroots-hyprland;
|
||||
inherit (inputs) hyprland-protocols;
|
||||
};
|
||||
hyprland-debug = hyprland.override {debug = true;};
|
||||
hyprland-no-hidpi = hyprland.override {hidpiXWayland = false;};
|
||||
@@ -61,6 +88,12 @@
|
||||
devShells = genSystems (system: {
|
||||
default = pkgsFor.${system}.mkShell.override {stdenv = pkgsFor.${system}.gcc12Stdenv;} {
|
||||
name = "hyprland-shell";
|
||||
nativeBuildInputs = with pkgsFor.${system}; [
|
||||
cmake
|
||||
];
|
||||
buildInputs = [
|
||||
self.packages.${system}.wlroots-hyprland
|
||||
];
|
||||
inputsFrom = [
|
||||
self.packages.${system}.wlroots-hyprland
|
||||
self.packages.${system}.hyprland
|
||||
@@ -70,7 +103,7 @@
|
||||
|
||||
formatter = genSystems (system: pkgsFor.${system}.alejandra);
|
||||
|
||||
nixosModules.default = import ./nix/module.nix self;
|
||||
nixosModules.default = import ./nix/module.nix inputs;
|
||||
homeManagerModules.default = import ./nix/hm-module.nix self;
|
||||
};
|
||||
|
||||
|
@@ -37,15 +37,23 @@ commands:
|
||||
setcursor
|
||||
getoption
|
||||
cursorpos
|
||||
switchxkblayout
|
||||
|
||||
flags:
|
||||
-j -> output in JSON
|
||||
--batch -> execute a batch of commands, separated by ';'
|
||||
)#";
|
||||
|
||||
void request(std::string arg) {
|
||||
void request(std::string arg, int minArgs = 0) {
|
||||
const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
const auto ARGS = std::count(arg.begin(), arg.end(), ' ');
|
||||
|
||||
if (ARGS < minArgs) {
|
||||
std::cout << "Not enough arguments, expected at least " << minArgs;
|
||||
return;
|
||||
}
|
||||
|
||||
if (SERVERSOCKET < 0) {
|
||||
std::cout << "Couldn't open a socket (1)";
|
||||
return;
|
||||
@@ -316,6 +324,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("/switchxkblayout")) request(fullRequest, 2);
|
||||
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);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
project('Hyprland', 'cpp', 'c',
|
||||
version : '0.17.0beta',
|
||||
version : '0.18.0beta',
|
||||
default_options : [
|
||||
'warning_level=2',
|
||||
'default_library=static',
|
||||
|
@@ -7,6 +7,7 @@
|
||||
meson,
|
||||
ninja,
|
||||
git,
|
||||
hyprland-protocols,
|
||||
libdrm,
|
||||
libinput,
|
||||
libxcb,
|
||||
@@ -92,6 +93,10 @@ in
|
||||
# Fix hardcoded paths to /usr installation
|
||||
postPatch = ''
|
||||
sed -i "s#/usr#$out#" src/render/OpenGL.cpp
|
||||
|
||||
# for some reason rmdir doesn't work in a dirty tree
|
||||
rmdir subprojects/hyprland-protocols || true
|
||||
ln -s ${hyprland-protocols} subprojects/hyprland-protocols
|
||||
'';
|
||||
|
||||
passthru.providedSessions = ["hyprland"];
|
||||
|
@@ -92,11 +92,7 @@ in {
|
||||
++ lib.optional cfg.xwayland.enable pkgs.xwayland;
|
||||
|
||||
home.sessionVariables = lib.mkIf cfg.recommendedEnvironment {
|
||||
GDK_BACKEND = "wayland,x11";
|
||||
_JAVA_AWT_WM_NONREPARENTING = "1";
|
||||
NIXOS_OZONE_WL = "1";
|
||||
XCURSOR_SIZE = toString config.home.pointerCursor.size or "24";
|
||||
XDG_SESSION_TYPE = "wayland";
|
||||
};
|
||||
|
||||
xdg.configFile."hypr/hyprland.conf" = {
|
||||
|
@@ -1,28 +0,0 @@
|
||||
{ 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;
|
||||
};
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
# Copied from https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/programs/sway.nix
|
||||
self: {
|
||||
inputs: {
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
@@ -23,7 +23,7 @@ in {
|
||||
|
||||
package = mkOption {
|
||||
type = types.nullOr types.package;
|
||||
default = self.packages.${pkgs.system}.default;
|
||||
default = inputs.self.packages.${pkgs.system}.default;
|
||||
defaultText = literalExpression "<Hyprland flake>.packages.<system>.default";
|
||||
example = literalExpression "<Hyprland flake>.packages.<system>.default.override { }";
|
||||
description = ''
|
||||
@@ -47,24 +47,30 @@ in {
|
||||
systemPackages = lib.optional (cfg.package != null) cfg.package;
|
||||
|
||||
sessionVariables = mkIf cfg.recommendedEnvironment {
|
||||
GDK_BACKEND = "wayland,x11";
|
||||
_JAVA_AWT_WM_NONREPARENTING = "1";
|
||||
NIXOS_OZONE_WL = "1";
|
||||
XCURSOR_SIZE = "24";
|
||||
XDG_SESSION_TYPE = "wayland";
|
||||
};
|
||||
};
|
||||
|
||||
fonts.enableDefaultFonts = mkDefault true;
|
||||
hardware.opengl.enable = mkDefault true;
|
||||
|
||||
# enable cachix
|
||||
nix.settings = {
|
||||
substituters = ["https://hyprland.cachix.org"];
|
||||
trusted-public-keys = ["hyprland.cachix.org-1:a7pgxzMz7+chwVL3/pzj6jIBMioiJM7ypFP8PwtkuGc="];
|
||||
};
|
||||
|
||||
programs = {
|
||||
dconf.enable = mkDefault true;
|
||||
xwayland.enable = mkDefault true;
|
||||
};
|
||||
|
||||
security.polkit.enable = true;
|
||||
services.xserver.displayManager.sessionPackages = lib.optional (cfg.package != null) cfg.package;
|
||||
xdg.portal = {
|
||||
enable = mkDefault true;
|
||||
extraPortals = [pkgs.xdg-desktop-portal-wlr];
|
||||
# xdg-desktop-portal-hyprland
|
||||
extraPortals = [inputs.xdph.packages.${pkgs.system}.default];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@@ -3,7 +3,14 @@ wayland_protos = dependency('wayland-protocols',
|
||||
fallback: 'wayland-protocols',
|
||||
default_options: ['tests=false'],
|
||||
)
|
||||
|
||||
hyprland_protos = dependency('hyprland-protocols',
|
||||
version: '>=0.1',
|
||||
fallback: 'hyprland-protocols',
|
||||
)
|
||||
|
||||
wl_protocol_dir = wayland_protos.get_variable('pkgdatadir')
|
||||
hl_protocol_dir = hyprland_protos.get_variable('pkgdatadir')
|
||||
|
||||
wayland_scanner_dep = dependency('wayland-scanner', native: true)
|
||||
wayland_scanner = find_program(
|
||||
@@ -19,7 +26,8 @@ protocols = [
|
||||
['ext-workspace-unstable-v1.xml'],
|
||||
['pointer-constraints-unstable-v1.xml'],
|
||||
['tablet-unstable-v2.xml'],
|
||||
['idle.xml']
|
||||
['idle.xml'],
|
||||
[hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml']
|
||||
]
|
||||
wl_protos_src = []
|
||||
wl_protos_headers = []
|
||||
|
@@ -53,7 +53,7 @@ CCompositor::CCompositor() {
|
||||
wl_event_loop_add_signal(m_sWLEventLoop, SIGTERM, handleCritSignal, nullptr);
|
||||
//wl_event_loop_add_signal(m_sWLEventLoop, SIGINT, handleCritSignal, nullptr);
|
||||
|
||||
m_sWLRBackend = wlr_backend_autocreate(m_sWLDisplay);
|
||||
m_sWLRBackend = wlr_backend_autocreate(m_sWLDisplay, &m_sWLRSession);
|
||||
|
||||
if (!m_sWLRBackend) {
|
||||
Debug::log(CRIT, "m_sWLRBackend was NULL!");
|
||||
@@ -76,11 +76,10 @@ CCompositor::CCompositor() {
|
||||
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) {
|
||||
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_sWLRLinuxDMABuf = wlr_linux_dmabuf_v1_create_with_renderer(m_sWLDisplay, 4, m_sWLRRenderer);
|
||||
}
|
||||
|
||||
m_sWLRAllocator = wlr_allocator_autocreate(m_sWLRBackend, m_sWLRRenderer);
|
||||
@@ -132,7 +131,7 @@ CCompositor::CCompositor() {
|
||||
|
||||
m_sWLRIdle = wlr_idle_create(m_sWLDisplay);
|
||||
|
||||
m_sWLRLayerShell = wlr_layer_shell_v1_create(m_sWLDisplay);
|
||||
m_sWLRLayerShell = wlr_layer_shell_v1_create(m_sWLDisplay, 4);
|
||||
|
||||
m_sWLRServerDecoMgr = wlr_server_decoration_manager_create(m_sWLDisplay);
|
||||
m_sWLRXDGDecoMgr = wlr_xdg_decoration_manager_v1_create(m_sWLDisplay);
|
||||
@@ -173,8 +172,6 @@ CCompositor::CCompositor() {
|
||||
|
||||
m_sWLRPointerGestures = wlr_pointer_gestures_v1_create(m_sWLDisplay);
|
||||
|
||||
m_sWLRSession = wlr_backend_get_session(m_sWLRBackend);
|
||||
|
||||
m_sWLRTextInputMgr = wlr_text_input_manager_v3_create(m_sWLDisplay);
|
||||
|
||||
m_sWLRIMEMgr = wlr_input_method_manager_v2_create(m_sWLDisplay);
|
||||
@@ -329,6 +326,9 @@ void CCompositor::startCompositor() {
|
||||
Debug::log(LOG, "Creating the XWaylandManager!");
|
||||
g_pXWaylandManager = std::make_unique<CHyprXWaylandManager>();
|
||||
|
||||
Debug::log(LOG, "Creating the ProtocolManager!");
|
||||
g_pProtocolManager = std::make_unique<CProtocolManager>();
|
||||
|
||||
Debug::log(LOG, "Creating the EventManager!");
|
||||
g_pEventManager = std::make_unique<CEventManager>();
|
||||
g_pEventManager->startThread();
|
||||
@@ -345,15 +345,21 @@ void CCompositor::startCompositor() {
|
||||
|
||||
initAllSignals();
|
||||
|
||||
m_szWLDisplaySocket = wl_display_add_socket_auto(m_sWLDisplay);
|
||||
// get socket, avoid using 0
|
||||
for (int candidate = 1; candidate <= 32; candidate++) {
|
||||
if (wl_display_add_socket(m_sWLDisplay, ("wayland-" + std::to_string(candidate)).c_str()) >= 0) {
|
||||
m_szWLDisplaySocket = "wayland-" + std::to_string(candidate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_szWLDisplaySocket) {
|
||||
if (m_szWLDisplaySocket.empty()) {
|
||||
Debug::log(CRIT, "m_szWLDisplaySocket NULL!");
|
||||
wlr_backend_destroy(m_sWLRBackend);
|
||||
throw std::runtime_error("m_szWLDisplaySocket was null! (wl_display_add_socket_auto failed)");
|
||||
}
|
||||
|
||||
setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket, 1);
|
||||
setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket.c_str(), 1);
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
@@ -432,7 +438,7 @@ CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) {
|
||||
void CCompositor::removeWindowFromVectorSafe(CWindow* pWindow) {
|
||||
if (windowExists(pWindow) && !pWindow->m_bFadingOut){
|
||||
if (pWindow->m_bIsX11 && pWindow->m_iX11Type == 2) {
|
||||
m_dUnmanagedX11Windows.erase(std::remove_if(m_dUnmanagedX11Windows.begin(), m_dUnmanagedX11Windows.end(), [&](std::unique_ptr<CWindow>& el) { return el.get() == pWindow; }));
|
||||
std::erase_if(m_dUnmanagedX11Windows, [&](std::unique_ptr<CWindow>& el) { return el.get() == pWindow; });
|
||||
}
|
||||
|
||||
// if X11, also check its children
|
||||
@@ -443,16 +449,16 @@ void CCompositor::removeWindowFromVectorSafe(CWindow* pWindow) {
|
||||
continue;
|
||||
|
||||
if (w->m_pX11Parent == pWindow)
|
||||
m_vWindows.erase(std::remove_if(m_vWindows.begin(), m_vWindows.end(), [&](std::unique_ptr<CWindow>& el) { return el.get() == w.get(); }));
|
||||
std::erase_if(m_vWindows, [&](std::unique_ptr<CWindow>& el) { return el.get() == w.get(); });
|
||||
}
|
||||
|
||||
for (auto& w : m_dUnmanagedX11Windows) {
|
||||
if (w->m_pX11Parent == pWindow)
|
||||
m_dUnmanagedX11Windows.erase(std::remove_if(m_dUnmanagedX11Windows.begin(), m_dUnmanagedX11Windows.end(), [&](std::unique_ptr<CWindow>& el) { return el.get() == w.get(); }));
|
||||
std::erase_if(m_dUnmanagedX11Windows, [&](std::unique_ptr<CWindow>& el) { return el.get() == w.get(); });
|
||||
}
|
||||
}
|
||||
|
||||
m_vWindows.erase(std::remove_if(m_vWindows.begin(), m_vWindows.end(), [&](std::unique_ptr<CWindow>& el) { return el.get() == pWindow; }));
|
||||
std::erase_if(m_vWindows, [&](std::unique_ptr<CWindow>& el) { return el.get() == pWindow; });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,16 +474,16 @@ bool CCompositor::windowExists(CWindow* pWindow) {
|
||||
CWindow* CCompositor::vectorToWindow(const Vector2D& pos) {
|
||||
const auto PMONITOR = getMonitorFromVector(pos);
|
||||
|
||||
if (PMONITOR->specialWorkspaceOpen) {
|
||||
if (PMONITOR->specialWorkspaceID) {
|
||||
for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) {
|
||||
wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y};
|
||||
if ((*w)->m_bIsFloating && (*w)->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && (*w)->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !(*w)->isHidden())
|
||||
if ((*w)->m_bIsFloating && (*w)->m_iWorkspaceID == PMONITOR->specialWorkspaceID && (*w)->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !(*w)->isHidden())
|
||||
return (*w).get();
|
||||
}
|
||||
|
||||
for (auto& w : m_vWindows) {
|
||||
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
|
||||
if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && !w->m_bIsFloating && !w->isHidden())
|
||||
if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && !w->m_bIsFloating && !w->isHidden())
|
||||
return w.get();
|
||||
}
|
||||
}
|
||||
@@ -508,10 +514,10 @@ CWindow* CCompositor::vectorToWindow(const Vector2D& pos) {
|
||||
CWindow* CCompositor::vectorToWindowTiled(const Vector2D& pos) {
|
||||
const auto PMONITOR = getMonitorFromVector(pos);
|
||||
|
||||
if (PMONITOR->specialWorkspaceOpen) {
|
||||
if (PMONITOR->specialWorkspaceID) {
|
||||
for (auto& w : m_vWindows) {
|
||||
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
|
||||
if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && wlr_box_contains_point(&box, pos.x, pos.y) && !w->m_bIsFloating && !w->isHidden())
|
||||
if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && wlr_box_contains_point(&box, pos.x, pos.y) && !w->m_bIsFloating && !w->isHidden())
|
||||
return w.get();
|
||||
}
|
||||
}
|
||||
@@ -538,16 +544,16 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
|
||||
const auto PMONITOR = getMonitorFromVector(pos);
|
||||
|
||||
// special workspace
|
||||
if (PMONITOR->specialWorkspaceOpen) {
|
||||
if (PMONITOR->specialWorkspaceID) {
|
||||
for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) {
|
||||
wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y};
|
||||
if ((*w)->m_bIsFloating && (*w)->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && (*w)->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !(*w)->isHidden() && !(*w)->m_bX11ShouldntFocus)
|
||||
if ((*w)->m_bIsFloating && (*w)->m_iWorkspaceID == PMONITOR->specialWorkspaceID && (*w)->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !(*w)->isHidden() && !(*w)->m_bX11ShouldntFocus)
|
||||
return (*w).get();
|
||||
}
|
||||
|
||||
for (auto& w : m_vWindows) {
|
||||
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
|
||||
if (!w->m_bIsFloating && w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !w->isHidden() && !w->m_bX11ShouldntFocus)
|
||||
if (!w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !w->isHidden() && !w->m_bX11ShouldntFocus)
|
||||
return w.get();
|
||||
}
|
||||
}
|
||||
@@ -626,16 +632,16 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
|
||||
CWindow* CCompositor::windowFromCursor() {
|
||||
const auto PMONITOR = getMonitorFromCursor();
|
||||
|
||||
if (PMONITOR->specialWorkspaceOpen) {
|
||||
if (PMONITOR->specialWorkspaceID) {
|
||||
for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) {
|
||||
wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y};
|
||||
if ((*w)->m_bIsFloating && (*w)->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && (*w)->m_bIsMapped && wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && !(*w)->isHidden())
|
||||
if ((*w)->m_bIsFloating && (*w)->m_iWorkspaceID == PMONITOR->specialWorkspaceID && (*w)->m_bIsMapped && wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && !(*w)->isHidden())
|
||||
return (*w).get();
|
||||
}
|
||||
|
||||
for (auto& w : m_vWindows) {
|
||||
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
|
||||
if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped)
|
||||
if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped)
|
||||
return w.get();
|
||||
}
|
||||
}
|
||||
@@ -888,7 +894,11 @@ wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector<
|
||||
if ((*it)->fadingOut || !(*it)->layerSurface || ((*it)->layerSurface && !(*it)->layerSurface->mapped) || (*it)->alpha.fl() == 0.f)
|
||||
continue;
|
||||
|
||||
const auto SURFACEAT = wlr_layer_surface_v1_surface_at((*it)->layerSurface, pos.x - (*it)->geometry.x, pos.y - (*it)->geometry.y, &sCoords->x, &sCoords->y);
|
||||
auto SURFACEAT = wlr_layer_surface_v1_surface_at((*it)->layerSurface, pos.x - (*it)->geometry.x, pos.y - (*it)->geometry.y, &sCoords->x, &sCoords->y);
|
||||
|
||||
if (!SURFACEAT && VECINRECT(pos, (*it)->geometry.x, (*it)->geometry.y, (*it)->geometry.x + (*it)->geometry.width, (*it)->geometry.y + (*it)->geometry.height)) {
|
||||
SURFACEAT = (*it)->layerSurface->surface;
|
||||
}
|
||||
|
||||
if (SURFACEAT) {
|
||||
*ppLayerSurfaceFound = it->get();
|
||||
@@ -908,6 +918,16 @@ CWindow* CCompositor::getWindowFromSurface(wlr_surface* pSurface) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CWindow* CCompositor::getWindowFromHandle(uint32_t handle) {
|
||||
for (auto& w : m_vWindows) {
|
||||
if ((uint32_t)(((uint64_t)w.get()) & 0xFFFFFFFF) == handle) {
|
||||
return w.get();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CWindow* CCompositor::getFullscreenWindowOnWorkspace(const int& ID) {
|
||||
for (auto& w : m_vWindows) {
|
||||
if (w->m_iWorkspaceID == ID && w->m_bIsFullscreen)
|
||||
@@ -922,7 +942,7 @@ bool CCompositor::isWorkspaceVisible(const int& w) {
|
||||
if (m->activeWorkspace == w)
|
||||
return true;
|
||||
|
||||
if (m->specialWorkspaceOpen && w == SPECIAL_WORKSPACE_ID)
|
||||
if (m->specialWorkspaceID && isWorkspaceSpecial(w))
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -951,10 +971,8 @@ void CCompositor::sanityCheckWorkspaces() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((*it)->m_iID == SPECIAL_WORKSPACE_ID && WINDOWSONWORKSPACE == 0) {
|
||||
for (auto& m : m_vMonitors) {
|
||||
m->specialWorkspaceOpen = false;
|
||||
}
|
||||
if ((*it)->m_bIsSpecialWorkspace && WINDOWSONWORKSPACE == 0) {
|
||||
getMonitorFromID((*it)->m_iMonitorID)->specialWorkspaceID = 0;
|
||||
|
||||
it = m_vWorkspaces.erase(it);
|
||||
|
||||
@@ -1050,8 +1068,9 @@ void CCompositor::cleanupFadingOut(const int& monid) {
|
||||
|
||||
g_pHyprOpenGL->m_mWindowFramebuffers[w].release();
|
||||
g_pHyprOpenGL->m_mWindowFramebuffers.erase(w);
|
||||
w->m_bFadingOut = false;
|
||||
removeWindowFromVectorSafe(w);
|
||||
m_vWindowsFadingOut.erase(std::remove(m_vWindowsFadingOut.begin(), m_vWindowsFadingOut.end(), w));
|
||||
std::erase(m_vWindowsFadingOut, w);
|
||||
|
||||
Debug::log(LOG, "Cleanup: destroyed a window");
|
||||
|
||||
@@ -1150,6 +1169,10 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
|
||||
if (w.get() == pWindow || !w->m_bIsMapped || w->isHidden() || w->m_bIsFloating || !isWorkspaceVisible(w->m_iWorkspaceID))
|
||||
continue;
|
||||
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID);
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow && !w->m_bIsFullscreen && !w->m_bCreatedOverFullscreen)
|
||||
continue;
|
||||
|
||||
const auto BWINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved();
|
||||
|
||||
const auto POSB = Vector2D(BWINDOWIDEALBB.x, BWINDOWIDEALBB.y);
|
||||
@@ -1401,8 +1424,8 @@ void CCompositor::updateAllWindowsAnimatedDecorationValues() {
|
||||
|
||||
void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
|
||||
// optimization
|
||||
static int64_t* ACTIVECOL = &g_pConfigManager->getConfigValuePtr("general:col.active_border")->intValue;
|
||||
static int64_t* INACTIVECOL = &g_pConfigManager->getConfigValuePtr("general:col.inactive_border")->intValue;
|
||||
static auto *const ACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.active_border")->data.get();
|
||||
static auto *const INACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.inactive_border")->data.get();
|
||||
static auto *const PINACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:inactive_opacity")->floatValue;
|
||||
static auto *const PACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:active_opacity")->floatValue;
|
||||
static auto *const PFULLSCREENALPHA = &g_pConfigManager->getConfigValuePtr("decoration:fullscreen_opacity")->floatValue;
|
||||
@@ -1410,14 +1433,25 @@ void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
|
||||
static auto *const PSHADOWCOLINACTIVE = &g_pConfigManager->getConfigValuePtr("decoration:col.shadow_inactive")->intValue;
|
||||
static auto *const PDIMSTRENGTH = &g_pConfigManager->getConfigValuePtr("decoration:dim_strength")->floatValue;
|
||||
|
||||
auto setBorderColor = [&] (CGradientValueData grad) -> void {
|
||||
|
||||
if (grad == pWindow->m_cRealBorderColor)
|
||||
return;
|
||||
|
||||
pWindow->m_cRealBorderColorPrevious = pWindow->m_cRealBorderColor;
|
||||
pWindow->m_cRealBorderColor = grad;
|
||||
pWindow->m_fBorderAnimationProgress.setValueAndWarp(0.f);
|
||||
pWindow->m_fBorderAnimationProgress = 1.f;
|
||||
};
|
||||
|
||||
// border
|
||||
const auto RENDERDATA = g_pLayoutManager->getCurrentLayout()->requestRenderHints(pWindow);
|
||||
if (RENDERDATA.isBorderColor)
|
||||
pWindow->m_cRealBorderColor = RENDERDATA.borderColor;
|
||||
setBorderColor(RENDERDATA.borderColor * (1.f / 255.f));
|
||||
else
|
||||
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));
|
||||
setBorderColor(pWindow == m_pLastWindow ?
|
||||
(pWindow->m_sSpecialRenderData.activeBorderColor >= 0 ? CGradientValueData(CColor(pWindow->m_sSpecialRenderData.activeBorderColor) * (1.f / 255.f)) : *ACTIVECOL) :
|
||||
(pWindow->m_sSpecialRenderData.inactiveBorderColor >= 0 ? CGradientValueData(CColor(pWindow->m_sSpecialRenderData.inactiveBorderColor) * (1.f / 255.f)) : *INACTIVECOL));
|
||||
|
||||
|
||||
// opacity
|
||||
@@ -1697,7 +1731,7 @@ bool CCompositor::workspaceIDOutOfBounds(const int& id) {
|
||||
int highestID = -99999;
|
||||
|
||||
for (auto& w : m_vWorkspaces) {
|
||||
if (w->m_iID == SPECIAL_WORKSPACE_ID)
|
||||
if (w->m_bIsSpecialWorkspace)
|
||||
continue;
|
||||
|
||||
if (w->m_iID < lowestID)
|
||||
@@ -1797,6 +1831,9 @@ void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor) {
|
||||
if ((m_sWLRSession && !m_sWLRSession->active) || !m_bSessionActive)
|
||||
return;
|
||||
|
||||
if (!pMonitor->m_bEnabled)
|
||||
return;
|
||||
|
||||
wlr_output_schedule_frame(pMonitor->output);
|
||||
}
|
||||
|
||||
@@ -1869,7 +1906,7 @@ void CCompositor::warpCursorTo(const Vector2D& pos) {
|
||||
|
||||
const auto PMONITORNEW = getMonitorFromVector(pos);
|
||||
if (PMONITORNEW != m_pLastMonitor)
|
||||
m_pLastMonitor = PMONITORNEW;
|
||||
setActiveMonitor(PMONITORNEW);
|
||||
}
|
||||
|
||||
SLayerSurface* CCompositor::getLayerSurfaceFromWlr(wlr_layer_surface_v1* pLS) {
|
||||
@@ -1971,10 +2008,12 @@ CWorkspace* CCompositor::createNewWorkspace(const int& id, const int& monid, con
|
||||
monID = PMONITOR->ID;
|
||||
}
|
||||
|
||||
const auto PWORKSPACE = m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(monID, NAME, id == SPECIAL_WORKSPACE_ID)).get();
|
||||
const bool SPECIAL = id >= SPECIAL_WORKSPACE_START && id <= -2;
|
||||
|
||||
const auto PWORKSPACE = m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(monID, NAME, SPECIAL)).get();
|
||||
|
||||
// We are required to set the name here immediately
|
||||
if (id != SPECIAL_WORKSPACE_ID)
|
||||
if (!SPECIAL)
|
||||
wlr_ext_workspace_handle_v1_set_name(PWORKSPACE->m_pWlrHandle, NAME.c_str());
|
||||
|
||||
PWORKSPACE->m_iID = id;
|
||||
@@ -1982,3 +2021,33 @@ CWorkspace* CCompositor::createNewWorkspace(const int& id, const int& monid, con
|
||||
|
||||
return PWORKSPACE;
|
||||
}
|
||||
|
||||
void CCompositor::setActiveMonitor(CMonitor* pMonitor) {
|
||||
if (m_pLastMonitor == pMonitor)
|
||||
return;
|
||||
|
||||
if (!pMonitor) {
|
||||
m_pLastMonitor = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto PWORKSPACE = getWorkspaceByID(pMonitor->activeWorkspace);
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", pMonitor->szName + "," + PWORKSPACE->m_szName});
|
||||
m_pLastMonitor = pMonitor;
|
||||
}
|
||||
|
||||
bool CCompositor::isWorkspaceSpecial(const int& id) {
|
||||
return id >= SPECIAL_WORKSPACE_START && id <= -2;
|
||||
}
|
||||
|
||||
int CCompositor::getNewSpecialID() {
|
||||
int highest = -100;
|
||||
for (auto& ws : m_vWorkspaces) {
|
||||
if (ws->m_bIsSpecialWorkspace && ws->m_iID > highest) {
|
||||
highest = ws->m_iID;
|
||||
}
|
||||
}
|
||||
|
||||
return highest + 1;
|
||||
}
|
||||
|
@@ -15,6 +15,7 @@
|
||||
#include "managers/KeybindManager.hpp"
|
||||
#include "managers/AnimationManager.hpp"
|
||||
#include "managers/EventManager.hpp"
|
||||
#include "managers/ProtocolManager.hpp"
|
||||
#include "debug/HyprDebugOverlay.hpp"
|
||||
#include "helpers/Monitor.hpp"
|
||||
#include "helpers/Workspace.hpp"
|
||||
@@ -75,7 +76,7 @@ public:
|
||||
// ------------------------------------------------- //
|
||||
|
||||
|
||||
const char* m_szWLDisplaySocket;
|
||||
std::string m_szWLDisplaySocket = "";
|
||||
std::string m_szInstanceSignature = "";
|
||||
std::string m_szCurrentSplash = "error";
|
||||
|
||||
@@ -126,6 +127,7 @@ public:
|
||||
CMonitor* getMonitorFromOutput(wlr_output*);
|
||||
CWindow* getWindowForPopup(wlr_xdg_popup*);
|
||||
CWindow* getWindowFromSurface(wlr_surface*);
|
||||
CWindow* getWindowFromHandle(uint32_t);
|
||||
bool isWorkspaceVisible(const int&);
|
||||
CWorkspace* getWorkspaceByID(const int&);
|
||||
CWorkspace* getWorkspaceByName(const std::string&);
|
||||
@@ -169,6 +171,9 @@ public:
|
||||
void forceReportSizesToWindowsOnWorkspace(const int&);
|
||||
bool cursorOnReservedArea();
|
||||
CWorkspace* createNewWorkspace(const int&, const int&, const std::string& name = ""); // will be deleted next frame if left empty and unfocused!
|
||||
void setActiveMonitor(CMonitor*);
|
||||
bool isWorkspaceSpecial(const int&);
|
||||
int getNewSpecialID();
|
||||
|
||||
std::string explicitConfigPath;
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
CWindow::CWindow() {
|
||||
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_fBorderAnimationProgress.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("border"), (void*)this, AVARDAMAGE_BORDER);
|
||||
m_fAlpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||
m_fActiveInactiveAlpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||
m_cRealShadowColor.create(AVARTYPE_COLOR, g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), (void*)this, AVARDAMAGE_SHADOW);
|
||||
@@ -59,6 +59,13 @@ wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
|
||||
auto POS = m_vPosition;
|
||||
auto SIZE = m_vSize;
|
||||
|
||||
if (m_bIsFullscreen) {
|
||||
POS = PMONITOR->vecPosition;
|
||||
SIZE = PMONITOR->vecSize;
|
||||
|
||||
return wlr_box{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y};
|
||||
}
|
||||
|
||||
if (DELTALESSTHAN(POS.y - PMONITOR->vecPosition.y, PMONITOR->vecReservedTopLeft.y, 1)) {
|
||||
POS.y = PMONITOR->vecPosition.y;
|
||||
SIZE.y += PMONITOR->vecReservedTopLeft.y;
|
||||
@@ -255,7 +262,7 @@ void CWindow::onUnmap() {
|
||||
|
||||
m_vRealPosition.setCallbackOnEnd(unregisterVar);
|
||||
m_vRealSize.setCallbackOnEnd(unregisterVar);
|
||||
m_cRealBorderColor.setCallbackOnEnd(unregisterVar);
|
||||
m_fBorderAnimationProgress.setCallbackOnEnd(unregisterVar);
|
||||
m_fActiveInactiveAlpha.setCallbackOnEnd(unregisterVar);
|
||||
m_fAlpha.setCallbackOnEnd(unregisterVar);
|
||||
m_cRealShadowColor.setCallbackOnEnd(unregisterVar);
|
||||
@@ -265,9 +272,19 @@ void CWindow::onUnmap() {
|
||||
}
|
||||
|
||||
void CWindow::onMap() {
|
||||
|
||||
// JIC, reset the callbacks. If any are set, we'll make sure they are cleared so we don't accidentally unset them. (In case a window got remapped)
|
||||
m_vRealPosition.resetAllCallbacks();
|
||||
m_vRealSize.resetAllCallbacks();
|
||||
m_fBorderAnimationProgress.resetAllCallbacks();
|
||||
m_fActiveInactiveAlpha.resetAllCallbacks();
|
||||
m_fAlpha.resetAllCallbacks();
|
||||
m_cRealShadowColor.resetAllCallbacks();
|
||||
m_fDimPercent.resetAllCallbacks();
|
||||
|
||||
m_vRealPosition.registerVar();
|
||||
m_vRealSize.registerVar();
|
||||
m_cRealBorderColor.registerVar();
|
||||
m_fBorderAnimationProgress.registerVar();
|
||||
m_fActiveInactiveAlpha.registerVar();
|
||||
m_fAlpha.registerVar();
|
||||
m_cRealShadowColor.registerVar();
|
||||
@@ -301,7 +318,8 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
|
||||
} else if (r.szRule == "noshadow") {
|
||||
m_sAdditionalConfigData.forceNoShadow = true;
|
||||
} else if (r.szRule == "opaque") {
|
||||
m_sAdditionalConfigData.forceOpaque = true;
|
||||
if (!m_sAdditionalConfigData.forceOpaqueOverriden)
|
||||
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));
|
||||
@@ -352,7 +370,8 @@ void CWindow::updateDynamicRules() {
|
||||
m_sAdditionalConfigData.forceNoBlur = false;
|
||||
m_sAdditionalConfigData.forceNoBorder = false;
|
||||
m_sAdditionalConfigData.forceNoShadow = false;
|
||||
m_sAdditionalConfigData.forceOpaque = false;
|
||||
if (!m_sAdditionalConfigData.forceOpaqueOverriden)
|
||||
m_sAdditionalConfigData.forceOpaque = false;
|
||||
m_sAdditionalConfigData.forceNoAnims = false;
|
||||
m_sAdditionalConfigData.animationStyle = "";
|
||||
m_sAdditionalConfigData.rounding = -1;
|
||||
|
@@ -6,6 +6,7 @@
|
||||
#include "helpers/AnimatedVariable.hpp"
|
||||
#include "render/decorations/IHyprWindowDecoration.hpp"
|
||||
#include <deque>
|
||||
#include "config/ConfigDataValues.hpp"
|
||||
|
||||
enum eIdleInhibitMode {
|
||||
IDLEINHIBIT_NONE = 0,
|
||||
@@ -32,11 +33,13 @@ struct SWindowAdditionalConfigData {
|
||||
int rounding = -1; // -1 means no
|
||||
bool forceNoBlur = false;
|
||||
bool forceOpaque = false;
|
||||
bool forceOpaqueOverriden = false; // if true, a rule will not change the forceOpaque state. This is for the force opaque dispatcher.
|
||||
bool forceAllowsInput = false;
|
||||
bool forceNoAnims = false;
|
||||
bool forceNoBorder = false;
|
||||
bool forceNoShadow = false;
|
||||
bool windowDanceCompat = false;
|
||||
bool noMaxSize = false;
|
||||
};
|
||||
|
||||
struct SWindowRule {
|
||||
@@ -129,13 +132,16 @@ public:
|
||||
bool m_bNoFocus = false;
|
||||
bool m_bNoInitialFocus = false;
|
||||
|
||||
// initial fullscreen
|
||||
// initial fullscreen and fullscreen disabled
|
||||
bool m_bWantsInitialFullscreen = false;
|
||||
bool m_bNoFullscreenRequest = false;
|
||||
|
||||
SSurfaceTreeNode* m_pSurfaceTree = nullptr;
|
||||
|
||||
// Animated border
|
||||
CAnimatedVariable m_cRealBorderColor;
|
||||
CGradientValueData m_cRealBorderColor = {0};
|
||||
CGradientValueData m_cRealBorderColorPrevious = {0};
|
||||
CAnimatedVariable m_fBorderAnimationProgress;
|
||||
|
||||
// Fade in-out
|
||||
CAnimatedVariable m_fAlpha;
|
||||
|
48
src/config/ConfigDataValues.hpp
Normal file
48
src/config/ConfigDataValues.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
#include "../defines.hpp"
|
||||
|
||||
enum eConfigValueDataTypes {
|
||||
CVD_TYPE_INVALID = -1,
|
||||
CVD_TYPE_GRADIENT = 0
|
||||
};
|
||||
|
||||
interface ICustomConfigValueData {
|
||||
public:
|
||||
virtual ~ICustomConfigValueData() = 0;
|
||||
|
||||
virtual eConfigValueDataTypes getDataType() = 0;
|
||||
};
|
||||
|
||||
class CGradientValueData : public ICustomConfigValueData {
|
||||
public:
|
||||
CGradientValueData(CColor col) {
|
||||
m_vColors.push_back(col);
|
||||
};
|
||||
virtual ~CGradientValueData() { };
|
||||
|
||||
virtual eConfigValueDataTypes getDataType() {
|
||||
return CVD_TYPE_GRADIENT;
|
||||
}
|
||||
|
||||
void reset(CColor col) {
|
||||
m_vColors.clear();
|
||||
m_vColors.emplace_back(col);
|
||||
m_fAngle = 0;
|
||||
}
|
||||
|
||||
/* Vector containing the colors */
|
||||
std::vector<CColor> m_vColors;
|
||||
|
||||
/* Float corresponding to the angle (rad) */
|
||||
float m_fAngle = 0;
|
||||
|
||||
bool operator==(const CGradientValueData& other) {
|
||||
if (other.m_vColors.size() != m_vColors.size() || m_fAngle != other.m_fAngle)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < m_vColors.size(); ++i)
|
||||
if (m_vColors[i] != other.m_vColors[i]) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
@@ -11,6 +11,9 @@
|
||||
#include <iostream>
|
||||
|
||||
CConfigManager::CConfigManager() {
|
||||
configValues["general:col.active_border"].data = std::make_shared<CGradientValueData>(0xffffffff);
|
||||
configValues["general:col.inactive_border"].data = std::make_shared<CGradientValueData>(0xff444444);
|
||||
|
||||
setDefaultVars();
|
||||
setDefaultAnimationVars();
|
||||
|
||||
@@ -39,8 +42,8 @@ void CConfigManager::setDefaultVars() {
|
||||
configValues["general:no_border_on_floating"].intValue = 0;
|
||||
configValues["general:gaps_in"].intValue = 5;
|
||||
configValues["general:gaps_out"].intValue = 20;
|
||||
configValues["general:col.active_border"].intValue = 0xffffffff;
|
||||
configValues["general:col.inactive_border"].intValue = 0xff444444;
|
||||
((CGradientValueData*)configValues["general:col.active_border"].data.get())->reset(0xffffffff);
|
||||
((CGradientValueData*)configValues["general:col.inactive_border"].data.get())->reset(0xff444444);
|
||||
configValues["general:cursor_inactive_timeout"].intValue = 0;
|
||||
configValues["general:no_cursor_warps"].intValue = 0;
|
||||
|
||||
@@ -73,7 +76,8 @@ void CConfigManager::setDefaultVars() {
|
||||
configValues["decoration:blur_size"].intValue = 8;
|
||||
configValues["decoration:blur_passes"].intValue = 1;
|
||||
configValues["decoration:blur_ignore_opacity"].intValue = 0;
|
||||
configValues["decoration:blur_new_optimizations"].intValue = 0;
|
||||
configValues["decoration:blur_new_optimizations"].intValue = 1;
|
||||
configValues["decoration:blur_xray"].intValue = 0;
|
||||
configValues["decoration:active_opacity"].floatValue = 1;
|
||||
configValues["decoration:inactive_opacity"].floatValue = 1;
|
||||
configValues["decoration:fullscreen_opacity"].floatValue = 1;
|
||||
@@ -89,6 +93,7 @@ void CConfigManager::setDefaultVars() {
|
||||
configValues["decoration:col.shadow_inactive"].intValue = INT_MAX;
|
||||
configValues["decoration:dim_inactive"].intValue = 0;
|
||||
configValues["decoration:dim_strength"].floatValue = 0.5f;
|
||||
configValues["decoration:screen_shader"].strValue = STRVAL_EMPTY;
|
||||
|
||||
configValues["dwindle:pseudotile"].intValue = 0;
|
||||
configValues["dwindle:col.group_border"].intValue = 0x66777700;
|
||||
@@ -106,7 +111,6 @@ 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;
|
||||
@@ -142,6 +146,7 @@ void CConfigManager::setDefaultVars() {
|
||||
configValues["input:float_switch_override_focus"].intValue = 1;
|
||||
configValues["input:left_handed"].intValue = 0;
|
||||
configValues["input:scroll_method"].strValue = STRVAL_EMPTY;
|
||||
configValues["input:scroll_button"].intValue = 0;
|
||||
configValues["input:touchpad:natural_scroll"].intValue = 0;
|
||||
configValues["input:touchpad:disable_while_typing"].intValue = 1;
|
||||
configValues["input:touchpad:clickfinger_behavior"].intValue = 0;
|
||||
@@ -193,6 +198,7 @@ void CConfigManager::setDeviceDefaultVars(const std::string& dev) {
|
||||
cfgValues["drag_lock"].intValue = 0;
|
||||
cfgValues["left_handed"].intValue = 0;
|
||||
cfgValues["scroll_method"].strValue = STRVAL_EMPTY;
|
||||
cfgValues["scroll_button"].intValue = 0;
|
||||
cfgValues["touch_transform"].intValue = 0;
|
||||
cfgValues["touch_output"].strValue = STRVAL_EMPTY;
|
||||
cfgValues["enabled"].intValue = 1; // only for mice / touchpads
|
||||
@@ -348,6 +354,71 @@ void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::s
|
||||
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
|
||||
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
|
||||
}
|
||||
} else if (CONFIGENTRY->data.get() != nullptr) {
|
||||
|
||||
switch (CONFIGENTRY->data->getDataType()) {
|
||||
case CVD_TYPE_GRADIENT: {
|
||||
|
||||
CVarList varlist(VALUE, 0, ' ');
|
||||
|
||||
CGradientValueData* data = (CGradientValueData*)CONFIGENTRY->data.get();
|
||||
data->m_vColors.clear();
|
||||
|
||||
for (auto& var : varlist) {
|
||||
if (var.find("deg") != std::string::npos) {
|
||||
// last arg
|
||||
try {
|
||||
data->m_fAngle = std::stoi(var.substr(0, var.find("deg"))) * (PI / 180.0); // radians
|
||||
} catch (...) {
|
||||
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
|
||||
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (data->m_vColors.size() >= 10) {
|
||||
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
|
||||
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">. Max colors in a gradient is 10.";
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
data->m_vColors.push_back(CColor(configStringToInt(var)) * (1.f / 255.f));
|
||||
} catch (std::exception& e) {
|
||||
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
|
||||
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">. " + e.what();
|
||||
}
|
||||
}
|
||||
|
||||
if (data->m_vColors.size() == 0) {
|
||||
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
|
||||
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">. No colors provided.";
|
||||
|
||||
data->m_vColors.push_back(0); // transparent
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (COMMAND == "decoration:screen_shader") {
|
||||
const auto PATH = absolutePath(VALUE, configCurrentPath);
|
||||
|
||||
configPaths.push_back(PATH);
|
||||
|
||||
struct stat fileStat;
|
||||
int err = stat(PATH.c_str(), &fileStat);
|
||||
if (err != 0) {
|
||||
Debug::log(WARN, "Error at ticking config at %s, error %i: %s", PATH.c_str(), err, strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
configModifyTimes[PATH] = fileStat.st_mtime;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -677,6 +748,8 @@ bool windowRuleValid(const std::string& RULE) {
|
||||
&& RULE != "opaque"
|
||||
&& RULE != "forceinput"
|
||||
&& RULE != "fullscreen"
|
||||
&& RULE != "nofullscreenrequest"
|
||||
&& RULE != "nomaxsize"
|
||||
&& RULE != "pin"
|
||||
&& RULE != "noanim"
|
||||
&& RULE != "windowdance"
|
||||
@@ -830,7 +903,7 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
||||
void CConfigManager::handleBlurLS(const std::string& command, const std::string& value) {
|
||||
if (value.find("remove,") == 0) {
|
||||
const auto TOREMOVE = removeBeginEndSpacesTabs(value.substr(7));
|
||||
m_dBlurLSNamespaces.erase(std::remove(m_dBlurLSNamespaces.begin(), m_dBlurLSNamespaces.end(), TOREMOVE));
|
||||
std::erase_if(m_dBlurLSNamespaces, [&] (const auto& other) { return other == TOREMOVE; });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -928,6 +1001,8 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
|
||||
currentCategory = "";
|
||||
}
|
||||
|
||||
int needsLayoutRecalc = COMMAND == "monitor"; // 0 - no, 1 - yes, 2 - maybe
|
||||
|
||||
if (COMMAND == "exec") {
|
||||
if (isFirstLaunch) {
|
||||
firstExecRequests.push_back(VALUE);
|
||||
@@ -951,16 +1026,22 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
|
||||
else if (COMMAND == "submap") handleSubmap(COMMAND, VALUE);
|
||||
else if (COMMAND == "blurls") handleBlurLS(COMMAND, VALUE);
|
||||
else if (COMMAND == "wsbind") handleBindWS(COMMAND, VALUE);
|
||||
else
|
||||
else {
|
||||
configSetValueSafe(currentCategory + (currentCategory == "" ? "" : ":") + COMMAND, VALUE);
|
||||
needsLayoutRecalc = 2;
|
||||
}
|
||||
|
||||
if (dynamic) {
|
||||
std::string retval = parseError;
|
||||
parseError = "";
|
||||
|
||||
// invalidate layouts jic
|
||||
for (auto& m : g_pCompositor->m_vMonitors)
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
|
||||
// invalidate layouts if they changed
|
||||
if (needsLayoutRecalc) {
|
||||
if (needsLayoutRecalc == 1 || COMMAND.contains("gaps_") || COMMAND.find("dwindle:") == 0 || COMMAND.find("master:") == 0) {
|
||||
for (auto& m : g_pCompositor->m_vMonitors)
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
|
||||
}
|
||||
}
|
||||
|
||||
// Update window border colors
|
||||
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
|
||||
@@ -1167,6 +1248,9 @@ void CConfigManager::loadConfigLoadVars() {
|
||||
// Calculate the internal vars
|
||||
configValues["general:main_mod_internal"].intValue = g_pKeybindManager->stringToModMask(configValues["general:main_mod"].strValue);
|
||||
|
||||
if (!isFirstLaunch)
|
||||
g_pHyprOpenGL->m_bReloadScreenShader = true;
|
||||
|
||||
// parseError will be displayed next frame
|
||||
if (parseError != "")
|
||||
g_pHyprError->queueCreate(parseError + "\nHyprland may not work correctly.", CColor(255, 50, 50, 255));
|
||||
@@ -1180,9 +1264,8 @@ void CConfigManager::loadConfigLoadVars() {
|
||||
// and they'll be taken care of in the newMonitor event
|
||||
// ignore if nomonitorreload is set
|
||||
if (!isFirstLaunch && !m_bNoMonitorReload) {
|
||||
m_bWantsMonitorReload = true;
|
||||
|
||||
// check
|
||||
performMonitorReload();
|
||||
ensureDPMS();
|
||||
ensureVRR();
|
||||
}
|
||||
@@ -1251,13 +1334,10 @@ SConfigValue CConfigManager::getConfigValueSafe(const std::string& val) {
|
||||
SConfigValue CConfigManager::getConfigValueSafeDevice(const std::string& dev, const std::string& val) {
|
||||
std::lock_guard<std::mutex> lg(configmtx);
|
||||
|
||||
auto devcopy = dev;
|
||||
std::replace(devcopy.begin(), devcopy.end(), ' ', '-');
|
||||
|
||||
const auto it = deviceConfigs.find(devcopy);
|
||||
const auto it = deviceConfigs.find(dev);
|
||||
|
||||
if (it == deviceConfigs.end()) {
|
||||
Debug::log(ERR, "getConfigValueSafeDevice: No device config for %s found???", devcopy.c_str());
|
||||
Debug::log(ERR, "getConfigValueSafeDevice: No device config for %s found???", dev.c_str());
|
||||
return SConfigValue();
|
||||
}
|
||||
|
||||
@@ -1479,20 +1559,23 @@ void CConfigManager::performMonitorReload() {
|
||||
for (auto& m : g_pCompositor->m_vRealMonitors) {
|
||||
auto rule = getMonitorRuleFor(m->szName, m->output->description ? m->output->description : "");
|
||||
|
||||
// ensure mirror
|
||||
m->setMirror(rule.mirrorOf);
|
||||
|
||||
if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule)) {
|
||||
overAgain = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// ensure mirror
|
||||
m->setMirror(rule.mirrorOf);
|
||||
|
||||
g_pHyprRenderer->arrangeLayersForMonitor(m->ID);
|
||||
}
|
||||
|
||||
if (overAgain)
|
||||
performMonitorReload();
|
||||
|
||||
if (!g_pCompositor->m_vMonitors.empty()) // reset unsafe state if we have monitors
|
||||
g_pCompositor->m_bUnsafeState = false;
|
||||
|
||||
m_bWantsMonitorReload = false;
|
||||
}
|
||||
|
||||
@@ -1589,6 +1672,8 @@ SAnimationPropertyConfig* CConfigManager::getAnimationPropertyConfig(const std::
|
||||
void CConfigManager::addParseError(const std::string& err) {
|
||||
if (parseError == "")
|
||||
parseError = err;
|
||||
|
||||
g_pHyprError->queueCreate(parseError + "\nHyprland may not work correctly.", CColor(255, 50, 50, 255));
|
||||
}
|
||||
|
||||
CMonitor* CConfigManager::getBoundMonitorForWS(std::string wsname) {
|
||||
@@ -1606,3 +1691,7 @@ CMonitor* CConfigManager::getBoundMonitorForWS(std::string wsname) {
|
||||
void CConfigManager::addExecRule(SExecRequestedRule rule) {
|
||||
execRequestedRules.push_back(rule);
|
||||
}
|
||||
|
||||
ICustomConfigValueData::~ICustomConfigValueData() {
|
||||
; // empty
|
||||
}
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include "../Window.hpp"
|
||||
|
||||
#include "defaultConfig.hpp"
|
||||
#include "ConfigDataValues.hpp"
|
||||
|
||||
#define STRVAL_EMPTY "[[EMPTY]]"
|
||||
|
||||
@@ -24,6 +25,7 @@ struct SConfigValue {
|
||||
float floatValue = -__FLT_MAX__;
|
||||
std::string strValue = "";
|
||||
Vector2D vecValue = Vector2D(-__FLT_MAX__, -__FLT_MAX__);
|
||||
std::shared_ptr<ICustomConfigValueData> data;
|
||||
|
||||
bool set = false; // used for device configs
|
||||
};
|
||||
|
@@ -51,7 +51,7 @@ general {
|
||||
gaps_in = 5
|
||||
gaps_out = 20
|
||||
border_size = 2
|
||||
col.active_border = rgba(1affffee)
|
||||
col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg
|
||||
col.inactive_border = rgba(595959aa)
|
||||
|
||||
layout = dwindle
|
||||
|
@@ -68,6 +68,34 @@ R"#({
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string getGroupedData(CWindow* w, HyprCtl::eHyprCtlOutputFormat format) {
|
||||
const bool isJson = format == HyprCtl::FORMAT_JSON;
|
||||
if (g_pLayoutManager->getCurrentLayout()->getLayoutName() != "dwindle")
|
||||
return isJson ? "" : "0";
|
||||
|
||||
SLayoutMessageHeader header;
|
||||
header.pWindow = w;
|
||||
const auto groupMembers = std::any_cast<std::deque<CWindow*>>(g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "groupinfo"));
|
||||
if (groupMembers.empty())
|
||||
return isJson ? "" : "0";
|
||||
|
||||
const auto comma = isJson ? ", " : ",";
|
||||
const auto fmt = isJson ? "\"0x%x\"" : "%x";
|
||||
std::ostringstream result;
|
||||
|
||||
bool first = true;
|
||||
for (auto& gw : groupMembers) {
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
result << comma;
|
||||
|
||||
result << getFormat(fmt, gw);
|
||||
}
|
||||
|
||||
return result.str();
|
||||
}
|
||||
|
||||
static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat format) {
|
||||
if (format == HyprCtl::FORMAT_JSON) {
|
||||
return getFormat(
|
||||
@@ -87,7 +115,9 @@ R"#({
|
||||
"xwayland": %s,
|
||||
"pinned": %s,
|
||||
"fullscreen": %s,
|
||||
"fullscreenMode": %i
|
||||
"fullscreenMode": %i,
|
||||
"grouped": [%s],
|
||||
"swallowing": %s
|
||||
},)#",
|
||||
w,
|
||||
(int)w->m_vRealPosition.goalv().x, (int)w->m_vRealPosition.goalv().y,
|
||||
@@ -101,11 +131,13 @@ R"#({
|
||||
((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)
|
||||
(w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0),
|
||||
getGroupedData(w, format).c_str(),
|
||||
(w->m_pSwallowed ? getFormat("\"0x%x\"", w->m_pSwallowed).c_str() : "null")
|
||||
);
|
||||
} 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));
|
||||
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\tgrouped: %s\n\tswallowing: %x\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), getGroupedData(w, format).c_str(), w->m_pSwallowed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,7 +321,7 @@ R"#( {
|
||||
"defaultSpeed": %f
|
||||
},)#",
|
||||
&m,
|
||||
escapeJSONStrings(m.mouse->name).c_str(),
|
||||
escapeJSONStrings(m.name).c_str(),
|
||||
wlr_input_device_is_libinput(m.mouse) ? libinput_device_config_accel_get_default_speed((libinput_device*)wlr_libinput_get_device_handle(m.mouse)) : 0.f
|
||||
);
|
||||
}
|
||||
@@ -314,7 +346,7 @@ R"#( {
|
||||
"main": %s
|
||||
},)#",
|
||||
&k,
|
||||
escapeJSONStrings(k.keyboard->name).c_str(),
|
||||
escapeJSONStrings(k.name).c_str(),
|
||||
escapeJSONStrings(k.currentRules.rules).c_str(),
|
||||
escapeJSONStrings(k.currentRules.model).c_str(),
|
||||
escapeJSONStrings(k.currentRules.layout).c_str(),
|
||||
@@ -343,7 +375,7 @@ R"#( {
|
||||
},)#",
|
||||
&d,
|
||||
d.pTabletParent,
|
||||
escapeJSONStrings(d.pTabletParent ? d.pTabletParent->wlrDevice ? d.pTabletParent->wlrDevice->name : "" : "").c_str()
|
||||
escapeJSONStrings(d.pTabletParent ? d.pTabletParent->name : "").c_str()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -354,7 +386,7 @@ R"#( {
|
||||
"name": "%s"
|
||||
},)#",
|
||||
&d,
|
||||
escapeJSONStrings(d.wlrDevice ? d.wlrDevice->name : "").c_str()
|
||||
escapeJSONStrings(d.name).c_str()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -383,7 +415,7 @@ R"#( {
|
||||
"name": "%s"
|
||||
},)#",
|
||||
&d,
|
||||
d.pWlrDevice ? d.pWlrDevice->name : ""
|
||||
d.name.c_str()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -416,24 +448,24 @@ R"#( {
|
||||
result += "mice:\n";
|
||||
|
||||
for (auto& m : g_pInputManager->m_lMice) {
|
||||
result += getFormat("\tMouse at %x:\n\t\t%s\n\t\t\tdefault speed: %f\n", &m, m.mouse->name, (wlr_input_device_is_libinput(m.mouse) ? libinput_device_config_accel_get_default_speed((libinput_device*)wlr_libinput_get_device_handle(m.mouse)) : 0.f));
|
||||
result += getFormat("\tMouse at %x:\n\t\t%s\n\t\t\tdefault speed: %f\n", &m, m.name.c_str(), (wlr_input_device_is_libinput(m.mouse) ? libinput_device_config_accel_get_default_speed((libinput_device*)wlr_libinput_get_device_handle(m.mouse)) : 0.f));
|
||||
}
|
||||
|
||||
result += "\n\nKeyboards:\n";
|
||||
|
||||
for (auto& k : g_pInputManager->m_lKeyboards) {
|
||||
const auto KM = g_pInputManager->getActiveLayoutForKeyboard(&k);
|
||||
result += getFormat("\tKeyboard at %x:\n\t\t%s\n\t\t\trules: r \"%s\", m \"%s\", l \"%s\", v \"%s\", o \"%s\"\n\t\t\tactive keymap: %s\n\t\t\tmain: %s\n", &k, k.keyboard->name, k.currentRules.rules.c_str(), k.currentRules.model.c_str(), k.currentRules.layout.c_str(), k.currentRules.variant.c_str(), k.currentRules.options.c_str(), KM.c_str(), (k.active ? "yes" : "no"));
|
||||
result += getFormat("\tKeyboard at %x:\n\t\t%s\n\t\t\trules: r \"%s\", m \"%s\", l \"%s\", v \"%s\", o \"%s\"\n\t\t\tactive keymap: %s\n\t\t\tmain: %s\n", &k, k.name.c_str(), k.currentRules.rules.c_str(), k.currentRules.model.c_str(), k.currentRules.layout.c_str(), k.currentRules.variant.c_str(), k.currentRules.options.c_str(), KM.c_str(), (k.active ? "yes" : "no"));
|
||||
}
|
||||
|
||||
result += "\n\nTablets:\n";
|
||||
|
||||
for (auto& d : g_pInputManager->m_lTabletPads) {
|
||||
result += getFormat("\tTablet Pad at %x (belongs to %x -> %s)\n", &d, d.pTabletParent, d.pTabletParent ? d.pTabletParent->wlrDevice ? d.pTabletParent->wlrDevice->name : "" : "");
|
||||
result += getFormat("\tTablet Pad at %x (belongs to %x -> %s)\n", &d, d.pTabletParent, d.pTabletParent ? d.pTabletParent->name.c_str() : "");
|
||||
}
|
||||
|
||||
for (auto& d : g_pInputManager->m_lTablets) {
|
||||
result += getFormat("\tTablet at %x:\n\t\t%s\n", &d, d.wlrDevice ? d.wlrDevice->name : "");
|
||||
result += getFormat("\tTablet at %x:\n\t\t%s\n", &d, d.name.c_str());
|
||||
}
|
||||
|
||||
for (auto& d : g_pInputManager->m_lTabletTools) {
|
||||
@@ -443,7 +475,7 @@ R"#( {
|
||||
result += "\n\nTouch:\n";
|
||||
|
||||
for (auto& d : g_pInputManager->m_lTouchDevices) {
|
||||
result += getFormat("\tTouch Device at %x:\n\t\t%s\n", &d, d.pWlrDevice ? d.pWlrDevice->name : "");
|
||||
result += getFormat("\tTouch Device at %x:\n\t\t%s\n", &d, d.name.c_str());
|
||||
}
|
||||
|
||||
result += "\n\nSwitches:\n";
|
||||
@@ -548,6 +580,9 @@ std::string dispatchKeyword(std::string in) {
|
||||
|
||||
if (COMMAND.contains("general:layout"))
|
||||
g_pLayoutManager->switchToLayout(g_pConfigManager->getString("general:layout")); // update layout
|
||||
|
||||
if (COMMAND.contains("decoration:screen_shader"))
|
||||
g_pHyprOpenGL->m_bReloadScreenShader = true;
|
||||
|
||||
Debug::log(LOG, "Hyprctl: keyword %s : %s", COMMAND.c_str(), VALUE.c_str());
|
||||
|
||||
@@ -683,6 +718,51 @@ std::string dispatchSetCursor(std::string request) {
|
||||
return "ok";
|
||||
}
|
||||
|
||||
std::string switchXKBLayoutRequest(std::string request) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
|
||||
const auto KB = vars[1];
|
||||
const auto CMD = vars[2];
|
||||
|
||||
// get kb
|
||||
const auto PKEYBOARD = std::find_if(g_pInputManager->m_lKeyboards.begin(), g_pInputManager->m_lKeyboards.end(), [&] (const SKeyboard& other) { return other.name == g_pInputManager->deviceNameToInternalString(KB); });
|
||||
|
||||
if (PKEYBOARD == g_pInputManager->m_lKeyboards.end())
|
||||
return "device not found";
|
||||
|
||||
const auto PWLRKEYBOARD = wlr_keyboard_from_input_device(PKEYBOARD->keyboard);
|
||||
const auto LAYOUTS = xkb_keymap_num_layouts(PWLRKEYBOARD->keymap);
|
||||
xkb_layout_index_t activeLayout = 0;
|
||||
while (activeLayout < LAYOUTS) {
|
||||
if (xkb_state_layout_index_is_active(PWLRKEYBOARD->xkb_state, activeLayout, XKB_STATE_LAYOUT_EFFECTIVE))
|
||||
break;
|
||||
|
||||
activeLayout++;
|
||||
}
|
||||
|
||||
if (CMD == "next") {
|
||||
wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked, activeLayout > LAYOUTS ? 0 : activeLayout + 1);
|
||||
} else if (CMD == "prev") {
|
||||
wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked, activeLayout == 0 ? LAYOUTS - 1 : activeLayout - 1);
|
||||
} else {
|
||||
|
||||
int requestedLayout = 0;
|
||||
try {
|
||||
requestedLayout = std::stoi(CMD);
|
||||
} catch (std::exception& e) {
|
||||
return "invalid arg 2";
|
||||
}
|
||||
|
||||
if (requestedLayout < 0 || (uint64_t)requestedLayout > LAYOUTS - 1) {
|
||||
return "layout idx out of range of " + std::to_string(LAYOUTS);
|
||||
}
|
||||
|
||||
wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked, requestedLayout);
|
||||
}
|
||||
|
||||
return "ok";
|
||||
}
|
||||
|
||||
std::string dispatchGetOption(std::string request, HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string curitem = "";
|
||||
|
||||
@@ -709,7 +789,7 @@ std::string dispatchGetOption(std::string request, HyprCtl::eHyprCtlOutputFormat
|
||||
return "no such option";
|
||||
|
||||
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL)
|
||||
return getFormat("option %s\n\tint: %lld\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\"\n\tdata: %x", curitem.c_str(), PCFGOPT->intValue, PCFGOPT->floatValue, PCFGOPT->strValue.c_str(), PCFGOPT->data.get());
|
||||
else {
|
||||
return getFormat(
|
||||
R"#(
|
||||
@@ -717,9 +797,10 @@ R"#(
|
||||
"option": "%s",
|
||||
"int": %lld,
|
||||
"float": %f,
|
||||
"str": "%s"
|
||||
"str": "%s",
|
||||
"data": "0x%x"
|
||||
}
|
||||
)#", curitem.c_str(), PCFGOPT->intValue, PCFGOPT->floatValue, PCFGOPT->strValue.c_str()
|
||||
)#", curitem.c_str(), PCFGOPT->intValue, PCFGOPT->floatValue, PCFGOPT->strValue.c_str(), PCFGOPT->data.get()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -847,6 +928,8 @@ std::string getReply(std::string request) {
|
||||
return splashRequest();
|
||||
else if (request == "cursorpos")
|
||||
return cursorPosRequest(format);
|
||||
else if (request.find("switchxkblayout") == 0)
|
||||
return switchXKBLayoutRequest(request);
|
||||
else if (request.find("output") == 0)
|
||||
return dispatchOutput(request);
|
||||
else if (request.find("dispatch") == 0)
|
||||
|
@@ -18,10 +18,10 @@
|
||||
#define ISDEBUG false
|
||||
#endif
|
||||
|
||||
#define LISTENER(name) void listener_##name(wl_listener*, void*); inline wl_listener listen_##name = { .notify = listener_##name };
|
||||
#define DYNLISTENFUNC(name) void listener_##name(void*, void*);
|
||||
#define DYNLISTENER(name) CHyprWLListener hyprListener_##name;
|
||||
#define DYNMULTILISTENER(name) wl_listener listen_##name;
|
||||
#define LISTENER(name) void listener_##name(wl_listener*, void*); inline wl_listener listen_##name = { .notify = listener_##name }
|
||||
#define DYNLISTENFUNC(name) void listener_##name(void*, void*)
|
||||
#define DYNLISTENER(name) CHyprWLListener hyprListener_##name
|
||||
#define DYNMULTILISTENER(name) wl_listener listen_##name
|
||||
|
||||
#define VECINRECT(vec, x1, y1, x2, y2) (vec.x >= (x1) && vec.x <= (x2) && vec.y >= (y1) && vec.y <= (y2))
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
const auto RECTSARR = pixman_region32_rectangles(region, &rectsNum); \
|
||||
for (int i = 0; i < rectsNum; ++i)
|
||||
|
||||
#define PIXMAN_REGION_FOREACH(region) PIXMAN_DAMAGE_FOREACH(region)
|
||||
|
||||
|
||||
#define interface class
|
||||
|
||||
@@ -76,4 +78,6 @@
|
||||
#define GIT_DIRTY "?"
|
||||
#endif
|
||||
|
||||
#define SPECIAL_WORKSPACE_ID -99
|
||||
#define SPECIAL_WORKSPACE_START -99
|
||||
|
||||
#define PI 3.14159265358979
|
||||
|
@@ -91,7 +91,7 @@ void Events::listener_newInput(wl_listener* listener, void* data) {
|
||||
break;
|
||||
}
|
||||
|
||||
g_pInputManager->updateCapabilities(DEVICE);
|
||||
g_pInputManager->updateCapabilities();
|
||||
}
|
||||
|
||||
void Events::listener_newConstraint(wl_listener* listener, void* data) {
|
||||
|
@@ -96,6 +96,7 @@ namespace Events {
|
||||
// Monitor part 2 the sequel
|
||||
DYNLISTENFUNC(monitorFrame);
|
||||
DYNLISTENFUNC(monitorDestroy);
|
||||
DYNLISTENFUNC(monitorStateRequest);
|
||||
|
||||
// XWayland
|
||||
LISTENER(readyXWayland);
|
||||
|
@@ -126,6 +126,8 @@ void Events::listener_startDrag(wl_listener* listener, void* data) {
|
||||
void Events::listener_destroyDrag(void* owner, void* data) {
|
||||
Debug::log(LOG, "Drag destroyed.");
|
||||
|
||||
static auto *const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
|
||||
|
||||
if (g_pInputManager->m_sDrag.drag && g_pInputManager->m_sDrag.dragIcon && g_pInputManager->m_sDrag.dragIcon->surface)
|
||||
g_pHyprRenderer->damageBox(g_pInputManager->m_sDrag.pos.x - 2, g_pInputManager->m_sDrag.pos.y - 2, g_pInputManager->m_sDrag.dragIcon->surface->current.width + 4, g_pInputManager->m_sDrag.dragIcon->surface->current.height + 4);
|
||||
|
||||
@@ -135,7 +137,7 @@ void Events::listener_destroyDrag(void* owner, void* data) {
|
||||
|
||||
g_pInputManager->refocus();
|
||||
|
||||
if (g_pInputManager->m_pFollowOnDnDBegin)
|
||||
if (g_pInputManager->m_pFollowOnDnDBegin && *PFOLLOWMOUSE != 1)
|
||||
g_pCompositor->focusWindow(g_pInputManager->m_pFollowOnDnDBegin);
|
||||
|
||||
g_pInputManager->m_pFollowOnDnDBegin = nullptr;
|
||||
@@ -189,6 +191,12 @@ void Events::listener_sessionActive(wl_listener* listener, void* data) {
|
||||
Debug::log(LOG, "Session got activated!");
|
||||
|
||||
g_pCompositor->m_bSessionActive = true;
|
||||
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
g_pCompositor->scheduleFrameForMonitor(m.get());
|
||||
}
|
||||
|
||||
g_pConfigManager->m_bWantsMonitorReload = true;
|
||||
}
|
||||
|
||||
void Events::listener_powerMgrSetMode(wl_listener* listener, void* data) {
|
||||
|
@@ -88,6 +88,9 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
|
||||
g_pCompositor->m_bReadyToProcess = true;
|
||||
g_pCompositor->m_bUnsafeState = false;
|
||||
}
|
||||
|
||||
g_pConfigManager->m_bWantsMonitorReload = true;
|
||||
g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR);
|
||||
}
|
||||
|
||||
void Events::listener_monitorFrame(void* owner, void* data) {
|
||||
@@ -263,15 +266,16 @@ void Events::listener_monitorFrame(void* owner, void* data) {
|
||||
damageBlinkCleanup = 0;
|
||||
}
|
||||
|
||||
wlr_renderer_begin(g_pCompositor->m_sWLRRenderer, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
|
||||
|
||||
wlr_output_render_software_cursors(PMONITOR->output, NULL);
|
||||
|
||||
wlr_renderer_end(g_pCompositor->m_sWLRRenderer);
|
||||
if (wlr_renderer_begin(g_pCompositor->m_sWLRRenderer, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y)) {
|
||||
wlr_output_render_software_cursors(PMONITOR->output, NULL);
|
||||
wlr_renderer_end(g_pCompositor->m_sWLRRenderer);
|
||||
}
|
||||
}
|
||||
|
||||
g_pHyprOpenGL->end();
|
||||
|
||||
g_pProtocolManager->m_pToplevelExportProtocolManager->onMonitorRender(PMONITOR); // dispatch any toplevel sharing
|
||||
|
||||
// calc frame damage
|
||||
pixman_region32_t frameDamage;
|
||||
pixman_region32_init(&frameDamage);
|
||||
@@ -316,8 +320,8 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
|
||||
|
||||
CMonitor* pMonitor = nullptr;
|
||||
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
if (m->szName == OUTPUT->name) {
|
||||
for (auto& m : g_pCompositor->m_vRealMonitors) {
|
||||
if (m->output == OUTPUT) {
|
||||
pMonitor = m.get();
|
||||
break;
|
||||
}
|
||||
@@ -326,11 +330,14 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
|
||||
if (!pMonitor)
|
||||
return;
|
||||
|
||||
Debug::log(LOG, "Destroy called for monitor %s", pMonitor->output->name);
|
||||
|
||||
pMonitor->onDisconnect();
|
||||
|
||||
// cleanup if not unsafe
|
||||
|
||||
if (!g_pCompositor->m_bUnsafeState) {
|
||||
Debug::log(LOG, "Removing monitor %s from realMonitors", pMonitor->output->name);
|
||||
|
||||
g_pCompositor->m_vRealMonitors.erase(std::remove_if(g_pCompositor->m_vRealMonitors.begin(), g_pCompositor->m_vRealMonitors.end(), [&](std::shared_ptr<CMonitor>& el) { return el.get() == pMonitor; }));
|
||||
|
||||
if (pMostHzMonitor == pMonitor) {
|
||||
@@ -348,3 +355,10 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Events::listener_monitorStateRequest(void* owner, void* data) {
|
||||
const auto PMONITOR = (CMonitor*)owner;
|
||||
const auto E = (wlr_output_event_request_state*)data;
|
||||
|
||||
wlr_output_commit_state(PMONITOR->output, E->state);
|
||||
}
|
||||
|
@@ -52,11 +52,11 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
static auto *const PSWALLOW = &g_pConfigManager->getConfigValuePtr("misc:enable_swallow")->intValue;
|
||||
static auto *const PSWALLOWREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_regex")->strValue;
|
||||
|
||||
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
|
||||
const auto PWORKSPACE = PMONITOR->specialWorkspaceOpen ? g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID) : g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
|
||||
auto PMONITOR = g_pCompositor->m_pLastMonitor;
|
||||
const auto PWORKSPACE = PMONITOR->specialWorkspaceID ? g_pCompositor->getWorkspaceByID(PMONITOR->specialWorkspaceID) : g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
|
||||
PWINDOW->m_iMonitorID = PMONITOR->ID;
|
||||
PWINDOW->m_bMappedX11 = true;
|
||||
PWINDOW->m_iWorkspaceID = PMONITOR->specialWorkspaceOpen ? SPECIAL_WORKSPACE_ID : PMONITOR->activeWorkspace;
|
||||
PWINDOW->m_iWorkspaceID = PMONITOR->specialWorkspaceID ? PMONITOR->specialWorkspaceID : PMONITOR->activeWorkspace;
|
||||
PWINDOW->m_bIsMapped = true;
|
||||
PWINDOW->m_bReadyToDelete = false;
|
||||
PWINDOW->m_bFadingOut = false;
|
||||
@@ -133,7 +133,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
}
|
||||
|
||||
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->activeWorkspace;
|
||||
g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->m_iMonitorID));
|
||||
if (PWINDOW->m_iMonitorID != PMONITOR->ID) {
|
||||
g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->m_iMonitorID));
|
||||
PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
||||
}
|
||||
|
||||
Debug::log(ERR, "Rule monitor, applying to window %x -> mon: %i, workspace: %i", PWINDOW, PWINDOW->m_iMonitorID, PWINDOW->m_iWorkspaceID);
|
||||
} catch (std::exception& e) {
|
||||
@@ -161,10 +164,14 @@ 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.find("nofullscreenrequest") == 0) {
|
||||
PWINDOW->m_bNoFullscreenRequest = true;
|
||||
} else if (r.szRule == "fullscreen") {
|
||||
requestsFullscreen = true;
|
||||
} else if (r.szRule == "windowdance") {
|
||||
PWINDOW->m_sAdditionalConfigData.windowDanceCompat = true;
|
||||
} else if (r.szRule == "nomaxsize") {
|
||||
PWINDOW->m_sAdditionalConfigData.noMaxSize = true;
|
||||
} else if (r.szRule == "forceinput") {
|
||||
PWINDOW->m_sAdditionalConfigData.forceAllowsInput = true;
|
||||
} else if (r.szRule == "pin") {
|
||||
@@ -206,9 +213,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
shouldFocus = true;
|
||||
}
|
||||
|
||||
if (requestedWorkspace == "special") {
|
||||
if (requestedWorkspace.find("special" == 0)) {
|
||||
workspaceSpecial = true;
|
||||
workspaceSilent = true;
|
||||
}
|
||||
|
||||
if (!workspaceSilent) {
|
||||
@@ -216,6 +222,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
|
||||
PWINDOW->m_iMonitorID = g_pCompositor->m_pLastMonitor->ID;
|
||||
PWINDOW->m_iWorkspaceID = g_pCompositor->m_pLastMonitor->activeWorkspace;
|
||||
|
||||
PMONITOR = g_pCompositor->m_pLastMonitor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,7 +241,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
workspaceID = g_pCompositor->getNextAvailableNamedWorkspace();
|
||||
} else if (workspaceSpecial) {
|
||||
workspaceName = "";
|
||||
workspaceID = SPECIAL_WORKSPACE_ID;
|
||||
workspaceID = getWorkspaceIDFromString(requestedWorkspace, workspaceName);
|
||||
} else {
|
||||
try {
|
||||
workspaceID = std::stoi(requestedWorkspace);
|
||||
@@ -397,6 +405,11 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
PWINDOW->m_bX11ShouldntFocus = false;
|
||||
}
|
||||
|
||||
// check LS focus grab
|
||||
const auto PLSFROMFOCUS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus);
|
||||
if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.keyboard_interactive)
|
||||
PWINDOW->m_bNoInitialFocus = true;
|
||||
|
||||
if (!PWINDOW->m_bNoFocus && !PWINDOW->m_bNoInitialFocus && PWINDOW->m_iX11Type != 2 && !workspaceSilent) {
|
||||
g_pCompositor->focusWindow(PWINDOW);
|
||||
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA);
|
||||
@@ -437,7 +450,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
const auto TIMER = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, setAnimToMove, PWINDOW);
|
||||
wl_event_source_timer_update(TIMER, PWINDOW->m_vRealPosition.getDurationLeftMs() + 5);
|
||||
|
||||
if (requestsFullscreen) {
|
||||
if (requestsFullscreen && !PWINDOW->m_bNoFullscreenRequest) {
|
||||
// fix fullscreen on requested (basically do a switcheroo)
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow) {
|
||||
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
|
||||
@@ -545,6 +558,8 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", getFormat("%x", PWINDOW)});
|
||||
|
||||
g_pProtocolManager->m_pToplevelExportProtocolManager->onWindowUnmap(PWINDOW);
|
||||
|
||||
if (!PWINDOW->m_bIsX11) {
|
||||
Debug::log(LOG, "Unregistered late callbacks XDG");
|
||||
PWINDOW->hyprListener_commitWindow.removeCallback();
|
||||
@@ -693,6 +708,11 @@ void Events::listener_destroyWindow(void* owner, void* data) {
|
||||
}
|
||||
|
||||
PWINDOW->m_bReadyToDelete = true;
|
||||
|
||||
if (!PWINDOW->m_bFadingOut) {
|
||||
g_pCompositor->removeWindowFromVectorSafe(PWINDOW); // most likely X11 unmanaged or sumn
|
||||
Debug::log(LOG, "Unmapped window %x removed instantly", PWINDOW);
|
||||
}
|
||||
}
|
||||
|
||||
void Events::listener_setTitleWindow(void* owner, void* data) {
|
||||
@@ -721,7 +741,7 @@ void Events::listener_fullscreenWindow(void* owner, void* data) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (PWINDOW->isHidden())
|
||||
if (PWINDOW->isHidden() || PWINDOW->m_bNoFullscreenRequest)
|
||||
return;
|
||||
|
||||
if (!PWINDOW->m_bIsX11) {
|
||||
@@ -907,8 +927,10 @@ void Events::listener_NewXDGDeco(wl_listener* listener, void* data) {
|
||||
void Events::listener_requestMaximize(void* owner, void* data) {
|
||||
const auto PWINDOW = (CWindow*)owner;
|
||||
|
||||
Debug::log(LOG, "Maximize request for %x", PWINDOW);
|
||||
if (PWINDOW->m_bNoFullscreenRequest)
|
||||
return;
|
||||
|
||||
Debug::log(LOG, "Maximize request for %x", PWINDOW);
|
||||
if (!PWINDOW->m_bIsX11) {
|
||||
const auto EV = (wlr_foreign_toplevel_handle_v1_maximized_event*)data;
|
||||
|
||||
|
@@ -205,6 +205,14 @@ public:
|
||||
m_bRemoveBeginAfterRan = remove;
|
||||
}
|
||||
|
||||
/* resets all callbacks. Does not call any. */
|
||||
void resetAllCallbacks() {
|
||||
m_fBeginCallback = nullptr;
|
||||
m_fEndCallback = nullptr;
|
||||
m_bRemoveBeginAfterRan = false;
|
||||
m_bRemoveEndAfterRan = false;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Vector2D m_vValue = Vector2D(0,0);
|
||||
|
@@ -234,7 +234,18 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||
int result = INT_MAX;
|
||||
if (in.find("special") == 0) {
|
||||
outName = "special";
|
||||
return SPECIAL_WORKSPACE_ID;
|
||||
|
||||
if (in.length() > 8) {
|
||||
const auto NAME = in.substr(8);
|
||||
|
||||
const auto WS = g_pCompositor->getWorkspaceByName("special:" + NAME);
|
||||
|
||||
outName = "special:" + NAME;
|
||||
|
||||
return WS ? WS->m_iID : g_pCompositor->getNewSpecialID();
|
||||
}
|
||||
|
||||
return SPECIAL_WORKSPACE_START;
|
||||
} else if (in.find("name:") == 0) {
|
||||
const auto WORKSPACENAME = in.substr(in.find_first_of(':') + 1);
|
||||
const auto WORKSPACE = g_pCompositor->getWorkspaceByName(WORKSPACENAME);
|
||||
@@ -244,6 +255,13 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||
result = WORKSPACE->m_iID;
|
||||
}
|
||||
outName = WORKSPACENAME;
|
||||
} else if (in.find("empty") == 0) {
|
||||
int id = 0;
|
||||
while (++id < INT_MAX) {
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id);
|
||||
if (!PWORKSPACE || (g_pCompositor->getWindowsOnWorkspace(id) == 0))
|
||||
return id;
|
||||
}
|
||||
} else {
|
||||
if ((in[0] == 'm' || in[0] == 'e') && (in[1] == '-' || in[1] == '+') && isNumber(in.substr(2))) {
|
||||
bool onAllMonitors = in[0] == 'e';
|
||||
@@ -274,7 +292,7 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||
int highestID = -99999;
|
||||
|
||||
for (auto& w : g_pCompositor->m_vWorkspaces) {
|
||||
if (w->m_iID == SPECIAL_WORKSPACE_ID)
|
||||
if (g_pCompositor->isWorkspaceSpecial(w->m_iID))
|
||||
continue;
|
||||
|
||||
if (w->m_iID < lowestID)
|
||||
@@ -290,7 +308,7 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||
searchID = lowestID;
|
||||
}
|
||||
|
||||
if (const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(searchID); PWORKSPACE && PWORKSPACE->m_iID != SPECIAL_WORKSPACE_ID) {
|
||||
if (const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(searchID); PWORKSPACE && !PWORKSPACE->m_bIsSpecialWorkspace) {
|
||||
if (onAllMonitors || PWORKSPACE->m_iMonitorID == g_pCompositor->m_pLastMonitor->ID) {
|
||||
currentID = PWORKSPACE->m_iID;
|
||||
|
||||
@@ -485,4 +503,4 @@ int64_t configStringToInt(const std::string& VALUE) {
|
||||
return 0;
|
||||
}
|
||||
return stol(VALUE);
|
||||
}
|
||||
}
|
||||
|
@@ -3,8 +3,18 @@
|
||||
#include "../Compositor.hpp"
|
||||
|
||||
void CMonitor::onConnect(bool noRule) {
|
||||
if (m_bEnabled)
|
||||
hyprListener_monitorDestroy.removeCallback();
|
||||
hyprListener_monitorFrame.removeCallback();
|
||||
hyprListener_monitorStateRequest.removeCallback();
|
||||
hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this);
|
||||
hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this);
|
||||
hyprListener_monitorStateRequest.initCallback(&output->events.request_state, &Events::listener_monitorStateRequest, this);
|
||||
|
||||
if (m_bEnabled) {
|
||||
wlr_output_enable(output, 1);
|
||||
wlr_output_commit(output);
|
||||
return;
|
||||
}
|
||||
|
||||
szName = output->name;
|
||||
|
||||
@@ -14,13 +24,9 @@ void CMonitor::onConnect(bool noRule) {
|
||||
// get monitor rule that matches
|
||||
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(output->name, output->description ? output->description : "");
|
||||
|
||||
hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this);
|
||||
hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this);
|
||||
|
||||
// if it's disabled, disable and ignore
|
||||
if (monitorRule.disabled) {
|
||||
|
||||
wlr_output_enable_adaptive_sync(output, 1);
|
||||
wlr_output_set_scale(output, 1);
|
||||
wlr_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL);
|
||||
|
||||
@@ -90,10 +96,8 @@ void CMonitor::onConnect(bool noRule) {
|
||||
}
|
||||
|
||||
m_bEnabled = true;
|
||||
|
||||
wlr_output_set_scale(output, monitorRule.scale);
|
||||
|
||||
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, monitorRule.scale);
|
||||
wlr_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL); // TODO: support other transforms
|
||||
|
||||
// create it in the arr
|
||||
vecPosition = monitorRule.offset;
|
||||
@@ -126,16 +130,16 @@ void CMonitor::onConnect(bool noRule) {
|
||||
forceFullFrames = 3; // force 3 full frames to make sure there is no blinking due to double-buffering.
|
||||
//
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName});
|
||||
|
||||
if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet
|
||||
g_pCompositor->m_pLastMonitor = this;
|
||||
g_pCompositor->setActiveMonitor(this);
|
||||
|
||||
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, scale);
|
||||
|
||||
g_pHyprRenderer->arrangeLayersForMonitor(ID);
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName});
|
||||
|
||||
// ensure VRR (will enable if necessary)
|
||||
g_pConfigManager->ensureVRR(this);
|
||||
}
|
||||
@@ -145,6 +149,8 @@ void CMonitor::onDisconnect() {
|
||||
if (!m_bEnabled || g_pCompositor->m_bIsShuttingDown)
|
||||
return;
|
||||
|
||||
Debug::log(LOG, "onDisconnect called for %s", output->name);
|
||||
|
||||
// Cleanup everything. Move windows back, snap cursor, shit.
|
||||
CMonitor* BACKUPMON = nullptr;
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
@@ -155,7 +161,7 @@ void CMonitor::onDisconnect() {
|
||||
}
|
||||
|
||||
if (g_pCompositor->m_pLastMonitor == this)
|
||||
g_pCompositor->m_pLastMonitor = BACKUPMON;
|
||||
g_pCompositor->setActiveMonitor(BACKUPMON);
|
||||
|
||||
// remove mirror
|
||||
if (pMirrorOf) {
|
||||
@@ -179,7 +185,7 @@ void CMonitor::onDisconnect() {
|
||||
if (!BACKUPMON) {
|
||||
Debug::log(WARN, "Unplugged last monitor, entering an unsafe state. Good luck my friend.");
|
||||
|
||||
hyprListener_monitorMode.removeCallback();
|
||||
hyprListener_monitorStateRequest.removeCallback();
|
||||
hyprListener_monitorDestroy.removeCallback();
|
||||
|
||||
g_pCompositor->m_bUnsafeState = true;
|
||||
@@ -187,10 +193,8 @@ void CMonitor::onDisconnect() {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto BACKUPWORKSPACE = BACKUPMON->activeWorkspace > 0 ? std::to_string(BACKUPMON->activeWorkspace) : "name:" + g_pCompositor->getWorkspaceByID(BACKUPMON->activeWorkspace)->m_szName;
|
||||
|
||||
// snap cursor
|
||||
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, BACKUPMON->vecPosition.x + BACKUPMON->vecTransformedSize.x / 2.f, BACKUPMON->vecPosition.y + BACKUPMON->vecTransformedSize.y / 2.f);
|
||||
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, BACKUPMON->vecPosition.x + BACKUPMON->vecTransformedSize.x / 2.f, BACKUPMON->vecPosition.y + BACKUPMON->vecTransformedSize.y / 2.f);
|
||||
|
||||
// move workspaces
|
||||
std::deque<CWorkspace*> wspToMove;
|
||||
@@ -215,13 +219,13 @@ void CMonitor::onDisconnect() {
|
||||
|
||||
wlr_output_commit(output);
|
||||
|
||||
g_pCompositor->m_vWorkspaces.erase(std::remove_if(g_pCompositor->m_vWorkspaces.begin(), g_pCompositor->m_vWorkspaces.end(), [&](std::unique_ptr<CWorkspace>& el) { return el->m_iMonitorID == ID; }));
|
||||
std::erase_if(g_pCompositor->m_vWorkspaces, [&](std::unique_ptr<CWorkspace>& el) { return el->m_iMonitorID == ID; });
|
||||
|
||||
Debug::log(LOG, "Removed monitor %s!", szName.c_str());
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName});
|
||||
|
||||
g_pCompositor->m_vMonitors.erase(std::remove_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](std::shared_ptr<CMonitor>& el) { return el.get() == this; }));
|
||||
std::erase_if(g_pCompositor->m_vMonitors, [&](std::shared_ptr<CMonitor>& el) { return el.get() == this; });
|
||||
}
|
||||
|
||||
void CMonitor::addDamage(pixman_region32_t* rg) {
|
||||
@@ -239,9 +243,9 @@ bool CMonitor::isMirror() {
|
||||
void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) {
|
||||
// Workspace
|
||||
std::string newDefaultWorkspaceName = "";
|
||||
auto WORKSPACEID = monitorRule.defaultWorkspace == "" ? g_pCompositor->m_vWorkspaces.size() + 1 : getWorkspaceIDFromString(monitorRule.defaultWorkspace, newDefaultWorkspaceName);
|
||||
int64_t WORKSPACEID = monitorRule.defaultWorkspace == "" ? g_pCompositor->m_vWorkspaces.size() + 1 : getWorkspaceIDFromString(monitorRule.defaultWorkspace, newDefaultWorkspaceName);
|
||||
|
||||
if (WORKSPACEID == INT_MAX || WORKSPACEID == (long unsigned int)SPECIAL_WORKSPACE_ID) {
|
||||
if (WORKSPACEID == INT_MAX || (WORKSPACEID >= SPECIAL_WORKSPACE_START && WORKSPACEID <= -2)) {
|
||||
WORKSPACEID = g_pCompositor->m_vWorkspaces.size() + 1;
|
||||
newDefaultWorkspaceName = std::to_string(WORKSPACEID);
|
||||
|
||||
@@ -323,7 +327,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
|
||||
|
||||
setupDefaultWS(RULE);
|
||||
|
||||
wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, output, (int)vecPosition.x, (int)vecPosition.y);
|
||||
g_pHyprRenderer->applyMonitorRule(this, (SMonitorRule*)&RULE, true); // will apply the offset and stuff
|
||||
} else {
|
||||
CMonitor* BACKUPMON = nullptr;
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
@@ -361,6 +365,6 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
|
||||
g_pCompositor->m_vMonitors.erase(std::remove_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](const auto& other) { return other.get() == this; }));
|
||||
}
|
||||
|
||||
g_pCompositor->m_pLastMonitor = g_pCompositor->m_vMonitors.front().get();
|
||||
g_pCompositor->setActiveMonitor(g_pCompositor->m_vMonitors.front().get());
|
||||
}
|
||||
}
|
||||
|
@@ -46,8 +46,8 @@ public:
|
||||
CMonitor* pMirrorOf = nullptr;
|
||||
std::vector<CMonitor*> mirrors;
|
||||
|
||||
// for the special workspace
|
||||
bool specialWorkspaceOpen = false;
|
||||
// for the special workspace. 0 means not open.
|
||||
int specialWorkspaceID = 0;
|
||||
|
||||
// Double-linked list because we need to have constant mem addresses for signals
|
||||
// We have to store pointers and use raw new/delete because they might be moved between them
|
||||
@@ -56,7 +56,7 @@ public:
|
||||
|
||||
DYNLISTENER(monitorFrame);
|
||||
DYNLISTENER(monitorDestroy);
|
||||
DYNLISTENER(monitorMode);
|
||||
DYNLISTENER(monitorStateRequest);
|
||||
|
||||
// hack: a group = workspaces on a monitor.
|
||||
// I don't really care lol :P
|
||||
|
@@ -3,8 +3,8 @@
|
||||
#include "../Compositor.hpp"
|
||||
|
||||
void addSurfaceGlobalOffset(SSurfaceTreeNode* node, int* lx, int* ly) {
|
||||
*lx += node->pSurface->sx;
|
||||
*ly += node->pSurface->sy;
|
||||
*lx += node->pSurface->current.dx;
|
||||
*ly += node->pSurface->current.dy;
|
||||
|
||||
if (node->offsetfn) {
|
||||
// This is the root node
|
||||
|
@@ -70,6 +70,7 @@ struct SRenderData {
|
||||
|
||||
// for blurring
|
||||
bool blur = false;
|
||||
bool blockBlurOptimization = false;
|
||||
|
||||
// only for windows, not popups
|
||||
bool squishOversized = true;
|
||||
|
@@ -96,7 +96,7 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
|
||||
}
|
||||
|
||||
// check LS-es
|
||||
if (in) {
|
||||
if (in && !m_bIsSpecialWorkspace) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||
for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
|
||||
if (!ls->fadingOut)
|
||||
|
@@ -144,9 +144,9 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
|
||||
|
||||
CMonitor* PMONITOR = nullptr;
|
||||
|
||||
if (pNode->workspaceID == SPECIAL_WORKSPACE_ID) {
|
||||
if (g_pCompositor->isWorkspaceSpecial(pNode->workspaceID)) {
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
if (m->specialWorkspaceOpen) {
|
||||
if (m->specialWorkspaceID == pNode->workspaceID) {
|
||||
PMONITOR = m.get();
|
||||
break;
|
||||
}
|
||||
@@ -188,7 +188,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
|
||||
|
||||
const auto NODESONWORKSPACE = getNodesOnWorkspace(PWINDOW->m_iWorkspaceID);
|
||||
|
||||
if (*PNOGAPSWHENONLY && PWINDOW->m_iWorkspaceID != SPECIAL_WORKSPACE_ID && (NODESONWORKSPACE == 1 || (pNode->isGroupMember() && pNode->getGroupMemberCount() == NODESONWORKSPACE))) {
|
||||
if (*PNOGAPSWHENONLY && !g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID) && (NODESONWORKSPACE == 1 || (pNode->isGroupMember() && pNode->getGroupMemberCount() == NODESONWORKSPACE) || (PWINDOW->m_bIsFullscreen && g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) {
|
||||
PWINDOW->m_vRealPosition = calcPos - Vector2D(*PBORDERSIZE, *PBORDERSIZE);
|
||||
PWINDOW->m_vRealSize = calcSize + Vector2D(2 * *PBORDERSIZE, 2 * *PBORDERSIZE);
|
||||
|
||||
@@ -238,7 +238,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
|
||||
}
|
||||
}
|
||||
|
||||
if (PWINDOW->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) {
|
||||
if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID)) {
|
||||
// if special, we adjust the coords a bit
|
||||
static auto *const PSCALEFACTOR = &g_pConfigManager->getConfigValuePtr("dwindle:special_scale_factor")->floatValue;
|
||||
|
||||
@@ -293,7 +293,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
|
||||
SDwindleNodeData* OPENINGON;
|
||||
const auto MONFROMCURSOR = g_pCompositor->getMonitorFromCursor();
|
||||
|
||||
if (PMONITOR->ID == MONFROMCURSOR->ID && (PNODE->workspaceID == PMONITOR->activeWorkspace || (PNODE->workspaceID == SPECIAL_WORKSPACE_ID && PMONITOR->specialWorkspaceOpen)) && !*PUSEACTIVE) {
|
||||
if (PMONITOR->ID == MONFROMCURSOR->ID && (PNODE->workspaceID == PMONITOR->activeWorkspace || (g_pCompositor->isWorkspaceSpecial(PNODE->workspaceID) && PMONITOR->specialWorkspaceID)) && !*PUSEACTIVE) {
|
||||
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(g_pInputManager->getMouseCoordsInternal()));
|
||||
|
||||
// happens on reserved area
|
||||
@@ -336,6 +336,16 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
|
||||
g_pCompositor->setWindowFullscreen(PFULLWINDOW, false, FULLSCREEN_FULL);
|
||||
}
|
||||
|
||||
// last fail-safe to avoid duplicate fullscreens
|
||||
if ((!OPENINGON || OPENINGON->pWindow == pWindow) && getNodesOnWorkspace(PNODE->workspaceID) > 1) {
|
||||
for (auto& node : m_lDwindleNodesData) {
|
||||
if (node.workspaceID == PNODE->workspaceID && node.pWindow != pWindow) {
|
||||
OPENINGON = &node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if it's the first, it's easy. Make it fullscreen.
|
||||
if (!OPENINGON || OPENINGON->pWindow == pWindow) {
|
||||
PNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
|
||||
@@ -457,6 +467,10 @@ void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
pWindow->m_sSpecialRenderData.rounding = true;
|
||||
pWindow->m_sSpecialRenderData.border = true;
|
||||
pWindow->m_sSpecialRenderData.decorate = true;
|
||||
|
||||
if (pWindow->m_bIsFullscreen)
|
||||
g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL);
|
||||
|
||||
@@ -563,8 +577,8 @@ void CHyprDwindleLayout::recalculateMonitor(const int& monid) {
|
||||
|
||||
g_pHyprRenderer->damageMonitor(PMONITOR);
|
||||
|
||||
if (PMONITOR->specialWorkspaceOpen) {
|
||||
const auto TOPNODE = getMasterNodeOnWorkspace(SPECIAL_WORKSPACE_ID);
|
||||
if (PMONITOR->specialWorkspaceID) {
|
||||
const auto TOPNODE = getMasterNodeOnWorkspace(PMONITOR->specialWorkspaceID);
|
||||
|
||||
if (TOPNODE && PMONITOR) {
|
||||
TOPNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
|
||||
@@ -705,7 +719,7 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
|
||||
if (!g_pCompositor->windowValidMapped(pWindow))
|
||||
return;
|
||||
|
||||
if (on == pWindow->m_bIsFullscreen || pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
|
||||
if (on == pWindow->m_bIsFullscreen || g_pCompositor->isWorkspaceSpecial(pWindow->m_iWorkspaceID))
|
||||
return; // ignore
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
|
||||
@@ -1008,6 +1022,8 @@ void CHyprDwindleLayout::switchGroupWindow(CWindow* pWindow, bool forward, CWind
|
||||
|
||||
pNewNode->pWindow->updateWindowDecos();
|
||||
PNODE->pWindow->updateWindowDecos();
|
||||
|
||||
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID));
|
||||
}
|
||||
|
||||
SWindowRenderLayoutHints CHyprDwindleLayout::requestRenderHints(CWindow* pWindow) {
|
||||
@@ -1132,6 +1148,9 @@ void CHyprDwindleLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
|
||||
ACTIVE2->pWindow->m_vPosition = ACTIVE2->position;
|
||||
ACTIVE2->pWindow->m_vSize = ACTIVE2->size;
|
||||
}
|
||||
|
||||
g_pHyprRenderer->damageWindow(pWindow);
|
||||
g_pHyprRenderer->damageWindow(pWindow2);
|
||||
}
|
||||
|
||||
void CHyprDwindleLayout::alterSplitRatioBy(CWindow* pWindow, float ratio) {
|
||||
|
@@ -21,6 +21,9 @@ void IHyprLayout::onWindowCreated(CWindow* pWindow) {
|
||||
}
|
||||
|
||||
void IHyprLayout::onWindowRemoved(CWindow* pWindow) {
|
||||
if (pWindow->m_bIsFullscreen)
|
||||
g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL);
|
||||
|
||||
if (pWindow->m_bIsFloating) {
|
||||
onWindowRemovedFloating(pWindow);
|
||||
} else {
|
||||
@@ -380,8 +383,17 @@ CWindow* IHyprLayout::getNextWindowCandidate(CWindow* pWindow) {
|
||||
return g_pCompositor->getFullscreenWindowOnWorkspace(pWindow->m_iWorkspaceID);
|
||||
|
||||
if (pWindow->m_bIsFloating) {
|
||||
// the window was floating, let's try the last tiled window.
|
||||
|
||||
// find whether there is a floating window below this one
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && !w->m_bX11ShouldntFocus && !w->m_bNoFocus) {
|
||||
if (VECINRECT((pWindow->m_vSize / 2.f + pWindow->m_vPosition), w->m_vPosition.x, w->m_vPosition.y, w->m_vPosition.x + w->m_vSize.x, w->m_vPosition.y + w->m_vSize.y)) {
|
||||
return w.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// let's try the last tiled window.
|
||||
if (m_pLastTiledWindow && m_pLastTiledWindow->m_iWorkspaceID == pWindow->m_iWorkspaceID)
|
||||
return m_pLastTiledWindow;
|
||||
|
||||
@@ -407,3 +419,6 @@ CWindow* IHyprLayout::getNextWindowCandidate(CWindow* pWindow) {
|
||||
|
||||
return PWINDOWCANDIDATE;
|
||||
}
|
||||
|
||||
IHyprLayout::~IHyprLayout() {
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@ enum eFullscreenMode : uint8_t;
|
||||
|
||||
interface IHyprLayout {
|
||||
public:
|
||||
virtual ~IHyprLayout() = 0;
|
||||
virtual void onEnable() = 0;
|
||||
virtual void onDisable() = 0;
|
||||
|
||||
|
@@ -111,6 +111,10 @@ void CHyprMasterLayout::onWindowRemovedTiling(CWindow* pWindow) {
|
||||
if (!PNODE)
|
||||
return;
|
||||
|
||||
pWindow->m_sSpecialRenderData.rounding = true;
|
||||
pWindow->m_sSpecialRenderData.border = true;
|
||||
pWindow->m_sSpecialRenderData.decorate = true;
|
||||
|
||||
if (pWindow->m_bIsFullscreen)
|
||||
g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL);
|
||||
|
||||
@@ -149,8 +153,8 @@ void CHyprMasterLayout::recalculateMonitor(const int& monid) {
|
||||
|
||||
g_pHyprRenderer->damageMonitor(PMONITOR);
|
||||
|
||||
if (PMONITOR->specialWorkspaceOpen) {
|
||||
calculateWorkspace(SPECIAL_WORKSPACE_ID);
|
||||
if (PMONITOR->specialWorkspaceID) {
|
||||
calculateWorkspace(PMONITOR->specialWorkspaceID);
|
||||
}
|
||||
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow) {
|
||||
@@ -244,9 +248,9 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
|
||||
void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
|
||||
CMonitor* PMONITOR = nullptr;
|
||||
|
||||
if (pNode->workspaceID == SPECIAL_WORKSPACE_ID) {
|
||||
if (g_pCompositor->isWorkspaceSpecial(pNode->workspaceID)) {
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
if (m->specialWorkspaceOpen) {
|
||||
if (m->specialWorkspaceID == pNode->workspaceID) {
|
||||
PMONITOR = m.get();
|
||||
break;
|
||||
}
|
||||
@@ -285,7 +289,7 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
|
||||
auto calcPos = PWINDOW->m_vPosition + Vector2D(*PBORDERSIZE, *PBORDERSIZE);
|
||||
auto calcSize = PWINDOW->m_vSize - Vector2D(2 * *PBORDERSIZE, 2 * *PBORDERSIZE);
|
||||
|
||||
if (*PNOGAPSWHENONLY && PWINDOW->m_iWorkspaceID != SPECIAL_WORKSPACE_ID && getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) == 1) {
|
||||
if (*PNOGAPSWHENONLY && !g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID) && (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) == 1 || (PWINDOW->m_bIsFullscreen && g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) {
|
||||
PWINDOW->m_vRealPosition = calcPos - Vector2D(*PBORDERSIZE, *PBORDERSIZE);
|
||||
PWINDOW->m_vRealSize = calcSize + Vector2D(2 * *PBORDERSIZE, 2 * *PBORDERSIZE);
|
||||
|
||||
@@ -311,7 +315,7 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
|
||||
calcPos = calcPos + OFFSETTOPLEFT;
|
||||
calcSize = calcSize - OFFSETTOPLEFT - OFFSETBOTTOMRIGHT;
|
||||
|
||||
if (PWINDOW->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) {
|
||||
if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID)) {
|
||||
static auto *const PSCALEFACTOR = &g_pConfigManager->getConfigValuePtr("master:special_scale_factor")->floatValue;
|
||||
|
||||
PWINDOW->m_vRealPosition = calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f;
|
||||
@@ -366,7 +370,7 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow* p
|
||||
double delta = pixResize.x / PMONITOR->vecSize.x;
|
||||
|
||||
for (auto& n : m_lMasterNodesData) {
|
||||
if (n.isMaster)
|
||||
if (n.isMaster && n.workspaceID == PMONITOR->activeWorkspace)
|
||||
n.percMaster = std::clamp(n.percMaster + delta, 0.05, 0.95);
|
||||
}
|
||||
|
||||
@@ -391,7 +395,7 @@ void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreen
|
||||
if (!g_pCompositor->windowValidMapped(pWindow))
|
||||
return;
|
||||
|
||||
if (on == pWindow->m_bIsFullscreen || pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
|
||||
if (on == pWindow->m_bIsFullscreen || g_pCompositor->isWorkspaceSpecial(pWindow->m_iWorkspaceID))
|
||||
return; // ignore
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
|
||||
@@ -498,6 +502,9 @@ void CHyprMasterLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
|
||||
recalculateMonitor(pWindow->m_iMonitorID);
|
||||
if (PNODE2->workspaceID != PNODE->workspaceID)
|
||||
recalculateMonitor(pWindow2->m_iMonitorID);
|
||||
|
||||
g_pHyprRenderer->damageWindow(pWindow);
|
||||
g_pHyprRenderer->damageWindow(pWindow2);
|
||||
}
|
||||
|
||||
void CHyprMasterLayout::alterSplitRatioBy(CWindow* pWindow, float ratio) {
|
||||
@@ -590,8 +597,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
|
||||
return;
|
||||
|
||||
g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
|
||||
Vector2D middle = PWINDOWTOCHANGETO->m_vRealPosition.goalv() + PWINDOWTOCHANGETO->m_vRealSize.goalv() / 2.f;
|
||||
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, middle.x, middle.y);
|
||||
g_pCompositor->warpCursorTo(PWINDOWTOCHANGETO->m_vRealPosition.goalv() + PWINDOWTOCHANGETO->m_vRealSize.goalv() / 2.f);
|
||||
};
|
||||
|
||||
if (message == "swapwithmaster") {
|
||||
@@ -605,12 +611,21 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
|
||||
|
||||
const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID);
|
||||
|
||||
if (!PMASTER || PMASTER->pWindow == PWINDOW)
|
||||
if (!PMASTER)
|
||||
return 0;
|
||||
|
||||
switchWindows(PWINDOW, PMASTER->pWindow);
|
||||
|
||||
switchToWindow(PWINDOW);
|
||||
if (PMASTER->pWindow != PWINDOW) {
|
||||
switchWindows(PWINDOW, PMASTER->pWindow);
|
||||
switchToWindow(PWINDOW);
|
||||
} else {
|
||||
for (auto& n : m_lMasterNodesData) {
|
||||
if (n.workspaceID == PMASTER->workspaceID && !n.isMaster) {
|
||||
switchWindows(n.pWindow, PMASTER->pWindow);
|
||||
switchToWindow(n.pWindow);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else if (message == "focusmaster") {
|
||||
@@ -621,10 +636,19 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
|
||||
|
||||
const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID);
|
||||
|
||||
if (!PMASTER || PMASTER->pWindow == PWINDOW)
|
||||
if (!PMASTER)
|
||||
return 0;
|
||||
|
||||
switchToWindow(PMASTER->pWindow);
|
||||
if (PMASTER->pWindow != PWINDOW)
|
||||
switchToWindow(PMASTER->pWindow);
|
||||
else {
|
||||
for (auto& n : m_lMasterNodesData) {
|
||||
if (n.workspaceID == PMASTER->workspaceID && !n.isMaster) {
|
||||
switchToWindow(n.pWindow);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else if (message == "cyclenext") {
|
||||
|
@@ -5,10 +5,6 @@
|
||||
#include "init/initHelpers.hpp"
|
||||
#include <iostream>
|
||||
|
||||
// I am a bad bad boy and have used some global vars here,
|
||||
// just for this file
|
||||
bool ignoreSudo = false;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
if (!getenv("XDG_RUNTIME_DIR"))
|
||||
@@ -19,9 +15,12 @@ int main(int argc, char** argv) {
|
||||
for (auto i = 0; i < argc; ++i)
|
||||
cmd += std::string(i == 0 ? "" : " ") + argv[i];
|
||||
setenv("HYPRLAND_CMD", cmd.c_str(), 1);
|
||||
setenv("XDG_BACKEND", "wayland", 1);
|
||||
setenv("_JAVA_AWT_WM_NONREPARENTING", "1", 0);
|
||||
|
||||
// parse some args
|
||||
std::string configPath;
|
||||
bool ignoreSudo = false;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (!strcmp(argv[i], "--i-am-really-stupid"))
|
||||
ignoreSudo = true;
|
||||
|
@@ -594,7 +594,7 @@ void CKeybindManager::toggleActiveFloating(std::string args) {
|
||||
// remove drag status
|
||||
g_pInputManager->currentlyDraggedWindow = nullptr;
|
||||
|
||||
if (PWINDOW->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
|
||||
if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID))
|
||||
return;
|
||||
|
||||
PWINDOW->m_bIsFloating = !PWINDOW->m_bIsFloating;
|
||||
@@ -707,6 +707,8 @@ void CKeybindManager::changeworkspace(std::string args) {
|
||||
// remove constraints
|
||||
g_pInputManager->unconstrainMouse();
|
||||
|
||||
g_pInputManager->m_bEmptyFocusCursorSet = false;
|
||||
|
||||
// if it's not internal, we will unfocus to prevent stuck focus
|
||||
if (!internal)
|
||||
g_pCompositor->focusWindow(nullptr);
|
||||
@@ -721,7 +723,7 @@ void CKeybindManager::changeworkspace(std::string args) {
|
||||
// Remember previous workspace.
|
||||
PWORKSPACETOCHANGETO->m_iPrevWorkspaceID = g_pCompositor->m_pLastMonitor->activeWorkspace;
|
||||
|
||||
if (workspaceToChangeTo == SPECIAL_WORKSPACE_ID)
|
||||
if (g_pCompositor->isWorkspaceSpecial(workspaceToChangeTo))
|
||||
PWORKSPACETOCHANGETO->m_iMonitorID = PMONITOR->ID;
|
||||
|
||||
// if it's not visible, make it visible.
|
||||
@@ -736,10 +738,10 @@ void CKeybindManager::changeworkspace(std::string args) {
|
||||
}
|
||||
|
||||
// change it
|
||||
if (workspaceToChangeTo != SPECIAL_WORKSPACE_ID)
|
||||
if (!g_pCompositor->isWorkspaceSpecial(workspaceToChangeTo))
|
||||
PMONITOR->activeWorkspace = workspaceToChangeTo;
|
||||
else
|
||||
PMONITOR->specialWorkspaceOpen = true;
|
||||
PMONITOR->specialWorkspaceID = workspaceToChangeTo;
|
||||
|
||||
// here and only here begin anim. we don't want to anim visible workspaces on other monitors.
|
||||
// check if anim left or right
|
||||
@@ -755,15 +757,9 @@ void CKeybindManager::changeworkspace(std::string args) {
|
||||
}
|
||||
|
||||
// If the monitor is not the one our cursor's at, warp to it.
|
||||
const bool anotherMonitor = PMONITOR != g_pCompositor->getMonitorFromCursor();
|
||||
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;
|
||||
}
|
||||
const bool anotherMonitor = PMONITOR != g_pCompositor->m_pLastMonitor;
|
||||
if (anotherMonitor)
|
||||
g_pCompositor->warpCursorTo(PMONITOR->vecPosition + PMONITOR->vecSize / 2.f);
|
||||
|
||||
// set active and deactivate all other in wlr
|
||||
g_pCompositor->deactivateAllWLRWorkspaces(PWORKSPACETOCHANGETO->m_pWlrHandle);
|
||||
@@ -788,7 +784,7 @@ void CKeybindManager::changeworkspace(std::string args) {
|
||||
g_pInputManager->refocus();
|
||||
|
||||
// set the new monitor as the last (no warps would bug otherwise)
|
||||
g_pCompositor->m_pLastMonitor = g_pCompositor->getMonitorFromID(PWORKSPACETOCHANGETO->m_iMonitorID);
|
||||
g_pCompositor->setActiveMonitor(g_pCompositor->getMonitorFromID(PWORKSPACETOCHANGETO->m_iMonitorID));
|
||||
|
||||
// mark the monitor dirty
|
||||
g_pHyprRenderer->damageMonitor(PMONITOR);
|
||||
@@ -812,6 +808,8 @@ void CKeybindManager::changeworkspace(std::string args) {
|
||||
|
||||
const auto PWORKSPACE = g_pCompositor->createNewWorkspace(workspaceToChangeTo, PMONITOR->ID, workspaceName);
|
||||
|
||||
const bool ANOTHERMONITOR = PMONITOR != g_pCompositor->m_pLastMonitor;
|
||||
|
||||
if (!isSwitchingToPrevious)
|
||||
// Remember previous workspace.
|
||||
PWORKSPACE->m_iPrevWorkspaceID = OLDWORKSPACE;
|
||||
@@ -819,7 +817,7 @@ void CKeybindManager::changeworkspace(std::string args) {
|
||||
// start anim on new workspace
|
||||
PWORKSPACE->startAnim(true, ANIMTOLEFT);
|
||||
|
||||
PMONITOR->specialWorkspaceOpen = false;
|
||||
PMONITOR->specialWorkspaceID = 0;
|
||||
|
||||
// fix pinned windows
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
@@ -828,10 +826,10 @@ void CKeybindManager::changeworkspace(std::string args) {
|
||||
}
|
||||
}
|
||||
|
||||
if (workspaceToChangeTo != SPECIAL_WORKSPACE_ID)
|
||||
if (!g_pCompositor->isWorkspaceSpecial(workspaceToChangeTo))
|
||||
PMONITOR->activeWorkspace = workspaceToChangeTo;
|
||||
else
|
||||
PMONITOR->specialWorkspaceOpen = true;
|
||||
PMONITOR->specialWorkspaceID = workspaceToChangeTo;
|
||||
|
||||
// set active and deactivate all other
|
||||
g_pCompositor->deactivateAllWLRWorkspaces(PWORKSPACE->m_pWlrHandle);
|
||||
@@ -844,13 +842,16 @@ void CKeybindManager::changeworkspace(std::string args) {
|
||||
if (g_pCompositor->m_pLastMonitor != PMONITOR)
|
||||
g_pCompositor->warpCursorTo(PMONITOR->vecPosition + PMONITOR->vecSize / 2.f);
|
||||
|
||||
g_pCompositor->m_pLastMonitor = PMONITOR;
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"workspace", PWORKSPACE->m_szName});
|
||||
|
||||
g_pCompositor->setActiveMonitor(PMONITOR);
|
||||
|
||||
// focus (clears the last)
|
||||
g_pInputManager->refocus();
|
||||
|
||||
// Event
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"workspace", PWORKSPACE->m_szName});
|
||||
// Events
|
||||
if (ANOTHERMONITOR)
|
||||
g_pCompositor->warpCursorTo(PMONITOR->vecPosition + PMONITOR->vecSize / 2.f);
|
||||
|
||||
Debug::log(LOG, "Changed to workspace %i", workspaceToChangeTo);
|
||||
}
|
||||
@@ -861,7 +862,7 @@ void CKeybindManager::fullscreenActive(std::string args) {
|
||||
if (!PWINDOW)
|
||||
return;
|
||||
|
||||
if (PWINDOW->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
|
||||
if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID))
|
||||
return;
|
||||
|
||||
g_pCompositor->setWindowFullscreen(PWINDOW, !PWINDOW->m_bIsFullscreen, args == "1" ? FULLSCREEN_MAXIMIZED : FULLSCREEN_FULL);
|
||||
@@ -884,8 +885,8 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
|
||||
const auto OLDWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID);
|
||||
|
||||
// hack
|
||||
std::string unusedName;
|
||||
const auto WORKSPACEID = getWorkspaceIDFromString(args, unusedName);
|
||||
std::string workspaceName;
|
||||
const auto WORKSPACEID = getWorkspaceIDFromString(args, workspaceName);
|
||||
|
||||
if (WORKSPACEID == PWINDOW->m_iWorkspaceID) {
|
||||
Debug::log(LOG, "Not moving to workspace because it didn't change.");
|
||||
@@ -894,12 +895,11 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
|
||||
|
||||
auto PSAVEDSIZE = PWINDOW->m_vRealSize.goalv();
|
||||
auto PSAVEDPOS = PWINDOW->m_vRealPosition.goalv();
|
||||
const bool WASFULLSCREEN = PWINDOW->m_bIsFullscreen;
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW);
|
||||
|
||||
g_pKeybindManager->changeworkspace(args);
|
||||
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);
|
||||
auto PWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);
|
||||
|
||||
if (PWORKSPACE == OLDWORKSPACE) {
|
||||
Debug::log(LOG, "Not moving to workspace because it didn't change.");
|
||||
@@ -907,19 +907,13 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
|
||||
}
|
||||
|
||||
if (!PWORKSPACE) {
|
||||
Debug::log(ERR, "Workspace null in moveActiveToWorkspace?");
|
||||
return;
|
||||
// create
|
||||
PWORKSPACE = g_pCompositor->createNewWorkspace(WORKSPACEID, OLDWORKSPACE->m_iMonitorID, workspaceName);
|
||||
}
|
||||
|
||||
OLDWORKSPACE->m_bHasFullscreenWindow = false;
|
||||
|
||||
PWINDOW->moveToWorkspace(PWORKSPACE->m_iID);
|
||||
PWINDOW->m_iMonitorID = PWORKSPACE->m_iMonitorID;
|
||||
|
||||
if (PWINDOW->m_bIsFullscreen) {
|
||||
g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL);
|
||||
}
|
||||
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow) {
|
||||
g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), false, FULLSCREEN_FULL);
|
||||
}
|
||||
@@ -936,17 +930,14 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
|
||||
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.vec();
|
||||
}
|
||||
|
||||
// undo the damage if we are moving to the special workspace
|
||||
if (WORKSPACEID == SPECIAL_WORKSPACE_ID) {
|
||||
changeworkspace("[internal]" + std::to_string(OLDWORKSPACE->m_iID));
|
||||
OLDWORKSPACE->startAnim(true, true, true);
|
||||
toggleSpecialWorkspace("");
|
||||
g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID)->startAnim(false, false, true);
|
||||
if (WASFULLSCREEN)
|
||||
g_pCompositor->setWindowFullscreen(PWINDOW, true, OLDWORKSPACE->m_efFullscreenMode);
|
||||
|
||||
for (auto& m : g_pCompositor->m_vMonitors)
|
||||
m->specialWorkspaceOpen = false;
|
||||
} else {
|
||||
if (!g_pCompositor->isWorkspaceSpecial(WORKSPACEID)) {
|
||||
g_pKeybindManager->changeworkspace(args);
|
||||
g_pCompositor->focusWindow(PWINDOW);
|
||||
} else {
|
||||
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID));
|
||||
}
|
||||
|
||||
PWINDOW->updateToplevel();
|
||||
@@ -1064,10 +1055,8 @@ void CKeybindManager::moveFocusTo(std::string args) {
|
||||
if (PLASTWINDOW->m_iMonitorID != PWINDOWTOCHANGETO->m_iMonitorID) {
|
||||
// event
|
||||
const auto PNEWMON = g_pCompositor->getMonitorFromID(PWINDOWTOCHANGETO->m_iMonitorID);
|
||||
const auto PNEWWS = g_pCompositor->getWorkspaceByID(PNEWMON->activeWorkspace);
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", PNEWMON->szName + "," + PNEWWS->m_szName});
|
||||
|
||||
g_pCompositor->m_pLastMonitor = PNEWMON;
|
||||
g_pCompositor->setActiveMonitor(PNEWMON);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1329,52 +1318,93 @@ void CKeybindManager::moveWorkspaceToMonitor(std::string args) {
|
||||
|
||||
void CKeybindManager::toggleSpecialWorkspace(std::string args) {
|
||||
|
||||
if (g_pCompositor->getWindowsOnWorkspace(SPECIAL_WORKSPACE_ID) == 0) {
|
||||
static auto *const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
|
||||
|
||||
std::string workspaceName = "";
|
||||
int workspaceID = getWorkspaceIDFromString("special:" + args, workspaceName);
|
||||
|
||||
if (workspaceID == INT_MAX || !g_pCompositor->isWorkspaceSpecial(workspaceID)) {
|
||||
Debug::log(ERR, "Invalid workspace passed to special");
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_pCompositor->getWindowsOnWorkspace(workspaceID) == 0) {
|
||||
Debug::log(LOG, "Can't open empty special workspace!");
|
||||
return;
|
||||
}
|
||||
|
||||
bool open = false;
|
||||
bool requestedWorkspaceIsAlreadyOpen = false;
|
||||
const auto PMONITOR = *PFOLLOWMOUSE == 1 ? g_pCompositor->getMonitorFromCursor() : g_pCompositor->m_pLastMonitor;
|
||||
int specialOpenOnMonitor = PMONITOR->specialWorkspaceID;
|
||||
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
if (m->specialWorkspaceOpen) {
|
||||
open = true;
|
||||
if (m->specialWorkspaceID == workspaceID) {
|
||||
requestedWorkspaceIsAlreadyOpen = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (open)
|
||||
Debug::log(LOG, "Toggling special workspace to closed");
|
||||
if (requestedWorkspaceIsAlreadyOpen && specialOpenOnMonitor == workspaceID)
|
||||
Debug::log(LOG, "Toggling special workspace %d to closed");
|
||||
else
|
||||
Debug::log(LOG, "Toggling special workspace to open");
|
||||
Debug::log(LOG, "Toggling special workspace %d to open");
|
||||
|
||||
if (open) {
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
if (m->specialWorkspaceOpen != !open) {
|
||||
m->specialWorkspaceOpen = !open;
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
|
||||
if (requestedWorkspaceIsAlreadyOpen && specialOpenOnMonitor == workspaceID) {
|
||||
// already open on this monitor
|
||||
|
||||
g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID)->startAnim(false, false);
|
||||
}
|
||||
PMONITOR->specialWorkspaceID = 0;
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
|
||||
|
||||
g_pCompositor->getWorkspaceByID(workspaceID)->startAnim(false, false);
|
||||
|
||||
if (const auto PWINDOW = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace)->getLastFocusedWindow(); PWINDOW)
|
||||
g_pCompositor->focusWindow(PWINDOW);
|
||||
else
|
||||
g_pInputManager->refocus();
|
||||
} else if (requestedWorkspaceIsAlreadyOpen) {
|
||||
// already open on another monitor
|
||||
|
||||
if (specialOpenOnMonitor) {
|
||||
g_pCompositor->getWorkspaceByID(PMONITOR->specialWorkspaceID)->startAnim(false, false);
|
||||
PMONITOR->specialWorkspaceID = 0;
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
|
||||
}
|
||||
|
||||
if (const auto PWINDOW = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace)->getLastFocusedWindow(); PWINDOW)
|
||||
// move to current
|
||||
const auto PSPECIALWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceID);
|
||||
const auto POLDMON = g_pCompositor->getMonitorFromID(PSPECIALWORKSPACE->m_iMonitorID);
|
||||
|
||||
POLDMON->specialWorkspaceID = 0;
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(POLDMON->ID);
|
||||
PMONITOR->specialWorkspaceID = workspaceID;
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
|
||||
PSPECIALWORKSPACE->m_iMonitorID = PMONITOR->ID;
|
||||
|
||||
if (const auto PWINDOW = PSPECIALWORKSPACE->getLastFocusedWindow(); PWINDOW)
|
||||
g_pCompositor->focusWindow(PWINDOW);
|
||||
else
|
||||
g_pInputManager->refocus();
|
||||
} else {
|
||||
auto PSPECIALWORKSPACE = g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID);
|
||||
// not open anywhere
|
||||
|
||||
if (specialOpenOnMonitor) {
|
||||
g_pCompositor->getWorkspaceByID(PMONITOR->specialWorkspaceID)->startAnim(false, false);
|
||||
PMONITOR->specialWorkspaceID = 0;
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
|
||||
}
|
||||
|
||||
auto PSPECIALWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceID);
|
||||
|
||||
if (!PSPECIALWORKSPACE) {
|
||||
// ??? happens sometimes...?
|
||||
PSPECIALWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(g_pCompositor->m_pLastMonitor->ID, "special", true)).get();
|
||||
PSPECIALWORKSPACE = g_pCompositor->createNewWorkspace(workspaceID, PMONITOR->ID, workspaceName);
|
||||
}
|
||||
|
||||
g_pCompositor->m_pLastMonitor->specialWorkspaceOpen = true;
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(g_pCompositor->m_pLastMonitor->ID);
|
||||
PMONITOR->specialWorkspaceID = workspaceID;
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
|
||||
|
||||
PSPECIALWORKSPACE->m_iMonitorID = PMONITOR->ID;
|
||||
PSPECIALWORKSPACE->startAnim(true, true);
|
||||
PSPECIALWORKSPACE->m_iMonitorID = g_pCompositor->m_pLastMonitor->ID;
|
||||
|
||||
if (const auto PWINDOW = PSPECIALWORKSPACE->getLastFocusedWindow(); PWINDOW)
|
||||
g_pCompositor->focusWindow(PWINDOW);
|
||||
@@ -1626,6 +1656,7 @@ void CKeybindManager::toggleOpaque(std::string unused) {
|
||||
return;
|
||||
|
||||
PWINDOW->m_sAdditionalConfigData.forceOpaque = !PWINDOW->m_sAdditionalConfigData.forceOpaque;
|
||||
PWINDOW->m_sAdditionalConfigData.forceOpaqueOverriden = true;
|
||||
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
}
|
||||
|
5
src/managers/ProtocolManager.cpp
Normal file
5
src/managers/ProtocolManager.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
#include "ProtocolManager.hpp"
|
||||
|
||||
CProtocolManager::CProtocolManager() {
|
||||
m_pToplevelExportProtocolManager = std::make_unique<CToplevelExportProtocolManager>();
|
||||
}
|
13
src/managers/ProtocolManager.hpp
Normal file
13
src/managers/ProtocolManager.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "../defines.hpp"
|
||||
#include "../protocols/ToplevelExport.hpp"
|
||||
|
||||
class CProtocolManager {
|
||||
public:
|
||||
CProtocolManager();
|
||||
|
||||
std::unique_ptr<CToplevelExportProtocolManager> m_pToplevelExportProtocolManager;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CProtocolManager> g_pProtocolManager;
|
@@ -263,7 +263,7 @@ Vector2D CHyprXWaylandManager::getMaxSizeForWindow(CWindow* pWindow) {
|
||||
if (!g_pCompositor->windowValidMapped(pWindow))
|
||||
return Vector2D(99999, 99999);
|
||||
|
||||
if ((pWindow->m_bIsX11 && !pWindow->m_uSurface.xwayland->size_hints) || (!pWindow->m_bIsX11 && !pWindow->m_uSurface.xdg->toplevel))
|
||||
if ((pWindow->m_bIsX11 && !pWindow->m_uSurface.xwayland->size_hints) || (!pWindow->m_bIsX11 && !pWindow->m_uSurface.xdg->toplevel) || pWindow->m_sAdditionalConfigData.noMaxSize)
|
||||
return Vector2D(99999, 99999);
|
||||
|
||||
auto MAXSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_uSurface.xwayland->size_hints->max_width, pWindow->m_uSurface.xwayland->size_hints->max_height)
|
||||
|
@@ -73,6 +73,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
// 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);
|
||||
const auto PCONSTRAINT = g_pCompositor->m_sSeat.mouse->currentConstraint;
|
||||
|
||||
if (!CONSTRAINTWINDOW) {
|
||||
unconstrainMouse();
|
||||
@@ -82,27 +83,26 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
const auto CONSTRAINTPOS = CONSTRAINTWINDOW->m_bIsX11 ? Vector2D(CONSTRAINTWINDOW->m_uSurface.xwayland->x, CONSTRAINTWINDOW->m_uSurface.xwayland->y) : CONSTRAINTWINDOW->m_vRealPosition.vec();
|
||||
const auto CONSTRAINTSIZE = CONSTRAINTWINDOW->m_bIsX11 ? Vector2D(CONSTRAINTWINDOW->m_uSurface.xwayland->width, CONSTRAINTWINDOW->m_uSurface.xwayland->height) : CONSTRAINTWINDOW->m_vRealSize.vec();
|
||||
|
||||
if (!VECINRECT(mouseCoords, CONSTRAINTPOS.x, CONSTRAINTPOS.y, CONSTRAINTPOS.x + CONSTRAINTSIZE.x - 1.0, CONSTRAINTPOS.y + CONSTRAINTSIZE.y - 1.0)) {
|
||||
if (g_pCompositor->m_sSeat.mouse->constraintActive) {
|
||||
Vector2D newConstrainedCoords = mouseCoords;
|
||||
if (g_pCompositor->m_sSeat.mouse->currentConstraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED) {
|
||||
// we just snap the cursor to where it should be.
|
||||
|
||||
if (mouseCoords.x < CONSTRAINTPOS.x)
|
||||
newConstrainedCoords.x = CONSTRAINTPOS.x;
|
||||
else if (mouseCoords.x >= CONSTRAINTPOS.x + CONSTRAINTSIZE.x)
|
||||
newConstrainedCoords.x = CONSTRAINTPOS.x + CONSTRAINTSIZE.x - 1.0;
|
||||
Vector2D hint = { PCONSTRAINT->current.cursor_hint.x, PCONSTRAINT->current.cursor_hint.y };
|
||||
|
||||
if (mouseCoords.y < CONSTRAINTPOS.y)
|
||||
newConstrainedCoords.y = CONSTRAINTPOS.y;
|
||||
else if (mouseCoords.y >= CONSTRAINTPOS.y + CONSTRAINTSIZE.y)
|
||||
newConstrainedCoords.y = CONSTRAINTPOS.y + CONSTRAINTSIZE.y - 1.0;
|
||||
wlr_cursor_warp_closest(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, CONSTRAINTPOS.x + hint.x, CONSTRAINTPOS.y + hint.y);
|
||||
|
||||
wlr_cursor_warp_closest(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, newConstrainedCoords.x, newConstrainedCoords.y);
|
||||
|
||||
mouseCoords = newConstrainedCoords;
|
||||
}
|
||||
return; // don't process anything else, the cursor is locked. The surface should not receive any further events.
|
||||
// these are usually FPS games. They will use the relative motion.
|
||||
} else {
|
||||
if ((!CONSTRAINTWINDOW->m_bIsX11 && PMONITOR && CONSTRAINTWINDOW->m_iWorkspaceID == PMONITOR->activeWorkspace) || (CONSTRAINTWINDOW->m_bIsX11)) {
|
||||
g_pCompositor->m_sSeat.mouse->constraintActive = true;
|
||||
// we restrict the cursor to the confined region
|
||||
if (!pixman_region32_contains_point(&PCONSTRAINT->region, mouseCoords.x - CONSTRAINTPOS.x, mouseCoords.y - CONSTRAINTPOS.y, nullptr)) {
|
||||
if (g_pCompositor->m_sSeat.mouse->constraintActive) {
|
||||
wlr_cursor_warp_closest(g_pCompositor->m_sWLRCursor, NULL, mouseCoords.x, mouseCoords.y);
|
||||
mouseCoords = getMouseCoordsInternal();
|
||||
}
|
||||
} else {
|
||||
if ((!CONSTRAINTWINDOW->m_bIsX11 && PMONITOR && CONSTRAINTWINDOW->m_iWorkspaceID == PMONITOR->activeWorkspace) || (CONSTRAINTWINDOW->m_bIsX11)) {
|
||||
g_pCompositor->m_sSeat.mouse->constraintActive = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,15 +123,12 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
g_pLayoutManager->getCurrentLayout()->onMouseMove(getMouseCoordsInternal());
|
||||
|
||||
if (PMONITOR && PMONITOR != g_pCompositor->m_pLastMonitor) {
|
||||
g_pCompositor->m_pLastMonitor = PMONITOR;
|
||||
g_pCompositor->setActiveMonitor(PMONITOR);
|
||||
|
||||
// set active workspace and deactivate all other in wlr
|
||||
const auto ACTIVEWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
|
||||
g_pCompositor->deactivateAllWLRWorkspaces(ACTIVEWORKSPACE->m_pWlrHandle);
|
||||
ACTIVEWORKSPACE->setActive(true);
|
||||
|
||||
// event
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", PMONITOR->szName + "," + ACTIVEWORKSPACE->m_szName});
|
||||
}
|
||||
|
||||
// overlay is above fullscreen
|
||||
@@ -155,7 +152,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
// only check floating because tiled cant be over fullscreen
|
||||
for (auto w = g_pCompositor->m_vWindows.rbegin(); w != g_pCompositor->m_vWindows.rend(); w++) {
|
||||
wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y};
|
||||
if ((((*w)->m_bIsFloating && (*w)->m_bIsMapped && ((*w)->m_bCreatedOverFullscreen || (*w)->m_bPinned)) || ((*w)->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && PMONITOR->specialWorkspaceOpen)) && wlr_box_contains_point(&box, mouseCoords.x, mouseCoords.y) && g_pCompositor->isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->isHidden()) {
|
||||
if ((((*w)->m_bIsFloating && (*w)->m_bIsMapped && ((*w)->m_bCreatedOverFullscreen || (*w)->m_bPinned)) || (g_pCompositor->isWorkspaceSpecial((*w)->m_iWorkspaceID) && PMONITOR->specialWorkspaceID)) && wlr_box_contains_point(&box, mouseCoords.x, mouseCoords.y) && g_pCompositor->isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->isHidden()) {
|
||||
pFoundWindow = (*w).get();
|
||||
break;
|
||||
}
|
||||
@@ -174,10 +171,10 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
if (!foundSurface) {
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) {
|
||||
|
||||
if (PMONITOR->specialWorkspaceOpen) {
|
||||
if (PMONITOR->specialWorkspaceID) {
|
||||
pFoundWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords);
|
||||
|
||||
if (pFoundWindow && pFoundWindow->m_iWorkspaceID != SPECIAL_WORKSPACE_ID) {
|
||||
if (pFoundWindow && !g_pCompositor->isWorkspaceSpecial(pFoundWindow->m_iWorkspaceID)) {
|
||||
pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
|
||||
}
|
||||
} else {
|
||||
@@ -221,7 +218,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "crosshair", g_pCompositor->m_sWLRCursor);
|
||||
else
|
||||
wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", g_pCompositor->m_sWLRCursor);
|
||||
|
||||
|
||||
m_bEmptyFocusCursorSet = true;
|
||||
}
|
||||
|
||||
@@ -381,13 +378,7 @@ void CInputManager::setClickMode(eClickBehaviorMode mode) {
|
||||
}
|
||||
|
||||
void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
|
||||
const auto PKEYBOARD = wlr_seat_get_keyboard(g_pCompositor->m_sSeat.seat);
|
||||
|
||||
if (!PKEYBOARD) { // ???
|
||||
Debug::log(ERR, "No active keyboard in processMouseDownNormal??");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// notify the keybind manager
|
||||
static auto *const PPASSMOUSE = &g_pConfigManager->getConfigValuePtr("binds:pass_mouse_when_bound")->intValue;
|
||||
const auto PASS = g_pKeybindManager->onMouseEvent(e);
|
||||
@@ -468,7 +459,7 @@ void CInputManager::newKeyboard(wlr_input_device* keyboard) {
|
||||
PNEWKEYBOARD->keyboard = keyboard;
|
||||
|
||||
try {
|
||||
PNEWKEYBOARD->name = std::string(keyboard->name);
|
||||
PNEWKEYBOARD->name = getNameForNewDevice(keyboard->name);
|
||||
} catch (std::exception& e) {
|
||||
Debug::log(ERR, "Keyboard had no name???"); // logic error
|
||||
}
|
||||
@@ -504,7 +495,7 @@ void CInputManager::newVirtualKeyboard(wlr_input_device* keyboard) {
|
||||
PNEWKEYBOARD->isVirtual = true;
|
||||
|
||||
try {
|
||||
PNEWKEYBOARD->name = std::string(keyboard->name);
|
||||
PNEWKEYBOARD->name = getNameForNewDevice(keyboard->name);
|
||||
} catch (std::exception& e) {
|
||||
Debug::log(ERR, "Keyboard had no name???"); // logic error
|
||||
}
|
||||
@@ -541,7 +532,6 @@ void CInputManager::setKeyboardLayout() {
|
||||
|
||||
void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
|
||||
auto devname = pKeyboard->name;
|
||||
transform(devname.begin(), devname.end(), devname.begin(), ::tolower);
|
||||
|
||||
const auto HASCONFIG = g_pConfigManager->deviceConfigExists(devname);
|
||||
|
||||
@@ -665,7 +655,7 @@ void CInputManager::newMouse(wlr_input_device* mouse, bool virt) {
|
||||
PMOUSE->mouse = mouse;
|
||||
PMOUSE->virt = virt;
|
||||
try {
|
||||
PMOUSE->name = std::string(mouse->name);
|
||||
PMOUSE->name = getNameForNewDevice(mouse->name);
|
||||
} catch(std::exception& e) {
|
||||
Debug::log(ERR, "Mouse had no name???"); // logic error
|
||||
}
|
||||
@@ -696,7 +686,6 @@ void CInputManager::setPointerConfigs() {
|
||||
const auto PPOINTER = &m;
|
||||
|
||||
auto devname = PPOINTER->name;
|
||||
transform(devname.begin(), devname.end(), devname.begin(), ::tolower);
|
||||
|
||||
const auto HASCONFIG = g_pConfigManager->deviceConfigExists(devname);
|
||||
|
||||
@@ -732,7 +721,7 @@ void CInputManager::setPointerConfigs() {
|
||||
}
|
||||
|
||||
const auto SCROLLMETHOD = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "scroll_method") : g_pConfigManager->getString("input:scroll_method");
|
||||
if (SCROLLMETHOD == "" || SCROLLMETHOD == STRVAL_EMPTY) {
|
||||
if (SCROLLMETHOD == "") {
|
||||
libinput_device_config_scroll_set_method(LIBINPUTDEV, libinput_device_config_scroll_get_default_method(LIBINPUTDEV));
|
||||
} else if (SCROLLMETHOD == "no_scroll") {
|
||||
libinput_device_config_scroll_set_method(LIBINPUTDEV, LIBINPUT_CONFIG_SCROLL_NO_SCROLL);
|
||||
@@ -774,7 +763,7 @@ void CInputManager::setPointerConfigs() {
|
||||
|
||||
const auto ACCELPROFILE = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "accel_profile") : g_pConfigManager->getString("input:accel_profile");
|
||||
|
||||
if (ACCELPROFILE == "" || ACCELPROFILE == STRVAL_EMPTY) {
|
||||
if (ACCELPROFILE == "") {
|
||||
libinput_device_config_accel_set_profile(LIBINPUTDEV, libinput_device_config_accel_get_default_profile(LIBINPUTDEV));
|
||||
} else if (ACCELPROFILE == "adaptive") {
|
||||
libinput_device_config_accel_set_profile(LIBINPUTDEV, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE);
|
||||
@@ -782,7 +771,11 @@ void CInputManager::setPointerConfigs() {
|
||||
libinput_device_config_accel_set_profile(LIBINPUTDEV, LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT);
|
||||
} else {
|
||||
Debug::log(WARN, "Unknown acceleration profile, falling back to default");
|
||||
}
|
||||
}
|
||||
|
||||
const auto SCROLLBUTTON = HASCONFIG ? g_pConfigManager->getDeviceInt(devname, "scroll_button") : g_pConfigManager->getInt("input:scroll_button");
|
||||
|
||||
libinput_device_config_scroll_set_button(LIBINPUTDEV, SCROLLBUTTON == 0 ? libinput_device_config_scroll_get_default_button(LIBINPUTDEV) : SCROLLBUTTON);
|
||||
|
||||
Debug::log(LOG, "Applied config to mouse %s, sens %.2f", m.name.c_str(), LIBINPUTSENS);
|
||||
}
|
||||
@@ -1015,24 +1008,20 @@ void Events::listener_commitConstraint(void* owner, void* data) {
|
||||
//g_pInputManager->recheckConstraint((SMouse*)owner);
|
||||
}
|
||||
|
||||
void CInputManager::updateCapabilities(wlr_input_device* pDev) {
|
||||
// TODO: this is dumb
|
||||
void CInputManager::updateCapabilities() {
|
||||
uint32_t caps = 0;
|
||||
|
||||
switch (pDev->type) {
|
||||
case WLR_INPUT_DEVICE_KEYBOARD:
|
||||
m_uiCapabilities |= WL_SEAT_CAPABILITY_KEYBOARD;
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_POINTER:
|
||||
m_uiCapabilities |= WL_SEAT_CAPABILITY_POINTER;
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_TOUCH:
|
||||
m_uiCapabilities |= WL_SEAT_CAPABILITY_TOUCH;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!m_lKeyboards.empty())
|
||||
caps |= WL_SEAT_CAPABILITY_KEYBOARD;
|
||||
if (!m_lMice.empty())
|
||||
caps |= WL_SEAT_CAPABILITY_POINTER;
|
||||
if (!m_lTouchDevices.empty())
|
||||
caps |= WL_SEAT_CAPABILITY_TOUCH;
|
||||
if (!m_lTabletTools.empty())
|
||||
caps |= WL_SEAT_CAPABILITY_POINTER;
|
||||
|
||||
wlr_seat_set_capabilities(g_pCompositor->m_sSeat.seat, m_uiCapabilities);
|
||||
wlr_seat_set_capabilities(g_pCompositor->m_sSeat.seat, caps);
|
||||
m_uiCapabilities = caps;
|
||||
}
|
||||
|
||||
uint32_t CInputManager::accumulateModsFromAllKBs() {
|
||||
@@ -1083,7 +1072,7 @@ void CInputManager::newTouchDevice(wlr_input_device* pDevice) {
|
||||
PNEWDEV->pWlrDevice = pDevice;
|
||||
|
||||
try {
|
||||
PNEWDEV->name = std::string(pDevice->name);
|
||||
PNEWDEV->name = getNameForNewDevice(pDevice->name);
|
||||
} catch(std::exception& e) {
|
||||
Debug::log(ERR, "Touch Device had no name???"); // logic error
|
||||
}
|
||||
@@ -1137,18 +1126,15 @@ void CInputManager::setTouchDeviceConfigs() {
|
||||
for (auto& m : m_lTouchDevices) {
|
||||
const auto PTOUCHDEV = &m;
|
||||
|
||||
auto devname = PTOUCHDEV->name;
|
||||
transform(devname.begin(), devname.end(), devname.begin(), ::tolower);
|
||||
|
||||
const auto HASCONFIG = g_pConfigManager->deviceConfigExists(devname);
|
||||
const auto HASCONFIG = g_pConfigManager->deviceConfigExists(PTOUCHDEV->name);
|
||||
|
||||
if (wlr_input_device_is_libinput(m.pWlrDevice)) {
|
||||
const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(m.pWlrDevice);
|
||||
|
||||
const int ROTATION = std::clamp(HASCONFIG ? g_pConfigManager->getDeviceInt(devname, "touch_transform") : g_pConfigManager->getInt("input:touchdevice:transform"), 0, 7);
|
||||
const int ROTATION = std::clamp(HASCONFIG ? g_pConfigManager->getDeviceInt(PTOUCHDEV->name, "touch_transform") : g_pConfigManager->getInt("input:touchdevice:transform"), 0, 7);
|
||||
libinput_device_config_calibration_set_matrix(LIBINPUTDEV, MATRICES[ROTATION]);
|
||||
|
||||
const auto OUTPUT = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "touch_output") : g_pConfigManager->getString("input:touchdevice:output");
|
||||
const auto OUTPUT = HASCONFIG ? g_pConfigManager->getDeviceString(PTOUCHDEV->name, "touch_output") : g_pConfigManager->getString("input:touchdevice:output");
|
||||
if (!OUTPUT.empty() && OUTPUT != STRVAL_EMPTY)
|
||||
PTOUCHDEV->boundOutput = OUTPUT;
|
||||
else
|
||||
@@ -1202,3 +1188,35 @@ void CInputManager::unsetCursorImage() {
|
||||
if (!g_pHyprRenderer->m_bWindowRequestedCursorHide)
|
||||
wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", g_pCompositor->m_sWLRCursor);
|
||||
}
|
||||
|
||||
std::string CInputManager::deviceNameToInternalString(std::string in) {
|
||||
std::replace(in.begin(), in.end(), ' ', '-');
|
||||
std::transform(in.begin(), in.end(), in.begin(), ::tolower);
|
||||
return in;
|
||||
}
|
||||
|
||||
std::string CInputManager::getNameForNewDevice(std::string internalName) {
|
||||
|
||||
auto proposedNewName = deviceNameToInternalString(internalName);
|
||||
int dupeno = 0;
|
||||
|
||||
while (std::find_if(m_lKeyboards.begin(), m_lKeyboards.end(), [&] (const SKeyboard& other) { return other.name == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_lKeyboards.end())
|
||||
dupeno++;
|
||||
|
||||
while (std::find_if(m_lMice.begin(), m_lMice.end(), [&] (const SMouse& other) { return other.name == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_lMice.end())
|
||||
dupeno++;
|
||||
|
||||
while (std::find_if(m_lTouchDevices.begin(), m_lTouchDevices.end(), [&] (const STouchDevice& other) { return other.name == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_lTouchDevices.end())
|
||||
dupeno++;
|
||||
|
||||
while (std::find_if(m_lTabletPads.begin(), m_lTabletPads.end(), [&] (const STabletPad& other) { return other.name == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_lTabletPads.end())
|
||||
dupeno++;
|
||||
|
||||
while (std::find_if(m_lTablets.begin(), m_lTablets.end(), [&] (const STablet& other) { return other.name == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_lTablets.end())
|
||||
dupeno++;
|
||||
|
||||
while (std::find_if(m_lTabletTools.begin(), m_lTabletTools.end(), [&] (const STabletTool& other) { return other.name == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_lTabletTools.end())
|
||||
dupeno++;
|
||||
|
||||
return proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno)));
|
||||
}
|
||||
|
@@ -25,6 +25,8 @@ struct STouchData {
|
||||
Vector2D touchSurfaceOrigin;
|
||||
};
|
||||
|
||||
class CKeybindManager;
|
||||
|
||||
class CInputManager {
|
||||
public:
|
||||
|
||||
@@ -58,7 +60,7 @@ public:
|
||||
void setTouchDeviceConfigs();
|
||||
|
||||
void updateDragIcon();
|
||||
void updateCapabilities(wlr_input_device*);
|
||||
void updateCapabilities();
|
||||
|
||||
void setClickMode(eClickBehaviorMode);
|
||||
eClickBehaviorMode getClickMode();
|
||||
@@ -129,6 +131,9 @@ public:
|
||||
void setCursorImageUntilUnset(std::string);
|
||||
void unsetCursorImage();
|
||||
|
||||
std::string deviceNameToInternalString(std::string);
|
||||
std::string getNameForNewDevice(std::string);
|
||||
|
||||
private:
|
||||
|
||||
bool m_bCursorImageOverriden = false;
|
||||
@@ -161,6 +166,8 @@ private:
|
||||
|
||||
// swipe
|
||||
void beginWorkspaceSwipe();
|
||||
|
||||
friend class CKeybindManager;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CInputManager> g_pInputManager;
|
||||
|
@@ -11,7 +11,7 @@ void CInputManager::onSwipeBegin(wlr_pointer_swipe_begin_event* e) {
|
||||
|
||||
int onMonitor = 0;
|
||||
for (auto& w : g_pCompositor->m_vWorkspaces) {
|
||||
if (w->m_iMonitorID == g_pCompositor->m_pLastMonitor->ID && w->m_iID != SPECIAL_WORKSPACE_ID) {
|
||||
if (w->m_iMonitorID == g_pCompositor->m_pLastMonitor->ID && !g_pCompositor->isWorkspaceSpecial(w->m_iID)) {
|
||||
onMonitor++;
|
||||
}
|
||||
}
|
||||
@@ -188,7 +188,10 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
|
||||
|
||||
m_sActiveSwipe.delta = std::clamp(m_sActiveSwipe.delta, (double)-*PSWIPEDIST, (double)*PSWIPEDIST);
|
||||
|
||||
if (((m_sActiveSwipe.pWorkspaceBegin->m_iID == workspaceIDLeft || m_sActiveSwipe.pWorkspaceBegin->m_iID == workspaceIDRight) && *PSWIPENEW && (m_sActiveSwipe.delta < 0)) || (m_sActiveSwipe.delta > 0 && g_pCompositor->getWindowsOnWorkspace(m_sActiveSwipe.pWorkspaceBegin->m_iID) == 0 && workspaceIDRight <= m_sActiveSwipe.pWorkspaceBegin->m_iID)) {
|
||||
if ((m_sActiveSwipe.pWorkspaceBegin->m_iID == workspaceIDLeft && *PSWIPENEW && (m_sActiveSwipe.delta < 0)) ||
|
||||
(m_sActiveSwipe.delta > 0 && g_pCompositor->getWindowsOnWorkspace(m_sActiveSwipe.pWorkspaceBegin->m_iID) == 0 && workspaceIDRight <= m_sActiveSwipe.pWorkspaceBegin->m_iID) ||
|
||||
(m_sActiveSwipe.delta < 0 && m_sActiveSwipe.pWorkspaceBegin->m_iID <= workspaceIDLeft)) {
|
||||
|
||||
m_sActiveSwipe.delta = 0;
|
||||
return;
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
|
||||
const auto PNEWTABLET = &m_lTablets.emplace_back();
|
||||
|
||||
try {
|
||||
PNEWTABLET->name = std::string(pDevice->name);
|
||||
PNEWTABLET->name = deviceNameToInternalString(pDevice->name);
|
||||
} catch (std::exception& e) {
|
||||
Debug::log(ERR, "Tablet had no name???"); // logic error
|
||||
}
|
||||
@@ -158,7 +158,7 @@ void CInputManager::newTabletPad(wlr_input_device* pDevice) {
|
||||
const auto PNEWPAD = &m_lTabletPads.emplace_back();
|
||||
|
||||
try {
|
||||
PNEWPAD->name = std::string(pDevice->name);
|
||||
PNEWPAD->name = deviceNameToInternalString(pDevice->name);
|
||||
} catch (std::exception& e) {
|
||||
Debug::log(ERR, "Pad had no name???"); // logic error
|
||||
}
|
||||
|
392
src/protocols/ToplevelExport.cpp
Normal file
392
src/protocols/ToplevelExport.cpp
Normal file
@@ -0,0 +1,392 @@
|
||||
#include "ToplevelExport.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include <drm_fourcc.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "ToplevelExportWlrFuncs.hpp"
|
||||
|
||||
#define TOPLEVEL_EXPORT_VERSION 1
|
||||
|
||||
static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint32_t id) {
|
||||
g_pProtocolManager->m_pToplevelExportProtocolManager->bindManager(client, data, version, id);
|
||||
}
|
||||
|
||||
static void handleDisplayDestroy(struct wl_listener* listener, void* data) {
|
||||
g_pProtocolManager->m_pToplevelExportProtocolManager->displayDestroy();
|
||||
}
|
||||
|
||||
void CToplevelExportProtocolManager::displayDestroy() {
|
||||
wl_global_destroy(m_pGlobal);
|
||||
}
|
||||
|
||||
CToplevelExportProtocolManager::CToplevelExportProtocolManager() {
|
||||
|
||||
#ifndef GLES32
|
||||
Debug::log(WARN, "Toplevel sharing is not supported on LEGACY_RENDERER!");
|
||||
return;
|
||||
#endif
|
||||
|
||||
m_pGlobal = wl_global_create(g_pCompositor->m_sWLDisplay, &hyprland_toplevel_export_manager_v1_interface,
|
||||
TOPLEVEL_EXPORT_VERSION, this, bindManagerInt);
|
||||
|
||||
if (!m_pGlobal) {
|
||||
Debug::log(ERR, "ToplevelExportManager could not start! Sharing windows will not work!");
|
||||
return;
|
||||
}
|
||||
|
||||
m_liDisplayDestroy.notify = handleDisplayDestroy;
|
||||
wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy);
|
||||
|
||||
Debug::log(LOG, "ToplevelExportManager started successfully!");
|
||||
}
|
||||
|
||||
void handleCaptureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, uint32_t handle) {
|
||||
g_pProtocolManager->m_pToplevelExportProtocolManager->captureToplevel(client, resource, frame, overlay_cursor, handle);
|
||||
}
|
||||
|
||||
void handleDestroy(wl_client* client, wl_resource* resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
void handleCopyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage) {
|
||||
g_pProtocolManager->m_pToplevelExportProtocolManager->copyFrame(client, resource, buffer, ignore_damage);
|
||||
}
|
||||
|
||||
void handleDestroyFrame(wl_client* client, wl_resource* resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static const struct hyprland_toplevel_export_manager_v1_interface toplevelExportManagerImpl = {
|
||||
.capture_toplevel = handleCaptureToplevel,
|
||||
.destroy = handleDestroy
|
||||
};
|
||||
|
||||
static const struct hyprland_toplevel_export_frame_v1_interface toplevelFrameImpl = {
|
||||
.copy = handleCopyFrame,
|
||||
.destroy = handleDestroyFrame
|
||||
};
|
||||
|
||||
SToplevelClient* clientFromResource(wl_resource* resource) {
|
||||
ASSERT(wl_resource_instance_of(resource, &hyprland_toplevel_export_manager_v1_interface, &toplevelExportManagerImpl));
|
||||
return (SToplevelClient*)wl_resource_get_user_data(resource);
|
||||
}
|
||||
|
||||
SToplevelFrame* frameFromResource(wl_resource* resource) {
|
||||
ASSERT(wl_resource_instance_of(resource, &hyprland_toplevel_export_frame_v1_interface, &toplevelFrameImpl));
|
||||
return (SToplevelFrame*)wl_resource_get_user_data(resource);
|
||||
}
|
||||
|
||||
void CToplevelExportProtocolManager::removeClient(SToplevelClient* client, bool force) {
|
||||
if (!force) {
|
||||
if (!client || client->ref <= 0)
|
||||
return;
|
||||
|
||||
if (--client->ref != 0)
|
||||
return;
|
||||
}
|
||||
|
||||
m_lClients.remove(*client); // TODO: this doesn't get cleaned up after sharing app exits???
|
||||
}
|
||||
|
||||
void handleManagerResourceDestroy(wl_resource* resource) {
|
||||
const auto PCLIENT = clientFromResource(resource);
|
||||
|
||||
g_pProtocolManager->m_pToplevelExportProtocolManager->removeClient(PCLIENT, true);
|
||||
}
|
||||
|
||||
void CToplevelExportProtocolManager::bindManager(wl_client* client, void* data, uint32_t version, uint32_t id) {
|
||||
const auto PCLIENT = &m_lClients.emplace_back();
|
||||
|
||||
PCLIENT->resource = wl_resource_create(client, &hyprland_toplevel_export_manager_v1_interface,
|
||||
version, id);
|
||||
|
||||
if (!PCLIENT->resource) {
|
||||
Debug::log(ERR, "ToplevelExportManager could not bind! (out of memory?)");
|
||||
m_lClients.remove(*PCLIENT);
|
||||
wl_client_post_no_memory(client);
|
||||
return;
|
||||
}
|
||||
|
||||
PCLIENT->ref = 1;
|
||||
|
||||
wl_resource_set_implementation(PCLIENT->resource, &toplevelExportManagerImpl, PCLIENT, handleManagerResourceDestroy);
|
||||
|
||||
Debug::log(LOG, "ToplevelExportManager bound successfully!");
|
||||
}
|
||||
|
||||
void handleFrameResourceDestroy(wl_resource* resource) {
|
||||
const auto PFRAME = frameFromResource(resource);
|
||||
|
||||
g_pProtocolManager->m_pToplevelExportProtocolManager->removeFrame(PFRAME);
|
||||
}
|
||||
|
||||
void CToplevelExportProtocolManager::removeFrame(SToplevelFrame* frame, bool force) {
|
||||
if (!frame)
|
||||
return;
|
||||
|
||||
std::erase_if(m_vFramesAwaitingWrite, [&] (const auto& other) { return other == frame; });
|
||||
|
||||
wl_resource_set_user_data(frame->resource, nullptr);
|
||||
wlr_buffer_unlock(frame->buffer);
|
||||
removeClient(frame->client, force);
|
||||
m_lFrames.remove(*frame);
|
||||
}
|
||||
|
||||
void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, uint32_t handle) {
|
||||
const auto PCLIENT = clientFromResource(resource);
|
||||
|
||||
const auto PWINDOW = g_pCompositor->getWindowFromHandle(handle);
|
||||
|
||||
// create a frame
|
||||
const auto PFRAME = &m_lFrames.emplace_back();
|
||||
PFRAME->overlayCursor = !!overlay_cursor;
|
||||
PFRAME->resource = wl_resource_create(client, &hyprland_toplevel_export_frame_v1_interface, wl_resource_get_version(resource), frame);
|
||||
PFRAME->pWindow = PWINDOW;
|
||||
|
||||
if (!PWINDOW) {
|
||||
Debug::log(ERR, "Client requested sharing of window handle %x which does not exist!", handle);
|
||||
hyprland_toplevel_export_frame_v1_send_failed(PFRAME->resource);
|
||||
removeFrame(PFRAME);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PWINDOW->m_bIsMapped || PWINDOW->isHidden()) {
|
||||
Debug::log(ERR, "Client requested sharing of window handle %x which is not shareable!", handle);
|
||||
hyprland_toplevel_export_frame_v1_send_failed(PFRAME->resource);
|
||||
removeFrame(PFRAME);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PFRAME->resource) {
|
||||
Debug::log(ERR, "Couldn't alloc frame for sharing! (no memory)");
|
||||
m_lFrames.remove(*PFRAME);
|
||||
wl_client_post_no_memory(client);
|
||||
return;
|
||||
}
|
||||
|
||||
wl_resource_set_implementation(PFRAME->resource, &toplevelFrameImpl, PFRAME, handleFrameResourceDestroy);
|
||||
|
||||
PFRAME->client = PCLIENT;
|
||||
PCLIENT->ref++;
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
||||
|
||||
PFRAME->shmFormat = wlr_output_preferred_read_format(PMONITOR->output);
|
||||
if (PFRAME->shmFormat == DRM_FORMAT_INVALID) {
|
||||
Debug::log(ERR, "No format supported by renderer in capture toplevel");
|
||||
hyprland_toplevel_export_frame_v1_send_failed(resource);
|
||||
removeFrame(PFRAME);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto PSHMINFO = drm_get_pixel_format_info(PFRAME->shmFormat);
|
||||
if (!PSHMINFO) {
|
||||
Debug::log(ERR, "No pixel format supported by renderer in capture toplevel");
|
||||
hyprland_toplevel_export_frame_v1_send_failed(resource);
|
||||
removeFrame(PFRAME);
|
||||
return;
|
||||
}
|
||||
|
||||
if (PMONITOR->output->allocator && (PMONITOR->output->allocator->buffer_caps & WLR_BUFFER_CAP_DMABUF)) {
|
||||
PFRAME->dmabufFormat = PMONITOR->output->render_format;
|
||||
} else {
|
||||
PFRAME->dmabufFormat = DRM_FORMAT_INVALID;
|
||||
}
|
||||
|
||||
PFRAME->box = {0, 0, (int)PWINDOW->m_vRealSize.vec().x, (int)PWINDOW->m_vRealSize.vec().y};
|
||||
int ow, oh;
|
||||
wlr_output_effective_resolution(PMONITOR->output, &ow, &oh);
|
||||
wlr_box_transform(&PFRAME->box, &PFRAME->box, PMONITOR->transform, ow, oh);
|
||||
|
||||
PFRAME->shmStride = (PSHMINFO->bpp / 8) * PFRAME->box.width;
|
||||
|
||||
hyprland_toplevel_export_frame_v1_send_buffer(PFRAME->resource, convert_drm_format_to_wl_shm(PFRAME->shmFormat), PFRAME->box.width, PFRAME->box.height, PFRAME->shmStride);
|
||||
}
|
||||
|
||||
void CToplevelExportProtocolManager::copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage) {
|
||||
const auto PFRAME = frameFromResource(resource);
|
||||
|
||||
if (!PFRAME) {
|
||||
Debug::log(ERR, "No frame in copyFrame??");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PFRAME->pWindow->m_bIsMapped || PFRAME->pWindow->isHidden()) {
|
||||
Debug::log(ERR, "Client requested sharing of window handle %x which is not shareable (2)!", PFRAME->pWindow);
|
||||
hyprland_toplevel_export_frame_v1_send_failed(PFRAME->resource);
|
||||
removeFrame(PFRAME);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto PBUFFER = wlr_buffer_from_resource(buffer);
|
||||
if (!PBUFFER) {
|
||||
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer");
|
||||
removeFrame(PFRAME);
|
||||
return;
|
||||
}
|
||||
|
||||
if (PBUFFER->width != PFRAME->box.width || PBUFFER->height != PFRAME->box.height) {
|
||||
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions");
|
||||
removeFrame(PFRAME);
|
||||
return;
|
||||
}
|
||||
|
||||
if (PFRAME->buffer) {
|
||||
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_ALREADY_USED, "frame already used");
|
||||
removeFrame(PFRAME);
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_dmabuf_attributes dmabufAttrs;
|
||||
void* wlrBufferAccessData;
|
||||
uint32_t wlrBufferAccessFormat;
|
||||
size_t wlrBufferAccessStride;
|
||||
if (wlr_buffer_get_dmabuf(PBUFFER, &dmabufAttrs)) {
|
||||
PFRAME->bufferCap = WLR_BUFFER_CAP_DMABUF;
|
||||
|
||||
if (dmabufAttrs.format != PFRAME->dmabufFormat) {
|
||||
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format");
|
||||
removeFrame(PFRAME);
|
||||
return;
|
||||
}
|
||||
} else if (wlr_buffer_begin_data_ptr_access(PBUFFER, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &wlrBufferAccessData, &wlrBufferAccessFormat, &wlrBufferAccessStride)) {
|
||||
wlr_buffer_end_data_ptr_access(PBUFFER);
|
||||
|
||||
if (wlrBufferAccessFormat != PFRAME->shmFormat) {
|
||||
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format");
|
||||
removeFrame(PFRAME);
|
||||
return;
|
||||
} else if ((int)wlrBufferAccessStride != PFRAME->shmStride) {
|
||||
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer stride");
|
||||
removeFrame(PFRAME);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer type");
|
||||
removeFrame(PFRAME);
|
||||
return;
|
||||
}
|
||||
|
||||
PFRAME->buffer = PBUFFER;
|
||||
|
||||
m_vFramesAwaitingWrite.emplace_back(PFRAME);
|
||||
}
|
||||
|
||||
void CToplevelExportProtocolManager::onMonitorRender(CMonitor* pMonitor) {
|
||||
|
||||
if (m_vFramesAwaitingWrite.empty())
|
||||
return; // nothing to share
|
||||
|
||||
std::vector<SToplevelFrame*> framesToRemove;
|
||||
|
||||
// share frame if correct output
|
||||
for (auto& f : m_vFramesAwaitingWrite) {
|
||||
if (!f->pWindow) {
|
||||
framesToRemove.push_back(f);
|
||||
continue;
|
||||
}
|
||||
|
||||
wlr_box geometry = { f->pWindow->m_vRealPosition.vec().x, f->pWindow->m_vRealPosition.vec().y,
|
||||
f->pWindow->m_vRealSize.vec().x, f->pWindow->m_vRealSize.vec().y };
|
||||
|
||||
if (!wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, &geometry))
|
||||
continue;
|
||||
|
||||
shareFrame(f);
|
||||
|
||||
framesToRemove.push_back(f);
|
||||
}
|
||||
|
||||
for (auto& f : framesToRemove) {
|
||||
removeFrame(f);
|
||||
}
|
||||
}
|
||||
|
||||
void CToplevelExportProtocolManager::shareFrame(SToplevelFrame* frame) {
|
||||
if (!frame->buffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: damage
|
||||
|
||||
timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
uint32_t flags = 0;
|
||||
if (frame->bufferCap == WLR_BUFFER_CAP_DMABUF) {
|
||||
if (!copyFrameDmabuf(frame)) {
|
||||
hyprland_toplevel_export_frame_v1_send_failed(frame->resource);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!copyFrameShm(frame, &now)) {
|
||||
hyprland_toplevel_export_frame_v1_send_failed(frame->resource);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
hyprland_toplevel_export_frame_v1_send_flags(frame->resource, flags);
|
||||
// todo: send damage
|
||||
uint32_t tvSecHi = (sizeof(now.tv_sec) > 4) ? now.tv_sec >> 32 : 0;
|
||||
uint32_t tvSecLo = now.tv_sec & 0xFFFFFFFF;
|
||||
hyprland_toplevel_export_frame_v1_send_ready(frame->resource, tvSecHi, tvSecLo, now.tv_nsec);
|
||||
}
|
||||
|
||||
bool CToplevelExportProtocolManager::copyFrameShm(SToplevelFrame* frame, timespec* now) {
|
||||
void* data;
|
||||
uint32_t format;
|
||||
size_t stride;
|
||||
if (!wlr_buffer_begin_data_ptr_access(frame->buffer, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &data, &format, &stride))
|
||||
return false;
|
||||
|
||||
// render the client
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(frame->pWindow->m_iMonitorID);
|
||||
pixman_region32_t fakeDamage;
|
||||
pixman_region32_init_rect(&fakeDamage, 0, 0, PMONITOR->vecPixelSize.x * 10, PMONITOR->vecPixelSize.y * 10);
|
||||
|
||||
g_pHyprOpenGL->begin(PMONITOR, &fakeDamage, true);
|
||||
g_pHyprOpenGL->clear(CColor(0, 0, 0, 255));
|
||||
|
||||
// render client at 0,0
|
||||
g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(frame->pWindow); // block the feedback to avoid spamming the surface if it's visible
|
||||
g_pHyprRenderer->renderWindow(frame->pWindow, PMONITOR, now, false, RENDER_PASS_ALL, true, true);
|
||||
g_pHyprRenderer->m_bBlockSurfaceFeedback = false;
|
||||
|
||||
// copy pixels
|
||||
const auto PFORMAT = get_gles2_format_from_drm(format);
|
||||
if (!PFORMAT) {
|
||||
Debug::log(ERR, "Cannot read pixels, unsupported format %x", PFORMAT);
|
||||
g_pHyprOpenGL->end();
|
||||
pixman_region32_fini(&fakeDamage);
|
||||
wlr_buffer_end_data_ptr_access(frame->buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, g_pHyprOpenGL->m_RenderData.pCurrentMonData->primaryFB.m_iFb);
|
||||
|
||||
glFinish(); // flush
|
||||
|
||||
glReadPixels(0, 0, frame->box.width, frame->box.height, PFORMAT->gl_format, PFORMAT->gl_type, data);
|
||||
|
||||
g_pHyprOpenGL->end();
|
||||
|
||||
pixman_region32_fini(&fakeDamage);
|
||||
|
||||
wlr_buffer_end_data_ptr_access(frame->buffer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CToplevelExportProtocolManager::copyFrameDmabuf(SToplevelFrame* frame) {
|
||||
// todo
|
||||
Debug::log(ERR, "DMABUF copying not impl'd!");
|
||||
return false;
|
||||
}
|
||||
|
||||
void CToplevelExportProtocolManager::onWindowUnmap(CWindow* pWindow) {
|
||||
for (auto& f : m_lFrames) {
|
||||
if (f.pWindow == pWindow)
|
||||
f.pWindow = nullptr;
|
||||
}
|
||||
}
|
69
src/protocols/ToplevelExport.hpp
Normal file
69
src/protocols/ToplevelExport.hpp
Normal file
@@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
|
||||
#include "../defines.hpp"
|
||||
#include "hyprland-toplevel-export-v1-protocol.h"
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
class CMonitor;
|
||||
class CWindow;
|
||||
|
||||
struct SToplevelClient {
|
||||
int ref = 0;
|
||||
wl_resource* resource = nullptr;
|
||||
|
||||
bool operator==(const SToplevelClient& other) {
|
||||
return resource == other.resource;
|
||||
}
|
||||
};
|
||||
|
||||
struct SToplevelFrame {
|
||||
wl_resource* resource = nullptr;
|
||||
SToplevelClient* client = nullptr;
|
||||
|
||||
uint32_t shmFormat = 0;
|
||||
uint32_t dmabufFormat = 0;
|
||||
wlr_box box = { 0 };
|
||||
int shmStride = 0;
|
||||
|
||||
bool overlayCursor = false;
|
||||
|
||||
wlr_buffer_cap bufferCap = WLR_BUFFER_CAP_SHM;
|
||||
|
||||
wlr_buffer* buffer = nullptr;
|
||||
|
||||
CWindow* pWindow = nullptr;
|
||||
|
||||
bool operator==(const SToplevelFrame& other) {
|
||||
return resource == other.resource && client == other.client;
|
||||
}
|
||||
};
|
||||
|
||||
class CToplevelExportProtocolManager {
|
||||
public:
|
||||
CToplevelExportProtocolManager();
|
||||
|
||||
void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id);
|
||||
void captureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, uint32_t handle);
|
||||
void removeClient(SToplevelClient* client, bool force = false);
|
||||
void removeFrame(SToplevelFrame* frame, bool force = false);
|
||||
void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage);
|
||||
|
||||
void onMonitorRender(CMonitor* pMonitor);
|
||||
void displayDestroy();
|
||||
void onWindowUnmap(CWindow* pWindow);
|
||||
|
||||
private:
|
||||
wl_global* m_pGlobal = nullptr;
|
||||
std::list<SToplevelFrame> m_lFrames;
|
||||
std::list<SToplevelClient> m_lClients;
|
||||
|
||||
wl_listener m_liDisplayDestroy;
|
||||
|
||||
std::vector<SToplevelFrame*> m_vFramesAwaitingWrite;
|
||||
|
||||
void shareFrame(SToplevelFrame* frame);
|
||||
bool copyFrameDmabuf(SToplevelFrame* frame);
|
||||
bool copyFrameShm(SToplevelFrame* frame, timespec* now);
|
||||
};
|
312
src/protocols/ToplevelExportWlrFuncs.hpp
Normal file
312
src/protocols/ToplevelExportWlrFuncs.hpp
Normal file
@@ -0,0 +1,312 @@
|
||||
#include <GLES2/gl2ext.h>
|
||||
|
||||
struct wlr_pixel_format_info {
|
||||
uint32_t drm_format;
|
||||
|
||||
/* Equivalent of the format if it has an alpha channel,
|
||||
* DRM_FORMAT_INVALID (0) if NA
|
||||
*/
|
||||
uint32_t opaque_substitute;
|
||||
|
||||
/* Bits per pixels */
|
||||
uint32_t bpp;
|
||||
|
||||
/* True if the format has an alpha channel */
|
||||
bool has_alpha;
|
||||
};
|
||||
|
||||
static const struct wlr_pixel_format_info pixel_format_info[] = {
|
||||
{
|
||||
.drm_format = DRM_FORMAT_XRGB8888,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 32,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_ARGB8888,
|
||||
.opaque_substitute = DRM_FORMAT_XRGB8888,
|
||||
.bpp = 32,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_XBGR8888,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 32,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_ABGR8888,
|
||||
.opaque_substitute = DRM_FORMAT_XBGR8888,
|
||||
.bpp = 32,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_RGBX8888,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 32,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_RGBA8888,
|
||||
.opaque_substitute = DRM_FORMAT_RGBX8888,
|
||||
.bpp = 32,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_BGRX8888,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 32,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_BGRA8888,
|
||||
.opaque_substitute = DRM_FORMAT_BGRX8888,
|
||||
.bpp = 32,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_BGR888,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 24,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_RGBX4444,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 16,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_RGBA4444,
|
||||
.opaque_substitute = DRM_FORMAT_RGBX4444,
|
||||
.bpp = 16,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_RGBX5551,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 16,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_RGBA5551,
|
||||
.opaque_substitute = DRM_FORMAT_RGBX5551,
|
||||
.bpp = 16,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_RGB565,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 16,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_BGR565,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 16,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_XRGB2101010,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 32,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_ARGB2101010,
|
||||
.opaque_substitute = DRM_FORMAT_XRGB2101010,
|
||||
.bpp = 32,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_XBGR2101010,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 32,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_ABGR2101010,
|
||||
.opaque_substitute = DRM_FORMAT_XBGR2101010,
|
||||
.bpp = 32,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_XBGR16161616F,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 64,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_ABGR16161616F,
|
||||
.opaque_substitute = DRM_FORMAT_XBGR16161616F,
|
||||
.bpp = 64,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_XBGR16161616,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 64,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_ABGR16161616,
|
||||
.opaque_substitute = DRM_FORMAT_XBGR16161616,
|
||||
.bpp = 64,
|
||||
.has_alpha = true,
|
||||
},
|
||||
};
|
||||
|
||||
static const size_t pixel_format_info_size =
|
||||
sizeof(pixel_format_info) / sizeof(pixel_format_info[0]);
|
||||
|
||||
const struct wlr_pixel_format_info* drm_get_pixel_format_info(uint32_t fmt) {
|
||||
for (size_t i = 0; i < pixel_format_info_size; ++i) {
|
||||
if (pixel_format_info[i].drm_format == fmt) {
|
||||
return &pixel_format_info[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32_t convert_wl_shm_format_to_drm(enum wl_shm_format fmt) {
|
||||
switch (fmt) {
|
||||
case WL_SHM_FORMAT_XRGB8888:
|
||||
return DRM_FORMAT_XRGB8888;
|
||||
case WL_SHM_FORMAT_ARGB8888:
|
||||
return DRM_FORMAT_ARGB8888;
|
||||
default:
|
||||
return (uint32_t)fmt;
|
||||
}
|
||||
}
|
||||
|
||||
enum wl_shm_format convert_drm_format_to_wl_shm(uint32_t fmt) {
|
||||
switch (fmt) {
|
||||
case DRM_FORMAT_XRGB8888:
|
||||
return WL_SHM_FORMAT_XRGB8888;
|
||||
case DRM_FORMAT_ARGB8888:
|
||||
return WL_SHM_FORMAT_ARGB8888;
|
||||
default:
|
||||
return (enum wl_shm_format)fmt;
|
||||
}
|
||||
}
|
||||
|
||||
struct wlr_gles2_pixel_format {
|
||||
uint32_t drm_format;
|
||||
// optional field, if empty then internalformat = format
|
||||
GLint gl_internalformat;
|
||||
GLint gl_format, gl_type;
|
||||
bool has_alpha;
|
||||
};
|
||||
|
||||
static const struct wlr_gles2_pixel_format formats[] = {
|
||||
{
|
||||
.drm_format = DRM_FORMAT_ARGB8888,
|
||||
.gl_format = GL_BGRA_EXT,
|
||||
.gl_type = GL_UNSIGNED_BYTE,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_XRGB8888,
|
||||
.gl_format = GL_BGRA_EXT,
|
||||
.gl_type = GL_UNSIGNED_BYTE,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_XBGR8888,
|
||||
.gl_format = GL_RGBA,
|
||||
.gl_type = GL_UNSIGNED_BYTE,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_ABGR8888,
|
||||
.gl_format = GL_RGBA,
|
||||
.gl_type = GL_UNSIGNED_BYTE,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_BGR888,
|
||||
.gl_format = GL_RGB,
|
||||
.gl_type = GL_UNSIGNED_BYTE,
|
||||
.has_alpha = false,
|
||||
},
|
||||
#if WLR_LITTLE_ENDIAN
|
||||
{
|
||||
.drm_format = DRM_FORMAT_RGBX4444,
|
||||
.gl_format = GL_RGBA,
|
||||
.gl_type = GL_UNSIGNED_SHORT_4_4_4_4,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_RGBA4444,
|
||||
.gl_format = GL_RGBA,
|
||||
.gl_type = GL_UNSIGNED_SHORT_4_4_4_4,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_RGBX5551,
|
||||
.gl_format = GL_RGBA,
|
||||
.gl_type = GL_UNSIGNED_SHORT_5_5_5_1,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_RGBA5551,
|
||||
.gl_format = GL_RGBA,
|
||||
.gl_type = GL_UNSIGNED_SHORT_5_5_5_1,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_RGB565,
|
||||
.gl_format = GL_RGB,
|
||||
.gl_type = GL_UNSIGNED_SHORT_5_6_5,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_XBGR2101010,
|
||||
.gl_format = GL_RGBA,
|
||||
.gl_type = GL_UNSIGNED_INT_2_10_10_10_REV_EXT,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_ABGR2101010,
|
||||
.gl_format = GL_RGBA,
|
||||
.gl_type = GL_UNSIGNED_INT_2_10_10_10_REV_EXT,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_XBGR16161616F,
|
||||
.gl_format = GL_RGBA,
|
||||
.gl_type = GL_HALF_FLOAT_OES,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_ABGR16161616F,
|
||||
.gl_format = GL_RGBA,
|
||||
.gl_type = GL_HALF_FLOAT_OES,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_XBGR16161616,
|
||||
.gl_internalformat = GL_RGBA16_EXT,
|
||||
.gl_format = GL_RGBA,
|
||||
.gl_type = GL_UNSIGNED_SHORT,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_ABGR16161616,
|
||||
.gl_internalformat = GL_RGBA16_EXT,
|
||||
.gl_format = GL_RGBA,
|
||||
.gl_type = GL_UNSIGNED_SHORT,
|
||||
.has_alpha = true,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
const struct wlr_gles2_pixel_format* get_gles2_format_from_drm(uint32_t fmt) {
|
||||
for (size_t i = 0; i < sizeof(formats) / sizeof(*formats); ++i) {
|
||||
if (formats[i].drm_format == fmt) {
|
||||
return &formats[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
@@ -30,12 +30,22 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
|
||||
RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!");
|
||||
}
|
||||
|
||||
GLuint CHyprOpenGLImpl::createProgram(const std::string& vert, const std::string& frag) {
|
||||
auto vertCompiled = compileShader(GL_VERTEX_SHADER, vert);
|
||||
RASSERT(vertCompiled, "Compiling shader failed. VERTEX NULL! Shader source:\n\n%s", vert.c_str());
|
||||
GLuint CHyprOpenGLImpl::createProgram(const std::string& vert, const std::string& frag, bool dynamic) {
|
||||
auto vertCompiled = compileShader(GL_VERTEX_SHADER, vert, dynamic);
|
||||
if (dynamic) {
|
||||
if (vertCompiled == 0)
|
||||
return 0;
|
||||
} else {
|
||||
RASSERT(vertCompiled, "Compiling shader failed. VERTEX NULL! Shader source:\n\n%s", vert.c_str());
|
||||
}
|
||||
|
||||
auto fragCompiled = compileShader(GL_FRAGMENT_SHADER, frag);
|
||||
RASSERT(fragCompiled, "Compiling shader failed. FRAGMENT NULL! Shader source:\n\n%s", frag.c_str());
|
||||
auto fragCompiled = compileShader(GL_FRAGMENT_SHADER, frag, dynamic);
|
||||
if (dynamic) {
|
||||
if (fragCompiled == 0)
|
||||
return 0;
|
||||
} else {
|
||||
RASSERT(fragCompiled, "Compiling shader failed. FRAGMENT NULL! Shader source:\n\n%s", frag.c_str());
|
||||
}
|
||||
|
||||
auto prog = glCreateProgram();
|
||||
glAttachShader(prog, vertCompiled);
|
||||
@@ -49,12 +59,17 @@ GLuint CHyprOpenGLImpl::createProgram(const std::string& vert, const std::string
|
||||
|
||||
GLint ok;
|
||||
glGetProgramiv(prog, GL_LINK_STATUS, &ok);
|
||||
RASSERT(ok != GL_FALSE, "createProgram() failed! GL_LINK_STATUS not OK!");
|
||||
if (dynamic) {
|
||||
if (ok == GL_FALSE)
|
||||
return 0;
|
||||
} else {
|
||||
RASSERT(ok != GL_FALSE, "createProgram() failed! GL_LINK_STATUS not OK!");
|
||||
}
|
||||
|
||||
return prog;
|
||||
}
|
||||
|
||||
GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src) {
|
||||
GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src, bool dynamic) {
|
||||
auto shader = glCreateShader(type);
|
||||
|
||||
auto shaderSource = src.c_str();
|
||||
@@ -64,7 +79,12 @@ GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src) {
|
||||
|
||||
GLint ok;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &ok);
|
||||
RASSERT(ok != GL_FALSE, "compileShader() failed! GL_COMPILE_STATUS not OK!");
|
||||
if (dynamic) {
|
||||
if (ok == GL_FALSE)
|
||||
return 0;
|
||||
} else {
|
||||
RASSERT(ok != GL_FALSE, "compileShader() failed! GL_COMPILE_STATUS not OK!");
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
@@ -112,6 +132,11 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, pixman_region32_t* pDamage, bool
|
||||
m_RenderData.pDamage = pDamage;
|
||||
|
||||
m_bFakeFrame = fake;
|
||||
|
||||
if (m_bReloadScreenShader) {
|
||||
m_bReloadScreenShader = false;
|
||||
applyScreenShader(g_pConfigManager->getString("decoration:screen_shader"));
|
||||
}
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::end() {
|
||||
@@ -128,9 +153,11 @@ void CHyprOpenGLImpl::end() {
|
||||
clear(CColor(11, 11, 11, 255));
|
||||
|
||||
m_bEndFrame = true;
|
||||
m_bApplyFinalShader = true;
|
||||
|
||||
renderTexture(m_RenderData.pCurrentMonData->primaryFB.m_cTex, &monbox, 255.f, 0);
|
||||
|
||||
m_bApplyFinalShader = false;
|
||||
m_bEndFrame = false;
|
||||
}
|
||||
|
||||
@@ -237,15 +264,48 @@ void CHyprOpenGLImpl::initShaders() {
|
||||
m_RenderData.pCurrentMonData->m_shBORDER1.topLeft = glGetUniformLocation(prog, "topLeft");
|
||||
m_RenderData.pCurrentMonData->m_shBORDER1.bottomRight = glGetUniformLocation(prog, "bottomRight");
|
||||
m_RenderData.pCurrentMonData->m_shBORDER1.fullSize = glGetUniformLocation(prog, "fullSize");
|
||||
m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed = glGetUniformLocation(prog, "fullSizeUntransformed");
|
||||
m_RenderData.pCurrentMonData->m_shBORDER1.radius = glGetUniformLocation(prog, "radius");
|
||||
m_RenderData.pCurrentMonData->m_shBORDER1.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample");
|
||||
m_RenderData.pCurrentMonData->m_shBORDER1.color = glGetUniformLocation(prog, "color");
|
||||
m_RenderData.pCurrentMonData->m_shBORDER1.gradient = glGetUniformLocation(prog, "gradient");
|
||||
m_RenderData.pCurrentMonData->m_shBORDER1.gradientLength = glGetUniformLocation(prog, "gradientLength");
|
||||
m_RenderData.pCurrentMonData->m_shBORDER1.angle = glGetUniformLocation(prog, "angle");
|
||||
m_RenderData.pCurrentMonData->m_shBORDER1.alpha = glGetUniformLocation(prog, "alpha");
|
||||
|
||||
m_RenderData.pCurrentMonData->m_bShadersInitialized = true;
|
||||
|
||||
Debug::log(LOG, "Shaders initialized successfully.");
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::applyScreenShader(const std::string& path) {
|
||||
|
||||
m_sFinalScreenShader.destroy();
|
||||
|
||||
if (path == "" || path == STRVAL_EMPTY)
|
||||
return;
|
||||
|
||||
std::ifstream infile(absolutePath(path, std::string(getenv("HOME")) + "/.config/hypr"));
|
||||
|
||||
if (!infile.good()) {
|
||||
g_pConfigManager->addParseError("Screen shader parser: Screen shader path not found");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string fragmentShader((std::istreambuf_iterator<char>(infile)), (std::istreambuf_iterator<char>()));
|
||||
|
||||
m_sFinalScreenShader.program = createProgram(TEXVERTSRC, fragmentShader, true);
|
||||
|
||||
if (!m_sFinalScreenShader.program) {
|
||||
g_pConfigManager->addParseError("Screen shader parser: Screen shader parse failed");
|
||||
return;
|
||||
}
|
||||
|
||||
m_sFinalScreenShader.proj = glGetUniformLocation(m_sFinalScreenShader.program, "proj");
|
||||
m_sFinalScreenShader.tex = glGetUniformLocation(m_sFinalScreenShader.program, "tex");
|
||||
m_sFinalScreenShader.texAttrib = glGetAttribLocation(m_sFinalScreenShader.program, "texcoord");
|
||||
m_sFinalScreenShader.posAttrib = glGetAttribLocation(m_sFinalScreenShader.program, "pos");
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::clear(const CColor& color) {
|
||||
RASSERT(m_RenderData.pMonitor, "Tried to render without begin()!");
|
||||
|
||||
@@ -416,18 +476,25 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
switch (tex.m_iType) {
|
||||
case TEXTURE_RGBA:
|
||||
shader = &m_RenderData.pCurrentMonData->m_shRGBA;
|
||||
break;
|
||||
case TEXTURE_RGBX:
|
||||
shader = &m_RenderData.pCurrentMonData->m_shRGBX;
|
||||
break;
|
||||
case TEXTURE_EXTERNAL:
|
||||
shader = &m_RenderData.pCurrentMonData->m_shEXT;
|
||||
break;
|
||||
default:
|
||||
RASSERT(false, "tex.m_iTarget unsupported!");
|
||||
bool usingFinalShader = false;
|
||||
|
||||
if (m_bApplyFinalShader && m_sFinalScreenShader.program) {
|
||||
shader = &m_sFinalScreenShader;
|
||||
usingFinalShader = true;
|
||||
} else {
|
||||
switch (tex.m_iType) {
|
||||
case TEXTURE_RGBA:
|
||||
shader = &m_RenderData.pCurrentMonData->m_shRGBA;
|
||||
break;
|
||||
case TEXTURE_RGBX:
|
||||
shader = &m_RenderData.pCurrentMonData->m_shRGBX;
|
||||
break;
|
||||
case TEXTURE_EXTERNAL:
|
||||
shader = &m_RenderData.pCurrentMonData->m_shEXT;
|
||||
break;
|
||||
default:
|
||||
RASSERT(false, "tex.m_iTarget unsupported!");
|
||||
}
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
@@ -444,8 +511,10 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
|
||||
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix);
|
||||
#endif
|
||||
glUniform1i(shader->tex, 0);
|
||||
glUniform1f(shader->alpha, alpha / 255.f);
|
||||
glUniform1i(shader->discardOpaque, (int)discardOpaque);
|
||||
if (!usingFinalShader) {
|
||||
glUniform1f(shader->alpha, alpha / 255.f);
|
||||
glUniform1i(shader->discardOpaque, (int)discardOpaque);
|
||||
}
|
||||
|
||||
wlr_box transformedBox;
|
||||
wlr_box_transform(&transformedBox, pBox, wlr_output_transform_invert(m_RenderData.pMonitor->transform),
|
||||
@@ -455,18 +524,20 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
|
||||
const auto FULLSIZE = Vector2D(transformedBox.width, transformedBox.height);
|
||||
static auto *const PMULTISAMPLEEDGES = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue;
|
||||
|
||||
// Rounded corners
|
||||
glUniform2f(shader->topLeft, TOPLEFT.x, TOPLEFT.y);
|
||||
glUniform2f(shader->fullSize, FULLSIZE.x ,FULLSIZE.y);
|
||||
glUniform1f(shader->radius, round);
|
||||
glUniform1i(shader->primitiveMultisample, (int)(*PMULTISAMPLEEDGES == 1 && round != 0 && !noAA));
|
||||
if (!usingFinalShader) {
|
||||
// Rounded corners
|
||||
glUniform2f(shader->topLeft, TOPLEFT.x, TOPLEFT.y);
|
||||
glUniform2f(shader->fullSize, FULLSIZE.x, FULLSIZE.y);
|
||||
glUniform1f(shader->radius, round);
|
||||
glUniform1i(shader->primitiveMultisample, (int)(*PMULTISAMPLEEDGES == 1 && round != 0 && !noAA));
|
||||
|
||||
if (allowDim && m_pCurrentWindow && *PDIMINACTIVE && m_pCurrentWindow != g_pCompositor->m_pLastWindow) {
|
||||
glUniform1i(shader->applyTint, 1);
|
||||
const auto DIM = m_pCurrentWindow->m_fDimPercent.fl();
|
||||
glUniform3f(shader->tint, 1.f - DIM, 1.f - DIM, 1.f - DIM);
|
||||
} else {
|
||||
glUniform1i(shader->applyTint, 0);
|
||||
if (allowDim && m_pCurrentWindow && *PDIMINACTIVE && m_pCurrentWindow != g_pCompositor->m_pLastWindow) {
|
||||
glUniform1i(shader->applyTint, 1);
|
||||
const auto DIM = m_pCurrentWindow->m_fDimPercent.fl();
|
||||
glUniform3f(shader->tint, 1.f - DIM, 1.f - DIM, 1.f - DIM);
|
||||
} else {
|
||||
glUniform1i(shader->applyTint, 0);
|
||||
}
|
||||
}
|
||||
|
||||
const float verts[] = {
|
||||
@@ -500,13 +571,13 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
|
||||
}
|
||||
}
|
||||
|
||||
pixman_region32_fini(&damageClip);
|
||||
pixman_region32_fini(&damageClip);
|
||||
} else {
|
||||
PIXMAN_DAMAGE_FOREACH(damage) {
|
||||
const auto RECT = RECTSARR[i];
|
||||
scissor(&RECT);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
PIXMAN_DAMAGE_FOREACH(damage) {
|
||||
const auto RECT = RECTSARR[i];
|
||||
scissor(&RECT);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
}
|
||||
|
||||
glDisableVertexAttribArray(shader->posAttrib);
|
||||
@@ -644,14 +715,16 @@ void CHyprOpenGLImpl::markBlurDirtyForMonitor(CMonitor* pMonitor) {
|
||||
|
||||
void CHyprOpenGLImpl::preRender(CMonitor* pMonitor) {
|
||||
static auto *const PBLURNEWOPTIMIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_new_optimizations")->intValue;
|
||||
static auto *const PBLURXRAY = &g_pConfigManager->getConfigValuePtr("decoration:blur_xray")->intValue;
|
||||
static auto *const PBLUR = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue;
|
||||
|
||||
if (!*PBLURNEWOPTIMIZE || !m_mMonitorRenderResources[pMonitor].blurFBDirty)
|
||||
if (!*PBLURNEWOPTIMIZE || !m_mMonitorRenderResources[pMonitor].blurFBDirty || !*PBLUR)
|
||||
return;
|
||||
|
||||
bool has = false;
|
||||
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_iWorkspaceID == pMonitor->activeWorkspace && w->m_bIsMapped && !w->isHidden() && !w->m_bIsFloating) {
|
||||
if (w->m_iWorkspaceID == pMonitor->activeWorkspace && w->m_bIsMapped && !w->isHidden() && (!w->m_bIsFloating || *PBLURXRAY)) {
|
||||
has = true;
|
||||
break;
|
||||
}
|
||||
@@ -688,13 +761,54 @@ void CHyprOpenGLImpl::preBlurForCurrentMonitor() {
|
||||
|
||||
void CHyprOpenGLImpl::preWindowPass() {
|
||||
static auto *const PBLURNEWOPTIMIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_new_optimizations")->intValue;
|
||||
static auto *const PBLURXRAY = &g_pConfigManager->getConfigValuePtr("decoration:blur_xray")->intValue;
|
||||
static auto *const PBLUR = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue;
|
||||
|
||||
if (!m_RenderData.pCurrentMonData->blurFBDirty || !*PBLURNEWOPTIMIZE)
|
||||
if (!m_RenderData.pCurrentMonData->blurFBDirty || !*PBLURNEWOPTIMIZE || !*PBLUR)
|
||||
return;
|
||||
|
||||
auto windowShouldBeBlurred = [&] (CWindow* pWindow) -> bool {
|
||||
if (!pWindow)
|
||||
return false;
|
||||
|
||||
if (pWindow->m_sAdditionalConfigData.forceNoBlur)
|
||||
return false;
|
||||
|
||||
const auto PSURFACE = g_pXWaylandManager->getWindowSurface(pWindow);
|
||||
|
||||
if (PSURFACE->opaque)
|
||||
return false;
|
||||
|
||||
pixman_region32_t inverseOpaque;
|
||||
pixman_region32_init(&inverseOpaque);
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
|
||||
const float A = pWindow->m_fAlpha.fl() * pWindow->m_fActiveInactiveAlpha.fl() * PWORKSPACE->m_fAlpha.fl() / 255.f;
|
||||
|
||||
if (A >= 255.f) {
|
||||
pixman_box32_t surfbox = {0, 0, PSURFACE->current.width, PSURFACE->current.height};
|
||||
pixman_region32_copy(&inverseOpaque, &PSURFACE->current.opaque);
|
||||
pixman_region32_inverse(&inverseOpaque, &inverseOpaque, &surfbox);
|
||||
pixman_region32_intersect_rect(&inverseOpaque, &inverseOpaque, 0, 0, PSURFACE->current.width, PSURFACE->current.height);
|
||||
|
||||
if (!pixman_region32_not_empty(&inverseOpaque)) {
|
||||
pixman_region32_fini(&inverseOpaque);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
pixman_region32_fini(&inverseOpaque);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
bool hasWindows = false;
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_iWorkspaceID == m_RenderData.pMonitor->activeWorkspace && !w->isHidden() && w->m_bIsMapped && !w->m_bIsFloating) {
|
||||
if (w->m_iWorkspaceID == m_RenderData.pMonitor->activeWorkspace && !w->isHidden() && w->m_bIsMapped && (!w->m_bIsFloating || *PBLURXRAY)) {
|
||||
|
||||
// check if window is valid
|
||||
if (!windowShouldBeBlurred(w.get()))
|
||||
continue;
|
||||
|
||||
hasWindows = true;
|
||||
break;
|
||||
}
|
||||
@@ -707,12 +821,13 @@ void CHyprOpenGLImpl::preWindowPass() {
|
||||
preBlurForCurrentMonitor();
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, float a, wlr_surface* pSurface, int round) {
|
||||
void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, float a, wlr_surface* pSurface, int round, bool blockBlurOptimization) {
|
||||
RASSERT(m_RenderData.pMonitor, "Tried to render texture with blur without begin()!");
|
||||
|
||||
static auto *const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue;
|
||||
static auto *const PNOBLUROVERSIZED = &g_pConfigManager->getConfigValuePtr("decoration:no_blur_on_oversized")->intValue;
|
||||
static auto *const PBLURNEWOPTIMIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_new_optimizations")->intValue;
|
||||
static auto *const PBLURXRAY = &g_pConfigManager->getConfigValuePtr("decoration:blur_xray")->intValue;
|
||||
|
||||
// make a damage region for this window
|
||||
pixman_region32_t damage;
|
||||
@@ -720,7 +835,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox,
|
||||
pixman_region32_intersect_rect(&damage, m_RenderData.pDamage, pBox->x, pBox->y, pBox->width, pBox->height); // clip it to the box
|
||||
|
||||
if(!pixman_region32_not_empty(&damage))
|
||||
return;
|
||||
return;
|
||||
|
||||
if (*PBLURENABLED == 0 || (*PNOBLUROVERSIZED && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) || (m_pCurrentWindow && m_pCurrentWindow->m_sAdditionalConfigData.forceNoBlur)) {
|
||||
renderTexture(tex, pBox, a, round, false, true);
|
||||
@@ -730,26 +845,33 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox,
|
||||
// amazing hack: the surface has an opaque region!
|
||||
pixman_region32_t inverseOpaque;
|
||||
pixman_region32_init(&inverseOpaque);
|
||||
if (a == 255.f) {
|
||||
pixman_box32_t monbox = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y};
|
||||
if (a >= 255.f) {
|
||||
pixman_box32_t surfbox = {0, 0, pSurface->current.width, pSurface->current.height};
|
||||
pixman_region32_copy(&inverseOpaque, &pSurface->current.opaque);
|
||||
pixman_region32_translate(&inverseOpaque, pBox->x, pBox->y);
|
||||
pixman_region32_inverse(&inverseOpaque, &inverseOpaque, &monbox);
|
||||
pixman_region32_intersect(&inverseOpaque, &damage, &inverseOpaque);
|
||||
pixman_region32_inverse(&inverseOpaque, &inverseOpaque, &surfbox);
|
||||
pixman_region32_intersect_rect(&inverseOpaque, &inverseOpaque, 0, 0, pSurface->current.width, pSurface->current.height);
|
||||
|
||||
if (!pixman_region32_not_empty(&inverseOpaque)) {
|
||||
pixman_region32_fini(&inverseOpaque);
|
||||
renderTexture(tex, pBox, a, round, false, true);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
pixman_region32_copy(&inverseOpaque, &damage);
|
||||
pixman_region32_init_rect(&inverseOpaque, 0, 0, pBox->width, pBox->height);
|
||||
}
|
||||
|
||||
if (!pixman_region32_not_empty(&inverseOpaque)) {
|
||||
renderTexture(tex, pBox, a, round, false, true); // reject blurring a fully opaque window
|
||||
return;
|
||||
// vvv TODO: layered blur fbs?
|
||||
const bool USENEWOPTIMIZE = (*PBLURNEWOPTIMIZE && !blockBlurOptimization && ((m_pCurrentWindow && !m_pCurrentWindow->m_bIsFloating) || *PBLURXRAY) && m_RenderData.pCurrentMonData->blurFB.m_cTex.m_iTexID && (!m_pCurrentWindow || !g_pCompositor->isWorkspaceSpecial(m_pCurrentWindow->m_iWorkspaceID) ));
|
||||
|
||||
CFramebuffer* POUTFB = nullptr;
|
||||
if (!USENEWOPTIMIZE) {
|
||||
pixman_region32_translate(&inverseOpaque, pBox->x, pBox->y);
|
||||
|
||||
POUTFB = blurMainFramebufferWithDamage(a, pBox, &inverseOpaque);
|
||||
} else {
|
||||
POUTFB = &m_RenderData.pCurrentMonData->blurFB;
|
||||
}
|
||||
|
||||
// vvv TODO: layered blur fbs?
|
||||
const bool USENEWOPTIMIZE = (*PBLURNEWOPTIMIZE && m_pCurrentWindow && !m_pCurrentWindow->m_bIsFloating && m_RenderData.pCurrentMonData->blurFB.m_cTex.m_iTexID && m_pCurrentWindow->m_iWorkspaceID != SPECIAL_WORKSPACE_ID);
|
||||
|
||||
const auto POUTFB = USENEWOPTIMIZE ? &m_RenderData.pCurrentMonData->blurFB : blurMainFramebufferWithDamage(a, pBox, &inverseOpaque);
|
||||
|
||||
pixman_region32_fini(&inverseOpaque);
|
||||
|
||||
// bind primary
|
||||
@@ -804,12 +926,12 @@ void pushVert2D(float x, float y, float* arr, int& counter, wlr_box* box) {
|
||||
counter++;
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int round) {
|
||||
void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CGradientValueData& grad, int round, float a) {
|
||||
RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!");
|
||||
RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!");
|
||||
|
||||
if (!pixman_region32_not_empty(m_RenderData.pDamage) || (m_pCurrentWindow && m_pCurrentWindow->m_sAdditionalConfigData.forceNoBorder))
|
||||
return;
|
||||
return;
|
||||
|
||||
static auto *const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
|
||||
static auto *const PMULTISAMPLE = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue;
|
||||
@@ -819,27 +941,13 @@ void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int round) {
|
||||
|
||||
int scaledBorderSize = *PBORDERSIZE * m_RenderData.pMonitor->scale;
|
||||
|
||||
if (round < 1) {
|
||||
// zero rounding, just lines
|
||||
wlr_box borderbox = {box->x - scaledBorderSize, box->y - scaledBorderSize, scaledBorderSize, box->height + 2 * scaledBorderSize};
|
||||
renderRect(&borderbox, col, 0); // left
|
||||
borderbox = {box->x, box->y - (int)scaledBorderSize, box->width + (int)scaledBorderSize, (int)scaledBorderSize};
|
||||
renderRect(&borderbox, col, 0); // top
|
||||
borderbox = {box->x + box->width, box->y, (int)scaledBorderSize, box->height + (int)scaledBorderSize};
|
||||
renderRect(&borderbox, col, 0); // right
|
||||
borderbox = {box->x, box->y + box->height, box->width, (int)scaledBorderSize};
|
||||
renderRect(&borderbox, col, 0); // bottom
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// adjust box
|
||||
box->x -= scaledBorderSize;
|
||||
box->y -= scaledBorderSize;
|
||||
box->width += 2 * scaledBorderSize;
|
||||
box->height += 2 * scaledBorderSize;
|
||||
|
||||
round += scaledBorderSize;
|
||||
round += round == 0 ? 0 : scaledBorderSize;
|
||||
|
||||
float matrix[9];
|
||||
wlr_matrix_project_box(matrix, box, wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), 0, m_RenderData.pMonitor->output->transform_matrix); // TODO: write own, don't use WLR here
|
||||
@@ -858,15 +966,24 @@ void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int round) {
|
||||
wlr_matrix_transpose(glMatrix, glMatrix);
|
||||
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_FALSE, glMatrix);
|
||||
#endif
|
||||
glUniform4f(m_RenderData.pCurrentMonData->m_shBORDER1.color, col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f);
|
||||
|
||||
const auto TOPLEFT = Vector2D(round, round);
|
||||
const auto BOTTOMRIGHT = Vector2D(box->width - round, box->height - round);
|
||||
const auto FULLSIZE = Vector2D(box->width, box->height);
|
||||
static_assert(sizeof(CColor) == 4 * sizeof(float)); // otherwise the line below this will fail
|
||||
|
||||
glUniform4fv(m_RenderData.pCurrentMonData->m_shBORDER1.gradient, grad.m_vColors.size(), (float*)grad.m_vColors.data());
|
||||
glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.gradientLength, grad.m_vColors.size());
|
||||
glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.angle, (int)(grad.m_fAngle / (PI / 180.0)) % 360 * (PI / 180.0));
|
||||
glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.alpha, a);
|
||||
|
||||
wlr_box transformedBox;
|
||||
wlr_box_transform(&transformedBox, box, wlr_output_transform_invert(m_RenderData.pMonitor->transform),
|
||||
m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y);
|
||||
|
||||
const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y);
|
||||
const auto FULLSIZE = Vector2D(transformedBox.width, transformedBox.height);
|
||||
|
||||
glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y);
|
||||
glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
|
||||
glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y);
|
||||
glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed, (float)box->width, (float)box->height);
|
||||
glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radius, round);
|
||||
glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.thick, scaledBorderSize);
|
||||
glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.primitiveMultisample, *PMULTISAMPLE);
|
||||
@@ -890,19 +1007,25 @@ void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int round) {
|
||||
}
|
||||
}
|
||||
|
||||
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_shBORDER1.posAttrib);
|
||||
glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib);
|
||||
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// fix back box
|
||||
box->x += scaledBorderSize;
|
||||
box->y += scaledBorderSize;
|
||||
box->width -= 2 * scaledBorderSize;
|
||||
box->height -= 2 * scaledBorderSize;
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::makeRawWindowSnapshot(CWindow* pWindow, CFramebuffer* pFramebuffer) {
|
||||
@@ -1069,29 +1192,11 @@ void CHyprOpenGLImpl::makeLayerSnapshot(SLayerSurface* pLayer) {
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@@ -68,6 +68,8 @@ struct SCurrentRenderData {
|
||||
wlr_box clipBox = {};
|
||||
};
|
||||
|
||||
class CGradientValueData;
|
||||
|
||||
class CHyprOpenGLImpl {
|
||||
public:
|
||||
|
||||
@@ -80,9 +82,9 @@ public:
|
||||
void renderRectWithDamage(wlr_box*, const CColor&, pixman_region32_t* damage, int round = 0);
|
||||
void renderTexture(wlr_texture*, wlr_box*, float a, int round = 0, bool allowCustomUV = false);
|
||||
void renderTexture(const CTexture&, wlr_box*, float a, int round = 0, bool discardOpaque = false, bool allowCustomUV = false);
|
||||
void renderTextureWithBlur(const CTexture&, wlr_box*, float a, wlr_surface* pSurface, int round = 0);
|
||||
void renderTextureWithBlur(const CTexture&, wlr_box*, float a, wlr_surface* pSurface, int round = 0, bool blockBlurOptimization = false);
|
||||
void renderRoundedShadow(wlr_box*, int round, int range, float a = 1.0);
|
||||
void renderBorder(wlr_box*, const CColor&, int round);
|
||||
void renderBorder(wlr_box*, const CGradientValueData&, int round, float a = 1.0);
|
||||
|
||||
void makeWindowSnapshot(CWindow*);
|
||||
void makeRawWindowSnapshot(CWindow*, CFramebuffer*);
|
||||
@@ -109,17 +111,20 @@ public:
|
||||
void onWindowResizeStart(CWindow*);
|
||||
void onWindowResizeEnd(CWindow*);
|
||||
|
||||
void applyScreenShader(const std::string& path);
|
||||
|
||||
SCurrentRenderData m_RenderData;
|
||||
|
||||
GLint m_iCurrentOutputFb = 0;
|
||||
GLint m_iWLROutputFb = 0;
|
||||
|
||||
bool m_bReloadScreenShader = true; // at launch it can be set
|
||||
|
||||
CWindow* m_pCurrentWindow = nullptr; // hack to get the current rendered window
|
||||
|
||||
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;
|
||||
@@ -133,9 +138,12 @@ private:
|
||||
|
||||
bool m_bFakeFrame = false;
|
||||
bool m_bEndFrame = false;
|
||||
bool m_bApplyFinalShader = false;
|
||||
|
||||
GLuint createProgram(const std::string&, const std::string&);
|
||||
GLuint compileShader(const GLuint&, std::string);
|
||||
CShader m_sFinalScreenShader;
|
||||
|
||||
GLuint createProgram(const std::string&, const std::string&, bool dynamic = false);
|
||||
GLuint compileShader(const GLuint&, std::string, bool dynamic = false);
|
||||
void createBGTextureForMonitor(CMonitor*);
|
||||
void initShaders();
|
||||
|
||||
|
@@ -42,7 +42,7 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
|
||||
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true);
|
||||
} else {
|
||||
if (RDATA->blur)
|
||||
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, rounding);
|
||||
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, rounding, RDATA->blockBlurOptimization);
|
||||
else
|
||||
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true);
|
||||
}
|
||||
@@ -51,9 +51,10 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
|
||||
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true);
|
||||
}
|
||||
|
||||
wlr_surface_send_frame_done(surface, RDATA->when);
|
||||
|
||||
wlr_presentation_surface_sampled_on_output(g_pCompositor->m_sWLRPresentation, surface, RDATA->output);
|
||||
if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) {
|
||||
wlr_surface_send_frame_done(surface, RDATA->when);
|
||||
wlr_presentation_surface_sampled_on_output(g_pCompositor->m_sWLRPresentation, surface, RDATA->output);
|
||||
}
|
||||
|
||||
// reset the UV, we might've set it above
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
|
||||
@@ -88,7 +89,7 @@ bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow, CMonitor* pMonitor) {
|
||||
if (g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID) && pWindow->m_bIsFloating /* tiled windows can't be multi-ws */)
|
||||
return !pWindow->m_bIsFullscreen; // Do not draw fullscreen windows on other monitors
|
||||
|
||||
if (pMonitor->specialWorkspaceOpen && pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
|
||||
if (pMonitor->specialWorkspaceID && g_pCompositor->isWorkspaceSpecial(pWindow->m_iWorkspaceID))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@@ -111,7 +112,7 @@ bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow) {
|
||||
if (PWORKSPACE && PWORKSPACE->m_iMonitorID == m->ID && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated()))
|
||||
return true;
|
||||
|
||||
if (m->specialWorkspaceOpen && pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
|
||||
if (m->specialWorkspaceID && g_pCompositor->isWorkspaceSpecial(pWindow->m_iWorkspaceID))
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -183,11 +184,11 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(CMonitor* pMonitor, CWor
|
||||
}
|
||||
|
||||
// and then special windows
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (pMonitor->specialWorkspaceID) for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (!g_pCompositor->windowValidMapped(w.get()) && !w->m_bFadingOut)
|
||||
continue;
|
||||
|
||||
if (w->m_iWorkspaceID != SPECIAL_WORKSPACE_ID)
|
||||
if (w->m_iWorkspaceID != pMonitor->specialWorkspaceID)
|
||||
continue;
|
||||
|
||||
if (!shouldRenderWindow(w.get(), pMonitor))
|
||||
@@ -215,7 +216,7 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(CMonitor* pMonitor, CWor
|
||||
g_pHyprError->draw();
|
||||
}
|
||||
|
||||
void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec* time, bool decorate, eRenderPassMode mode, bool ignorePosition) {
|
||||
void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec* time, bool decorate, eRenderPassMode mode, bool ignorePosition, bool ignoreAllGeometry) {
|
||||
if (pWindow->isHidden())
|
||||
return;
|
||||
|
||||
@@ -228,7 +229,6 @@ 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 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) {
|
||||
@@ -236,6 +236,9 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
|
||||
renderdata.y = pMonitor->vecPosition.y;
|
||||
}
|
||||
|
||||
if (ignoreAllGeometry)
|
||||
decorate = false;
|
||||
|
||||
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
|
||||
@@ -243,10 +246,15 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
|
||||
renderdata.fadeAlpha = pWindow->m_fAlpha.fl() * (pWindow->m_bPinned ? 1.f : (PWORKSPACE->m_fAlpha.fl() / 255.f));
|
||||
renderdata.alpha = pWindow->m_fActiveInactiveAlpha.fl();
|
||||
renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && (pWindow->m_bIsFloating ? *PNOFLOATINGBORDERS == 0 : true) && (!pWindow->m_bIsFullscreen || PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL);
|
||||
renderdata.rounding = pWindow->m_sAdditionalConfigData.rounding;
|
||||
renderdata.blur = true; // if it shouldn't, it will be ignored later
|
||||
renderdata.rounding = ignoreAllGeometry ? 0 : pWindow->m_sAdditionalConfigData.rounding;
|
||||
renderdata.blur = !ignoreAllGeometry; // if it shouldn't, it will be ignored later
|
||||
renderdata.pWindow = pWindow;
|
||||
|
||||
if (ignoreAllGeometry) {
|
||||
renderdata.alpha = 1.f;
|
||||
renderdata.fadeAlpha = 255.f;
|
||||
}
|
||||
|
||||
// apply window special data
|
||||
if (pWindow->m_sSpecialRenderData.alphaInactive == -1)
|
||||
renderdata.alpha *= pWindow->m_sSpecialRenderData.alpha;
|
||||
@@ -295,39 +303,26 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
|
||||
|
||||
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;
|
||||
|
||||
float rounding = renderdata.dontRound ? 0 : renderdata.rounding == -1 ? *PROUNDING : renderdata.rounding;
|
||||
rounding *= pMonitor->scale;
|
||||
|
||||
auto col = g_pHyprOpenGL->m_pCurrentWindow->m_cRealBorderColor.col();
|
||||
col.a *= renderdata.fadeAlpha * renderdata.alpha / 255.f;
|
||||
auto grad = g_pHyprOpenGL->m_pCurrentWindow->m_cRealBorderColor;
|
||||
const bool ANIMATED = g_pHyprOpenGL->m_pCurrentWindow->m_fBorderAnimationProgress.isBeingAnimated();
|
||||
float a1 = renderdata.fadeAlpha * renderdata.alpha / 255.f * (ANIMATED ? g_pHyprOpenGL->m_pCurrentWindow->m_fBorderAnimationProgress.fl() : 1.f);
|
||||
|
||||
wlr_box windowBox = {renderdata.x - pMonitor->vecPosition.x, renderdata.y - pMonitor->vecPosition.y, renderdata.w, renderdata.h};
|
||||
|
||||
scaleBox(&windowBox, pMonitor->scale);
|
||||
|
||||
g_pHyprOpenGL->renderBorder(&windowBox, col, rounding);
|
||||
g_pHyprOpenGL->renderBorder(&windowBox, grad, rounding, a1);
|
||||
|
||||
if (ANIMATED) {
|
||||
float a2 = renderdata.fadeAlpha * renderdata.alpha / 255.f * (1.f - g_pHyprOpenGL->m_pCurrentWindow->m_fBorderAnimationProgress.fl());
|
||||
g_pHyprOpenGL->renderBorder(&windowBox, g_pHyprOpenGL->m_pCurrentWindow->m_cRealBorderColorPrevious, rounding, a2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -363,6 +358,7 @@ void CHyprRenderer::renderLayer(SLayerSurface* pLayer, CMonitor* pMonitor, times
|
||||
renderdata.decorate = false;
|
||||
renderdata.w = pLayer->layerSurface->surface->current.width;
|
||||
renderdata.h = pLayer->layerSurface->surface->current.height;
|
||||
renderdata.blockBlurOptimization = pLayer->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM || pLayer->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND;
|
||||
wlr_surface_for_each_surface(pLayer->layerSurface->surface, renderSurface, &renderdata);
|
||||
|
||||
renderdata.squishOversized = false; // don't squish popups
|
||||
@@ -408,6 +404,8 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
|
||||
return;
|
||||
}
|
||||
|
||||
CWindow* lastWindow = nullptr;
|
||||
|
||||
// Non-floating main
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->isHidden() && !w->m_bIsMapped && !w->m_bFadingOut)
|
||||
@@ -416,16 +414,25 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
|
||||
if (w->m_bIsFloating)
|
||||
continue; // floating are in the second pass
|
||||
|
||||
if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
|
||||
if (g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID))
|
||||
continue; // special are in the third pass
|
||||
|
||||
if (!shouldRenderWindow(w.get(), PMONITOR))
|
||||
continue;
|
||||
|
||||
// render active window after all others of this pass
|
||||
if (w.get() == g_pCompositor->m_pLastWindow) {
|
||||
lastWindow = w.get();
|
||||
continue;
|
||||
}
|
||||
|
||||
// render the bad boy
|
||||
renderWindow(w.get(), PMONITOR, time, true, RENDER_PASS_MAIN);
|
||||
}
|
||||
|
||||
if (lastWindow)
|
||||
renderWindow(lastWindow, PMONITOR, time, true, RENDER_PASS_MAIN);
|
||||
|
||||
// Non-floating popup
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->isHidden() && !w->m_bIsMapped && !w->m_bFadingOut)
|
||||
@@ -434,7 +441,7 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
|
||||
if (w->m_bIsFloating)
|
||||
continue; // floating are in the second pass
|
||||
|
||||
if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
|
||||
if (g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID))
|
||||
continue; // special are in the third pass
|
||||
|
||||
if (!shouldRenderWindow(w.get(), PMONITOR))
|
||||
@@ -452,7 +459,7 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
|
||||
if (!w->m_bIsFloating)
|
||||
continue;
|
||||
|
||||
if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
|
||||
if (g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID))
|
||||
continue;
|
||||
|
||||
if (!shouldRenderWindow(w.get(), PMONITOR))
|
||||
@@ -467,7 +474,7 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
|
||||
if (w->isHidden() && !w->m_bIsMapped && !w->m_bFadingOut)
|
||||
continue;
|
||||
|
||||
if (w->m_iWorkspaceID != SPECIAL_WORKSPACE_ID)
|
||||
if (!g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID))
|
||||
continue;
|
||||
|
||||
if (!shouldRenderWindow(w.get(), PMONITOR))
|
||||
@@ -570,7 +577,7 @@ bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) {
|
||||
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pMonitor->activeWorkspace);
|
||||
|
||||
if (!PWORKSPACE || !PWORKSPACE->m_bHasFullscreenWindow || g_pInputManager->m_sDrag.drag || g_pCompositor->m_sSeat.exclusiveClient)
|
||||
if (!PWORKSPACE || !PWORKSPACE->m_bHasFullscreenWindow || g_pInputManager->m_sDrag.drag || g_pCompositor->m_sSeat.exclusiveClient || pMonitor->specialWorkspaceID)
|
||||
return false;
|
||||
|
||||
const auto PCANDIDATE = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
|
||||
@@ -1143,6 +1150,9 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
wlr_output_set_scale(pMonitor->output, pMonitorRule->scale);
|
||||
pMonitor->scale = pMonitorRule->scale;
|
||||
|
||||
wlr_output_set_transform(pMonitor->output, pMonitorRule->transform);
|
||||
pMonitor->transform = pMonitorRule->transform;
|
||||
|
||||
// loop over modes and choose an appropriate one.
|
||||
if (pMonitorRule->resolution != Vector2D() && pMonitorRule->resolution != Vector2D(-1,-1) && pMonitorRule->resolution != Vector2D(-1,-2)) {
|
||||
if (!wl_list_empty(&pMonitor->output->modes)) {
|
||||
@@ -1339,9 +1349,6 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
|
||||
pMonitor->vrrActive = pMonitor->output->pending.adaptive_sync_enabled; // disabled here, will be tested in CConfigManager::ensureVRR()
|
||||
|
||||
wlr_output_set_transform(pMonitor->output, pMonitorRule->transform);
|
||||
pMonitor->transform = pMonitorRule->transform;
|
||||
|
||||
pMonitor->vecPixelSize = pMonitor->vecSize;
|
||||
|
||||
if (pMonitorRule->enable10bit) {
|
||||
@@ -1371,7 +1378,6 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
|
||||
if (!wlr_output_commit(pMonitor->output)) {
|
||||
Debug::log(ERR, "Couldn't commit output named %s", pMonitor->output->name);
|
||||
return true;
|
||||
}
|
||||
|
||||
int x, y;
|
||||
@@ -1404,14 +1410,11 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
pMonitor->vecPosition = pMonitorRule->offset;
|
||||
}
|
||||
|
||||
wlr_output_enable(pMonitor->output, true);
|
||||
|
||||
// update renderer (here because it will call rollback, so we cannot do this before committing)
|
||||
g_pHyprOpenGL->destroyMonitorResources(pMonitor);
|
||||
|
||||
// updato wlroots
|
||||
wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, pMonitor->output, (int)pMonitor->vecPosition.x, (int)pMonitor->vecPosition.y);
|
||||
Events::listener_change(nullptr, nullptr);
|
||||
|
||||
// updato us
|
||||
arrangeLayersForMonitor(pMonitor->ID);
|
||||
|
@@ -23,6 +23,8 @@ enum eRenderPassMode {
|
||||
RENDER_PASS_POPUP
|
||||
};
|
||||
|
||||
class CToplevelExportProtocolManager;
|
||||
|
||||
class CHyprRenderer {
|
||||
public:
|
||||
|
||||
@@ -44,6 +46,7 @@ public:
|
||||
void calculateUVForWindowSurface(CWindow*, wlr_surface*, bool main = false);
|
||||
|
||||
bool m_bWindowRequestedCursorHide = false;
|
||||
bool m_bBlockSurfaceFeedback = false;
|
||||
CWindow* m_pLastScanout = nullptr;
|
||||
|
||||
DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&);
|
||||
@@ -54,7 +57,7 @@ public:
|
||||
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, bool ignorePosition = false);
|
||||
void renderWindow(CWindow*, CMonitor*, timespec*, bool, eRenderPassMode, bool ignorePosition = false, bool ignoreAllGeometry = false);
|
||||
void renderLayer(SLayerSurface*, CMonitor*, timespec*);
|
||||
void renderDragIcon(CMonitor*, timespec*);
|
||||
void renderIMEPopup(SIMEPopup*, CMonitor*, timespec*);
|
||||
@@ -63,6 +66,7 @@ private:
|
||||
|
||||
|
||||
friend class CHyprOpenGLImpl;
|
||||
friend class CToplevelExportProtocolManager;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CHyprRenderer> g_pHyprRenderer;
|
||||
|
@@ -14,5 +14,11 @@ GLint CShader::getUniformLocation(const std::string& unif) {
|
||||
|
||||
CShader::~CShader() {
|
||||
// destroy shader
|
||||
destroy();
|
||||
}
|
||||
|
||||
void CShader::destroy() {
|
||||
glDeleteProgram(program);
|
||||
|
||||
program = 0;
|
||||
}
|
@@ -19,6 +19,7 @@ public:
|
||||
GLint topLeft;
|
||||
GLint bottomRight;
|
||||
GLint fullSize;
|
||||
GLint fullSizeUntransformed;
|
||||
GLint radius;
|
||||
GLint primitiveMultisample;
|
||||
|
||||
@@ -32,8 +33,14 @@ public:
|
||||
GLint applyTint;
|
||||
GLint tint;
|
||||
|
||||
GLint gradient;
|
||||
GLint gradientLength;
|
||||
GLint angle;
|
||||
|
||||
GLint getUniformLocation(const std::string&);
|
||||
|
||||
void destroy();
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, GLint> m_muUniforms;
|
||||
};
|
@@ -9,82 +9,111 @@ varying vec4 v_color;
|
||||
varying vec2 v_texcoord;
|
||||
|
||||
uniform vec2 topLeft;
|
||||
uniform vec2 bottomRight;
|
||||
uniform vec2 fullSize;
|
||||
uniform vec2 fullSizeUntransformed;
|
||||
uniform float radius;
|
||||
uniform float thick;
|
||||
uniform int primitiveMultisample;
|
||||
|
||||
float getOpacityForPixAndCorner(vec2 pix, vec2 corner) {
|
||||
uniform vec4 gradient[10];
|
||||
uniform int gradientLength;
|
||||
uniform float angle;
|
||||
uniform float alpha;
|
||||
|
||||
if (primitiveMultisample == 0) {
|
||||
float dis = distance(pix + vec2(0.5, 0.5), corner);
|
||||
return dis < radius && dis > radius - thick ? 1.0 : 0.0;
|
||||
vec4 getColorForCoord(vec2 normalizedCoord) {
|
||||
if (gradientLength < 2)
|
||||
return gradient[0];
|
||||
|
||||
float finalAng = 0.0;
|
||||
|
||||
if (angle > 4.71 /* 270 deg */) {
|
||||
normalizedCoord[1] = 1.0 - normalizedCoord[1];
|
||||
finalAng = 6.28 - angle;
|
||||
} else if (angle > 3.14 /* 180 deg */) {
|
||||
normalizedCoord[0] = 1.0 - normalizedCoord[0];
|
||||
normalizedCoord[1] = 1.0 - normalizedCoord[1];
|
||||
finalAng = angle - 3.14;
|
||||
} else if (angle > 1.57 /* 90 deg */) {
|
||||
normalizedCoord[0] = 1.0 - normalizedCoord[0];
|
||||
finalAng = 3.14 - angle;
|
||||
} else {
|
||||
finalAng = angle;
|
||||
}
|
||||
|
||||
float distance1 = distance(pix + vec2(0.25, 0.25), corner);
|
||||
float distance2 = distance(pix + vec2(0.75, 0.25), corner);
|
||||
float distance3 = distance(pix + vec2(0.25, 0.75), corner);
|
||||
float distance4 = distance(pix + vec2(0.75, 0.75), corner);
|
||||
float sine = sin(finalAng);
|
||||
|
||||
float v1 = distance1 < radius && distance1 > radius - thick ? 1.0 : 0.0;
|
||||
float v2 = distance2 < radius && distance2 > radius - thick ? 1.0 : 0.0;
|
||||
float v3 = distance3 < radius && distance3 > radius - thick ? 1.0 : 0.0;
|
||||
float v4 = distance4 < radius && distance4 > radius - thick ? 1.0 : 0.0;
|
||||
float progress = (normalizedCoord[1] * sine + normalizedCoord[0] * (1.0 - sine)) * float(gradientLength - 1);
|
||||
int bottom = int(floor(progress));
|
||||
int top = bottom + 1;
|
||||
|
||||
return (v1 + v2 + v3 + v4) / 4.0;
|
||||
return gradient[top] * (progress - float(bottom)) + gradient[bottom] * (float(top) - progress);
|
||||
}
|
||||
|
||||
void main() {
|
||||
|
||||
vec2 pixCoord = fullSize * v_texcoord;
|
||||
highp vec2 pixCoord = vec2(gl_FragCoord);
|
||||
highp vec2 originalPixCoord = v_texcoord;
|
||||
originalPixCoord *= fullSizeUntransformed;
|
||||
|
||||
vec4 pixColor = v_color;
|
||||
vec4 pixColor = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
|
||||
bool done = false;
|
||||
|
||||
// check for edges
|
||||
if (pixCoord[0] < topLeft[0]) {
|
||||
if (pixCoord[1] < topLeft[1]) {
|
||||
// top left
|
||||
pixColor[3] = pixColor[3] * getOpacityForPixAndCorner(pixCoord, topLeft + vec2(1,1));
|
||||
done = true;
|
||||
} else if (pixCoord[1] > bottomRight[1]) {
|
||||
// bottom left
|
||||
pixColor[3] = pixColor[3] * getOpacityForPixAndCorner(pixCoord, vec2(topLeft[0] + 1.0, bottomRight[1]));
|
||||
done = true;
|
||||
}
|
||||
} else if (pixCoord[0] > bottomRight[0]) {
|
||||
if (pixCoord[1] < topLeft[1]) {
|
||||
// top right
|
||||
pixColor[3] = pixColor[3] * getOpacityForPixAndCorner(pixCoord, vec2(bottomRight[0], topLeft[1] + 1.0));
|
||||
done = true;
|
||||
} else if (pixCoord[1] > bottomRight[1]) {
|
||||
// bottom right
|
||||
pixColor[3] = pixColor[3] * getOpacityForPixAndCorner(pixCoord, bottomRight);
|
||||
done = true;
|
||||
}
|
||||
pixCoord -= topLeft + fullSize * 0.5;
|
||||
pixCoord *= vec2(lessThan(pixCoord, vec2(0.0))) * -2.0 + 1.0;
|
||||
pixCoord -= fullSize * 0.5 - radius;
|
||||
|
||||
if (min(pixCoord.x, pixCoord.y) > 0.0 && radius > 0.0) {
|
||||
|
||||
float dist = length(pixCoord);
|
||||
|
||||
if (dist > radius + 1.0 || dist < radius - thick - 1.0)
|
||||
discard;
|
||||
|
||||
if (primitiveMultisample == 1 && (dist > radius - 1.0 || dist < radius - thick + 1.0)) {
|
||||
float distances = 0.0;
|
||||
float len = length(pixCoord + vec2(0.25, 0.25));
|
||||
distances += float(len < radius && len > radius - thick);
|
||||
len = length(pixCoord + vec2(0.75, 0.25));
|
||||
distances += float(len < radius && len > radius - thick);
|
||||
len = length(pixCoord + vec2(0.25, 0.75));
|
||||
distances += float(len < radius && len > radius - thick);
|
||||
len = length(pixCoord + vec2(0.75, 0.75));
|
||||
distances += float(len < radius && len > radius - thick);
|
||||
|
||||
if (distances == 0.0)
|
||||
discard;
|
||||
|
||||
distances /= 4.0;
|
||||
|
||||
pixColor[3] *= distances;
|
||||
} else if (dist > radius || dist < radius - thick)
|
||||
discard;
|
||||
|
||||
done = true;
|
||||
}
|
||||
|
||||
// now check for other shit
|
||||
if (!done) {
|
||||
// distance to all straight bb borders
|
||||
float distanceT = pixCoord[1];
|
||||
float distanceB = fullSize[1] - pixCoord[1];
|
||||
float distanceL = pixCoord[0];
|
||||
float distanceR = fullSize[0] - pixCoord[0];
|
||||
float distanceT = originalPixCoord[1];
|
||||
float distanceB = fullSizeUntransformed[1] - originalPixCoord[1];
|
||||
float distanceL = originalPixCoord[0];
|
||||
float distanceR = fullSizeUntransformed[0] - originalPixCoord[0];
|
||||
|
||||
// get the smallest
|
||||
float smallest = min(min(distanceT, distanceB), min(distanceL, distanceR));
|
||||
|
||||
if (smallest > thick) {
|
||||
discard; return;
|
||||
}
|
||||
if (smallest > thick)
|
||||
discard;
|
||||
}
|
||||
|
||||
if (pixColor[3] == 0.0) {
|
||||
discard; return;
|
||||
}
|
||||
if (pixColor[3] == 0.0)
|
||||
discard;
|
||||
|
||||
float pixColor3 = pixColor[3];
|
||||
pixColor = getColorForCoord(v_texcoord);
|
||||
pixColor[3] *= alpha * pixColor3;
|
||||
|
||||
gl_FragColor = pixColor;
|
||||
}
|
||||
|
@@ -13,24 +13,24 @@ inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVar
|
||||
|
||||
if (pixCoord.x + pixCoord.y > radius) {
|
||||
|
||||
float dist = length(pixCoord);
|
||||
float dist = length(pixCoord);
|
||||
|
||||
if (dist > radius)
|
||||
discard;
|
||||
if (dist > radius)
|
||||
discard;
|
||||
|
||||
if (primitiveMultisample == 1 && dist > radius - 1.0) {
|
||||
float distances = 0.0;
|
||||
distances += float(length(pixCoord + vec2(0.25, 0.25)) < radius);
|
||||
distances += float(length(pixCoord + vec2(0.75, 0.25)) < radius);
|
||||
distances += float(length(pixCoord + vec2(0.25, 0.75)) < radius);
|
||||
distances += float(length(pixCoord + vec2(0.75, 0.75)) < radius);
|
||||
if (primitiveMultisample == 1 && dist > radius - 1.0) {
|
||||
float distances = 0.0;
|
||||
distances += float(length(pixCoord + vec2(0.25, 0.25)) < radius);
|
||||
distances += float(length(pixCoord + vec2(0.75, 0.25)) < radius);
|
||||
distances += float(length(pixCoord + vec2(0.25, 0.75)) < radius);
|
||||
distances += float(length(pixCoord + vec2(0.75, 0.75)) < radius);
|
||||
|
||||
if (distances == 0.0)
|
||||
discard;
|
||||
if (distances == 0.0)
|
||||
discard;
|
||||
|
||||
distances /= 4.0;
|
||||
distances /= 4.0;
|
||||
|
||||
)#" + colorVarName + R"#( = )#" + colorVarName + R"#( * distances;
|
||||
)#" + colorVarName + R"#( = )#" + colorVarName + R"#( * distances;
|
||||
}
|
||||
|
||||
}
|
||||
|
1
subprojects/hyprland-protocols
Submodule
1
subprojects/hyprland-protocols
Submodule
Submodule subprojects/hyprland-protocols added at 0dcff94fc1
Submodule subprojects/wlroots updated: 627a5c5112...86fc2199f8
Reference in New Issue
Block a user