mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-08-15 03:55:46 -07:00
Compare commits
379 Commits
v0.10.3bet
...
v0.15.1bet
Author | SHA1 | Date | |
---|---|---|---|
|
28a6e0ce31 | ||
|
af7d60b3f8 | ||
|
c4487534d2 | ||
|
e4820d1c71 | ||
|
b4a8efc1a7 | ||
|
9480c0fb90 | ||
|
f901c60da5 | ||
|
922e978f56 | ||
|
0508c7d384 | ||
|
ee3b770cfd | ||
|
a29af89545 | ||
|
552c4b7361 | ||
|
d7ef19e2e7 | ||
|
190ddb5697 | ||
|
095688712d | ||
|
d264fbd36a | ||
|
e4527c6b60 | ||
|
32e8eda40a | ||
|
477ad2dd82 | ||
|
e90c5c6347 | ||
|
11ce468996 | ||
|
9c5023ab1a | ||
|
0e4a894edb | ||
|
71e2562a41 | ||
|
9153a81090 | ||
|
0d7f6eac9e | ||
|
6d46ed4011 | ||
|
f825b87c2a | ||
|
44da575ea8 | ||
|
a587909fd5 | ||
|
fd81ba5a4f | ||
|
934f81c93d | ||
|
e8be1507ef | ||
|
60c414ccad | ||
|
0d702b556d | ||
|
9bbae5b8e2 | ||
|
719a5b4f0b | ||
|
7bdfdaa28a | ||
|
a80e0cecfe | ||
|
3e3f6aef5e | ||
|
996938b7e7 | ||
|
f9325b1655 | ||
|
63dfe305dd | ||
|
ec0c6fa22a | ||
|
ff5843bd85 | ||
|
3bb5971c2e | ||
|
a1d9404f9f | ||
|
ab82c4806d | ||
|
49ab3890aa | ||
|
85eea70be4 | ||
|
174b593438 | ||
|
0a08830375 | ||
|
a97621b1cb | ||
|
355366714e | ||
|
590fbf808b | ||
|
bbeed21e62 | ||
|
c6333ba796 | ||
|
6fe103cf06 | ||
|
71733f68ef | ||
|
e6c9e3f81d | ||
|
7579e03b64 | ||
|
1ef23a304a | ||
|
3c27d1ab13 | ||
|
59a3c43913 | ||
|
d867d42366 | ||
|
6eb7d00386 | ||
|
2d73da1a79 | ||
|
45fe185cb9 | ||
|
09268d756f | ||
|
e5dced8b3f | ||
|
b38e7b596f | ||
|
da40bf823f | ||
|
caeb0636fa | ||
|
1424539e4d | ||
|
bdd9680adf | ||
|
ff4c22ca90 | ||
|
9f9129e536 | ||
|
ab42e4bccf | ||
|
425b07d1e5 | ||
|
2636abca2d | ||
|
ead0e74471 | ||
|
dcf5e34bfa | ||
|
65fb526d5c | ||
|
10c4f4ba35 | ||
|
a1319e5110 | ||
|
5233746ac5 | ||
|
0549aa193f | ||
|
168a326609 | ||
|
31cb4c49d9 | ||
|
11ee78f88b | ||
|
7edbaea23d | ||
|
ec5ffe8839 | ||
|
e3b1d3c3c5 | ||
|
458ba3237b | ||
|
5ff44467d7 | ||
|
7a775c0584 | ||
|
87afc8c250 | ||
|
cd2b2c4fba | ||
|
c48336aac3 | ||
|
f70b57f360 | ||
|
bf3f519eb7 | ||
|
190229942f | ||
|
e476382d08 | ||
|
c885afcbc6 | ||
|
fad5fc587d | ||
|
73dbacd16d | ||
|
65fb0cf0f6 | ||
|
5101ddeff1 | ||
|
959557ecc3 | ||
|
bccc81d306 | ||
|
718de0d9fa | ||
|
fd6116c0cd | ||
|
00b16888bf | ||
|
abee2da5bd | ||
|
695411f1bd | ||
|
f9d8b3096a | ||
|
e5d143b238 | ||
|
37f2e1ddbe | ||
|
ef3eb37c7f | ||
|
db551b8970 | ||
|
c08218301b | ||
|
75aaf11a9c | ||
|
c4e782ca5d | ||
|
da2c2ddc21 | ||
|
5272588270 | ||
|
215125bd66 | ||
|
30d16373d0 | ||
|
c1feb683ce | ||
|
d3ffccd45f | ||
|
d49af1cc18 | ||
|
8b46d0b5a9 | ||
|
336883dda3 | ||
|
65ec8c7694 | ||
|
79c645f8cd | ||
|
d44cc9f112 | ||
|
1963da2d47 | ||
|
2b99dbb446 | ||
|
d24f31de51 | ||
|
d51c7ca135 | ||
|
8b11a2e1b1 | ||
|
b4bcba935d | ||
|
7f3750bd75 | ||
|
7a9423c782 | ||
|
6f98b3cbd8 | ||
|
2dd1661aec | ||
|
cde624ec6a | ||
|
b82621c4ec | ||
|
5b6c8d5b0f | ||
|
4dca2b945b | ||
|
a8943246a7 | ||
|
e42de0b778 | ||
|
5146165599 | ||
|
73e19aee6f | ||
|
3780361b95 | ||
|
ec6144e5da | ||
|
b6eaeffcf6 | ||
|
c24b45671a | ||
|
85c7aaf155 | ||
|
696253b348 | ||
|
abb6db9c37 | ||
|
18b483b8e1 | ||
|
7c809a3059 | ||
|
4070e1a148 | ||
|
dd61f88ed1 | ||
|
29626989e7 | ||
|
cf32d28082 | ||
|
5131a4acaf | ||
|
a72a39ebd5 | ||
|
151e013241 | ||
|
fa2d81b649 | ||
|
037d4ed422 | ||
|
9f82278d65 | ||
|
8e0f7b9b11 | ||
|
a96acc8fa4 | ||
|
5a146e9d90 | ||
|
da10022d84 | ||
|
e518adf1ac | ||
|
d8dbe26f31 | ||
|
e9f226797e | ||
|
7d4f0a3199 | ||
|
0062281092 | ||
|
81f267dff9 | ||
|
a09c614c2d | ||
|
b49d7007b5 | ||
|
864e227f5d | ||
|
82aa78916d | ||
|
f024d7114f | ||
|
8808d40008 | ||
|
d94fe3d063 | ||
|
f663fa209c | ||
|
9370c7aa8a | ||
|
928158bbfb | ||
|
bacfae3084 | ||
|
0d95a0174c | ||
|
0eb5ecafb9 | ||
|
49a55f136e | ||
|
64be57b780 | ||
|
6e195a6b8c | ||
|
8d3f6c5d84 | ||
|
5c470d2e54 | ||
|
26910a8b63 | ||
|
44a2d755c6 | ||
|
cf5426f2d8 | ||
|
1d631c8a23 | ||
|
789eedd115 | ||
|
4a8274e5f0 | ||
|
4b7d28d2cb | ||
|
5fdd1dd60f | ||
|
e71a4d75de | ||
|
f002bd1603 | ||
|
16f1d1b99b | ||
|
c1bc8d46e9 | ||
|
94ca386a8c | ||
|
2ba7cb2414 | ||
|
5b5f36f494 | ||
|
a74b8033ca | ||
|
41883e0522 | ||
|
3ea89e6171 | ||
|
d6c06318af | ||
|
cb839c9dcc | ||
|
3dd514a452 | ||
|
6afab12b91 | ||
|
7a3b57c99c | ||
|
ba0c5fe0bb | ||
|
f6ecef0959 | ||
|
ff26531e11 | ||
|
fbd2b4799d | ||
|
1664f81cae | ||
|
c425e620af | ||
|
f4add0ac6d | ||
|
3c3f80c2fe | ||
|
eee0cad4d0 | ||
|
0ea96e87c0 | ||
|
5d09bb647b | ||
|
f5697095bc | ||
|
56203b1757 | ||
|
c0a7dffcdc | ||
|
8581e71789 | ||
|
bb90ff0461 | ||
|
1d4d2f4793 | ||
|
7f62cbc48a | ||
|
f2d84a7e3a | ||
|
095185cfe7 | ||
|
f77fac9df9 | ||
|
dacaf72e02 | ||
|
0ad261aa9c | ||
|
7610c20761 | ||
|
4103bca056 | ||
|
21a1b62b6a | ||
|
7f483dfdb0 | ||
|
1cf46fd6a2 | ||
|
eb658dcb61 | ||
|
195ec2b092 | ||
|
dd6aba07e9 | ||
|
d35d949bc5 | ||
|
48eb2e0d6f | ||
|
179562b646 | ||
|
20c050e890 | ||
|
bdd20c401d | ||
|
6865660e51 | ||
|
6c8ce734fb | ||
|
09495375b5 | ||
|
3c20ecb04d | ||
|
5da114477f | ||
|
c757fa54e1 | ||
|
16f8d46391 | ||
|
5726f394b1 | ||
|
f5f99c6700 | ||
|
cfa6c01df0 | ||
|
d413388761 | ||
|
4203a61b69 | ||
|
80b3a436d2 | ||
|
5d9d55a245 | ||
|
52c0ba544c | ||
|
8b5c64c8fd | ||
|
2ea5f50f40 | ||
|
1d97ad9856 | ||
|
1d43bb70d4 | ||
|
573cb0d4e0 | ||
|
59d7cfcd02 | ||
|
ed2cacc5d5 | ||
|
df4c1c02a6 | ||
|
8122505825 | ||
|
0964448f93 | ||
|
5d63152219 | ||
|
aaa834d0c3 | ||
|
28966d85ae | ||
|
a648b452dd | ||
|
d53b0a6491 | ||
|
80d522cb26 | ||
|
dbd774fedb | ||
|
bf00bf7963 | ||
|
949655005a | ||
|
56caba5f01 | ||
|
b09f157b93 | ||
|
10f529ada7 | ||
|
f7c741317f | ||
|
b16a57ceeb | ||
|
0eb86f4b0d | ||
|
7b01c3d028 | ||
|
89018bfa95 | ||
|
0d1a9e4ba9 | ||
|
e327b0a835 | ||
|
de477a6ff5 | ||
|
e92469121d | ||
|
a9761cb1c8 | ||
|
6c2175ed52 | ||
|
00ef40dda1 | ||
|
9c3aeda9f9 | ||
|
a4f7bd4bc2 | ||
|
3fd903ee74 | ||
|
83ef951c21 | ||
|
8bbb790d87 | ||
|
ffaf14c19e | ||
|
9366c187dc | ||
|
29696d046e | ||
|
09f3999b1e | ||
|
fba7ed97fb | ||
|
fd70a9184b | ||
|
0a9ac47030 | ||
|
e2450247c0 | ||
|
973540bbc5 | ||
|
f9b2aa5468 | ||
|
451659ec34 | ||
|
a9e34cba93 | ||
|
48c9e9d83d | ||
|
23c5760538 | ||
|
9bfa3ebc50 | ||
|
8feb6f7da1 | ||
|
fb0e81c18e | ||
|
359df96d53 | ||
|
63493b5736 | ||
|
6565c31dbf | ||
|
575bfa40e5 | ||
|
429b2bffed | ||
|
c83948ea9a | ||
|
8a6e29974b | ||
|
4c6d9b7d5a | ||
|
9f5e099cd1 | ||
|
8b39a1cf9b | ||
|
e9551731f0 | ||
|
39a9980fb1 | ||
|
d0ec2b72ae | ||
|
e97fa4e26b | ||
|
52318692f0 | ||
|
86be6c3884 | ||
|
21bea0fcb4 | ||
|
83f7fee3f5 | ||
|
f273ebed9c | ||
|
3cb30e7fb0 | ||
|
3e9a8a7bc8 | ||
|
7ca50d7566 | ||
|
ebe07c6656 | ||
|
ce62a98470 | ||
|
8faac0c9ac | ||
|
fea6d7deb0 | ||
|
463bc7ab13 | ||
|
c4ba11729f | ||
|
5569e1f69c | ||
|
da725d7aa5 | ||
|
f7f3446882 | ||
|
0f63077a07 | ||
|
0f25f3aee3 | ||
|
5e1f2539cb | ||
|
9dbdd66da4 | ||
|
6ec932d11f | ||
|
3c8c605541 | ||
|
9ee42836d5 | ||
|
d6ff7e40cf | ||
|
04f0efadc3 | ||
|
12cdca7422 | ||
|
7ce2c91673 | ||
|
aaba11b7a2 | ||
|
9513031da3 | ||
|
08e874bcf9 | ||
|
776750ee34 | ||
|
37e1450a4d | ||
|
4af95d4253 | ||
|
844c33c980 |
28
.github/workflows/man-update.yaml
vendored
Normal file
28
.github/workflows/man-update.yaml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
name: Build man pages
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- docs/**
|
||||
branches:
|
||||
- 'main'
|
||||
|
||||
jobs:
|
||||
main:
|
||||
name: Build man pages
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install deps
|
||||
run: sudo apt install pandoc
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@v3
|
||||
# Not needed
|
||||
# with:
|
||||
# submodules: recursive
|
||||
- name: Build man pages
|
||||
run: make man
|
||||
- uses: stefanzweifel/git-auto-commit-action@v4
|
||||
name: Commit
|
||||
with:
|
||||
commit_message: "[gha] build man pages"
|
7
.github/workflows/nix-build.yaml
vendored
7
.github/workflows/nix-build.yaml
vendored
@@ -5,6 +5,11 @@ jobs:
|
||||
nix:
|
||||
name: "Build Hyprland (Nix)"
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
package:
|
||||
- default
|
||||
- hyprland-no-hidpi
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@v3
|
||||
@@ -22,4 +27,4 @@ jobs:
|
||||
name: hyprland
|
||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||
- name: Build Hyprland with default settings
|
||||
run: nix build --print-build-logs
|
||||
run: nix build .#${{ matrix.package }} --print-build-logs
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -10,7 +10,7 @@ CTestTestfile.cmake
|
||||
_deps
|
||||
|
||||
build/
|
||||
result
|
||||
result*
|
||||
/.vscode/
|
||||
.envrc
|
||||
.cache
|
||||
|
31
Makefile
31
Makefile
@@ -126,8 +126,8 @@ install:
|
||||
make release
|
||||
cd hyprctl && make all && cd ..
|
||||
|
||||
mkdir -p ${PREFIX}/share/wayland-sessions
|
||||
cp ./example/hyprland.desktop ${PREFIX}/share/wayland-sessions/
|
||||
mkdir -p /usr/share/wayland-sessions
|
||||
cp ./example/hyprland.desktop /usr/share/wayland-sessions/
|
||||
mkdir -p ${PREFIX}/bin
|
||||
cp ./build/Hyprland ${PREFIX}/bin
|
||||
cp ./hyprctl/hyprctl ${PREFIX}/bin
|
||||
@@ -136,12 +136,35 @@ install:
|
||||
cp ./assets/wall_4K.png ${PREFIX}/share/hyprland
|
||||
cp ./assets/wall_8K.png ${PREFIX}/share/hyprland
|
||||
|
||||
install -Dm644 -t ${PREFIX}/share/man/man1 ./docs/*.1
|
||||
|
||||
cleaninstall:
|
||||
make clear
|
||||
make fixwlr
|
||||
cd ./subprojects/wlroots && meson build/ --buildtype=release && ninja -C build/ && cp ./build/libwlroots.so.11032 /usr/lib/ && cd ../..
|
||||
make protocols
|
||||
make release
|
||||
cd hyprctl && make all && cd ..
|
||||
|
||||
mkdir -p /usr/share/wayland-sessions
|
||||
mkdir -p ${PREFIX}/bin
|
||||
cp ./build/Hyprland ${PREFIX}/bin
|
||||
cp ./hyprctl/hyprctl ${PREFIX}/bin
|
||||
mkdir -p ${PREFIX}/share/hyprland
|
||||
cp ./assets/wall_2K.png ${PREFIX}/share/hyprland
|
||||
cp ./assets/wall_4K.png ${PREFIX}/share/hyprland
|
||||
cp ./assets/wall_8K.png ${PREFIX}/share/hyprland
|
||||
|
||||
install -Dm644 -t ${PREFIX}/share/man/man1 ./docs/*.1
|
||||
|
||||
uninstall:
|
||||
rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop
|
||||
rm -f ${PREFIX}/bin/Hyprland
|
||||
rm -f ${PREFIX}/bin/hyprctl
|
||||
rm -f /usr/lib/libwlroots.so.11032
|
||||
rm -rf ${PREFIX}/share/hyprland
|
||||
rm -f ${PREFIX}/share/man/man1/Hyprland.1
|
||||
rm -f ${PREFIX}/share/man/man1/hyprctl.1
|
||||
|
||||
protocols: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o wlr-screencopy-unstable-v1-protocol.o idle-protocol.o ext-workspace-unstable-v1-protocol.o pointer-constraints-unstable-v1-protocol.o tablet-unstable-v2-protocol.o wlr-output-power-management-unstable-v1-protocol.o
|
||||
|
||||
@@ -167,7 +190,7 @@ man:
|
||||
--variable=date:"${DATE}" \
|
||||
--variable=section:1 \
|
||||
--from rst \
|
||||
--to man | gzip -c > /usr/share/man/man1/Hyprland.1.gz
|
||||
--to man > ./docs/Hyprland.1
|
||||
|
||||
pandoc ./docs/hyprctl.1.rst \
|
||||
--standalone \
|
||||
@@ -175,4 +198,4 @@ man:
|
||||
--variable=date:"${DATE}" \
|
||||
--variable=section:1 \
|
||||
--from rst \
|
||||
--to man | gzip -c > /usr/share/man/man1/hyprctl.1.gz
|
||||
--to man > ./docs/hyprctl.1
|
||||
|
@@ -150,9 +150,9 @@ Try it out and report bugs / suggestions!
|
||||
<!----------------------------------{ Images }--------------------------------->
|
||||
|
||||
[Stars Preview]: https://starchart.cc/vaxerski/Hyprland.svg
|
||||
[Preview A]: https://i.imgur.com/sCafdKQ.png
|
||||
[Preview A]: https://i.imgur.com/pC6YF1Y.png
|
||||
[Preview B]: https://i.imgur.com/NbrTnZH.png
|
||||
[Preview C]: https://i.imgur.com/ZA4Fa8R.png
|
||||
[Preview C]: https://i.imgur.com/sCafdKQ.png
|
||||
|
||||
|
||||
<!----------------------------------{ Badges }--------------------------------->
|
||||
|
46
docs/Hyprland.1
Normal file
46
docs/Hyprland.1
Normal file
@@ -0,0 +1,46 @@
|
||||
.\" Automatically generated by Pandoc 2.5
|
||||
.\"
|
||||
.TH "Hyprland" "1" "24 Aug 2022" "" "Hyprland User Manual"
|
||||
.hy
|
||||
.SH NAME
|
||||
.PP
|
||||
Hyprland \- Dynamic tiling Wayland compositor
|
||||
.SH SYNOPSIS
|
||||
.PP
|
||||
\f[B]Hyprland\f[R] [\f[I]arg [...]\f[R]].
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
\f[B]Hyprland\f[R] is a dynamic tiling Wayland compositor based on
|
||||
wlroots that doesn\[aq]t sacrifice on its looks.
|
||||
.PP
|
||||
You can launch Hyprland by either going into a TTY and executing
|
||||
\f[B]Hyprland\f[R], or with a login manager.
|
||||
.SH NOTICE
|
||||
.PP
|
||||
Hyprland is still in pretty early development compared to some other
|
||||
Wayland compositors.
|
||||
.PP
|
||||
Although Hyprland is pretty stable, it may have some bugs.
|
||||
.SH CONFIGURATION
|
||||
.PP
|
||||
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]
|
||||
Show command usage.
|
||||
.TP
|
||||
.B \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:
|
||||
<\f[I]https://github.com/hyprwm/Hyprland/issues\f[R]>
|
||||
.SH SEE ALSO
|
||||
.PP
|
||||
Sources at: <\f[I]https://github.com/hyprwm/Hyprland\f[R]>
|
||||
.SH COPYRIGHT
|
||||
.PP
|
||||
Copyright (c) 2022, vaxerski
|
||||
.SH AUTHORS
|
||||
Vaxerski <\f[I]https://github.com/vaxerski\f[R]>.
|
145
docs/hyprctl.1
Normal file
145
docs/hyprctl.1
Normal file
@@ -0,0 +1,145 @@
|
||||
.\" Automatically generated by Pandoc 2.5
|
||||
.\"
|
||||
.TH "hyprctl" "1" "24 Aug 2022" "" "hyprctl User Manual"
|
||||
.hy
|
||||
.SH NAME
|
||||
.PP
|
||||
hyprctl \- Utility for controlling parts of Hyprland from a CLI or a
|
||||
script
|
||||
.SH SYNOPSIS
|
||||
.PP
|
||||
\f[B]hyprctl\f[R] [\f[I](opt)flags\f[R]] [\f[B]command\f[R]]
|
||||
[\f[I](opt)args\f[R]]
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
\f[B]hyprctl\f[R] is a utility for controlling some parts of the
|
||||
compositor from a CLI or a script.
|
||||
.SH CONTROL COMMANDS
|
||||
.PP
|
||||
\f[B]dispatch\f[R]
|
||||
.RS
|
||||
.PP
|
||||
Call a dispatcher with an argument.
|
||||
.PP
|
||||
An argument must be present.
|
||||
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:
|
||||
\f[B]hyprctl\f[R] \f[I]dispatch exec kitty\f[R]
|
||||
.RS
|
||||
.PP
|
||||
\f[B]hyprctl\f[R] \f[I]dispatch pseudo x\f[R]
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\f[B]keyword\f[R]
|
||||
.RS
|
||||
.PP
|
||||
Set a config keyword dynamically.
|
||||
.PP
|
||||
Returns: \f[I]ok\f[R] on success, and an error message on failure.
|
||||
.TP
|
||||
.B Examples:
|
||||
\f[B]hyprctl\f[R] \f[I]keyword bind SUPER,0,pseudo\f[R]
|
||||
.RS
|
||||
.PP
|
||||
\f[B]hyprctl\f[R] \f[I]keyword general:border_size 10\f[R]
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\f[B]reload\f[R]
|
||||
.RS
|
||||
.PP
|
||||
Force a reload of the config file.
|
||||
.RE
|
||||
.PP
|
||||
\f[B]kill\f[R]
|
||||
.RS
|
||||
.PP
|
||||
Enter kill mode, where you can kill an app by clicking on it.
|
||||
You can exit by pressing ESCAPE.
|
||||
.RE
|
||||
.SH INFO COMMANDS
|
||||
.PP
|
||||
\f[B]version\f[R]
|
||||
.RS
|
||||
.PP
|
||||
Prints the Hyprland version, flags, commit and branch of build.
|
||||
.RE
|
||||
.PP
|
||||
\f[B]monitors\f[R]
|
||||
.RS
|
||||
.PP
|
||||
Lists all the outputs with their properties.
|
||||
.RE
|
||||
.PP
|
||||
\f[B]workspaces\f[R]
|
||||
.RS
|
||||
.PP
|
||||
Lists all workspaces with their properties.
|
||||
.RE
|
||||
.PP
|
||||
\f[B]clients\f[R]
|
||||
.RS
|
||||
.PP
|
||||
Lists all windows with their properties.
|
||||
.RE
|
||||
.PP
|
||||
\f[B]devices\f[R]
|
||||
.RS
|
||||
.PP
|
||||
Lists all connected input devices.
|
||||
.RE
|
||||
.PP
|
||||
\f[B]activewindow\f[R]
|
||||
.RS
|
||||
.PP
|
||||
Returns the active window name.
|
||||
.RE
|
||||
.PP
|
||||
\f[B]layers\f[R]
|
||||
.RS
|
||||
.PP
|
||||
Lists all the layers.
|
||||
.RE
|
||||
.PP
|
||||
\f[B]splash\f[R]
|
||||
.RS
|
||||
.PP
|
||||
Returns the current random splash.
|
||||
.RE
|
||||
.SH OPTIONS
|
||||
.PP
|
||||
\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 ;
|
||||
keyword general:gaps_out 20\[dq]\f[R]
|
||||
.RS
|
||||
.PP
|
||||
\f[I];\f[R] separates the commands.
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\f[B]\-j\f[R]
|
||||
.RS
|
||||
.PP
|
||||
Outputs information in JSON.
|
||||
.RE
|
||||
.SH BUGS
|
||||
.TP
|
||||
.B Submit bug reports and request features online at:
|
||||
<\f[I]https://github.com/hyprwm/Hyprland/issues\f[R]>
|
||||
.SH SEE ALSO
|
||||
.PP
|
||||
Sources at: <\f[I]https://github.com/hyprwm/Hyprland\f[R]>
|
||||
.SH COPYRIGHT
|
||||
.PP
|
||||
Copyright (c) 2022, vaxerski
|
||||
.SH AUTHORS
|
||||
Vaxerski <\f[I]https://github.com/vaxerski\f[R]>.
|
2
docs/meson.build
Normal file
2
docs/meson.build
Normal file
@@ -0,0 +1,2 @@
|
||||
install_man ('Hyprland.1')
|
||||
install_man ('hyprctl.1')
|
@@ -24,12 +24,11 @@ input {
|
||||
touchpad {
|
||||
natural_scroll=no
|
||||
}
|
||||
|
||||
sensitivity=0 # -1.0 - 1.0, 0 means no modification.
|
||||
}
|
||||
|
||||
general {
|
||||
sensitivity=1.0 # for mouse cursor
|
||||
main_mod=SUPER
|
||||
|
||||
gaps_in=5
|
||||
gaps_out=20
|
||||
border_size=2
|
||||
@@ -45,10 +44,8 @@ decoration {
|
||||
rounding=10
|
||||
blur=1
|
||||
blur_size=3 # minimum 1
|
||||
blur_passes=1 # minimum 1, more passes = more resource intensive.
|
||||
# Your blur "amount" is blur_size * blur_passes, but high blur_size (over around 5-ish) will produce artifacts.
|
||||
# if you want heavy blur, you need to up the blur_passes.
|
||||
# the more passes, the more you can up the blur_size without noticing artifacts.
|
||||
blur_passes=1 # minimum 1
|
||||
blur_new_optimizations=1
|
||||
}
|
||||
|
||||
animations {
|
||||
@@ -76,6 +73,10 @@ gestures {
|
||||
#windowrule=pseudo,abc
|
||||
#windowrule=monitor 0,xyz
|
||||
|
||||
# some nice mouse binds
|
||||
bindm=SUPER,mouse:272,movewindow
|
||||
bindm=SUPER,mouse:273,resizewindow
|
||||
|
||||
# example binds
|
||||
bind=SUPER,Q,exec,kitty
|
||||
bind=SUPER,C,killactive,
|
||||
|
12
flake.lock
generated
12
flake.lock
generated
@@ -2,11 +2,11 @@
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1660908602,
|
||||
"narHash": "sha256-SwZ85IPWvC4NxxFhWhRMTJpApSHbY1u4YK2UFWEBWvY=",
|
||||
"lastModified": 1664989420,
|
||||
"narHash": "sha256-Q8IxomUjjmewsoJgO3htkXLfCckQ7HkDJ/ZhdYVf/fA=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "495b19d5b3e62b4ec7e846bdfb6ef3d9c3b83492",
|
||||
"rev": "37bd39839acf99c5b738319f42478296f827f274",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -26,11 +26,11 @@
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"host": "gitlab.freedesktop.org",
|
||||
"lastModified": 1660930713,
|
||||
"narHash": "sha256-bY7q1NqG/sjCUAWPn/Ne9NCigLlPlH5Lk1WCMqv3rTU=",
|
||||
"lastModified": 1663507239,
|
||||
"narHash": "sha256-LISZtkPVe8lQ2N8YwVe+KxCkXWLP9mdw6Q2kG93wE8A=",
|
||||
"owner": "wlroots",
|
||||
"repo": "wlroots",
|
||||
"rev": "7c575922c05e4d5fd9a403c2aa631a54c7531d44",
|
||||
"rev": "2ad25b1460400e66ea26bd6489b04072be7d9dbb",
|
||||
"type": "gitlab"
|
||||
},
|
||||
"original": {
|
||||
|
41
flake.nix
41
flake.nix
@@ -20,7 +20,31 @@
|
||||
"aarch64-linux"
|
||||
"x86_64-linux"
|
||||
];
|
||||
pkgsFor = nixpkgs.legacyPackages;
|
||||
pkgsFor = genSystems (system:
|
||||
import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [
|
||||
(_: prev: {
|
||||
libdrm = prev.libdrm.overrideAttrs (old: rec {
|
||||
version = "2.4.113";
|
||||
src = prev.fetchurl {
|
||||
url = "https://dri.freedesktop.org/${old.pname}/${old.pname}-${version}.tar.xz";
|
||||
sha256 = "sha256-f9frKWf2O+tGBvItUOJ32ZNIDQXvdd2Iqb2OZ3Mj5eE=";
|
||||
};
|
||||
mesonFlags =
|
||||
[
|
||||
"-Dinstall-test-programs=true"
|
||||
"-Domap=enabled"
|
||||
"-Dcairo-tests=disabled"
|
||||
]
|
||||
++ lib.optionals prev.stdenv.hostPlatform.isAarch [
|
||||
"-Dtegra=enabled"
|
||||
"-Detnaviv=enabled"
|
||||
];
|
||||
});
|
||||
})
|
||||
];
|
||||
});
|
||||
mkDate = longDate: (lib.concatStringsSep "-" [
|
||||
(__substring 0 4 longDate)
|
||||
(__substring 4 2 longDate)
|
||||
@@ -28,16 +52,18 @@
|
||||
]);
|
||||
in {
|
||||
overlays.default = _: prev: rec {
|
||||
wlroots-hyprland = prev.wlroots.overrideAttrs (__: {
|
||||
version = mkDate (inputs.wlroots.lastModifiedDate or "19700101");
|
||||
wlroots-hyprland = prev.callPackage ./nix/wlroots.nix {
|
||||
version = mkDate (inputs.wlroots.lastModifiedDate or "19700101") + "_" + (inputs.wlroots.shortRev or "dirty");
|
||||
src = inputs.wlroots;
|
||||
});
|
||||
};
|
||||
hyprland = prev.callPackage ./nix/default.nix {
|
||||
stdenv = prev.gcc12Stdenv;
|
||||
version = "0.10.0beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101"));
|
||||
version = "0.15.0beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty");
|
||||
wlroots = wlroots-hyprland;
|
||||
};
|
||||
hyprland-debug = hyprland.override {debug = true;};
|
||||
hyprland-no-hidpi = hyprland.override {hidpiXWayland = false;};
|
||||
|
||||
waybar-hyprland = prev.waybar.overrideAttrs (oldAttrs: {
|
||||
mesonFlags = oldAttrs.mesonFlags ++ ["-Dexperimental=true"];
|
||||
});
|
||||
@@ -63,7 +89,10 @@
|
||||
|
||||
nixosModules.default = import ./nix/module.nix self;
|
||||
homeManagerModules.default = import ./nix/hm-module.nix self;
|
||||
};
|
||||
|
||||
overlay = throw "Hyprland: .overlay output is deprecated, please use the .overlays.default output";
|
||||
nixConfig = {
|
||||
extra-substituters = ["https://hyprland.cachix.org"];
|
||||
extra-trusted-public-keys = ["hyprland.cachix.org-1:a7pgxzMz7+chwVL3/pzj6jIBMioiJM7ypFP8PwtkuGc="];
|
||||
};
|
||||
}
|
||||
|
@@ -50,12 +50,6 @@ void request(std::string arg) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto SERVER = gethostbyname("localhost");
|
||||
|
||||
if (!SERVER) {
|
||||
std::cout << "Couldn't get host (2)";
|
||||
return;
|
||||
}
|
||||
|
||||
// get the instance signature
|
||||
auto instanceSig = getenv("HYPRLAND_INSTANCE_SIGNATURE");
|
||||
@@ -158,7 +152,10 @@ void dispatchRequest(int argc, char** argv) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string rq = "/dispatch " + std::string(argv[2]) + " " + std::string(argv[3]);
|
||||
std::string rq = "/dispatch";
|
||||
|
||||
for(int i = 2; i < argc; i++)
|
||||
rq += " " + std::string(argv[i]);
|
||||
|
||||
request(rq);
|
||||
}
|
||||
@@ -169,7 +166,10 @@ void keywordRequest(int argc, char** argv) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string rq = "keyword " + std::string(argv[2]) + " " + std::string(argv[3]);
|
||||
std::string rq = "/keyword";
|
||||
|
||||
for(int i = 2; i < argc; i++)
|
||||
rq += " " + std::string(argv[i]);
|
||||
|
||||
request(rq);
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
project('Hyprland', 'cpp', 'c',
|
||||
version : '0.10.0beta',
|
||||
version : '0.15.0beta',
|
||||
default_options : [
|
||||
'warning_level=2',
|
||||
'default_library=static',
|
||||
@@ -15,7 +15,7 @@ if cpp_compiler.has_argument('-std=c++23')
|
||||
elif cpp_compiler.has_argument('-std=c++2b')
|
||||
add_global_arguments('-std=c++2b', language: 'cpp')
|
||||
else
|
||||
error('Could not configure current C++ compiler (' + cpp_compiler.get_id() + ' ' + cpp_compiler.get_version() + ') with required C++ standard (C++23)')
|
||||
error('Could not configure current C++ compiler (' + cpp_compiler.get_id() + ' ' + cpp_compiler.version() + ') with required C++ standard (C++23)')
|
||||
endif
|
||||
|
||||
GIT_BRANCH = run_command('git', 'rev-parse', '--abbrev-ref', 'HEAD', check: false).stdout().strip()
|
||||
@@ -59,3 +59,4 @@ subdir('src')
|
||||
subdir('hyprctl')
|
||||
subdir('assets')
|
||||
subdir('example')
|
||||
subdir('docs')
|
||||
|
@@ -2,6 +2,7 @@
|
||||
lib,
|
||||
stdenv,
|
||||
fetchFromGitHub,
|
||||
fetchpatch,
|
||||
pkg-config,
|
||||
meson,
|
||||
ninja,
|
||||
@@ -21,10 +22,17 @@
|
||||
xwayland,
|
||||
debug ? false,
|
||||
enableXWayland ? true,
|
||||
hidpiXWayland ? true,
|
||||
legacyRenderer ? false,
|
||||
nvidiaPatches ? false,
|
||||
version ? "git",
|
||||
}:
|
||||
stdenv.mkDerivation {
|
||||
}: let
|
||||
assertXWayland = lib.assertMsg (hidpiXWayland -> enableXWayland) ''
|
||||
Hyprland: cannot have hidpiXWayland when enableXWayland is false.
|
||||
'';
|
||||
in
|
||||
assert assertXWayland;
|
||||
stdenv.mkDerivation {
|
||||
pname = "hyprland" + lib.optionalString debug "-debug";
|
||||
inherit version;
|
||||
|
||||
@@ -44,6 +52,11 @@ stdenv.mkDerivation {
|
||||
pkg-config
|
||||
];
|
||||
|
||||
outputs = [
|
||||
"out"
|
||||
"man"
|
||||
];
|
||||
|
||||
buildInputs =
|
||||
[
|
||||
git
|
||||
@@ -56,7 +69,7 @@ stdenv.mkDerivation {
|
||||
wayland
|
||||
wayland-protocols
|
||||
wayland-scanner
|
||||
(wlroots.override {inherit enableXWayland;})
|
||||
(wlroots.override {inherit enableXWayland hidpiXWayland nvidiaPatches;})
|
||||
xcbutilwm
|
||||
]
|
||||
++ lib.optional enableXWayland xwayland;
|
||||
@@ -67,7 +80,7 @@ stdenv.mkDerivation {
|
||||
else "release";
|
||||
|
||||
mesonFlags = builtins.concatLists [
|
||||
(lib.optional (!enableXWayland) "-DNO_XWAYLAND=true")
|
||||
(lib.optional (!enableXWayland) "-Dxwayland=disabled")
|
||||
(lib.optional legacyRenderer "-DLEGACY_RENDERER:STRING=true")
|
||||
];
|
||||
|
||||
@@ -90,4 +103,4 @@ stdenv.mkDerivation {
|
||||
platforms = platforms.linux;
|
||||
mainProgram = "Hyprland";
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@@ -6,7 +6,8 @@ self: {
|
||||
}: let
|
||||
cfg = config.wayland.windowManager.hyprland;
|
||||
defaultHyprlandPackage = self.packages.${pkgs.system}.default.override {
|
||||
enableXWayland = cfg.xwayland;
|
||||
enableXWayland = cfg.xwayland.enable;
|
||||
hidpiXWayland = cfg.xwayland.hidpi;
|
||||
};
|
||||
in {
|
||||
options.wayland.windowManager.hyprland = {
|
||||
@@ -41,13 +42,22 @@ in {
|
||||
</itemizedlist>
|
||||
'';
|
||||
};
|
||||
xwayland = lib.mkOption {
|
||||
xwayland = {
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Enable xwayland.
|
||||
Enable XWayland.
|
||||
'';
|
||||
};
|
||||
hidpi = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Enable HiDPI XWayland.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
extraConfig = lib.mkOption {
|
||||
type = lib.types.lines;
|
||||
@@ -56,17 +66,42 @@ in {
|
||||
Extra configuration lines to add to ~/.config/hypr/hyprland.conf.
|
||||
'';
|
||||
};
|
||||
|
||||
recommendedEnvironment = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
defaultText = lib.literalExpression "true";
|
||||
example = lib.literalExpression "false";
|
||||
description = ''
|
||||
Whether to set the recommended environment variables.
|
||||
'';
|
||||
};
|
||||
|
||||
imports = [
|
||||
(
|
||||
lib.mkRenamedOptionModule
|
||||
["wayland" "windowManager" "hyprland" "xwayland"]
|
||||
["wayland" "windowManager" "hyprland" "xwayland" "enable"]
|
||||
)
|
||||
];
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
home.packages =
|
||||
lib.optional (cfg.package != null) cfg.package
|
||||
++ lib.optional cfg.xwayland pkgs.xwayland;
|
||||
++ lib.optional cfg.xwayland.enable pkgs.xwayland;
|
||||
|
||||
home.sessionVariables = lib.mkIf cfg.recommendedEnvironment {
|
||||
GDK_BACKEND = "wayland";
|
||||
_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" = {
|
||||
text =
|
||||
(lib.optionalString cfg.systemdIntegration ''
|
||||
exec-once=export XDG_SESSION_TYPE=wayland
|
||||
exec-once=${pkgs.dbus}/bin/dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP
|
||||
exec-once=systemctl --user start hyprland-session.target
|
||||
'')
|
||||
|
@@ -8,6 +8,10 @@ self: {
|
||||
with lib; let
|
||||
cfg = config.programs.hyprland;
|
||||
in {
|
||||
imports = [
|
||||
(mkRemovedOptionModule ["programs" "hyprland" "extraPackages"] "extraPackages has been removed. Use environment.systemPackages instead.")
|
||||
];
|
||||
|
||||
options.programs.hyprland = {
|
||||
enable = mkEnableOption ''
|
||||
Hyprland, the dynamic tiling Wayland compositor that doesn't sacrifice on its looks.
|
||||
@@ -27,20 +31,40 @@ in {
|
||||
'';
|
||||
};
|
||||
|
||||
imports = [
|
||||
(mkRemovedOptionModule ["programs" "hyprland" "extraPackages"] "extraPackages has been removed. Use environment.systemPackages instead.")
|
||||
];
|
||||
recommendedEnvironment = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
defaultText = literalExpression "true";
|
||||
example = literalExpression "false";
|
||||
description = ''
|
||||
Whether to set the recommended environment variables.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
environment.systemPackages = lib.optional (cfg.package != null) cfg.package;
|
||||
security.polkit.enable = true;
|
||||
hardware.opengl.enable = mkDefault true;
|
||||
environment = {
|
||||
systemPackages = lib.optional (cfg.package != null) cfg.package;
|
||||
|
||||
sessionVariables = mkIf cfg.recommendedEnvironment {
|
||||
GDK_BACKEND = "wayland";
|
||||
_JAVA_AWT_WM_NONREPARENTING = "1";
|
||||
NIXOS_OZONE_WL = "1";
|
||||
XCURSOR_SIZE = "24";
|
||||
XDG_SESSION_TYPE = "wayland";
|
||||
};
|
||||
};
|
||||
fonts.enableDefaultFonts = mkDefault true;
|
||||
programs.dconf.enable = mkDefault true;
|
||||
hardware.opengl.enable = mkDefault true;
|
||||
programs = {
|
||||
dconf.enable = mkDefault true;
|
||||
xwayland.enable = mkDefault true;
|
||||
};
|
||||
security.polkit.enable = true;
|
||||
services.xserver.displayManager.sessionPackages = lib.optional (cfg.package != null) cfg.package;
|
||||
programs.xwayland.enable = mkDefault true;
|
||||
xdg.portal.enable = mkDefault true;
|
||||
xdg.portal.extraPortals = [pkgs.xdg-desktop-portal-wlr];
|
||||
xdg.portal = {
|
||||
enable = mkDefault true;
|
||||
extraPortals = [pkgs.xdg-desktop-portal-wlr];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
64
nix/wlroots.nix
Normal file
64
nix/wlroots.nix
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
version,
|
||||
src,
|
||||
#
|
||||
wlroots,
|
||||
xwayland,
|
||||
fetchpatch,
|
||||
lib,
|
||||
hidpiXWayland ? true,
|
||||
enableXWayland ? true,
|
||||
nvidiaPatches ? false,
|
||||
}:
|
||||
assert (lib.assertMsg (hidpiXWayland -> enableXWayland) ''
|
||||
wlroots-hyprland: cannot have hidpiXWayland when enableXWayland is false.
|
||||
'');
|
||||
(wlroots.overrideAttrs
|
||||
(old: {
|
||||
inherit version src;
|
||||
pname =
|
||||
old.pname
|
||||
+ "-hyprland"
|
||||
+ (
|
||||
if hidpiXWayland
|
||||
then "-hidpi"
|
||||
else ""
|
||||
)
|
||||
+ (
|
||||
if nvidiaPatches
|
||||
then "-nvidia"
|
||||
else ""
|
||||
);
|
||||
patches =
|
||||
(old.patches or [])
|
||||
++ (lib.optionals (enableXWayland && hidpiXWayland) [
|
||||
(fetchpatch {
|
||||
url = "https://gitlab.freedesktop.org/lilydjwg/wlroots/-/commit/6c5ffcd1fee9e44780a6a8792f74ecfbe24a1ca7.diff";
|
||||
sha256 = "sha256-Eo1pTa/PIiJsRZwIUnHGTIFFIedzODVf0ZeuXb0a3TQ=";
|
||||
})
|
||||
(fetchpatch {
|
||||
url = "https://gitlab.freedesktop.org/wlroots/wlroots/-/commit/18595000f3a21502fd60bf213122859cc348f9af.diff";
|
||||
sha256 = "sha256-jvfkAMh3gzkfuoRhB4E9T5X1Hu62wgUjj4tZkJm0mrI=";
|
||||
revert = true;
|
||||
})
|
||||
]);
|
||||
postPatch =
|
||||
(old.postPatch or "")
|
||||
+ (
|
||||
if nvidiaPatches
|
||||
then ''
|
||||
substituteInPlace render/gles2/renderer.c --replace "glFlush();" "glFinish();"
|
||||
''
|
||||
else ""
|
||||
);
|
||||
}))
|
||||
.override {
|
||||
xwayland = xwayland.overrideAttrs (old: {
|
||||
patches =
|
||||
(old.patches or [])
|
||||
++ (lib.optionals hidpiXWayland [
|
||||
./xwayland-vsync.patch
|
||||
./xwayland-hidpi.patch
|
||||
]);
|
||||
});
|
||||
}
|
498
nix/xwayland-hidpi.patch
Normal file
498
nix/xwayland-hidpi.patch
Normal file
@@ -0,0 +1,498 @@
|
||||
diff --git a/hw/xwayland/xwayland-cursor.c b/hw/xwayland/xwayland-cursor.c
|
||||
index c4457cc2a61b2103b47f996b51dbbe9eb87bd715..4a33e1f33e73c35c1691564ef4852e7501b02245 100644
|
||||
--- a/hw/xwayland/xwayland-cursor.c
|
||||
+++ b/hw/xwayland/xwayland-cursor.c
|
||||
@@ -171,6 +171,8 @@ xwl_cursor_attach_pixmap(struct xwl_seat *xwl_seat,
|
||||
}
|
||||
|
||||
wl_surface_attach(xwl_cursor->surface, buffer, 0, 0);
|
||||
+ wl_surface_set_buffer_scale(xwl_cursor->surface,
|
||||
+ xwl_seat->xwl_screen->global_output_scale);
|
||||
xwl_surface_damage(xwl_seat->xwl_screen, xwl_cursor->surface, 0, 0,
|
||||
xwl_seat->x_cursor->bits->width,
|
||||
xwl_seat->x_cursor->bits->height);
|
||||
@@ -190,6 +192,7 @@ xwl_cursor_attach_pixmap(struct xwl_seat *xwl_seat,
|
||||
void
|
||||
xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
|
||||
{
|
||||
+ struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
|
||||
struct xwl_cursor *xwl_cursor = &xwl_seat->cursor;
|
||||
PixmapPtr pixmap;
|
||||
CursorPtr cursor;
|
||||
@@ -220,8 +223,8 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
|
||||
wl_pointer_set_cursor(xwl_seat->wl_pointer,
|
||||
xwl_seat->pointer_enter_serial,
|
||||
xwl_cursor->surface,
|
||||
- xwl_seat->x_cursor->bits->xhot,
|
||||
- xwl_seat->x_cursor->bits->yhot);
|
||||
+ xwl_scale_to(xwl_screen, xwl_seat->x_cursor->bits->xhot),
|
||||
+ xwl_scale_to(xwl_screen, xwl_seat->x_cursor->bits->yhot));
|
||||
|
||||
xwl_cursor_attach_pixmap(xwl_seat, xwl_cursor, pixmap);
|
||||
}
|
||||
@@ -230,6 +233,7 @@ void
|
||||
xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool)
|
||||
{
|
||||
struct xwl_seat *xwl_seat = xwl_tablet_tool->seat;
|
||||
+ struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
|
||||
struct xwl_cursor *xwl_cursor = &xwl_tablet_tool->cursor;
|
||||
PixmapPtr pixmap;
|
||||
CursorPtr cursor;
|
||||
@@ -258,9 +262,9 @@ xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool)
|
||||
zwp_tablet_tool_v2_set_cursor(xwl_tablet_tool->tool,
|
||||
xwl_tablet_tool->proximity_in_serial,
|
||||
xwl_cursor->surface,
|
||||
- xwl_seat->x_cursor->bits->xhot,
|
||||
- xwl_seat->x_cursor->bits->yhot);
|
||||
-
|
||||
+ xwl_scale_to(xwl_screen, xwl_seat->x_cursor->bits->xhot),
|
||||
+ xwl_scale_to(xwl_screen, xwl_seat->x_cursor->bits->yhot));
|
||||
+ wl_surface_set_buffer_scale(xwl_cursor->surface, xwl_screen->global_output_scale);
|
||||
xwl_cursor_attach_pixmap(xwl_seat, xwl_cursor, pixmap);
|
||||
}
|
||||
|
||||
diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
|
||||
index 26b3630c73b62514fe3ba7824371f79868e953f3..55cd8d466a55db03948abe93ffa03bf129b5e17a 100644
|
||||
--- a/hw/xwayland/xwayland-input.c
|
||||
+++ b/hw/xwayland/xwayland-input.c
|
||||
@@ -412,8 +412,8 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer,
|
||||
DeviceIntPtr dev = get_pointer_device(xwl_seat);
|
||||
DeviceIntPtr master;
|
||||
int i;
|
||||
- int sx = wl_fixed_to_int(sx_w);
|
||||
- int sy = wl_fixed_to_int(sy_w);
|
||||
+ int sx = wl_fixed_to_int(sx_w) * xwl_seat->xwl_screen->global_output_scale;
|
||||
+ int sy = wl_fixed_to_int(sy_w) * xwl_seat->xwl_screen->global_output_scale;
|
||||
int dx, dy;
|
||||
ScreenPtr pScreen = xwl_seat->xwl_screen->screen;
|
||||
ValuatorMask mask;
|
||||
@@ -592,13 +592,14 @@ pointer_handle_motion(void *data, struct wl_pointer *pointer,
|
||||
uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
|
||||
{
|
||||
struct xwl_seat *xwl_seat = data;
|
||||
+ int32_t scale = xwl_seat->xwl_screen->global_output_scale;
|
||||
|
||||
if (!xwl_seat->focus_window)
|
||||
return;
|
||||
|
||||
xwl_seat->pending_pointer_event.has_absolute = TRUE;
|
||||
- xwl_seat->pending_pointer_event.x = sx_w;
|
||||
- xwl_seat->pending_pointer_event.y = sy_w;
|
||||
+ xwl_seat->pending_pointer_event.x = sx_w * scale;
|
||||
+ xwl_seat->pending_pointer_event.y = sy_w * scale;
|
||||
|
||||
if (wl_proxy_get_version((struct wl_proxy *) xwl_seat->wl_pointer) < 5)
|
||||
dispatch_pointer_motion_event(xwl_seat);
|
||||
@@ -672,7 +673,8 @@ pointer_handle_axis(void *data, struct wl_pointer *pointer,
|
||||
xorg_list_del(&pending->l);
|
||||
free(pending);
|
||||
} else {
|
||||
- valuator_mask_set_double(&mask, index, wl_fixed_to_double(value) / divisor);
|
||||
+ double scaled_value = wl_fixed_to_double(value);
|
||||
+ valuator_mask_set_double(&mask, index, scaled_value / divisor);
|
||||
}
|
||||
|
||||
QueuePointerEvents(get_pointer_device(xwl_seat),
|
||||
@@ -740,12 +742,13 @@ relative_pointer_handle_relative_motion(void *data,
|
||||
wl_fixed_t dy_unaccelf)
|
||||
{
|
||||
struct xwl_seat *xwl_seat = data;
|
||||
+ int32_t scale = xwl_seat->xwl_screen->global_output_scale;
|
||||
|
||||
xwl_seat->pending_pointer_event.has_relative = TRUE;
|
||||
- xwl_seat->pending_pointer_event.dx = wl_fixed_to_double(dxf);
|
||||
- xwl_seat->pending_pointer_event.dy = wl_fixed_to_double(dyf);
|
||||
- xwl_seat->pending_pointer_event.dx_unaccel = wl_fixed_to_double(dx_unaccelf);
|
||||
- xwl_seat->pending_pointer_event.dy_unaccel = wl_fixed_to_double(dy_unaccelf);
|
||||
+ xwl_seat->pending_pointer_event.dx = wl_fixed_to_double(dxf) * scale;
|
||||
+ xwl_seat->pending_pointer_event.dy = wl_fixed_to_double(dyf) * scale;
|
||||
+ xwl_seat->pending_pointer_event.dx_unaccel = wl_fixed_to_double(dx_unaccelf) * scale;
|
||||
+ xwl_seat->pending_pointer_event.dy_unaccel = wl_fixed_to_double(dy_unaccelf) * scale;
|
||||
|
||||
if (!xwl_seat->focus_window)
|
||||
return;
|
||||
@@ -1057,8 +1060,8 @@ touch_handle_down(void *data, struct wl_touch *wl_touch,
|
||||
|
||||
xwl_touch->window = wl_surface_get_user_data(surface);
|
||||
xwl_touch->id = id;
|
||||
- xwl_touch->x = wl_fixed_to_int(sx_w);
|
||||
- xwl_touch->y = wl_fixed_to_int(sy_w);
|
||||
+ xwl_touch->x = wl_fixed_to_int(sx_w) * xwl_seat->xwl_screen->global_output_scale;
|
||||
+ xwl_touch->y = wl_fixed_to_int(sy_w) * xwl_seat->xwl_screen->global_output_scale;
|
||||
xorg_list_add(&xwl_touch->link_touch, &xwl_seat->touches);
|
||||
|
||||
xwl_touch_send_event(xwl_touch, xwl_seat, XI_TouchBegin);
|
||||
@@ -1094,8 +1097,8 @@ touch_handle_motion(void *data, struct wl_touch *wl_touch,
|
||||
if (!xwl_touch)
|
||||
return;
|
||||
|
||||
- xwl_touch->x = wl_fixed_to_int(sx_w);
|
||||
- xwl_touch->y = wl_fixed_to_int(sy_w);
|
||||
+ xwl_touch->x = wl_fixed_to_int(sx_w) * xwl_seat->xwl_screen->global_output_scale;;
|
||||
+ xwl_touch->y = wl_fixed_to_int(sy_w) * xwl_seat->xwl_screen->global_output_scale;;
|
||||
xwl_touch_send_event(xwl_touch, xwl_seat, XI_TouchUpdate);
|
||||
}
|
||||
|
||||
@@ -1726,8 +1729,8 @@ tablet_tool_motion(void *data, struct zwp_tablet_tool_v2 *tool,
|
||||
struct xwl_tablet_tool *xwl_tablet_tool = data;
|
||||
struct xwl_seat *xwl_seat = xwl_tablet_tool->seat;
|
||||
int32_t dx, dy;
|
||||
- double sx = wl_fixed_to_double(x);
|
||||
- double sy = wl_fixed_to_double(y);
|
||||
+ double sx = wl_fixed_to_double(x) * xwl_seat->xwl_screen->global_output_scale;
|
||||
+ double sy = wl_fixed_to_double(y) * xwl_seat->xwl_screen->global_output_scale;
|
||||
|
||||
if (!xwl_seat->tablet_focus_window)
|
||||
return;
|
||||
@@ -2714,6 +2717,7 @@ xwl_pointer_warp_emulator_set_fake_pos(struct xwl_pointer_warp_emulator *warp_em
|
||||
int x,
|
||||
int y)
|
||||
{
|
||||
+ struct xwl_screen *xwl_screen;
|
||||
struct zwp_locked_pointer_v1 *locked_pointer =
|
||||
warp_emulator->locked_pointer;
|
||||
WindowPtr window;
|
||||
@@ -2725,6 +2729,7 @@ xwl_pointer_warp_emulator_set_fake_pos(struct xwl_pointer_warp_emulator *warp_em
|
||||
if (!warp_emulator->xwl_seat->focus_window)
|
||||
return;
|
||||
|
||||
+ xwl_screen = warp_emulator->xwl_seat->xwl_screen;
|
||||
window = warp_emulator->xwl_seat->focus_window->window;
|
||||
if (x >= window->drawable.x ||
|
||||
y >= window->drawable.y ||
|
||||
@@ -2733,8 +2738,8 @@ xwl_pointer_warp_emulator_set_fake_pos(struct xwl_pointer_warp_emulator *warp_em
|
||||
sx = x - window->drawable.x;
|
||||
sy = y - window->drawable.y;
|
||||
zwp_locked_pointer_v1_set_cursor_position_hint(locked_pointer,
|
||||
- wl_fixed_from_int(sx),
|
||||
- wl_fixed_from_int(sy));
|
||||
+ wl_fixed_from_int(xwl_scale_to(xwl_screen, sx)),
|
||||
+ wl_fixed_from_int(xwl_scale_to(xwl_screen, sy)));
|
||||
wl_surface_commit(warp_emulator->xwl_seat->focus_window->surface);
|
||||
}
|
||||
}
|
||||
diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c
|
||||
index ef705bc01bf8c2d2f170cda9ba21ed8293f50559..b8f6cd51bd240ed5e16271eb4749db18868bea7b 100644
|
||||
--- a/hw/xwayland/xwayland-output.c
|
||||
+++ b/hw/xwayland/xwayland-output.c
|
||||
@@ -191,6 +191,9 @@ update_screen_size(struct xwl_output *xwl_output, int width, int height)
|
||||
{
|
||||
struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
|
||||
|
||||
+ width *= xwl_screen->global_output_scale;
|
||||
+ height *= xwl_screen->global_output_scale;
|
||||
+
|
||||
if (xwl_screen->root_clip_mode == ROOT_CLIP_FULL)
|
||||
SetRootClip(xwl_screen->screen, ROOT_CLIP_NONE);
|
||||
|
||||
@@ -497,14 +500,15 @@ xwl_output_set_emulated_mode(struct xwl_output *xwl_output, ClientPtr client,
|
||||
xwl_output_set_randr_emu_props(xwl_output->xwl_screen, client);
|
||||
}
|
||||
|
||||
-static void
|
||||
-apply_output_change(struct xwl_output *xwl_output)
|
||||
+void
|
||||
+xwl_output_apply_changes(struct xwl_output *xwl_output)
|
||||
{
|
||||
struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
|
||||
struct xwl_output *it;
|
||||
int mode_width, mode_height, count;
|
||||
int width = 0, height = 0, has_this_output = 0;
|
||||
RRModePtr *randr_modes;
|
||||
+ int32_t scale = xwl_screen->global_output_scale;
|
||||
|
||||
/* Clear out the "done" received flags */
|
||||
xwl_output->wl_output_done = FALSE;
|
||||
@@ -523,10 +527,10 @@ apply_output_change(struct xwl_output *xwl_output)
|
||||
}
|
||||
|
||||
/* Build a fresh modes array using the current refresh rate */
|
||||
- randr_modes = output_get_rr_modes(xwl_output, mode_width, mode_height, &count);
|
||||
+ randr_modes = output_get_rr_modes(xwl_output, mode_width * scale, mode_height * scale, &count);
|
||||
RROutputSetModes(xwl_output->randr_output, randr_modes, count, 1);
|
||||
RRCrtcNotify(xwl_output->randr_crtc, randr_modes[0],
|
||||
- xwl_output->x, xwl_output->y,
|
||||
+ xwl_output->x * scale, xwl_output->y * scale,
|
||||
xwl_output->rotation, NULL, 1, &xwl_output->randr_output);
|
||||
/* RROutputSetModes takes ownership of the passed in modes, so we only
|
||||
* have to free the pointer array.
|
||||
@@ -567,7 +571,7 @@ output_handle_done(void *data, struct wl_output *wl_output)
|
||||
*/
|
||||
if (xwl_output->xdg_output_done || !xwl_output->xdg_output ||
|
||||
zxdg_output_v1_get_version(xwl_output->xdg_output) >= 3)
|
||||
- apply_output_change(xwl_output);
|
||||
+ xwl_output_apply_changes(xwl_output);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -610,7 +614,7 @@ xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output)
|
||||
xwl_output->xdg_output_done = TRUE;
|
||||
if (xwl_output->wl_output_done &&
|
||||
zxdg_output_v1_get_version(xdg_output) < 3)
|
||||
- apply_output_change(xwl_output);
|
||||
+ xwl_output_apply_changes(xwl_output);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -678,6 +682,8 @@ xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id)
|
||||
RROutputSetConnection(xwl_output->randr_output, RR_Connected);
|
||||
RRTellChanged(xwl_screen->screen);
|
||||
|
||||
+ xwl_output->scale = 1;
|
||||
+
|
||||
/* We want the output to be in the list as soon as created so we can
|
||||
* use it when binding to the xdg-output protocol...
|
||||
*/
|
||||
diff --git a/hw/xwayland/xwayland-output.h b/hw/xwayland/xwayland-output.h
|
||||
index 02b9831083e82a33d85d4404e39d00f06f6c56fd..ec089757f44178dcd7f9c48907f790ce1b2a2729 100644
|
||||
--- a/hw/xwayland/xwayland-output.h
|
||||
+++ b/hw/xwayland/xwayland-output.h
|
||||
@@ -53,7 +53,7 @@ struct xwl_output {
|
||||
struct wl_output *output;
|
||||
struct zxdg_output_v1 *xdg_output;
|
||||
uint32_t server_output_id;
|
||||
- int32_t x, y, width, height, refresh;
|
||||
+ int32_t x, y, width, height, refresh, scale;
|
||||
Rotation rotation;
|
||||
Bool wl_output_done;
|
||||
Bool xdg_output_done;
|
||||
@@ -100,6 +100,8 @@ void xwl_output_set_emulated_mode(struct xwl_output *xwl_output,
|
||||
void xwl_output_set_window_randr_emu_props(struct xwl_screen *xwl_screen,
|
||||
WindowPtr window);
|
||||
|
||||
+void xwl_output_apply_changes(struct xwl_output *xwl_output);
|
||||
+
|
||||
void xwl_screen_init_xdg_output(struct xwl_screen *xwl_screen);
|
||||
|
||||
#endif /* XWAYLAND_OUTPUT_H */
|
||||
diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c
|
||||
index c9cf8c2f569a319034e0789e7587414e50237065..5be0c208ca46b1a53a136885fdc8ab44251fe7ff 100644
|
||||
--- a/hw/xwayland/xwayland-present.c
|
||||
+++ b/hw/xwayland/xwayland-present.c
|
||||
@@ -680,6 +680,8 @@ xwl_present_flip(WindowPtr present_window,
|
||||
|
||||
/* We can flip directly to the main surface (full screen window without clips) */
|
||||
wl_surface_attach(xwl_window->surface, buffer, 0, 0);
|
||||
+ wl_surface_set_buffer_scale(xwl_window->surface,
|
||||
+ xwl_window->xwl_screen->global_output_scale);
|
||||
|
||||
if (!xwl_window->frame_callback)
|
||||
xwl_window_create_frame_callback(xwl_window);
|
||||
diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c
|
||||
index bb18e5c94fbc7134c801e4e1979e8184079d352e..4ec2de7d123dd36315df07a1e95b1f417925f0f8 100644
|
||||
--- a/hw/xwayland/xwayland-screen.c
|
||||
+++ b/hw/xwayland/xwayland-screen.c
|
||||
@@ -51,6 +51,7 @@
|
||||
#include "xwayland-pixmap.h"
|
||||
#include "xwayland-present.h"
|
||||
#include "xwayland-shm.h"
|
||||
+#include "xwayland-window-buffers.h"
|
||||
|
||||
#ifdef MITSHM
|
||||
#include "shmint.h"
|
||||
@@ -110,6 +111,12 @@ xwl_screen_has_resolution_change_emulation(struct xwl_screen *xwl_screen)
|
||||
return xwl_screen->rootless && xwl_screen_has_viewport_support(xwl_screen);
|
||||
}
|
||||
|
||||
+int
|
||||
+xwl_scale_to(struct xwl_screen *xwl_screen, int value)
|
||||
+{
|
||||
+ return value / (double)xwl_screen->global_output_scale + 0.5;
|
||||
+}
|
||||
+
|
||||
/* Return the output @ 0x0, falling back to the first output in the list */
|
||||
struct xwl_output *
|
||||
xwl_screen_get_first_output(struct xwl_screen *xwl_screen)
|
||||
@@ -127,6 +134,37 @@ xwl_screen_get_first_output(struct xwl_screen *xwl_screen)
|
||||
return xorg_list_first_entry(&xwl_screen->output_list, struct xwl_output, link);
|
||||
}
|
||||
|
||||
+static void
|
||||
+xwl_screen_set_global_scale_from_property(struct xwl_screen *screen,
|
||||
+ PropertyPtr prop)
|
||||
+{
|
||||
+ CARD32 *propdata;
|
||||
+
|
||||
+ if (prop->type != XA_CARDINAL || prop->format != 32 || prop->size != 1) {
|
||||
+ // TODO: handle warnings more cleanly.
|
||||
+ LogMessageVerb(X_WARNING, 0, "Bad value for property %s.\n",
|
||||
+ NameForAtom(prop->propertyName));
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ propdata = prop->data;
|
||||
+ xwl_screen_set_global_scale(screen, propdata[0]);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+xwl_screen_update_property(struct xwl_screen *screen,
|
||||
+ PropertyStateRec *propstate)
|
||||
+{
|
||||
+ switch (propstate->state) {
|
||||
+ case PropertyNewValue:
|
||||
+ xwl_screen_set_global_scale_from_property(screen, propstate->prop);
|
||||
+ break;
|
||||
+ case PropertyDelete:
|
||||
+ xwl_screen_set_global_scale(screen, 1);
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static void
|
||||
xwl_property_callback(CallbackListPtr *pcbl, void *closure,
|
||||
void *calldata)
|
||||
@@ -134,19 +172,24 @@ xwl_property_callback(CallbackListPtr *pcbl, void *closure,
|
||||
ScreenPtr screen = closure;
|
||||
PropertyStateRec *rec = calldata;
|
||||
struct xwl_screen *xwl_screen;
|
||||
- struct xwl_window *xwl_window;
|
||||
|
||||
if (rec->win->drawable.pScreen != screen)
|
||||
return;
|
||||
|
||||
- xwl_window = xwl_window_get(rec->win);
|
||||
- if (!xwl_window)
|
||||
- return;
|
||||
-
|
||||
xwl_screen = xwl_screen_get(screen);
|
||||
|
||||
- if (rec->prop->propertyName == xwl_screen->allow_commits_prop)
|
||||
+ if (rec->prop->propertyName == xwl_screen->allow_commits_prop) {
|
||||
+ struct xwl_window *xwl_window;
|
||||
+
|
||||
+ xwl_window = xwl_window_get(rec->win);
|
||||
+ if (!xwl_window)
|
||||
+ return;
|
||||
+
|
||||
xwl_window_update_property(xwl_window, rec);
|
||||
+ }
|
||||
+ else if (rec->prop->propertyName == xwl_screen->global_output_scale_prop) {
|
||||
+ xwl_screen_update_property(xwl_screen, rec);
|
||||
+ }
|
||||
}
|
||||
|
||||
Bool
|
||||
@@ -521,8 +564,14 @@ void xwl_surface_damage(struct xwl_screen *xwl_screen,
|
||||
{
|
||||
if (wl_surface_get_version(surface) >= WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION)
|
||||
wl_surface_damage_buffer(surface, x, y, width, height);
|
||||
- else
|
||||
+ else {
|
||||
+ x = xwl_scale_to(xwl_screen, x);
|
||||
+ y = xwl_scale_to(xwl_screen, y);
|
||||
+ width = xwl_scale_to(xwl_screen, width);
|
||||
+ height = xwl_scale_to(xwl_screen, height);
|
||||
+
|
||||
wl_surface_damage(surface, x, y, width, height);
|
||||
+ }
|
||||
}
|
||||
|
||||
void
|
||||
@@ -538,10 +587,34 @@ xwl_screen_roundtrip(struct xwl_screen *xwl_screen)
|
||||
xwl_give_up("could not connect to wayland server\n");
|
||||
}
|
||||
|
||||
+void
|
||||
+xwl_screen_set_global_scale(struct xwl_screen *xwl_screen, int32_t scale)
|
||||
+{
|
||||
+ struct xwl_output *it;
|
||||
+ struct xwl_window *xwl_window;
|
||||
+
|
||||
+ xwl_screen->global_output_scale = scale;
|
||||
+
|
||||
+ /* change randr resolutions and positions */
|
||||
+ xorg_list_for_each_entry(it, &xwl_screen->output_list, link) {
|
||||
+ xwl_output_apply_changes(it);
|
||||
+ }
|
||||
+
|
||||
+ if (!xwl_screen->rootless && xwl_screen->screen->root) {
|
||||
+ /* Clear all the buffers, so that they'll be remade with the new sizes
|
||||
+ * (this doesn't occur automatically because as far as Xorg is
|
||||
+ * concerned, the window's size is the same) */
|
||||
+ xorg_list_for_each_entry(xwl_window, &xwl_screen->window_list, link_window) {
|
||||
+ xwl_window_buffers_recycle(xwl_window);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
Bool
|
||||
xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
|
||||
{
|
||||
static const char allow_commits[] = "_XWAYLAND_ALLOW_COMMITS";
|
||||
+ static const char global_output_scale[] = "_XWAYLAND_GLOBAL_OUTPUT_SCALE";
|
||||
struct xwl_screen *xwl_screen;
|
||||
Pixel red_mask, blue_mask, green_mask;
|
||||
int ret, bpc, green_bpc, i;
|
||||
@@ -573,6 +646,7 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
|
||||
#ifdef XWL_HAS_GLAMOR
|
||||
xwl_screen->glamor = 1;
|
||||
#endif
|
||||
+ xwl_screen->global_output_scale = 1;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-rootless") == 0) {
|
||||
@@ -743,6 +817,12 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
|
||||
if (xwl_screen->allow_commits_prop == BAD_RESOURCE)
|
||||
return FALSE;
|
||||
|
||||
+ xwl_screen->global_output_scale_prop = MakeAtom(global_output_scale,
|
||||
+ strlen(global_output_scale),
|
||||
+ TRUE);
|
||||
+ if (xwl_screen->global_output_scale_prop == BAD_RESOURCE)
|
||||
+ return FALSE;
|
||||
+
|
||||
AddCallback(&PropertyStateCallback, xwl_property_callback, pScreen);
|
||||
|
||||
xwl_screen_roundtrip(xwl_screen);
|
||||
diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h
|
||||
index b965dddd7f964b1d100bbb9d10da1c35ab39810e..7446829d098fbe235e605084a016daff1a8eaea2 100644
|
||||
--- a/hw/xwayland/xwayland-screen.h
|
||||
+++ b/hw/xwayland/xwayland-screen.h
|
||||
@@ -72,6 +72,8 @@ struct xwl_screen {
|
||||
struct xorg_list damage_window_list;
|
||||
struct xorg_list window_list;
|
||||
|
||||
+ int32_t global_output_scale;
|
||||
+
|
||||
int wayland_fd;
|
||||
struct wl_display *display;
|
||||
struct wl_registry *registry;
|
||||
@@ -107,6 +109,7 @@ struct xwl_screen {
|
||||
struct glamor_context *glamor_ctx;
|
||||
|
||||
Atom allow_commits_prop;
|
||||
+ Atom global_output_scale_prop;
|
||||
|
||||
/* The preferred GLVND vendor. If NULL, "mesa" is assumed. */
|
||||
const char *glvnd_vendor;
|
||||
@@ -134,5 +137,7 @@ void xwl_screen_roundtrip (struct xwl_screen *xwl_screen);
|
||||
void xwl_surface_damage(struct xwl_screen *xwl_screen,
|
||||
struct wl_surface *surface,
|
||||
int32_t x, int32_t y, int32_t width, int32_t height);
|
||||
+int xwl_scale_to(struct xwl_screen *xwl_screen, int value);
|
||||
+void xwl_screen_set_global_scale(struct xwl_screen *xwl_screen, int32_t scale);
|
||||
|
||||
#endif /* XWAYLAND_SCREEN_H */
|
||||
diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
|
||||
index 00f161eda084e335ac07471a2198176d75d9fcf0..ed3903853f0dab1dad390cd8429639541546157d 100644
|
||||
--- a/hw/xwayland/xwayland-window.c
|
||||
+++ b/hw/xwayland/xwayland-window.c
|
||||
@@ -470,7 +470,8 @@ ensure_surface_for_window(WindowPtr window)
|
||||
}
|
||||
|
||||
wl_region_add(region, 0, 0,
|
||||
- window->drawable.width, window->drawable.height);
|
||||
+ xwl_scale_to(xwl_screen, window->drawable.width),
|
||||
+ xwl_scale_to(xwl_screen, window->drawable.height));
|
||||
wl_surface_set_opaque_region(xwl_window->surface, region);
|
||||
wl_region_destroy(region);
|
||||
}
|
||||
@@ -820,6 +821,7 @@ xwl_window_post_damage(struct xwl_window *xwl_window)
|
||||
#endif
|
||||
|
||||
wl_surface_attach(xwl_window->surface, buffer, 0, 0);
|
||||
+ wl_surface_set_buffer_scale(xwl_window->surface, xwl_screen->global_output_scale);
|
||||
|
||||
/* Arbitrary limit to try to avoid flooding the Wayland
|
||||
* connection. If we flood it too much anyway, this could
|
||||
|
12
nix/xwayland-vsync.patch
Normal file
12
nix/xwayland-vsync.patch
Normal file
@@ -0,0 +1,12 @@
|
||||
--- a/hw/xwayland/xwayland-present.c
|
||||
+++ b/hw/xwayland/xwayland-present.c
|
||||
@@ -824,7 +824,8 @@
|
||||
dixDestroyPixmap(vblank->pixmap, vblank->pixmap->drawable.id);
|
||||
vblank->pixmap = NULL;
|
||||
|
||||
- if (xwl_present_queue_vblank(screen, window, vblank->crtc,
|
||||
+ if (vblank->target_msc > crtc_msc &&
|
||||
+ xwl_present_queue_vblank(screen, window, vblank->crtc,
|
||||
vblank->event_id, crtc_msc + 1)
|
||||
== Success)
|
||||
return;
|
@@ -16,6 +16,8 @@ int handleCritSignal(int signo, void* data) {
|
||||
CCompositor::CCompositor() {
|
||||
wlr_log_init(WLR_INFO, NULL);
|
||||
|
||||
m_iHyprlandPID = getpid();
|
||||
|
||||
m_szInstanceSignature = GIT_COMMIT_HASH + std::string("_") + std::to_string(time(NULL));
|
||||
|
||||
setenv("HYPRLAND_INSTANCE_SIGNATURE", m_szInstanceSignature.c_str(), true);
|
||||
@@ -27,6 +29,8 @@ CCompositor::CCompositor() {
|
||||
|
||||
Debug::log(LOG, "Instance Signature: %s", m_szInstanceSignature.c_str());
|
||||
|
||||
Debug::log(LOG, "Hyprland PID: %i", m_iHyprlandPID);
|
||||
|
||||
Debug::log(LOG, "===== SYSTEM INFO: =====");
|
||||
|
||||
logSystemInfo();
|
||||
@@ -94,7 +98,7 @@ CCompositor::CCompositor() {
|
||||
wlr_data_control_manager_v1_create(m_sWLDisplay);
|
||||
wlr_gamma_control_manager_v1_create(m_sWLDisplay);
|
||||
wlr_primary_selection_v1_device_manager_create(m_sWLDisplay);
|
||||
// wlr_viewporter_create(m_sWLDisplay); // TODO: support wl_viewporter
|
||||
wlr_viewporter_create(m_sWLDisplay);
|
||||
|
||||
m_sWLROutputLayout = wlr_output_layout_create();
|
||||
|
||||
@@ -141,6 +145,12 @@ CCompositor::CCompositor() {
|
||||
|
||||
m_sWLRToplevelMgr = wlr_foreign_toplevel_manager_v1_create(m_sWLDisplay);
|
||||
|
||||
m_sWRLDRMLeaseMgr = wlr_drm_lease_v1_manager_create(m_sWLDisplay, m_sWLRBackend);
|
||||
if (!m_sWRLDRMLeaseMgr) {
|
||||
Debug::log(INFO, "Failed to create wlr_drm_lease_v1_manager");
|
||||
Debug::log(INFO, "VR will not be available");
|
||||
}
|
||||
|
||||
m_sWLRTabletManager = wlr_tablet_v2_create(m_sWLDisplay);
|
||||
|
||||
m_sWLRForeignRegistry = wlr_xdg_foreign_registry_create(m_sWLDisplay);
|
||||
@@ -188,6 +198,9 @@ void CCompositor::initAllSignals() {
|
||||
addWLSignal(&m_sWLRCursor->events.touch_down, &Events::listen_touchBegin, m_sWLRCursor, "WLRCursor");
|
||||
addWLSignal(&m_sWLRCursor->events.touch_up, &Events::listen_touchEnd, m_sWLRCursor, "WLRCursor");
|
||||
addWLSignal(&m_sWLRCursor->events.touch_motion, &Events::listen_touchUpdate, m_sWLRCursor, "WLRCursor");
|
||||
addWLSignal(&m_sWLRCursor->events.touch_frame, &Events::listen_touchFrame, m_sWLRCursor, "WLRCursor");
|
||||
addWLSignal(&m_sWLRCursor->events.hold_begin, &Events::listen_holdBegin, m_sWLRCursor, "WLRCursor");
|
||||
addWLSignal(&m_sWLRCursor->events.hold_end, &Events::listen_holdEnd, m_sWLRCursor, "WLRCursor");
|
||||
addWLSignal(&m_sWLRBackend->events.new_input, &Events::listen_newInput, m_sWLRBackend, "Backend");
|
||||
addWLSignal(&m_sSeat.seat->events.request_set_cursor, &Events::listen_requestMouse, &m_sSeat, "Seat");
|
||||
addWLSignal(&m_sSeat.seat->events.request_set_selection, &Events::listen_requestSetSel, &m_sSeat, "Seat");
|
||||
@@ -211,20 +224,43 @@ void CCompositor::initAllSignals() {
|
||||
addWLSignal(&m_sWLRIMEMgr->events.input_method, &Events::listen_newIME, m_sWLRIMEMgr, "IMEMgr");
|
||||
addWLSignal(&m_sWLRTextInputMgr->events.text_input, &Events::listen_newTextInput, m_sWLRTextInputMgr, "TextInputMgr");
|
||||
|
||||
if(m_sWRLDRMLeaseMgr)
|
||||
addWLSignal(&m_sWRLDRMLeaseMgr->events.request, &Events::listen_leaseRequest, &m_sWRLDRMLeaseMgr, "DRM");
|
||||
|
||||
if (m_sWLRSession)
|
||||
addWLSignal(&m_sWLRSession->events.active, &Events::listen_sessionActive, m_sWLRSession, "Session");
|
||||
}
|
||||
|
||||
void CCompositor::cleanup() {
|
||||
if (!m_sWLDisplay)
|
||||
if (!m_sWLDisplay || m_bIsShuttingDown)
|
||||
return;
|
||||
|
||||
m_pLastFocus = nullptr;
|
||||
m_pLastWindow = nullptr;
|
||||
|
||||
// accumulate all PIDs for killing, also request closing.
|
||||
for (auto& w : m_vWindows) {
|
||||
if (w->m_bIsMapped && !w->m_bHidden)
|
||||
m_dProcessPIDsOnShutdown.push_back(w->getPID());
|
||||
}
|
||||
|
||||
// end threads
|
||||
g_pEventManager->m_tThread = std::thread();
|
||||
|
||||
m_vWorkspaces.clear();
|
||||
m_vWindows.clear();
|
||||
|
||||
m_bIsShuttingDown = true;
|
||||
|
||||
for (auto& m : m_vMonitors) {
|
||||
g_pHyprOpenGL->destroyMonitorResources(m.get());
|
||||
|
||||
wlr_output_enable(m->output, false);
|
||||
wlr_output_commit(m->output);
|
||||
}
|
||||
|
||||
m_vMonitors.clear();
|
||||
|
||||
if (g_pXWaylandManager->m_sWLRXWayland) {
|
||||
wlr_xwayland_destroy(g_pXWaylandManager->m_sWLRXWayland);
|
||||
g_pXWaylandManager->m_sWLRXWayland = nullptr;
|
||||
@@ -232,14 +268,7 @@ void CCompositor::cleanup() {
|
||||
|
||||
wl_display_terminate(m_sWLDisplay);
|
||||
|
||||
m_sWLDisplay = nullptr;
|
||||
|
||||
// kill the PID with a sigkill after 2 seconds
|
||||
const auto PID = getpid();
|
||||
|
||||
std::string call = "sleep 2 && kill -9 " + std::to_string(PID);
|
||||
|
||||
execl("/bin/sh", "/bin/sh", "-c", call.c_str(), ">", "/dev/null", nullptr); // this is to prevent that random "freezing"
|
||||
g_pKeybindManager->spawn("sleep 5 && kill -9 " + std::to_string(m_iHyprlandPID)); // this is to prevent that random "freezing"
|
||||
// the PID should not be reused.
|
||||
}
|
||||
|
||||
@@ -427,10 +456,17 @@ CWindow* CCompositor::vectorToWindow(const Vector2D& pos) {
|
||||
}
|
||||
}
|
||||
|
||||
// pinned
|
||||
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 (wlr_box_contains_point(&box, pos.x, pos.y) && (*w)->m_bIsMapped && (*w)->m_bIsFloating && !(*w)->m_bHidden && (*w)->m_bPinned)
|
||||
return w->get();
|
||||
}
|
||||
|
||||
// first loop over floating cuz they're above, m_vWindows should be sorted bottom->top, for tiled it doesn't matter.
|
||||
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 (wlr_box_contains_point(&box, pos.x, pos.y) && (*w)->m_bIsMapped && (*w)->m_bIsFloating && isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->m_bHidden)
|
||||
if (wlr_box_contains_point(&box, pos.x, pos.y) && (*w)->m_bIsMapped && (*w)->m_bIsFloating && isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->m_bHidden && !(*w)->m_bPinned)
|
||||
return w->get();
|
||||
}
|
||||
|
||||
@@ -490,12 +526,43 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
|
||||
}
|
||||
}
|
||||
|
||||
// pinned windows on top of floating regardless
|
||||
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_bIsMapped && !(*w)->m_bHidden && !(*w)->m_bX11ShouldntFocus && (*w)->m_bPinned) {
|
||||
if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y))
|
||||
return w->get();
|
||||
|
||||
if (!(*w)->m_bIsX11) {
|
||||
wlr_surface* resultSurf = nullptr;
|
||||
Vector2D origin = (*w)->m_vRealPosition.vec();
|
||||
SExtensionFindingData data = {origin, pos, &resultSurf};
|
||||
wlr_xdg_surface_for_each_popup_surface((*w)->m_uSurface.xdg, findExtensionForVector2D, &data);
|
||||
|
||||
if (resultSurf)
|
||||
return w->get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter.
|
||||
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_bIsMapped && isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->m_bHidden && !(*w)->m_bX11ShouldntFocus) {
|
||||
if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y))
|
||||
if ((*w)->m_bIsFloating && (*w)->m_bIsMapped && isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->m_bHidden && !(*w)->m_bPinned) {
|
||||
// OR windows should add focus to parent
|
||||
if ((*w)->m_bX11ShouldntFocus && (*w)->m_iX11Type != 2)
|
||||
continue;
|
||||
|
||||
if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y)) {
|
||||
|
||||
if ((*w)->m_iX11Type == 2) {
|
||||
// Override Redirect
|
||||
return g_pCompositor->m_pLastWindow; // we kinda trick everything here.
|
||||
// TODO: this is wrong, we should focus the parent, but idk how to get it considering it's nullptr in most cases.
|
||||
}
|
||||
|
||||
return w->get();
|
||||
}
|
||||
|
||||
if (!(*w)->m_bIsX11) {
|
||||
wlr_surface* resultSurf = nullptr;
|
||||
@@ -547,10 +614,17 @@ CWindow* CCompositor::windowFromCursor() {
|
||||
}
|
||||
}
|
||||
|
||||
// pinned
|
||||
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 (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && (*w)->m_bIsMapped && (*w)->m_bIsFloating && (*w)->m_bPinned)
|
||||
return w->get();
|
||||
}
|
||||
|
||||
// first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter.
|
||||
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 (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && (*w)->m_bIsMapped && (*w)->m_bIsFloating && isWorkspaceVisible((*w)->m_iWorkspaceID))
|
||||
if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && (*w)->m_bIsMapped && (*w)->m_bIsFloating && isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->m_bPinned)
|
||||
return w->get();
|
||||
}
|
||||
|
||||
@@ -566,7 +640,13 @@ CWindow* CCompositor::windowFromCursor() {
|
||||
CWindow* CCompositor::windowFloatingFromCursor() {
|
||||
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 (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && (*w)->m_bIsMapped && (*w)->m_bIsFloating && isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->m_bHidden)
|
||||
if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && (*w)->m_bIsMapped && (*w)->m_bIsFloating && !(*w)->m_bHidden && (*w)->m_bPinned)
|
||||
return w->get();
|
||||
}
|
||||
|
||||
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 (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && (*w)->m_bIsMapped && (*w)->m_bIsFloating && isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->m_bHidden && !(*w)->m_bPinned)
|
||||
return w->get();
|
||||
}
|
||||
|
||||
@@ -635,6 +715,8 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
|
||||
|
||||
wlr_seat_keyboard_notify_clear_focus(m_sSeat.seat);
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","});
|
||||
|
||||
m_pLastFocus = nullptr;
|
||||
return;
|
||||
}
|
||||
@@ -647,6 +729,9 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
|
||||
if (m_pLastWindow == pWindow && m_sSeat.seat->keyboard_state.focused_surface == pSurface)
|
||||
return;
|
||||
|
||||
if (pWindow->m_bPinned)
|
||||
pWindow->m_iWorkspaceID = m_pLastMonitor->activeWorkspace;
|
||||
|
||||
if (!isWorkspaceVisible(pWindow->m_iWorkspaceID))
|
||||
g_pKeybindManager->changeworkspace("[internal]" + std::to_string(pWindow->m_iWorkspaceID));
|
||||
|
||||
@@ -756,7 +841,7 @@ CWindow* CCompositor::getWindowForPopup(wlr_xdg_popup* popup) {
|
||||
|
||||
wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector<std::unique_ptr<SLayerSurface>>* layerSurfaces, Vector2D* sCoords, SLayerSurface** ppLayerSurfaceFound) {
|
||||
for (auto it = layerSurfaces->rbegin(); it != layerSurfaces->rend(); it++) {
|
||||
if ((*it)->fadingOut || !(*it)->layerSurface || ((*it)->layerSurface && !(*it)->layerSurface->mapped))
|
||||
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);
|
||||
@@ -876,12 +961,35 @@ void CCompositor::moveWindowToTop(CWindow* pWindow) {
|
||||
if (!windowValidMapped(pWindow))
|
||||
return;
|
||||
|
||||
auto moveToTop = [&](CWindow* pw) -> void {
|
||||
for (auto it = m_vWindows.begin(); it != m_vWindows.end(); ++it) {
|
||||
if (it->get() == pWindow) {
|
||||
if (it->get() == pw) {
|
||||
std::rotate(it, it + 1, m_vWindows.end());
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
moveToTop(pWindow);
|
||||
|
||||
if (!pWindow->m_bIsX11)
|
||||
return;
|
||||
|
||||
// move all children
|
||||
|
||||
std::deque<CWindow*> toMove;
|
||||
|
||||
for (auto& w : m_vWindows) {
|
||||
if (w->m_bIsMapped && w->m_bMappedX11 && !w->m_bHidden && w->m_bIsX11 && w->X11TransientFor() == pWindow) {
|
||||
toMove.emplace_back(w.get());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& pw : toMove) {
|
||||
moveToTop(pw);
|
||||
|
||||
moveWindowToTop(pw);
|
||||
}
|
||||
}
|
||||
|
||||
void CCompositor::cleanupFadingOut(const int& monid) {
|
||||
@@ -1006,7 +1114,7 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
|
||||
switch (dir) {
|
||||
case 'l':
|
||||
if (STICKS(POSA.x, POSB.x + SIZEB.x)) {
|
||||
const auto INTERSECTLEN = std::max((double)0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y));
|
||||
const auto INTERSECTLEN = std::max(0.0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y));
|
||||
if (INTERSECTLEN > longestIntersect) {
|
||||
longestIntersect = INTERSECTLEN;
|
||||
longestIntersectWindow = w.get();
|
||||
@@ -1015,7 +1123,7 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
|
||||
break;
|
||||
case 'r':
|
||||
if (STICKS(POSA.x + SIZEA.x, POSB.x)) {
|
||||
const auto INTERSECTLEN = std::max((double)0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y));
|
||||
const auto INTERSECTLEN = std::max(0.0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y));
|
||||
if (INTERSECTLEN > longestIntersect) {
|
||||
longestIntersect = INTERSECTLEN;
|
||||
longestIntersectWindow = w.get();
|
||||
@@ -1025,7 +1133,7 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
|
||||
case 't':
|
||||
case 'u':
|
||||
if (STICKS(POSA.y, POSB.y + SIZEB.y)) {
|
||||
const auto INTERSECTLEN = std::max((double)0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x));
|
||||
const auto INTERSECTLEN = std::max(0.0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x));
|
||||
if (INTERSECTLEN > longestIntersect) {
|
||||
longestIntersect = INTERSECTLEN;
|
||||
longestIntersectWindow = w.get();
|
||||
@@ -1035,7 +1143,7 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
|
||||
case 'b':
|
||||
case 'd':
|
||||
if (STICKS(POSA.y + SIZEA.y, POSB.y)) {
|
||||
const auto INTERSECTLEN = std::max((double)0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x));
|
||||
const auto INTERSECTLEN = std::max(0.0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x));
|
||||
if (INTERSECTLEN > longestIntersect) {
|
||||
longestIntersect = INTERSECTLEN;
|
||||
longestIntersectWindow = w.get();
|
||||
@@ -1058,7 +1166,7 @@ void CCompositor::deactivateAllWLRWorkspaces(wlr_ext_workspace_handle_v1* exclud
|
||||
}
|
||||
}
|
||||
|
||||
CWindow* CCompositor::getNextWindowOnWorkspace(CWindow* pWindow) {
|
||||
CWindow* CCompositor::getNextWindowOnWorkspace(CWindow* pWindow, bool focusableOnly) {
|
||||
bool gotToWindow = false;
|
||||
for (auto& w : m_vWindows) {
|
||||
if (w.get() != pWindow && !gotToWindow)
|
||||
@@ -1069,19 +1177,19 @@ CWindow* CCompositor::getNextWindowOnWorkspace(CWindow* pWindow) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->m_bHidden)
|
||||
if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->m_bHidden && (!focusableOnly || !w->m_bNoFocus))
|
||||
return w.get();
|
||||
}
|
||||
|
||||
for (auto& w : m_vWindows) {
|
||||
if (w.get() != pWindow && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->m_bHidden)
|
||||
if (w.get() != pWindow && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->m_bHidden && (!focusableOnly || !w->m_bNoFocus))
|
||||
return w.get();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CWindow* CCompositor::getPrevWindowOnWorkspace(CWindow* pWindow) {
|
||||
CWindow* CCompositor::getPrevWindowOnWorkspace(CWindow* pWindow, bool focusableOnly) {
|
||||
bool gotToWindow = false;
|
||||
for (auto it = m_vWindows.rbegin(); it != m_vWindows.rend(); it++) {
|
||||
if (it->get() != pWindow && !gotToWindow)
|
||||
@@ -1092,12 +1200,12 @@ CWindow* CCompositor::getPrevWindowOnWorkspace(CWindow* pWindow) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((*it)->m_iWorkspaceID == pWindow->m_iWorkspaceID && (*it)->m_bIsMapped && !(*it)->m_bHidden)
|
||||
if ((*it)->m_iWorkspaceID == pWindow->m_iWorkspaceID && (*it)->m_bIsMapped && !(*it)->m_bHidden && (!focusableOnly || !(*it)->m_bNoFocus))
|
||||
return it->get();
|
||||
}
|
||||
|
||||
for (auto it = m_vWindows.rbegin(); it != m_vWindows.rend(); it++) {
|
||||
if (it->get() != pWindow && (*it)->m_iWorkspaceID == pWindow->m_iWorkspaceID && (*it)->m_bIsMapped && !(*it)->m_bHidden)
|
||||
if (it->get() != pWindow && (*it)->m_iWorkspaceID == pWindow->m_iWorkspaceID && (*it)->m_bIsMapped && !(*it)->m_bHidden && (!focusableOnly || !(*it)->m_bNoFocus))
|
||||
return it->get();
|
||||
}
|
||||
|
||||
@@ -1181,7 +1289,7 @@ CMonitor* CCompositor::getMonitorInDirection(const char& dir) {
|
||||
switch (dir) {
|
||||
case 'l':
|
||||
if (STICKS(POSA.x, POSB.x + SIZEB.x)) {
|
||||
const auto INTERSECTLEN = std::max((double)0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y));
|
||||
const auto INTERSECTLEN = std::max(0.0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y));
|
||||
if (INTERSECTLEN > longestIntersect) {
|
||||
longestIntersect = INTERSECTLEN;
|
||||
longestIntersectMonitor = m.get();
|
||||
@@ -1190,7 +1298,7 @@ CMonitor* CCompositor::getMonitorInDirection(const char& dir) {
|
||||
break;
|
||||
case 'r':
|
||||
if (STICKS(POSA.x + SIZEA.x, POSB.x)) {
|
||||
const auto INTERSECTLEN = std::max((double)0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y));
|
||||
const auto INTERSECTLEN = std::max(0.0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y));
|
||||
if (INTERSECTLEN > longestIntersect) {
|
||||
longestIntersect = INTERSECTLEN;
|
||||
longestIntersectMonitor = m.get();
|
||||
@@ -1200,7 +1308,7 @@ CMonitor* CCompositor::getMonitorInDirection(const char& dir) {
|
||||
case 't':
|
||||
case 'u':
|
||||
if (STICKS(POSA.y, POSB.y + SIZEB.y)) {
|
||||
const auto INTERSECTLEN = std::max((double)0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x));
|
||||
const auto INTERSECTLEN = std::max(0.0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x));
|
||||
if (INTERSECTLEN > longestIntersect) {
|
||||
longestIntersect = INTERSECTLEN;
|
||||
longestIntersectMonitor = m.get();
|
||||
@@ -1210,7 +1318,7 @@ CMonitor* CCompositor::getMonitorInDirection(const char& dir) {
|
||||
case 'b':
|
||||
case 'd':
|
||||
if (STICKS(POSA.y + SIZEA.y, POSB.y)) {
|
||||
const auto INTERSECTLEN = std::max((double)0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x));
|
||||
const auto INTERSECTLEN = std::max(0.0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x));
|
||||
if (INTERSECTLEN > longestIntersect) {
|
||||
longestIntersect = INTERSECTLEN;
|
||||
longestIntersectMonitor = m.get();
|
||||
@@ -1244,6 +1352,7 @@ void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
|
||||
static auto *const PFULLSCREENALPHA = &g_pConfigManager->getConfigValuePtr("decoration:fullscreen_opacity")->floatValue;
|
||||
static auto *const PSHADOWCOL = &g_pConfigManager->getConfigValuePtr("decoration:col.shadow")->intValue;
|
||||
static auto *const PSHADOWCOLINACTIVE = &g_pConfigManager->getConfigValuePtr("decoration:col.shadow_inactive")->intValue;
|
||||
static auto *const PDIMSTRENGTH = &g_pConfigManager->getConfigValuePtr("decoration:dim_strength")->floatValue;
|
||||
|
||||
// border
|
||||
const auto RENDERDATA = g_pLayoutManager->getCurrentLayout()->requestRenderHints(pWindow);
|
||||
@@ -1272,6 +1381,13 @@ void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
|
||||
pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaInactive != -1 ? pWindow->m_sSpecialRenderData.alphaInactive * *PINACTIVEALPHA : *PINACTIVEALPHA;
|
||||
}
|
||||
|
||||
// dim
|
||||
if (pWindow == m_pLastWindow) {
|
||||
pWindow->m_fDimPercent = 0;
|
||||
} else {
|
||||
pWindow->m_fDimPercent = *PDIMSTRENGTH;
|
||||
}
|
||||
|
||||
// shadow
|
||||
if (pWindow->m_iX11Type != 2 && !pWindow->m_bX11DoesntWantBorders) {
|
||||
if (pWindow == m_pLastWindow) {
|
||||
@@ -1284,13 +1400,6 @@ void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
|
||||
}
|
||||
}
|
||||
|
||||
void CCompositor::moveWindowToWorkspace(CWindow* pWindow, const std::string& work) {
|
||||
m_pLastWindow = pWindow;
|
||||
g_pKeybindManager->moveActiveToWorkspace(work);
|
||||
|
||||
g_pInputManager->refocus();
|
||||
}
|
||||
|
||||
int CCompositor::getNextAvailableMonitorID() {
|
||||
int64_t topID = -1;
|
||||
for (auto& m : m_vRealMonitors) {
|
||||
@@ -1301,6 +1410,114 @@ int CCompositor::getNextAvailableMonitorID() {
|
||||
return topID + 1;
|
||||
}
|
||||
|
||||
void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB) {
|
||||
|
||||
const auto PWORKSPACEA = g_pCompositor->getWorkspaceByID(pMonitorA->activeWorkspace);
|
||||
const auto PWORKSPACEB = g_pCompositor->getWorkspaceByID(pMonitorB->activeWorkspace);
|
||||
|
||||
PWORKSPACEA->m_iMonitorID = pMonitorB->ID;
|
||||
PWORKSPACEA->moveToMonitor(pMonitorB->ID);
|
||||
|
||||
for (auto& w : m_vWindows) {
|
||||
if (w->m_iWorkspaceID == PWORKSPACEA->m_iID) {
|
||||
w->m_iMonitorID = pMonitorB->ID;
|
||||
|
||||
// additionally, move floating and fs windows manually
|
||||
if (w->m_bIsFloating)
|
||||
w->m_vRealPosition = w->m_vRealPosition.vec() - pMonitorA->vecPosition + pMonitorB->vecPosition;
|
||||
|
||||
if (w->m_bIsFullscreen) {
|
||||
w->m_vRealPosition = pMonitorB->vecPosition;
|
||||
w->m_vRealSize = pMonitorB->vecSize;
|
||||
}
|
||||
|
||||
w->updateToplevel();
|
||||
}
|
||||
}
|
||||
|
||||
PWORKSPACEB->m_iMonitorID = pMonitorA->ID;
|
||||
PWORKSPACEB->moveToMonitor(pMonitorA->ID);
|
||||
|
||||
for (auto& w : m_vWindows) {
|
||||
if (w->m_iWorkspaceID == PWORKSPACEB->m_iID) {
|
||||
w->m_iMonitorID = pMonitorA->ID;
|
||||
|
||||
// additionally, move floating and fs windows manually
|
||||
if (w->m_bIsFloating)
|
||||
w->m_vRealPosition = w->m_vRealPosition.vec() - pMonitorB->vecPosition + pMonitorA->vecPosition;
|
||||
|
||||
if (w->m_bIsFullscreen) {
|
||||
w->m_vRealPosition = pMonitorA->vecPosition;
|
||||
w->m_vRealSize = pMonitorA->vecSize;
|
||||
}
|
||||
|
||||
w->updateToplevel();
|
||||
}
|
||||
}
|
||||
|
||||
// fix pinned windows
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_iWorkspaceID == pMonitorA->activeWorkspace && w->m_bPinned) {
|
||||
w->m_iWorkspaceID = PWORKSPACEB->m_iID;
|
||||
}
|
||||
|
||||
if (w->m_iWorkspaceID == pMonitorB->activeWorkspace && w->m_bPinned) {
|
||||
w->m_iWorkspaceID = PWORKSPACEA->m_iID;
|
||||
}
|
||||
}
|
||||
|
||||
pMonitorA->activeWorkspace = PWORKSPACEB->m_iID;
|
||||
pMonitorB->activeWorkspace = PWORKSPACEA->m_iID;
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(pMonitorA->ID);
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(pMonitorB->ID);
|
||||
|
||||
g_pInputManager->refocus();
|
||||
|
||||
// event
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", PWORKSPACEA->m_szName + "," + pMonitorB->szName});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", PWORKSPACEB->m_szName + "," + pMonitorA->szName});
|
||||
}
|
||||
|
||||
CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
|
||||
if (isNumber(name)) {
|
||||
// change by ID
|
||||
int monID = -1;
|
||||
try {
|
||||
monID = std::stoi(name);
|
||||
} catch (std::exception& e) {
|
||||
// shouldn't happen but jic
|
||||
Debug::log(ERR, "Error in getMonitorFromString: invalid num");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (monID > -1 && monID < (int)g_pCompositor->m_vMonitors.size()) {
|
||||
return g_pCompositor->getMonitorFromID(monID);
|
||||
} else {
|
||||
Debug::log(ERR, "Error in getMonitorFromString: invalid arg 1");
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
if (name == "current")
|
||||
return g_pCompositor->m_pLastMonitor;
|
||||
|
||||
if (isDirection(name)) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorInDirection(name[0]);
|
||||
return PMONITOR;
|
||||
} else {
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
if (m->szName == name) {
|
||||
return m.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Debug::log(ERR, "Error in getMonitorFromString: no such monitor");
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMonitor) {
|
||||
|
||||
// We trust the workspace and monitor to be correct.
|
||||
@@ -1346,9 +1563,15 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
|
||||
if (w->m_iWorkspaceID == pWorkspace->m_iID) {
|
||||
w->m_iMonitorID = pMonitor->ID;
|
||||
|
||||
// additionally, move floating windows manually
|
||||
if (w->m_bIsFloating && w->m_bIsMapped && !w->m_bHidden) {
|
||||
// additionally, move floating and fs windows manually
|
||||
if (w->m_bIsMapped && !w->m_bHidden) {
|
||||
if (w->m_bIsFloating)
|
||||
w->m_vRealPosition = w->m_vRealPosition.vec() - POLDMON->vecPosition + pMonitor->vecPosition;
|
||||
|
||||
if (w->m_bIsFullscreen) {
|
||||
w->m_vRealPosition = pMonitor->vecPosition;
|
||||
w->m_vRealSize = pMonitor->vecSize;
|
||||
}
|
||||
}
|
||||
|
||||
w->updateToplevel();
|
||||
@@ -1373,6 +1596,9 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(POLDMON->ID);
|
||||
|
||||
g_pInputManager->refocus();
|
||||
|
||||
// event
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", pWorkspace->m_szName + "," + pMonitor->szName});
|
||||
}
|
||||
|
||||
bool CCompositor::workspaceIDOutOfBounds(const int& id) {
|
||||
@@ -1380,6 +1606,9 @@ bool CCompositor::workspaceIDOutOfBounds(const int& id) {
|
||||
int highestID = -99999;
|
||||
|
||||
for (auto& w : m_vWorkspaces) {
|
||||
if (w->m_iID == SPECIAL_WORKSPACE_ID)
|
||||
continue;
|
||||
|
||||
if (w->m_iID < lowestID)
|
||||
lowestID = w->m_iID;
|
||||
|
||||
@@ -1394,7 +1623,19 @@ void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode
|
||||
if (!windowValidMapped(pWindow))
|
||||
return;
|
||||
|
||||
focusWindow(pWindow);
|
||||
if (pWindow->m_bPinned) {
|
||||
Debug::log(LOG, "Pinned windows cannot be fullscreen'd");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto PMONITOR = getMonitorFromID(pWindow->m_iMonitorID);
|
||||
|
||||
const auto PWORKSPACE = getWorkspaceByID(pWindow->m_iWorkspaceID);
|
||||
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow && on) {
|
||||
Debug::log(LOG, "Rejecting fullscreen ON on a fullscreen workspace");
|
||||
return;
|
||||
}
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(pWindow, mode, on);
|
||||
|
||||
@@ -1402,11 +1643,21 @@ void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode
|
||||
|
||||
// make all windows on the same workspace under the fullscreen window
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID)
|
||||
if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID) {
|
||||
w->m_bCreatedOverFullscreen = false;
|
||||
if (w.get() != pWindow && !w->m_bFadingOut && !w->m_bPinned)
|
||||
w->m_fAlpha = pWindow->m_bIsFullscreen && mode == FULLSCREEN_FULL ? 0.f : 255.f;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
|
||||
if (!ls->fadingOut)
|
||||
ls->alpha = pWindow->m_bIsFullscreen && mode == FULLSCREEN_FULL ? 0.f : 255.f;
|
||||
}
|
||||
|
||||
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv(), true);
|
||||
|
||||
forceReportSizesToWindowsOnWorkspace(pWindow->m_iWorkspaceID);
|
||||
}
|
||||
|
||||
void CCompositor::moveUnmanagedX11ToWindows(CWindow* pWindow) {
|
||||
@@ -1505,25 +1756,6 @@ CWindow* CCompositor::getWindowByRegex(const std::string& regexp) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
wl_event_source* hyprCtlTickSource = nullptr;
|
||||
|
||||
int hyprCtlTick(void* data) {
|
||||
HyprCtl::tickHyprCtl(); // so that we dont get that race condition multithread bullshit
|
||||
|
||||
wl_event_source_timer_update(hyprCtlTickSource, 16); // tick it 60/s, should be enough.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CCompositor::startHyprCtlTick() {
|
||||
if (hyprCtlTickSource)
|
||||
return;
|
||||
|
||||
hyprCtlTickSource = wl_event_loop_add_timer(m_sWLEventLoop, hyprCtlTick, nullptr);
|
||||
|
||||
wl_event_source_timer_update(hyprCtlTickSource, 16);
|
||||
}
|
||||
|
||||
void CCompositor::warpCursorTo(const Vector2D& pos) {
|
||||
|
||||
// warpCursorTo should only be used for warps that
|
||||
@@ -1535,6 +1767,10 @@ void CCompositor::warpCursorTo(const Vector2D& pos) {
|
||||
return;
|
||||
|
||||
wlr_cursor_warp(m_sWLRCursor, m_sSeat.mouse->mouse, pos.x, pos.y);
|
||||
|
||||
const auto PMONITORNEW = getMonitorFromVector(pos);
|
||||
if (PMONITORNEW != m_pLastMonitor)
|
||||
m_pLastMonitor = PMONITORNEW;
|
||||
}
|
||||
|
||||
SLayerSurface* CCompositor::getLayerSurfaceFromWlr(wlr_layer_surface_v1* pLS) {
|
||||
@@ -1553,13 +1789,6 @@ SLayerSurface* CCompositor::getLayerSurfaceFromWlr(wlr_layer_surface_v1* pLS) {
|
||||
void CCompositor::closeWindow(CWindow* pWindow) {
|
||||
if (pWindow && windowValidMapped(pWindow)) {
|
||||
g_pXWaylandManager->sendCloseWindow(pWindow);
|
||||
|
||||
if (pWindow == m_pLastWindow) {
|
||||
m_pLastFocus = nullptr;
|
||||
m_pLastWindow = nullptr;
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","}); // post an activewindow event to empty, as we are currently unfocused
|
||||
focusWindow(windowFromCursor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1614,3 +1843,22 @@ Vector2D CCompositor::parseWindowVectorArgsRelative(const std::string& args, con
|
||||
|
||||
return Vector2D(X + relativeTo.x, Y + relativeTo.y);
|
||||
}
|
||||
|
||||
void CCompositor::forceReportSizesToWindowsOnWorkspace(const int& wid) {
|
||||
for (auto& w : m_vWindows) {
|
||||
if (w->m_iWorkspaceID == wid && w->m_bIsMapped && !w->m_bHidden) {
|
||||
g_pXWaylandManager->setWindowSize(w.get(), w->m_vRealSize.vec(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CCompositor::cursorOnReservedArea() {
|
||||
const auto PMONITOR = getMonitorFromCursor();
|
||||
|
||||
const auto XY1 = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
|
||||
const auto XY2 = PMONITOR->vecPosition + PMONITOR->vecSize - PMONITOR->vecReservedBottomRight;
|
||||
|
||||
const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal();
|
||||
|
||||
return !VECINRECT(CURSORPOS, XY1.x, XY1.y, XY2.x, XY2.y);
|
||||
}
|
||||
|
@@ -38,6 +38,8 @@ public:
|
||||
wlr_compositor* m_sWLRCompositor;
|
||||
wlr_subcompositor* m_sWLRSubCompositor;
|
||||
wlr_data_device_manager* m_sWLRDataDevMgr;
|
||||
wlr_drm* m_sWRLDRM;
|
||||
wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr;
|
||||
wlr_xdg_activation_v1* m_sWLRXDGActivation;
|
||||
wlr_output_layout* m_sWLROutputLayout;
|
||||
wlr_idle* m_sWLRIdle;
|
||||
@@ -54,7 +56,6 @@ public:
|
||||
wlr_egl* m_sWLREGL;
|
||||
int m_iDRMFD;
|
||||
wlr_ext_workspace_manager_v1* m_sWLREXTWorkspaceMgr;
|
||||
wlr_linux_dmabuf_v1* m_sWLRDmabuf;
|
||||
wlr_pointer_constraints_v1* m_sWLRPointerConstraints;
|
||||
wlr_relative_pointer_manager_v1* m_sWLRRelPointerMgr;
|
||||
wlr_server_decoration_manager* m_sWLRServerDecoMgr;
|
||||
@@ -98,6 +99,8 @@ public:
|
||||
bool m_bSessionActive = true;
|
||||
bool m_bDPMSStateON = true;
|
||||
bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
|
||||
bool m_bIsShuttingDown = false;
|
||||
std::deque<uint64_t> m_dProcessPIDsOnShutdown; // stores PIDs of apps to kill later when shutting down
|
||||
|
||||
// ------------------------------------------------- //
|
||||
|
||||
@@ -135,17 +138,18 @@ public:
|
||||
void cleanupFadingOut(const int& monid);
|
||||
CWindow* getWindowInDirection(CWindow*, char);
|
||||
void deactivateAllWLRWorkspaces(wlr_ext_workspace_handle_v1* exclude = nullptr);
|
||||
CWindow* getNextWindowOnWorkspace(CWindow*);
|
||||
CWindow* getPrevWindowOnWorkspace(CWindow*);
|
||||
CWindow* getNextWindowOnWorkspace(CWindow*, bool focusableOnly = false);
|
||||
CWindow* getPrevWindowOnWorkspace(CWindow*, bool focusableOnly = false);
|
||||
int getNextAvailableNamedWorkspace();
|
||||
bool isPointOnAnyMonitor(const Vector2D&);
|
||||
CWindow* getConstraintWindow(SMouse*);
|
||||
CMonitor* getMonitorInDirection(const char&);
|
||||
void updateAllWindowsAnimatedDecorationValues();
|
||||
void updateWindowAnimatedDecorationValues(CWindow*);
|
||||
void moveWindowToWorkspace(CWindow*, const std::string&);
|
||||
int getNextAvailableMonitorID();
|
||||
void moveWorkspaceToMonitor(CWorkspace*, CMonitor*);
|
||||
void swapActiveWorkspaces(CMonitor*, CMonitor*);
|
||||
CMonitor* getMonitorFromString(const std::string&);
|
||||
bool workspaceIDOutOfBounds(const int&);
|
||||
void setWindowFullscreen(CWindow*, bool, eFullscreenMode);
|
||||
void moveUnmanagedX11ToWindows(CWindow*);
|
||||
@@ -159,15 +163,16 @@ public:
|
||||
SLayerSurface* getLayerSurfaceFromSurface(wlr_surface*);
|
||||
void closeWindow(CWindow*);
|
||||
Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&);
|
||||
|
||||
void forceReportSizesToWindowsOnWorkspace(const int&);
|
||||
bool cursorOnReservedArea();
|
||||
|
||||
std::string explicitConfigPath;
|
||||
|
||||
void startHyprCtlTick();
|
||||
|
||||
private:
|
||||
void initAllSignals();
|
||||
void setRandomSplash();
|
||||
|
||||
uint64_t m_iHyprlandPID = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@@ -9,6 +9,7 @@ CWindow::CWindow() {
|
||||
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);
|
||||
m_fDimPercent.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||
|
||||
m_dWindowDecorations.emplace_back(std::make_unique<CHyprDropShadowDecoration>(this)); // put the shadow so it's the first deco (has to be rendered first)
|
||||
}
|
||||
@@ -21,9 +22,9 @@ CWindow::~CWindow() {
|
||||
}
|
||||
|
||||
wlr_box CWindow::getFullWindowBoundingBox() {
|
||||
static auto* const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
|
||||
static auto *const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
|
||||
|
||||
SWindowDecorationExtents maxExtents = {{*PBORDERSIZE + 1, *PBORDERSIZE + 1}, {*PBORDERSIZE + 1, *PBORDERSIZE + 1}};
|
||||
SWindowDecorationExtents maxExtents = {{*PBORDERSIZE + 2, *PBORDERSIZE + 2}, {*PBORDERSIZE + 2, *PBORDERSIZE + 2}};
|
||||
|
||||
for (auto& wd : m_dWindowDecorations) {
|
||||
|
||||
@@ -96,8 +97,7 @@ void CWindow::updateWindowDecos() {
|
||||
pid_t CWindow::getPID() {
|
||||
pid_t PID = -1;
|
||||
if (!m_bIsX11) {
|
||||
const auto CLIENT = wl_resource_get_client(m_uSurface.xdg->resource);
|
||||
wl_client_get_credentials(CLIENT, &PID, nullptr, nullptr);
|
||||
wl_client_get_credentials(wl_resource_get_client(m_uSurface.xdg->resource), &PID, nullptr, nullptr);
|
||||
} else {
|
||||
PID = m_uSurface.xwayland->pid;
|
||||
}
|
||||
@@ -206,3 +206,41 @@ void CWindow::updateSurfaceOutputs() {
|
||||
|
||||
wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(this), sendEnterIter, PNEWMONITOR->output);
|
||||
}
|
||||
|
||||
void CWindow::moveToWorkspace(int workspaceID) {
|
||||
if (m_iWorkspaceID != workspaceID) {
|
||||
m_iWorkspaceID = workspaceID;
|
||||
|
||||
if (const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID); PWORKSPACE) {
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"movewindow", getFormat("%x,%s", this, PWORKSPACE->m_szName.c_str())});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CWindow* CWindow::X11TransientFor() {
|
||||
if (!m_bIsX11)
|
||||
return nullptr;
|
||||
|
||||
if (!m_uSurface.xwayland->parent)
|
||||
return nullptr;
|
||||
|
||||
auto PPARENT = g_pCompositor->getWindowFromSurface(m_uSurface.xwayland->parent->surface);
|
||||
|
||||
while (g_pCompositor->windowValidMapped(PPARENT) && PPARENT->m_uSurface.xwayland->parent) {
|
||||
PPARENT = g_pCompositor->getWindowFromSurface(PPARENT->m_uSurface.xwayland->parent->surface);
|
||||
}
|
||||
|
||||
if (!g_pCompositor->windowValidMapped(PPARENT))
|
||||
return nullptr;
|
||||
|
||||
return PPARENT;
|
||||
}
|
||||
|
||||
void CWindow::removeDecorationByType(eDecorationType type) {
|
||||
for (auto& wd : m_dWindowDecorations) {
|
||||
if (wd->getDecorationType() == type)
|
||||
m_vDecosToRemove.push_back(wd.get());
|
||||
}
|
||||
|
||||
updateWindowDecos();
|
||||
}
|
||||
|
@@ -14,6 +14,7 @@ struct SWindowSpecialRenderData {
|
||||
// set by the layout
|
||||
bool rounding = true;
|
||||
bool border = true;
|
||||
bool decorate = true;
|
||||
};
|
||||
|
||||
struct SWindowAdditionalConfigData {
|
||||
@@ -21,6 +22,8 @@ struct SWindowAdditionalConfigData {
|
||||
int rounding = -1; // -1 means no
|
||||
bool forceNoBlur = false;
|
||||
bool forceOpaque = false;
|
||||
bool forceAllowsInput = false;
|
||||
bool forceNoAnims = false;
|
||||
};
|
||||
|
||||
class CWindow {
|
||||
@@ -100,6 +103,9 @@ public:
|
||||
bool m_bNoFocus = false;
|
||||
bool m_bNoInitialFocus = false;
|
||||
|
||||
// initial fullscreen
|
||||
bool m_bWantsInitialFullscreen = false;
|
||||
|
||||
SSurfaceTreeNode* m_pSurfaceTree = nullptr;
|
||||
|
||||
// Animated border
|
||||
@@ -115,6 +121,12 @@ public:
|
||||
// For hidden windows and stuff
|
||||
bool m_bHidden = false;
|
||||
|
||||
// For pinned (sticky) windows
|
||||
bool m_bPinned = false;
|
||||
|
||||
// for proper cycling. While cycling we can't just move the pointers, so we need to keep track of the last cycled window.
|
||||
CWindow* m_pLastCycledWindow = nullptr;
|
||||
|
||||
// Foreign Toplevel proto
|
||||
wlr_foreign_toplevel_handle_v1* m_phForeignToplevel = nullptr;
|
||||
|
||||
@@ -132,6 +144,12 @@ public:
|
||||
// animated shadow color
|
||||
CAnimatedVariable m_cRealShadowColor;
|
||||
|
||||
// animated tint
|
||||
CAnimatedVariable m_fDimPercent;
|
||||
|
||||
// swallowing
|
||||
CWindow* m_pSwallowed = nullptr;
|
||||
|
||||
// for toplevel monitor events
|
||||
uint64_t m_iLastToplevelMonitorID = -1;
|
||||
uint64_t m_iLastSurfaceMonitorID = -1;
|
||||
@@ -147,8 +165,11 @@ public:
|
||||
void updateWindowDecos();
|
||||
pid_t getPID();
|
||||
IHyprWindowDecoration* getDecorationByType(eDecorationType);
|
||||
void removeDecorationByType(eDecorationType);
|
||||
void createToplevelHandle();
|
||||
void destroyToplevelHandle();
|
||||
void updateToplevel();
|
||||
void updateSurfaceOutputs();
|
||||
void moveToWorkspace(int);
|
||||
CWindow* X11TransientFor();
|
||||
};
|
||||
|
@@ -57,6 +57,9 @@ void CConfigManager::setDefaultVars() {
|
||||
configValues["misc:always_follow_on_dnd"].intValue = 1;
|
||||
configValues["misc:layers_hog_keyboard_focus"].intValue = 1;
|
||||
configValues["misc:animate_manual_resizes"].intValue = 0;
|
||||
configValues["misc:disable_autoreload"].intValue = 0;
|
||||
configValues["misc:enable_swallow"].intValue = 0;
|
||||
configValues["misc:swallow_regex"].strValue = STRVAL_EMPTY;
|
||||
|
||||
configValues["debug:int"].intValue = 0;
|
||||
configValues["debug:log_damage"].intValue = 0;
|
||||
@@ -65,7 +68,7 @@ void CConfigManager::setDefaultVars() {
|
||||
configValues["debug:disable_logs"].intValue = 0;
|
||||
configValues["debug:disable_time"].intValue = 1;
|
||||
|
||||
configValues["decoration:rounding"].intValue = 1;
|
||||
configValues["decoration:rounding"].intValue = 0;
|
||||
configValues["decoration:blur"].intValue = 1;
|
||||
configValues["decoration:blur_size"].intValue = 8;
|
||||
configValues["decoration:blur_passes"].intValue = 1;
|
||||
@@ -80,9 +83,11 @@ void CConfigManager::setDefaultVars() {
|
||||
configValues["decoration:shadow_range"].intValue = 4;
|
||||
configValues["decoration:shadow_render_power"].intValue = 3;
|
||||
configValues["decoration:shadow_ignore_window"].intValue = 1;
|
||||
configValues["decoration:shadow_offset"].strValue = "0 0";
|
||||
configValues["decoration:shadow_offset"].vecValue = Vector2D();
|
||||
configValues["decoration:col.shadow"].intValue = 0xee1a1a1a;
|
||||
configValues["decoration:col.shadow_inactive"].intValue = INT_MAX;
|
||||
configValues["decoration:dim_inactive"].intValue = 0;
|
||||
configValues["decoration:dim_strength"].floatValue = 0.5f;
|
||||
|
||||
configValues["dwindle:pseudotile"].intValue = 0;
|
||||
configValues["dwindle:col.group_border"].intValue = 0x66777700;
|
||||
@@ -120,6 +125,7 @@ void CConfigManager::setDefaultVars() {
|
||||
configValues["animations:workspaces"].intValue = 1;
|
||||
|
||||
configValues["input:sensitivity"].floatValue = 0.f;
|
||||
configValues["input:accel_profile"].strValue = STRVAL_EMPTY;
|
||||
configValues["input:kb_file"].strValue = STRVAL_EMPTY;
|
||||
configValues["input:kb_layout"].strValue = "us";
|
||||
configValues["input:kb_variant"].strValue = STRVAL_EMPTY;
|
||||
@@ -131,15 +137,21 @@ void CConfigManager::setDefaultVars() {
|
||||
configValues["input:natural_scroll"].intValue = 0;
|
||||
configValues["input:numlock_by_default"].intValue = 0;
|
||||
configValues["input:force_no_accel"].intValue = 0;
|
||||
configValues["input:float_switch_override_focus"].intValue = 1;
|
||||
configValues["input:left_handed"].intValue = 0;
|
||||
configValues["input:scroll_method"].strValue = STRVAL_EMPTY;
|
||||
configValues["input:touchpad:natural_scroll"].intValue = 0;
|
||||
configValues["input:touchpad:disable_while_typing"].intValue = 1;
|
||||
configValues["input:touchpad:clickfinger_behavior"].intValue = 0;
|
||||
configValues["input:touchpad:middle_button_emulation"].intValue = 0;
|
||||
configValues["input:touchpad:tap-to-click"].intValue = 1;
|
||||
configValues["input:touchpad:drag_lock"].intValue = 0;
|
||||
configValues["input:touchpad:scroll_factor"].floatValue = 1.f;
|
||||
|
||||
configValues["binds:pass_mouse_when_bound"].intValue = 1;
|
||||
configValues["binds:pass_mouse_when_bound"].intValue = 0;
|
||||
configValues["binds:scroll_event_delay"].intValue = 300;
|
||||
configValues["binds:workspace_back_and_forth"].intValue = 0;
|
||||
configValues["binds:allow_workspace_cycles"].intValue = 0;
|
||||
|
||||
configValues["gestures:workspace_swipe"].intValue = 0;
|
||||
configValues["gestures:workspace_swipe_fingers"].intValue = 3;
|
||||
@@ -157,6 +169,7 @@ void CConfigManager::setDeviceDefaultVars(const std::string& dev) {
|
||||
auto& cfgValues = deviceConfigs[dev];
|
||||
|
||||
cfgValues["sensitivity"].floatValue = 0.f;
|
||||
cfgValues["accel_profile"].strValue = STRVAL_EMPTY;
|
||||
cfgValues["kb_file"].strValue = STRVAL_EMPTY;
|
||||
cfgValues["kb_layout"].strValue = "us";
|
||||
cfgValues["kb_variant"].strValue = STRVAL_EMPTY;
|
||||
@@ -172,6 +185,8 @@ void CConfigManager::setDeviceDefaultVars(const std::string& dev) {
|
||||
cfgValues["middle_button_emulation"].intValue = 0;
|
||||
cfgValues["tap-to-click"].intValue = 1;
|
||||
cfgValues["drag_lock"].intValue = 0;
|
||||
cfgValues["left_handed"].intValue = 0;
|
||||
cfgValues["scroll_method"].strValue = STRVAL_EMPTY;
|
||||
}
|
||||
|
||||
void CConfigManager::setDefaultAnimationVars() {
|
||||
@@ -192,10 +207,12 @@ void CConfigManager::setDefaultAnimationVars() {
|
||||
INITANIMCFG("fadeOut");
|
||||
INITANIMCFG("fadeSwitch");
|
||||
INITANIMCFG("fadeShadow");
|
||||
INITANIMCFG("fadeDim");
|
||||
|
||||
// border
|
||||
|
||||
// workspaces
|
||||
INITANIMCFG("specialWorkspace");
|
||||
}
|
||||
|
||||
// init the values
|
||||
@@ -222,6 +239,9 @@ void CConfigManager::setDefaultAnimationVars() {
|
||||
CREATEANIMCFG("fadeOut", "fade");
|
||||
CREATEANIMCFG("fadeSwitch", "fade");
|
||||
CREATEANIMCFG("fadeShadow", "fade");
|
||||
CREATEANIMCFG("fadeDim", "fade");
|
||||
|
||||
CREATEANIMCFG("specialWorkspace", "workspaces");
|
||||
}
|
||||
|
||||
void CConfigManager::init() {
|
||||
@@ -281,7 +301,7 @@ void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::s
|
||||
|
||||
CONFIGENTRY->set = true;
|
||||
|
||||
if (CONFIGENTRY->intValue != -1) {
|
||||
if (CONFIGENTRY->intValue != -INT64_MAX) {
|
||||
try {
|
||||
if (VALUE.find("0x") == 0) {
|
||||
// Values with 0x are hex
|
||||
@@ -298,7 +318,7 @@ 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->floatValue != -1) {
|
||||
} else if (CONFIGENTRY->floatValue != -__FLT_MAX__) {
|
||||
try {
|
||||
CONFIGENTRY->floatValue = stof(VALUE);
|
||||
} catch (...) {
|
||||
@@ -312,6 +332,23 @@ 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->vecValue != Vector2D(-__FLT_MAX__, -__FLT_MAX__)) {
|
||||
try {
|
||||
if (const auto SPACEPOS = VALUE.find(' '); SPACEPOS != std::string::npos) {
|
||||
const auto X = VALUE.substr(0, SPACEPOS);
|
||||
const auto Y = VALUE.substr(SPACEPOS + 1);
|
||||
|
||||
if (isNumber(X, true) && isNumber(Y, true)) {
|
||||
CONFIGENTRY->vecValue = Vector2D(std::stof(X), std::stof(Y));
|
||||
}
|
||||
} else {
|
||||
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
|
||||
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
|
||||
}
|
||||
} catch (...) {
|
||||
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
|
||||
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,6 +380,11 @@ void CConfigManager::handleRawExec(const std::string& command, const std::string
|
||||
if (child == 0) {
|
||||
// run in child
|
||||
grandchild = fork();
|
||||
|
||||
sigset_t set;
|
||||
sigemptyset(&set);
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
|
||||
if (grandchild == 0) {
|
||||
// run in grandchild
|
||||
close(socket[0]);
|
||||
@@ -375,35 +417,15 @@ void CConfigManager::handleMonitor(const std::string& command, const std::string
|
||||
// get the monitor config
|
||||
SMonitorRule newrule;
|
||||
|
||||
std::string curitem = "";
|
||||
const auto ARGS = CVarList(args);
|
||||
|
||||
std::string argZ = args;
|
||||
newrule.name = ARGS[0];
|
||||
|
||||
auto nextItem = [&]() {
|
||||
auto idx = argZ.find_first_of(',');
|
||||
|
||||
if (idx != std::string::npos) {
|
||||
curitem = argZ.substr(0, idx);
|
||||
argZ = argZ.substr(idx + 1);
|
||||
} else {
|
||||
curitem = argZ;
|
||||
argZ = "";
|
||||
}
|
||||
};
|
||||
|
||||
nextItem();
|
||||
|
||||
newrule.name = curitem;
|
||||
|
||||
nextItem();
|
||||
|
||||
if (curitem == "disable" || curitem == "disabled" || curitem == "addreserved" || curitem == "transform") {
|
||||
if (curitem == "disable" || curitem == "disabled")
|
||||
if (ARGS[1] == "disable" || ARGS[1] == "disabled" || ARGS[1] == "addreserved" || ARGS[1] == "transform") {
|
||||
if (ARGS[1] == "disable" || ARGS[1] == "disabled")
|
||||
newrule.disabled = true;
|
||||
else if (curitem == "transform") {
|
||||
nextItem();
|
||||
|
||||
wl_output_transform transform = (wl_output_transform)std::stoi(curitem);
|
||||
else if (ARGS[1] == "transform") {
|
||||
wl_output_transform transform = (wl_output_transform)std::stoi(ARGS[2]);
|
||||
|
||||
// overwrite if exists
|
||||
for (auto& r : m_dMonitorRules) {
|
||||
@@ -414,22 +436,14 @@ void CConfigManager::handleMonitor(const std::string& command, const std::string
|
||||
}
|
||||
|
||||
return;
|
||||
} else if (curitem == "addreserved") {
|
||||
nextItem();
|
||||
} else if (ARGS[1] == "addreserved") {
|
||||
int top = std::stoi(ARGS[2]);
|
||||
|
||||
int top = std::stoi(curitem);
|
||||
int bottom = std::stoi(ARGS[3]);
|
||||
|
||||
nextItem();
|
||||
int left = std::stoi(ARGS[4]);
|
||||
|
||||
int bottom = std::stoi(curitem);
|
||||
|
||||
nextItem();
|
||||
|
||||
int left = std::stoi(curitem);
|
||||
|
||||
nextItem();
|
||||
|
||||
int right = std::stoi(curitem);
|
||||
int right = std::stoi(ARGS[5]);
|
||||
|
||||
m_mAdditionalReservedAreas[newrule.name] = {top, bottom, left, right};
|
||||
|
||||
@@ -447,23 +461,25 @@ void CConfigManager::handleMonitor(const std::string& command, const std::string
|
||||
return;
|
||||
}
|
||||
|
||||
if (curitem.find("pref") == 0) {
|
||||
if (ARGS[1].find("pref") == 0) {
|
||||
newrule.resolution = Vector2D();
|
||||
} else if (ARGS[1].find("highrr") == 0) {
|
||||
newrule.resolution = Vector2D(-1,-1);
|
||||
} else if (ARGS[1].find("highres") == 0) {
|
||||
newrule.resolution = Vector2D(-1,-2);
|
||||
} else {
|
||||
newrule.resolution.x = stoi(curitem.substr(0, curitem.find_first_of('x')));
|
||||
newrule.resolution.y = stoi(curitem.substr(curitem.find_first_of('x') + 1, curitem.find_first_of('@')));
|
||||
newrule.resolution.x = stoi(ARGS[1].substr(0, ARGS[1].find_first_of('x')));
|
||||
newrule.resolution.y = stoi(ARGS[1].substr(ARGS[1].find_first_of('x') + 1, ARGS[1].find_first_of('@')));
|
||||
|
||||
if (curitem.contains("@"))
|
||||
newrule.refreshRate = stof(curitem.substr(curitem.find_first_of('@') + 1));
|
||||
if (ARGS[1].contains("@"))
|
||||
newrule.refreshRate = stof(ARGS[1].substr(ARGS[1].find_first_of('@') + 1));
|
||||
}
|
||||
|
||||
nextItem();
|
||||
|
||||
if (curitem.find("auto") == 0) {
|
||||
if (ARGS[2].find("auto") == 0) {
|
||||
newrule.offset = Vector2D(-1, -1);
|
||||
} else {
|
||||
newrule.offset.x = stoi(curitem.substr(0, curitem.find_first_of('x')));
|
||||
newrule.offset.y = stoi(curitem.substr(curitem.find_first_of('x') + 1));
|
||||
newrule.offset.x = stoi(ARGS[2].substr(0, ARGS[2].find_first_of('x')));
|
||||
newrule.offset.y = stoi(ARGS[2].substr(ARGS[2].find_first_of('x') + 1));
|
||||
|
||||
if (newrule.offset.x < 0 || newrule.offset.y < 0) {
|
||||
parseError = "invalid offset. Offset cannot be negative.";
|
||||
@@ -471,24 +487,28 @@ void CConfigManager::handleMonitor(const std::string& command, const std::string
|
||||
}
|
||||
}
|
||||
|
||||
nextItem();
|
||||
|
||||
newrule.scale = stof(curitem);
|
||||
newrule.scale = stof(ARGS[3]);
|
||||
|
||||
if (newrule.scale < 0.25f) {
|
||||
parseError = "not a valid scale.";
|
||||
newrule.scale = 1;
|
||||
}
|
||||
|
||||
nextItem();
|
||||
int argno = 4;
|
||||
|
||||
if (curitem != "") {
|
||||
// warning for old cfg
|
||||
Debug::log(ERR, "Error in parsing rule for %s, possibly old config!", newrule.name.c_str());
|
||||
parseError = "Error in setting monitor rule. Are you using the old syntax? Confront the wiki.";
|
||||
while (ARGS[argno] != "") {
|
||||
if (ARGS[argno] == "mirror") {
|
||||
newrule.mirrorOf = ARGS[argno + 1];
|
||||
argno++;
|
||||
} else {
|
||||
Debug::log(ERR, "Config error: invalid monitor syntax");
|
||||
parseError = "invalid syntax at \"" + ARGS[argno] + "\"";
|
||||
return;
|
||||
}
|
||||
|
||||
argno++;
|
||||
}
|
||||
|
||||
if (std::find_if(m_dMonitorRules.begin(), m_dMonitorRules.end(), [&](const auto& other) { return other.name == newrule.name; }) != m_dMonitorRules.end())
|
||||
m_dMonitorRules.erase(std::remove_if(m_dMonitorRules.begin(), m_dMonitorRules.end(), [&](const auto& other) { return other.name == newrule.name; }));
|
||||
|
||||
@@ -496,44 +516,27 @@ void CConfigManager::handleMonitor(const std::string& command, const std::string
|
||||
}
|
||||
|
||||
void CConfigManager::handleBezier(const std::string& command, const std::string& args) {
|
||||
std::string curitem = "";
|
||||
const auto ARGS = CVarList(args);
|
||||
|
||||
std::string argZ = args;
|
||||
std::string bezierName = ARGS[0];
|
||||
|
||||
auto nextItem = [&]() {
|
||||
auto idx = argZ.find_first_of(',');
|
||||
|
||||
if (idx != std::string::npos) {
|
||||
curitem = argZ.substr(0, idx);
|
||||
argZ = argZ.substr(idx + 1);
|
||||
} else {
|
||||
curitem = argZ;
|
||||
argZ = "";
|
||||
}
|
||||
};
|
||||
|
||||
nextItem();
|
||||
|
||||
std::string bezierName = curitem;
|
||||
|
||||
nextItem();
|
||||
if (curitem == "")
|
||||
if (ARGS[1] == "")
|
||||
parseError = "too few arguments";
|
||||
float p1x = std::stof(curitem);
|
||||
nextItem();
|
||||
if (curitem == "")
|
||||
float p1x = std::stof(ARGS[1]);
|
||||
|
||||
if (ARGS[2] == "")
|
||||
parseError = "too few arguments";
|
||||
float p1y = std::stof(curitem);
|
||||
nextItem();
|
||||
if (curitem == "")
|
||||
float p1y = std::stof(ARGS[2]);
|
||||
|
||||
if (ARGS[3] == "")
|
||||
parseError = "too few arguments";
|
||||
float p2x = std::stof(curitem);
|
||||
nextItem();
|
||||
if (curitem == "")
|
||||
float p2x = std::stof(ARGS[3]);
|
||||
|
||||
if (ARGS[4] == "")
|
||||
parseError = "too few arguments";
|
||||
float p2y = std::stof(curitem);
|
||||
nextItem();
|
||||
if (curitem != "")
|
||||
float p2y = std::stof(ARGS[4]);
|
||||
|
||||
if (ARGS[5] != "")
|
||||
parseError = "too many arguments";
|
||||
|
||||
g_pAnimationManager->addBezierWithName(bezierName, Vector2D(p1x, p1y), Vector2D(p2x, p2y));
|
||||
@@ -551,28 +554,12 @@ void CConfigManager::setAnimForChildren(SAnimationPropertyConfig *const ANIM) {
|
||||
};
|
||||
|
||||
void CConfigManager::handleAnimation(const std::string& command, const std::string& args) {
|
||||
std::string curitem = "";
|
||||
|
||||
std::string argZ = args;
|
||||
|
||||
auto nextItem = [&]() {
|
||||
auto idx = argZ.find_first_of(',');
|
||||
|
||||
if (idx != std::string::npos) {
|
||||
curitem = argZ.substr(0, idx);
|
||||
argZ = argZ.substr(idx + 1);
|
||||
} else {
|
||||
curitem = argZ;
|
||||
argZ = "";
|
||||
}
|
||||
};
|
||||
|
||||
nextItem();
|
||||
const auto ARGS = CVarList(args);
|
||||
|
||||
// Master on/off
|
||||
|
||||
// anim name
|
||||
const auto ANIMNAME = curitem;
|
||||
const auto ANIMNAME = ARGS[0];
|
||||
|
||||
const auto PANIM = animationConfig.find(ANIMNAME);
|
||||
|
||||
@@ -584,20 +571,16 @@ void CConfigManager::handleAnimation(const std::string& command, const std::stri
|
||||
PANIM->second.overriden = true;
|
||||
PANIM->second.pValues = &PANIM->second;
|
||||
|
||||
nextItem();
|
||||
|
||||
// on/off
|
||||
PANIM->second.internalEnabled = curitem == "1";
|
||||
PANIM->second.internalEnabled = ARGS[1] == "1";
|
||||
|
||||
if (curitem != "0" && curitem != "1") {
|
||||
if (ARGS[1] != "0" && ARGS[1] != "1") {
|
||||
parseError = "invalid animation on/off state";
|
||||
}
|
||||
|
||||
nextItem();
|
||||
|
||||
// speed
|
||||
if (isNumber(curitem, true)) {
|
||||
PANIM->second.internalSpeed = std::stof(curitem);
|
||||
if (isNumber(ARGS[2], true)) {
|
||||
PANIM->second.internalSpeed = std::stof(ARGS[2]);
|
||||
|
||||
if (PANIM->second.internalSpeed <= 0) {
|
||||
parseError = "invalid speed";
|
||||
@@ -608,23 +591,19 @@ void CConfigManager::handleAnimation(const std::string& command, const std::stri
|
||||
parseError = "invalid speed";
|
||||
}
|
||||
|
||||
nextItem();
|
||||
|
||||
// curve
|
||||
PANIM->second.internalBezier = curitem;
|
||||
PANIM->second.internalBezier = ARGS[3];
|
||||
|
||||
if (!g_pAnimationManager->bezierExists(curitem)) {
|
||||
if (!g_pAnimationManager->bezierExists(ARGS[3])) {
|
||||
parseError = "no such bezier";
|
||||
PANIM->second.internalBezier = "default";
|
||||
}
|
||||
|
||||
nextItem();
|
||||
|
||||
// style
|
||||
PANIM->second.internalStyle = curitem;
|
||||
PANIM->second.internalStyle = ARGS[4];
|
||||
|
||||
if (curitem != "") {
|
||||
const auto ERR = g_pAnimationManager->styleValidInConfigVar(ANIMNAME, curitem);
|
||||
if (ARGS[4] != "") {
|
||||
const auto ERR = g_pAnimationManager->styleValidInConfigVar(ANIMNAME, ARGS[4]);
|
||||
|
||||
if (ERR != "")
|
||||
parseError = ERR;
|
||||
@@ -642,15 +621,18 @@ void CConfigManager::handleBind(const std::string& command, const std::string& v
|
||||
bool locked = false;
|
||||
bool release = false;
|
||||
bool repeat = false;
|
||||
const auto ARGS = command.substr(4);
|
||||
bool mouse = false;
|
||||
const auto BINDARGS = command.substr(4);
|
||||
|
||||
for (auto& arg : ARGS) {
|
||||
for (auto& arg : BINDARGS) {
|
||||
if (arg == 'l') {
|
||||
locked = true;
|
||||
} else if (arg == 'r') {
|
||||
release = true;
|
||||
} else if (arg == 'e') {
|
||||
repeat = true;
|
||||
} else if (arg == 'm') {
|
||||
mouse = true;
|
||||
} else {
|
||||
parseError = "bind: invalid flag";
|
||||
return;
|
||||
@@ -662,19 +644,35 @@ void CConfigManager::handleBind(const std::string& command, const std::string& v
|
||||
return;
|
||||
}
|
||||
|
||||
auto valueCopy = value;
|
||||
if (mouse && (repeat || release || locked)) {
|
||||
parseError = "flag m is exclusive";
|
||||
return;
|
||||
}
|
||||
|
||||
const auto MOD = g_pKeybindManager->stringToModMask(valueCopy.substr(0, valueCopy.find_first_of(",")));
|
||||
const auto MODSTR = valueCopy.substr(0, valueCopy.find_first_of(","));
|
||||
valueCopy = valueCopy.substr(valueCopy.find_first_of(",") + 1);
|
||||
const auto ARGS = CVarList(value, 4);
|
||||
|
||||
const auto KEY = valueCopy.substr(0, valueCopy.find_first_of(","));
|
||||
valueCopy = valueCopy.substr(valueCopy.find_first_of(",") + 1);
|
||||
if ((ARGS.size() < 3 && !mouse) || (ARGS.size() < 3 && mouse)) {
|
||||
parseError = "bind: too few args";
|
||||
return;
|
||||
} else if ((ARGS.size() > 4 && !mouse) || (ARGS.size() > 3 && mouse)) {
|
||||
parseError = "bind: too many args";
|
||||
return;
|
||||
}
|
||||
|
||||
const auto HANDLER = valueCopy.substr(0, valueCopy.find_first_of(","));
|
||||
valueCopy = valueCopy.substr(valueCopy.find_first_of(",") + 1);
|
||||
const auto MOD = g_pKeybindManager->stringToModMask(ARGS[0]);
|
||||
const auto MODSTR = ARGS[0];
|
||||
|
||||
const auto COMMAND = valueCopy;
|
||||
const auto KEY = ARGS[1];
|
||||
|
||||
auto HANDLER = ARGS[2];
|
||||
|
||||
const auto COMMAND = mouse ? HANDLER : ARGS[3];
|
||||
|
||||
if (mouse)
|
||||
HANDLER = "mouse";
|
||||
|
||||
// to lower
|
||||
std::transform(HANDLER.begin(), HANDLER.end(), HANDLER.begin(), ::tolower);
|
||||
|
||||
const auto DISPATCHER = g_pKeybindManager->m_mDispatchers.find(HANDLER);
|
||||
|
||||
@@ -690,29 +688,54 @@ void CConfigManager::handleBind(const std::string& command, const std::string& v
|
||||
return;
|
||||
}
|
||||
|
||||
if (KEY != "") {
|
||||
if (isNumber(KEY) && std::stoi(KEY) > 9)
|
||||
g_pKeybindManager->addKeybind(SKeybind{"", std::stoi(KEY), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat});
|
||||
else
|
||||
g_pKeybindManager->addKeybind(SKeybind{KEY, -1, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat});
|
||||
if (KEY == "exclam" || KEY == "asciicircum" || KEY == "at") { // just some
|
||||
parseError = "Your config contains (probably) wrong keys. The SHIFT keysym behavior has changed after v0.10.3beta. Please consult the wiki (Advanced configuring -> binds)";
|
||||
return;
|
||||
}
|
||||
|
||||
if (KEY != "") {
|
||||
if (isNumber(KEY) && std::stoi(KEY) > 9)
|
||||
g_pKeybindManager->addKeybind(SKeybind{"", std::stoi(KEY), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse});
|
||||
else
|
||||
g_pKeybindManager->addKeybind(SKeybind{KEY, -1, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse});
|
||||
}
|
||||
}
|
||||
|
||||
void CConfigManager::handleUnbind(const std::string& command, const std::string& value) {
|
||||
auto valueCopy = value;
|
||||
const auto ARGS = CVarList(value);
|
||||
|
||||
const auto MOD = g_pKeybindManager->stringToModMask(valueCopy.substr(0, valueCopy.find_first_of(",")));
|
||||
valueCopy = valueCopy.substr(valueCopy.find_first_of(",") + 1);
|
||||
const auto MOD = g_pKeybindManager->stringToModMask(ARGS[0]);
|
||||
|
||||
const auto KEY = valueCopy;
|
||||
const auto KEY = ARGS[1];
|
||||
|
||||
g_pKeybindManager->removeKeybind(MOD, KEY);
|
||||
}
|
||||
|
||||
bool windowRuleValid(const std::string& RULE) {
|
||||
return !(RULE != "float"
|
||||
&& RULE != "tile"
|
||||
&& RULE.find("opacity") != 0
|
||||
&& RULE.find("move") != 0
|
||||
&& RULE.find("size") != 0
|
||||
&& RULE.find("minsize") != 0
|
||||
&& RULE.find("pseudo") != 0
|
||||
&& RULE.find("monitor") != 0
|
||||
&& RULE != "nofocus"
|
||||
&& RULE != "noblur"
|
||||
&& RULE != "center"
|
||||
&& RULE != "opaque"
|
||||
&& RULE != "forceinput"
|
||||
&& RULE != "fullscreen"
|
||||
&& RULE != "pin"
|
||||
&& RULE != "noanim"
|
||||
&& RULE.find("animation") != 0
|
||||
&& RULE.find("rounding") != 0
|
||||
&& RULE.find("workspace") != 0);
|
||||
}
|
||||
|
||||
void CConfigManager::handleWindowRule(const std::string& command, const std::string& value) {
|
||||
const auto RULE = value.substr(0, value.find_first_of(","));
|
||||
const auto VALUE = value.substr(value.find_first_of(",") + 1);
|
||||
const auto RULE = removeBeginEndSpacesTabs(value.substr(0, value.find_first_of(",")));
|
||||
const auto VALUE = removeBeginEndSpacesTabs(value.substr(value.find_first_of(",") + 1));
|
||||
|
||||
// check rule and value
|
||||
if (RULE == "" || VALUE == "") {
|
||||
@@ -720,33 +743,84 @@ void CConfigManager::handleWindowRule(const std::string& command, const std::str
|
||||
}
|
||||
|
||||
// verify we support a rule
|
||||
if (RULE != "float"
|
||||
&& RULE != "tile"
|
||||
&& RULE.find("opacity") != 0
|
||||
&& RULE.find("move") != 0
|
||||
&& RULE.find("size") != 0
|
||||
&& RULE.find("pseudo") != 0
|
||||
&& RULE.find("monitor") != 0
|
||||
&& RULE != "nofocus"
|
||||
&& RULE != "noblur"
|
||||
&& RULE != "center"
|
||||
&& RULE != "opaque"
|
||||
&& RULE != "fullscreen"
|
||||
&& RULE.find("animation") != 0
|
||||
&& RULE.find("rounding") != 0
|
||||
&& RULE.find("workspace") != 0) {
|
||||
if (!windowRuleValid(RULE)) {
|
||||
Debug::log(ERR, "Invalid rule found: %s", RULE.c_str());
|
||||
parseError = "Invalid rule found: " + RULE;
|
||||
return;
|
||||
}
|
||||
|
||||
m_dWindowRules.push_back({RULE, VALUE});
|
||||
}
|
||||
|
||||
void CConfigManager::handleWindowRuleV2(const std::string& command, const std::string& value) {
|
||||
const auto RULE = value.substr(0, value.find_first_of(","));
|
||||
const auto VALUE = value.substr(value.find_first_of(",") + 1);
|
||||
|
||||
if (!windowRuleValid(RULE)) {
|
||||
Debug::log(ERR, "Invalid rulev2 found: %s", RULE.c_str());
|
||||
parseError = "Invalid rulev2 found: " + RULE;
|
||||
return;
|
||||
}
|
||||
|
||||
// now we estract shit from the value
|
||||
SWindowRule rule;
|
||||
rule.v2 = true;
|
||||
rule.szRule = RULE;
|
||||
rule.szValue = VALUE;
|
||||
|
||||
const auto TITLEPOS = VALUE.find("title:");
|
||||
const auto CLASSPOS = VALUE.find("class:");
|
||||
const auto X11POS = VALUE.find("xwayland:");
|
||||
const auto FLOATPOS = VALUE.find("floating:");
|
||||
|
||||
if (TITLEPOS == std::string::npos && CLASSPOS == std::string::npos && X11POS == std::string::npos && FLOATPOS == std::string::npos) {
|
||||
Debug::log(ERR, "Invalid rulev2 syntax: %s", VALUE.c_str());
|
||||
parseError = "Invalid rulev2 syntax: " + VALUE;
|
||||
return;
|
||||
}
|
||||
|
||||
auto extract = [&](size_t pos) -> std::string {
|
||||
std::string result;
|
||||
result = VALUE.substr(pos);
|
||||
|
||||
size_t min = 999999;
|
||||
if (TITLEPOS > pos && TITLEPOS < min) min = TITLEPOS;
|
||||
if (CLASSPOS > pos && CLASSPOS < min) min = CLASSPOS;
|
||||
if (X11POS > pos && X11POS < min) min = X11POS;
|
||||
if (FLOATPOS > pos && FLOATPOS < min) min = FLOATPOS;
|
||||
|
||||
result = result.substr(0, min - pos);
|
||||
|
||||
result = removeBeginEndSpacesTabs(result);
|
||||
|
||||
if (result.back() == ',')
|
||||
result.pop_back();
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
if (CLASSPOS != std::string::npos) {
|
||||
rule.szClass = extract(CLASSPOS + 6);
|
||||
}
|
||||
|
||||
if (TITLEPOS != std::string::npos) {
|
||||
rule.szTitle = extract(TITLEPOS + 6);
|
||||
}
|
||||
|
||||
if (X11POS != std::string::npos) {
|
||||
rule.bX11 = extract(X11POS + 9) == "1" ? 1 : 0;
|
||||
}
|
||||
|
||||
if (FLOATPOS != std::string::npos) {
|
||||
rule.bFloating = extract(FLOATPOS + 9) == "1" ? 1 : 0;
|
||||
}
|
||||
|
||||
m_dWindowRules.push_back(rule);
|
||||
}
|
||||
|
||||
void CConfigManager::handleBlurLS(const std::string& command, const std::string& value) {
|
||||
if (value.find("remove,") == 0) {
|
||||
const auto TOREMOVE = value.substr(7);
|
||||
const auto TOREMOVE = removeBeginEndSpacesTabs(value.substr(7));
|
||||
m_dBlurLSNamespaces.erase(std::remove(m_dBlurLSNamespaces.begin(), m_dBlurLSNamespaces.end(), TOREMOVE));
|
||||
return;
|
||||
}
|
||||
@@ -755,13 +829,11 @@ void CConfigManager::handleBlurLS(const std::string& command, const std::string&
|
||||
}
|
||||
|
||||
void CConfigManager::handleDefaultWorkspace(const std::string& command, const std::string& value) {
|
||||
|
||||
const auto DISPLAY = value.substr(0, value.find_first_of(','));
|
||||
const auto WORKSPACE = value.substr(value.find_first_of(',') + 1);
|
||||
const auto ARGS = CVarList(value);
|
||||
|
||||
for (auto& mr : m_dMonitorRules) {
|
||||
if (mr.name == DISPLAY) {
|
||||
mr.defaultWorkspace = WORKSPACE;
|
||||
if (mr.name == ARGS[0]) {
|
||||
mr.defaultWorkspace = ARGS[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -775,8 +847,6 @@ void CConfigManager::handleSubmap(const std::string& command, const std::string&
|
||||
}
|
||||
|
||||
void CConfigManager::handleSource(const std::string& command, const std::string& rawpath) {
|
||||
static const char* const ENVHOME = getenv("HOME");
|
||||
|
||||
if (rawpath.length() < 2) {
|
||||
Debug::log(ERR, "source= path garbage");
|
||||
parseError = "source path " + rawpath + " bogus!";
|
||||
@@ -830,6 +900,19 @@ void CConfigManager::handleSource(const std::string& command, const std::string&
|
||||
}
|
||||
}
|
||||
|
||||
void CConfigManager::handleBindWS(const std::string& command, const std::string& value) {
|
||||
const auto ARGS = CVarList(value);
|
||||
|
||||
const auto FOUND = std::find_if(boundWorkspaces.begin(), boundWorkspaces.end(), [&](const auto& other) { return other.first == ARGS[0]; });
|
||||
|
||||
if (FOUND != boundWorkspaces.end()) {
|
||||
FOUND->second = ARGS[1];
|
||||
return;
|
||||
}
|
||||
|
||||
boundWorkspaces.push_back({ARGS[0], ARGS[1]});
|
||||
}
|
||||
|
||||
std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::string& VALUE, bool dynamic) {
|
||||
if (dynamic) {
|
||||
parseError = "";
|
||||
@@ -852,11 +935,13 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
|
||||
else if (COMMAND == "unbind") handleUnbind(COMMAND, VALUE);
|
||||
else if (COMMAND == "workspace") handleDefaultWorkspace(COMMAND, VALUE);
|
||||
else if (COMMAND == "windowrule") handleWindowRule(COMMAND, VALUE);
|
||||
else if (COMMAND == "windowrulev2") handleWindowRuleV2(COMMAND, VALUE);
|
||||
else if (COMMAND == "bezier") handleBezier(COMMAND, VALUE);
|
||||
else if (COMMAND == "animation") handleAnimation(COMMAND, VALUE);
|
||||
else if (COMMAND == "source") handleSource(COMMAND, VALUE);
|
||||
else if (COMMAND == "submap") handleSubmap(COMMAND, VALUE);
|
||||
else if (COMMAND == "blurls") handleBlurLS(COMMAND, VALUE);
|
||||
else if (COMMAND == "wsbind") handleBindWS(COMMAND, VALUE);
|
||||
else
|
||||
configSetValueSafe(currentCategory + (currentCategory == "" ? "" : ":") + COMMAND, VALUE);
|
||||
|
||||
@@ -925,7 +1010,14 @@ void CConfigManager::parseLine(std::string& line) {
|
||||
}
|
||||
|
||||
if (line.contains("}") && currentCategory != "") {
|
||||
|
||||
const auto LASTSEP = currentCategory.find_last_of(':');
|
||||
|
||||
if (LASTSEP == std::string::npos || currentCategory.contains("device"))
|
||||
currentCategory = "";
|
||||
else
|
||||
currentCategory = currentCategory.substr(0, LASTSEP);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -961,6 +1053,7 @@ void CConfigManager::loadConfigLoadVars() {
|
||||
configDynamicVars.clear();
|
||||
deviceConfigs.clear();
|
||||
m_dBlurLSNamespaces.clear();
|
||||
boundWorkspaces.clear();
|
||||
setDefaultAnimationVars(); // reset anims
|
||||
|
||||
// paths
|
||||
@@ -1045,7 +1138,7 @@ void CConfigManager::loadConfigLoadVars() {
|
||||
// Update the keyboard layout to the cfg'd one if this is not the first launch
|
||||
if (!isFirstLaunch) {
|
||||
g_pInputManager->setKeyboardLayout();
|
||||
g_pInputManager->setMouseConfigs();
|
||||
g_pInputManager->setPointerConfigs();
|
||||
}
|
||||
|
||||
// Calculate the internal vars
|
||||
@@ -1083,13 +1176,13 @@ void CConfigManager::loadConfigLoadVars() {
|
||||
// update layout
|
||||
g_pLayoutManager->switchToLayout(configValues["general:layout"].strValue);
|
||||
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
// mark blur dirty
|
||||
for (auto& m : g_pCompositor->m_vMonitors)
|
||||
g_pHyprOpenGL->markBlurDirtyForMonitor(m.get());
|
||||
|
||||
// Force the compositor to fully re-render all monitors
|
||||
for (auto& m : g_pCompositor->m_vMonitors)
|
||||
m->forceFullFrames = 2;
|
||||
}
|
||||
|
||||
// Reset no monitor reload
|
||||
m_bNoMonitorReload = false;
|
||||
@@ -1215,11 +1308,11 @@ void CConfigManager::setString(std::string v, std::string val) {
|
||||
configValues[v].strValue = val;
|
||||
}
|
||||
|
||||
SMonitorRule CConfigManager::getMonitorRuleFor(std::string name) {
|
||||
SMonitorRule CConfigManager::getMonitorRuleFor(std::string name, std::string displayName) {
|
||||
SMonitorRule* found = nullptr;
|
||||
|
||||
for (auto& r : m_dMonitorRules) {
|
||||
if (r.name == name) {
|
||||
if (r.name == name || (r.name.find("desc:") == 0 && (r.name.substr(5) == displayName || r.name.substr(5) == removeBeginEndSpacesTabs(displayName.substr(0, displayName.find_first_of('(')))))) {
|
||||
found = &r;
|
||||
break;
|
||||
}
|
||||
@@ -1258,6 +1351,7 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
|
||||
|
||||
for (auto& rule : m_dWindowRules) {
|
||||
// check if we have a matching rule
|
||||
if (!rule.v2) {
|
||||
try {
|
||||
if (rule.szValue.find("title:") == 0) {
|
||||
// we have a title rule.
|
||||
@@ -1275,6 +1369,36 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
|
||||
Debug::log(ERR, "Regex error at %s", rule.szValue.c_str());
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
if (rule.szClass != "") {
|
||||
std::regex RULECHECK(rule.szClass);
|
||||
|
||||
if (!std::regex_search(appidclass, RULECHECK))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rule.szTitle != "") {
|
||||
std::regex RULECHECK(rule.szTitle);
|
||||
|
||||
if (!std::regex_search(title, RULECHECK))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rule.bX11 != -1) {
|
||||
if (pWindow->m_bIsX11 != rule.bX11)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rule.bFloating != -1) {
|
||||
if (pWindow->m_bIsFloating != rule.bFloating)
|
||||
continue;
|
||||
}
|
||||
} catch (...) {
|
||||
Debug::log(ERR, "Regex error at %s", rule.szValue.c_str());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// applies. Read the rule and behave accordingly
|
||||
Debug::log(LOG, "Window rule %s -> %s matched %x [%s]", rule.szRule.c_str(), rule.szValue.c_str(), pWindow, pWindow->m_szTitle.c_str());
|
||||
@@ -1299,7 +1423,7 @@ void CConfigManager::dispatchExecOnce() {
|
||||
|
||||
// set input, fixes some certain issues
|
||||
g_pInputManager->setKeyboardLayout();
|
||||
g_pInputManager->setMouseConfigs();
|
||||
g_pInputManager->setPointerConfigs();
|
||||
|
||||
// set ws names again
|
||||
for (auto& ws : g_pCompositor->m_vWorkspaces) {
|
||||
@@ -1312,11 +1436,17 @@ void CConfigManager::performMonitorReload() {
|
||||
bool overAgain = false;
|
||||
|
||||
for (auto& m : g_pCompositor->m_vRealMonitors) {
|
||||
auto rule = getMonitorRuleFor(m->szName);
|
||||
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;
|
||||
}
|
||||
|
||||
g_pHyprRenderer->arrangeLayersForMonitor(m->ID);
|
||||
}
|
||||
|
||||
if (overAgain)
|
||||
@@ -1359,7 +1489,7 @@ bool CConfigManager::shouldBlurLS(const std::string& ns) {
|
||||
|
||||
void CConfigManager::ensureDPMS() {
|
||||
for (auto& rm : g_pCompositor->m_vRealMonitors) {
|
||||
auto rule = getMonitorRuleFor(rm->szName);
|
||||
auto rule = getMonitorRuleFor(rm->szName, rm->output->description ? rm->output->description : "");
|
||||
|
||||
if (rule.disabled == rm->m_bEnabled) {
|
||||
rm->m_pThisWrap = &rm;
|
||||
@@ -1376,3 +1506,15 @@ void CConfigManager::addParseError(const std::string& err) {
|
||||
if (parseError == "")
|
||||
parseError = err;
|
||||
}
|
||||
|
||||
CMonitor* CConfigManager::getBoundMonitorForWS(std::string wsname) {
|
||||
for (auto&[ws, mon] : boundWorkspaces) {
|
||||
const auto WSNAME = ws.find("name:") == 0 ? ws.substr(5) : ws;
|
||||
|
||||
if (WSNAME == wsname) {
|
||||
return g_pCompositor->getMonitorFromString(mon);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
@@ -20,9 +20,10 @@
|
||||
#define CREATEANIMCFG(name, parent) animationConfig[name] = {false, "", "", 0.f, -1, &animationConfig["global"], &animationConfig[parent]}
|
||||
|
||||
struct SConfigValue {
|
||||
int64_t intValue = -1;
|
||||
float floatValue = -1;
|
||||
int64_t intValue = -INT64_MAX;
|
||||
float floatValue = -__FLT_MAX__;
|
||||
std::string strValue = "";
|
||||
Vector2D vecValue = Vector2D(-__FLT_MAX__, -__FLT_MAX__);
|
||||
|
||||
bool set = false; // used for device configs
|
||||
};
|
||||
@@ -36,6 +37,7 @@ struct SMonitorRule {
|
||||
std::string defaultWorkspace = "";
|
||||
bool disabled = false;
|
||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
std::string mirrorOf = "";
|
||||
};
|
||||
|
||||
struct SMonitorAdditionalReservedArea {
|
||||
@@ -48,6 +50,12 @@ struct SMonitorAdditionalReservedArea {
|
||||
struct SWindowRule {
|
||||
std::string szRule;
|
||||
std::string szValue;
|
||||
|
||||
bool v2 = false;
|
||||
std::string szTitle;
|
||||
std::string szClass;
|
||||
int bX11 = -1; // -1 means "ANY"
|
||||
int bFloating = -1;
|
||||
};
|
||||
|
||||
struct SAnimationPropertyConfig {
|
||||
@@ -62,6 +70,48 @@ struct SAnimationPropertyConfig {
|
||||
SAnimationPropertyConfig* pParentAnimation = nullptr;
|
||||
};
|
||||
|
||||
class CVarList {
|
||||
public:
|
||||
CVarList(const std::string& in, long unsigned int lastArgNo = 0) {
|
||||
std::string curitem = "";
|
||||
std::string argZ = in;
|
||||
|
||||
auto nextItem = [&]() {
|
||||
auto idx = lastArgNo != 0 && m_vArgs.size() >= lastArgNo - 1 ? std::string::npos : argZ.find_first_of(',');
|
||||
|
||||
if (idx != std::string::npos) {
|
||||
curitem = argZ.substr(0, idx);
|
||||
argZ = argZ.substr(idx + 1);
|
||||
} else {
|
||||
curitem = argZ;
|
||||
argZ = STRVAL_EMPTY;
|
||||
}
|
||||
};
|
||||
|
||||
nextItem();
|
||||
|
||||
while (curitem != STRVAL_EMPTY) {
|
||||
m_vArgs.push_back(removeBeginEndSpacesTabs(curitem));
|
||||
nextItem();
|
||||
}
|
||||
};
|
||||
|
||||
~CVarList() = default;
|
||||
|
||||
int size() const {
|
||||
return m_vArgs.size();
|
||||
}
|
||||
|
||||
std::string operator[](const long unsigned int& idx) const {
|
||||
if (idx >= m_vArgs.size())
|
||||
return "";
|
||||
return m_vArgs[idx];
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_vArgs;
|
||||
};
|
||||
|
||||
class CConfigManager {
|
||||
public:
|
||||
CConfigManager();
|
||||
@@ -85,7 +135,9 @@ public:
|
||||
SConfigValue* getConfigValuePtr(std::string);
|
||||
SConfigValue* getConfigValuePtrSafe(std::string);
|
||||
|
||||
SMonitorRule getMonitorRuleFor(std::string);
|
||||
SMonitorRule getMonitorRuleFor(std::string, std::string displayName = "");
|
||||
|
||||
CMonitor* getBoundMonitorForWS(std::string);
|
||||
|
||||
std::vector<SWindowRule> getMatchingRules(CWindow*);
|
||||
|
||||
@@ -123,6 +175,8 @@ private:
|
||||
|
||||
std::string m_szCurrentSubmap = ""; // For storing the current keybind submap
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> boundWorkspaces;
|
||||
|
||||
bool isFirstLaunch = true; // For exec-once
|
||||
|
||||
std::deque<SMonitorRule> m_dMonitorRules;
|
||||
@@ -151,12 +205,14 @@ private:
|
||||
void handleBind(const std::string&, const std::string&);
|
||||
void handleUnbind(const std::string&, const std::string&);
|
||||
void handleWindowRule(const std::string&, const std::string&);
|
||||
void handleWindowRuleV2(const std::string&, const std::string&);
|
||||
void handleDefaultWorkspace(const std::string&, const std::string&);
|
||||
void handleBezier(const std::string&, const std::string&);
|
||||
void handleAnimation(const std::string&, const std::string&);
|
||||
void handleSource(const std::string&, const std::string&);
|
||||
void handleSubmap(const std::string&, const std::string&);
|
||||
void handleBlurLS(const std::string&, const std::string&);
|
||||
void handleBindWS(const std::string&, const std::string&);
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CConfigManager> g_pConfigManager;
|
||||
|
@@ -32,10 +32,11 @@ input {
|
||||
touchpad {
|
||||
natural_scroll=no
|
||||
}
|
||||
|
||||
sensitivity=0 # -1.0 - 1.0, 0 means no modification.
|
||||
}
|
||||
|
||||
general {
|
||||
sensitivity=1.0 # for mouse cursor
|
||||
main_mod=SUPER
|
||||
|
||||
gaps_in=5
|
||||
@@ -53,10 +54,8 @@ decoration {
|
||||
rounding=10
|
||||
blur=1
|
||||
blur_size=3 # minimum 1
|
||||
blur_passes=1 # minimum 1, more passes = more resource intensive.
|
||||
# Your blur "amount" is blur_size * blur_passes, but high blur_size (over around 5-ish) will produce artifacts.
|
||||
# if you want heavy blur, you need to up the blur_passes.
|
||||
# the more passes, the more you can up the blur_size without noticing artifacts.
|
||||
blur_passes=1 # minimum 1
|
||||
blur_new_optimizations=1
|
||||
}
|
||||
|
||||
animations {
|
||||
@@ -84,6 +83,10 @@ gestures {
|
||||
#windowrule=pseudo,abc
|
||||
#windowrule=monitor 0,xyz
|
||||
|
||||
# some nice mouse binds
|
||||
bindm=SUPER,mouse:272,movewindow
|
||||
bindm=SUPER,mouse:273,resizewindow
|
||||
|
||||
# example binds
|
||||
bind=SUPER,Q,exec,kitty
|
||||
bind=SUPER,RETURN,exec,alacritty
|
||||
|
@@ -23,6 +23,7 @@ std::string monitorsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
R"#({
|
||||
"id": %i,
|
||||
"name": "%s",
|
||||
"description": "%s",
|
||||
"width": %i,
|
||||
"height": %i,
|
||||
"refreshRate": %f,
|
||||
@@ -35,10 +36,12 @@ R"#({
|
||||
"reserved": [%i, %i, %i, %i],
|
||||
"scale": %.2f,
|
||||
"transform": %i,
|
||||
"focused": %s
|
||||
"focused": %s,
|
||||
"dpmsStatus": %s
|
||||
},)#",
|
||||
m->ID,
|
||||
escapeJSONStrings(m->szName).c_str(),
|
||||
escapeJSONStrings(m->output->description ? m->output->description : "").c_str(),
|
||||
(int)m->vecPixelSize.x, (int)m->vecPixelSize.y,
|
||||
m->refreshRate,
|
||||
(int)m->vecPosition.x, (int)m->vecPosition.y,
|
||||
@@ -46,7 +49,8 @@ R"#({
|
||||
(int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y,
|
||||
m->scale,
|
||||
(int)m->transform,
|
||||
(m.get() == g_pCompositor->m_pLastMonitor ? "true" : "false")
|
||||
(m.get() == g_pCompositor->m_pLastMonitor ? "true" : "false"),
|
||||
(m->dpmsStatus ? "true" : "false")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -56,8 +60,8 @@ R"#({
|
||||
result += "]";
|
||||
} else {
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
result += getFormat("Monitor %s (ID %i):\n\t%ix%i@%f at %ix%i\n\tactive workspace: %i (%s)\n\treserved: %i %i %i %i\n\tscale: %.2f\n\ttransform: %i\n\tfocused: %s\n\n",
|
||||
m->szName.c_str(), m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->activeWorkspace, g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName.c_str(), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "yes" : "no"));
|
||||
result += getFormat("Monitor %s (ID %i):\n\t%ix%i@%f at %ix%i\n\tdescription: %s\n\tactive workspace: %i (%s)\n\treserved: %i %i %i %i\n\tscale: %.2f\n\ttransform: %i\n\tfocused: %s\n\tdpmsStatus: %i\n\n",
|
||||
m->szName.c_str(), m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, (m->output->description ? m->output->description : ""), m->activeWorkspace, g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName.c_str(), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,18 +89,24 @@ R"#({
|
||||
"class": "%s",
|
||||
"title": "%s",
|
||||
"pid": %i,
|
||||
"xwayland": %s
|
||||
"xwayland": %s,
|
||||
"pinned": %s,
|
||||
"fullscreen": %s,
|
||||
"fullscreenMode": %i
|
||||
},)#",
|
||||
w.get(),
|
||||
(int)w->m_vRealPosition.vec().x, (int)w->m_vRealPosition.vec().y,
|
||||
(int)w->m_vRealSize.vec().x, (int)w->m_vRealSize.vec().y,
|
||||
(int)w->m_vRealPosition.goalv().x, (int)w->m_vRealPosition.goalv().y,
|
||||
(int)w->m_vRealSize.goalv().x, (int)w->m_vRealSize.goalv().y,
|
||||
w->m_iWorkspaceID, escapeJSONStrings(w->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName : std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID))).c_str(),
|
||||
((int)w->m_bIsFloating == 1 ? "true" : "false"),
|
||||
w->m_iMonitorID,
|
||||
escapeJSONStrings(g_pXWaylandManager->getAppIDClass(w.get())).c_str(),
|
||||
escapeJSONStrings(g_pXWaylandManager->getTitle(w.get())).c_str(),
|
||||
w->getPID(),
|
||||
((int)w->m_bIsX11 == 1 ? "true" : "false")
|
||||
((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)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -109,8 +119,8 @@ R"#({
|
||||
} else {
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_bIsMapped) {
|
||||
result += getFormat("Window %x -> %s:\n\tat: %i,%i\n\tsize: %i,%i\n\tworkspace: %i (%s)\n\tfloating: %i\n\tmonitor: %i\n\tclass: %s\n\ttitle: %s\n\tpid: %i\n\txwayland: %i\n\n",
|
||||
w.get(), w->m_szTitle.c_str(), (int)w->m_vRealPosition.vec().x, (int)w->m_vRealPosition.vec().y, (int)w->m_vRealSize.vec().x, (int)w->m_vRealSize.vec().y, w->m_iWorkspaceID, (w->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName.c_str() : std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID)).c_str()), (int)w->m_bIsFloating, w->m_iMonitorID, g_pXWaylandManager->getAppIDClass(w.get()).c_str(), g_pXWaylandManager->getTitle(w.get()).c_str(), w->getPID(), (int)w->m_bIsX11);
|
||||
result += getFormat("Window %x -> %s:\n\tat: %i,%i\n\tsize: %i,%i\n\tworkspace: %i (%s)\n\tfloating: %i\n\tmonitor: %i\n\tclass: %s\n\ttitle: %s\n\tpid: %i\n\txwayland: %i\n\tpinned: %i\n\tfullscreen: %i\n\tfullscreenmode: %i\n\n",
|
||||
w.get(), w->m_szTitle.c_str(), (int)w->m_vRealPosition.goalv().x, (int)w->m_vRealPosition.goalv().y, (int)w->m_vRealSize.goalv().x, (int)w->m_vRealSize.goalv().y, w->m_iWorkspaceID, (w->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName.c_str() : std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID)).c_str()), (int)w->m_bIsFloating, w->m_iMonitorID, g_pXWaylandManager->getAppIDClass(w.get()).c_str(), g_pXWaylandManager->getTitle(w.get()).c_str(), w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen, (w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -124,19 +134,25 @@ std::string workspacesRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
result += "[";
|
||||
|
||||
for (auto& w : g_pCompositor->m_vWorkspaces) {
|
||||
const auto PLASTW = w->getLastFocusedWindow();
|
||||
|
||||
result += getFormat(
|
||||
R"#({
|
||||
"id": %i,
|
||||
"name": "%s",
|
||||
"monitor": "%s",
|
||||
"windows": %i,
|
||||
"hasfullscreen": %s
|
||||
"hasfullscreen": %s,
|
||||
"lastwindow": "0x%x",
|
||||
"lastwindowtitle": "%s"
|
||||
},)#",
|
||||
w->m_iID,
|
||||
escapeJSONStrings(w->m_szName).c_str(),
|
||||
escapeJSONStrings(g_pCompositor->getMonitorFromID(w->m_iMonitorID)->szName).c_str(),
|
||||
g_pCompositor->getWindowsOnWorkspace(w->m_iID),
|
||||
((int)w->m_bHasFullscreenWindow == 1 ? "true" : "false")
|
||||
((int)w->m_bHasFullscreenWindow == 1 ? "true" : "false"),
|
||||
PLASTW,
|
||||
PLASTW ? escapeJSONStrings(PLASTW->m_szTitle).c_str() : ""
|
||||
);
|
||||
}
|
||||
|
||||
@@ -146,8 +162,9 @@ R"#({
|
||||
result += "]";
|
||||
} else {
|
||||
for (auto& w : g_pCompositor->m_vWorkspaces) {
|
||||
result += getFormat("workspace ID %i (%s) on monitor %s:\n\twindows: %i\n\thasfullscreen: %i\n\n",
|
||||
w->m_iID, w->m_szName.c_str(), g_pCompositor->getMonitorFromID(w->m_iMonitorID)->szName.c_str(), g_pCompositor->getWindowsOnWorkspace(w->m_iID), (int)w->m_bHasFullscreenWindow);
|
||||
const auto PLASTW = w->getLastFocusedWindow();
|
||||
result += getFormat("workspace ID %i (%s) on monitor %s:\n\twindows: %i\n\thasfullscreen: %i\n\tlastwindow: 0x%x\n\tlastwindowtitle: %s\n\n",
|
||||
w->m_iID, w->m_szName.c_str(), g_pCompositor->getMonitorFromID(w->m_iMonitorID)->szName.c_str(), g_pCompositor->getWindowsOnWorkspace(w->m_iID), (int)w->m_bHasFullscreenWindow, PLASTW, PLASTW ? PLASTW->m_szTitle.c_str() : "");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -287,10 +304,12 @@ std::string devicesRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
result += getFormat(
|
||||
R"#( {
|
||||
"address": "0x%x",
|
||||
"name": "%s"
|
||||
"name": "%s",
|
||||
"defaultSpeed": %f
|
||||
},)#",
|
||||
&m,
|
||||
escapeJSONStrings(m.mouse->name).c_str()
|
||||
escapeJSONStrings(m.mouse->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
|
||||
);
|
||||
}
|
||||
|
||||
@@ -370,6 +389,41 @@ R"#( {
|
||||
);
|
||||
}
|
||||
|
||||
// remove trailing comma
|
||||
result.pop_back();
|
||||
result += "\n],\n";
|
||||
|
||||
result += "\"touch\": [\n";
|
||||
|
||||
for (auto& d : g_pInputManager->m_lTouchDevices) {
|
||||
result += getFormat(
|
||||
R"#( {
|
||||
"address": "0x%x",
|
||||
"name": "%s"
|
||||
},)#",
|
||||
&d,
|
||||
d.pWlrDevice ? d.pWlrDevice->name : ""
|
||||
);
|
||||
}
|
||||
|
||||
// remove trailing comma
|
||||
if (result[result.size() - 1] == ',')
|
||||
result.pop_back();
|
||||
result += "\n],\n";
|
||||
|
||||
result += "\"switches\": [\n";
|
||||
|
||||
for (auto& d : g_pInputManager->m_lSwitches) {
|
||||
result += getFormat(
|
||||
R"#( {
|
||||
"address": "0x%x",
|
||||
"name": "%s"
|
||||
},)#",
|
||||
&d,
|
||||
d.pWlrDevice ? d.pWlrDevice->name : ""
|
||||
);
|
||||
}
|
||||
|
||||
// remove trailing comma
|
||||
if (result[result.size() - 1] == ',')
|
||||
result.pop_back();
|
||||
@@ -381,7 +435,7 @@ R"#( {
|
||||
result += "mice:\n";
|
||||
|
||||
for (auto& m : g_pInputManager->m_lMice) {
|
||||
result += getFormat("\tMouse at %x:\n\t\t%s\n", &m, m.mouse->name);
|
||||
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 += "\n\nKeyboards:\n";
|
||||
@@ -404,6 +458,18 @@ R"#( {
|
||||
for (auto& d : g_pInputManager->m_lTabletTools) {
|
||||
result += getFormat("\tTablet Tool at %x (belongs to %x)\n", &d, d.wlrTabletTool ? d.wlrTabletTool->data : 0);
|
||||
}
|
||||
|
||||
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 += "\n\nSwitches:\n";
|
||||
|
||||
for (auto& d : g_pInputManager->m_lSwitches) {
|
||||
result += getFormat("\tSwitch Device at %x:\n\t\t%s\n", &d, d.pWlrDevice ? d.pWlrDevice->name : "");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -495,7 +561,7 @@ std::string dispatchKeyword(std::string in) {
|
||||
|
||||
if (COMMAND.contains("input") || COMMAND.contains("device:")) {
|
||||
g_pInputManager->setKeyboardLayout(); // update kb layout
|
||||
g_pInputManager->setMouseConfigs(); // update mouse cfgs
|
||||
g_pInputManager->setPointerConfigs(); // update mouse cfgs
|
||||
}
|
||||
|
||||
if (COMMAND.contains("general:layout"))
|
||||
@@ -519,6 +585,8 @@ std::string reloadRequest(std::string request) {
|
||||
g_pConfigManager->m_bNoMonitorReload = true;
|
||||
}
|
||||
|
||||
g_pConfigManager->tick();
|
||||
|
||||
return "ok";
|
||||
}
|
||||
|
||||
@@ -712,9 +780,21 @@ std::string getReply(std::string request) {
|
||||
return "unknown request";
|
||||
}
|
||||
|
||||
void HyprCtl::tickHyprCtl() {
|
||||
if (!requestMade)
|
||||
return;
|
||||
int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
|
||||
if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP)
|
||||
return 0;
|
||||
|
||||
sockaddr_in clientAddress;
|
||||
socklen_t clientSize = sizeof(clientAddress);
|
||||
|
||||
const auto ACCEPTEDCONNECTION = accept(HyprCtl::iSocketFD, (sockaddr*)&clientAddress, &clientSize);
|
||||
|
||||
char readBuffer[1024];
|
||||
|
||||
auto messageSize = read(ACCEPTEDCONNECTION, readBuffer, 1024);
|
||||
readBuffer[messageSize == 1024 ? 1023 : messageSize] = '\0';
|
||||
|
||||
std::string request(readBuffer);
|
||||
|
||||
std::string reply = "";
|
||||
|
||||
@@ -725,44 +805,22 @@ void HyprCtl::tickHyprCtl() {
|
||||
reply = "Err: " + std::string(e.what());
|
||||
}
|
||||
|
||||
request = reply;
|
||||
write(ACCEPTEDCONNECTION, reply.c_str(), reply.length());
|
||||
|
||||
requestMade = false;
|
||||
requestReady = true;
|
||||
close(ACCEPTEDCONNECTION);
|
||||
|
||||
if (g_pConfigManager->m_bWantsMonitorReload) {
|
||||
g_pConfigManager->ensureDPMS();
|
||||
}
|
||||
}
|
||||
|
||||
std::string getRequestFromThread(std::string rq) {
|
||||
|
||||
while (HyprCtl::request != "" || HyprCtl::requestMade || HyprCtl::requestReady) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
}
|
||||
|
||||
HyprCtl::request = rq;
|
||||
HyprCtl::requestMade = true;
|
||||
|
||||
while (!HyprCtl::requestReady) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
}
|
||||
|
||||
HyprCtl::requestReady = false;
|
||||
HyprCtl::requestMade = false;
|
||||
|
||||
std::string toReturn = HyprCtl::request;
|
||||
|
||||
HyprCtl::request = "";
|
||||
|
||||
return toReturn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void HyprCtl::startHyprCtlSocket() {
|
||||
std::thread([&]() {
|
||||
const auto SOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
if (SOCKET < 0) {
|
||||
iSocketFD = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
if (iSocketFD < 0) {
|
||||
Debug::log(ERR, "Couldn't start the Hyprland Socket. (1) IPC will not work.");
|
||||
return;
|
||||
}
|
||||
@@ -773,38 +831,12 @@ void HyprCtl::startHyprCtlSocket() {
|
||||
|
||||
strcpy(SERVERADDRESS.sun_path, socketPath.c_str());
|
||||
|
||||
bind(SOCKET, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS));
|
||||
bind(iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS));
|
||||
|
||||
// 10 max queued.
|
||||
listen(SOCKET, 10);
|
||||
|
||||
sockaddr_in clientAddress;
|
||||
socklen_t clientSize = sizeof(clientAddress);
|
||||
|
||||
char readBuffer[1024] = {0};
|
||||
listen(iSocketFD, 10);
|
||||
|
||||
Debug::log(LOG, "Hypr socket started at %s", socketPath.c_str());
|
||||
|
||||
while(1) {
|
||||
const auto ACCEPTEDCONNECTION = accept(SOCKET, (sockaddr*)&clientAddress, &clientSize);
|
||||
|
||||
if (ACCEPTEDCONNECTION < 0) {
|
||||
Debug::log(ERR, "Couldn't listen on the Hyprland Socket. (3) IPC will not work.");
|
||||
break;
|
||||
}
|
||||
|
||||
auto messageSize = read(ACCEPTEDCONNECTION, readBuffer, 1024);
|
||||
readBuffer[messageSize == 1024 ? 1023 : messageSize] = '\0';
|
||||
|
||||
std::string request(readBuffer);
|
||||
|
||||
std::string reply = getRequestFromThread(request);
|
||||
|
||||
write(ACCEPTEDCONNECTION, reply.c_str(), reply.length());
|
||||
|
||||
close(ACCEPTEDCONNECTION);
|
||||
}
|
||||
|
||||
close(SOCKET);
|
||||
}).detach();
|
||||
wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, iSocketFD, WL_EVENT_READABLE, hyprCtlFDTick, nullptr);
|
||||
}
|
||||
|
@@ -6,7 +6,6 @@
|
||||
|
||||
namespace HyprCtl {
|
||||
void startHyprCtlSocket();
|
||||
void tickHyprCtl();
|
||||
|
||||
// very simple thread-safe request method
|
||||
inline bool requestMade = false;
|
||||
@@ -15,6 +14,10 @@ namespace HyprCtl {
|
||||
|
||||
inline std::ifstream requestStream;
|
||||
|
||||
inline wl_event_source* hyprCtlTickSource = nullptr;
|
||||
|
||||
inline int iSocketFD = -1;
|
||||
|
||||
enum eHyprCtlOutputFormat {
|
||||
FORMAT_NORMAL = 0,
|
||||
FORMAT_JSON
|
||||
|
@@ -6,10 +6,23 @@
|
||||
#include <iostream>
|
||||
|
||||
void Debug::init(std::string IS) {
|
||||
if (ISDEBUG)
|
||||
logFile = "/tmp/hypr/" + IS + "/hyprlandd.log";
|
||||
else
|
||||
logFile = "/tmp/hypr/" + IS + "/hyprland.log";
|
||||
logFile = "/tmp/hypr/" + IS + (ISDEBUG ? "/hyprlandd.log" : "/hyprland.log");
|
||||
}
|
||||
|
||||
void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) {
|
||||
char* outputStr = nullptr;
|
||||
|
||||
std::ofstream ofs;
|
||||
ofs.open(logFile, std::ios::out | std::ios::app);
|
||||
|
||||
vasprintf(&outputStr, fmt, args);
|
||||
|
||||
std::string output = std::string(outputStr);
|
||||
free(outputStr);
|
||||
|
||||
ofs << "[wlr] " << output << "\n";
|
||||
|
||||
ofs.close();
|
||||
}
|
||||
|
||||
void Debug::log(LogLevel level, const char* fmt, ...) {
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
#define LOGMESSAGESIZE 1024
|
||||
|
||||
@@ -15,6 +16,7 @@ enum LogLevel {
|
||||
namespace Debug {
|
||||
void init(std::string IS);
|
||||
void log(LogLevel level, const char* fmt, ...);
|
||||
void wlrLog(wlr_log_importance level, const char* fmt, va_list args);
|
||||
|
||||
inline std::string logFile;
|
||||
inline int64_t* disableLogs = nullptr;
|
||||
|
@@ -72,7 +72,7 @@ void Events::listener_newInput(wl_listener* listener, void* data) {
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_TOUCH:
|
||||
Debug::log(LOG, "Attached a touch device with name %s", DEVICE->name);
|
||||
wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, DEVICE);
|
||||
g_pInputManager->newTouchDevice(DEVICE);
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_TABLET_TOOL:
|
||||
Debug::log(LOG, "Attached a tablet tool with name %s", DEVICE->name);
|
||||
@@ -82,6 +82,10 @@ void Events::listener_newInput(wl_listener* listener, void* data) {
|
||||
Debug::log(LOG, "Attached a tablet pad with name %s", DEVICE->name);
|
||||
g_pInputManager->newTabletPad(DEVICE);
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_SWITCH:
|
||||
Debug::log(LOG, "Attached a switch device with name %s", DEVICE->name);
|
||||
g_pInputManager->newSwitch(DEVICE);
|
||||
break;
|
||||
default:
|
||||
Debug::log(WARN, "Unrecognized input device plugged in: %s", DEVICE->name);
|
||||
break;
|
||||
@@ -207,3 +211,15 @@ void Events::listener_touchEnd(wl_listener* listener, void* data) {
|
||||
void Events::listener_touchUpdate(wl_listener* listener, void* data) {
|
||||
g_pInputManager->onTouchMove((wlr_touch_motion_event*)data);
|
||||
}
|
||||
|
||||
void Events::listener_touchFrame(wl_listener* listener, void* data) {
|
||||
wlr_seat_touch_notify_frame(g_pCompositor->m_sSeat.seat);
|
||||
}
|
||||
|
||||
void Events::listener_holdBegin(wl_listener* listener, void* data) {
|
||||
g_pInputManager->onPointerHoldBegin((wlr_pointer_hold_begin_event*)data);
|
||||
}
|
||||
|
||||
void Events::listener_holdEnd(wl_listener* listener, void* data) {
|
||||
g_pInputManager->onPointerHoldEnd((wlr_pointer_hold_end_event*)data);
|
||||
}
|
@@ -12,6 +12,9 @@ namespace Events {
|
||||
LISTENER(change);
|
||||
LISTENER(newOutput);
|
||||
|
||||
// DRM events
|
||||
LISTENER(leaseRequest);
|
||||
|
||||
// Layer events
|
||||
LISTENER(newLayerSurface);
|
||||
DYNLISTENFUNC(destroyLayerSurface);
|
||||
@@ -149,4 +152,8 @@ namespace Events {
|
||||
LISTENER(touchBegin);
|
||||
LISTENER(touchEnd);
|
||||
LISTENER(touchUpdate);
|
||||
LISTENER(touchFrame);
|
||||
|
||||
LISTENER(holdBegin);
|
||||
LISTENER(holdEnd);
|
||||
};
|
@@ -133,8 +133,9 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
|
||||
|
||||
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID);
|
||||
|
||||
if (layersurface->layerSurface->current.keyboard_interactive && (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint)) { // don't focus if constrained
|
||||
wlr_surface_send_enter(layersurface->layerSurface->surface, layersurface->layerSurface->output);
|
||||
|
||||
if (layersurface->layerSurface->current.keyboard_interactive && (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint)) { // don't focus if constrained
|
||||
g_pCompositor->focusSurface(layersurface->layerSurface->surface);
|
||||
|
||||
const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y);
|
||||
@@ -158,7 +159,7 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
|
||||
|
||||
Debug::log(LOG, "LayerSurface %x unmapped", layersurface->layerSurface);
|
||||
|
||||
if (!g_pCompositor->getMonitorFromID(layersurface->monitorID)) {
|
||||
if (!g_pCompositor->getMonitorFromID(layersurface->monitorID) || g_pCompositor->m_bUnsafeState) {
|
||||
Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring.");
|
||||
|
||||
g_pCompositor->addToFadingOutSafe(layersurface);
|
||||
|
@@ -25,6 +25,15 @@ void Events::listener_outputMgrTest(wl_listener* listener, void* data) {
|
||||
g_pHyprRenderer->outputMgrApplyTest(CONFIG, true);
|
||||
}
|
||||
|
||||
void Events::listener_leaseRequest(wl_listener* listener, void* data) {
|
||||
const auto REQUEST = (wlr_drm_lease_request_v1*)data;
|
||||
struct wlr_drm_lease_v1* lease = wlr_drm_lease_request_v1_grant(REQUEST);
|
||||
if (!lease) {
|
||||
Debug::log(ERR, "Failed to grant lease request!");
|
||||
wlr_drm_lease_request_v1_reject(REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
void Events::listener_requestSetPrimarySel(wl_listener* listener, void* data) {
|
||||
const auto EVENT = (wlr_seat_request_set_primary_selection_event*)data;
|
||||
wlr_seat_set_primary_selection(g_pCompositor->m_sSeat.seat, EVENT->source, EVENT->serial);
|
||||
@@ -115,6 +124,9 @@ void Events::listener_startDrag(wl_listener* listener, void* data) {
|
||||
void Events::listener_destroyDrag(void* owner, void* data) {
|
||||
Debug::log(LOG, "Drag destroyed.");
|
||||
|
||||
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);
|
||||
|
||||
g_pInputManager->m_sDrag.drag = nullptr;
|
||||
g_pInputManager->m_sDrag.dragIcon = nullptr;
|
||||
g_pInputManager->m_sDrag.hyprListener_destroy.removeCallback();
|
||||
|
@@ -190,18 +190,18 @@ void Events::listener_monitorFrame(void* owner, void* data) {
|
||||
}
|
||||
|
||||
// if we have no tracking or full tracking, invalidate the entire monitor
|
||||
if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR || PMONITOR->forceFullFrames > 0 || damageBlinkCleanup > 0) {
|
||||
pixman_region32_union_rect(&damage, &damage, 0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y);
|
||||
if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR || PMONITOR->forceFullFrames > 0 || damageBlinkCleanup > 0 || PMONITOR->isMirror() /* why??? */) {
|
||||
pixman_region32_union_rect(&damage, &damage, 0, 0, (int)PMONITOR->vecTransformedSize.x * 10, (int)PMONITOR->vecTransformedSize.y * 10); // wot?
|
||||
|
||||
pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage);
|
||||
} else {
|
||||
static auto* const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue;
|
||||
static auto *const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue;
|
||||
|
||||
// if we use blur we need to expand the damage for proper blurring
|
||||
if (*PBLURENABLED == 1) {
|
||||
// TODO: can this be optimized?
|
||||
static auto* const PBLURSIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_size")->intValue;
|
||||
static auto* const PBLURPASSES = &g_pConfigManager->getConfigValuePtr("decoration:blur_passes")->intValue;
|
||||
static auto *const PBLURSIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_size")->intValue;
|
||||
static auto *const PBLURPASSES = &g_pConfigManager->getConfigValuePtr("decoration:blur_passes")->intValue;
|
||||
const auto BLURRADIUS = *PBLURSIZE * pow(2, *PBLURPASSES); // is this 2^pass? I don't know but it works... I think.
|
||||
|
||||
pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage);
|
||||
@@ -224,6 +224,12 @@ void Events::listener_monitorFrame(void* owner, void* data) {
|
||||
// potentially can save on resources.
|
||||
|
||||
g_pHyprOpenGL->begin(PMONITOR, &damage);
|
||||
|
||||
if (PMONITOR->isMirror()) {
|
||||
g_pHyprOpenGL->renderMirrored();
|
||||
|
||||
Debug::log(LOG, "Mirror frame");
|
||||
} else {
|
||||
g_pHyprOpenGL->clear(CColor(17, 17, 17, 255));
|
||||
g_pHyprOpenGL->clearWithTex(); // will apply the hypr "wallpaper"
|
||||
|
||||
@@ -241,8 +247,8 @@ void Events::listener_monitorFrame(void* owner, void* data) {
|
||||
}
|
||||
|
||||
if (*PDAMAGEBLINK && damageBlinkCleanup == 0) {
|
||||
wlr_box monrect = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
|
||||
g_pHyprOpenGL->renderRect(&monrect, CColor(255,0,255,100), 0);
|
||||
wlr_box monrect = {0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y};
|
||||
g_pHyprOpenGL->renderRect(&monrect, CColor(255, 0, 255, 100), 0);
|
||||
damageBlinkCleanup = 1;
|
||||
} else if (*PDAMAGEBLINK) {
|
||||
damageBlinkCleanup++;
|
||||
@@ -255,6 +261,7 @@ void Events::listener_monitorFrame(void* owner, void* data) {
|
||||
wlr_output_render_software_cursors(PMONITOR->output, NULL);
|
||||
|
||||
wlr_renderer_end(g_pCompositor->m_sWLRRenderer);
|
||||
}
|
||||
|
||||
g_pHyprOpenGL->end();
|
||||
|
||||
@@ -272,10 +279,15 @@ void Events::listener_monitorFrame(void* owner, void* data) {
|
||||
pixman_region32_union(&frameDamage, &frameDamage, &damage);
|
||||
|
||||
wlr_output_set_damage(PMONITOR->output, &frameDamage);
|
||||
|
||||
if (!PMONITOR->mirrors.empty())
|
||||
g_pHyprRenderer->damageMirrorsWith(PMONITOR, &frameDamage);
|
||||
|
||||
pixman_region32_fini(&frameDamage);
|
||||
pixman_region32_fini(&damage);
|
||||
|
||||
wlr_output_commit(PMONITOR->output);
|
||||
if (!wlr_output_commit(PMONITOR->output))
|
||||
return;
|
||||
|
||||
if (*PDAMAGEBLINK || *PNOVFR)
|
||||
g_pCompositor->scheduleFrameForMonitor(PMONITOR);
|
||||
|
@@ -18,17 +18,21 @@
|
||||
void addPopupGlobalCoords(void* pPopup, int* x, int* y) {
|
||||
SXDGPopup *const PPOPUP = (SXDGPopup*)pPopup;
|
||||
|
||||
auto curPopup = PPOPUP;
|
||||
|
||||
int px = 0;
|
||||
int py = 0;
|
||||
|
||||
auto curPopup = PPOPUP;
|
||||
while (true) {
|
||||
px += curPopup->popup->current.geometry.x;
|
||||
py += curPopup->popup->current.geometry.y;
|
||||
|
||||
// fix oversized fucking popups
|
||||
// kill me
|
||||
if (curPopup->pSurfaceTree && curPopup->pSurfaceTree->pSurface && !curPopup->parentPopup) {
|
||||
if (curPopup == PPOPUP && PPOPUP->parentWindow) {
|
||||
px -= curPopup->popup->base->current.geometry.x;
|
||||
py -= curPopup->popup->base->current.geometry.y;
|
||||
}
|
||||
|
||||
if (curPopup->pSurfaceTree && curPopup->pSurfaceTree->pSurface && !curPopup->parentPopup && !curPopup->parentWindow) {
|
||||
const auto EXTENTSSURFACE = pixman_region32_extents(&curPopup->pSurfaceTree->pSurface->input_region);
|
||||
px -= EXTENTSSURFACE->x1;
|
||||
py -= EXTENTSSURFACE->y1;
|
||||
@@ -104,12 +108,9 @@ void Events::listener_newPopupXDG(void* owner, void* data) {
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
||||
|
||||
wlr_box geom;
|
||||
wlr_xdg_surface_get_geometry(PWINDOW->m_uSurface.xdg, &geom);
|
||||
|
||||
PNEWPOPUP->popup = WLRPOPUP;
|
||||
PNEWPOPUP->lx = PWINDOW->m_vRealPosition.goalv().x - geom.x;
|
||||
PNEWPOPUP->ly = PWINDOW->m_vRealPosition.goalv().y - geom.y;
|
||||
PNEWPOPUP->lx = PWINDOW->m_vRealPosition.goalv().x;
|
||||
PNEWPOPUP->ly = PWINDOW->m_vRealPosition.goalv().y;
|
||||
PNEWPOPUP->parentWindow = PWINDOW;
|
||||
PNEWPOPUP->monitor = PMONITOR;
|
||||
createNewPopup(WLRPOPUP, PNEWPOPUP);
|
||||
@@ -154,7 +155,7 @@ void Events::listener_mapPopupXDG(void* owner, void* data) {
|
||||
wlr_box extents;
|
||||
wlr_surface_get_extends(PPOPUP->popup->base->surface, &extents);
|
||||
|
||||
g_pHyprRenderer->damageBox(lx, ly, extents.width + 2, extents.height + 2);
|
||||
g_pHyprRenderer->damageBox(lx - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
|
||||
|
||||
Debug::log(LOG, "XDG Popup got assigned a surfaceTreeNode %x", PPOPUP->pSurfaceTree);
|
||||
}
|
||||
@@ -173,7 +174,7 @@ void Events::listener_unmapPopupXDG(void* owner, void* data) {
|
||||
wlr_box extents;
|
||||
wlr_surface_get_extends(PPOPUP->popup->base->surface, &extents);
|
||||
|
||||
g_pHyprRenderer->damageBox(lx, ly, extents.width + 2, extents.height + 2);
|
||||
g_pHyprRenderer->damageBox(lx - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
|
||||
|
||||
PPOPUP->pSurfaceTree = nullptr;
|
||||
}
|
||||
|
@@ -48,8 +48,11 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
|
||||
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 PDIMSTRENGTH = &g_pConfigManager->getConfigValuePtr("decoration:dim_strength")->floatValue;
|
||||
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->getMonitorFromCursor();
|
||||
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
|
||||
const auto PWORKSPACE = PMONITOR->specialWorkspaceOpen ? g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID) : g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
|
||||
PWINDOW->m_iMonitorID = PMONITOR->ID;
|
||||
PWINDOW->m_bMappedX11 = true;
|
||||
@@ -97,17 +100,20 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
PWINDOW->m_vPseudoSize = Vector2D(desiredGeometry.width, desiredGeometry.height);
|
||||
}
|
||||
|
||||
CWindow* pFullscreenWindow = nullptr;
|
||||
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->m_bIsFloating) {
|
||||
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
|
||||
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PFULLWINDOW, FULLSCREEN_FULL, false);
|
||||
g_pXWaylandManager->setWindowFullscreen(PFULLWINDOW, PFULLWINDOW->m_bIsFullscreen);
|
||||
pFullscreenWindow = PFULLWINDOW;
|
||||
g_pCompositor->setWindowFullscreen(PFULLWINDOW, false, PWORKSPACE->m_efFullscreenMode);
|
||||
}
|
||||
|
||||
// window rules
|
||||
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(PWINDOW);
|
||||
std::string requestedWorkspace = "";
|
||||
bool workspaceSilent = false;
|
||||
bool requestsFullscreen = false;
|
||||
bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen || (!PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xdg->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL && PWINDOW->m_uSurface.xdg->toplevel->requested.fullscreen);
|
||||
bool shouldFocus = true;
|
||||
|
||||
for (auto& r : WINDOWRULES) {
|
||||
if (r.szRule.find("monitor") == 0) {
|
||||
@@ -156,6 +162,12 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
requestsFullscreen = true;
|
||||
} else if (r.szRule == "opaque") {
|
||||
PWINDOW->m_sAdditionalConfigData.forceOpaque = true;
|
||||
} else if (r.szRule == "forceinput") {
|
||||
PWINDOW->m_sAdditionalConfigData.forceAllowsInput = true;
|
||||
} else if (r.szRule == "pin") {
|
||||
PWINDOW->m_bPinned = true;
|
||||
} else if (r.szRule == "noanim") {
|
||||
PWINDOW->m_sAdditionalConfigData.forceNoAnims = true;
|
||||
} else if (r.szRule.find("rounding") == 0) {
|
||||
try {
|
||||
PWINDOW->m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
|
||||
@@ -182,16 +194,24 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
}
|
||||
}
|
||||
|
||||
// disallow tiled pinned
|
||||
if (PWINDOW->m_bPinned && !PWINDOW->m_bIsFloating)
|
||||
PWINDOW->m_bPinned = false;
|
||||
|
||||
if (requestedWorkspace != "") {
|
||||
// process requested workspace
|
||||
if (requestedWorkspace.contains(' ')) {
|
||||
// check for silent
|
||||
if (requestedWorkspace.contains("silent")) {
|
||||
workspaceSilent = true;
|
||||
shouldFocus = false;
|
||||
}
|
||||
|
||||
requestedWorkspace = requestedWorkspace.substr(0, requestedWorkspace.find_first_of(' '));
|
||||
|
||||
if (!shouldFocus && requestedWorkspace == std::to_string(PMONITOR->activeWorkspace))
|
||||
shouldFocus = true;
|
||||
|
||||
if (requestedWorkspace == "special") {
|
||||
workspaceSilent = true;
|
||||
}
|
||||
@@ -217,8 +237,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(" "));
|
||||
const auto SIZEYSTR = VALUE.substr(VALUE.find(" ") + 1);
|
||||
|
||||
const auto SIZEX = !SIZEXSTR.contains('%') ? std::stoi(SIZEXSTR) : std::stoi(SIZEXSTR.substr(0, SIZEXSTR.length() - 1)) * 0.01f * PMONITOR->vecSize.x;
|
||||
const auto SIZEY = !SIZEYSTR.contains('%') ? std::stoi(SIZEYSTR) : std::stoi(SIZEYSTR.substr(0, SIZEYSTR.length() - 1)) * 0.01f * PMONITOR->vecSize.y;
|
||||
const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(PWINDOW);
|
||||
|
||||
const auto SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, 20.0, PMONITOR->vecSize.x) : (!SIZEXSTR.contains('%') ? std::stoi(SIZEXSTR) : std::stoi(SIZEXSTR.substr(0, SIZEXSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.x);
|
||||
const auto SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, 20.0, PMONITOR->vecSize.y) : (!SIZEYSTR.contains('%') ? std::stoi(SIZEYSTR) : std::stoi(SIZEYSTR.substr(0, SIZEYSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.y);
|
||||
|
||||
Debug::log(LOG, "Rule size, applying to window %x", PWINDOW);
|
||||
|
||||
@@ -229,14 +251,29 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
} catch (...) {
|
||||
Debug::log(LOG, "Rule size failed, rule: %s -> %s", r.szRule.c_str(), r.szValue.c_str());
|
||||
}
|
||||
} else if (r.szRule.find("minsize") == 0) {
|
||||
try {
|
||||
const auto VALUE = r.szRule.substr(r.szRule.find(" ") + 1);
|
||||
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(" "));
|
||||
const auto SIZEYSTR = VALUE.substr(VALUE.find(" ") + 1);
|
||||
|
||||
const auto SIZE = Vector2D(std::max((double)std::stoll(SIZEXSTR), PWINDOW->m_vRealSize.goalv().x), std::max((double)std::stoll(SIZEYSTR), PWINDOW->m_vRealSize.goalv().y));
|
||||
|
||||
PWINDOW->m_vRealSize = SIZE;
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
|
||||
|
||||
PWINDOW->m_bHidden = false;
|
||||
} catch (...) {
|
||||
Debug::log(LOG, "Rule minsize failed, rule: %s -> %s", r.szRule.c_str(), r.szValue.c_str());
|
||||
}
|
||||
} else if (r.szRule.find("move") == 0) {
|
||||
try {
|
||||
const auto VALUE = r.szRule.substr(r.szRule.find(" ") + 1);
|
||||
const auto POSXSTR = VALUE.substr(0, VALUE.find(" "));
|
||||
const auto POSYSTR = VALUE.substr(VALUE.find(" ") + 1);
|
||||
|
||||
const auto POSX = !POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stoi(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01f * PMONITOR->vecSize.x;
|
||||
const auto POSY = !POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stoi(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01f * PMONITOR->vecSize.y;
|
||||
const auto POSX = !POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stoi(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.x;
|
||||
const auto POSY = !POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stoi(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.y;
|
||||
|
||||
Debug::log(LOG, "Rule move, applying to window %x", PWINDOW);
|
||||
|
||||
@@ -254,6 +291,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
// set the pseudo size to the GOAL of our current size
|
||||
// because the windows are animated on RealSize
|
||||
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goalv();
|
||||
|
||||
g_pCompositor->moveWindowToTop(PWINDOW);
|
||||
}
|
||||
else {
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW);
|
||||
@@ -262,23 +301,34 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goalv() - Vector2D(10,10);
|
||||
}
|
||||
|
||||
const auto PFOCUSEDWINDOWPREV = g_pCompositor->m_pLastWindow;
|
||||
|
||||
if (PWINDOW->m_sAdditionalConfigData.forceAllowsInput) {
|
||||
PWINDOW->m_bNoFocus = false;
|
||||
PWINDOW->m_bNoInitialFocus = false;
|
||||
PWINDOW->m_bX11ShouldntFocus = false;
|
||||
}
|
||||
|
||||
if (!PWINDOW->m_bNoFocus && !PWINDOW->m_bNoInitialFocus && PWINDOW->m_iX11Type != 2) {
|
||||
g_pCompositor->focusWindow(PWINDOW);
|
||||
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA);
|
||||
} else
|
||||
PWINDOW->m_fDimPercent.setValueAndWarp(*PDIMSTRENGTH);
|
||||
} else {
|
||||
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PINACTIVEALPHA);
|
||||
PWINDOW->m_fDimPercent.setValueAndWarp(0);
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Window got assigned a surfaceTreeNode %x", PWINDOW->m_pSurfaceTree);
|
||||
|
||||
if (!PWINDOW->m_bIsX11) {
|
||||
PWINDOW->hyprListener_commitWindow.initCallback(&PWINDOW->m_uSurface.xdg->surface->events.commit, &Events::listener_commitWindow, PWINDOW, "XDG Window Late");
|
||||
PWINDOW->hyprListener_setTitleWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.set_title, &Events::listener_setTitleWindow, PWINDOW, "XDG Window Late");
|
||||
PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW, "XDG Window Late");
|
||||
PWINDOW->hyprListener_newPopupXDG.initCallback(&PWINDOW->m_uSurface.xdg->events.new_popup, &Events::listener_newPopupXDG, PWINDOW, "XDG Window Late");
|
||||
PWINDOW->hyprListener_requestMaximize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_maximize, &Events::listener_requestMaximize, PWINDOW, "XDG Window Late");
|
||||
PWINDOW->hyprListener_requestMinimize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_minimize, &Events::listener_requestMinimize, PWINDOW, "XDG Window Late");
|
||||
PWINDOW->hyprListener_requestMove.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_move, &Events::listener_requestMove, PWINDOW, "XDG Window Late");
|
||||
PWINDOW->hyprListener_requestResize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_resize, &Events::listener_requestResize, PWINDOW, "XDG Window Late");
|
||||
PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW, "XDG Window Late");
|
||||
} else {
|
||||
PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW, "XWayland Window Late");
|
||||
PWINDOW->hyprListener_activateX11.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_activate, &Events::listener_activateX11, PWINDOW, "XWayland Window Late");
|
||||
@@ -299,6 +349,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
|
||||
if (workspaceSilent) {
|
||||
// move the window
|
||||
const auto OLDWORKSPACE = PWINDOW->m_iWorkspaceID;
|
||||
|
||||
if (g_pCompositor->m_pLastWindow == PWINDOW) {
|
||||
if (requestedWorkspace != "special")
|
||||
g_pKeybindManager->m_mDispatchers["movetoworkspacesilent"](requestedWorkspace);
|
||||
@@ -307,14 +359,15 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
} else {
|
||||
Debug::log(ERR, "Tried to set workspace silent rule to a nofocus window!");
|
||||
}
|
||||
|
||||
g_pCompositor->forceReportSizesToWindowsOnWorkspace(OLDWORKSPACE);
|
||||
}
|
||||
|
||||
if (requestsFullscreen) {
|
||||
// fix fullscreen on requested (basically do a switcheroo)
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow) {
|
||||
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
|
||||
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PFULLWINDOW, FULLSCREEN_FULL, false);
|
||||
g_pXWaylandManager->setWindowFullscreen(PFULLWINDOW, PFULLWINDOW->m_bIsFullscreen);
|
||||
g_pCompositor->setWindowFullscreen(PFULLWINDOW, false, FULLSCREEN_FULL);
|
||||
}
|
||||
|
||||
PWINDOW->m_vRealPosition.warp();
|
||||
@@ -323,6 +376,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
g_pCompositor->setWindowFullscreen(PWINDOW, true, FULLSCREEN_FULL);
|
||||
}
|
||||
|
||||
if (pFullscreenWindow && workspaceSilent) {
|
||||
g_pCompositor->setWindowFullscreen(pFullscreenWindow, true, PWORKSPACE->m_efFullscreenMode);
|
||||
}
|
||||
|
||||
// recheck idle inhibitors
|
||||
g_pInputManager->recheckIdleInhibitorStatus();
|
||||
|
||||
@@ -330,7 +387,86 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
|
||||
PWINDOW->updateToplevel();
|
||||
|
||||
if (!shouldFocus) {
|
||||
if (g_pCompositor->windowValidMapped(PFOCUSEDWINDOWPREV)) {
|
||||
g_pCompositor->focusWindow(PFOCUSEDWINDOWPREV);
|
||||
PFOCUSEDWINDOWPREV->updateWindowDecos(); // need to for some reason i cba to find out why
|
||||
} else if (!PFOCUSEDWINDOWPREV)
|
||||
g_pCompositor->focusWindow(nullptr);
|
||||
}
|
||||
|
||||
// verify swallowing
|
||||
if (*PSWALLOW) {
|
||||
// check parent
|
||||
int ppid = getPPIDof(PWINDOW->getPID());
|
||||
|
||||
const auto PPPID = getPPIDof(ppid);
|
||||
|
||||
// why? no clue. Blame terminals.
|
||||
if (PPPID > 2) {
|
||||
ppid = PPPID;
|
||||
}
|
||||
|
||||
if (ppid) {
|
||||
// get window by pid
|
||||
std::vector<CWindow*> found;
|
||||
CWindow* finalFound = nullptr;
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (!w->m_bIsMapped || w->m_bHidden)
|
||||
continue;
|
||||
|
||||
if (w->getPID() == ppid) {
|
||||
found.push_back(w.get());
|
||||
}
|
||||
}
|
||||
|
||||
if (found.size() > 1) {
|
||||
for (auto& w : found) {
|
||||
// try get the focus
|
||||
if (w == PFOCUSEDWINDOWPREV) {
|
||||
finalFound = w;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!finalFound) {
|
||||
// just get the closest (ws)
|
||||
for (auto& w : found) {
|
||||
if (w->m_iWorkspaceID == g_pCompositor->m_pLastMonitor->activeWorkspace) {
|
||||
finalFound = w;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!finalFound) {
|
||||
// what, just use 0
|
||||
finalFound = found[0];
|
||||
}
|
||||
|
||||
} else if (found.size() == 1) {
|
||||
finalFound = found[0];
|
||||
}
|
||||
|
||||
if (finalFound) {
|
||||
// check if it's the window we want
|
||||
std::regex rgx(*PSWALLOWREGEX);
|
||||
if (std::regex_match(g_pXWaylandManager->getAppIDClass(finalFound), rgx)) {
|
||||
// swallow
|
||||
PWINDOW->m_pSwallowed = finalFound;
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(finalFound);
|
||||
|
||||
finalFound->m_bHidden = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Map request dispatched, monitor %s, xywh: %f %f %f %f", PMONITOR->szName.c_str(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y, PWINDOW->m_vRealSize.goalv().x, PWINDOW->m_vRealSize.goalv().y);
|
||||
|
||||
auto workspaceID = requestedWorkspace != "" ? requestedWorkspace : PWORKSPACE->m_szName;
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", getFormat("%x,%s,%s,%s", PWINDOW, workspaceID.c_str(), g_pXWaylandManager->getAppIDClass(PWINDOW).c_str(), PWINDOW->m_szTitle.c_str())});
|
||||
}
|
||||
|
||||
void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
@@ -338,16 +474,18 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
|
||||
Debug::log(LOG, "Window %x unmapped (class %s)", PWINDOW, g_pXWaylandManager->getAppIDClass(PWINDOW).c_str());
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", getFormat("%x", PWINDOW)});
|
||||
|
||||
if (!PWINDOW->m_bIsX11) {
|
||||
Debug::log(LOG, "Unregistered late callbacks XDG");
|
||||
PWINDOW->hyprListener_commitWindow.removeCallback();
|
||||
PWINDOW->hyprListener_setTitleWindow.removeCallback();
|
||||
PWINDOW->hyprListener_fullscreenWindow.removeCallback();
|
||||
PWINDOW->hyprListener_newPopupXDG.removeCallback();
|
||||
PWINDOW->hyprListener_requestMaximize.removeCallback();
|
||||
PWINDOW->hyprListener_requestMinimize.removeCallback();
|
||||
PWINDOW->hyprListener_requestMove.removeCallback();
|
||||
PWINDOW->hyprListener_requestResize.removeCallback();
|
||||
PWINDOW->hyprListener_fullscreenWindow.removeCallback();
|
||||
} else {
|
||||
Debug::log(LOG, "Unregistered late callbacks XWL");
|
||||
PWINDOW->hyprListener_fullscreenWindow.removeCallback();
|
||||
@@ -358,14 +496,23 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
}
|
||||
|
||||
if (PWINDOW->m_bIsFullscreen) {
|
||||
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, FULLSCREEN_FULL, false);
|
||||
g_pXWaylandManager->setWindowFullscreen(PWINDOW, PWINDOW->m_bIsFullscreen);
|
||||
g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL);
|
||||
}
|
||||
|
||||
// Allow the renderer to catch the last frame.
|
||||
g_pHyprOpenGL->makeWindowSnapshot(PWINDOW);
|
||||
|
||||
// swallowing
|
||||
if (PWINDOW->m_pSwallowed && g_pCompositor->windowExists(PWINDOW->m_pSwallowed)) {
|
||||
PWINDOW->m_pSwallowed->m_bHidden = false;
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW->m_pSwallowed);
|
||||
PWINDOW->m_pSwallowed = nullptr;
|
||||
}
|
||||
|
||||
bool wasLastWindow = false;
|
||||
|
||||
if (PWINDOW == g_pCompositor->m_pLastWindow) {
|
||||
wasLastWindow = true;
|
||||
g_pCompositor->m_pLastWindow = nullptr;
|
||||
g_pCompositor->m_pLastFocus = nullptr;
|
||||
}
|
||||
@@ -383,18 +530,27 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
// do this after onWindowRemoved because otherwise it'll think the window is invalid
|
||||
PWINDOW->m_bIsMapped = false;
|
||||
|
||||
// refocus on a new window
|
||||
// refocus on a new window if needed
|
||||
if (wasLastWindow) {
|
||||
auto PWINDOWCANDIDATE = g_pCompositor->vectorToWindowIdeal(PWINDOW->m_vRealPosition.goalv() + PWINDOW->m_vRealSize.goalv() / 2.f);
|
||||
|
||||
if (!PWINDOWCANDIDATE)
|
||||
PWINDOWCANDIDATE = g_pCompositor->getFirstWindowOnWorkspace(PWINDOW->m_iWorkspaceID);
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow && ((!PWINDOWCANDIDATE || !PWINDOWCANDIDATE->m_bCreatedOverFullscreen) || !PWINDOW->m_bIsFloating))
|
||||
PWINDOWCANDIDATE = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
|
||||
|
||||
if (!PWINDOWCANDIDATE || PWINDOW == PWINDOWCANDIDATE || !PWINDOWCANDIDATE->m_bIsMapped || PWINDOWCANDIDATE->m_bHidden || PWINDOWCANDIDATE->m_bX11ShouldntFocus || PWINDOWCANDIDATE->m_iX11Type == 2)
|
||||
if (!PWINDOWCANDIDATE || PWINDOW == PWINDOWCANDIDATE || !PWINDOWCANDIDATE->m_bIsMapped || PWINDOWCANDIDATE->m_bHidden || PWINDOWCANDIDATE->m_bX11ShouldntFocus || PWINDOWCANDIDATE->m_iX11Type == 2 || PWINDOWCANDIDATE->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID)
|
||||
PWINDOWCANDIDATE = nullptr;
|
||||
|
||||
Debug::log(LOG, "On closed window, new focused candidate is %x", PWINDOWCANDIDATE);
|
||||
|
||||
if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow) {
|
||||
if (!PWINDOWCANDIDATE)
|
||||
g_pInputManager->refocus();
|
||||
else
|
||||
g_pCompositor->focusWindow(PWINDOWCANDIDATE);
|
||||
}
|
||||
} else {
|
||||
Debug::log(LOG, "Unmapped was not focused, ignoring a refocus.");
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Destroying the SubSurface tree of unmapped window %x", PWINDOW);
|
||||
SubsurfaceTree::destroySurfaceTree(PWINDOW->m_pSurfaceTree);
|
||||
@@ -485,7 +641,12 @@ void Events::listener_setTitleWindow(void* owner, void* data) {
|
||||
void Events::listener_fullscreenWindow(void* owner, void* data) {
|
||||
CWindow* PWINDOW = (CWindow*)owner;
|
||||
|
||||
if (!PWINDOW->m_bIsMapped || PWINDOW->m_bHidden)
|
||||
if (!PWINDOW->m_bIsMapped) {
|
||||
PWINDOW->m_bWantsInitialFullscreen = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (PWINDOW->m_bHidden)
|
||||
return;
|
||||
|
||||
if (!PWINDOW->m_bIsX11) {
|
||||
@@ -640,7 +801,10 @@ void Events::listener_NewXDGDeco(wl_listener* listener, void* data) {
|
||||
void Events::listener_requestMaximize(void* owner, void* data) {
|
||||
const auto PWINDOW = (CWindow*)owner;
|
||||
|
||||
// ignore
|
||||
const auto EV = (wlr_foreign_toplevel_handle_v1_maximized_event*)data;
|
||||
|
||||
g_pCompositor->setWindowFullscreen(PWINDOW, EV ? EV->maximized : !PWINDOW->m_bIsFullscreen, FULLSCREEN_MAXIMIZED); // this will be rejected if there already is a fullscreen window
|
||||
|
||||
wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg);
|
||||
}
|
||||
|
||||
|
@@ -59,5 +59,5 @@ void CAnimatedVariable::unregister() {
|
||||
}
|
||||
|
||||
int CAnimatedVariable::getDurationLeftMs() {
|
||||
return std::clamp((int)(m_pConfig->pValues->internalSpeed * 100) - (int)std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - animationBegin).count(), 0, INT_MAX);
|
||||
return std::max((int)(m_pConfig->pValues->internalSpeed * 100) - (int)std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - animationBegin).count(), 0);
|
||||
}
|
||||
|
@@ -1,9 +1,7 @@
|
||||
#include "Color.hpp"
|
||||
#include "../defines.hpp"
|
||||
|
||||
CColor::CColor() {
|
||||
|
||||
}
|
||||
CColor::CColor() { }
|
||||
|
||||
CColor::CColor(float r, float g, float b, float a) {
|
||||
this->r = r;
|
||||
|
@@ -120,14 +120,18 @@ void scaleBox(wlr_box* box, float scale) {
|
||||
}
|
||||
|
||||
std::string removeBeginEndSpacesTabs(std::string str) {
|
||||
while (str[0] == ' ' || str[0] == '\t') {
|
||||
str = str.substr(1);
|
||||
int countBefore = 0;
|
||||
while (str[countBefore] == ' ' || str[countBefore] == '\t') {
|
||||
countBefore++;
|
||||
}
|
||||
|
||||
while (str.length() != 0 && (str[str.length() - 1] == ' ' || str[str.length() - 1] == '\t')) {
|
||||
str = str.substr(0, str.length() - 1);
|
||||
int countAfter = 0;
|
||||
while (str.length() != 0 && (str[str.length() - countAfter - 1] == ' ' || str[str.length() - 1 - countAfter] == '\t')) {
|
||||
countAfter++;
|
||||
}
|
||||
|
||||
str = str.substr(countBefore, str.length() - countBefore - countAfter);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
@@ -170,7 +174,28 @@ float getPlusMinusKeywordResult(std::string source, float relative) {
|
||||
}
|
||||
|
||||
bool isNumber(const std::string& str, bool allowfloat) {
|
||||
return std::ranges::all_of(str.begin(), str.end(), [&](char c) { return isdigit(c) != 0 || c == '-' || (allowfloat && c == '.'); });
|
||||
|
||||
std::string copy = str;
|
||||
if (*copy.begin() == '-')
|
||||
copy = copy.substr(1);
|
||||
|
||||
if (copy.empty())
|
||||
return false;
|
||||
|
||||
bool point = !allowfloat;
|
||||
for (auto& c : copy) {
|
||||
if (c == '.') {
|
||||
if (point)
|
||||
return false;
|
||||
point = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!std::isdigit(c))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isDirection(const std::string& arg) {
|
||||
@@ -192,7 +217,7 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||
}
|
||||
outName = WORKSPACENAME;
|
||||
} else {
|
||||
if (in[0] == 'm' || in[0] == 'e') {
|
||||
if ((in[0] == 'm' || in[0] == 'e') && (in[1] == '-' || in[1] == '+') && isNumber(in.substr(2))) {
|
||||
bool onAllMonitors = in[0] == 'e';
|
||||
|
||||
if (!g_pCompositor->m_pLastMonitor) {
|
||||
@@ -221,6 +246,9 @@ 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)
|
||||
continue;
|
||||
|
||||
if (w->m_iID < lowestID)
|
||||
lowestID = w->m_iID;
|
||||
|
||||
@@ -250,14 +278,22 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||
outName = g_pCompositor->getWorkspaceByID(currentID)->m_szName;
|
||||
|
||||
} else {
|
||||
if (in[0] == '+' || in[0] == '-') {
|
||||
if (g_pCompositor->m_pLastMonitor)
|
||||
result = std::clamp((int)getPlusMinusKeywordResult(in, g_pCompositor->m_pLastMonitor->activeWorkspace), 1, INT_MAX);
|
||||
else if (isNumber(in))
|
||||
result = std::clamp(std::stoi(in), 1, INT_MAX);
|
||||
result = std::max((int)getPlusMinusKeywordResult(in, g_pCompositor->m_pLastMonitor->activeWorkspace), 1);
|
||||
else {
|
||||
Debug::log(ERR, "Relative workspace on no mon!");
|
||||
result = INT_MAX;
|
||||
}
|
||||
} else if (isNumber(in))
|
||||
result = std::max(std::stoi(in), 1);
|
||||
else {
|
||||
// maybe name
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByName(in);
|
||||
if (PWORKSPACE)
|
||||
result = PWORKSPACE->m_iID;
|
||||
}
|
||||
|
||||
outName = std::to_string(result);
|
||||
}
|
||||
}
|
||||
@@ -266,8 +302,8 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||
}
|
||||
|
||||
float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2) {
|
||||
const float DX = std::max((double)0, std::max(p1.x - vec.x, vec.x - p2.x));
|
||||
const float DY = std::max((double)0, std::max(p1.y - vec.y, vec.y - p2.y));
|
||||
const float DX = std::max({0.0, p1.x - vec.x, vec.x - p2.x});
|
||||
const float DY = std::max({0.0, p1.y - vec.y, vec.y - p2.y});
|
||||
return DX * DX + DY * DY;
|
||||
}
|
||||
|
||||
@@ -296,6 +332,15 @@ void logSystemInfo() {
|
||||
Debug::log(LOG, "Release: %s", unameInfo.release);
|
||||
Debug::log(LOG, "Version: %s", unameInfo.version);
|
||||
|
||||
Debug::log(NONE, "\n");
|
||||
|
||||
const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA");
|
||||
Debug::log(LOG, "GPU information:\n%s\n", GPUINFO.c_str());
|
||||
|
||||
if (GPUINFO.contains("NVIDIA")) {
|
||||
Debug::log(WARN, "Warning: you're using an NVIDIA GPU. Make sure you follow the instructions on the wiki if anything is amiss.\n");
|
||||
}
|
||||
|
||||
// log etc
|
||||
Debug::log(LOG, "os-release:");
|
||||
|
||||
@@ -322,3 +367,38 @@ void matrixProjection(float mat[9], int w, int h, wl_output_transform tr) {
|
||||
// Identity
|
||||
mat[8] = 1.0f;
|
||||
}
|
||||
|
||||
int64_t getPPIDof(int64_t pid) {
|
||||
std::string dir = "/proc/" + std::to_string(pid) + "/status";
|
||||
FILE* infile;
|
||||
|
||||
infile = fopen(dir.c_str(), "r");
|
||||
if (!infile)
|
||||
return 0;
|
||||
|
||||
char* line = nullptr;
|
||||
size_t len = 0;
|
||||
ssize_t len2 = 0;
|
||||
|
||||
std::string pidstr;
|
||||
|
||||
while ((len2 = getline(&line, &len, infile)) != -1) {
|
||||
if (strstr(line, "PPid:")) {
|
||||
pidstr = std::string(line, len2);
|
||||
const auto tabpos = pidstr.find_last_of('\t');
|
||||
if (tabpos != std::string::npos)
|
||||
pidstr = pidstr.substr(tabpos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(infile);
|
||||
if (line)
|
||||
free(line);
|
||||
|
||||
try {
|
||||
return std::stoll(pidstr);
|
||||
} catch (std::exception& e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
@@ -14,6 +14,7 @@ int getWorkspaceIDFromString(const std::string&, std::string&);
|
||||
float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2);
|
||||
void logSystemInfo();
|
||||
std::string execAndGet(const char*);
|
||||
int64_t getPPIDof(int64_t pid);
|
||||
|
||||
float getPlusMinusKeywordResult(std::string in, float relative);
|
||||
|
||||
|
@@ -9,7 +9,7 @@ void CMonitor::onConnect(bool noRule) {
|
||||
szName = output->name;
|
||||
|
||||
// get monitor rule that matches
|
||||
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(output->name);
|
||||
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);
|
||||
@@ -56,7 +56,17 @@ void CMonitor::onConnect(bool noRule) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (output->non_desktop) {
|
||||
Debug::log(LOG, "Not configuring non-desktop output");
|
||||
if (g_pCompositor->m_sWRLDRMLeaseMgr) {
|
||||
wlr_drm_lease_v1_manager_offer_output(g_pCompositor->m_sWRLDRMLeaseMgr, output);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_bRenderingInitPassed) {
|
||||
output->allocator = nullptr;
|
||||
output->renderer = nullptr;
|
||||
wlr_output_init_render(output, g_pCompositor->m_sWLRAllocator, g_pCompositor->m_sWLRRenderer);
|
||||
m_bRenderingInitPassed = true;
|
||||
}
|
||||
@@ -82,8 +92,6 @@ void CMonitor::onConnect(bool noRule) {
|
||||
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, monitorRule.scale);
|
||||
wlr_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL); // TODO: support other transforms
|
||||
|
||||
wlr_output_enable_adaptive_sync(output, 1);
|
||||
|
||||
// create it in the arr
|
||||
vecPosition = monitorRule.offset;
|
||||
vecSize = monitorRule.resolution;
|
||||
@@ -110,49 +118,13 @@ void CMonitor::onConnect(bool noRule) {
|
||||
|
||||
wlr_ext_workspace_group_handle_v1_output_enter(pWLRWorkspaceGroupHandle, output);
|
||||
|
||||
// Workspace
|
||||
std::string newDefaultWorkspaceName = "";
|
||||
auto WORKSPACEID = monitorRule.defaultWorkspace == "" ? g_pCompositor->m_vWorkspaces.size() + 1 : getWorkspaceIDFromString(monitorRule.defaultWorkspace, newDefaultWorkspaceName);
|
||||
setupDefaultWS(monitorRule);
|
||||
|
||||
if (WORKSPACEID == INT_MAX || WORKSPACEID == (long unsigned int)SPECIAL_WORKSPACE_ID) {
|
||||
WORKSPACEID = g_pCompositor->m_vWorkspaces.size() + 1;
|
||||
newDefaultWorkspaceName = std::to_string(WORKSPACEID);
|
||||
|
||||
Debug::log(LOG, "Invalid workspace= directive name in monitor parsing, workspace name \"%s\" is invalid.", monitorRule.defaultWorkspace.c_str());
|
||||
}
|
||||
|
||||
auto PNEWWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);
|
||||
|
||||
Debug::log(LOG, "New monitor: WORKSPACEID %d, exists: %d", WORKSPACEID, (int)(PNEWWORKSPACE != nullptr));
|
||||
|
||||
if (PNEWWORKSPACE) {
|
||||
// workspace exists, move it to the newly connected monitor
|
||||
g_pCompositor->moveWorkspaceToMonitor(PNEWWORKSPACE, this);
|
||||
activeWorkspace = PNEWWORKSPACE->m_iID;
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
|
||||
PNEWWORKSPACE->startAnim(true, true, true);
|
||||
} else {
|
||||
|
||||
if (newDefaultWorkspaceName == "")
|
||||
newDefaultWorkspaceName = std::to_string(WORKSPACEID);
|
||||
|
||||
PNEWWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(ID, newDefaultWorkspaceName)).get();
|
||||
|
||||
// We are required to set the name here immediately
|
||||
wlr_ext_workspace_handle_v1_set_name(PNEWWORKSPACE->m_pWlrHandle, newDefaultWorkspaceName.c_str());
|
||||
|
||||
PNEWWORKSPACE->m_iID = WORKSPACEID;
|
||||
}
|
||||
|
||||
activeWorkspace = PNEWWORKSPACE->m_iID;
|
||||
scale = monitorRule.scale;
|
||||
|
||||
m_pThisWrap = nullptr;
|
||||
|
||||
forceFullFrames = 3; // force 3 full frames to make sure there is no blinking due to double-buffering.
|
||||
|
||||
g_pCompositor->deactivateAllWLRWorkspaces(PNEWWORKSPACE->m_pWlrHandle);
|
||||
PNEWWORKSPACE->setActive(true);
|
||||
//
|
||||
|
||||
if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet
|
||||
@@ -168,7 +140,7 @@ void CMonitor::onConnect(bool noRule) {
|
||||
|
||||
void CMonitor::onDisconnect() {
|
||||
|
||||
if (!m_bEnabled)
|
||||
if (!m_bEnabled || g_pCompositor->m_bIsShuttingDown)
|
||||
return;
|
||||
|
||||
// Cleanup everything. Move windows back, snap cursor, shit.
|
||||
@@ -180,6 +152,20 @@ void CMonitor::onDisconnect() {
|
||||
}
|
||||
}
|
||||
|
||||
// remove mirror
|
||||
if (pMirrorOf) {
|
||||
pMirrorOf->mirrors.erase(std::find_if(pMirrorOf->mirrors.begin(), pMirrorOf->mirrors.end(), [&](const auto& other) { return other == this; }));
|
||||
pMirrorOf = nullptr;
|
||||
}
|
||||
|
||||
if (!mirrors.empty()) {
|
||||
for (auto& m : mirrors) {
|
||||
m->setMirror("");
|
||||
}
|
||||
|
||||
g_pConfigManager->m_bWantsMonitorReload = true;
|
||||
}
|
||||
|
||||
m_bEnabled = false;
|
||||
m_bRenderingInitPassed = false;
|
||||
|
||||
@@ -232,3 +218,144 @@ void CMonitor::onDisconnect() {
|
||||
|
||||
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; }));
|
||||
}
|
||||
|
||||
void CMonitor::addDamage(pixman_region32_t* rg) {
|
||||
wlr_output_damage_add(damage, rg);
|
||||
}
|
||||
|
||||
void CMonitor::addDamage(wlr_box* box) {
|
||||
wlr_output_damage_add_box(damage, box);
|
||||
}
|
||||
|
||||
bool CMonitor::isMirror() {
|
||||
return pMirrorOf != nullptr;
|
||||
}
|
||||
|
||||
void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) {
|
||||
// Workspace
|
||||
std::string newDefaultWorkspaceName = "";
|
||||
auto WORKSPACEID = monitorRule.defaultWorkspace == "" ? g_pCompositor->m_vWorkspaces.size() + 1 : getWorkspaceIDFromString(monitorRule.defaultWorkspace, newDefaultWorkspaceName);
|
||||
|
||||
if (WORKSPACEID == INT_MAX || WORKSPACEID == (long unsigned int)SPECIAL_WORKSPACE_ID) {
|
||||
WORKSPACEID = g_pCompositor->m_vWorkspaces.size() + 1;
|
||||
newDefaultWorkspaceName = std::to_string(WORKSPACEID);
|
||||
|
||||
Debug::log(LOG, "Invalid workspace= directive name in monitor parsing, workspace name \"%s\" is invalid.", monitorRule.defaultWorkspace.c_str());
|
||||
}
|
||||
|
||||
auto PNEWWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);
|
||||
|
||||
Debug::log(LOG, "New monitor: WORKSPACEID %d, exists: %d", WORKSPACEID, (int)(PNEWWORKSPACE != nullptr));
|
||||
|
||||
if (PNEWWORKSPACE) {
|
||||
// workspace exists, move it to the newly connected monitor
|
||||
g_pCompositor->moveWorkspaceToMonitor(PNEWWORKSPACE, this);
|
||||
activeWorkspace = PNEWWORKSPACE->m_iID;
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
|
||||
PNEWWORKSPACE->startAnim(true, true, true);
|
||||
} else {
|
||||
if (newDefaultWorkspaceName == "")
|
||||
newDefaultWorkspaceName = std::to_string(WORKSPACEID);
|
||||
|
||||
PNEWWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(ID, newDefaultWorkspaceName)).get();
|
||||
|
||||
// We are required to set the name here immediately
|
||||
wlr_ext_workspace_handle_v1_set_name(PNEWWORKSPACE->m_pWlrHandle, newDefaultWorkspaceName.c_str());
|
||||
|
||||
PNEWWORKSPACE->m_iID = WORKSPACEID;
|
||||
}
|
||||
|
||||
activeWorkspace = PNEWWORKSPACE->m_iID;
|
||||
|
||||
g_pCompositor->deactivateAllWLRWorkspaces(PNEWWORKSPACE->m_pWlrHandle);
|
||||
PNEWWORKSPACE->setActive(true);
|
||||
}
|
||||
|
||||
void CMonitor::setMirror(const std::string& mirrorOf) {
|
||||
const auto PMIRRORMON = g_pCompositor->getMonitorFromString(mirrorOf);
|
||||
|
||||
if (PMIRRORMON == pMirrorOf)
|
||||
return;
|
||||
|
||||
if (PMIRRORMON && PMIRRORMON->isMirror()) {
|
||||
Debug::log(ERR, "Cannot mirror a mirror!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (PMIRRORMON == this) {
|
||||
Debug::log(ERR, "Cannot mirror self!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PMIRRORMON) {
|
||||
// disable mirroring
|
||||
|
||||
if (pMirrorOf) {
|
||||
pMirrorOf->mirrors.erase(std::find_if(pMirrorOf->mirrors.begin(), pMirrorOf->mirrors.end(), [&](const auto& other) { return other == this; }));
|
||||
}
|
||||
|
||||
pMirrorOf = nullptr;
|
||||
|
||||
// set rule
|
||||
const auto RULE = g_pConfigManager->getMonitorRuleFor(this->szName, this->output->description ? this->output->description : "");
|
||||
|
||||
vecPosition = RULE.offset;
|
||||
|
||||
// push to mvmonitors
|
||||
if (!m_pThisWrap) {
|
||||
// find the wrap
|
||||
for (auto& m : g_pCompositor->m_vRealMonitors) {
|
||||
if (m->ID == ID) {
|
||||
m_pThisWrap = &m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (std::find_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& other) { return other.get() == this; }) == g_pCompositor->m_vMonitors.end()) {
|
||||
g_pCompositor->m_vMonitors.push_back(*m_pThisWrap);
|
||||
}
|
||||
|
||||
setupDefaultWS(RULE);
|
||||
|
||||
wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, output, (int)vecPosition.x, (int)vecPosition.y);
|
||||
} else {
|
||||
CMonitor* BACKUPMON = nullptr;
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
if (m.get() != this) {
|
||||
BACKUPMON = m.get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// move all the WS
|
||||
std::deque<CWorkspace*> wspToMove;
|
||||
for (auto& w : g_pCompositor->m_vWorkspaces) {
|
||||
if (w->m_iMonitorID == ID) {
|
||||
wspToMove.push_back(w.get());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& w : wspToMove) {
|
||||
g_pCompositor->moveWorkspaceToMonitor(w, BACKUPMON);
|
||||
w->startAnim(true, true, true);
|
||||
}
|
||||
|
||||
activeWorkspace = -1;
|
||||
|
||||
wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output);
|
||||
|
||||
vecPosition = Vector2D(-1337420, -1337420);
|
||||
|
||||
pMirrorOf = PMIRRORMON;
|
||||
|
||||
pMirrorOf->mirrors.push_back(this);
|
||||
|
||||
// remove from mvmonitors
|
||||
if (std::find_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& other) { return other.get() == this; }) != g_pCompositor->m_vMonitors.end()) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@@ -7,6 +7,8 @@
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
struct SMonitorRule;
|
||||
|
||||
class CMonitor {
|
||||
public:
|
||||
Vector2D vecPosition = Vector2D(0,0);
|
||||
@@ -35,6 +37,12 @@ public:
|
||||
bool scheduledRecalc = false;
|
||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
|
||||
bool dpmsStatus = true;
|
||||
|
||||
// mirroring
|
||||
CMonitor* pMirrorOf = nullptr;
|
||||
std::vector<CMonitor*> mirrors;
|
||||
|
||||
// for the special workspace
|
||||
bool specialWorkspaceOpen = false;
|
||||
|
||||
@@ -55,6 +63,10 @@ public:
|
||||
// methods
|
||||
void onConnect(bool noRule);
|
||||
void onDisconnect();
|
||||
void addDamage(pixman_region32_t* rg);
|
||||
void addDamage(wlr_box* box);
|
||||
void setMirror(const std::string&);
|
||||
bool isMirror();
|
||||
|
||||
std::shared_ptr<CMonitor>* m_pThisWrap = nullptr;
|
||||
bool m_bEnabled = false;
|
||||
@@ -65,4 +77,7 @@ public:
|
||||
bool operator==(const CMonitor& rhs) {
|
||||
return vecPosition == rhs.vecPosition && vecSize == rhs.vecSize && szName == rhs.szName;
|
||||
}
|
||||
|
||||
private:
|
||||
void setupDefaultWS(const SMonitorRule&);
|
||||
};
|
@@ -101,6 +101,14 @@ void SubsurfaceTree::destroySurfaceTree(SSurfaceTreeNode* pNode) {
|
||||
g_pHyprRenderer->damageBox(&extents);
|
||||
}
|
||||
|
||||
// remove references to this node
|
||||
for (auto& tn : surfaceTreeNodes) {
|
||||
for (auto& cs : tn.childSubsurfaces) {
|
||||
if (cs.pChild == pNode)
|
||||
cs.pChild = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
surfaceTreeNodes.remove(*pNode);
|
||||
|
||||
Debug::log(LOG, "SurfaceTree Node removed");
|
||||
@@ -139,6 +147,9 @@ void Events::listener_newSubsurfaceNode(void* owner, void* data) {
|
||||
|
||||
PNEWSUBSURFACE->pWindowOwner = pNode->pWindowOwner;
|
||||
|
||||
if (PSUBSURFACE->mapped)
|
||||
listener_mapSubsurface(PNEWSUBSURFACE, nullptr);
|
||||
|
||||
wlr_subsurface* existingWlrSubsurface;
|
||||
wl_list_for_each(existingWlrSubsurface, &PSUBSURFACE->surface->current.subsurfaces_below, current.link) {
|
||||
listener_newSubsurfaceNode(pNode, existingWlrSubsurface);
|
||||
@@ -151,6 +162,9 @@ void Events::listener_newSubsurfaceNode(void* owner, void* data) {
|
||||
void Events::listener_mapSubsurface(void* owner, void* data) {
|
||||
SSubsurface* subsurface = (SSubsurface*)owner;
|
||||
|
||||
if (subsurface->pChild)
|
||||
return;
|
||||
|
||||
Debug::log(LOG, "Subsurface %x mapped", subsurface->pSubsurface);
|
||||
|
||||
subsurface->pChild = createSubsurfaceNode(subsurface->pParent, subsurface, subsurface->pSubsurface->surface, subsurface->pWindowOwner);
|
||||
@@ -167,18 +181,16 @@ void Events::listener_unmapSubsurface(void* owner, void* data) {
|
||||
int lx = 0, ly = 0;
|
||||
addSurfaceGlobalOffset(PNODE, &lx, &ly);
|
||||
|
||||
wlr_box extents = {0};
|
||||
wlr_box extents = {lx, ly, 0, 0};
|
||||
if (PNODE->pSurface) {
|
||||
wlr_surface_get_extends(PNODE->pSurface, &extents);
|
||||
|
||||
extents.x += lx;
|
||||
extents.y += ly;
|
||||
extents.width = PNODE->pSurface->current.width;
|
||||
extents.height = PNODE->pSurface->current.height;
|
||||
|
||||
g_pHyprRenderer->damageBox(&extents);
|
||||
}
|
||||
|
||||
SubsurfaceTree::destroySurfaceTree(subsurface->pChild);
|
||||
subsurface->pChild = nullptr;
|
||||
//SubsurfaceTree::destroySurfaceTree(subsurface->pChild);
|
||||
//subsurface->pChild = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,7 +199,7 @@ void Events::listener_commitSubsurface(void* owner, void* data) {
|
||||
|
||||
// no damaging if it's not visible
|
||||
if (!g_pHyprRenderer->shouldRenderWindow(pNode->pWindowOwner)) {
|
||||
static auto* const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
|
||||
static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
|
||||
if (*PLOGDAMAGE)
|
||||
Debug::log(LOG, "Refusing to commit damage from %x because it's invisible.", pNode->pWindowOwner);
|
||||
return;
|
||||
@@ -214,8 +226,9 @@ void Events::listener_commitSubsurface(void* owner, void* data) {
|
||||
void Events::listener_destroySubsurface(void* owner, void* data) {
|
||||
SSubsurface* subsurface = (SSubsurface*)owner;
|
||||
|
||||
if (subsurface->pChild)
|
||||
listener_destroySubsurfaceNode(subsurface->pChild, nullptr);
|
||||
if (subsurface->pChild) {
|
||||
SubsurfaceTree::destroySurfaceTree(subsurface->pChild);
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Subsurface %x destroyed", subsurface);
|
||||
|
||||
|
@@ -35,6 +35,10 @@ class Vector2D {
|
||||
return a.x != x || a.y != y;
|
||||
}
|
||||
|
||||
Vector2D operator*(const Vector2D& a) const {
|
||||
return Vector2D(this->x * a.x, this->y * a.y);
|
||||
}
|
||||
|
||||
Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D());
|
||||
|
||||
Vector2D floor();
|
||||
|
@@ -73,6 +73,9 @@ struct SRenderData {
|
||||
|
||||
// only for windows, not popups
|
||||
bool squishOversized = true;
|
||||
|
||||
// for calculating UV
|
||||
CWindow* pWindow = nullptr;
|
||||
};
|
||||
|
||||
struct SExtensionFindingData {
|
||||
@@ -306,6 +309,7 @@ struct SIMEPopup {
|
||||
int x, y;
|
||||
int realX, realY;
|
||||
bool visible;
|
||||
Vector2D lastSize;
|
||||
|
||||
DYNLISTENER(mapPopup);
|
||||
DYNLISTENER(unmapPopup);
|
||||
@@ -318,3 +322,24 @@ struct SIMEPopup {
|
||||
return pSurface == other.pSurface;
|
||||
}
|
||||
};
|
||||
|
||||
struct STouchDevice {
|
||||
wlr_input_device* pWlrDevice = nullptr;
|
||||
|
||||
DYNLISTENER(destroy);
|
||||
|
||||
bool operator==(const STouchDevice& other) {
|
||||
return pWlrDevice == other.pWlrDevice;
|
||||
}
|
||||
};
|
||||
|
||||
struct SSwitchDevice {
|
||||
wlr_input_device* pWlrDevice = nullptr;
|
||||
|
||||
DYNLISTENER(destroy);
|
||||
DYNLISTENER(toggle);
|
||||
|
||||
bool operator==(const SSwitchDevice& other) {
|
||||
return pWlrDevice == other.pWlrDevice;
|
||||
}
|
||||
};
|
||||
|
@@ -26,9 +26,9 @@ CWorkspace::CWorkspace(int monitorID, std::string name, bool special) {
|
||||
}
|
||||
|
||||
m_vRenderOffset.m_pWorkspace = this;
|
||||
m_vRenderOffset.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("workspaces"), nullptr, AVARDAMAGE_ENTIRE);
|
||||
m_vRenderOffset.create(AVARTYPE_VECTOR, special ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspace") : g_pConfigManager->getAnimationPropertyConfig("workspaces"), nullptr, AVARDAMAGE_ENTIRE);
|
||||
m_fAlpha.m_pWorkspace = this;
|
||||
m_fAlpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("workspaces"), nullptr, AVARDAMAGE_ENTIRE);
|
||||
m_fAlpha.create(AVARTYPE_FLOAT, special ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspace") : g_pConfigManager->getAnimationPropertyConfig("workspaces"), nullptr, AVARDAMAGE_ENTIRE);
|
||||
m_fAlpha.setValueAndWarp(255.f);
|
||||
|
||||
g_pEventManager->postEvent({"createworkspace", m_szName}, true);
|
||||
@@ -91,6 +91,15 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
|
||||
m_vRenderOffset.warp();
|
||||
m_fAlpha.warp();
|
||||
}
|
||||
|
||||
// check LS-es
|
||||
if (in) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||
for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
|
||||
if (!ls->fadingOut)
|
||||
ls->alpha = m_bHasFullscreenWindow && m_efFullscreenMode == FULLSCREEN_FULL ? 0.f : 255.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CWorkspace::setActive(bool on) {
|
||||
@@ -120,3 +129,10 @@ void CWorkspace::moveToMonitor(const int& id) {
|
||||
|
||||
wlr_ext_workspace_handle_v1_set_name(m_pWlrHandle, m_szName.c_str());
|
||||
}
|
||||
|
||||
CWindow* CWorkspace::getLastFocusedWindow() {
|
||||
if (!g_pCompositor->windowValidMapped(m_pLastFocusedWindow) || m_pLastFocusedWindow->m_iWorkspaceID != m_iID)
|
||||
return nullptr;
|
||||
|
||||
return m_pLastFocusedWindow;
|
||||
}
|
||||
|
@@ -8,6 +8,8 @@ enum eFullscreenMode : uint8_t {
|
||||
FULLSCREEN_MAXIMIZED
|
||||
};
|
||||
|
||||
class CWindow;
|
||||
|
||||
class CWorkspace {
|
||||
public:
|
||||
CWorkspace(int monitorID, std::string name, bool special = false);
|
||||
@@ -18,6 +20,9 @@ public:
|
||||
int m_iID = -1;
|
||||
std::string m_szName = "";
|
||||
uint64_t m_iMonitorID = -1;
|
||||
// Previous workspace ID is stored during a workspace change, allowing travel
|
||||
// to the previous workspace.
|
||||
int m_iPrevWorkspaceID = -1;
|
||||
bool m_bHasFullscreenWindow = false;
|
||||
eFullscreenMode m_efFullscreenMode = FULLSCREEN_FULL;
|
||||
|
||||
@@ -33,6 +38,9 @@ public:
|
||||
// "scratchpad"
|
||||
bool m_bIsSpecialWorkspace = false;
|
||||
|
||||
// last window
|
||||
CWindow* m_pLastFocusedWindow = nullptr;
|
||||
|
||||
// user-set
|
||||
bool m_bDefaultFloating = false;
|
||||
bool m_bDefaultPseudo = false;
|
||||
@@ -41,4 +49,6 @@ public:
|
||||
void setActive(bool on);
|
||||
|
||||
void moveToMonitor(const int&);
|
||||
|
||||
CWindow* getLastFocusedWindow();
|
||||
};
|
@@ -37,12 +37,15 @@
|
||||
extern "C" {
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/backend/libinput.h>
|
||||
#include <wlr/backend/drm.h>
|
||||
#include <wlr/render/allocator.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_cursor.h>
|
||||
#include <wlr/types/wlr_data_control_v1.h>
|
||||
#include <wlr/types/wlr_data_device.h>
|
||||
#include <wlr/types/wlr_drm_lease_v1.h>
|
||||
#include <wlr/types/wlr_drm.h>
|
||||
#include <wlr/types/wlr_export_dmabuf_v1.h>
|
||||
#include <wlr/types/wlr_linux_dmabuf_v1.h>
|
||||
#include <wlr/types/wlr_gamma_control_v1.h>
|
||||
@@ -98,6 +101,7 @@ extern "C" {
|
||||
#include <wlr/types/wlr_input_method_v2.h>
|
||||
#include <wlr/types/wlr_text_input_v3.h>
|
||||
#include <wlr/types/wlr_touch.h>
|
||||
#include <wlr/types/wlr_switch.h>
|
||||
}
|
||||
|
||||
#undef delete
|
||||
|
@@ -6,9 +6,11 @@ void SDwindleNodeData::recalcSizePosRecursive(bool force) {
|
||||
|
||||
const auto REVERSESPLITRATIO = 2.f - splitRatio;
|
||||
|
||||
if (g_pConfigManager->getInt("dwindle:preserve_split") == 0) {
|
||||
const auto WIDTHMULTIPLIER = g_pConfigManager->getFloat("dwindle:split_width_multiplier");
|
||||
splitTop = size.y * WIDTHMULTIPLIER > size.x;
|
||||
static auto *const PPRESERVESPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:preserve_split")->intValue;
|
||||
static auto *const PFLMULT = &g_pConfigManager->getConfigValuePtr("dwindle:split_width_multiplier")->floatValue;
|
||||
|
||||
if (*PPRESERVESPLIT == 0) {
|
||||
splitTop = size.y * *PFLMULT > size.x;
|
||||
}
|
||||
|
||||
const auto SPLITSIDE = !splitTop;
|
||||
@@ -88,6 +90,19 @@ void SDwindleNodeData::setGroupFocusedNode(SDwindleNodeData* pMember) {
|
||||
this->pWindow->m_bHidden = pMember != this;
|
||||
}
|
||||
|
||||
int SDwindleNodeData::getGroupMemberCount() {
|
||||
SDwindleNodeData* current = this->pNextGroupMember;
|
||||
|
||||
int no = 1;
|
||||
|
||||
while (current != this) {
|
||||
current = current->pNextGroupMember;
|
||||
no++;
|
||||
}
|
||||
|
||||
return no;
|
||||
}
|
||||
|
||||
int CHyprDwindleLayout::getNodesOnWorkspace(const int& id) {
|
||||
int no = 0;
|
||||
for (auto& n : m_lDwindleNodesData) {
|
||||
@@ -151,14 +166,15 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
|
||||
const bool DISPLAYTOP = STICKS(pNode->position.y, PMONITOR->vecPosition.y + PMONITOR->vecReservedTopLeft.y);
|
||||
const bool DISPLAYBOTTOM = STICKS(pNode->position.y + pNode->size.y, PMONITOR->vecPosition.y + PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y);
|
||||
|
||||
const auto BORDERSIZE = g_pConfigManager->getInt("general:border_size");
|
||||
const auto GAPSIN = g_pConfigManager->getInt("general:gaps_in");
|
||||
const auto GAPSOUT = g_pConfigManager->getInt("general:gaps_out");
|
||||
const auto PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
|
||||
const auto PGAPSIN = &g_pConfigManager->getConfigValuePtr("general:gaps_in")->intValue;
|
||||
const auto PGAPSOUT = &g_pConfigManager->getConfigValuePtr("general:gaps_out")->intValue;
|
||||
|
||||
const auto PWINDOW = pNode->pWindow;
|
||||
|
||||
if (!g_pCompositor->windowExists(PWINDOW) || !PWINDOW->m_bIsMapped) {
|
||||
Debug::log(ERR, "Node %x holding invalid window %x!!", pNode, PWINDOW);
|
||||
onWindowRemovedTiling(PWINDOW);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -167,29 +183,33 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
|
||||
|
||||
static auto *const PNOGAPSWHENONLY = &g_pConfigManager->getConfigValuePtr("dwindle:no_gaps_when_only")->intValue;
|
||||
|
||||
auto calcPos = PWINDOW->m_vPosition + Vector2D(BORDERSIZE, BORDERSIZE);
|
||||
auto calcSize = PWINDOW->m_vSize - Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE);
|
||||
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) {
|
||||
PWINDOW->m_vRealPosition = calcPos - Vector2D(BORDERSIZE, BORDERSIZE);
|
||||
PWINDOW->m_vRealSize = calcSize + Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE);
|
||||
const auto NODESONWORKSPACE = getNodesOnWorkspace(PWINDOW->m_iWorkspaceID);
|
||||
|
||||
if (*PNOGAPSWHENONLY && PWINDOW->m_iWorkspaceID != SPECIAL_WORKSPACE_ID && (NODESONWORKSPACE == 1 || (pNode->isGroupMember() && pNode->getGroupMemberCount() == NODESONWORKSPACE))) {
|
||||
PWINDOW->m_vRealPosition = calcPos - Vector2D(*PBORDERSIZE, *PBORDERSIZE);
|
||||
PWINDOW->m_vRealSize = calcSize + Vector2D(2 * *PBORDERSIZE, 2 * *PBORDERSIZE);
|
||||
|
||||
PWINDOW->updateWindowDecos();
|
||||
|
||||
PWINDOW->m_sSpecialRenderData.rounding = false;
|
||||
PWINDOW->m_sSpecialRenderData.border = false;
|
||||
PWINDOW->m_sSpecialRenderData.decorate = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
PWINDOW->m_sSpecialRenderData.rounding = true;
|
||||
PWINDOW->m_sSpecialRenderData.border = true;
|
||||
PWINDOW->m_sSpecialRenderData.decorate = true;
|
||||
|
||||
const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? GAPSOUT : GAPSIN,
|
||||
DISPLAYTOP ? GAPSOUT : GAPSIN);
|
||||
const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? *PGAPSOUT : *PGAPSIN,
|
||||
DISPLAYTOP ? *PGAPSOUT : *PGAPSIN);
|
||||
|
||||
const auto OFFSETBOTTOMRIGHT = Vector2D(DISPLAYRIGHT ? GAPSOUT : GAPSIN,
|
||||
DISPLAYBOTTOM ? GAPSOUT : GAPSIN);
|
||||
const auto OFFSETBOTTOMRIGHT = Vector2D(DISPLAYRIGHT ? *PGAPSOUT : *PGAPSIN,
|
||||
DISPLAYBOTTOM ? *PGAPSOUT : *PGAPSIN);
|
||||
|
||||
calcPos = calcPos + OFFSETTOPLEFT;
|
||||
calcSize = calcSize - OFFSETTOPLEFT - OFFSETBOTTOMRIGHT;
|
||||
@@ -234,8 +254,12 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
|
||||
}
|
||||
|
||||
if (force) {
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
|
||||
PWINDOW->m_vRealPosition.warp();
|
||||
PWINDOW->m_vRealSize.warp();
|
||||
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
}
|
||||
|
||||
if (pNode->isGroupMember() && pNode->groupHead) {
|
||||
@@ -305,6 +329,13 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
|
||||
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow) {
|
||||
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
|
||||
g_pCompositor->setWindowFullscreen(PFULLWINDOW, false, FULLSCREEN_FULL);
|
||||
}
|
||||
|
||||
// if it's the first, it's easy. Make it fullscreen.
|
||||
if (!OPENINGON || OPENINGON->pWindow == pWindow) {
|
||||
PNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
|
||||
@@ -334,6 +365,8 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
|
||||
|
||||
applyNodeDataToWindow(PNODE);
|
||||
|
||||
pWindow->m_dWindowDecorations.emplace_back(std::make_unique<CHyprGroupBarDecoration>(pWindow));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -349,19 +382,19 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
|
||||
NEWPARENT->pParent = OPENINGON->pParent;
|
||||
NEWPARENT->isNode = true; // it is a node
|
||||
|
||||
const auto WIDTHMULTIPLIER = g_pConfigManager->getFloat("dwindle:split_width_multiplier");
|
||||
const auto PWIDTHMULTIPLIER = &g_pConfigManager->getConfigValuePtr("dwindle:split_width_multiplier")->floatValue;
|
||||
|
||||
// if cursor over first child, make it first, etc
|
||||
const auto SIDEBYSIDE = NEWPARENT->size.x > NEWPARENT->size.y * WIDTHMULTIPLIER;
|
||||
const auto SIDEBYSIDE = NEWPARENT->size.x > NEWPARENT->size.y * *PWIDTHMULTIPLIER;
|
||||
NEWPARENT->splitTop = !SIDEBYSIDE;
|
||||
|
||||
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
|
||||
|
||||
const auto FORCESPLIT = g_pConfigManager->getInt("dwindle:force_split");
|
||||
const auto PFORCESPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:force_split")->intValue;
|
||||
|
||||
if (FORCESPLIT == 0) {
|
||||
if ((SIDEBYSIDE && VECINRECT(MOUSECOORDS, NEWPARENT->position.x, NEWPARENT->position.y / WIDTHMULTIPLIER, NEWPARENT->position.x + NEWPARENT->size.x / 2.f, NEWPARENT->position.y + NEWPARENT->size.y))
|
||||
|| (!SIDEBYSIDE && VECINRECT(MOUSECOORDS, NEWPARENT->position.x, NEWPARENT->position.y / WIDTHMULTIPLIER, NEWPARENT->position.x + NEWPARENT->size.x, NEWPARENT->position.y + NEWPARENT->size.y / 2.f))) {
|
||||
if (*PFORCESPLIT == 0) {
|
||||
if ((SIDEBYSIDE && VECINRECT(MOUSECOORDS, NEWPARENT->position.x, NEWPARENT->position.y / *PWIDTHMULTIPLIER, NEWPARENT->position.x + NEWPARENT->size.x / 2.f, NEWPARENT->position.y + NEWPARENT->size.y))
|
||||
|| (!SIDEBYSIDE && VECINRECT(MOUSECOORDS, NEWPARENT->position.x, NEWPARENT->position.y / *PWIDTHMULTIPLIER, NEWPARENT->position.x + NEWPARENT->size.x, NEWPARENT->position.y + NEWPARENT->size.y / 2.f))) {
|
||||
// we are hovering over the first node, make PNODE first.
|
||||
NEWPARENT->children[1] = OPENINGON;
|
||||
NEWPARENT->children[0] = PNODE;
|
||||
@@ -371,7 +404,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
|
||||
NEWPARENT->children[1] = PNODE;
|
||||
}
|
||||
} else {
|
||||
if (FORCESPLIT == 1) {
|
||||
if (*PFORCESPLIT == 1) {
|
||||
NEWPARENT->children[1] = OPENINGON;
|
||||
NEWPARENT->children[0] = PNODE;
|
||||
} else {
|
||||
@@ -392,7 +425,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
|
||||
// Update the children
|
||||
|
||||
|
||||
if (NEWPARENT->size.x * WIDTHMULTIPLIER > NEWPARENT->size.y) {
|
||||
if (NEWPARENT->size.x * *PWIDTHMULTIPLIER > NEWPARENT->size.y) {
|
||||
// split left/right
|
||||
OPENINGON->position = NEWPARENT->position;
|
||||
OPENINGON->size = Vector2D(NEWPARENT->size.x / 2.f, NEWPARENT->size.y);
|
||||
@@ -424,6 +457,9 @@ void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pWindow->m_bIsFullscreen)
|
||||
g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL);
|
||||
|
||||
// check if it was grouped
|
||||
if (PNODE->isGroupMember()) {
|
||||
// get shit
|
||||
@@ -447,21 +483,25 @@ void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) {
|
||||
|
||||
PNEXT->position = PNODE->position;
|
||||
PNEXT->size = PNODE->size;
|
||||
|
||||
applyNodeDataToWindow(PNEXT);
|
||||
} else {
|
||||
const auto PHEAD = PNODE->getGroupHead();
|
||||
|
||||
PNEXT->position = PHEAD->position;
|
||||
PNEXT->size = PHEAD->size;
|
||||
|
||||
applyNodeDataToWindow(PNEXT);
|
||||
}
|
||||
|
||||
PNEXT->setGroupFocusedNode(PNEXT);
|
||||
PNEXT->pWindow->m_bHidden = false;
|
||||
|
||||
m_lDwindleNodesData.remove(*PNODE);
|
||||
|
||||
applyNodeDataToWindow(PNEXT);
|
||||
|
||||
if (!PNEXT->isGroupMember()) {
|
||||
// means we dissolved the group
|
||||
recalculateMonitor(PNEXT->pWindow->m_iMonitorID);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -479,6 +519,17 @@ void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) {
|
||||
PSIBLING->size = PPARENT->size;
|
||||
PSIBLING->pParent = PPARENT->pParent;
|
||||
|
||||
if (PSIBLING->isGroupMember()) {
|
||||
// apply to all group members
|
||||
SDwindleNodeData* current = PSIBLING->pNextGroupMember;
|
||||
|
||||
while (current != PSIBLING) {
|
||||
current->position = PPARENT->position;
|
||||
current->size = PPARENT->size;
|
||||
current = current->pNextGroupMember;
|
||||
}
|
||||
}
|
||||
|
||||
if (PPARENT->pParent != nullptr) {
|
||||
if (PPARENT->pParent->children[0] == PPARENT) {
|
||||
PPARENT->pParent->children[0] = PSIBLING;
|
||||
@@ -570,7 +621,7 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow*
|
||||
const auto PNODE = getNodeFromWindow(PWINDOW);
|
||||
|
||||
if (!PNODE) {
|
||||
PWINDOW->m_vRealSize = Vector2D(std::clamp((PWINDOW->m_vRealSize.goalv() + pixResize).x, (double)20, (double)999999), std::clamp((PWINDOW->m_vRealSize.goalv() + pixResize).y, (double)20, (double)999999));
|
||||
PWINDOW->m_vRealSize = Vector2D(std::max((PWINDOW->m_vRealSize.goalv() + pixResize).x, 20.0), std::max((PWINDOW->m_vRealSize.goalv() + pixResize).y, 20.0));
|
||||
PWINDOW->updateWindowDecos();
|
||||
return;
|
||||
}
|
||||
@@ -607,11 +658,11 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow*
|
||||
if (!PPARENT2) {
|
||||
if (PARENTSIDEBYSIDE) {
|
||||
allowedMovement.x *= 2.f / PPARENT->size.x;
|
||||
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, (double)0.1f, (double)1.9f);
|
||||
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, 0.1, 1.9);
|
||||
PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
|
||||
} else {
|
||||
allowedMovement.y *= 2.f / PPARENT->size.y;
|
||||
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, (double)0.1f, (double)1.9f);
|
||||
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, 0.1, 1.9);
|
||||
PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
|
||||
}
|
||||
|
||||
@@ -626,11 +677,11 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow*
|
||||
if (!PPARENT2) {
|
||||
if (PARENTSIDEBYSIDE) {
|
||||
allowedMovement.x *= 2.f / PPARENT->size.x;
|
||||
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, (double)0.1f, (double)1.9f);
|
||||
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, 0.1, 1.9);
|
||||
PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
|
||||
} else {
|
||||
allowedMovement.y *= 2.f / PPARENT->size.y;
|
||||
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, (double)0.1f, (double)1.9f);
|
||||
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, 0.1, 1.9);
|
||||
PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
|
||||
}
|
||||
|
||||
@@ -644,8 +695,8 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow*
|
||||
allowedMovement.x *= 2.f / SIDECONTAINER->size.x;
|
||||
allowedMovement.y *= 2.f / TOPCONTAINER->size.y;
|
||||
|
||||
SIDECONTAINER->splitRatio = std::clamp(SIDECONTAINER->splitRatio + allowedMovement.x, (double)0.1f, (double)1.9f);
|
||||
TOPCONTAINER->splitRatio = std::clamp(TOPCONTAINER->splitRatio + allowedMovement.y, (double)0.1f, (double)1.9f);
|
||||
SIDECONTAINER->splitRatio = std::clamp(SIDECONTAINER->splitRatio + allowedMovement.x, 0.1, 1.9);
|
||||
TOPCONTAINER->splitRatio = std::clamp(TOPCONTAINER->splitRatio + allowedMovement.y, 0.1, 1.9);
|
||||
SIDECONTAINER->recalcSizePosRecursive(*PANIMATE == 0);
|
||||
TOPCONTAINER->recalcSizePosRecursive(*PANIMATE == 0);
|
||||
}
|
||||
@@ -654,10 +705,7 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
|
||||
if (!g_pCompositor->windowValidMapped(pWindow))
|
||||
return;
|
||||
|
||||
if (!g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID))
|
||||
return;
|
||||
|
||||
if (on == pWindow->m_bIsFullscreen)
|
||||
if (on == pWindow->m_bIsFullscreen || pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
|
||||
return; // ignore
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
|
||||
@@ -757,12 +805,13 @@ void CHyprDwindleLayout::toggleWindowGroup(CWindow* pWindow) {
|
||||
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PNODE->workspaceID);
|
||||
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow)
|
||||
fullscreenRequestForWindow(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), FULLSCREEN_FULL, false);
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow && !PNODE->isGroupMember()) {
|
||||
Debug::log(ERR, "Cannot enable group on fullscreen window");
|
||||
return;
|
||||
}
|
||||
|
||||
if (PNODE->isGroupMember()) {
|
||||
// dissolve group
|
||||
|
||||
const auto PHEAD = PNODE->getGroupHead();
|
||||
|
||||
SDwindleNodeData* current = PNODE->pNextGroupMember;
|
||||
@@ -783,8 +832,15 @@ void CHyprDwindleLayout::toggleWindowGroup(CWindow* pWindow) {
|
||||
PWINDOW->m_bHidden = false;
|
||||
}
|
||||
|
||||
if (PHEAD->pPreviousGroupMember)
|
||||
PHEAD->pPreviousGroupMember->pNextGroupMember = PHEAD->pNextGroupMember;
|
||||
|
||||
if (PHEAD->pNextGroupMember)
|
||||
PHEAD->pNextGroupMember->pPreviousGroupMember = PHEAD->pPreviousGroupMember;
|
||||
|
||||
PHEAD->pPreviousGroupMember = nullptr;
|
||||
PHEAD->pNextGroupMember = nullptr;
|
||||
|
||||
onWindowRemoved(PHEAD->pWindow);
|
||||
|
||||
for (auto& pw : toAddWindows) {
|
||||
@@ -797,6 +853,7 @@ void CHyprDwindleLayout::toggleWindowGroup(CWindow* pWindow) {
|
||||
|
||||
for (auto& pw : toAddWindows) {
|
||||
onWindowCreated(pw);
|
||||
pw->removeDecorationByType(DECORATION_GROUPBAR);
|
||||
}
|
||||
|
||||
recalculateMonitor(PWORKSPACE->m_iMonitorID);
|
||||
@@ -856,10 +913,16 @@ void CHyprDwindleLayout::toggleWindowGroup(CWindow* pWindow) {
|
||||
|
||||
newGroupMembers[i]->pPreviousGroupMember = PREVMEMBER;
|
||||
newGroupMembers[i]->pNextGroupMember = NEXTMEMBER;
|
||||
|
||||
// add the deco
|
||||
newGroupMembers[i]->pWindow->m_dWindowDecorations.emplace_back(std::make_unique<CHyprGroupBarDecoration>(newGroupMembers[i]->pWindow));
|
||||
}
|
||||
|
||||
// focus
|
||||
PNODE->setGroupFocusedNode(PNODE);
|
||||
|
||||
// required for no_gaps_when_only to work
|
||||
applyNodeDataToWindow(PNODE);
|
||||
}
|
||||
|
||||
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
|
||||
@@ -877,14 +940,15 @@ std::deque<CWindow*> CHyprDwindleLayout::getGroupMembers(CWindow* pWindow) {
|
||||
// get the node
|
||||
const auto PNODE = getNodeFromWindow(pWindow);
|
||||
|
||||
if (!PNODE)
|
||||
if (!PNODE || !PNODE->isGroupMember())
|
||||
return result; // reject with empty
|
||||
|
||||
SDwindleNodeData* current = PNODE->pNextGroupMember;
|
||||
const auto HEAD = PNODE->getGroupHead();
|
||||
SDwindleNodeData* current = HEAD->pNextGroupMember;
|
||||
|
||||
result.push_back(pWindow);
|
||||
result.push_back(HEAD->pWindow);
|
||||
|
||||
while (current != PNODE) {
|
||||
while (current != HEAD) {
|
||||
result.push_back(current->pWindow);
|
||||
current = current->pNextGroupMember;
|
||||
}
|
||||
@@ -892,7 +956,7 @@ std::deque<CWindow*> CHyprDwindleLayout::getGroupMembers(CWindow* pWindow) {
|
||||
return result;
|
||||
}
|
||||
|
||||
void CHyprDwindleLayout::switchGroupWindow(CWindow* pWindow, bool forward) {
|
||||
void CHyprDwindleLayout::switchGroupWindow(CWindow* pWindow, bool forward, CWindow* forceTo) {
|
||||
if (!g_pCompositor->windowValidMapped(pWindow))
|
||||
return; // reject
|
||||
|
||||
@@ -910,10 +974,18 @@ void CHyprDwindleLayout::switchGroupWindow(CWindow* pWindow, bool forward) {
|
||||
else
|
||||
pNewNode = PNODE->pPreviousGroupMember;
|
||||
|
||||
if (forceTo) {
|
||||
const auto NODETO = getNodeFromWindow(forceTo);
|
||||
|
||||
if (NODETO)
|
||||
pNewNode = NODETO;
|
||||
}
|
||||
|
||||
PNODE->setGroupFocusedNode(pNewNode);
|
||||
|
||||
pNewNode->position = PNODE->position;
|
||||
pNewNode->size = PNODE->size;
|
||||
pNewNode->workspaceID = PNODE->workspaceID;
|
||||
|
||||
applyNodeDataToWindow(pNewNode);
|
||||
|
||||
@@ -933,6 +1005,9 @@ void CHyprDwindleLayout::switchGroupWindow(CWindow* pWindow, bool forward) {
|
||||
pNewNode->pWindow->m_vRealSize.warp();
|
||||
pNewNode->pWindow->m_vRealPosition.warp();
|
||||
}
|
||||
|
||||
pNewNode->pWindow->updateWindowDecos();
|
||||
PNODE->pWindow->updateWindowDecos();
|
||||
}
|
||||
|
||||
SWindowRenderLayoutHints CHyprDwindleLayout::requestRenderHints(CWindow* pWindow) {
|
||||
@@ -940,6 +1015,9 @@ SWindowRenderLayoutHints CHyprDwindleLayout::requestRenderHints(CWindow* pWindow
|
||||
|
||||
SWindowRenderLayoutHints hints;
|
||||
|
||||
static auto *const PGROUPCOLACTIVE = &g_pConfigManager->getConfigValuePtr("dwindle:col.group_border_active")->intValue;
|
||||
static auto *const PGROUPCOLINACTIVE = &g_pConfigManager->getConfigValuePtr("dwindle:col.group_border")->intValue;
|
||||
|
||||
const auto PNODE = getNodeFromWindow(pWindow);
|
||||
if (!PNODE)
|
||||
return hints; // left for the future, maybe floating funkiness
|
||||
@@ -948,9 +1026,9 @@ SWindowRenderLayoutHints CHyprDwindleLayout::requestRenderHints(CWindow* pWindow
|
||||
hints.isBorderColor = true;
|
||||
|
||||
if (pWindow == g_pCompositor->m_pLastWindow)
|
||||
hints.borderColor = CColor(g_pConfigManager->getInt("dwindle:col.group_border_active"));
|
||||
hints.borderColor = CColor(*PGROUPCOLACTIVE);
|
||||
else
|
||||
hints.borderColor = CColor(g_pConfigManager->getInt("dwindle:col.group_border"));
|
||||
hints.borderColor = CColor(*PGROUPCOLINACTIVE);
|
||||
}
|
||||
|
||||
return hints;
|
||||
@@ -959,18 +1037,33 @@ SWindowRenderLayoutHints CHyprDwindleLayout::requestRenderHints(CWindow* pWindow
|
||||
void CHyprDwindleLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
|
||||
// windows should be valid, insallah
|
||||
|
||||
const auto PNODE = getNodeFromWindow(pWindow);
|
||||
const auto PNODE2 = getNodeFromWindow(pWindow2);
|
||||
auto PNODE = getNodeFromWindow(pWindow);
|
||||
auto PNODE2 = getNodeFromWindow(pWindow2);
|
||||
|
||||
if (!PNODE2 || !PNODE)
|
||||
return;
|
||||
|
||||
if (PNODE->workspaceID != PNODE2->workspaceID) {
|
||||
Debug::log(ERR, "Dwindle: Rejecting a swap between workspaces");
|
||||
if (!PNODE2 || !PNODE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// we will not delete the nodes, just fix the tree
|
||||
SDwindleNodeData* ACTIVE1 = nullptr;
|
||||
SDwindleNodeData* ACTIVE2 = nullptr;
|
||||
|
||||
if (PNODE2->isGroupMember() || PNODE->isGroupMember()) {
|
||||
|
||||
if (PNODE->workspaceID != PNODE2->workspaceID) {
|
||||
Debug::log(ERR, "Groups are confined to a monitor");
|
||||
return;
|
||||
}
|
||||
|
||||
if (PNODE->isGroupMember()) {
|
||||
ACTIVE1 = PNODE;
|
||||
PNODE = PNODE->getGroupHead();
|
||||
}
|
||||
|
||||
if (PNODE2->isGroupMember()) {
|
||||
ACTIVE2 = PNODE2;
|
||||
PNODE2 = PNODE2->getGroupHead();
|
||||
}
|
||||
|
||||
if (PNODE2->pParent == PNODE->pParent) {
|
||||
const auto PPARENT = PNODE->pParent;
|
||||
|
||||
@@ -1007,10 +1100,38 @@ void CHyprDwindleLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
|
||||
PNODE2->pParent = PNODE->pParent;
|
||||
PNODE->pParent = PPARENTNODE2;
|
||||
|
||||
// these are window nodes, so no children.
|
||||
std::swap(PNODE2->workspaceID, PNODE->workspaceID);
|
||||
} else {
|
||||
// swap the windows and recalc
|
||||
PNODE2->pWindow = pWindow;
|
||||
PNODE->pWindow = pWindow2;
|
||||
}
|
||||
|
||||
if (PNODE->workspaceID != PNODE2->workspaceID) {
|
||||
std::swap(pWindow2->m_iMonitorID, pWindow->m_iMonitorID);
|
||||
std::swap(pWindow2->m_iWorkspaceID, pWindow->m_iWorkspaceID);
|
||||
}
|
||||
|
||||
// recalc the workspace
|
||||
getMasterNodeOnWorkspace(PNODE->workspaceID)->recalcSizePosRecursive();
|
||||
|
||||
if (PNODE2->workspaceID != PNODE->workspaceID) {
|
||||
getMasterNodeOnWorkspace(PNODE2->workspaceID)->recalcSizePosRecursive();
|
||||
}
|
||||
|
||||
if (ACTIVE1) {
|
||||
ACTIVE1->position = PNODE->position;
|
||||
ACTIVE1->size = PNODE->size;
|
||||
ACTIVE1->pWindow->m_vPosition = ACTIVE1->position;
|
||||
ACTIVE1->pWindow->m_vSize = ACTIVE1->size;
|
||||
}
|
||||
|
||||
if (ACTIVE2) {
|
||||
ACTIVE2->position = PNODE2->position;
|
||||
ACTIVE2->size = PNODE2->size;
|
||||
ACTIVE2->pWindow->m_vPosition = ACTIVE2->position;
|
||||
ACTIVE2->pWindow->m_vSize = ACTIVE2->size;
|
||||
}
|
||||
}
|
||||
|
||||
void CHyprDwindleLayout::alterSplitRatioBy(CWindow* pWindow, float ratio) {
|
||||
@@ -1018,7 +1139,7 @@ void CHyprDwindleLayout::alterSplitRatioBy(CWindow* pWindow, float ratio) {
|
||||
|
||||
const auto PNODE = getNodeFromWindow(pWindow);
|
||||
|
||||
if (!PNODE || !PNODE->pParent)
|
||||
if (!PNODE || !PNODE->pParent || (PNODE->isGroupMember() && PNODE->getGroupMemberCount() == g_pCompositor->getWindowsOnWorkspace(PNODE->workspaceID)))
|
||||
return;
|
||||
|
||||
PNODE->pParent->splitRatio = std::clamp(PNODE->pParent->splitRatio + ratio, 0.1f, 1.9f);
|
||||
@@ -1036,7 +1157,7 @@ std::any CHyprDwindleLayout::layoutMessage(SLayoutMessageHeader header, std::str
|
||||
else if (message == "togglesplit")
|
||||
toggleSplit(header.pWindow);
|
||||
else if (message == "groupinfo") {
|
||||
auto res = getGroupMembers(g_pCompositor->m_pLastWindow);
|
||||
auto res = getGroupMembers(header.pWindow ? header.pWindow : g_pCompositor->m_pLastWindow);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@@ -41,6 +41,7 @@ struct SDwindleNodeData {
|
||||
bool isGroupMember();
|
||||
SDwindleNodeData* getGroupHead();
|
||||
SDwindleNodeData* getGroupVisible();
|
||||
int getGroupMemberCount();
|
||||
void setGroupFocusedNode(SDwindleNodeData*);
|
||||
CHyprDwindleLayout* layout = nullptr;
|
||||
};
|
||||
@@ -74,7 +75,7 @@ private:
|
||||
SDwindleNodeData* getMasterNodeOnWorkspace(const int&);
|
||||
|
||||
void toggleWindowGroup(CWindow*);
|
||||
void switchGroupWindow(CWindow*, bool forward);
|
||||
void switchGroupWindow(CWindow*, bool forward, CWindow* to = nullptr);
|
||||
void toggleSplit(CWindow*);
|
||||
std::deque<CWindow*> getGroupMembers(CWindow*);
|
||||
|
||||
|
@@ -64,8 +64,24 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
|
||||
// check if it's on the correct monitor!
|
||||
Vector2D middlePoint = Vector2D(desiredGeometry.x, desiredGeometry.y) + Vector2D(desiredGeometry.width, desiredGeometry.height) / 2.f;
|
||||
|
||||
// check if it's visible on any monitor (only for XDG)
|
||||
bool visible = pWindow->m_bIsX11;
|
||||
|
||||
if (!pWindow->m_bIsX11) {
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
if (VECINRECT(Vector2D(desiredGeometry.x, desiredGeometry.y), m->vecPosition.x, m->vecPosition.y, m->vecPosition.x + m->vecSize.x, m->vecPosition.y + m->vecPosition.y)
|
||||
|| VECINRECT(Vector2D(desiredGeometry.x + desiredGeometry.width, desiredGeometry.y), m->vecPosition.x, m->vecPosition.y, m->vecPosition.x + m->vecSize.x, m->vecPosition.y + m->vecPosition.y)
|
||||
|| VECINRECT(Vector2D(desiredGeometry.x, desiredGeometry.y + desiredGeometry.height), m->vecPosition.x, m->vecPosition.y, m->vecPosition.x + m->vecSize.x, m->vecPosition.y + m->vecPosition.y)
|
||||
|| VECINRECT(Vector2D(desiredGeometry.x + desiredGeometry.width, desiredGeometry.y + desiredGeometry.height), m->vecPosition.x, m->vecPosition.y, m->vecPosition.x + m->vecSize.x, m->vecPosition.y + m->vecPosition.y)) {
|
||||
|
||||
visible = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: detect a popup in a more consistent way.
|
||||
if ((desiredGeometry.x == 0 && desiredGeometry.y == 0)) {
|
||||
if ((desiredGeometry.x == 0 && desiredGeometry.y == 0) || !visible) {
|
||||
// if it's not, fall back to the center placement
|
||||
pWindow->m_vRealPosition = PMONITOR->vecPosition + Vector2D((PMONITOR->vecSize.x - desiredGeometry.width) / 2.f, (PMONITOR->vecSize.y - desiredGeometry.height) / 2.f);
|
||||
} else {
|
||||
@@ -121,7 +137,7 @@ void IHyprLayout::onBeginDragWindow() {
|
||||
DRAGGINGWINDOW->m_bDraggingTiled = false;
|
||||
|
||||
if (!DRAGGINGWINDOW->m_bIsFloating) {
|
||||
if (g_pInputManager->dragButton == BTN_LEFT) {
|
||||
if (g_pInputManager->dragMode == MBIND_MOVE) {
|
||||
changeWindowFloatingMode(DRAGGINGWINDOW);
|
||||
DRAGGINGWINDOW->m_bIsFloating = true;
|
||||
DRAGGINGWINDOW->m_bDraggingTiled = true;
|
||||
@@ -135,6 +151,21 @@ void IHyprLayout::onBeginDragWindow() {
|
||||
m_vBeginDragSizeXY = DRAGGINGWINDOW->m_vRealSize.goalv();
|
||||
m_vLastDragXY = m_vBeginDragXY;
|
||||
|
||||
// get the grab corner
|
||||
if (m_vBeginDragXY.x < m_vBeginDragPositionXY.x + m_vBeginDragSizeXY.x / 2.0) {
|
||||
// left
|
||||
if (m_vBeginDragXY.y < m_vBeginDragPositionXY.y + m_vBeginDragSizeXY.y / 2.0)
|
||||
m_iGrabbedCorner = 0;
|
||||
else
|
||||
m_iGrabbedCorner = 4;
|
||||
} else {
|
||||
// right
|
||||
if (m_vBeginDragXY.y < m_vBeginDragPositionXY.y + m_vBeginDragSizeXY.y / 2.0)
|
||||
m_iGrabbedCorner = 1;
|
||||
else
|
||||
m_iGrabbedCorner = 3;
|
||||
}
|
||||
|
||||
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
|
||||
|
||||
// shadow to ignore any bound to MAIN_MOD
|
||||
@@ -176,20 +207,41 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
|
||||
|
||||
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
|
||||
|
||||
if (g_pInputManager->dragButton == BTN_LEFT) {
|
||||
if (g_pInputManager->dragMode == MBIND_MOVE) {
|
||||
DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(m_vBeginDragPositionXY + DELTA);
|
||||
|
||||
g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv());
|
||||
} else {
|
||||
} else if (g_pInputManager->dragMode == MBIND_RESIZE) {
|
||||
if (DRAGGINGWINDOW->m_bIsFloating) {
|
||||
|
||||
const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(DRAGGINGWINDOW);
|
||||
|
||||
// calc the new size and pos
|
||||
|
||||
Vector2D newSize = m_vBeginDragSizeXY;
|
||||
Vector2D newPos = m_vBeginDragPositionXY;
|
||||
|
||||
if (m_iGrabbedCorner == 3) {
|
||||
newSize = newSize + DELTA;
|
||||
} else if (m_iGrabbedCorner == 0) {
|
||||
newSize = newSize - DELTA;
|
||||
newPos = newPos + DELTA;
|
||||
} else if (m_iGrabbedCorner == 1) {
|
||||
newSize = newSize + Vector2D(DELTA.x, -DELTA.y);
|
||||
newPos = newPos + Vector2D(0, DELTA.y);
|
||||
} else if (m_iGrabbedCorner == 4) {
|
||||
newSize = newSize + Vector2D(-DELTA.x, DELTA.y);
|
||||
newPos = newPos + Vector2D(DELTA.x, 0);
|
||||
}
|
||||
|
||||
newSize = newSize.clamp(Vector2D(20,20), MAXSIZE);
|
||||
|
||||
if (*PANIMATE) {
|
||||
DRAGGINGWINDOW->m_vRealSize = Vector2D(std::clamp(m_vBeginDragSizeXY.x + DELTA.x, (double)20, (double)MAXSIZE.x), std::clamp(m_vBeginDragSizeXY.y + DELTA.y, (double)20, (double)MAXSIZE.y));
|
||||
DRAGGINGWINDOW->m_vRealSize = newSize;
|
||||
DRAGGINGWINDOW->m_vRealPosition = newPos;
|
||||
} else {
|
||||
DRAGGINGWINDOW->m_vRealSize.setValueAndWarp(m_vBeginDragSizeXY + DELTA);
|
||||
DRAGGINGWINDOW->m_vRealSize.setValueAndWarp(Vector2D(std::clamp(DRAGGINGWINDOW->m_vRealSize.vec().x, (double)20, (double)MAXSIZE.x), std::clamp(DRAGGINGWINDOW->m_vRealSize.vec().y, (double)20, (double)MAXSIZE.y)));
|
||||
DRAGGINGWINDOW->m_vRealSize.setValueAndWarp(newSize);
|
||||
DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(newPos);
|
||||
}
|
||||
|
||||
g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv());
|
||||
@@ -206,7 +258,7 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
|
||||
|
||||
if (PMONITOR) {
|
||||
DRAGGINGWINDOW->m_iMonitorID = PMONITOR->ID;
|
||||
DRAGGINGWINDOW->m_iWorkspaceID = PMONITOR->activeWorkspace;
|
||||
DRAGGINGWINDOW->moveToWorkspace(PMONITOR->activeWorkspace);
|
||||
|
||||
DRAGGINGWINDOW->updateToplevel();
|
||||
}
|
||||
@@ -226,12 +278,14 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
pWindow->m_bPinned = false;
|
||||
|
||||
const auto TILED = isWindowTiled(pWindow);
|
||||
|
||||
if (!TILED) {
|
||||
const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.vec() + pWindow->m_vRealSize.vec() / 2.f);
|
||||
pWindow->m_iMonitorID = PNEWMON->ID;
|
||||
pWindow->m_iWorkspaceID = PNEWMON->activeWorkspace;
|
||||
pWindow->moveToWorkspace(PNEWMON->activeWorkspace);
|
||||
|
||||
// save real pos cuz the func applies the default 5,5 mid
|
||||
const auto PSAVEDPOS = pWindow->m_vRealPosition.vec();
|
||||
|
@@ -128,4 +128,5 @@ private:
|
||||
Vector2D m_vLastDragXY;
|
||||
Vector2D m_vBeginDragPositionXY;
|
||||
Vector2D m_vBeginDragSizeXY;
|
||||
int m_iGrabbedCorner = 0;
|
||||
};
|
@@ -84,6 +84,13 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow) {
|
||||
}
|
||||
}
|
||||
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
|
||||
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow) {
|
||||
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
|
||||
g_pCompositor->setWindowFullscreen(PFULLWINDOW, false, FULLSCREEN_FULL);
|
||||
}
|
||||
|
||||
// recalc
|
||||
recalculateMonitor(pWindow->m_iMonitorID);
|
||||
}
|
||||
@@ -94,6 +101,9 @@ void CHyprMasterLayout::onWindowRemovedTiling(CWindow* pWindow) {
|
||||
if (!PNODE)
|
||||
return;
|
||||
|
||||
if (pWindow->m_bIsFullscreen)
|
||||
g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL);
|
||||
|
||||
if (PNODE->isMaster) {
|
||||
// find new one
|
||||
for (auto& nd : m_lMasterNodesData) {
|
||||
@@ -215,9 +225,9 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
|
||||
const bool DISPLAYTOP = STICKS(pNode->position.y, PMONITOR->vecPosition.y + PMONITOR->vecReservedTopLeft.y);
|
||||
const bool DISPLAYBOTTOM = STICKS(pNode->position.y + pNode->size.y, PMONITOR->vecPosition.y + PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y);
|
||||
|
||||
const auto BORDERSIZE = g_pConfigManager->getInt("general:border_size");
|
||||
const auto GAPSIN = g_pConfigManager->getInt("general:gaps_in");
|
||||
const auto GAPSOUT = g_pConfigManager->getInt("general:gaps_out");
|
||||
const auto PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
|
||||
const auto PGAPSIN = &g_pConfigManager->getConfigValuePtr("general:gaps_in")->intValue;
|
||||
const auto PGAPSOUT = &g_pConfigManager->getConfigValuePtr("general:gaps_out")->intValue;
|
||||
|
||||
const auto PWINDOW = pNode->pWindow;
|
||||
|
||||
@@ -231,29 +241,31 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
|
||||
PWINDOW->m_vSize = pNode->size;
|
||||
PWINDOW->m_vPosition = pNode->position;
|
||||
|
||||
auto calcPos = PWINDOW->m_vPosition + Vector2D(BORDERSIZE, BORDERSIZE);
|
||||
auto calcSize = PWINDOW->m_vSize - Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE);
|
||||
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) {
|
||||
PWINDOW->m_vRealPosition = calcPos - Vector2D(BORDERSIZE, BORDERSIZE);
|
||||
PWINDOW->m_vRealSize = calcSize + Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE);
|
||||
PWINDOW->m_vRealPosition = calcPos - Vector2D(*PBORDERSIZE, *PBORDERSIZE);
|
||||
PWINDOW->m_vRealSize = calcSize + Vector2D(2 * *PBORDERSIZE, 2 * *PBORDERSIZE);
|
||||
|
||||
PWINDOW->updateWindowDecos();
|
||||
|
||||
PWINDOW->m_sSpecialRenderData.rounding = false;
|
||||
PWINDOW->m_sSpecialRenderData.border = false;
|
||||
PWINDOW->m_sSpecialRenderData.decorate = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
PWINDOW->m_sSpecialRenderData.rounding = true;
|
||||
PWINDOW->m_sSpecialRenderData.border = true;
|
||||
PWINDOW->m_sSpecialRenderData.decorate = true;
|
||||
|
||||
const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? GAPSOUT : GAPSIN,
|
||||
DISPLAYTOP ? GAPSOUT : GAPSIN);
|
||||
const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? *PGAPSOUT : *PGAPSIN,
|
||||
DISPLAYTOP ? *PGAPSOUT : *PGAPSIN);
|
||||
|
||||
const auto OFFSETBOTTOMRIGHT = Vector2D(DISPLAYRIGHT ? GAPSOUT : GAPSIN,
|
||||
DISPLAYBOTTOM ? GAPSOUT : GAPSIN);
|
||||
const auto OFFSETBOTTOMRIGHT = Vector2D(DISPLAYRIGHT ? *PGAPSOUT : *PGAPSIN,
|
||||
DISPLAYBOTTOM ? *PGAPSOUT : *PGAPSIN);
|
||||
|
||||
calcPos = calcPos + OFFSETTOPLEFT;
|
||||
calcSize = calcSize - OFFSETTOPLEFT - OFFSETBOTTOMRIGHT;
|
||||
@@ -273,8 +285,12 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
|
||||
}
|
||||
|
||||
if (m_bForceWarps) {
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
|
||||
PWINDOW->m_vRealPosition.warp();
|
||||
PWINDOW->m_vRealSize.warp();
|
||||
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
}
|
||||
|
||||
PWINDOW->updateWindowDecos();
|
||||
@@ -293,7 +309,7 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow* p
|
||||
const auto PNODE = getNodeFromWindow(PWINDOW);
|
||||
|
||||
if (!PNODE) {
|
||||
PWINDOW->m_vRealSize = Vector2D(std::clamp((PWINDOW->m_vRealSize.goalv() + pixResize).x, (double)20, (double)999999), std::clamp((PWINDOW->m_vRealSize.goalv() + pixResize).y, (double)20, (double)999999));
|
||||
PWINDOW->m_vRealSize = Vector2D(std::max((PWINDOW->m_vRealSize.goalv() + pixResize).x, 20.0), std::max((PWINDOW->m_vRealSize.goalv() + pixResize).y, 20.0));
|
||||
PWINDOW->updateWindowDecos();
|
||||
return;
|
||||
}
|
||||
@@ -322,10 +338,7 @@ void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreen
|
||||
if (!g_pCompositor->windowValidMapped(pWindow))
|
||||
return;
|
||||
|
||||
if (!g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID))
|
||||
return;
|
||||
|
||||
if (on == pWindow->m_bIsFullscreen)
|
||||
if (on == pWindow->m_bIsFullscreen || pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
|
||||
return; // ignore
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
|
||||
@@ -421,16 +434,17 @@ void CHyprMasterLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
|
||||
return;
|
||||
|
||||
if (PNODE->workspaceID != PNODE2->workspaceID) {
|
||||
Debug::log(ERR, "Master: Rejecting a swap between workspaces");
|
||||
return;
|
||||
std::swap(pWindow2->m_iMonitorID, pWindow->m_iMonitorID);
|
||||
std::swap(pWindow2->m_iWorkspaceID, pWindow->m_iWorkspaceID);
|
||||
}
|
||||
|
||||
// massive hack: just swap window pointers, lol
|
||||
const auto PWINDOW1 = PNODE->pWindow;
|
||||
PNODE->pWindow = PNODE2->pWindow;
|
||||
PNODE2->pWindow = PWINDOW1;
|
||||
PNODE->pWindow = pWindow2;
|
||||
PNODE2->pWindow = pWindow;
|
||||
|
||||
recalculateMonitor(PWINDOW1->m_iMonitorID);
|
||||
recalculateMonitor(pWindow->m_iMonitorID);
|
||||
if (PNODE2->workspaceID != PNODE->workspaceID)
|
||||
recalculateMonitor(pWindow2->m_iMonitorID);
|
||||
}
|
||||
|
||||
void CHyprMasterLayout::alterSplitRatioBy(CWindow* pWindow, float ratio) {
|
||||
@@ -448,8 +462,80 @@ void CHyprMasterLayout::alterSplitRatioBy(CWindow* pWindow, float ratio) {
|
||||
recalculateMonitor(pWindow->m_iMonitorID);
|
||||
}
|
||||
|
||||
CWindow* CHyprMasterLayout::getNextWindow(CWindow* pWindow, bool next) {
|
||||
if (!isWindowTiled(pWindow))
|
||||
return nullptr;
|
||||
|
||||
const auto PNODE = getNodeFromWindow(pWindow);
|
||||
|
||||
if (next) {
|
||||
if (PNODE->isMaster) {
|
||||
// focus the first non master
|
||||
for (auto n : m_lMasterNodesData) {
|
||||
if (n.pWindow != pWindow && n.workspaceID == pWindow->m_iWorkspaceID) {
|
||||
return n.pWindow;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// focus next
|
||||
bool reached = false;
|
||||
bool found = false;
|
||||
for (auto n : m_lMasterNodesData) {
|
||||
if (n.pWindow == pWindow) {
|
||||
reached = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n.workspaceID == pWindow->m_iWorkspaceID && reached) {
|
||||
return n.pWindow;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
const auto PMASTER = getMasterNodeOnWorkspace(pWindow->m_iWorkspaceID);
|
||||
|
||||
if (PMASTER)
|
||||
return PMASTER->pWindow;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (PNODE->isMaster) {
|
||||
// focus the first non master
|
||||
for (auto it = m_lMasterNodesData.rbegin(); it != m_lMasterNodesData.rend(); it++) {
|
||||
if (it->pWindow != pWindow && it->workspaceID == pWindow->m_iWorkspaceID) {
|
||||
return it->pWindow;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// focus next
|
||||
bool reached = false;
|
||||
bool found = false;
|
||||
for (auto it = m_lMasterNodesData.rbegin(); it != m_lMasterNodesData.rend(); it++) {
|
||||
if (it->pWindow == pWindow) {
|
||||
reached = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (it->workspaceID == pWindow->m_iWorkspaceID && reached) {
|
||||
return it->pWindow;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
const auto PMASTER = getMasterNodeOnWorkspace(pWindow->m_iWorkspaceID);
|
||||
|
||||
if (PMASTER)
|
||||
return PMASTER->pWindow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::string message) {
|
||||
auto switchToWindow = [&](CWindow* PWINDOWTOCHANGETO) {
|
||||
if (!g_pCompositor->windowValidMapped(PWINDOWTOCHANGETO))
|
||||
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);
|
||||
@@ -475,80 +561,40 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
|
||||
} else if (message == "cyclenext") {
|
||||
const auto PWINDOW = header.pWindow;
|
||||
|
||||
if (!isWindowTiled(PWINDOW))
|
||||
return 0;
|
||||
|
||||
const auto PNODE = getNodeFromWindow(PWINDOW);
|
||||
|
||||
if (PNODE->isMaster) {
|
||||
// focus the first non master
|
||||
for (auto n : m_lMasterNodesData) {
|
||||
if (n.pWindow != PWINDOW && n.workspaceID == PWINDOW->m_iWorkspaceID) {
|
||||
switchToWindow(n.pWindow);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// focus next
|
||||
bool reached = false;
|
||||
bool found = false;
|
||||
for (auto n : m_lMasterNodesData) {
|
||||
if (n.pWindow == PWINDOW) {
|
||||
reached = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n.workspaceID == PWINDOW->m_iWorkspaceID && reached) {
|
||||
switchToWindow(n.pWindow);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID);
|
||||
|
||||
if (PMASTER)
|
||||
switchToWindow(PMASTER->pWindow);
|
||||
}
|
||||
}
|
||||
switchToWindow(getNextWindow(PWINDOW, true));
|
||||
} else if (message == "cycleprev") {
|
||||
const auto PWINDOW = header.pWindow;
|
||||
|
||||
if (!isWindowTiled(PWINDOW))
|
||||
switchToWindow(getNextWindow(PWINDOW, false));
|
||||
} else if (message == "swapnext") {
|
||||
if (!g_pCompositor->windowValidMapped(header.pWindow))
|
||||
return 0;
|
||||
|
||||
const auto PNODE = getNodeFromWindow(PWINDOW);
|
||||
|
||||
if (PNODE->isMaster) {
|
||||
// focus the first non master
|
||||
for (auto it = m_lMasterNodesData.rbegin(); it != m_lMasterNodesData.rend(); it++) {
|
||||
if (it->pWindow != PWINDOW && it->workspaceID == PWINDOW->m_iWorkspaceID) {
|
||||
switchToWindow(it->pWindow);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// focus next
|
||||
bool reached = false;
|
||||
bool found = false;
|
||||
for (auto it = m_lMasterNodesData.rbegin(); it != m_lMasterNodesData.rend(); it++) {
|
||||
if (it->pWindow == PWINDOW) {
|
||||
reached = true;
|
||||
continue;
|
||||
if (header.pWindow->m_bIsFloating) {
|
||||
g_pKeybindManager->m_mDispatchers["swapnext"]("");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (it->workspaceID == PWINDOW->m_iWorkspaceID && reached) {
|
||||
switchToWindow(it->pWindow);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID);
|
||||
const auto PWINDOWTOSWAPWITH = getNextWindow(header.pWindow, true);
|
||||
|
||||
if (PMASTER)
|
||||
switchToWindow(PMASTER->pWindow);
|
||||
if (PWINDOWTOSWAPWITH) {
|
||||
switchWindows(header.pWindow, PWINDOWTOSWAPWITH);
|
||||
g_pCompositor->focusWindow(header.pWindow);
|
||||
}
|
||||
} else if (message == "swapprev") {
|
||||
if (!g_pCompositor->windowValidMapped(header.pWindow))
|
||||
return 0;
|
||||
|
||||
if (header.pWindow->m_bIsFloating) {
|
||||
g_pKeybindManager->m_mDispatchers["swapnext"]("prev");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto PWINDOWTOSWAPWITH = getNextWindow(header.pWindow, false);
|
||||
|
||||
if (PWINDOWTOSWAPWITH) {
|
||||
switchWindows(header.pWindow, PWINDOWTOSWAPWITH);
|
||||
g_pCompositor->focusWindow(header.pWindow);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -51,6 +51,7 @@ private:
|
||||
SMasterNodeData* getNodeFromWindow(CWindow*);
|
||||
SMasterNodeData* getMasterNodeOnWorkspace(const int&);
|
||||
void calculateWorkspace(const int&);
|
||||
CWindow* getNextWindow(CWindow*, bool);
|
||||
|
||||
friend struct SMasterNodeData;
|
||||
};
|
18
src/main.cpp
18
src/main.cpp
@@ -14,6 +14,12 @@ int main(int argc, char** argv) {
|
||||
if (!getenv("XDG_RUNTIME_DIR"))
|
||||
throw std::runtime_error("XDG_RUNTIME_DIR is not set!");
|
||||
|
||||
// export HYPRLAND_CMD
|
||||
std::string cmd = "";
|
||||
for (auto i = 0; i < argc; ++i)
|
||||
cmd += std::string(i == 0 ? "" : " ") + argv[i];
|
||||
setenv("HYPRLAND_CMD", cmd.c_str(), 1);
|
||||
|
||||
// parse some args
|
||||
std::string configPath;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
@@ -44,6 +50,10 @@ int main(int argc, char** argv) {
|
||||
|
||||
std::cout << "Welcome to Hyprland!\n";
|
||||
|
||||
const auto LOGWLR = getenv("HYPRLAND_LOG_WLR");
|
||||
if (LOGWLR && std::string(LOGWLR) == "1")
|
||||
wlr_log_init(WLR_DEBUG, Debug::wlrLog);
|
||||
|
||||
// let's init the compositor.
|
||||
// it initializes basic Wayland stuff in the constructor.
|
||||
g_pCompositor = std::make_unique<CCompositor>();
|
||||
@@ -57,7 +67,13 @@ int main(int argc, char** argv) {
|
||||
// If we are here it means we got yote.
|
||||
Debug::log(LOG, "Hyprland reached the end.");
|
||||
|
||||
g_pCompositor->cleanup();
|
||||
wl_display_destroy_clients(g_pCompositor->m_sWLDisplay);
|
||||
|
||||
// kill all clients
|
||||
for (auto& c : g_pCompositor->m_dProcessPIDsOnShutdown)
|
||||
kill(c, SIGKILL);
|
||||
|
||||
wl_display_destroy(g_pCompositor->m_sWLDisplay);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@@ -21,12 +21,12 @@ void CAnimationManager::addBezierWithName(std::string name, const Vector2D& p1,
|
||||
|
||||
void CAnimationManager::tick() {
|
||||
|
||||
bool animationsDisabled = false;
|
||||
bool animGlobalDisabled = false;
|
||||
|
||||
static auto *const PANIMENABLED = &g_pConfigManager->getConfigValuePtr("animations:enabled")->intValue;
|
||||
|
||||
if (!*PANIMENABLED)
|
||||
animationsDisabled = true;
|
||||
animGlobalDisabled = true;
|
||||
|
||||
static auto *const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
|
||||
static auto *const PSHADOWSENABLED = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue;
|
||||
@@ -56,11 +56,13 @@ void CAnimationManager::tick() {
|
||||
const auto PWORKSPACE = (CWorkspace*)av->m_pWorkspace;
|
||||
const auto PLAYER = (SLayerSurface*)av->m_pLayer;
|
||||
CMonitor* PMONITOR = nullptr;
|
||||
bool animationsDisabled = animGlobalDisabled;
|
||||
|
||||
wlr_box WLRBOXPREV = {0,0,0,0};
|
||||
if (PWINDOW) {
|
||||
WLRBOXPREV = PWINDOW->getFullWindowBoundingBox();
|
||||
PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
||||
animationsDisabled = animationsDisabled || PWINDOW->m_sAdditionalConfigData.forceNoAnims;
|
||||
} else if (PWORKSPACE) {
|
||||
PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
|
||||
WLRBOXPREV = {(int)PMONITOR->vecPosition.x, (int)PMONITOR->vecPosition.y, (int)PMONITOR->vecSize.x, (int)PMONITOR->vecSize.y};
|
||||
@@ -190,7 +192,7 @@ void CAnimationManager::tick() {
|
||||
} case AVARDAMAGE_SHADOW: {
|
||||
RASSERT(PWINDOW, "Tried to AVARDAMAGE_SHADOW a non-window AVAR!");
|
||||
|
||||
static auto* const PSHADOWIGNOREWINDOW = &g_pConfigManager->getConfigValuePtr("decoration:shadow_ignore_window")->intValue;
|
||||
static auto *const PSHADOWIGNOREWINDOW = &g_pConfigManager->getConfigValuePtr("decoration:shadow_ignore_window")->intValue;
|
||||
|
||||
const auto PDECO = PWINDOW->getDecorationByType(DECORATION_SHADOW);
|
||||
|
||||
@@ -428,7 +430,7 @@ std::string CAnimationManager::styleValidInConfigVar(const std::string& config,
|
||||
}
|
||||
|
||||
return "unknown style";
|
||||
} else if (config == "workspaces") {
|
||||
} else if (config == "workspaces" || config == "specialWorkspace") {
|
||||
if (style == "slide" || style == "slidevert" || style == "fade")
|
||||
return "";
|
||||
|
||||
|
@@ -19,7 +19,7 @@ CEventManager::CEventManager() {
|
||||
}
|
||||
|
||||
void CEventManager::startThread() {
|
||||
std::thread([&]() {
|
||||
m_tThread = std::thread([&]() {
|
||||
const auto SOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
if (SOCKET < 0) {
|
||||
@@ -36,19 +36,12 @@ void CEventManager::startThread() {
|
||||
// 10 max queued.
|
||||
listen(SOCKET, 10);
|
||||
|
||||
char readBuf[1024] = {0};
|
||||
|
||||
sockaddr_in clientAddress;
|
||||
socklen_t clientSize = sizeof(clientAddress);
|
||||
|
||||
Debug::log(LOG, "Hypr socket 2 started at %s", socketPath.c_str());
|
||||
|
||||
// set the socket nonblock
|
||||
int flags = fcntl(SOCKET, F_GETFL, 0);
|
||||
fcntl(SOCKET, F_SETFL, flags | O_NONBLOCK);
|
||||
|
||||
while (1) {
|
||||
|
||||
const auto ACCEPTEDCONNECTION = accept(SOCKET, (sockaddr*)&clientAddress, &clientSize);
|
||||
|
||||
if (ACCEPTEDCONNECTION > 0) {
|
||||
@@ -61,6 +54,18 @@ void CEventManager::startThread() {
|
||||
Debug::log(LOG, "Socket 2 accepted a new client at FD %d", ACCEPTEDCONNECTION);
|
||||
}
|
||||
|
||||
ensureFDsValid();
|
||||
}
|
||||
|
||||
close(SOCKET);
|
||||
});
|
||||
|
||||
m_tThread.detach();
|
||||
}
|
||||
|
||||
void CEventManager::ensureFDsValid() {
|
||||
static char readBuf[1024] = {0};
|
||||
|
||||
// pong if all FDs valid
|
||||
for (auto it = m_dAcceptedSocketFDs.begin(); it != m_dAcceptedSocketFDs.end();) {
|
||||
auto sizeRead = recv(*it, &readBuf, 1024, 0);
|
||||
@@ -74,18 +79,14 @@ void CEventManager::startThread() {
|
||||
Debug::log(LOG, "Removed invalid socket (2) FD: %d", *it);
|
||||
it = m_dAcceptedSocketFDs.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void CEventManager::flushEvents() {
|
||||
|
||||
ensureFDsValid();
|
||||
|
||||
// valid FDs, check the queue
|
||||
// don't do anything if main thread is writing to the eventqueue
|
||||
eventQueueMutex.lock();
|
||||
|
||||
if (m_dQueuedEvents.empty()){ // if queue empty, sleep and ignore
|
||||
eventQueueMutex.unlock();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
continue;
|
||||
}
|
||||
|
||||
// write all queued events
|
||||
for (auto& ev : m_dQueuedEvents) {
|
||||
std::string eventString = (ev.event + ">>" + ev.data).substr(0, 1022) + "\n";
|
||||
for (auto& fd : m_dAcceptedSocketFDs) {
|
||||
@@ -96,18 +97,12 @@ void CEventManager::startThread() {
|
||||
m_dQueuedEvents.clear();
|
||||
|
||||
eventQueueMutex.unlock();
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
close(SOCKET);
|
||||
}).detach();
|
||||
}
|
||||
|
||||
void CEventManager::postEvent(const SHyprIPCEvent event, bool force) {
|
||||
|
||||
if (m_bIgnoreEvents && !force) {
|
||||
Debug::log(WARN, "Suppressed (ignoreevents true) event of type %s, content: %s",event.event.c_str(), event.data.c_str());
|
||||
if ((m_bIgnoreEvents && !force) || g_pCompositor->m_bIsShuttingDown) {
|
||||
Debug::log(WARN, "Suppressed (ignoreevents true / shutting down) event of type %s, content: %s",event.event.c_str(), event.data.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -115,5 +110,7 @@ void CEventManager::postEvent(const SHyprIPCEvent event, bool force) {
|
||||
eventQueueMutex.lock();
|
||||
m_dQueuedEvents.push_back(ev);
|
||||
eventQueueMutex.unlock();
|
||||
|
||||
flushEvents();
|
||||
}, event).detach();
|
||||
}
|
||||
|
@@ -21,8 +21,13 @@ public:
|
||||
|
||||
bool m_bIgnoreEvents = false;
|
||||
|
||||
std::thread m_tThread;
|
||||
|
||||
private:
|
||||
|
||||
void flushEvents();
|
||||
void ensureFDsValid();
|
||||
|
||||
std::mutex eventQueueMutex;
|
||||
std::deque<SHyprIPCEvent> m_dQueuedEvents;
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -18,6 +18,7 @@ struct SKeybind {
|
||||
std::string submap = "";
|
||||
bool release = false;
|
||||
bool repeat = false;
|
||||
bool mouse = false;
|
||||
|
||||
// DO NOT INITIALIZE
|
||||
bool shadowed = false;
|
||||
@@ -37,6 +38,7 @@ public:
|
||||
bool onKeyEvent(wlr_keyboard_key_event*, SKeyboard*);
|
||||
bool onAxisEvent(wlr_pointer_axis_event*);
|
||||
bool onMouseEvent(wlr_pointer_button_event*);
|
||||
void onSwitchEvent(const std::string&);
|
||||
|
||||
void addKeybind(SKeybind);
|
||||
void removeKeybind(uint32_t, const std::string&);
|
||||
@@ -61,6 +63,11 @@ private:
|
||||
|
||||
uint32_t m_uTimeLastMs = 0;
|
||||
uint32_t m_uLastCode = 0;
|
||||
uint32_t m_uLastMouseCode = 0;
|
||||
|
||||
bool m_bIsMouseBindActive = false;
|
||||
|
||||
int m_iPassPressed = -1; // used for pass
|
||||
|
||||
CTimer m_tScrollTimer;
|
||||
|
||||
@@ -69,8 +76,14 @@ private:
|
||||
bool handleInternalKeybinds(xkb_keysym_t);
|
||||
bool handleVT(xkb_keysym_t);
|
||||
|
||||
xkb_state* m_pXKBTranslationState = nullptr;
|
||||
|
||||
void updateXKBTranslationState();
|
||||
bool ensureMouseBindState();
|
||||
|
||||
// -------------- Dispatchers -------------- //
|
||||
static void killActive(std::string);
|
||||
static void kill(std::string);
|
||||
static void spawn(std::string);
|
||||
static void toggleActiveFloating(std::string);
|
||||
static void toggleActivePseudo(std::string);
|
||||
@@ -103,6 +116,10 @@ private:
|
||||
static void layoutmsg(std::string);
|
||||
static void toggleOpaque(std::string);
|
||||
static void dpms(std::string);
|
||||
static void swapnext(std::string);
|
||||
static void swapActiveWorkspaces(std::string);
|
||||
static void pinActive(std::string);
|
||||
static void mouse(std::string);
|
||||
|
||||
friend class CCompositor;
|
||||
friend class CInputManager;
|
||||
|
@@ -7,6 +7,9 @@ int slowUpdate = 0;
|
||||
int handleTimer(void* data) {
|
||||
const auto PTM = (CThreadManager*)data;
|
||||
|
||||
static auto *const PDISABLECFGRELOAD = &g_pConfigManager->getConfigValuePtr("misc:disable_autoreload")->intValue;
|
||||
|
||||
if (*PDISABLECFGRELOAD != 1)
|
||||
g_pConfigManager->tick();
|
||||
|
||||
wl_event_source_timer_update(PTM->m_esConfigTimer, 1000);
|
||||
@@ -19,8 +22,6 @@ CThreadManager::CThreadManager() {
|
||||
|
||||
HyprCtl::startHyprCtlSocket();
|
||||
|
||||
g_pCompositor->startHyprCtlTick();
|
||||
|
||||
m_esConfigTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, handleTimer, this);
|
||||
|
||||
wl_event_source_timer_update(m_esConfigTimer, 1000);
|
||||
|
@@ -32,9 +32,15 @@ wlr_surface* CHyprXWaylandManager::getWindowSurface(CWindow* pWindow) {
|
||||
}
|
||||
|
||||
void CHyprXWaylandManager::activateSurface(wlr_surface* pSurface, bool activate) {
|
||||
if (wlr_surface_is_xdg_surface(pSurface))
|
||||
wlr_xdg_toplevel_set_activated(wlr_xdg_surface_from_wlr_surface(pSurface)->toplevel, activate);
|
||||
else if (wlr_surface_is_xwayland_surface(pSurface)) {
|
||||
if (!pSurface)
|
||||
return;
|
||||
|
||||
if (wlr_surface_is_xdg_surface(pSurface)) {
|
||||
const auto PSURF = wlr_xdg_surface_from_wlr_surface(pSurface);
|
||||
if (PSURF && PSURF->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
|
||||
wlr_xdg_toplevel_set_activated(PSURF->toplevel, activate);
|
||||
}
|
||||
} else if (wlr_surface_is_xwayland_surface(pSurface)) {
|
||||
wlr_xwayland_surface_activate(wlr_xwayland_surface_from_wlr_surface(pSurface), activate);
|
||||
|
||||
if (activate)
|
||||
@@ -56,6 +62,9 @@ void CHyprXWaylandManager::activateWindow(CWindow* pWindow, bool activate) {
|
||||
|
||||
g_pCompositor->m_pLastFocus = getWindowSurface(pWindow);
|
||||
g_pCompositor->m_pLastWindow = pWindow;
|
||||
|
||||
if (!pWindow->m_bPinned)
|
||||
g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID)->m_pLastFocusedWindow = pWindow;
|
||||
}
|
||||
|
||||
void CHyprXWaylandManager::getGeometryForWindow(CWindow* pWindow, wlr_box* pbox) {
|
||||
|
@@ -2,16 +2,18 @@
|
||||
#include "../../Compositor.hpp"
|
||||
|
||||
void CInputManager::onMouseMoved(wlr_pointer_motion_event* e) {
|
||||
float sensitivity = g_pConfigManager->getFloat("general:sensitivity");
|
||||
static auto *const PSENS = &g_pConfigManager->getConfigValuePtr("general:sensitivity")->floatValue;
|
||||
static auto *const PNOACCEL = &g_pConfigManager->getConfigValuePtr("input:force_no_accel")->intValue;
|
||||
static auto* const PSENSTORAW = &g_pConfigManager->getConfigValuePtr("general:apply_sens_to_raw")->intValue;
|
||||
|
||||
const auto DELTA = g_pConfigManager->getInt("input:force_no_accel") == 1 ? Vector2D(e->unaccel_dx, e->unaccel_dy) : Vector2D(e->delta_x, e->delta_y);
|
||||
const auto DELTA = *PNOACCEL == 1 ? Vector2D(e->unaccel_dx, e->unaccel_dy) : Vector2D(e->delta_x, e->delta_y);
|
||||
|
||||
if (g_pConfigManager->getInt("general:apply_sens_to_raw") == 1)
|
||||
wlr_relative_pointer_manager_v1_send_relative_motion(g_pCompositor->m_sWLRRelPointerMgr, g_pCompositor->m_sSeat.seat, (uint64_t)e->time_msec * 1000, DELTA.x * sensitivity, DELTA.y * sensitivity, e->unaccel_dx * sensitivity, e->unaccel_dy * sensitivity);
|
||||
if (*PSENSTORAW == 1)
|
||||
wlr_relative_pointer_manager_v1_send_relative_motion(g_pCompositor->m_sWLRRelPointerMgr, g_pCompositor->m_sSeat.seat, (uint64_t)e->time_msec * 1000, DELTA.x * *PSENS, DELTA.y * *PSENS, e->unaccel_dx * *PSENS, e->unaccel_dy * *PSENS);
|
||||
else
|
||||
wlr_relative_pointer_manager_v1_send_relative_motion(g_pCompositor->m_sWLRRelPointerMgr, g_pCompositor->m_sSeat.seat, (uint64_t)e->time_msec * 1000, DELTA.x, DELTA.y, e->unaccel_dx, e->unaccel_dy);
|
||||
|
||||
wlr_cursor_move(g_pCompositor->m_sWLRCursor, &e->pointer->base, DELTA.x * sensitivity, DELTA.y * sensitivity);
|
||||
wlr_cursor_move(g_pCompositor->m_sWLRCursor, &e->pointer->base, DELTA.x * *PSENS, DELTA.y * *PSENS);
|
||||
|
||||
mouseMoveUnified(e->time_msec);
|
||||
|
||||
@@ -27,11 +29,11 @@ void CInputManager::onMouseWarp(wlr_pointer_motion_absolute_event* e) {
|
||||
}
|
||||
|
||||
void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
|
||||
static auto *const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
|
||||
static auto *const PMOUSEDPMS = &g_pConfigManager->getConfigValuePtr("misc:mouse_move_enables_dpms")->intValue;
|
||||
static auto *const PFOLLOWONDND = &g_pConfigManager->getConfigValuePtr("misc:always_follow_on_dnd")->intValue;
|
||||
static auto *const PHOGFOCUS = &g_pConfigManager->getConfigValuePtr("misc:layers_hog_keyboard_focus")->intValue;
|
||||
static auto *const PFLOATBEHAVIOR = &g_pConfigManager->getConfigValuePtr("input:float_switch_override_focus")->intValue;
|
||||
|
||||
if (!g_pCompositor->m_bReadyToProcess)
|
||||
return;
|
||||
@@ -137,17 +139,27 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
if (!foundSurface)
|
||||
foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &surfaceCoords, &pFoundLayerSurface);
|
||||
|
||||
if (!foundSurface)
|
||||
foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &surfaceCoords, &pFoundLayerSurface);
|
||||
|
||||
// then, we check if the workspace doesnt have a fullscreen window
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow && !foundSurface && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) {
|
||||
pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
|
||||
|
||||
if (!pFoundWindow) {
|
||||
// what the fuck, somehow happens occasionally??
|
||||
PWORKSPACE->m_bHasFullscreenWindow = false;
|
||||
return;
|
||||
}
|
||||
|
||||
foundSurface = g_pXWaylandManager->getWindowSurface(pFoundWindow);
|
||||
surfacePos = pFoundWindow->m_vRealPosition.vec();
|
||||
|
||||
// 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_iWorkspaceID == SPECIAL_WORKSPACE_ID && PMONITOR->specialWorkspaceOpen)) && wlr_box_contains_point(&box, mouseCoords.x, mouseCoords.y) && g_pCompositor->isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->m_bHidden) {
|
||||
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)->m_bHidden) {
|
||||
pFoundWindow = (*w).get();
|
||||
|
||||
if (!pFoundWindow->m_bIsX11) {
|
||||
@@ -163,9 +175,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundSurface)
|
||||
foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &surfaceCoords, &pFoundLayerSurface);
|
||||
|
||||
// then windows
|
||||
if (!foundSurface) {
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) {
|
||||
@@ -208,12 +217,19 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
if (!foundSurface)
|
||||
foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &surfaceCoords, &pFoundLayerSurface);
|
||||
|
||||
g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor);
|
||||
|
||||
if (!foundSurface) {
|
||||
if (!m_bEmptyFocusCursorSet) {
|
||||
// TODO: maybe wrap?
|
||||
if (m_ecbClickBehavior == CLICKMODE_KILL)
|
||||
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;
|
||||
}
|
||||
|
||||
wlr_seat_pointer_clear_focus(g_pCompositor->m_sSeat.seat);
|
||||
|
||||
if (refocus) { // if we are forcing a refocus, and we don't find a surface, clear the kb focus too!
|
||||
@@ -223,6 +239,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_bEmptyFocusCursorSet = false;
|
||||
|
||||
if (time)
|
||||
wlr_idle_notify_activity(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat);
|
||||
|
||||
@@ -248,7 +266,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
|
||||
if (pFoundWindow) {
|
||||
if (*PFOLLOWMOUSE != 1 && !refocus) {
|
||||
if (pFoundWindow != g_pCompositor->m_pLastWindow && g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow) && (g_pCompositor->m_pLastWindow->m_bIsFloating != pFoundWindow->m_bIsFloating)) {
|
||||
if (pFoundWindow != g_pCompositor->m_pLastWindow && g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow) && g_pCompositor->m_pLastWindow->m_bIsFloating != pFoundWindow->m_bIsFloating && *PFLOATBEHAVIOR) {
|
||||
// enter if change floating style
|
||||
if (*PFOLLOWMOUSE != 3 && allowKeyboardRefocus)
|
||||
g_pCompositor->focusWindow(pFoundWindow, foundSurface);
|
||||
@@ -257,26 +275,36 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
|
||||
}
|
||||
|
||||
if (pFoundWindow == g_pCompositor->m_pLastWindow && foundSurface != g_pCompositor->m_pLastFocus) {
|
||||
// we changed the subsurface
|
||||
if (pFoundWindow == g_pCompositor->m_pLastWindow) {
|
||||
if (foundSurface != g_pCompositor->m_pLastFocus || m_bLastFocusOnLS) {
|
||||
// ^^^ changed the subsurface ^^^ came back from a LS
|
||||
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
|
||||
}
|
||||
}
|
||||
|
||||
if (*PFOLLOWONDND && m_sDrag.dragIcon) {
|
||||
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
|
||||
}
|
||||
|
||||
if (*PFOLLOWMOUSE != 0 || pFoundWindow == g_pCompositor->m_pLastWindow)
|
||||
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y);
|
||||
|
||||
m_bLastFocusOnLS = false;
|
||||
return; // don't enter any new surfaces
|
||||
} else {
|
||||
if (*PFOLLOWMOUSE != 3 && allowKeyboardRefocus)
|
||||
if ((*PFOLLOWMOUSE != 3 && allowKeyboardRefocus) || refocus)
|
||||
g_pCompositor->focusWindow(pFoundWindow, foundSurface);
|
||||
}
|
||||
|
||||
m_bLastFocusOnLS = false;
|
||||
} else {
|
||||
if (pFoundLayerSurface && pFoundLayerSurface->layerSurface->current.keyboard_interactive && *PFOLLOWMOUSE != 3 && allowKeyboardRefocus) {
|
||||
g_pCompositor->focusSurface(foundSurface);
|
||||
g_pCompositor->m_pLastWindow = nullptr; // reset last window as we have a full focus on a LS
|
||||
}
|
||||
|
||||
if (pFoundLayerSurface)
|
||||
m_bLastFocusOnLS = true;
|
||||
}
|
||||
|
||||
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
|
||||
@@ -371,22 +399,8 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
|
||||
if (g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow) && g_pCompositor->m_pLastWindow->m_bIsFloating)
|
||||
g_pCompositor->moveWindowToTop(g_pCompositor->m_pLastWindow);
|
||||
|
||||
if ((e->button == BTN_LEFT || e->button == BTN_RIGHT) && wlr_keyboard_get_modifiers(PKEYBOARD) == (uint32_t)g_pConfigManager->getInt("general:main_mod_internal")) {
|
||||
currentlyDraggedWindow = g_pCompositor->windowFromCursor();
|
||||
dragButton = e->button;
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->onBeginDragWindow();
|
||||
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case WLR_BUTTON_RELEASED:
|
||||
if (currentlyDraggedWindow) {
|
||||
g_pLayoutManager->getCurrentLayout()->onEndDragWindow();
|
||||
currentlyDraggedWindow = nullptr;
|
||||
dragButton = -1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -421,12 +435,17 @@ void CInputManager::processMouseDownKill(wlr_pointer_button_event* e) {
|
||||
}
|
||||
|
||||
void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) {
|
||||
static auto *const PSCROLLFACTOR = &g_pConfigManager->getConfigValuePtr("input:touchpad:scroll_factor")->floatValue;
|
||||
|
||||
auto factor = (*PSCROLLFACTOR <= 0.f || e->source != WLR_AXIS_SOURCE_FINGER ? 1.f : *PSCROLLFACTOR);
|
||||
|
||||
bool passEvent = g_pKeybindManager->onAxisEvent(e);
|
||||
|
||||
wlr_idle_notify_activity(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat);
|
||||
|
||||
if (passEvent) {
|
||||
wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, e->time_msec, e->orientation, e->delta, e->delta_discrete, e->source);
|
||||
wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, e->time_msec, e->orientation, factor * e->delta,
|
||||
std::round(factor * e->delta_discrete), e->source);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,6 +526,8 @@ void CInputManager::newVirtualKeyboard(wlr_input_device* keyboard) {
|
||||
void CInputManager::setKeyboardLayout() {
|
||||
for (auto& k : m_lKeyboards)
|
||||
applyConfigToKeyboard(&k);
|
||||
|
||||
g_pKeybindManager->updateXKBTranslationState();
|
||||
}
|
||||
|
||||
void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
|
||||
@@ -646,7 +667,7 @@ void CInputManager::newMouse(wlr_input_device* mouse, bool virt) {
|
||||
Debug::log(LOG, "New mouse has libinput sens %.2f (%.2f) with accel profile %i (%i)", libinput_device_config_accel_get_speed(LIBINPUTDEV), libinput_device_config_accel_get_default_speed(LIBINPUTDEV), libinput_device_config_accel_get_profile(LIBINPUTDEV), libinput_device_config_accel_get_default_profile(LIBINPUTDEV));
|
||||
}
|
||||
|
||||
setMouseConfigs();
|
||||
setPointerConfigs();
|
||||
|
||||
PMOUSE->hyprListener_destroyMouse.initCallback(&mouse->events.destroy, &Events::listener_destroyMouse, PMOUSE, "Mouse");
|
||||
|
||||
@@ -659,11 +680,11 @@ void CInputManager::newMouse(wlr_input_device* mouse, bool virt) {
|
||||
Debug::log(LOG, "New mouse created, pointer WLR: %x", mouse);
|
||||
}
|
||||
|
||||
void CInputManager::setMouseConfigs() {
|
||||
void CInputManager::setPointerConfigs() {
|
||||
for (auto& m : m_lMice) {
|
||||
const auto PMOUSE = &m;
|
||||
const auto PPOINTER = &m;
|
||||
|
||||
auto devname = PMOUSE->name;
|
||||
auto devname = PPOINTER->name;
|
||||
transform(devname.begin(), devname.end(), devname.begin(), ::tolower);
|
||||
|
||||
const auto HASCONFIG = g_pConfigManager->deviceConfigExists(devname);
|
||||
@@ -676,6 +697,11 @@ void CInputManager::setMouseConfigs() {
|
||||
else
|
||||
libinput_device_config_click_set_method(LIBINPUTDEV, LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
|
||||
|
||||
if ((HASCONFIG ? g_pConfigManager->getDeviceInt(devname, "left_handed") : g_pConfigManager->getInt("input:left_handed")) == 0)
|
||||
libinput_device_config_left_handed_set(LIBINPUTDEV, 0);
|
||||
else
|
||||
libinput_device_config_left_handed_set(LIBINPUTDEV, 1);
|
||||
|
||||
if (libinput_device_config_middle_emulation_is_available(LIBINPUTDEV)) { // middleclick on r+l mouse button pressed
|
||||
if ((HASCONFIG ? g_pConfigManager->getDeviceInt(devname, "middle_button_emulation") : g_pConfigManager->getInt("input:touchpad:middle_button_emulation")) == 1)
|
||||
libinput_device_config_middle_emulation_set_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED);
|
||||
@@ -683,6 +709,21 @@ void CInputManager::setMouseConfigs() {
|
||||
libinput_device_config_middle_emulation_set_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED);
|
||||
}
|
||||
|
||||
const auto SCROLLMETHOD = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "scroll_method") : g_pConfigManager->getString("input:scroll_method");
|
||||
if (SCROLLMETHOD == "" || SCROLLMETHOD == STRVAL_EMPTY) {
|
||||
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);
|
||||
} else if (SCROLLMETHOD == "2fg") {
|
||||
libinput_device_config_scroll_set_method(LIBINPUTDEV, LIBINPUT_CONFIG_SCROLL_2FG);
|
||||
} else if (SCROLLMETHOD == "edge") {
|
||||
libinput_device_config_scroll_set_method(LIBINPUTDEV, LIBINPUT_CONFIG_SCROLL_EDGE);
|
||||
} else if (SCROLLMETHOD == "on_button_down") {
|
||||
libinput_device_config_scroll_set_method(LIBINPUTDEV, LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN);
|
||||
} else {
|
||||
Debug::log(WARN, "Scroll method unknown");
|
||||
}
|
||||
|
||||
if ((HASCONFIG ? g_pConfigManager->getDeviceInt(devname, "drag_lock") : g_pConfigManager->getInt("input:touchpad:drag_lock")) == 0)
|
||||
libinput_device_config_tap_set_drag_lock_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_DRAG_LOCK_DISABLED);
|
||||
else
|
||||
@@ -707,10 +748,20 @@ void CInputManager::setMouseConfigs() {
|
||||
}
|
||||
|
||||
const auto LIBINPUTSENS = std::clamp((HASCONFIG ? g_pConfigManager->getDeviceFloat(devname, "sensitivity") : g_pConfigManager->getFloat("input:sensitivity")), -1.f, 1.f);
|
||||
|
||||
libinput_device_config_accel_set_profile(LIBINPUTDEV, LIBINPUT_CONFIG_ACCEL_PROFILE_NONE);
|
||||
libinput_device_config_accel_set_speed(LIBINPUTDEV, LIBINPUTSENS);
|
||||
|
||||
const auto ACCELPROFILE = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "accel_profile") : g_pConfigManager->getString("input:accel_profile");
|
||||
|
||||
if (ACCELPROFILE == "" || ACCELPROFILE == STRVAL_EMPTY) {
|
||||
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);
|
||||
} else if (ACCELPROFILE == "flat") {
|
||||
libinput_device_config_accel_set_profile(LIBINPUTDEV, LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT);
|
||||
} else {
|
||||
Debug::log(WARN, "Unknown acceleration profile, falling back to default");
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Applied config to mouse %s, sens %.2f", m.name.c_str(), LIBINPUTSENS);
|
||||
}
|
||||
}
|
||||
@@ -771,12 +822,17 @@ void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboar
|
||||
void CInputManager::onKeyboardMod(void* data, SKeyboard* pKeyboard) {
|
||||
const auto PIMEGRAB = m_sIMERelay.getIMEKeyboardGrab(pKeyboard);
|
||||
|
||||
const auto ALLMODS = accumulateModsFromAllKBs();
|
||||
|
||||
auto MODS = wlr_keyboard_from_input_device(pKeyboard->keyboard)->modifiers;
|
||||
MODS.depressed = ALLMODS;
|
||||
|
||||
if (PIMEGRAB && PIMEGRAB->pWlrKbGrab && PIMEGRAB->pWlrKbGrab->input_method) {
|
||||
wlr_input_method_keyboard_grab_v2_set_keyboard(PIMEGRAB->pWlrKbGrab, wlr_keyboard_from_input_device(pKeyboard->keyboard));
|
||||
wlr_input_method_keyboard_grab_v2_send_modifiers(PIMEGRAB->pWlrKbGrab, &wlr_keyboard_from_input_device(pKeyboard->keyboard)->modifiers);
|
||||
wlr_input_method_keyboard_grab_v2_send_modifiers(PIMEGRAB->pWlrKbGrab, &MODS);
|
||||
} else {
|
||||
wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, wlr_keyboard_from_input_device(pKeyboard->keyboard));
|
||||
wlr_seat_keyboard_notify_modifiers(g_pCompositor->m_sSeat.seat, &wlr_keyboard_from_input_device(pKeyboard->keyboard)->modifiers);
|
||||
wlr_seat_keyboard_notify_modifiers(g_pCompositor->m_sSeat.seat, &MODS);
|
||||
}
|
||||
|
||||
const auto PWLRKB = wlr_keyboard_from_input_device(pKeyboard->keyboard);
|
||||
@@ -888,11 +944,7 @@ void CInputManager::unconstrainMouse() {
|
||||
const auto CONSTRAINTWINDOW = g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse);
|
||||
|
||||
if (CONSTRAINTWINDOW) {
|
||||
if (CONSTRAINTWINDOW->m_bIsX11) {
|
||||
wlr_xwayland_surface_activate(CONSTRAINTWINDOW->m_uSurface.xwayland, false);
|
||||
} else {
|
||||
wlr_xdg_toplevel_set_activated(CONSTRAINTWINDOW->m_uSurface.xdg->toplevel, false);
|
||||
}
|
||||
g_pXWaylandManager->activateSurface(g_pXWaylandManager->getWindowSurface(CONSTRAINTWINDOW), false);
|
||||
}
|
||||
|
||||
wlr_pointer_constraint_v1_send_deactivated(g_pCompositor->m_sSeat.mouse->currentConstraint);
|
||||
@@ -933,6 +985,9 @@ uint32_t CInputManager::accumulateModsFromAllKBs() {
|
||||
uint32_t finalMask = 0;
|
||||
|
||||
for (auto& kb : m_lKeyboards) {
|
||||
if (kb.isVirtual)
|
||||
continue;
|
||||
|
||||
finalMask |= wlr_keyboard_get_modifiers(wlr_keyboard_from_input_device(kb.keyboard));
|
||||
}
|
||||
|
||||
@@ -967,3 +1022,48 @@ void CInputManager::disableAllKeyboards(bool virt) {
|
||||
k.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
void CInputManager::newTouchDevice(wlr_input_device* pDevice) {
|
||||
const auto PNEWDEV = &m_lTouchDevices.emplace_back();
|
||||
PNEWDEV->pWlrDevice = pDevice;
|
||||
|
||||
wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, pDevice);
|
||||
|
||||
Debug::log(LOG, "New touch device added at %x", PNEWDEV);
|
||||
|
||||
PNEWDEV->hyprListener_destroy.initCallback(&pDevice->events.destroy, [&](void* owner, void* data) {
|
||||
destroyTouchDevice((STouchDevice*)data);
|
||||
}, PNEWDEV, "TouchDevice");
|
||||
}
|
||||
|
||||
void CInputManager::destroyTouchDevice(STouchDevice* pDevice) {
|
||||
Debug::log(LOG, "Touch device at %x removed", pDevice);
|
||||
|
||||
m_lTouchDevices.remove(*pDevice);
|
||||
}
|
||||
|
||||
void CInputManager::newSwitch(wlr_input_device* pDevice) {
|
||||
const auto PNEWDEV = &m_lSwitches.emplace_back();
|
||||
PNEWDEV->pWlrDevice = pDevice;
|
||||
|
||||
Debug::log(LOG, "New switch with name \"%s\" added", pDevice->name);
|
||||
|
||||
PNEWDEV->hyprListener_destroy.initCallback(&pDevice->events.destroy, [&](void* owner, void* data) {
|
||||
destroySwitch((SSwitchDevice*)owner);
|
||||
}, PNEWDEV, "SwitchDevice");
|
||||
|
||||
const auto PSWITCH = wlr_switch_from_input_device(pDevice);
|
||||
|
||||
PNEWDEV->hyprListener_toggle.initCallback(&PSWITCH->events.toggle, [&](void* owner, void* data) {
|
||||
const auto PDEVICE = (SSwitchDevice*)owner;
|
||||
const auto NAME = std::string(PDEVICE->pWlrDevice->name);
|
||||
|
||||
Debug::log(LOG, "Switch %s fired, triggering binds.", NAME.c_str());
|
||||
|
||||
g_pKeybindManager->onSwitchEvent(NAME);
|
||||
}, PNEWDEV, "SwitchDevice");
|
||||
}
|
||||
|
||||
void CInputManager::destroySwitch(SSwitchDevice* pDevice) {
|
||||
m_lSwitches.remove(*pDevice);
|
||||
}
|
||||
|
@@ -12,6 +12,12 @@ enum eClickBehaviorMode {
|
||||
CLICKMODE_KILL
|
||||
};
|
||||
|
||||
enum eMouseBindMode {
|
||||
MBIND_INVALID = -1,
|
||||
MBIND_MOVE = 0,
|
||||
MBIND_RESIZE
|
||||
};
|
||||
|
||||
struct STouchData {
|
||||
CWindow* touchFocusWindow = nullptr;
|
||||
Vector2D touchSurfaceOrigin;
|
||||
@@ -30,8 +36,12 @@ public:
|
||||
void newKeyboard(wlr_input_device*);
|
||||
void newVirtualKeyboard(wlr_input_device*);
|
||||
void newMouse(wlr_input_device*, bool virt = false);
|
||||
void newTouchDevice(wlr_input_device*);
|
||||
void newSwitch(wlr_input_device*);
|
||||
void destroyTouchDevice(STouchDevice*);
|
||||
void destroyKeyboard(SKeyboard*);
|
||||
void destroyMouse(wlr_input_device*);
|
||||
void destroySwitch(SSwitchDevice*);
|
||||
|
||||
void constrainMouse(SMouse*, wlr_pointer_constraint_v1*);
|
||||
void recheckConstraint(SMouse*);
|
||||
@@ -42,7 +52,7 @@ public:
|
||||
void refocus();
|
||||
|
||||
void setKeyboardLayout();
|
||||
void setMouseConfigs();
|
||||
void setPointerConfigs();
|
||||
|
||||
void updateDragIcon();
|
||||
void updateCapabilities(wlr_input_device*);
|
||||
@@ -55,11 +65,14 @@ public:
|
||||
void onTouchUp(wlr_touch_up_event*);
|
||||
void onTouchMove(wlr_touch_motion_event*);
|
||||
|
||||
void onPointerHoldBegin(wlr_pointer_hold_begin_event*);
|
||||
void onPointerHoldEnd(wlr_pointer_hold_end_event*);
|
||||
|
||||
STouchData m_sTouchData;
|
||||
|
||||
// for dragging floating windows
|
||||
CWindow* currentlyDraggedWindow = nullptr;
|
||||
int dragButton = -1;
|
||||
eMouseBindMode dragMode = MBIND_INVALID;
|
||||
|
||||
SDrag m_sDrag;
|
||||
|
||||
@@ -75,6 +88,12 @@ public:
|
||||
// idle inhibitors
|
||||
std::list<SIdleInhibitor> m_lIdleInhibitors;
|
||||
|
||||
// Touch devices
|
||||
std::list<STouchDevice> m_lTouchDevices;
|
||||
|
||||
// Switches
|
||||
std::list<SSwitchDevice> m_lSwitches;
|
||||
|
||||
void newTabletTool(wlr_input_device*);
|
||||
void newTabletPad(wlr_input_device*);
|
||||
void focusTablet(STablet*, wlr_tablet_tool*, bool motion = false);
|
||||
@@ -102,8 +121,12 @@ private:
|
||||
|
||||
// for click behavior override
|
||||
eClickBehaviorMode m_ecbClickBehavior = CLICKMODE_DEFAULT;
|
||||
bool m_bEmptyFocusCursorSet = false;
|
||||
Vector2D m_vLastCursorPosFloored = Vector2D();
|
||||
|
||||
// for some bugs in follow mouse 0
|
||||
bool m_bLastFocusOnLS = false;
|
||||
|
||||
void processMouseDownNormal(wlr_pointer_button_event* e);
|
||||
void processMouseDownKill(wlr_pointer_button_event* e);
|
||||
|
||||
|
@@ -2,9 +2,7 @@
|
||||
#include "InputManager.hpp"
|
||||
#include "../../Compositor.hpp"
|
||||
|
||||
CInputMethodRelay::CInputMethodRelay() {
|
||||
|
||||
}
|
||||
CInputMethodRelay::CInputMethodRelay() { }
|
||||
|
||||
void CInputMethodRelay::onNewIME(wlr_input_method_v2* pIME) {
|
||||
if (m_pWLRIME) {
|
||||
@@ -125,6 +123,9 @@ void CInputMethodRelay::updateInputPopup(SIMEPopup* pPopup) {
|
||||
if (!pPopup->pSurface->mapped)
|
||||
return;
|
||||
|
||||
// damage last known pos & size
|
||||
g_pHyprRenderer->damageBox(pPopup->realX, pPopup->realY, pPopup->lastSize.x, pPopup->lastSize.y);
|
||||
|
||||
const auto PFOCUSEDTI = getFocusedTextInput();
|
||||
|
||||
if (!PFOCUSEDTI || !PFOCUSEDTI->pWlrInput->focused_surface)
|
||||
@@ -167,6 +168,8 @@ void CInputMethodRelay::updateInputPopup(SIMEPopup* pPopup) {
|
||||
pPopup->realX = finalBox.x + parentPos.x;
|
||||
pPopup->realY = finalBox.y + parentPos.y + finalBox.height;
|
||||
|
||||
pPopup->lastSize = Vector2D(pPopup->pSurface->surface->current.width, pPopup->pSurface->surface->current.height);
|
||||
|
||||
wlr_input_popup_surface_v2_send_text_input_rectangle(pPopup->pSurface, &finalBox);
|
||||
|
||||
damagePopup(pPopup);
|
||||
@@ -189,6 +192,8 @@ void Events::listener_unmapInputPopup(void* owner, void* data) {
|
||||
|
||||
Debug::log(LOG, "Unmapped an IME Popup");
|
||||
|
||||
g_pHyprRenderer->damageBox(PPOPUP->realX, PPOPUP->realY, PPOPUP->lastSize.x, PPOPUP->lastSize.y);
|
||||
|
||||
g_pInputManager->m_sIMERelay.updateInputPopup(PPOPUP);
|
||||
}
|
||||
|
||||
@@ -259,9 +264,6 @@ SIMEKbGrab* CInputMethodRelay::getIMEKeyboardGrab(SKeyboard* pKeyboard) {
|
||||
if (VIRTKB && (wl_resource_get_client(VIRTKB->resource) == wl_resource_get_client(m_pKeyboardGrab->pWlrKbGrab->resource)))
|
||||
return nullptr;
|
||||
|
||||
if (wlr_keyboard_from_input_device(pKeyboard->keyboard) != m_pKeyboardGrab->pKeyboard)
|
||||
return nullptr;
|
||||
|
||||
return m_pKeyboardGrab.get();
|
||||
}
|
||||
|
||||
|
@@ -2,16 +2,15 @@
|
||||
#include "../../Compositor.hpp"
|
||||
|
||||
void CInputManager::onSwipeBegin(wlr_pointer_swipe_begin_event* e) {
|
||||
|
||||
static auto *const PSWIPE = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe")->intValue;
|
||||
static auto *const PSWIPEFINGERS = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_fingers")->intValue;
|
||||
|
||||
if (e->fingers != *PSWIPEFINGERS|| *PSWIPE == 0)
|
||||
if (e->fingers != *PSWIPEFINGERS || *PSWIPE == 0)
|
||||
return;
|
||||
|
||||
int onMonitor = 0;
|
||||
for (auto& w : g_pCompositor->m_vWorkspaces) {
|
||||
if (w->m_iMonitorID == g_pCompositor->m_pLastMonitor->ID) {
|
||||
if (w->m_iMonitorID == g_pCompositor->m_pLastMonitor->ID && w->m_iID != SPECIAL_WORKSPACE_ID) {
|
||||
onMonitor++;
|
||||
}
|
||||
}
|
||||
@@ -28,10 +27,15 @@ void CInputManager::onSwipeBegin(wlr_pointer_swipe_begin_event* e) {
|
||||
m_sActiveSwipe.pMonitor = g_pCompositor->m_pLastMonitor;
|
||||
m_sActiveSwipe.avgSpeed = 0;
|
||||
m_sActiveSwipe.speedPoints = 0;
|
||||
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow) {
|
||||
for (auto& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
|
||||
ls->alpha = 255.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
|
||||
|
||||
if (!m_sActiveSwipe.pWorkspaceBegin)
|
||||
return; // no valid swipe
|
||||
|
||||
@@ -49,6 +53,8 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
|
||||
|
||||
const auto RENDEROFFSETMIDDLE = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.vec();
|
||||
|
||||
CWorkspace* pSwitchedTo = nullptr;
|
||||
|
||||
if ((abs(m_sActiveSwipe.delta) < *PSWIPEDIST * *PSWIPEPERC && (*PSWIPEFORC == 0 || (*PSWIPEFORC != 0 && m_sActiveSwipe.avgSpeed < *PSWIPEFORC))) || abs(m_sActiveSwipe.delta) < 2) {
|
||||
// revert
|
||||
if (abs(m_sActiveSwipe.delta) < 2) {
|
||||
@@ -66,6 +72,8 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
|
||||
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D();
|
||||
}
|
||||
|
||||
pSwitchedTo = m_sActiveSwipe.pWorkspaceBegin;
|
||||
} else if (m_sActiveSwipe.delta < 0) {
|
||||
// switch to left
|
||||
const auto RENDEROFFSET = PWORKSPACEL->m_vRenderOffset.vec();
|
||||
@@ -82,6 +90,8 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
|
||||
g_pInputManager->unconstrainMouse();
|
||||
|
||||
Debug::log(LOG, "Ended swipe to the left");
|
||||
|
||||
pSwitchedTo = PWORKSPACEL;
|
||||
} else {
|
||||
// switch to right
|
||||
const auto RENDEROFFSET = PWORKSPACER->m_vRenderOffset.vec();
|
||||
@@ -98,6 +108,8 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
|
||||
g_pInputManager->unconstrainMouse();
|
||||
|
||||
Debug::log(LOG, "Ended swipe to the right");
|
||||
|
||||
pSwitchedTo = PWORKSPACER;
|
||||
}
|
||||
|
||||
g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor);
|
||||
@@ -109,6 +121,11 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
|
||||
m_sActiveSwipe.pWorkspaceBegin = nullptr;
|
||||
|
||||
g_pInputManager->refocus();
|
||||
|
||||
// apply alpha
|
||||
for (auto& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
|
||||
ls->alpha = pSwitchedTo->m_bHasFullscreenWindow ? 0.f : 255.f;
|
||||
}
|
||||
}
|
||||
|
||||
void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
|
||||
@@ -127,8 +144,10 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
|
||||
auto workspaceIDLeft = getWorkspaceIDFromString("m-1", wsname);
|
||||
auto workspaceIDRight = getWorkspaceIDFromString("m+1", wsname);
|
||||
|
||||
if (workspaceIDLeft == INT_MAX || workspaceIDRight == INT_MAX || workspaceIDLeft == m_sActiveSwipe.pWorkspaceBegin->m_iID)
|
||||
if (workspaceIDLeft == INT_MAX || workspaceIDRight == INT_MAX || workspaceIDLeft == m_sActiveSwipe.pWorkspaceBegin->m_iID) {
|
||||
m_sActiveSwipe.pWorkspaceBegin = nullptr; // invalidate the swipe
|
||||
return;
|
||||
}
|
||||
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_bForceRendering = true;
|
||||
|
||||
|
@@ -2,8 +2,10 @@
|
||||
#include "../../Compositor.hpp"
|
||||
|
||||
void CInputManager::onTouchDown(wlr_touch_down_event* e) {
|
||||
auto PMONITOR = g_pCompositor->getMonitorFromName(e->touch->output_name ? e->touch->output_name : "");
|
||||
PMONITOR = PMONITOR ? PMONITOR : g_pCompositor->m_pLastMonitor;
|
||||
|
||||
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, g_pCompositor->m_pLastMonitor->vecPosition.x + e->x * g_pCompositor->m_pLastMonitor->vecSize.x, g_pCompositor->m_pLastMonitor->vecPosition.y + e->y * g_pCompositor->m_pLastMonitor->vecSize.y);
|
||||
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, PMONITOR->vecPosition.x + e->x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e->y * PMONITOR->vecSize.y);
|
||||
|
||||
refocus();
|
||||
|
||||
@@ -26,7 +28,6 @@ void CInputManager::onTouchDown(wlr_touch_down_event* e) {
|
||||
}
|
||||
|
||||
void CInputManager::onTouchUp(wlr_touch_up_event* e){
|
||||
|
||||
if (m_sTouchData.touchFocusWindow) {
|
||||
wlr_seat_touch_notify_up(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id);
|
||||
}
|
||||
@@ -43,3 +44,11 @@ void CInputManager::onTouchMove(wlr_touch_motion_event* e){
|
||||
wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id, local.x, local.y);
|
||||
}
|
||||
}
|
||||
|
||||
void CInputManager::onPointerHoldBegin(wlr_pointer_hold_begin_event* e) {
|
||||
wlr_pointer_gestures_v1_send_hold_begin(g_pCompositor->m_sWLRPointerGestures, g_pCompositor->m_sSeat.seat, e->time_msec, e->fingers);
|
||||
}
|
||||
|
||||
void CInputManager::onPointerHoldEnd(wlr_pointer_hold_end_event* e) {
|
||||
wlr_pointer_gestures_v1_send_hold_end(g_pCompositor->m_sWLRPointerGestures, g_pCompositor->m_sSeat.seat, e->time_msec, e->cancelled);
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@
|
||||
|
||||
bool CFramebuffer::alloc(int w, int h) {
|
||||
bool firstAlloc = false;
|
||||
RASSERT((w > 1 && h > 1), "cannot alloc a FB with negative / zero size! (attempted %ix%i)", w, h);
|
||||
|
||||
if (m_iFb == (uint32_t)-1) {
|
||||
firstAlloc = true;
|
||||
|
@@ -1,6 +1,8 @@
|
||||
#include "Shaders.hpp"
|
||||
#include "OpenGL.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "../helpers/MiscFunctions.hpp"
|
||||
#include "Shaders.hpp"
|
||||
|
||||
CHyprOpenGLImpl::CHyprOpenGLImpl() {
|
||||
RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL)), "Couldn't unset current EGL!");
|
||||
@@ -102,6 +104,7 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, pixman_region32_t* pDamage, bool
|
||||
m_RenderData.pCurrentMonData->primaryFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y);
|
||||
m_RenderData.pCurrentMonData->mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y);
|
||||
m_RenderData.pCurrentMonData->mirrorSwapFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y);
|
||||
m_RenderData.pCurrentMonData->monitorMirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y);
|
||||
|
||||
createBGTextureForMonitor(pMonitor);
|
||||
}
|
||||
@@ -120,11 +123,14 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, pixman_region32_t* pDamage, bool
|
||||
void CHyprOpenGLImpl::end() {
|
||||
// end the render, copy the data to the WLR framebuffer
|
||||
if (!m_bFakeFrame) {
|
||||
pixman_region32_copy(m_RenderData.pDamage, &m_rOriginalDamageRegion);
|
||||
|
||||
if (!m_RenderData.pMonitor->mirrors.empty())
|
||||
g_pHyprOpenGL->saveBufferForMirror(); // save with original damage region
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_iWLROutputFb);
|
||||
wlr_box monbox = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y};
|
||||
|
||||
pixman_region32_copy(m_RenderData.pDamage, &m_rOriginalDamageRegion);
|
||||
|
||||
clear(CColor(11, 11, 11, 255));
|
||||
|
||||
m_bEndFrame = true;
|
||||
@@ -145,9 +151,7 @@ void CHyprOpenGLImpl::initShaders() {
|
||||
m_RenderData.pCurrentMonData->m_shQUAD.proj = glGetUniformLocation(prog, "proj");
|
||||
m_RenderData.pCurrentMonData->m_shQUAD.color = glGetUniformLocation(prog, "color");
|
||||
m_RenderData.pCurrentMonData->m_shQUAD.posAttrib = glGetAttribLocation(prog, "pos");
|
||||
m_RenderData.pCurrentMonData->m_shQUAD.texAttrib = glGetAttribLocation(prog, "texcoord");
|
||||
m_RenderData.pCurrentMonData->m_shQUAD.topLeft = glGetUniformLocation(prog, "topLeft");
|
||||
m_RenderData.pCurrentMonData->m_shQUAD.bottomRight = glGetUniformLocation(prog, "bottomRight");
|
||||
m_RenderData.pCurrentMonData->m_shQUAD.fullSize = glGetUniformLocation(prog, "fullSize");
|
||||
m_RenderData.pCurrentMonData->m_shQUAD.radius = glGetUniformLocation(prog, "radius");
|
||||
m_RenderData.pCurrentMonData->m_shQUAD.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample");
|
||||
@@ -161,10 +165,11 @@ void CHyprOpenGLImpl::initShaders() {
|
||||
m_RenderData.pCurrentMonData->m_shRGBA.posAttrib = glGetAttribLocation(prog, "pos");
|
||||
m_RenderData.pCurrentMonData->m_shRGBA.discardOpaque = glGetUniformLocation(prog, "discardOpaque");
|
||||
m_RenderData.pCurrentMonData->m_shRGBA.topLeft = glGetUniformLocation(prog, "topLeft");
|
||||
m_RenderData.pCurrentMonData->m_shRGBA.bottomRight = glGetUniformLocation(prog, "bottomRight");
|
||||
m_RenderData.pCurrentMonData->m_shRGBA.fullSize = glGetUniformLocation(prog, "fullSize");
|
||||
m_RenderData.pCurrentMonData->m_shRGBA.radius = glGetUniformLocation(prog, "radius");
|
||||
m_RenderData.pCurrentMonData->m_shRGBA.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample");
|
||||
m_RenderData.pCurrentMonData->m_shRGBA.applyTint = glGetUniformLocation(prog, "applyTint");
|
||||
m_RenderData.pCurrentMonData->m_shRGBA.tint = glGetUniformLocation(prog, "tint");
|
||||
|
||||
prog = createProgram(TEXVERTSRC, TEXFRAGSRCRGBX);
|
||||
m_RenderData.pCurrentMonData->m_shRGBX.program = prog;
|
||||
@@ -175,10 +180,11 @@ void CHyprOpenGLImpl::initShaders() {
|
||||
m_RenderData.pCurrentMonData->m_shRGBX.posAttrib = glGetAttribLocation(prog, "pos");
|
||||
m_RenderData.pCurrentMonData->m_shRGBX.discardOpaque = glGetUniformLocation(prog, "discardOpaque");
|
||||
m_RenderData.pCurrentMonData->m_shRGBX.topLeft = glGetUniformLocation(prog, "topLeft");
|
||||
m_RenderData.pCurrentMonData->m_shRGBX.bottomRight = glGetUniformLocation(prog, "bottomRight");
|
||||
m_RenderData.pCurrentMonData->m_shRGBX.fullSize = glGetUniformLocation(prog, "fullSize");
|
||||
m_RenderData.pCurrentMonData->m_shRGBX.radius = glGetUniformLocation(prog, "radius");
|
||||
m_RenderData.pCurrentMonData->m_shRGBX.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample");
|
||||
m_RenderData.pCurrentMonData->m_shRGBX.applyTint = glGetUniformLocation(prog, "applyTint");
|
||||
m_RenderData.pCurrentMonData->m_shRGBX.tint = glGetUniformLocation(prog, "tint");
|
||||
|
||||
prog = createProgram(TEXVERTSRC, TEXFRAGSRCEXT);
|
||||
m_RenderData.pCurrentMonData->m_shEXT.program = prog;
|
||||
@@ -189,10 +195,11 @@ void CHyprOpenGLImpl::initShaders() {
|
||||
m_RenderData.pCurrentMonData->m_shEXT.texAttrib = glGetAttribLocation(prog, "texcoord");
|
||||
m_RenderData.pCurrentMonData->m_shEXT.discardOpaque = glGetUniformLocation(prog, "discardOpaque");
|
||||
m_RenderData.pCurrentMonData->m_shEXT.topLeft = glGetUniformLocation(prog, "topLeft");
|
||||
m_RenderData.pCurrentMonData->m_shEXT.bottomRight = glGetUniformLocation(prog, "bottomRight");
|
||||
m_RenderData.pCurrentMonData->m_shEXT.fullSize = glGetUniformLocation(prog, "fullSize");
|
||||
m_RenderData.pCurrentMonData->m_shEXT.radius = glGetUniformLocation(prog, "radius");
|
||||
m_RenderData.pCurrentMonData->m_shEXT.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample");
|
||||
m_RenderData.pCurrentMonData->m_shEXT.applyTint = glGetUniformLocation(prog, "applyTint");
|
||||
m_RenderData.pCurrentMonData->m_shEXT.tint = glGetUniformLocation(prog, "tint");
|
||||
|
||||
prog = createProgram(TEXVERTSRC, FRAGBLUR1);
|
||||
m_RenderData.pCurrentMonData->m_shBLUR1.program = prog;
|
||||
@@ -262,7 +269,7 @@ void CHyprOpenGLImpl::clear(const CColor& color) {
|
||||
scissor((wlr_box*)nullptr);
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::scissor(const wlr_box* pBox) {
|
||||
void CHyprOpenGLImpl::scissor(const wlr_box* pBox, bool transform) {
|
||||
RASSERT(m_RenderData.pMonitor, "Tried to scissor without begin()!");
|
||||
|
||||
if (!pBox) {
|
||||
@@ -272,17 +279,19 @@ void CHyprOpenGLImpl::scissor(const wlr_box* pBox) {
|
||||
|
||||
wlr_box newBox = *pBox;
|
||||
|
||||
if (transform) {
|
||||
int w, h;
|
||||
wlr_output_transformed_resolution(m_RenderData.pMonitor->output, &w, &h);
|
||||
|
||||
const auto TR = wlr_output_transform_invert(m_RenderData.pMonitor->transform);
|
||||
wlr_box_transform(&newBox, &newBox, TR, w, h);
|
||||
}
|
||||
|
||||
glScissor(newBox.x, newBox.y, newBox.width, newBox.height);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::scissor(const pixman_box32* pBox) {
|
||||
void CHyprOpenGLImpl::scissor(const pixman_box32* pBox, bool transform) {
|
||||
RASSERT(m_RenderData.pMonitor, "Tried to scissor without begin()!");
|
||||
|
||||
if (!pBox) {
|
||||
@@ -292,12 +301,12 @@ void CHyprOpenGLImpl::scissor(const pixman_box32* pBox) {
|
||||
|
||||
wlr_box newBox = {pBox->x1, pBox->y1, pBox->x2 - pBox->x1, pBox->y2 - pBox->y1};
|
||||
|
||||
scissor(&newBox);
|
||||
scissor(&newBox, transform);
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::scissor(const int x, const int y, const int w, const int h) {
|
||||
void CHyprOpenGLImpl::scissor(const int x, const int y, const int w, const int h, bool transform) {
|
||||
wlr_box box = {x,y,w,h};
|
||||
scissor(&box);
|
||||
scissor(&box, transform);
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::renderRect(wlr_box* box, const CColor& col, int round) {
|
||||
@@ -325,15 +334,13 @@ void CHyprOpenGLImpl::renderRectWithDamage(wlr_box* box, const CColor& col, pixm
|
||||
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_FALSE, glMatrix);
|
||||
glUniform4f(m_RenderData.pCurrentMonData->m_shQUAD.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 TOPLEFT = Vector2D(box->x, box->y);
|
||||
const auto FULLSIZE = Vector2D(box->width, box->height);
|
||||
|
||||
static auto *const PMULTISAMPLEEDGES = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue;
|
||||
|
||||
// Rounded corners
|
||||
glUniform2f(m_RenderData.pCurrentMonData->m_shQUAD.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y);
|
||||
glUniform2f(m_RenderData.pCurrentMonData->m_shQUAD.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
|
||||
glUniform2f(m_RenderData.pCurrentMonData->m_shQUAD.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y);
|
||||
glUniform1f(m_RenderData.pCurrentMonData->m_shQUAD.radius, round);
|
||||
glUniform1i(m_RenderData.pCurrentMonData->m_shQUAD.primitiveMultisample, (int)(*PMULTISAMPLEEDGES == 1 && round != 0));
|
||||
@@ -367,15 +374,17 @@ void CHyprOpenGLImpl::renderTexture(wlr_texture* tex, wlr_box* pBox, float alpha
|
||||
void CHyprOpenGLImpl::renderTexture(const CTexture& tex, wlr_box* pBox, float alpha, int round, bool discardopaque, bool allowCustomUV) {
|
||||
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
|
||||
|
||||
renderTextureInternalWithDamage(tex, pBox, alpha, m_RenderData.pDamage, round, discardopaque, false, allowCustomUV);
|
||||
renderTextureInternalWithDamage(tex, pBox, alpha, m_RenderData.pDamage, round, discardopaque, false, allowCustomUV, true);
|
||||
|
||||
scissor((wlr_box*)nullptr);
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_box* pBox, float alpha, pixman_region32_t* damage, int round, bool discardOpaque, bool noAA, bool allowCustomUV) {
|
||||
void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_box* pBox, float alpha, pixman_region32_t* damage, int round, bool discardOpaque, bool noAA, bool allowCustomUV, bool allowDim) {
|
||||
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
|
||||
RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!");
|
||||
|
||||
static auto *const PDIMINACTIVE = &g_pConfigManager->getConfigValuePtr("decoration:dim_inactive")->intValue;
|
||||
|
||||
// get transform
|
||||
const auto TRANSFORM = wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform);
|
||||
float matrix[9];
|
||||
@@ -427,13 +436,18 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
|
||||
static auto *const PMULTISAMPLEEDGES = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue;
|
||||
|
||||
// Rounded corners
|
||||
glUniform2f(shader->topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y);
|
||||
glUniform2f(shader->bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
|
||||
glUniform2f(shader->fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y);
|
||||
glUniform2f(shader->topLeft, pBox->x, pBox->y);
|
||||
glUniform2f(shader->fullSize, pBox->width, pBox->height);
|
||||
glUniform1f(shader->radius, round);
|
||||
glUniform1i(shader->primitiveMultisample, (int)(*PMULTISAMPLEEDGES == 1 && round != 0 && !noAA));
|
||||
|
||||
glVertexAttribPointer(shader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
|
||||
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[] = {
|
||||
m_RenderData.primarySurfaceUVBottomRight.x, m_RenderData.primarySurfaceUVTopLeft.y, // top right
|
||||
@@ -442,6 +456,8 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
|
||||
m_RenderData.primarySurfaceUVTopLeft.x, m_RenderData.primarySurfaceUVBottomRight.y, // bottom left
|
||||
};
|
||||
|
||||
glVertexAttribPointer(shader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
|
||||
|
||||
if (allowCustomUV && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) {
|
||||
glVertexAttribPointer(shader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, verts);
|
||||
} else {
|
||||
@@ -475,9 +491,9 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
|
||||
// get transforms for the full monitor
|
||||
const auto TRANSFORM = wlr_output_transform_invert(WL_OUTPUT_TRANSFORM_NORMAL);
|
||||
const auto TRANSFORM = wlr_output_transform_invert(m_RenderData.pMonitor->transform);
|
||||
float matrix[9];
|
||||
wlr_box MONITORBOX = {0, 0, m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y};
|
||||
wlr_box MONITORBOX = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y};
|
||||
wlr_matrix_project_box(matrix, &MONITORBOX, TRANSFORM, 0, m_RenderData.pMonitor->output->transform_matrix);
|
||||
|
||||
float glMatrix[9];
|
||||
@@ -493,6 +509,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p
|
||||
pixman_region32_t damage;
|
||||
pixman_region32_init(&damage);
|
||||
pixman_region32_copy(&damage, originalDamage);
|
||||
wlr_region_transform(&damage, &damage, wlr_output_transform_invert(m_RenderData.pMonitor->transform), m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y);
|
||||
wlr_region_expand(&damage, &damage, pow(2, *PBLURPASSES) * *PBLURSIZE);
|
||||
|
||||
// helper
|
||||
@@ -534,7 +551,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p
|
||||
if (pixman_region32_not_empty(pDamage)) {
|
||||
PIXMAN_DAMAGE_FOREACH(pDamage) {
|
||||
const auto RECT = RECTSARR[i];
|
||||
scissor(&RECT);
|
||||
scissor(&RECT, false /* this region is already transformed */);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
@@ -621,7 +638,9 @@ void CHyprOpenGLImpl::preBlurForCurrentMonitor() {
|
||||
|
||||
clear(CColor(0,0,0,0));
|
||||
|
||||
m_bEndFrame = true; // fix transformed
|
||||
renderTextureInternalWithDamage(POUTFB->m_cTex, &wholeMonitor, 255, &fakeDamage, 0, false, true, false);
|
||||
m_bEndFrame = false;
|
||||
|
||||
m_RenderData.pCurrentMonData->primaryFB.bind();
|
||||
|
||||
@@ -629,7 +648,7 @@ void CHyprOpenGLImpl::preBlurForCurrentMonitor() {
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::preWindowPass() {
|
||||
static auto* const PBLURNEWOPTIMIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_new_optimizations")->intValue;
|
||||
static auto *const PBLURNEWOPTIMIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_new_optimizations")->intValue;
|
||||
|
||||
if (!m_RenderData.pCurrentMonData->blurFBDirty || !*PBLURNEWOPTIMIZE)
|
||||
return;
|
||||
@@ -654,7 +673,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox,
|
||||
|
||||
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 PBLURNEWOPTIMIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_new_optimizations")->intValue;
|
||||
|
||||
if (*PBLURENABLED == 0 || (*PNOBLUROVERSIZED && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) || (m_pCurrentWindow && m_pCurrentWindow->m_sAdditionalConfigData.forceNoBlur)) {
|
||||
renderTexture(tex, pBox, a, round, false, true);
|
||||
@@ -685,7 +704,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox,
|
||||
}
|
||||
|
||||
// vvv TODO: layered blur fbs?
|
||||
const bool USENEWOPTIMIZE = (*PBLURNEWOPTIMIZE && m_pCurrentWindow && !m_pCurrentWindow->m_bIsFloating && m_RenderData.pCurrentMonData->blurFB.m_cTex.m_iTexID);
|
||||
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);
|
||||
|
||||
@@ -719,7 +738,9 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox,
|
||||
if (pixman_region32_not_empty(&damage)) {
|
||||
// render our great blurred FB
|
||||
static auto *const PBLURIGNOREOPACITY = &g_pConfigManager->getConfigValuePtr("decoration:blur_ignore_opacity")->intValue;
|
||||
m_bEndFrame = true; // fix transformed
|
||||
renderTextureInternalWithDamage(POUTFB->m_cTex, &MONITORBOX, *PBLURIGNOREOPACITY ? 255.f : a, &damage, 0, false, false, false);
|
||||
m_bEndFrame = false;
|
||||
|
||||
// render the window, but clear stencil
|
||||
glClearStencil(0);
|
||||
@@ -727,7 +748,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox,
|
||||
|
||||
// draw window
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
renderTextureInternalWithDamage(tex, pBox, a, &damage, round, false, false, true);
|
||||
renderTextureInternalWithDamage(tex, pBox, a, &damage, round, false, false, true, true);
|
||||
}
|
||||
|
||||
glStencilMask(-1);
|
||||
@@ -753,27 +774,29 @@ void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int round) {
|
||||
if (*PBORDERSIZE < 1)
|
||||
return;
|
||||
|
||||
int scaledBorderSize = *PBORDERSIZE * m_RenderData.pMonitor->scale;
|
||||
|
||||
if (round < 1) {
|
||||
// zero rounding, just lines
|
||||
wlr_box borderbox = {box->x - *PBORDERSIZE, box->y - *PBORDERSIZE, *PBORDERSIZE, box->height + 2 * *PBORDERSIZE};
|
||||
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)*PBORDERSIZE, box->width + (int)*PBORDERSIZE, (int)*PBORDERSIZE};
|
||||
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)*PBORDERSIZE, box->height + (int)*PBORDERSIZE};
|
||||
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)*PBORDERSIZE};
|
||||
borderbox = {box->x, box->y + box->height, box->width, (int)scaledBorderSize};
|
||||
renderRect(&borderbox, col, 0); // bottom
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// adjust box
|
||||
box->x -= *PBORDERSIZE;
|
||||
box->y -= *PBORDERSIZE;
|
||||
box->width += 2 * *PBORDERSIZE;
|
||||
box->height += 2 * *PBORDERSIZE;
|
||||
box->x -= scaledBorderSize;
|
||||
box->y -= scaledBorderSize;
|
||||
box->width += 2 * scaledBorderSize;
|
||||
box->height += 2 * scaledBorderSize;
|
||||
|
||||
round += *PBORDERSIZE;
|
||||
round += 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
|
||||
@@ -800,7 +823,7 @@ void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int round) {
|
||||
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);
|
||||
glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radius, round);
|
||||
glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.thick, *PBORDERSIZE);
|
||||
glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.thick, scaledBorderSize);
|
||||
glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.primitiveMultisample, *PMULTISAMPLE);
|
||||
|
||||
glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
|
||||
@@ -850,28 +873,22 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
|
||||
const auto BLURVAL = g_pConfigManager->getInt("decoration:blur");
|
||||
g_pConfigManager->setInt("decoration:blur", 0);
|
||||
|
||||
g_pHyprRenderer->renderWindow(pWindow, PMONITOR, &now, !pWindow->m_bX11DoesntWantBorders, RENDER_PASS_ALL);
|
||||
|
||||
m_bEndFrame = true;
|
||||
|
||||
g_pConfigManager->setInt("decoration:blur", BLURVAL);
|
||||
|
||||
// render onto the window fb
|
||||
// we rendered onto the primary because it has a stencil, which we need for the borders etc
|
||||
const auto PFRAMEBUFFER = &m_mWindowFramebuffers[pWindow];
|
||||
|
||||
glViewport(0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.y);
|
||||
|
||||
PFRAMEBUFFER->m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex;
|
||||
|
||||
PFRAMEBUFFER->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
|
||||
|
||||
PFRAMEBUFFER->bind();
|
||||
|
||||
clear(CColor(0, 0, 0, 0)); // JIC
|
||||
|
||||
wlr_box fullMonBox = {0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y};
|
||||
g_pHyprRenderer->renderWindow(pWindow, PMONITOR, &now, !pWindow->m_bX11DoesntWantBorders, RENDER_PASS_ALL);
|
||||
|
||||
renderTexture(m_RenderData.pCurrentMonData->primaryFB.m_cTex, &fullMonBox, 255.f, 0);
|
||||
m_bEndFrame = false;
|
||||
g_pConfigManager->setInt("decoration:blur", BLURVAL);
|
||||
|
||||
// restore original fb
|
||||
#ifndef GLES2
|
||||
@@ -896,7 +913,7 @@ void CHyprOpenGLImpl::makeLayerSnapshot(SLayerSurface* pLayer) {
|
||||
// this is temporary, doesnt mess with the actual wlr damage
|
||||
pixman_region32_t fakeDamage;
|
||||
pixman_region32_init(&fakeDamage);
|
||||
pixman_region32_union_rect(&fakeDamage, &fakeDamage, 0, 0, (int)PMONITOR->vecPixelSize.x, (int)PMONITOR->vecPixelSize.y);
|
||||
pixman_region32_union_rect(&fakeDamage, &fakeDamage, 0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y);
|
||||
|
||||
begin(PMONITOR, &fakeDamage, true);
|
||||
|
||||
@@ -916,8 +933,6 @@ void CHyprOpenGLImpl::makeLayerSnapshot(SLayerSurface* pLayer) {
|
||||
// draw the layer
|
||||
g_pHyprRenderer->renderLayer(pLayer, PMONITOR, &now);
|
||||
|
||||
m_bEndFrame = false;
|
||||
|
||||
// TODO: WARN:
|
||||
// revise if any stencil-requiring rendering is done to the layers.
|
||||
|
||||
@@ -956,8 +971,6 @@ void CHyprOpenGLImpl::renderSnapshot(CWindow** pWindow) {
|
||||
// the originalClosedPos is relative to the monitor's pos
|
||||
Vector2D scaleXY = Vector2D((PMONITOR->scale * PWINDOW->m_vRealSize.vec().x / (PWINDOW->m_vOriginalClosedSize.x * PMONITOR->scale)), (PMONITOR->scale * PWINDOW->m_vRealSize.vec().y / (PWINDOW->m_vOriginalClosedSize.y * PMONITOR->scale)));
|
||||
|
||||
// TODO: this is wrong on scaled.
|
||||
|
||||
windowBox.width = PMONITOR->vecTransformedSize.x * scaleXY.x;
|
||||
windowBox.height = PMONITOR->vecTransformedSize.y * scaleXY.y;
|
||||
windowBox.x = ((PWINDOW->m_vRealPosition.vec().x - PMONITOR->vecPosition.x) * PMONITOR->scale) - ((PWINDOW->m_vOriginalClosedPos.x * PMONITOR->scale) * scaleXY.x);
|
||||
@@ -966,8 +979,12 @@ void CHyprOpenGLImpl::renderSnapshot(CWindow** pWindow) {
|
||||
pixman_region32_t fakeDamage;
|
||||
pixman_region32_init_rect(&fakeDamage, 0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y);
|
||||
|
||||
m_bEndFrame = true;
|
||||
|
||||
renderTextureInternalWithDamage(it->second.m_cTex, &windowBox, PWINDOW->m_fAlpha.fl(), &fakeDamage, 0);
|
||||
|
||||
m_bEndFrame = false;
|
||||
|
||||
pixman_region32_fini(&fakeDamage);
|
||||
|
||||
static auto *const PDAMAGEMON = &g_pConfigManager->getConfigValuePtr("misc:damage_entire_on_snapshot")->intValue;
|
||||
@@ -992,12 +1009,16 @@ void CHyprOpenGLImpl::renderSnapshot(SLayerSurface** pLayer) {
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(PLAYER->monitorID);
|
||||
|
||||
wlr_box windowBox = {0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y};
|
||||
wlr_box monbox = {0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y};
|
||||
|
||||
pixman_region32_t fakeDamage;
|
||||
pixman_region32_init_rect(&fakeDamage, 0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y);
|
||||
|
||||
renderTextureInternalWithDamage(it->second.m_cTex, &windowBox, PLAYER->alpha.fl(), &fakeDamage, 0);
|
||||
m_bEndFrame = true;
|
||||
|
||||
renderTextureInternalWithDamage(it->second.m_cTex, &monbox, PLAYER->alpha.fl(), &fakeDamage, 0);
|
||||
|
||||
m_bEndFrame = false;
|
||||
|
||||
pixman_region32_fini(&fakeDamage);
|
||||
|
||||
@@ -1067,18 +1088,40 @@ void CHyprOpenGLImpl::renderRoundedShadow(wlr_box* box, int round, int range, fl
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::renderSplash(cairo_t *const CAIRO, cairo_surface_t *const CAIROSURFACE) {
|
||||
void CHyprOpenGLImpl::saveBufferForMirror() {
|
||||
m_RenderData.pCurrentMonData->monitorMirrorFB.bind();
|
||||
|
||||
wlr_box monbox = {0, 0, m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y};
|
||||
|
||||
renderTexture(m_RenderData.pCurrentMonData->primaryFB.m_cTex, &monbox, 255.f, 0, false, false);
|
||||
|
||||
m_RenderData.pCurrentMonData->primaryFB.bind();
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::renderMirrored() {
|
||||
wlr_box monbox = {0, 0, m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y};
|
||||
|
||||
const auto PFB = &m_mMonitorRenderResources[m_RenderData.pMonitor->pMirrorOf].monitorMirrorFB;
|
||||
|
||||
if (PFB->m_cTex.m_iTexID <= 0)
|
||||
return;
|
||||
|
||||
renderTexture(PFB->m_cTex, &monbox, 255.f, 0, false, false);
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::renderSplash(cairo_t *const CAIRO, cairo_surface_t *const CAIROSURFACE, double offsetY) {
|
||||
cairo_select_font_face(CAIRO, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
|
||||
|
||||
const auto FONTSIZE = (int)(m_RenderData.pMonitor->vecPixelSize.y / 76);
|
||||
cairo_set_font_size(CAIRO, FONTSIZE);
|
||||
|
||||
cairo_set_source_rgba(CAIRO, 1.f, 1.f, 1.f, 0.32f);
|
||||
cairo_set_source_rgba(CAIRO, 1.0, 1.0, 1.0, 0.32);
|
||||
|
||||
cairo_text_extents_t textExtents;
|
||||
cairo_text_extents(CAIRO, g_pCompositor->m_szCurrentSplash.c_str(), &textExtents);
|
||||
|
||||
cairo_move_to(CAIRO, m_RenderData.pMonitor->vecTransformedSize.x / 2.f - textExtents.width / 2.f, m_RenderData.pMonitor->vecTransformedSize.y - textExtents.height - 1);
|
||||
cairo_move_to(CAIRO, (m_RenderData.pMonitor->vecPixelSize.x - textExtents.width) / 2.0, m_RenderData.pMonitor->vecPixelSize.y - textExtents.height + offsetY);
|
||||
|
||||
cairo_show_text(CAIRO, g_pCompositor->m_szCurrentSplash.c_str());
|
||||
|
||||
cairo_surface_flush(CAIROSURFACE);
|
||||
@@ -1120,13 +1163,37 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) {
|
||||
|
||||
PTEX->m_vSize = textureSize;
|
||||
|
||||
// calc the target box
|
||||
const double MONRATIO = m_RenderData.pMonitor->vecTransformedSize.x / m_RenderData.pMonitor->vecTransformedSize.y;
|
||||
const double WPRATIO = 1.77;
|
||||
|
||||
Vector2D origin;
|
||||
double scale;
|
||||
|
||||
if (MONRATIO > WPRATIO) {
|
||||
scale = m_RenderData.pMonitor->vecTransformedSize.x / PTEX->m_vSize.x;
|
||||
|
||||
origin.y = (m_RenderData.pMonitor->vecTransformedSize.y - PTEX->m_vSize.y * scale) / 2.0;
|
||||
} else {
|
||||
scale = m_RenderData.pMonitor->vecTransformedSize.y / PTEX->m_vSize.y;
|
||||
|
||||
origin.x = (m_RenderData.pMonitor->vecTransformedSize.x - PTEX->m_vSize.x * scale) / 2.0;
|
||||
}
|
||||
|
||||
wlr_box box = {origin.x, origin.y, PTEX->m_vSize.x * scale, PTEX->m_vSize.y * scale};
|
||||
|
||||
m_mMonitorRenderResources[pMonitor].backgroundTexBox = box;
|
||||
|
||||
// create a new one with cairo
|
||||
const auto CAIROSURFACE = cairo_image_surface_create_from_png(texPath.c_str());
|
||||
|
||||
const auto CAIRO = cairo_create(CAIROSURFACE);
|
||||
|
||||
// scale it to fit the current monitor
|
||||
cairo_scale(CAIRO, textureSize.x / pMonitor->vecTransformedSize.x, textureSize.y / pMonitor->vecTransformedSize.y);
|
||||
|
||||
// render splash on wallpaper
|
||||
if (!*PNOSPLASH)
|
||||
renderSplash(CAIRO, CAIROSURFACE);
|
||||
renderSplash(CAIRO, CAIROSURFACE, origin.y * WPRATIO / MONRATIO);
|
||||
|
||||
// copy the data to an OpenGL texture we have
|
||||
const auto DATA = cairo_image_surface_get_data(CAIROSURFACE);
|
||||
@@ -1142,28 +1209,6 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) {
|
||||
cairo_surface_destroy(CAIROSURFACE);
|
||||
cairo_destroy(CAIRO);
|
||||
|
||||
// calc the target box
|
||||
|
||||
const float MONRATIO = m_RenderData.pMonitor->vecTransformedSize.x / m_RenderData.pMonitor->vecTransformedSize.y;
|
||||
const float WPRATIO = 1.77f;
|
||||
|
||||
Vector2D origin;
|
||||
float scale;
|
||||
|
||||
if (MONRATIO > WPRATIO) {
|
||||
scale = m_RenderData.pMonitor->vecTransformedSize.x / PTEX->m_vSize.x;
|
||||
|
||||
origin.y = -(PTEX->m_vSize.y * scale - m_RenderData.pMonitor->vecTransformedSize.y) / 2.f / scale;
|
||||
} else {
|
||||
scale = m_RenderData.pMonitor->vecTransformedSize.y / PTEX->m_vSize.y;
|
||||
|
||||
origin.x = -(PTEX->m_vSize.x * scale - m_RenderData.pMonitor->vecTransformedSize.x) / 2.f / scale;
|
||||
}
|
||||
|
||||
wlr_box box = {origin.x * scale, origin.y * scale, PTEX->m_vSize.x * scale, PTEX->m_vSize.y * scale};
|
||||
|
||||
m_mMonitorRenderResources[pMonitor].backgroundTexBox = box;
|
||||
|
||||
Debug::log(LOG, "Background created for monitor %s", pMonitor->szName.c_str());
|
||||
}
|
||||
|
||||
|
@@ -8,7 +8,6 @@
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
|
||||
#include "Shaders.hpp"
|
||||
#include "Shader.hpp"
|
||||
#include "Texture.hpp"
|
||||
#include "Framebuffer.hpp"
|
||||
@@ -33,8 +32,10 @@ inline const float fanVertsFull[] = {
|
||||
|
||||
struct SMonitorRenderData {
|
||||
CFramebuffer primaryFB;
|
||||
CFramebuffer mirrorFB;
|
||||
CFramebuffer mirrorSwapFB;
|
||||
CFramebuffer mirrorFB; // these are used for some effects,
|
||||
CFramebuffer mirrorSwapFB; // etc
|
||||
|
||||
CFramebuffer monitorMirrorFB; // used for mirroring outputs
|
||||
|
||||
CTexture stencilTex;
|
||||
|
||||
@@ -91,9 +92,9 @@ public:
|
||||
|
||||
void clear(const CColor&);
|
||||
void clearWithTex();
|
||||
void scissor(const wlr_box*);
|
||||
void scissor(const pixman_box32*);
|
||||
void scissor(const int x, const int y, const int w, const int h);
|
||||
void scissor(const wlr_box*, bool transform = true);
|
||||
void scissor(const pixman_box32*, bool transform = true);
|
||||
void scissor(const int x, const int y, const int w, const int h, bool transform = true);
|
||||
|
||||
void destroyMonitorResources(CMonitor*);
|
||||
|
||||
@@ -102,6 +103,9 @@ public:
|
||||
void preWindowPass();
|
||||
void preRender(CMonitor*);
|
||||
|
||||
void saveBufferForMirror();
|
||||
void renderMirrored();
|
||||
|
||||
SCurrentRenderData m_RenderData;
|
||||
|
||||
GLint m_iCurrentOutputFb = 0;
|
||||
@@ -134,9 +138,8 @@ private:
|
||||
// returns the out FB, can be either Mirror or MirrorSwap
|
||||
CFramebuffer* blurMainFramebufferWithDamage(float a, wlr_box* pBox, pixman_region32_t* damage);
|
||||
|
||||
void renderTextureInternalWithDamage(const CTexture&, wlr_box* pBox, float a, pixman_region32_t* damage, int round = 0, bool discardOpaque = false, bool noAA = false, bool allowCustomUV = false);
|
||||
|
||||
void renderSplash(cairo_t *const, cairo_surface_t *const);
|
||||
void renderTextureInternalWithDamage(const CTexture&, wlr_box* pBox, float a, pixman_region32_t* damage, int round = 0, bool discardOpaque = false, bool noAA = false, bool allowCustomUV = false, bool allowDim = false);
|
||||
void renderSplash(cairo_t *const, cairo_surface_t *const, double);
|
||||
|
||||
void preBlurForCurrentMonitor();
|
||||
};
|
||||
|
@@ -15,13 +15,8 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
|
||||
if (RDATA->surface && surface == RDATA->surface)
|
||||
windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, RDATA->w, RDATA->h};
|
||||
else // here we clamp to 2, these might be some tiny specks
|
||||
windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, std::clamp(surface->current.width, 2, 1337420), std::clamp(surface->current.height, 2, 1337420)};
|
||||
windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, std::max(surface->current.width, 2), std::max(surface->current.height, 2)};
|
||||
|
||||
// squish all oversized but dont in some cases, jesus christ this is a mess
|
||||
// TODO: this shouldn't be done this way. Custom UV here as well.
|
||||
// this is fucking horrible
|
||||
// Issue: will cause oversized apps with reserved area to overflow from the window box. (see chromium on ozone wayland)
|
||||
const auto PRESQUISHSIZE = Vector2D(windowBox.width, windowBox.height);
|
||||
if (RDATA->squishOversized) {
|
||||
if (x + windowBox.width > RDATA->w)
|
||||
windowBox.width = RDATA->w - x;
|
||||
@@ -29,6 +24,9 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
|
||||
windowBox.height = RDATA->h - y;
|
||||
}
|
||||
|
||||
if (RDATA->pWindow)
|
||||
g_pHyprRenderer->calculateUVForWindowSurface(RDATA->pWindow, surface, RDATA->squishOversized);
|
||||
|
||||
scaleBox(&windowBox, RDATA->output->scale);
|
||||
|
||||
static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
|
||||
@@ -36,6 +34,8 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
|
||||
float rounding = RDATA->dontRound ? 0 : RDATA->rounding == -1 ? *PROUNDING : RDATA->rounding;
|
||||
rounding *= RDATA->output->scale;
|
||||
|
||||
rounding -= 1; // to fix a border issue
|
||||
|
||||
if (RDATA->surface && surface == RDATA->surface) {
|
||||
if (wlr_surface_is_xwayland_surface(surface) && !wlr_xwayland_surface_from_wlr_surface(surface)->has_alpha && RDATA->fadeAlpha * RDATA->alpha == 255.f) {
|
||||
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true);
|
||||
@@ -47,26 +47,16 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (RDATA->surface && wlr_surface_is_xdg_surface(RDATA->surface)) {
|
||||
wlr_box geo;
|
||||
wlr_xdg_surface_get_geometry(wlr_xdg_surface_from_wlr_surface(RDATA->surface), &geo);
|
||||
|
||||
// TODO: continuation of the above madness.
|
||||
if (geo.x != 0 || geo.y != 0) {
|
||||
windowBox.width = PRESQUISHSIZE.x;
|
||||
windowBox.height = PRESQUISHSIZE.y;
|
||||
}
|
||||
|
||||
windowBox.x -= geo.x;
|
||||
windowBox.y -= geo.y;
|
||||
}
|
||||
|
||||
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, false);
|
||||
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);
|
||||
|
||||
// reset the UV, we might've set it above
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
|
||||
}
|
||||
|
||||
bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow, CMonitor* pMonitor) {
|
||||
@@ -75,11 +65,14 @@ bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow, CMonitor* pMonitor) {
|
||||
if (!wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, &geometry))
|
||||
return false;
|
||||
|
||||
if (pWindow->m_bPinned)
|
||||
return true;
|
||||
|
||||
// now check if it has the same workspace
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
|
||||
|
||||
if (PWORKSPACE && PWORKSPACE->m_iMonitorID == pMonitor->ID) {
|
||||
if (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated()) {
|
||||
if (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated() || PWORKSPACE->m_bForceRendering) {
|
||||
return true;
|
||||
} else {
|
||||
if (!(!PWORKSPACE->m_bHasFullscreenWindow || pWindow->m_bIsFullscreen || (pWindow->m_bIsFloating && pWindow->m_bCreatedOverFullscreen)))
|
||||
@@ -109,6 +102,9 @@ bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow) {
|
||||
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
|
||||
|
||||
if (pWindow->m_bPinned || PWORKSPACE->m_bForceRendering)
|
||||
return true;
|
||||
|
||||
if (g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID))
|
||||
return true;
|
||||
|
||||
@@ -126,11 +122,39 @@ bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow) {
|
||||
void CHyprRenderer::renderWorkspaceWithFullscreenWindow(CMonitor* pMonitor, CWorkspace* pWorkspace, timespec* time) {
|
||||
CWindow* pWorkspaceWindow = nullptr;
|
||||
|
||||
// loop over the tiled windows that are fading out
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_iWorkspaceID != pMonitor->activeWorkspace)
|
||||
continue;
|
||||
|
||||
if (w->m_fAlpha.fl() == 0.f)
|
||||
continue;
|
||||
|
||||
if (w->m_bIsFullscreen || w->m_bIsFloating)
|
||||
continue;
|
||||
|
||||
renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_ALL);
|
||||
}
|
||||
|
||||
// and floating ones too
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_iWorkspaceID != pMonitor->activeWorkspace)
|
||||
continue;
|
||||
|
||||
if (w->m_fAlpha.fl() == 0.f)
|
||||
continue;
|
||||
|
||||
if (w->m_bIsFullscreen || !w->m_bIsFloating)
|
||||
continue;
|
||||
|
||||
renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_ALL);
|
||||
}
|
||||
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID);
|
||||
|
||||
if (w->m_iWorkspaceID != pWorkspace->m_iID || !w->m_bIsFullscreen){
|
||||
if (!(PWORKSPACE && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated())))
|
||||
if (!(PWORKSPACE && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated() || PWORKSPACE->m_bForceRendering)))
|
||||
continue;
|
||||
|
||||
if (w->m_iMonitorID != pMonitor->ID)
|
||||
@@ -145,9 +169,9 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(CMonitor* pMonitor, CWor
|
||||
pWorkspaceWindow = w.get();
|
||||
}
|
||||
|
||||
// then render windows over fullscreen
|
||||
// then render windows over fullscreen.
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_iWorkspaceID != pWorkspaceWindow->m_iWorkspaceID || !w->m_bCreatedOverFullscreen || !w->m_bIsMapped)
|
||||
if (w->m_iWorkspaceID != pWorkspaceWindow->m_iWorkspaceID || (!w->m_bCreatedOverFullscreen && !w->m_bPinned) || !w->m_bIsMapped)
|
||||
continue;
|
||||
|
||||
renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_ALL);
|
||||
@@ -169,12 +193,11 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(CMonitor* pMonitor, CWor
|
||||
}
|
||||
|
||||
// and the overlay layers
|
||||
if (pWorkspace->m_efFullscreenMode != FULLSCREEN_FULL) {
|
||||
// on non-full we draw the bar and shit
|
||||
for (auto& ls : pMonitor->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
|
||||
if (ls->alpha.fl() != 0.f)
|
||||
renderLayer(ls.get(), pMonitor, time);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (auto& ls : pMonitor->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) {
|
||||
renderLayer(ls.get(), pMonitor, time);
|
||||
@@ -198,19 +221,20 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
|
||||
}
|
||||
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
|
||||
const auto REALPOS = pWindow->m_vRealPosition.vec() + PWORKSPACE->m_vRenderOffset.vec();
|
||||
const auto REALPOS = pWindow->m_vRealPosition.vec() + (pWindow->m_bPinned ? Vector2D{} : PWORKSPACE->m_vRenderOffset.vec());
|
||||
static const auto PNOFLOATINGBORDERS = &g_pConfigManager->getConfigValuePtr("general:no_border_on_floating")->intValue;
|
||||
|
||||
SRenderData renderdata = {pMonitor->output, time, REALPOS.x, REALPOS.y};
|
||||
renderdata.surface = g_pXWaylandManager->getWindowSurface(pWindow);
|
||||
renderdata.w = std::clamp(pWindow->m_vRealSize.vec().x, (double)5, (double)1337420); // clamp the size to min 5,
|
||||
renderdata.h = std::clamp(pWindow->m_vRealSize.vec().y, (double)5, (double)1337420); // otherwise we'll have issues later with invalid boxes
|
||||
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
|
||||
renderdata.dontRound = (pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) || (!pWindow->m_sSpecialRenderData.rounding);
|
||||
renderdata.fadeAlpha = pWindow->m_fAlpha.fl() * (PWORKSPACE->m_fAlpha.fl() / 255.f);
|
||||
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.pWindow = pWindow;
|
||||
|
||||
// apply window special data
|
||||
if (pWindow->m_sSpecialRenderData.alphaInactive == -1)
|
||||
@@ -230,38 +254,6 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
|
||||
if (!pWindow->m_bIsFullscreen || PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL) for (auto& wd : pWindow->m_dWindowDecorations)
|
||||
wd->draw(pMonitor, renderdata.alpha * renderdata.fadeAlpha / 255.f);
|
||||
|
||||
if (!pWindow->m_bIsX11) {
|
||||
wlr_box geom;
|
||||
wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, &geom);
|
||||
|
||||
// first, check for poorly sized windows.
|
||||
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D((double)geom.x / (double)pWindow->m_uSurface.xdg->surface->current.width, (double)geom.y / (double)pWindow->m_uSurface.xdg->surface->current.height);
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D((double)(geom.width + geom.x) / (double)pWindow->m_uSurface.xdg->surface->current.width, (double)(geom.y + geom.height) / (double)pWindow->m_uSurface.xdg->surface->current.height);
|
||||
|
||||
if (g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft == Vector2D() && g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight == Vector2D(1, 1)) {
|
||||
// No special UV mods needed
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
|
||||
}
|
||||
|
||||
// then, if the surface is too big, modify the pos UV
|
||||
if (geom.width > renderdata.w + 1 || geom.height > renderdata.h + 1) {
|
||||
const auto OFF = Vector2D(renderdata.w / (double)geom.width, renderdata.h / (double)geom.height);
|
||||
|
||||
if (g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft == Vector2D(-1, -1))
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(0, 0);
|
||||
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.x * ((double)renderdata.w / ((double)geom.width / g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.x)),
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.y * ((double)renderdata.h / ((double)geom.height / g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.y))
|
||||
);
|
||||
}
|
||||
} else {
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
|
||||
}
|
||||
|
||||
wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(pWindow), renderSurface, &renderdata);
|
||||
|
||||
if (renderdata.decorate && pWindow->m_sSpecialRenderData.border) {
|
||||
@@ -279,14 +271,17 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
|
||||
|
||||
g_pHyprOpenGL->renderBorder(&windowBox, col, rounding);
|
||||
}
|
||||
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
|
||||
}
|
||||
|
||||
if (mode == RENDER_PASS_ALL || mode == RENDER_PASS_POPUP) {
|
||||
if (!pWindow->m_bIsX11) {
|
||||
renderdata.dontRound = false; // restore dontround
|
||||
wlr_box geom;
|
||||
wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, &geom);
|
||||
|
||||
renderdata.x -= geom.x;
|
||||
renderdata.y -= geom.y;
|
||||
|
||||
renderdata.dontRound = true; // don't round popups
|
||||
renderdata.pMonitor = pMonitor;
|
||||
renderdata.squishOversized = false; // don't squish popups
|
||||
wlr_xdg_surface_for_each_popup_surface(pWindow->m_uSurface.xdg, renderSurface, &renderdata);
|
||||
@@ -312,6 +307,7 @@ void CHyprRenderer::renderLayer(SLayerSurface* pLayer, CMonitor* pMonitor, times
|
||||
wlr_surface_for_each_surface(pLayer->layerSurface->surface, renderSurface, &renderdata);
|
||||
|
||||
renderdata.squishOversized = false; // don't squish popups
|
||||
renderdata.dontRound = true;
|
||||
wlr_layer_surface_v1_for_each_popup_surface(pLayer->layerSurface, renderSurface, &renderdata);
|
||||
}
|
||||
|
||||
@@ -439,6 +435,72 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
|
||||
renderDragIcon(PMONITOR, time);
|
||||
}
|
||||
|
||||
void CHyprRenderer::calculateUVForWindowSurface(CWindow* pWindow, wlr_surface* pSurface, bool main) {
|
||||
if (!pWindow->m_bIsX11) {
|
||||
Vector2D uvTL;
|
||||
Vector2D uvBR = Vector2D(1, 1);
|
||||
|
||||
wlr_box geom;
|
||||
wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, &geom);
|
||||
|
||||
const auto SUBSURFACE = g_pXWaylandManager->getWindowSurface(pWindow) != pSurface && main;
|
||||
|
||||
// wp_viewporter_v1 implementation
|
||||
if (pSurface->current.viewport.has_src) {
|
||||
wlr_fbox bufferSource;
|
||||
wlr_surface_get_buffer_source_box(pSurface, &bufferSource);
|
||||
|
||||
Vector2D surfaceSize = Vector2D(pSurface->buffer->texture->width, pSurface->buffer->texture->height);
|
||||
|
||||
uvTL = Vector2D(bufferSource.x / surfaceSize.x, bufferSource.y / surfaceSize.y);
|
||||
uvBR = Vector2D((bufferSource.x + bufferSource.width) / surfaceSize.x, (bufferSource.y + bufferSource.height) / surfaceSize.y);
|
||||
|
||||
if (uvBR.x < 0.01f || uvBR.y < 0.01f) {
|
||||
uvTL = Vector2D();
|
||||
uvBR = Vector2D(1,1);
|
||||
}
|
||||
|
||||
// TODO: (example: chromium) this still has a tiny "bump" at the end.
|
||||
if (main) {
|
||||
uvTL = uvTL + (Vector2D((double)geom.x / ((double)pWindow->m_uSurface.xdg->surface->current.width), (double)geom.y / ((double)pWindow->m_uSurface.xdg->surface->current.height)) * (((uvBR.x - uvTL.x) * surfaceSize.x) / surfaceSize.x));
|
||||
uvBR = uvBR * Vector2D((double)(geom.width + geom.x) / ((double)pWindow->m_uSurface.xdg->surface->current.width), (double)(geom.y + geom.height) / ((double)pWindow->m_uSurface.xdg->surface->current.height));
|
||||
}
|
||||
} else if (main) {
|
||||
// oversized windows' UV adjusting
|
||||
uvTL = Vector2D((double)geom.x / ((double)pWindow->m_uSurface.xdg->surface->current.width), (double)geom.y / ((double)pWindow->m_uSurface.xdg->surface->current.height));
|
||||
uvBR = Vector2D((double)(geom.width + geom.x) / ((double)pWindow->m_uSurface.xdg->surface->current.width), (double)(geom.y + geom.height) / ((double)pWindow->m_uSurface.xdg->surface->current.height));
|
||||
}
|
||||
|
||||
// set UV
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = uvTL;
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = uvBR;
|
||||
|
||||
if (g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft == Vector2D() && g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight == Vector2D(1, 1)) {
|
||||
// No special UV mods needed
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
|
||||
}
|
||||
|
||||
if (!main)
|
||||
return; // ignore the rest
|
||||
|
||||
// then, if the surface is too big, modify the pos UV
|
||||
if ((geom.width > pWindow->m_vRealSize.vec().x + 1 || geom.height > pWindow->m_vRealSize.vec().y + 1) && !SUBSURFACE) {
|
||||
const auto OFF = Vector2D(pWindow->m_vRealSize.vec().x / (double)geom.width, pWindow->m_vRealSize.vec().y / (double)geom.height);
|
||||
|
||||
if (g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft == Vector2D(-1, -1))
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(0, 0);
|
||||
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.x * (pWindow->m_vRealSize.vec().x / ((double)geom.width / g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.x)),
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.y * (pWindow->m_vRealSize.vec().y / ((double)geom.height / g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.y)));
|
||||
}
|
||||
} else {
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
|
||||
}
|
||||
}
|
||||
|
||||
void CHyprRenderer::outputMgrApplyTest(wlr_output_configuration_v1* config, bool test) {
|
||||
wlr_output_configuration_head_v1* head;
|
||||
bool noError = true;
|
||||
@@ -674,6 +736,8 @@ void CHyprRenderer::arrangeLayersForMonitor(const int& monitor) {
|
||||
if (PMONITOR->damage)
|
||||
damageMonitor(PMONITOR);
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitor);
|
||||
|
||||
Debug::log(LOG, "Monitor %s layers arranged: reserved: %f %f %f %f", PMONITOR->szName.c_str(), PMONITOR->vecReservedTopLeft.x, PMONITOR->vecReservedTopLeft.y, PMONITOR->vecReservedBottomRight.x, PMONITOR->vecReservedBottomRight.y);
|
||||
}
|
||||
|
||||
@@ -710,7 +774,7 @@ void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y) {
|
||||
wlr_region_scale(&damageBoxForEach, &damageBoxForEach, m->scale);
|
||||
pixman_region32_translate(&damageBoxForEach, lx + m->vecPosition.x, ly + m->vecPosition.y);
|
||||
|
||||
wlr_output_damage_add(m->damage, &damageBoxForEach);
|
||||
m->addDamage(&damageBoxForEach);
|
||||
}
|
||||
|
||||
pixman_region32_fini(&damageBoxForEach);
|
||||
@@ -731,21 +795,21 @@ void CHyprRenderer::damageWindow(CWindow* pWindow) {
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
wlr_box fixedDamageBox = {damageBox.x - m->vecPosition.x, damageBox.y - m->vecPosition.y, damageBox.width, damageBox.height};
|
||||
scaleBox(&fixedDamageBox, m->scale);
|
||||
wlr_output_damage_add_box(m->damage, &fixedDamageBox);
|
||||
m->addDamage(&fixedDamageBox);
|
||||
}
|
||||
|
||||
static auto* const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
|
||||
static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
|
||||
|
||||
if (*PLOGDAMAGE)
|
||||
Debug::log(LOG, "Damage: Window (%s): xy: %d, %d wh: %d, %d", pWindow->m_szTitle.c_str(), damageBox.x, damageBox.y, damageBox.width, damageBox.height);
|
||||
}
|
||||
|
||||
void CHyprRenderer::damageMonitor(CMonitor* pMonitor) {
|
||||
if (g_pCompositor->m_bUnsafeState)
|
||||
if (g_pCompositor->m_bUnsafeState || pMonitor->isMirror())
|
||||
return;
|
||||
|
||||
wlr_box damageBox = {0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y};
|
||||
wlr_output_damage_add_box(pMonitor->damage, &damageBox);
|
||||
pMonitor->addDamage(&damageBox);
|
||||
|
||||
static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
|
||||
|
||||
@@ -758,9 +822,12 @@ void CHyprRenderer::damageBox(wlr_box* pBox) {
|
||||
return;
|
||||
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
if (m->isMirror())
|
||||
continue; // don't damage mirrors traditionally
|
||||
|
||||
wlr_box damageBox = {pBox->x - m->vecPosition.x, pBox->y - m->vecPosition.y, pBox->width, pBox->height};
|
||||
scaleBox(&damageBox, m->scale);
|
||||
wlr_output_damage_add_box(m->damage, &damageBox);
|
||||
m->addDamage(&damageBox);
|
||||
}
|
||||
|
||||
static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
|
||||
@@ -781,6 +848,19 @@ void CHyprRenderer::damageRegion(pixman_region32_t* rg) {
|
||||
}
|
||||
}
|
||||
|
||||
void CHyprRenderer::damageMirrorsWith(CMonitor* pMonitor, pixman_region32_t* pRegion) {
|
||||
for (auto& mirror : pMonitor->mirrors) {
|
||||
Vector2D scale = {mirror->vecSize.x / pMonitor->vecSize.x, mirror->vecSize.y / pMonitor->vecSize.y};
|
||||
|
||||
pixman_region32_t rg;
|
||||
pixman_region32_init(&rg);
|
||||
pixman_region32_copy(&rg, pRegion);
|
||||
wlr_region_scale_xy(&rg, &rg, scale.x, scale.y);
|
||||
pMonitor->addDamage(&rg);
|
||||
pixman_region32_fini(&rg);
|
||||
}
|
||||
}
|
||||
|
||||
void CHyprRenderer::renderDragIcon(CMonitor* pMonitor, timespec* time) {
|
||||
if (!(g_pInputManager->m_sDrag.dragIcon && g_pInputManager->m_sDrag.iconMapped && g_pInputManager->m_sDrag.dragIcon->surface))
|
||||
return;
|
||||
@@ -844,7 +924,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
pMonitor->vecPosition = pMonitorRule->offset;
|
||||
|
||||
// loop over modes and choose an appropriate one.
|
||||
if (pMonitorRule->resolution != Vector2D()) {
|
||||
if (pMonitorRule->resolution != Vector2D() && pMonitorRule->resolution != Vector2D(-1,-1) && pMonitorRule->resolution != Vector2D(-1,-2)) {
|
||||
if (!wl_list_empty(&pMonitor->output->modes)) {
|
||||
wlr_output_mode* mode;
|
||||
bool found = false;
|
||||
@@ -877,6 +957,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
if (!found) {
|
||||
wlr_output_set_custom_mode(pMonitor->output, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (int)pMonitorRule->refreshRate * 1000);
|
||||
pMonitor->vecSize = pMonitorRule->resolution;
|
||||
pMonitor->refreshRate = pMonitorRule->refreshRate;
|
||||
|
||||
if (!wlr_output_test(pMonitor->output)) {
|
||||
Debug::log(ERR, "Custom resolution FAILED, falling back to preferred");
|
||||
@@ -905,8 +986,95 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
} else {
|
||||
wlr_output_set_custom_mode(pMonitor->output, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (int)pMonitorRule->refreshRate * 1000);
|
||||
pMonitor->vecSize = pMonitorRule->resolution;
|
||||
pMonitor->refreshRate = pMonitorRule->refreshRate;
|
||||
|
||||
Debug::log(LOG, "Setting custom mode for %s", pMonitor->output->name);
|
||||
if (!wlr_output_test(pMonitor->output)) {
|
||||
Debug::log(ERR, "Custom resolution FAILED, falling back to preferred");
|
||||
|
||||
const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output);
|
||||
|
||||
if (!PREFERREDMODE) {
|
||||
Debug::log(ERR, "Monitor %s has NO PREFERRED MODE, and an INVALID one was requested: %ix%i@%2f", (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Preferred is valid
|
||||
wlr_output_set_mode(pMonitor->output, PREFERREDMODE);
|
||||
|
||||
Debug::log(ERR, "Monitor %s got an invalid requested mode: %ix%i@%2f, using the preferred one instead: %ix%i@%2f", pMonitor->output->name, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f);
|
||||
|
||||
pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f;
|
||||
pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height);
|
||||
} else {
|
||||
Debug::log(LOG, "Set a custom mode %ix%i@%2f (mode not found in monitor modes)", (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate);
|
||||
}
|
||||
}
|
||||
} else if (pMonitorRule->resolution != Vector2D()) {
|
||||
if (!wl_list_empty(&pMonitor->output->modes)) {
|
||||
wlr_output_mode* mode;
|
||||
float currentWidth = 0;
|
||||
float currentHeight = 0;
|
||||
float currentRefresh = 0;
|
||||
bool success = false;
|
||||
|
||||
//(-1,-1) indicates a preference to refreshrate over resolution, (-1,-2) preference to resolution
|
||||
if(pMonitorRule->resolution == Vector2D(-1,-1)) {
|
||||
wl_list_for_each(mode, &pMonitor->output->modes, link) {
|
||||
if( ( mode->width >= currentWidth && mode->height >= currentHeight && mode->refresh >= ( currentRefresh - 1000.f ) ) || mode->refresh > ( currentRefresh + 3000.f ) ) {
|
||||
wlr_output_set_mode(pMonitor->output, mode);
|
||||
if (wlr_output_test(pMonitor->output)) {
|
||||
currentWidth = mode->width;
|
||||
currentHeight = mode->height;
|
||||
currentRefresh = mode->refresh;
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
wl_list_for_each(mode, &pMonitor->output->modes, link) {
|
||||
if( ( mode->width >= currentWidth && mode->height >= currentHeight && mode->refresh >= ( currentRefresh - 1000.f ) ) || ( mode->width > currentWidth && mode->height > currentHeight ) ) {
|
||||
wlr_output_set_mode(pMonitor->output, mode);
|
||||
if (wlr_output_test(pMonitor->output)) {
|
||||
currentWidth = mode->width;
|
||||
currentHeight = mode->height;
|
||||
currentRefresh = mode->refresh;
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
Debug::log(LOG, "Monitor %s: REJECTED mode: %ix%i@%2f! Falling back to preferred.",
|
||||
pMonitor->output->name, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate,
|
||||
mode->width, mode->height, mode->refresh / 1000.f);
|
||||
|
||||
const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output);
|
||||
|
||||
if (!PREFERREDMODE) {
|
||||
Debug::log(ERR, "Monitor %s has NO PREFERRED MODE, and an INVALID one was requested: %ix%i@%2f",
|
||||
(int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Preferred is valid
|
||||
wlr_output_set_mode(pMonitor->output, PREFERREDMODE);
|
||||
|
||||
Debug::log(ERR, "Monitor %s got an invalid requested mode: %ix%i@%2f, using the preferred one instead: %ix%i@%2f",
|
||||
pMonitor->output->name, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate,
|
||||
PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f);
|
||||
|
||||
pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f;
|
||||
pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height);
|
||||
} else {
|
||||
|
||||
Debug::log(LOG, "Monitor %s: Applying highest mode %ix%i@%2f.",
|
||||
pMonitor->output->name, (int)currentWidth, (int)currentHeight, (int)currentRefresh / 1000.f,
|
||||
mode->width, mode->height, mode->refresh / 1000.f);
|
||||
|
||||
pMonitor->refreshRate = currentRefresh / 1000.f;
|
||||
pMonitor->vecSize = Vector2D(currentWidth, currentHeight);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output);
|
||||
@@ -955,6 +1123,14 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
|
||||
pMonitor->vecPixelSize = pMonitor->vecSize;
|
||||
|
||||
// Adaptive sync (VRR)
|
||||
wlr_output_enable_adaptive_sync(pMonitor->output, 1);
|
||||
|
||||
if (!wlr_output_test(pMonitor->output)) {
|
||||
Debug::log(LOG, "Pending output %s does not accept VRR.", pMonitor->output->name);
|
||||
wlr_output_enable_adaptive_sync(pMonitor->output, 0);
|
||||
}
|
||||
|
||||
// update renderer
|
||||
g_pHyprOpenGL->destroyMonitorResources(pMonitor);
|
||||
|
||||
@@ -984,6 +1160,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
pMonitor->vecPosition = finalPos;
|
||||
}
|
||||
|
||||
if (!pMonitor->isMirror())
|
||||
wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, pMonitor->output, (int)pMonitor->vecPosition.x, (int)pMonitor->vecPosition.y);
|
||||
|
||||
wlr_output_enable(pMonitor->output, true);
|
||||
@@ -997,6 +1174,9 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
// frame skip
|
||||
pMonitor->framesToSkip = 1;
|
||||
|
||||
// reload to fix mirrors
|
||||
g_pConfigManager->m_bWantsMonitorReload = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -35,11 +35,13 @@ public:
|
||||
void damageBox(const int& x, const int& y, const int& w, const int& h);
|
||||
void damageRegion(pixman_region32_t*);
|
||||
void damageMonitor(CMonitor*);
|
||||
void damageMirrorsWith(CMonitor*, pixman_region32_t*);
|
||||
bool applyMonitorRule(CMonitor*, SMonitorRule*, bool force = false);
|
||||
bool shouldRenderWindow(CWindow*, CMonitor*);
|
||||
bool shouldRenderWindow(CWindow*);
|
||||
void ensureCursorRenderingMode();
|
||||
bool shouldRenderCursor();
|
||||
void calculateUVForWindowSurface(CWindow*, wlr_surface*, bool main = false);
|
||||
|
||||
bool m_bWindowRequestedCursorHide = false;
|
||||
|
||||
|
@@ -14,7 +14,7 @@ GLint CShader::getUniformLocation(const std::string& unif) {
|
||||
|
||||
CShader::~CShader() {
|
||||
// destroy shader
|
||||
if (program != 0) {
|
||||
if (program) {
|
||||
glDeleteProgram(program);
|
||||
}
|
||||
}
|
@@ -29,6 +29,9 @@ public:
|
||||
GLint range;
|
||||
GLint shadowPower;
|
||||
|
||||
GLint applyTint;
|
||||
GLint tint;
|
||||
|
||||
GLint getUniformLocation(const std::string&);
|
||||
|
||||
private:
|
||||
|
@@ -38,7 +38,7 @@ void CHyprDropShadowDecoration::updateWindow(CWindow* pWindow) {
|
||||
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
|
||||
|
||||
const auto WORKSPACEOFFSET = PWORKSPACE ? PWORKSPACE->m_vRenderOffset.vec() : Vector2D();
|
||||
const auto WORKSPACEOFFSET = PWORKSPACE && !pWindow->m_bPinned ? PWORKSPACE->m_vRenderOffset.vec() : Vector2D();
|
||||
|
||||
if (pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET != m_vLastWindowPos || pWindow->m_vRealSize.vec() != m_vLastWindowSize) {
|
||||
m_vLastWindowPos = pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET;
|
||||
@@ -56,34 +56,22 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a) {
|
||||
if (m_pWindow->m_cRealShadowColor.col() == CColor(0, 0, 0, 0))
|
||||
return; // don't draw invisible shadows
|
||||
|
||||
if (!m_pWindow->m_sSpecialRenderData.decorate)
|
||||
return;
|
||||
|
||||
static auto *const PSHADOWS = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue;
|
||||
static auto *const PSHADOWSIZE = &g_pConfigManager->getConfigValuePtr("decoration:shadow_range")->intValue;
|
||||
static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
|
||||
static auto *const PSHADOWIGNOREWINDOW = &g_pConfigManager->getConfigValuePtr("decoration:shadow_ignore_window")->intValue;
|
||||
static auto *const PSHADOWOFFSET = &g_pConfigManager->getConfigValuePtr("decoration:shadow_offset")->strValue;
|
||||
static auto *const PSHADOWOFFSET = &g_pConfigManager->getConfigValuePtr("decoration:shadow_offset")->vecValue;
|
||||
|
||||
if (*PSHADOWS != 1)
|
||||
return; // disabled
|
||||
|
||||
// get the real offset
|
||||
Vector2D offset;
|
||||
try {
|
||||
if (const auto SPACEPOS = PSHADOWOFFSET->find(' '); SPACEPOS != std::string::npos) {
|
||||
const auto X = PSHADOWOFFSET->substr(0, SPACEPOS);
|
||||
const auto Y = PSHADOWOFFSET->substr(SPACEPOS + 1);
|
||||
|
||||
if (isNumber(X, true) && isNumber(Y, true)) {
|
||||
offset = Vector2D(std::stof(X), std::stof(Y));
|
||||
}
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
return; // cannot parse
|
||||
}
|
||||
|
||||
const auto ROUNDING = !m_pWindow->m_sSpecialRenderData.rounding ? 0 : (m_pWindow->m_sAdditionalConfigData.rounding == -1 ? *PROUNDING : m_pWindow->m_sAdditionalConfigData.rounding);
|
||||
|
||||
// update the extents
|
||||
m_seExtents = {{*PSHADOWSIZE + 2 - offset.x, *PSHADOWSIZE + 2 - offset.y}, {*PSHADOWSIZE + 2 + offset.x, *PSHADOWSIZE + 2 + offset.y}};
|
||||
m_seExtents = {{*PSHADOWSIZE + 2 - PSHADOWOFFSET->x, *PSHADOWSIZE + 2 - PSHADOWOFFSET->y}, {*PSHADOWSIZE + 2 + PSHADOWOFFSET->x, *PSHADOWSIZE + 2 + PSHADOWOFFSET->y}};
|
||||
|
||||
// draw the shadow
|
||||
wlr_box fullBox = {m_vLastWindowPos.x - m_seExtents.topLeft.x + 2, m_vLastWindowPos.y - m_seExtents.topLeft.y + 2, m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x - 4, m_vLastWindowSize.y + m_seExtents.topLeft.y + m_seExtents.bottomRight.y - 4};
|
||||
|
@@ -3,7 +3,6 @@
|
||||
|
||||
CHyprGroupBarDecoration::CHyprGroupBarDecoration(CWindow* pWindow) {
|
||||
m_pWindow = pWindow;
|
||||
updateWindow(pWindow);
|
||||
}
|
||||
|
||||
CHyprGroupBarDecoration::~CHyprGroupBarDecoration() {
|
||||
@@ -23,13 +22,13 @@ void CHyprGroupBarDecoration::updateWindow(CWindow* pWindow) {
|
||||
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
|
||||
|
||||
const auto WORKSPACEOFFSET = PWORKSPACE ? PWORKSPACE->m_vRenderOffset.vec() : Vector2D();
|
||||
const auto WORKSPACEOFFSET = PWORKSPACE && !pWindow->m_bPinned ? PWORKSPACE->m_vRenderOffset.vec() : Vector2D();
|
||||
|
||||
if (pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET != m_vLastWindowPos || pWindow->m_vRealSize.vec() != m_vLastWindowSize) {
|
||||
// we draw 3px above the window's border with 3px
|
||||
const auto BORDERSIZE = g_pConfigManager->getInt("general:border_size");
|
||||
const auto PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
|
||||
|
||||
m_seExtents.topLeft = Vector2D(0, BORDERSIZE + 3 + 3);
|
||||
m_seExtents.topLeft = Vector2D(0, *PBORDERSIZE + 3 + 3);
|
||||
m_seExtents.bottomRight = Vector2D();
|
||||
|
||||
m_vLastWindowPos = pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET;
|
||||
@@ -46,7 +45,7 @@ void CHyprGroupBarDecoration::updateWindow(CWindow* pWindow) {
|
||||
|
||||
// get the group info
|
||||
SLayoutMessageHeader header;
|
||||
header.pWindow = g_pCompositor->m_pLastWindow;
|
||||
header.pWindow = m_pWindow;
|
||||
|
||||
m_dwGroupMembers = std::any_cast<std::deque<CWindow*>>(g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "groupinfo"));
|
||||
|
||||
@@ -71,6 +70,9 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) {
|
||||
if (barsToDraw < 1 || m_pWindow->m_bHidden || !g_pCompositor->windowValidMapped(m_pWindow))
|
||||
return;
|
||||
|
||||
if (!m_pWindow->m_sSpecialRenderData.decorate)
|
||||
return;
|
||||
|
||||
const int PAD = 2; //2px
|
||||
|
||||
const int BARW = (m_vLastWindowSize.x - PAD * (barsToDraw - 1)) / barsToDraw;
|
||||
@@ -83,7 +85,12 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) {
|
||||
if (rect.width <= 0 || rect.height <= 0)
|
||||
break;
|
||||
|
||||
CColor color = m_dwGroupMembers[i] == g_pCompositor->m_pLastWindow ? CColor(g_pConfigManager->getInt("dwindle:col.group_border_active")) : CColor(g_pConfigManager->getInt("dwindle:col.group_border"));
|
||||
scaleBox(&rect, pMonitor->scale);
|
||||
|
||||
static auto *const PGROUPCOLACTIVE = &g_pConfigManager->getConfigValuePtr("dwindle:col.group_border_active")->intValue;
|
||||
static auto *const PGROUPCOLINACTIVE = &g_pConfigManager->getConfigValuePtr("dwindle:col.group_border")->intValue;
|
||||
|
||||
CColor color = m_dwGroupMembers[i] == g_pCompositor->m_pLastWindow ? CColor(*PGROUPCOLACTIVE) : CColor(*PGROUPCOLINACTIVE);
|
||||
color.a *= a;
|
||||
g_pHyprOpenGL->renderRect(&rect, color);
|
||||
|
||||
|
@@ -4,139 +4,37 @@
|
||||
|
||||
inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVarName) -> std::string {
|
||||
return R"#(
|
||||
if (pixCoord[0] < topLeft[0]) {
|
||||
// we're close left
|
||||
if (pixCoord[1] < topLeft[1]) {
|
||||
// top
|
||||
|
||||
if (ignoreCorners == 1) {
|
||||
// branchless baby!
|
||||
highp vec2 pixCoord = vec2(gl_FragCoord);
|
||||
pixCoord -= topLeft + fullSize * 0.5;
|
||||
pixCoord *= vec2(lessThan(pixCoord, vec2(0.0))) * -2.0 + 1.0;
|
||||
pixCoord -= fullSize * 0.5 - radius;
|
||||
|
||||
if (pixCoord.x + pixCoord.y > radius) {
|
||||
|
||||
float dist = length(pixCoord);
|
||||
|
||||
if (dist > radius)
|
||||
discard;
|
||||
return;
|
||||
}
|
||||
|
||||
float topLeftDistance = distance(topLeft, pixCoord);
|
||||
|
||||
if (topLeftDistance > radius - 1.0) {
|
||||
if (primitiveMultisample == 0 && topLeftDistance > radius) {
|
||||
discard;
|
||||
return;
|
||||
} else if (primitiveMultisample == 1) {
|
||||
if (primitiveMultisample == 1 && dist > radius - 1.0) {
|
||||
float distances = 0.0;
|
||||
if (distance(topLeft, pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; }
|
||||
if (distance(topLeft, pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; }
|
||||
if (distance(topLeft, pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; }
|
||||
if (distance(topLeft, pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.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) {
|
||||
if (distances == 0.0)
|
||||
discard;
|
||||
return;
|
||||
}
|
||||
|
||||
distances = distances / 4.0;
|
||||
distances /= 4.0;
|
||||
|
||||
)#" + colorVarName + R"#( = )#" + colorVarName + R"#( * distances;
|
||||
}
|
||||
|
||||
}
|
||||
} else if (pixCoord[1] > bottomRight[1]) {
|
||||
// bottom
|
||||
|
||||
if (ignoreCorners == 1) {
|
||||
discard;
|
||||
return;
|
||||
}
|
||||
|
||||
float topLeftDistance = distance(vec2(topLeft[0], bottomRight[1]), pixCoord);
|
||||
|
||||
if (topLeftDistance > radius - 1.0) {
|
||||
if (primitiveMultisample == 0 && topLeftDistance > radius) {
|
||||
discard;
|
||||
return;
|
||||
} else if (primitiveMultisample == 1) {
|
||||
float distances = 0.0;
|
||||
if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; }
|
||||
if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; }
|
||||
if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; }
|
||||
if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; }
|
||||
|
||||
if (distances == 0.0) {
|
||||
discard;
|
||||
return;
|
||||
}
|
||||
|
||||
distances = distances / 4.0;
|
||||
|
||||
)#" + colorVarName + R"#( = )#" + colorVarName + R"#( * distances;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pixCoord[0] > bottomRight[0]) {
|
||||
// we're close right
|
||||
if (pixCoord[1] < topLeft[1]) {
|
||||
// top
|
||||
|
||||
if (ignoreCorners == 1) {
|
||||
discard;
|
||||
return;
|
||||
}
|
||||
|
||||
float topLeftDistance = distance(vec2(bottomRight[0], topLeft[1]), pixCoord);
|
||||
|
||||
if (topLeftDistance > radius - 1.0) {
|
||||
if (primitiveMultisample == 0 && topLeftDistance > radius) {
|
||||
discard;
|
||||
return;
|
||||
} else if (primitiveMultisample == 1) {
|
||||
float distances = 0.0;
|
||||
if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; }
|
||||
if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; }
|
||||
if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; }
|
||||
if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; }
|
||||
|
||||
if (distances == 0.0) {
|
||||
discard;
|
||||
return;
|
||||
}
|
||||
|
||||
distances = distances / 4.0;
|
||||
|
||||
)#" + colorVarName + R"#( = )#" + colorVarName + R"#( * distances;
|
||||
}
|
||||
}
|
||||
} else if (pixCoord[1] > bottomRight[1]) {
|
||||
// bottom
|
||||
|
||||
if (ignoreCorners == 1) {
|
||||
discard;
|
||||
return;
|
||||
}
|
||||
|
||||
float topLeftDistance = distance(bottomRight, pixCoord);
|
||||
|
||||
if (topLeftDistance > radius - 1.0) {
|
||||
if (primitiveMultisample == 0 && topLeftDistance > radius) {
|
||||
discard;
|
||||
return;
|
||||
} else if (primitiveMultisample == 1) {
|
||||
float distances = 0.0;
|
||||
if (distance(bottomRight, pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; }
|
||||
if (distance(bottomRight, pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; }
|
||||
if (distance(bottomRight, pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; }
|
||||
if (distance(bottomRight, pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; }
|
||||
|
||||
if (distances == 0.0) {
|
||||
discard;
|
||||
return;
|
||||
}
|
||||
|
||||
distances = distances / 4.0;
|
||||
|
||||
)#" + colorVarName + R"#( = )#" + colorVarName + R"#( * distances;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)#";
|
||||
)#";
|
||||
};
|
||||
|
||||
inline const std::string QUADVERTSRC = R"#(
|
||||
@@ -156,27 +54,20 @@ void main() {
|
||||
inline const std::string QUADFRAGSRC = R"#(
|
||||
precision mediump float;
|
||||
varying vec4 v_color;
|
||||
varying vec2 v_texcoord;
|
||||
|
||||
uniform vec2 topLeft;
|
||||
uniform vec2 bottomRight;
|
||||
uniform vec2 fullSize;
|
||||
uniform float radius;
|
||||
|
||||
uniform int primitiveMultisample;
|
||||
uniform int ignoreCorners;
|
||||
|
||||
void main() {
|
||||
if (radius == 0.0) {
|
||||
gl_FragColor = v_color;
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 pixColor = v_color;
|
||||
|
||||
vec2 pixCoord = fullSize * v_texcoord;
|
||||
|
||||
if (radius > 0.0) {
|
||||
)#" + ROUNDED_SHADER_FUNC("pixColor") + R"#(
|
||||
}
|
||||
|
||||
gl_FragColor = pixColor;
|
||||
})#";
|
||||
@@ -199,28 +90,31 @@ uniform sampler2D tex;
|
||||
uniform float alpha;
|
||||
|
||||
uniform vec2 topLeft;
|
||||
uniform vec2 bottomRight;
|
||||
uniform vec2 fullSize;
|
||||
uniform float radius;
|
||||
|
||||
uniform int discardOpaque;
|
||||
|
||||
uniform int applyTint;
|
||||
uniform vec3 tint;
|
||||
|
||||
uniform int primitiveMultisample;
|
||||
uniform int ignoreCorners;
|
||||
|
||||
void main() {
|
||||
|
||||
vec4 pixColor = texture2D(tex, v_texcoord);
|
||||
|
||||
if (discardOpaque == 1 && pixColor[3] * alpha == 1.0) {
|
||||
if (discardOpaque == 1 && pixColor[3] * alpha == 1.0)
|
||||
discard;
|
||||
return;
|
||||
|
||||
|
||||
if (applyTint == 1) {
|
||||
pixColor[0] = pixColor[0] * tint[0];
|
||||
pixColor[1] = pixColor[1] * tint[1];
|
||||
pixColor[2] = pixColor[2] * tint[2];
|
||||
}
|
||||
|
||||
vec2 pixCoord = fullSize * v_texcoord;
|
||||
|
||||
)#" + ROUNDED_SHADER_FUNC("pixColor") +
|
||||
R"#(
|
||||
)#" + ROUNDED_SHADER_FUNC("pixColor") + R"#(
|
||||
|
||||
gl_FragColor = pixColor * alpha;
|
||||
})#";
|
||||
@@ -232,25 +126,28 @@ uniform sampler2D tex;
|
||||
uniform float alpha;
|
||||
|
||||
uniform vec2 topLeft;
|
||||
uniform vec2 bottomRight;
|
||||
uniform vec2 fullSize;
|
||||
uniform float radius;
|
||||
|
||||
uniform int discardOpaque;
|
||||
|
||||
uniform int applyTint;
|
||||
uniform vec3 tint;
|
||||
|
||||
uniform int primitiveMultisample;
|
||||
uniform int ignoreCorners;
|
||||
|
||||
void main() {
|
||||
|
||||
if (discardOpaque == 1 && alpha == 1.0) {
|
||||
if (discardOpaque == 1 && alpha == 1.0)
|
||||
discard;
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 pixColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0);
|
||||
|
||||
vec2 pixCoord = fullSize * v_texcoord;
|
||||
if (applyTint == 1) {
|
||||
pixColor[0] = pixColor[0] * tint[0];
|
||||
pixColor[1] = pixColor[1] * tint[1];
|
||||
pixColor[2] = pixColor[2] * tint[2];
|
||||
}
|
||||
|
||||
)#" + ROUNDED_SHADER_FUNC("pixColor") + R"#(
|
||||
|
||||
@@ -274,6 +171,7 @@ void main() {
|
||||
sum += texture2D(tex, uv + halfpixel.xy * radius);
|
||||
sum += texture2D(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius);
|
||||
sum += texture2D(tex, uv - vec2(halfpixel.x, -halfpixel.y) * radius);
|
||||
|
||||
gl_FragColor = sum / 8.0;
|
||||
}
|
||||
)#";
|
||||
@@ -313,27 +211,31 @@ uniform samplerExternalOES texture0;
|
||||
uniform float alpha;
|
||||
|
||||
uniform vec2 topLeft;
|
||||
uniform vec2 bottomRight;
|
||||
uniform vec2 fullSize;
|
||||
uniform float radius;
|
||||
|
||||
uniform int discardOpaque;
|
||||
|
||||
uniform int applyTint;
|
||||
uniform vec3 tint;
|
||||
|
||||
uniform int primitiveMultisample;
|
||||
uniform int ignoreCorners;
|
||||
|
||||
void main() {
|
||||
|
||||
vec4 pixColor = texture2D(texture0, v_texcoord);
|
||||
|
||||
if (discardOpaque == 1 && pixColor[3] * alpha == 1.0) {
|
||||
if (discardOpaque == 1 && pixColor[3] * alpha == 1.0)
|
||||
discard;
|
||||
return;
|
||||
}
|
||||
|
||||
vec2 pixCoord = fullSize * v_texcoord;
|
||||
if (applyTint == 1) {
|
||||
pixColor[0] = pixColor[0] * tint[0];
|
||||
pixColor[1] = pixColor[1] * tint[1];
|
||||
pixColor[2] = pixColor[2] * tint[2];
|
||||
}
|
||||
|
||||
)#" + ROUNDED_SHADER_FUNC("pixColor") + R"#(
|
||||
|
||||
gl_FragColor = pixColor * alpha;
|
||||
})#";
|
||||
}
|
||||
)#";
|
||||
|
Submodule subprojects/wlroots updated: 7c575922c0...2ad25b1460
Reference in New Issue
Block a user