mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-08-15 12:03:48 -07:00
Compare commits
210 Commits
v0.17.0bet
...
v0.19.1bet
Author | SHA1 | Date | |
---|---|---|---|
|
e1d7a13333 | ||
|
bf5844d607 | ||
|
5b7fec481b | ||
|
73b3bbe49b | ||
|
d8dcf670da | ||
|
87b9313034 | ||
|
993c382e74 | ||
|
3c9a7811b8 | ||
|
6c8d993477 | ||
|
dfa9277867 | ||
|
50e37419e9 | ||
|
22978aa31e | ||
|
7ed401e5e0 | ||
|
da76a1ed9e | ||
|
9c67e08dbd | ||
|
6cf716f182 | ||
|
9fb24ac1e9 | ||
|
66fb083003 | ||
|
20b91f58f8 | ||
|
ac0e675f3b | ||
|
f71f04db9e | ||
|
9e4e98acfb | ||
|
826e35f7a4 | ||
|
ffc580dda9 | ||
|
4557d13a32 | ||
|
215c7bd3cb | ||
|
ea2ef63de5 | ||
|
d9998f2ca5 | ||
|
686d6fc6d1 | ||
|
9e8df888eb | ||
|
409ac12f23 | ||
|
6aa26582f6 | ||
|
056a45d035 | ||
|
fbc839e8d9 | ||
|
cb85eea261 | ||
|
439b827a08 | ||
|
d39d6cc1e3 | ||
|
d6b3bfc48e | ||
|
70d4fadc39 | ||
|
a2a12018d9 | ||
|
10d34ef818 | ||
|
bf52545a91 | ||
|
c012e3d66b | ||
|
39a4f82460 | ||
|
7b020ffa84 | ||
|
b8ccf3dc3a | ||
|
869f0a0238 | ||
|
ff4ea1a13a | ||
|
51aebb2845 | ||
|
212f599412 | ||
|
55776df685 | ||
|
3dd06b674a | ||
|
12df799572 | ||
|
c341792092 | ||
|
afe12dc90b | ||
|
45d2d1e97d | ||
|
0a302901d2 | ||
|
49063f949d | ||
|
7699d657d9 | ||
|
b2cb3b8bf2 | ||
|
6cbaad896c | ||
|
9247f88d0c | ||
|
92f2e342a3 | ||
|
e2f3f5fe63 | ||
|
0db75852f3 | ||
|
afe688e6ab | ||
|
493fc00953 | ||
|
c709dc5e8e | ||
|
684c59e5bc | ||
|
0948b078e1 | ||
|
52c0356900 | ||
|
1c9a0be8c4 | ||
|
f45ec24977 | ||
|
75b7e661e7 | ||
|
381d7a4300 | ||
|
0e6e8461eb | ||
|
141456dd89 | ||
|
9616dc7bd8 | ||
|
379597e78f | ||
|
f6067816fb | ||
|
750eb76df3 | ||
|
79a9bc9076 | ||
|
dcb6a0425c | ||
|
e15a9f3d7d | ||
|
b0f95c63c9 | ||
|
5327565b33 | ||
|
95047fb083 | ||
|
f00b2fd509 | ||
|
eb86e7967f | ||
|
88874fcfe2 | ||
|
d504c1e5ab | ||
|
c78db1212b | ||
|
be03a6186c | ||
|
41a8975bd1 | ||
|
254c3d166f | ||
|
137cf9e582 | ||
|
11e841580f | ||
|
f8b9138383 | ||
|
c03e4c36b0 | ||
|
5530cf6e79 | ||
|
1f72237291 | ||
|
e427d9f622 | ||
|
f88feec02b | ||
|
df132e5ff3 | ||
|
0ffaa8d667 | ||
|
e887149f25 | ||
|
250d61e0b3 | ||
|
ba05c43ae3 | ||
|
82fe530045 | ||
|
f91f3d1c81 | ||
|
5d39223239 | ||
|
d2a7e22efd | ||
|
724e411ffc | ||
|
c02bfc3897 | ||
|
878a20741b | ||
|
d5eafe1926 | ||
|
e2da4ff257 | ||
|
dbb6732743 | ||
|
4034aa2c60 | ||
|
fcb5037a1d | ||
|
0634abf168 | ||
|
478fa7cafe | ||
|
549fdf63f6 | ||
|
1a14841a75 | ||
|
a7ed3a5e47 | ||
|
884fc4f89c | ||
|
1e5cab1ee7 | ||
|
5a00f0c657 | ||
|
2cbb10d850 | ||
|
23cd1b8c66 | ||
|
be6f5ce831 | ||
|
78a545112a | ||
|
2cdabf581e | ||
|
34a7f17956 | ||
|
dd11434e90 | ||
|
61995e3b4e | ||
|
13befbd266 | ||
|
a5ffd44caf | ||
|
0208dff574 | ||
|
3157bebed7 | ||
|
c0bb4db15c | ||
|
27cada2a02 | ||
|
153c99217d | ||
|
851df11eb5 | ||
|
5f2c741f49 | ||
|
9a9ecc25db | ||
|
34b145ee65 | ||
|
f41fe59cb6 | ||
|
7ff1fd9d69 | ||
|
d0b3cdc835 | ||
|
1cf829c889 | ||
|
17992b633d | ||
|
c545ab4993 | ||
|
1d2e4243dc | ||
|
aefc34b405 | ||
|
2a20cf5379 | ||
|
e3a3837164 | ||
|
c86ab4694c | ||
|
5d5066570c | ||
|
1a55fb4170 | ||
|
efbc3f8194 | ||
|
f755351511 | ||
|
57817f7252 | ||
|
b4c45aa2e3 | ||
|
5295244026 | ||
|
082f439db2 | ||
|
12697d2b72 | ||
|
976b44443a | ||
|
6553fb5a40 | ||
|
bee06f3507 | ||
|
5a750b485a | ||
|
a71f44baa5 | ||
|
65db3a7bd3 | ||
|
22384869a6 | ||
|
ff76fbe763 | ||
|
cfbab453e8 | ||
|
6a59b57ef8 | ||
|
f50c786640 | ||
|
70aece8522 | ||
|
c9eb0f3aab | ||
|
206360177f | ||
|
34ad837fd9 | ||
|
e796157672 | ||
|
b51222c004 | ||
|
9aad352789 | ||
|
ce8c20c1ed | ||
|
349afa0e7a | ||
|
748a6965ca | ||
|
97af7c416e | ||
|
47512dd6db | ||
|
653b9ed0e4 | ||
|
d0e47d9fe0 | ||
|
f978368a4e | ||
|
c47581fc5a | ||
|
31aa357c17 | ||
|
6ddfae0a07 | ||
|
0d7176792b | ||
|
c1542da18a | ||
|
5b548f5bc3 | ||
|
5ac2005318 | ||
|
a2b8e3b34e | ||
|
d78b53968f | ||
|
61b950d942 | ||
|
a16073a87b | ||
|
603a90886f | ||
|
95bbac8791 | ||
|
a69fd21a1a | ||
|
b6e33830af | ||
|
2c67c1c4f8 | ||
|
989deafd5e |
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
@@ -41,7 +41,7 @@ jobs:
|
||||
cp ./LICENSE hyprland/
|
||||
cp build/Hyprland hyprland/
|
||||
cp hyprctl/hyprctl hyprland/
|
||||
cp subprojects/wlroots/build/libwlroots.so.11032 hyprland/
|
||||
cp subprojects/wlroots/build/libwlroots.so.12032 hyprland/
|
||||
cp build/Hyprland hyprland/
|
||||
cp -r example/ hyprland/
|
||||
cp -r assets/ hyprland/
|
||||
|
6
.github/workflows/nix-build.yaml
vendored
6
.github/workflows/nix-build.yaml
vendored
@@ -16,13 +16,13 @@ jobs:
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Install nix
|
||||
uses: cachix/install-nix-action@v17
|
||||
uses: cachix/install-nix-action@v18
|
||||
with:
|
||||
install_url: https://releases.nixos.org/nix/nix-2.10.3/install
|
||||
install_url: https://nixos.org/nix/install
|
||||
extra_nix_config: |
|
||||
auto-optimise-store = true
|
||||
experimental-features = nix-command flakes
|
||||
- uses: cachix/cachix-action@v10
|
||||
- uses: cachix/cachix-action@v12
|
||||
with:
|
||||
name: hyprland
|
||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||
|
4
.github/workflows/nix-update.yaml
vendored
4
.github/workflows/nix-update.yaml
vendored
@@ -9,9 +9,9 @@ jobs:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Install nix
|
||||
uses: cachix/install-nix-action@v17
|
||||
uses: cachix/install-nix-action@v18
|
||||
with:
|
||||
install_url: https://releases.nixos.org/nix/nix-2.8.0/install
|
||||
install_url: https://nixos.org/nix/install
|
||||
extra_nix_config: |
|
||||
auto-optimise-store = true
|
||||
experimental-features = nix-command flakes
|
||||
|
2
.github/workflows/release.yaml
vendored
2
.github/workflows/release.yaml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
|
||||
- name: Create tarball with submodules
|
||||
id: tar
|
||||
run: tar -czv --owner=0 --group=0 --no-same-owner --no-same-permissions -f source.tar.gz *
|
||||
run: mkdir hyprland-source; mv ./* ./hyprland-source || tar -czv --owner=0 --group=0 --no-same-owner --no-same-permissions -f source.tar.gz *
|
||||
|
||||
- id: whatrelease
|
||||
name: Get latest release
|
||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +1,6 @@
|
||||
[submodule "wlroots"]
|
||||
path = subprojects/wlroots
|
||||
url = https://gitlab.freedesktop.org/wlroots/wlroots.git
|
||||
[submodule "subprojects/hyprland-protocols"]
|
||||
path = subprojects/hyprland-protocols
|
||||
url = https://github.com/hyprwm/hyprland-protocols
|
||||
|
@@ -22,7 +22,7 @@ execute_process(
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
execute_process(
|
||||
COMMAND sh -c "git show ${GIT_COMMIT_HASH} | head -n 5 | tail -n 1"
|
||||
COMMAND sh -c "git show ${GIT_COMMIT_HASH} | head -n 5 | tail -n 1 | sed -s 's/#|\"//g'"
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GIT_COMMIT_MESSAGE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
@@ -45,7 +45,8 @@ ENDIF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||
|
||||
include_directories(. PRIVATE "subprojects/wlroots/include/")
|
||||
include_directories(. PRIVATE "subprojects/wlroots/build/include/")
|
||||
add_compile_options(-std=c++23 -DWLR_USE_UNSTABLE )
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
add_compile_options(-DWLR_USE_UNSTABLE)
|
||||
add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing)
|
||||
|
||||
message(STATUS "Checking deps...")
|
||||
@@ -89,13 +90,14 @@ message(STATUS "Setting link libraries")
|
||||
target_link_libraries(Hyprland PkgConfig::deps)
|
||||
|
||||
target_link_libraries(Hyprland
|
||||
${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.11032 # wlroots is provided by us
|
||||
${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.12032 # wlroots is provided by us
|
||||
pixman-1
|
||||
OpenGL
|
||||
GLESv2
|
||||
pthread
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${CMAKE_SOURCE_DIR}/ext-workspace-unstable-v1-protocol.o
|
||||
${CMAKE_SOURCE_DIR}/hyprland-toplevel-export-v1-protocol.o
|
||||
)
|
||||
|
||||
IF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||
|
39
Makefile
39
Makefile
@@ -91,6 +91,26 @@ wlr-output-power-management-unstable-v1-protocol.c:
|
||||
|
||||
wlr-output-power-management-unstable-v1-protocol.o: wlr-output-power-management-unstable-v1-protocol.h
|
||||
|
||||
hyprland-toplevel-export-v1-protocol.h:
|
||||
$(WAYLAND_SCANNER) server-header \
|
||||
subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml $@
|
||||
|
||||
hyprland-toplevel-export-v1-protocol.c:
|
||||
$(WAYLAND_SCANNER) private-code \
|
||||
subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml $@
|
||||
|
||||
hyprland-toplevel-export-v1-protocol.o: hyprland-toplevel-export-v1-protocol.h
|
||||
|
||||
linux-dmabuf-unstable-v1-protocol.h:
|
||||
$(WAYLAND_SCANNER) server-header \
|
||||
$(WAYLAND_PROTOCOLS)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml $@
|
||||
|
||||
linux-dmabuf-unstable-v1-protocol.c:
|
||||
$(WAYLAND_SCANNER) private-code \
|
||||
$(WAYLAND_PROTOCOLS)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml $@
|
||||
|
||||
linux-dmabuf-unstable-v1-protocol.o: linux-dmabuf-unstable-v1-protocol.h
|
||||
|
||||
legacyrenderer:
|
||||
mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DLEGACY_RENDERER:STRING=true -H./ -B./build -G Ninja
|
||||
cmake --build ./build --config Release --target all -j$(shell nproc)
|
||||
@@ -114,14 +134,17 @@ clear:
|
||||
rm -rf ./subprojects/wlroots/build
|
||||
|
||||
all:
|
||||
make config
|
||||
make clear
|
||||
make fixwlr
|
||||
cd ./subprojects/wlroots && meson build/ --buildtype=release && ninja -C build/ && cp ./build/libwlroots.so.12032 /usr/lib/ && cd ../..
|
||||
make protocols
|
||||
make release
|
||||
cd ./hyprctl && make all && cd ..
|
||||
cd hyprctl && make all && cd ..
|
||||
|
||||
install:
|
||||
make clear
|
||||
make fixwlr
|
||||
cd ./subprojects/wlroots && meson build/ --buildtype=release && ninja -C build/ && cp ./build/libwlroots.so.11032 /usr/lib/ && cd ../..
|
||||
cd ./subprojects/wlroots && meson build/ --buildtype=release && ninja -C build/ && cp ./build/libwlroots.so.12032 /usr/lib/ && cd ../..
|
||||
make protocols
|
||||
make release
|
||||
cd hyprctl && make all && cd ..
|
||||
@@ -141,7 +164,7 @@ install:
|
||||
cleaninstall:
|
||||
make clear
|
||||
make fixwlr
|
||||
cd ./subprojects/wlroots && meson build/ --buildtype=release && ninja -C build/ && cp ./build/libwlroots.so.11032 /usr/lib/ && cd ../..
|
||||
cd ./subprojects/wlroots && meson build/ --buildtype=release && ninja -C build/ && cp ./build/libwlroots.so.12032 /usr/lib/ && cd ../..
|
||||
make protocols
|
||||
make release
|
||||
cd hyprctl && make all && cd ..
|
||||
@@ -161,15 +184,15 @@ uninstall:
|
||||
rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop
|
||||
rm -f ${PREFIX}/bin/Hyprland
|
||||
rm -f ${PREFIX}/bin/hyprctl
|
||||
rm -f /usr/lib/libwlroots.so.11032
|
||||
rm -f /usr/lib/libwlroots.so.12032
|
||||
rm -rf ${PREFIX}/share/hyprland
|
||||
rm -f ${PREFIX}/share/man/man1/Hyprland.1
|
||||
rm -f ${PREFIX}/share/man/man1/hyprctl.1
|
||||
|
||||
protocols: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o wlr-screencopy-unstable-v1-protocol.o idle-protocol.o ext-workspace-unstable-v1-protocol.o pointer-constraints-unstable-v1-protocol.o tablet-unstable-v2-protocol.o wlr-output-power-management-unstable-v1-protocol.o
|
||||
protocols: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o wlr-screencopy-unstable-v1-protocol.o idle-protocol.o ext-workspace-unstable-v1-protocol.o pointer-constraints-unstable-v1-protocol.o tablet-unstable-v2-protocol.o wlr-output-power-management-unstable-v1-protocol.o linux-dmabuf-unstable-v1-protocol.o hyprland-toplevel-export-v1-protocol.o
|
||||
|
||||
fixwlr:
|
||||
sed -i -E 's/(soversion = 11)([^032]|$$)/soversion = 11032/g' subprojects/wlroots/meson.build
|
||||
sed -i -E 's/(soversion = 12)([^032]|$$)/soversion = 12032/g' subprojects/wlroots/meson.build
|
||||
|
||||
rm -rf ./subprojects/wlroots/build
|
||||
|
||||
@@ -178,7 +201,7 @@ config:
|
||||
|
||||
make fixwlr
|
||||
|
||||
cd subprojects/wlroots && meson ./build --prefix=/usr --buildtype=release
|
||||
cd subprojects/wlroots && meson ./build --prefix=/usr --buildtype=release -Dwerror=false -Dexamples=false
|
||||
cd subprojects/wlroots && ninja -C build/
|
||||
|
||||
cd subprojects/wlroots && ninja -C build/ install
|
||||
|
20
README.md
20
README.md
@@ -6,7 +6,6 @@
|
||||
|
||||
![Badge Workflow]
|
||||
[![Badge License]][License]
|
||||
![Badge Lines]
|
||||
![Badge Language]
|
||||
[![Badge Pull Requests]][Pull Requests]
|
||||
[![Badge Issues]][Issues]
|
||||
@@ -40,31 +39,28 @@ Hyprland is still in pretty early development compared to some other Wayland com
|
||||
|
||||
Although Hyprland is pretty stable, it may have some bugs.
|
||||
|
||||
### Help Wanted
|
||||
|
||||
Hyprland needs testers! <br/>
|
||||
Try it out and report bugs / suggestions!
|
||||
|
||||
# Features
|
||||
|
||||
- Easily expandable and readable codebase
|
||||
- Config reloaded instantly upon saving
|
||||
- Custom bezier curve based animations
|
||||
- `wlr_ext` workspaces protocol support
|
||||
- Dual Kawase blur
|
||||
- Drop shadows
|
||||
- Rounded corners
|
||||
- Gradient borders
|
||||
- Fully dynamic workspaces
|
||||
- Closely follows `wlroots-git`
|
||||
- Global keybinds passed to your apps of choice
|
||||
- A lot of customization
|
||||
- Bundled wlroots
|
||||
- Window/layer fade in/out
|
||||
- Tiling/pseudotiling/floating/fullscreen windows
|
||||
- Switching workspaces between window modes on the fly
|
||||
- Special workspace (scratchpad)
|
||||
- Special workspaces (scratchpads)
|
||||
- Window/monitor rules
|
||||
- Socket-based IPC
|
||||
- `wlr_ext` workspaces protocol support
|
||||
- Event system for bash scripts
|
||||
- Rounded corners
|
||||
- Full damage tracking
|
||||
- Docks support
|
||||
- Drawing tablet support
|
||||
@@ -150,9 +146,9 @@ Try it out and report bugs / suggestions!
|
||||
<!----------------------------------{ Images }--------------------------------->
|
||||
|
||||
[Stars Preview]: https://starchart.cc/vaxerski/Hyprland.svg
|
||||
[Preview A]: https://i.imgur.com/pC6YF1Y.png
|
||||
[Preview B]: https://i.imgur.com/NbrTnZH.png
|
||||
[Preview C]: https://i.imgur.com/sCafdKQ.png
|
||||
[Preview A]: https://i.ibb.co/B3GJg28/20221126-20h53m26s-grim.png
|
||||
[Preview B]: https://i.imgur.com/pC6YF1Y.png
|
||||
[Preview C]: https://i.imgur.com/NbrTnZH.png
|
||||
|
||||
|
||||
<!----------------------------------{ Badges }--------------------------------->
|
||||
|
@@ -1,10 +1,10 @@
|
||||
.\" Automatically generated by Pandoc 2.5
|
||||
.\" Automatically generated by Pandoc 2.9.2.1
|
||||
.\"
|
||||
.TH "Hyprland" "1" "11 Oct 2022" "" "Hyprland User Manual"
|
||||
.TH "Hyprland" "1" "02 Dec 2022" "" "Hyprland User Manual"
|
||||
.hy
|
||||
.SH NAME
|
||||
.PP
|
||||
Hyprland \- Dynamic tiling Wayland compositor
|
||||
Hyprland - Dynamic tiling Wayland compositor
|
||||
.SH SYNOPSIS
|
||||
.PP
|
||||
\f[B]Hyprland\f[R] [\f[I]arg [...]\f[R]].
|
||||
@@ -27,14 +27,14 @@ For configuration information please see
|
||||
<\f[I]https://github.com/hyprwm/Hyprland/wiki\f[R]>.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \f[B]\-h\f[R], \f[B]\-\-help\f[R]
|
||||
\f[B]-h\f[R], \f[B]--help\f[R]
|
||||
Show command usage.
|
||||
.TP
|
||||
.B \f[B]\-c\f[R], \f[B]\-\-config\f[R]
|
||||
\f[B]-c\f[R], \f[B]--config\f[R]
|
||||
Specify config file to use.
|
||||
.SH BUGS
|
||||
.TP
|
||||
.B Submit bug reports and request features online at:
|
||||
Submit bug reports and request features online at:
|
||||
<\f[I]https://github.com/hyprwm/Hyprland/issues\f[R]>
|
||||
.SH SEE ALSO
|
||||
.PP
|
||||
|
@@ -1,10 +1,10 @@
|
||||
.\" Automatically generated by Pandoc 2.5
|
||||
.\" Automatically generated by Pandoc 2.9.2.1
|
||||
.\"
|
||||
.TH "hyprctl" "1" "11 Oct 2022" "" "hyprctl User Manual"
|
||||
.TH "hyprctl" "1" "02 Dec 2022" "" "hyprctl User Manual"
|
||||
.hy
|
||||
.SH NAME
|
||||
.PP
|
||||
hyprctl \- Utility for controlling parts of Hyprland from a CLI or a
|
||||
hyprctl - Utility for controlling parts of Hyprland from a CLI or a
|
||||
script
|
||||
.SH SYNOPSIS
|
||||
.PP
|
||||
@@ -26,7 +26,7 @@ For dispatchers without parameters it can be anything.
|
||||
.PP
|
||||
Returns: \f[I]ok\f[R] on success, and an error message on failure.
|
||||
.TP
|
||||
.B Examples:
|
||||
Examples:
|
||||
\f[B]hyprctl\f[R] \f[I]dispatch exec kitty\f[R]
|
||||
.RS
|
||||
.PP
|
||||
@@ -41,7 +41,7 @@ Set a config keyword dynamically.
|
||||
.PP
|
||||
Returns: \f[I]ok\f[R] on success, and an error message on failure.
|
||||
.TP
|
||||
.B Examples:
|
||||
Examples:
|
||||
\f[B]hyprctl\f[R] \f[I]keyword bind SUPER,0,pseudo\f[R]
|
||||
.RS
|
||||
.PP
|
||||
@@ -112,13 +112,13 @@ Returns the current random splash.
|
||||
.RE
|
||||
.SH OPTIONS
|
||||
.PP
|
||||
\f[B]\-\-batch\f[R]
|
||||
\f[B]--batch\f[R]
|
||||
.RS
|
||||
.PP
|
||||
Specify a batch of commands to execute.
|
||||
.TP
|
||||
.B Example:
|
||||
\f[B]hyprctl\f[R] \f[I]\-\-batch \[dq]keyword general:border_size 2 ;
|
||||
Example:
|
||||
\f[B]hyprctl\f[R] \f[I]--batch \[dq]keyword general:border_size 2 ;
|
||||
keyword general:gaps_out 20\[dq]\f[R]
|
||||
.RS
|
||||
.PP
|
||||
@@ -126,14 +126,14 @@ keyword general:gaps_out 20\[dq]\f[R]
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\f[B]\-j\f[R]
|
||||
\f[B]-j\f[R]
|
||||
.RS
|
||||
.PP
|
||||
Outputs information in JSON.
|
||||
.RE
|
||||
.SH BUGS
|
||||
.TP
|
||||
.B Submit bug reports and request features online at:
|
||||
Submit bug reports and request features online at:
|
||||
<\f[I]https://github.com/hyprwm/Hyprland/issues\f[R]>
|
||||
.SH SEE ALSO
|
||||
.PP
|
||||
|
@@ -42,7 +42,7 @@ general {
|
||||
gaps_in = 5
|
||||
gaps_out = 20
|
||||
border_size = 2
|
||||
col.active_border = rgba(1affffee)
|
||||
col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg
|
||||
col.inactive_border = rgba(595959aa)
|
||||
|
||||
layout = dwindle
|
||||
|
16
example/screenShader.frag
Normal file
16
example/screenShader.frag
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Example blue light filter shader.
|
||||
//
|
||||
|
||||
precision mediump float;
|
||||
varying vec2 v_texcoord;
|
||||
uniform sampler2D tex;
|
||||
|
||||
void main() {
|
||||
|
||||
vec4 pixColor = texture2D(tex, v_texcoord);
|
||||
|
||||
pixColor[2] *= 0.8;
|
||||
|
||||
gl_FragColor = pixColor;
|
||||
}
|
69
flake.lock
generated
69
flake.lock
generated
@@ -1,12 +1,44 @@
|
||||
{
|
||||
"nodes": {
|
||||
"hyprland-protocols": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1670258048,
|
||||
"narHash": "sha256-Lm2sXnDVZNE+taHqsqVibvPmSdu65VHvXI507KVX4lg=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-protocols",
|
||||
"rev": "0dcff94fc10df2bbb66d3e1b5a1d6cfd3ada5515",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-protocols",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprland-protocols_2": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1670185345,
|
||||
"narHash": "sha256-hxWGqlPecqEsE6nOHDV29KFBKePbY2Ipeac6lrChMKY=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-protocols",
|
||||
"rev": "4623a404c091e64743ba310199bb380ec52f1936",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-protocols",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1666377499,
|
||||
"narHash": "sha256-dZZCGvWcxc7oGnUgFVf0UeNHsJ4VhkTM0v5JRe8EwR8=",
|
||||
"lastModified": 1670064435,
|
||||
"narHash": "sha256-+ELoY30UN+Pl3Yn7RWRPabykwebsVK/kYE9JsIsUMxQ=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "301aada7a64812853f2e2634a530ef5d34505048",
|
||||
"rev": "61a8a98e6d557e6dd7ed0cdb54c3a3e3bbc5e25c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -18,19 +50,21 @@
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"hyprland-protocols": "hyprland-protocols",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"wlroots": "wlroots"
|
||||
"wlroots": "wlroots",
|
||||
"xdph": "xdph"
|
||||
}
|
||||
},
|
||||
"wlroots": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"host": "gitlab.freedesktop.org",
|
||||
"lastModified": 1666466001,
|
||||
"narHash": "sha256-ZjxAnqtcGmHQHKL1Z9sIraDnzIqrJleWcJXfPtzAm74=",
|
||||
"lastModified": 1669925104,
|
||||
"narHash": "sha256-xMHfW+/G9MieN/5tXHUA5/ztE8dkE093cNFTEUgcwxI=",
|
||||
"owner": "wlroots",
|
||||
"repo": "wlroots",
|
||||
"rev": "c2d2773df57750081b16d56da13b5015d752cbd7",
|
||||
"rev": "c8eb24d30e18c165728b8788a10716611c3b633d",
|
||||
"type": "gitlab"
|
||||
},
|
||||
"original": {
|
||||
@@ -39,6 +73,27 @@
|
||||
"repo": "wlroots",
|
||||
"type": "gitlab"
|
||||
}
|
||||
},
|
||||
"xdph": {
|
||||
"inputs": {
|
||||
"hyprland-protocols": "hyprland-protocols_2",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1670202338,
|
||||
"narHash": "sha256-StTfshdAoSxO+t0wRbq1I3YESLFIQWFjGJse5ICV8rk=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "xdg-desktop-portal-hyprland",
|
||||
"rev": "af840a9e0947a79a37a95a9f62062653721e43fa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "xdg-desktop-portal-hyprland",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
|
55
flake.nix
55
flake.nix
@@ -7,6 +7,16 @@
|
||||
url = "gitlab:wlroots/wlroots?host=gitlab.freedesktop.org";
|
||||
flake = false;
|
||||
};
|
||||
|
||||
xdph = {
|
||||
url = "github:hyprwm/xdg-desktop-portal-hyprland";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
hyprland-protocols = {
|
||||
url = "github:hyprwm/hyprland-protocols";
|
||||
flake = false;
|
||||
};
|
||||
};
|
||||
|
||||
outputs = inputs @ {
|
||||
@@ -21,18 +31,28 @@
|
||||
"x86_64-linux"
|
||||
];
|
||||
|
||||
pkgsFor = genSystems (system: import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [(_: prev: {
|
||||
wayland-protocols = prev.wayland-protocols.overrideAttrs (old: rec {
|
||||
version = "1.27";
|
||||
src = prev.fetchurl {
|
||||
url = "https://gitlab.freedesktop.org/wayland/${old.pname}/-/releases/${version}/downloads/${old.pname}-${version}.tar.xz";
|
||||
hash = "sha256-kEbxCkJdTioAlloDrPtrP7V1pWUDrHLCuGghxpZTN1w=";
|
||||
};
|
||||
});
|
||||
})];
|
||||
});
|
||||
pkgsFor = genSystems (system:
|
||||
import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [
|
||||
(_: prev: {
|
||||
libdrm = prev.libdrm.overrideAttrs (old: rec {
|
||||
version = "2.4.114";
|
||||
src = prev.fetchurl {
|
||||
url = "https://dri.freedesktop.org/${old.pname}/${old.pname}-${version}.tar.xz";
|
||||
sha256 = "sha256-MEnPhDpH0S5e7vvDvjSW14L6CfQjRr8Lfe/j0eWY0CY=";
|
||||
};
|
||||
});
|
||||
wayland-protocols = prev.wayland-protocols.overrideAttrs (old: rec {
|
||||
version = "1.29";
|
||||
src = prev.fetchurl {
|
||||
url = "https://gitlab.freedesktop.org/wayland/${old.pname}/-/releases/${version}/downloads/${old.pname}-${version}.tar.xz";
|
||||
hash = "sha256-4l6at1rHNnBN3v6S6PmshzC+q29WTbYvetaVu6T/ntg=";
|
||||
};
|
||||
});
|
||||
})
|
||||
];
|
||||
});
|
||||
|
||||
mkDate = longDate: (lib.concatStringsSep "-" [
|
||||
(builtins.substring 0 4 longDate)
|
||||
@@ -47,8 +67,9 @@
|
||||
};
|
||||
hyprland = prev.callPackage ./nix/default.nix {
|
||||
stdenv = prev.gcc12Stdenv;
|
||||
version = "0.16.0beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty");
|
||||
version = "0.18.0beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty");
|
||||
wlroots = wlroots-hyprland;
|
||||
inherit (inputs) hyprland-protocols;
|
||||
};
|
||||
hyprland-debug = hyprland.override {debug = true;};
|
||||
hyprland-no-hidpi = hyprland.override {hidpiXWayland = false;};
|
||||
@@ -67,6 +88,12 @@
|
||||
devShells = genSystems (system: {
|
||||
default = pkgsFor.${system}.mkShell.override {stdenv = pkgsFor.${system}.gcc12Stdenv;} {
|
||||
name = "hyprland-shell";
|
||||
nativeBuildInputs = with pkgsFor.${system}; [
|
||||
cmake
|
||||
];
|
||||
buildInputs = [
|
||||
self.packages.${system}.wlroots-hyprland
|
||||
];
|
||||
inputsFrom = [
|
||||
self.packages.${system}.wlroots-hyprland
|
||||
self.packages.${system}.hyprland
|
||||
@@ -76,7 +103,7 @@
|
||||
|
||||
formatter = genSystems (system: pkgsFor.${system}.alejandra);
|
||||
|
||||
nixosModules.default = import ./nix/module.nix self;
|
||||
nixosModules.default = import ./nix/module.nix inputs;
|
||||
homeManagerModules.default = import ./nix/hm-module.nix self;
|
||||
};
|
||||
|
||||
|
@@ -37,15 +37,23 @@ commands:
|
||||
setcursor
|
||||
getoption
|
||||
cursorpos
|
||||
switchxkblayout
|
||||
|
||||
flags:
|
||||
-j -> output in JSON
|
||||
--batch -> execute a batch of commands, separated by ';'
|
||||
)#";
|
||||
|
||||
void request(std::string arg) {
|
||||
void request(std::string arg, int minArgs = 0) {
|
||||
const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
const auto ARGS = std::count(arg.begin(), arg.end(), ' ');
|
||||
|
||||
if (ARGS < minArgs) {
|
||||
std::cout << "Not enough arguments, expected at least " << minArgs;
|
||||
return;
|
||||
}
|
||||
|
||||
if (SERVERSOCKET < 0) {
|
||||
std::cout << "Couldn't open a socket (1)";
|
||||
return;
|
||||
@@ -168,8 +176,11 @@ int dispatchRequest(int argc, char** argv) {
|
||||
|
||||
std::string rq = "/dispatch";
|
||||
|
||||
for(int i = 2; i < argc; i++)
|
||||
for(int i = 2; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "--"))
|
||||
continue;
|
||||
rq += " " + std::string(argv[i]);
|
||||
}
|
||||
|
||||
request(rq);
|
||||
return 0;
|
||||
@@ -217,6 +228,21 @@ int setcursorRequest(int argc, char** argv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int outputRequest(int argc, char** argv) {
|
||||
if (argc < 4) {
|
||||
std::cout << "Usage: hyprctl output <mode> <name>\n\
|
||||
creates / destroys a fake output\n\
|
||||
with create, name is the backend name to use (available: auto, x11, wayland, headless)\n\
|
||||
with destroy, name is the output name to destroy";
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string rq = "output " + std::string(argv[2]) + " " + std::string(argv[3]);
|
||||
|
||||
request(rq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void batchRequest(std::string arg) {
|
||||
std::string rq = "[[BATCH]]" + arg.substr(arg.find_first_of(" ") + 1);
|
||||
|
||||
@@ -233,11 +259,14 @@ std::deque<std::string> splitArgs(int argc, char** argv) {
|
||||
}
|
||||
|
||||
bool isNumber(const std::string& str, bool allowfloat) {
|
||||
if (str.empty())
|
||||
return false;
|
||||
return std::ranges::all_of(str.begin(), str.end(), [&](char c) { return isdigit(c) != 0 || c == '-' || (allowfloat && c == '.'); });
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int bflag = 0, sflag = 0, index, c;
|
||||
bool parseArgs = true;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("%s\n", USAGE.c_str());
|
||||
@@ -249,7 +278,12 @@ int main(int argc, char** argv) {
|
||||
const auto ARGS = splitArgs(argc, argv);
|
||||
|
||||
for (auto i = 0; i < ARGS.size(); ++i) {
|
||||
if (ARGS[i][0] == '-' && !isNumber(ARGS[i], true) /* For stuff like -2 */) {
|
||||
if (ARGS[i] == "--") {
|
||||
// Stop parsing arguments after --
|
||||
parseArgs = false;
|
||||
continue;
|
||||
}
|
||||
if (parseArgs && (ARGS[i][0] == '-') && !isNumber(ARGS[i], true) /* For stuff like -2 */) {
|
||||
// parse
|
||||
if (ARGS[i] == "-j" && !fullArgs.contains("j")) {
|
||||
fullArgs += "j";
|
||||
@@ -290,6 +324,8 @@ int main(int argc, char** argv) {
|
||||
else if (fullRequest.contains("/reload")) request(fullRequest);
|
||||
else if (fullRequest.contains("/getoption")) request(fullRequest);
|
||||
else if (fullRequest.contains("/cursorpos")) request(fullRequest);
|
||||
else if (fullRequest.contains("/switchxkblayout")) request(fullRequest, 2);
|
||||
else if (fullRequest.contains("/output")) exitStatus = outputRequest(argc, argv);
|
||||
else if (fullRequest.contains("/setcursor")) exitStatus = setcursorRequest(argc, argv);
|
||||
else if (fullRequest.contains("/dispatch")) exitStatus = dispatchRequest(argc, argv);
|
||||
else if (fullRequest.contains("/keyword")) exitStatus = keywordRequest(argc, argv);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
project('Hyprland', 'cpp', 'c',
|
||||
version : '0.16.0beta',
|
||||
version : '0.18.0beta',
|
||||
default_options : [
|
||||
'warning_level=2',
|
||||
'default_library=static',
|
||||
|
@@ -7,6 +7,7 @@
|
||||
meson,
|
||||
ninja,
|
||||
git,
|
||||
hyprland-protocols,
|
||||
libdrm,
|
||||
libinput,
|
||||
libxcb,
|
||||
@@ -14,6 +15,7 @@
|
||||
mesa,
|
||||
mount,
|
||||
pango,
|
||||
pciutils,
|
||||
wayland,
|
||||
wayland-protocols,
|
||||
wayland-scanner,
|
||||
@@ -62,17 +64,16 @@ in
|
||||
git
|
||||
libdrm
|
||||
libinput
|
||||
libxcb
|
||||
libxkbcommon
|
||||
mesa
|
||||
pango
|
||||
wayland
|
||||
wayland-protocols
|
||||
wayland-scanner
|
||||
pciutils
|
||||
(wlroots.override {inherit enableXWayland hidpiXWayland nvidiaPatches;})
|
||||
xcbutilwm
|
||||
]
|
||||
++ lib.optional enableXWayland xwayland;
|
||||
++ lib.optionals enableXWayland [libxcb xcbutilwm xwayland];
|
||||
|
||||
mesonBuildType =
|
||||
if debug
|
||||
@@ -92,6 +93,10 @@ in
|
||||
# Fix hardcoded paths to /usr installation
|
||||
postPatch = ''
|
||||
sed -i "s#/usr#$out#" src/render/OpenGL.cpp
|
||||
|
||||
# for some reason rmdir doesn't work in a dirty tree
|
||||
rmdir subprojects/hyprland-protocols || true
|
||||
ln -s ${hyprland-protocols} subprojects/hyprland-protocols
|
||||
'';
|
||||
|
||||
passthru.providedSessions = ["hyprland"];
|
||||
|
@@ -92,18 +92,13 @@ in {
|
||||
++ lib.optional cfg.xwayland.enable pkgs.xwayland;
|
||||
|
||||
home.sessionVariables = lib.mkIf cfg.recommendedEnvironment {
|
||||
GDK_BACKEND = "wayland,x11";
|
||||
_JAVA_AWT_WM_NONREPARENTING = "1";
|
||||
NIXOS_OZONE_WL = "1";
|
||||
XCURSOR_SIZE = toString config.home.pointerCursor.size or "24";
|
||||
XDG_SESSION_TYPE = "wayland";
|
||||
};
|
||||
|
||||
xdg.configFile."hypr/hyprland.conf" = {
|
||||
text =
|
||||
(lib.optionalString cfg.systemdIntegration ''
|
||||
exec-once=${pkgs.dbus}/bin/dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP
|
||||
exec-once=systemctl --user start hyprland-session.target
|
||||
exec-once=${pkgs.dbus}/bin/dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP && systemctl --user start hyprland-session.target
|
||||
'')
|
||||
+ cfg.extraConfig;
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
# Copied from https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/programs/sway.nix
|
||||
self: {
|
||||
inputs: {
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
@@ -23,7 +23,7 @@ in {
|
||||
|
||||
package = mkOption {
|
||||
type = types.nullOr types.package;
|
||||
default = self.packages.${pkgs.system}.default;
|
||||
default = inputs.self.packages.${pkgs.system}.default;
|
||||
defaultText = literalExpression "<Hyprland flake>.packages.<system>.default";
|
||||
example = literalExpression "<Hyprland flake>.packages.<system>.default.override { }";
|
||||
description = ''
|
||||
@@ -47,24 +47,30 @@ in {
|
||||
systemPackages = lib.optional (cfg.package != null) cfg.package;
|
||||
|
||||
sessionVariables = mkIf cfg.recommendedEnvironment {
|
||||
GDK_BACKEND = "wayland,x11";
|
||||
_JAVA_AWT_WM_NONREPARENTING = "1";
|
||||
NIXOS_OZONE_WL = "1";
|
||||
XCURSOR_SIZE = "24";
|
||||
XDG_SESSION_TYPE = "wayland";
|
||||
};
|
||||
};
|
||||
|
||||
fonts.enableDefaultFonts = mkDefault true;
|
||||
hardware.opengl.enable = mkDefault true;
|
||||
|
||||
# enable cachix
|
||||
nix.settings = {
|
||||
substituters = ["https://hyprland.cachix.org"];
|
||||
trusted-public-keys = ["hyprland.cachix.org-1:a7pgxzMz7+chwVL3/pzj6jIBMioiJM7ypFP8PwtkuGc="];
|
||||
};
|
||||
|
||||
programs = {
|
||||
dconf.enable = mkDefault true;
|
||||
xwayland.enable = mkDefault true;
|
||||
};
|
||||
|
||||
security.polkit.enable = true;
|
||||
services.xserver.displayManager.sessionPackages = lib.optional (cfg.package != null) cfg.package;
|
||||
xdg.portal = {
|
||||
enable = mkDefault true;
|
||||
extraPortals = [pkgs.xdg-desktop-portal-wlr];
|
||||
# xdg-desktop-portal-hyprland
|
||||
extraPortals = [inputs.xdph.packages.${pkgs.system}.default];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@
|
||||
xwayland,
|
||||
fetchpatch,
|
||||
lib,
|
||||
hwdata,
|
||||
hidpiXWayland ? true,
|
||||
enableXWayland ? true,
|
||||
nvidiaPatches ? false,
|
||||
@@ -51,6 +52,7 @@ assert (lib.assertMsg (hidpiXWayland -> enableXWayland) ''
|
||||
''
|
||||
else ""
|
||||
);
|
||||
buildInputs = old.buildInputs ++ [hwdata];
|
||||
}))
|
||||
.override {
|
||||
xwayland = xwayland.overrideAttrs (old: {
|
||||
|
@@ -3,7 +3,14 @@ wayland_protos = dependency('wayland-protocols',
|
||||
fallback: 'wayland-protocols',
|
||||
default_options: ['tests=false'],
|
||||
)
|
||||
|
||||
hyprland_protos = dependency('hyprland-protocols',
|
||||
version: '>=0.1',
|
||||
fallback: 'hyprland-protocols',
|
||||
)
|
||||
|
||||
wl_protocol_dir = wayland_protos.get_variable('pkgdatadir')
|
||||
hl_protocol_dir = hyprland_protos.get_variable('pkgdatadir')
|
||||
|
||||
wayland_scanner_dep = dependency('wayland-scanner', native: true)
|
||||
wayland_scanner = find_program(
|
||||
@@ -13,12 +20,14 @@ wayland_scanner = find_program(
|
||||
|
||||
protocols = [
|
||||
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
|
||||
[wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'],
|
||||
['wlr-layer-shell-unstable-v1.xml'],
|
||||
['wlr-output-power-management-unstable-v1.xml'],
|
||||
['ext-workspace-unstable-v1.xml'],
|
||||
['pointer-constraints-unstable-v1.xml'],
|
||||
['tablet-unstable-v2.xml'],
|
||||
['idle.xml']
|
||||
['idle.xml'],
|
||||
[hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml']
|
||||
]
|
||||
wl_protos_src = []
|
||||
wl_protos_headers = []
|
||||
|
@@ -53,7 +53,7 @@ CCompositor::CCompositor() {
|
||||
wl_event_loop_add_signal(m_sWLEventLoop, SIGTERM, handleCritSignal, nullptr);
|
||||
//wl_event_loop_add_signal(m_sWLEventLoop, SIGINT, handleCritSignal, nullptr);
|
||||
|
||||
m_sWLRBackend = wlr_backend_autocreate(m_sWLDisplay);
|
||||
m_sWLRBackend = wlr_backend_autocreate(m_sWLDisplay, &m_sWLRSession);
|
||||
|
||||
if (!m_sWLRBackend) {
|
||||
Debug::log(CRIT, "m_sWLRBackend was NULL!");
|
||||
@@ -73,7 +73,14 @@ CCompositor::CCompositor() {
|
||||
throw std::runtime_error("wlr_gles2_renderer_create_with_drm_fd() failed!");
|
||||
}
|
||||
|
||||
wlr_renderer_init_wl_display(m_sWLRRenderer, m_sWLDisplay);
|
||||
wlr_renderer_init_wl_shm(m_sWLRRenderer, m_sWLDisplay);
|
||||
|
||||
if (wlr_renderer_get_dmabuf_texture_formats(m_sWLRRenderer)) {
|
||||
if (wlr_renderer_get_drm_fd(m_sWLRRenderer) >= 0)
|
||||
wlr_drm_create(m_sWLDisplay, m_sWLRRenderer);
|
||||
|
||||
m_sWLRLinuxDMABuf = wlr_linux_dmabuf_v1_create_with_renderer(m_sWLDisplay, 4, m_sWLRRenderer);
|
||||
}
|
||||
|
||||
m_sWLRAllocator = wlr_allocator_autocreate(m_sWLRBackend, m_sWLRRenderer);
|
||||
|
||||
@@ -124,7 +131,7 @@ CCompositor::CCompositor() {
|
||||
|
||||
m_sWLRIdle = wlr_idle_create(m_sWLDisplay);
|
||||
|
||||
m_sWLRLayerShell = wlr_layer_shell_v1_create(m_sWLDisplay);
|
||||
m_sWLRLayerShell = wlr_layer_shell_v1_create(m_sWLDisplay, 4);
|
||||
|
||||
m_sWLRServerDecoMgr = wlr_server_decoration_manager_create(m_sWLDisplay);
|
||||
m_sWLRXDGDecoMgr = wlr_xdg_decoration_manager_v1_create(m_sWLDisplay);
|
||||
@@ -165,13 +172,20 @@ CCompositor::CCompositor() {
|
||||
|
||||
m_sWLRPointerGestures = wlr_pointer_gestures_v1_create(m_sWLDisplay);
|
||||
|
||||
m_sWLRSession = wlr_backend_get_session(m_sWLRBackend);
|
||||
|
||||
m_sWLRTextInputMgr = wlr_text_input_manager_v3_create(m_sWLDisplay);
|
||||
|
||||
m_sWLRIMEMgr = wlr_input_method_manager_v2_create(m_sWLDisplay);
|
||||
|
||||
m_sWLRActivation = wlr_xdg_activation_v1_create(m_sWLDisplay);
|
||||
|
||||
m_sWLRHeadlessBackend = wlr_headless_backend_create(m_sWLDisplay);
|
||||
|
||||
if (!m_sWLRHeadlessBackend) {
|
||||
Debug::log(CRIT, "Couldn't create the headless backend");
|
||||
throw std::runtime_error("wlr_headless_backend_create() failed!");
|
||||
}
|
||||
|
||||
wlr_multi_backend_add(m_sWLRBackend, m_sWLRHeadlessBackend);
|
||||
}
|
||||
|
||||
CCompositor::~CCompositor() {
|
||||
@@ -312,6 +326,9 @@ void CCompositor::startCompositor() {
|
||||
Debug::log(LOG, "Creating the XWaylandManager!");
|
||||
g_pXWaylandManager = std::make_unique<CHyprXWaylandManager>();
|
||||
|
||||
Debug::log(LOG, "Creating the ProtocolManager!");
|
||||
g_pProtocolManager = std::make_unique<CProtocolManager>();
|
||||
|
||||
Debug::log(LOG, "Creating the EventManager!");
|
||||
g_pEventManager = std::make_unique<CEventManager>();
|
||||
g_pEventManager->startThread();
|
||||
@@ -328,18 +345,27 @@ void CCompositor::startCompositor() {
|
||||
|
||||
initAllSignals();
|
||||
|
||||
m_szWLDisplaySocket = wl_display_add_socket_auto(m_sWLDisplay);
|
||||
// get socket, avoid using 0
|
||||
for (int candidate = 1; candidate <= 32; candidate++) {
|
||||
if (wl_display_add_socket(m_sWLDisplay, ("wayland-" + std::to_string(candidate)).c_str()) >= 0) {
|
||||
m_szWLDisplaySocket = "wayland-" + std::to_string(candidate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_szWLDisplaySocket) {
|
||||
if (m_szWLDisplaySocket.empty()) {
|
||||
Debug::log(CRIT, "m_szWLDisplaySocket NULL!");
|
||||
wlr_backend_destroy(m_sWLRBackend);
|
||||
throw std::runtime_error("m_szWLDisplaySocket was null! (wl_display_add_socket_auto failed)");
|
||||
}
|
||||
|
||||
setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket, 1);
|
||||
setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket.c_str(), 1);
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
if (m_sWLRSession /* Session-less Hyprland usually means a nest, don't update the env in that case */ && fork() == 0)
|
||||
execl("/bin/sh", "/bin/sh", "-c", "dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE", nullptr);
|
||||
|
||||
Debug::log(LOG, "Running on WAYLAND_DISPLAY: %s", m_szWLDisplaySocket);
|
||||
|
||||
if (!wlr_backend_start(m_sWLRBackend)) {
|
||||
@@ -412,7 +438,7 @@ CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) {
|
||||
void CCompositor::removeWindowFromVectorSafe(CWindow* pWindow) {
|
||||
if (windowExists(pWindow) && !pWindow->m_bFadingOut){
|
||||
if (pWindow->m_bIsX11 && pWindow->m_iX11Type == 2) {
|
||||
m_dUnmanagedX11Windows.erase(std::remove_if(m_dUnmanagedX11Windows.begin(), m_dUnmanagedX11Windows.end(), [&](std::unique_ptr<CWindow>& el) { return el.get() == pWindow; }));
|
||||
std::erase_if(m_dUnmanagedX11Windows, [&](std::unique_ptr<CWindow>& el) { return el.get() == pWindow; });
|
||||
}
|
||||
|
||||
// if X11, also check its children
|
||||
@@ -423,16 +449,16 @@ void CCompositor::removeWindowFromVectorSafe(CWindow* pWindow) {
|
||||
continue;
|
||||
|
||||
if (w->m_pX11Parent == pWindow)
|
||||
m_vWindows.erase(std::remove_if(m_vWindows.begin(), m_vWindows.end(), [&](std::unique_ptr<CWindow>& el) { return el.get() == w.get(); }));
|
||||
std::erase_if(m_vWindows, [&](std::unique_ptr<CWindow>& el) { return el.get() == w.get(); });
|
||||
}
|
||||
|
||||
for (auto& w : m_dUnmanagedX11Windows) {
|
||||
if (w->m_pX11Parent == pWindow)
|
||||
m_dUnmanagedX11Windows.erase(std::remove_if(m_dUnmanagedX11Windows.begin(), m_dUnmanagedX11Windows.end(), [&](std::unique_ptr<CWindow>& el) { return el.get() == w.get(); }));
|
||||
std::erase_if(m_dUnmanagedX11Windows, [&](std::unique_ptr<CWindow>& el) { return el.get() == w.get(); });
|
||||
}
|
||||
}
|
||||
|
||||
m_vWindows.erase(std::remove_if(m_vWindows.begin(), m_vWindows.end(), [&](std::unique_ptr<CWindow>& el) { return el.get() == pWindow; }));
|
||||
std::erase_if(m_vWindows, [&](std::unique_ptr<CWindow>& el) { return el.get() == pWindow; });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -448,16 +474,16 @@ bool CCompositor::windowExists(CWindow* pWindow) {
|
||||
CWindow* CCompositor::vectorToWindow(const Vector2D& pos) {
|
||||
const auto PMONITOR = getMonitorFromVector(pos);
|
||||
|
||||
if (PMONITOR->specialWorkspaceOpen) {
|
||||
if (PMONITOR->specialWorkspaceID) {
|
||||
for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) {
|
||||
wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y};
|
||||
if ((*w)->m_bIsFloating && (*w)->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && (*w)->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !(*w)->isHidden())
|
||||
if ((*w)->m_bIsFloating && (*w)->m_iWorkspaceID == PMONITOR->specialWorkspaceID && (*w)->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !(*w)->isHidden())
|
||||
return (*w).get();
|
||||
}
|
||||
|
||||
for (auto& w : m_vWindows) {
|
||||
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
|
||||
if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && !w->m_bIsFloating && !w->isHidden())
|
||||
if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && !w->m_bIsFloating && !w->isHidden())
|
||||
return w.get();
|
||||
}
|
||||
}
|
||||
@@ -488,10 +514,10 @@ CWindow* CCompositor::vectorToWindow(const Vector2D& pos) {
|
||||
CWindow* CCompositor::vectorToWindowTiled(const Vector2D& pos) {
|
||||
const auto PMONITOR = getMonitorFromVector(pos);
|
||||
|
||||
if (PMONITOR->specialWorkspaceOpen) {
|
||||
if (PMONITOR->specialWorkspaceID) {
|
||||
for (auto& w : m_vWindows) {
|
||||
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
|
||||
if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && wlr_box_contains_point(&box, pos.x, pos.y) && !w->m_bIsFloating && !w->isHidden())
|
||||
if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && wlr_box_contains_point(&box, pos.x, pos.y) && !w->m_bIsFloating && !w->isHidden())
|
||||
return w.get();
|
||||
}
|
||||
}
|
||||
@@ -518,16 +544,16 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
|
||||
const auto PMONITOR = getMonitorFromVector(pos);
|
||||
|
||||
// special workspace
|
||||
if (PMONITOR->specialWorkspaceOpen) {
|
||||
if (PMONITOR->specialWorkspaceID) {
|
||||
for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) {
|
||||
wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y};
|
||||
if ((*w)->m_bIsFloating && (*w)->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && (*w)->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !(*w)->isHidden() && !(*w)->m_bX11ShouldntFocus)
|
||||
if ((*w)->m_bIsFloating && (*w)->m_iWorkspaceID == PMONITOR->specialWorkspaceID && (*w)->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !(*w)->isHidden() && !(*w)->m_bX11ShouldntFocus)
|
||||
return (*w).get();
|
||||
}
|
||||
|
||||
for (auto& w : m_vWindows) {
|
||||
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
|
||||
if (!w->m_bIsFloating && w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !w->isHidden() && !w->m_bX11ShouldntFocus)
|
||||
if (!w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !w->isHidden() && !w->m_bX11ShouldntFocus)
|
||||
return w.get();
|
||||
}
|
||||
}
|
||||
@@ -606,16 +632,16 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
|
||||
CWindow* CCompositor::windowFromCursor() {
|
||||
const auto PMONITOR = getMonitorFromCursor();
|
||||
|
||||
if (PMONITOR->specialWorkspaceOpen) {
|
||||
if (PMONITOR->specialWorkspaceID) {
|
||||
for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) {
|
||||
wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y};
|
||||
if ((*w)->m_bIsFloating && (*w)->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && (*w)->m_bIsMapped && wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && !(*w)->isHidden())
|
||||
if ((*w)->m_bIsFloating && (*w)->m_iWorkspaceID == PMONITOR->specialWorkspaceID && (*w)->m_bIsMapped && wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && !(*w)->isHidden())
|
||||
return (*w).get();
|
||||
}
|
||||
|
||||
for (auto& w : m_vWindows) {
|
||||
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
|
||||
if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped)
|
||||
if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped)
|
||||
return w.get();
|
||||
}
|
||||
}
|
||||
@@ -728,6 +754,8 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowFocusChange(nullptr);
|
||||
|
||||
m_pLastFocus = nullptr;
|
||||
|
||||
g_pInputManager->recheckIdleInhibitorStatus();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -787,7 +815,8 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
|
||||
if (PCONSTRAINT)
|
||||
g_pInputManager->constrainMouse(m_sSeat.mouse, PCONSTRAINT);
|
||||
}
|
||||
|
||||
|
||||
g_pInputManager->recheckIdleInhibitorStatus();
|
||||
}
|
||||
|
||||
void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) {
|
||||
@@ -828,7 +857,7 @@ void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) {
|
||||
else
|
||||
Debug::log(LOG, "Set keyboard focus to surface %x", pSurface);
|
||||
|
||||
g_pXWaylandManager->activateSurface(pSurface, false);
|
||||
g_pXWaylandManager->activateSurface(pSurface, true);
|
||||
m_pLastFocus = pSurface;
|
||||
}
|
||||
|
||||
@@ -865,7 +894,11 @@ wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector<
|
||||
if ((*it)->fadingOut || !(*it)->layerSurface || ((*it)->layerSurface && !(*it)->layerSurface->mapped) || (*it)->alpha.fl() == 0.f)
|
||||
continue;
|
||||
|
||||
const auto SURFACEAT = wlr_layer_surface_v1_surface_at((*it)->layerSurface, pos.x - (*it)->geometry.x, pos.y - (*it)->geometry.y, &sCoords->x, &sCoords->y);
|
||||
auto SURFACEAT = wlr_layer_surface_v1_surface_at((*it)->layerSurface, pos.x - (*it)->geometry.x, pos.y - (*it)->geometry.y, &sCoords->x, &sCoords->y);
|
||||
|
||||
if (!SURFACEAT && VECINRECT(pos, (*it)->geometry.x, (*it)->geometry.y, (*it)->geometry.x + (*it)->geometry.width, (*it)->geometry.y + (*it)->geometry.height)) {
|
||||
SURFACEAT = (*it)->layerSurface->surface;
|
||||
}
|
||||
|
||||
if (SURFACEAT) {
|
||||
*ppLayerSurfaceFound = it->get();
|
||||
@@ -885,6 +918,16 @@ CWindow* CCompositor::getWindowFromSurface(wlr_surface* pSurface) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CWindow* CCompositor::getWindowFromHandle(uint32_t handle) {
|
||||
for (auto& w : m_vWindows) {
|
||||
if ((uint32_t)(((uint64_t)w.get()) & 0xFFFFFFFF) == handle) {
|
||||
return w.get();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CWindow* CCompositor::getFullscreenWindowOnWorkspace(const int& ID) {
|
||||
for (auto& w : m_vWindows) {
|
||||
if (w->m_iWorkspaceID == ID && w->m_bIsFullscreen)
|
||||
@@ -899,7 +942,7 @@ bool CCompositor::isWorkspaceVisible(const int& w) {
|
||||
if (m->activeWorkspace == w)
|
||||
return true;
|
||||
|
||||
if (m->specialWorkspaceOpen && w == SPECIAL_WORKSPACE_ID)
|
||||
if (m->specialWorkspaceID && isWorkspaceSpecial(w))
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -928,10 +971,8 @@ void CCompositor::sanityCheckWorkspaces() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((*it)->m_iID == SPECIAL_WORKSPACE_ID && WINDOWSONWORKSPACE == 0) {
|
||||
for (auto& m : m_vMonitors) {
|
||||
m->specialWorkspaceOpen = false;
|
||||
}
|
||||
if ((*it)->m_bIsSpecialWorkspace && WINDOWSONWORKSPACE == 0) {
|
||||
getMonitorFromID((*it)->m_iMonitorID)->specialWorkspaceID = 0;
|
||||
|
||||
it = m_vWorkspaces.erase(it);
|
||||
|
||||
@@ -1027,8 +1068,9 @@ void CCompositor::cleanupFadingOut(const int& monid) {
|
||||
|
||||
g_pHyprOpenGL->m_mWindowFramebuffers[w].release();
|
||||
g_pHyprOpenGL->m_mWindowFramebuffers.erase(w);
|
||||
w->m_bFadingOut = false;
|
||||
removeWindowFromVectorSafe(w);
|
||||
m_vWindowsFadingOut.erase(std::remove(m_vWindowsFadingOut.begin(), m_vWindowsFadingOut.end(), w));
|
||||
std::erase(m_vWindowsFadingOut, w);
|
||||
|
||||
Debug::log(LOG, "Cleanup: destroyed a window");
|
||||
|
||||
@@ -1127,6 +1169,10 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
|
||||
if (w.get() == pWindow || !w->m_bIsMapped || w->isHidden() || w->m_bIsFloating || !isWorkspaceVisible(w->m_iWorkspaceID))
|
||||
continue;
|
||||
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID);
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow && !w->m_bIsFullscreen && !w->m_bCreatedOverFullscreen)
|
||||
continue;
|
||||
|
||||
const auto BWINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved();
|
||||
|
||||
const auto POSB = Vector2D(BWINDOWIDEALBB.x, BWINDOWIDEALBB.y);
|
||||
@@ -1378,8 +1424,8 @@ void CCompositor::updateAllWindowsAnimatedDecorationValues() {
|
||||
|
||||
void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
|
||||
// optimization
|
||||
static int64_t* ACTIVECOL = &g_pConfigManager->getConfigValuePtr("general:col.active_border")->intValue;
|
||||
static int64_t* INACTIVECOL = &g_pConfigManager->getConfigValuePtr("general:col.inactive_border")->intValue;
|
||||
static auto *const ACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.active_border")->data.get();
|
||||
static auto *const INACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.inactive_border")->data.get();
|
||||
static auto *const PINACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:inactive_opacity")->floatValue;
|
||||
static auto *const PACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:active_opacity")->floatValue;
|
||||
static auto *const PFULLSCREENALPHA = &g_pConfigManager->getConfigValuePtr("decoration:fullscreen_opacity")->floatValue;
|
||||
@@ -1387,12 +1433,25 @@ void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
|
||||
static auto *const PSHADOWCOLINACTIVE = &g_pConfigManager->getConfigValuePtr("decoration:col.shadow_inactive")->intValue;
|
||||
static auto *const PDIMSTRENGTH = &g_pConfigManager->getConfigValuePtr("decoration:dim_strength")->floatValue;
|
||||
|
||||
auto setBorderColor = [&] (CGradientValueData grad) -> void {
|
||||
|
||||
if (grad == pWindow->m_cRealBorderColor)
|
||||
return;
|
||||
|
||||
pWindow->m_cRealBorderColorPrevious = pWindow->m_cRealBorderColor;
|
||||
pWindow->m_cRealBorderColor = grad;
|
||||
pWindow->m_fBorderAnimationProgress.setValueAndWarp(0.f);
|
||||
pWindow->m_fBorderAnimationProgress = 1.f;
|
||||
};
|
||||
|
||||
// border
|
||||
const auto RENDERDATA = g_pLayoutManager->getCurrentLayout()->requestRenderHints(pWindow);
|
||||
if (RENDERDATA.isBorderColor)
|
||||
pWindow->m_cRealBorderColor = RENDERDATA.borderColor;
|
||||
setBorderColor(RENDERDATA.borderColor * (1.f / 255.f));
|
||||
else
|
||||
pWindow->m_cRealBorderColor = CColor(pWindow == m_pLastWindow ? *ACTIVECOL : *INACTIVECOL);
|
||||
setBorderColor(pWindow == m_pLastWindow ?
|
||||
(pWindow->m_sSpecialRenderData.activeBorderColor >= 0 ? CGradientValueData(CColor(pWindow->m_sSpecialRenderData.activeBorderColor) * (1.f / 255.f)) : *ACTIVECOL) :
|
||||
(pWindow->m_sSpecialRenderData.inactiveBorderColor >= 0 ? CGradientValueData(CColor(pWindow->m_sSpecialRenderData.inactiveBorderColor) * (1.f / 255.f)) : *INACTIVECOL));
|
||||
|
||||
|
||||
// opacity
|
||||
@@ -1513,7 +1572,40 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
|
||||
}
|
||||
|
||||
CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
|
||||
if (isNumber(name)) {
|
||||
if (name[0] == '+' || name[0] == '-') {
|
||||
// relative
|
||||
const auto OFFSET = name[0] == '-' ? name : name.substr(1);
|
||||
|
||||
if (!isNumber(OFFSET)) {
|
||||
Debug::log(ERR, "Error in getMonitorFromString: Not a number in relative.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int offsetLeft = std::stoi(OFFSET) % m_vMonitors.size(); // no need to cycle more
|
||||
|
||||
int currentPlace = 0;
|
||||
for (int i = 0; i < (int)m_vMonitors.size(); i++) {
|
||||
if (m_vMonitors[i].get() == m_pLastMonitor) {
|
||||
currentPlace = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
currentPlace += offsetLeft;
|
||||
|
||||
if (currentPlace < 0) {
|
||||
currentPlace = m_vMonitors.size() - currentPlace;
|
||||
} else {
|
||||
currentPlace = currentPlace % m_vMonitors.size();
|
||||
}
|
||||
|
||||
if (currentPlace != std::clamp(currentPlace, 0, (int)m_vMonitors.size())) {
|
||||
Debug::log(WARN, "Error in getMonitorFromString: Vaxry's code sucks.");
|
||||
currentPlace = std::clamp(currentPlace, 0, (int)m_vMonitors.size());
|
||||
}
|
||||
|
||||
return m_vMonitors[currentPlace].get();
|
||||
} else if (isNumber(name)) {
|
||||
// change by ID
|
||||
int monID = -1;
|
||||
try {
|
||||
@@ -1639,7 +1731,7 @@ bool CCompositor::workspaceIDOutOfBounds(const int& id) {
|
||||
int highestID = -99999;
|
||||
|
||||
for (auto& w : m_vWorkspaces) {
|
||||
if (w->m_iID == SPECIAL_WORKSPACE_ID)
|
||||
if (w->m_bIsSpecialWorkspace)
|
||||
continue;
|
||||
|
||||
if (w->m_iID < lowestID)
|
||||
@@ -1674,6 +1766,9 @@ void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode
|
||||
|
||||
g_pXWaylandManager->setWindowFullscreen(pWindow, pWindow->m_bIsFullscreen && mode == FULLSCREEN_FULL);
|
||||
|
||||
pWindow->updateDynamicRules();
|
||||
g_pCompositor->updateWindowAnimatedDecorationValues(pWindow);
|
||||
|
||||
// make all windows on the same workspace under the fullscreen window
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID) {
|
||||
@@ -1691,6 +1786,11 @@ void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode
|
||||
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv(), true);
|
||||
|
||||
forceReportSizesToWindowsOnWorkspace(pWindow->m_iWorkspaceID);
|
||||
|
||||
g_pInputManager->recheckIdleInhibitorStatus();
|
||||
|
||||
// DMAbuf stuff for direct scanout
|
||||
g_pHyprRenderer->setWindowScanoutMode(pWindow);
|
||||
}
|
||||
|
||||
void CCompositor::moveUnmanagedX11ToWindows(CWindow* pWindow) {
|
||||
@@ -1731,6 +1831,9 @@ void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor) {
|
||||
if ((m_sWLRSession && !m_sWLRSession->active) || !m_bSessionActive)
|
||||
return;
|
||||
|
||||
if (!pMonitor->m_bEnabled)
|
||||
return;
|
||||
|
||||
wlr_output_schedule_frame(pMonitor->output);
|
||||
}
|
||||
|
||||
@@ -1803,7 +1906,7 @@ void CCompositor::warpCursorTo(const Vector2D& pos) {
|
||||
|
||||
const auto PMONITORNEW = getMonitorFromVector(pos);
|
||||
if (PMONITORNEW != m_pLastMonitor)
|
||||
m_pLastMonitor = PMONITORNEW;
|
||||
setActiveMonitor(PMONITORNEW);
|
||||
}
|
||||
|
||||
SLayerSurface* CCompositor::getLayerSurfaceFromWlr(wlr_layer_surface_v1* pLS) {
|
||||
@@ -1905,10 +2008,12 @@ CWorkspace* CCompositor::createNewWorkspace(const int& id, const int& monid, con
|
||||
monID = PMONITOR->ID;
|
||||
}
|
||||
|
||||
const auto PWORKSPACE = m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(monID, NAME, id == SPECIAL_WORKSPACE_ID)).get();
|
||||
const bool SPECIAL = id >= SPECIAL_WORKSPACE_START && id <= -2;
|
||||
|
||||
const auto PWORKSPACE = m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(monID, NAME, SPECIAL)).get();
|
||||
|
||||
// We are required to set the name here immediately
|
||||
if (id != SPECIAL_WORKSPACE_ID)
|
||||
if (!SPECIAL)
|
||||
wlr_ext_workspace_handle_v1_set_name(PWORKSPACE->m_pWlrHandle, NAME.c_str());
|
||||
|
||||
PWORKSPACE->m_iID = id;
|
||||
@@ -1916,3 +2021,33 @@ CWorkspace* CCompositor::createNewWorkspace(const int& id, const int& monid, con
|
||||
|
||||
return PWORKSPACE;
|
||||
}
|
||||
|
||||
void CCompositor::setActiveMonitor(CMonitor* pMonitor) {
|
||||
if (m_pLastMonitor == pMonitor)
|
||||
return;
|
||||
|
||||
if (!pMonitor) {
|
||||
m_pLastMonitor = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto PWORKSPACE = getWorkspaceByID(pMonitor->activeWorkspace);
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", pMonitor->szName + "," + PWORKSPACE->m_szName});
|
||||
m_pLastMonitor = pMonitor;
|
||||
}
|
||||
|
||||
bool CCompositor::isWorkspaceSpecial(const int& id) {
|
||||
return id >= SPECIAL_WORKSPACE_START && id <= -2;
|
||||
}
|
||||
|
||||
int CCompositor::getNewSpecialID() {
|
||||
int highest = -100;
|
||||
for (auto& ws : m_vWorkspaces) {
|
||||
if (ws->m_bIsSpecialWorkspace && ws->m_iID > highest) {
|
||||
highest = ws->m_iID;
|
||||
}
|
||||
}
|
||||
|
||||
return highest + 1;
|
||||
}
|
||||
|
@@ -15,6 +15,7 @@
|
||||
#include "managers/KeybindManager.hpp"
|
||||
#include "managers/AnimationManager.hpp"
|
||||
#include "managers/EventManager.hpp"
|
||||
#include "managers/ProtocolManager.hpp"
|
||||
#include "debug/HyprDebugOverlay.hpp"
|
||||
#include "helpers/Monitor.hpp"
|
||||
#include "helpers/Workspace.hpp"
|
||||
@@ -70,10 +71,12 @@ public:
|
||||
wlr_input_method_manager_v2* m_sWLRIMEMgr;
|
||||
wlr_text_input_manager_v3* m_sWLRTextInputMgr;
|
||||
wlr_xdg_activation_v1* m_sWLRActivation;
|
||||
wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf;
|
||||
wlr_backend* m_sWLRHeadlessBackend;
|
||||
// ------------------------------------------------- //
|
||||
|
||||
|
||||
const char* m_szWLDisplaySocket;
|
||||
std::string m_szWLDisplaySocket = "";
|
||||
std::string m_szInstanceSignature = "";
|
||||
std::string m_szCurrentSplash = "error";
|
||||
|
||||
@@ -124,6 +127,7 @@ public:
|
||||
CMonitor* getMonitorFromOutput(wlr_output*);
|
||||
CWindow* getWindowForPopup(wlr_xdg_popup*);
|
||||
CWindow* getWindowFromSurface(wlr_surface*);
|
||||
CWindow* getWindowFromHandle(uint32_t);
|
||||
bool isWorkspaceVisible(const int&);
|
||||
CWorkspace* getWorkspaceByID(const int&);
|
||||
CWorkspace* getWorkspaceByName(const std::string&);
|
||||
@@ -167,6 +171,9 @@ public:
|
||||
void forceReportSizesToWindowsOnWorkspace(const int&);
|
||||
bool cursorOnReservedArea();
|
||||
CWorkspace* createNewWorkspace(const int&, const int&, const std::string& name = ""); // will be deleted next frame if left empty and unfocused!
|
||||
void setActiveMonitor(CMonitor*);
|
||||
bool isWorkspaceSpecial(const int&);
|
||||
int getNewSpecialID();
|
||||
|
||||
std::string explicitConfigPath;
|
||||
|
||||
|
130
src/Window.cpp
130
src/Window.cpp
@@ -3,9 +3,9 @@
|
||||
#include "render/decorations/CHyprDropShadowDecoration.hpp"
|
||||
|
||||
CWindow::CWindow() {
|
||||
m_vRealPosition.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*) this, AVARDAMAGE_ENTIRE);
|
||||
m_vRealPosition.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||
m_vRealSize.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||
m_cRealBorderColor.create(AVARTYPE_COLOR, g_pConfigManager->getAnimationPropertyConfig("border"), (void*)this, AVARDAMAGE_BORDER);
|
||||
m_fBorderAnimationProgress.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("border"), (void*)this, AVARDAMAGE_BORDER);
|
||||
m_fAlpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||
m_fActiveInactiveAlpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||
m_cRealShadowColor.create(AVARTYPE_COLOR, g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), (void*)this, AVARDAMAGE_SHADOW);
|
||||
@@ -59,6 +59,13 @@ wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
|
||||
auto POS = m_vPosition;
|
||||
auto SIZE = m_vSize;
|
||||
|
||||
if (m_bIsFullscreen) {
|
||||
POS = PMONITOR->vecPosition;
|
||||
SIZE = PMONITOR->vecSize;
|
||||
|
||||
return wlr_box{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y};
|
||||
}
|
||||
|
||||
if (DELTALESSTHAN(POS.y - PMONITOR->vecPosition.y, PMONITOR->vecReservedTopLeft.y, 1)) {
|
||||
POS.y = PMONITOR->vecPosition.y;
|
||||
SIZE.y += PMONITOR->vecReservedTopLeft.y;
|
||||
@@ -245,19 +252,132 @@ void CWindow::removeDecorationByType(eDecorationType type) {
|
||||
updateWindowDecos();
|
||||
}
|
||||
|
||||
void unregisterVar(void* ptr) {
|
||||
((CAnimatedVariable*)ptr)->unregister();
|
||||
}
|
||||
|
||||
void CWindow::onUnmap() {
|
||||
if (g_pCompositor->m_pLastWindow == this)
|
||||
g_pCompositor->m_pLastWindow = nullptr;
|
||||
|
||||
m_vRealPosition.setCallbackOnEnd(unregisterVar);
|
||||
m_vRealSize.setCallbackOnEnd(unregisterVar);
|
||||
m_fBorderAnimationProgress.setCallbackOnEnd(unregisterVar);
|
||||
m_fActiveInactiveAlpha.setCallbackOnEnd(unregisterVar);
|
||||
m_fAlpha.setCallbackOnEnd(unregisterVar);
|
||||
m_cRealShadowColor.setCallbackOnEnd(unregisterVar);
|
||||
m_fDimPercent.setCallbackOnEnd(unregisterVar);
|
||||
|
||||
m_vRealSize.setCallbackOnBegin(nullptr);
|
||||
}
|
||||
|
||||
void CWindow::onMap() {
|
||||
|
||||
// JIC, reset the callbacks. If any are set, we'll make sure they are cleared so we don't accidentally unset them. (In case a window got remapped)
|
||||
m_vRealPosition.resetAllCallbacks();
|
||||
m_vRealSize.resetAllCallbacks();
|
||||
m_fBorderAnimationProgress.resetAllCallbacks();
|
||||
m_fActiveInactiveAlpha.resetAllCallbacks();
|
||||
m_fAlpha.resetAllCallbacks();
|
||||
m_cRealShadowColor.resetAllCallbacks();
|
||||
m_fDimPercent.resetAllCallbacks();
|
||||
|
||||
m_vRealPosition.registerVar();
|
||||
m_vRealSize.registerVar();
|
||||
m_fBorderAnimationProgress.registerVar();
|
||||
m_fActiveInactiveAlpha.registerVar();
|
||||
m_fAlpha.registerVar();
|
||||
m_cRealShadowColor.registerVar();
|
||||
m_fDimPercent.registerVar();
|
||||
|
||||
m_vRealSize.setCallbackOnEnd([&] (void* ptr) {
|
||||
g_pHyprOpenGL->onWindowResizeEnd(this);
|
||||
}, false);
|
||||
m_vRealSize.setCallbackOnBegin([&] (void* ptr) {
|
||||
g_pHyprOpenGL->onWindowResizeStart(this);
|
||||
}, false);
|
||||
}
|
||||
|
||||
void CWindow::setHidden(bool hidden) {
|
||||
m_bHidden = hidden;
|
||||
|
||||
if (hidden) {
|
||||
onUnmap();
|
||||
if (hidden && g_pCompositor->m_pLastWindow == this) {
|
||||
g_pCompositor->m_pLastWindow = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool CWindow::isHidden() {
|
||||
return m_bHidden;
|
||||
}
|
||||
}
|
||||
|
||||
void CWindow::applyDynamicRule(const SWindowRule& r) {
|
||||
if (r.szRule == "noblur") {
|
||||
m_sAdditionalConfigData.forceNoBlur = true;
|
||||
} else if (r.szRule == "noborder") {
|
||||
m_sAdditionalConfigData.forceNoBorder = true;
|
||||
} else if (r.szRule == "noshadow") {
|
||||
m_sAdditionalConfigData.forceNoShadow = true;
|
||||
} else if (r.szRule == "opaque") {
|
||||
if (!m_sAdditionalConfigData.forceOpaqueOverriden)
|
||||
m_sAdditionalConfigData.forceOpaque = true;
|
||||
} else if (r.szRule.find("rounding") == 0) {
|
||||
try {
|
||||
m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
|
||||
} catch (std::exception& e) {
|
||||
Debug::log(ERR, "Rounding rule \"%s\" failed with: %s", r.szRule.c_str(), e.what());
|
||||
}
|
||||
} else if (r.szRule.find("opacity") == 0) {
|
||||
try {
|
||||
std::string alphaPart = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
|
||||
|
||||
if (alphaPart.contains(' ')) {
|
||||
// we have a space, 2 values
|
||||
m_sSpecialRenderData.alpha = std::stof(alphaPart.substr(0, alphaPart.find_first_of(' ')));
|
||||
m_sSpecialRenderData.alphaInactive = std::stof(alphaPart.substr(alphaPart.find_first_of(' ') + 1));
|
||||
} else {
|
||||
m_sSpecialRenderData.alpha = std::stof(alphaPart);
|
||||
}
|
||||
} catch(std::exception& e) {
|
||||
Debug::log(ERR, "Opacity rule \"%s\" failed with: %s", r.szRule.c_str(), e.what());
|
||||
}
|
||||
} else if (r.szRule == "noanim") {
|
||||
m_sAdditionalConfigData.forceNoAnims = true;
|
||||
} else if (r.szRule.find("animation") == 0) {
|
||||
auto STYLE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
|
||||
m_sAdditionalConfigData.animationStyle = STYLE;
|
||||
} else if (r.szRule.find("bordercolor") == 0) {
|
||||
try {
|
||||
std::string colorPart = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
|
||||
|
||||
if (colorPart.contains(' ')) {
|
||||
// we have a space, 2 values
|
||||
m_sSpecialRenderData.activeBorderColor = configStringToInt(colorPart.substr(0, colorPart.find_first_of(' ')));
|
||||
m_sSpecialRenderData.inactiveBorderColor = configStringToInt(colorPart.substr(colorPart.find_first_of(' ') + 1));
|
||||
} else {
|
||||
m_sSpecialRenderData.activeBorderColor = configStringToInt(colorPart);
|
||||
}
|
||||
} catch(std::exception& e) {
|
||||
Debug::log(ERR, "BorderColor rule \"%s\" failed with: %s", r.szRule.c_str(), e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CWindow::updateDynamicRules() {
|
||||
m_sSpecialRenderData.activeBorderColor = -1;
|
||||
m_sSpecialRenderData.inactiveBorderColor = -1;
|
||||
m_sSpecialRenderData.alpha = 1.f;
|
||||
m_sSpecialRenderData.alphaInactive = -1.f;
|
||||
m_sAdditionalConfigData.forceNoBlur = false;
|
||||
m_sAdditionalConfigData.forceNoBorder = false;
|
||||
m_sAdditionalConfigData.forceNoShadow = false;
|
||||
if (!m_sAdditionalConfigData.forceOpaqueOverriden)
|
||||
m_sAdditionalConfigData.forceOpaque = false;
|
||||
m_sAdditionalConfigData.forceNoAnims = false;
|
||||
m_sAdditionalConfigData.animationStyle = "";
|
||||
m_sAdditionalConfigData.rounding = -1;
|
||||
|
||||
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(this);
|
||||
for (auto& r : WINDOWRULES) {
|
||||
applyDynamicRule(r);
|
||||
}
|
||||
}
|
||||
|
@@ -6,11 +6,22 @@
|
||||
#include "helpers/AnimatedVariable.hpp"
|
||||
#include "render/decorations/IHyprWindowDecoration.hpp"
|
||||
#include <deque>
|
||||
#include "config/ConfigDataValues.hpp"
|
||||
|
||||
enum eIdleInhibitMode {
|
||||
IDLEINHIBIT_NONE = 0,
|
||||
IDLEINHIBIT_ALWAYS,
|
||||
IDLEINHIBIT_FULLSCREEN,
|
||||
IDLEINHIBIT_FOCUS
|
||||
};
|
||||
|
||||
struct SWindowSpecialRenderData {
|
||||
float alpha = 1.f;
|
||||
float alphaInactive = -1.f; // -1 means unset
|
||||
|
||||
int64_t activeBorderColor = -1; // -1 means unset
|
||||
int64_t inactiveBorderColor = -1; // -1 means unset
|
||||
|
||||
// set by the layout
|
||||
bool rounding = true;
|
||||
bool border = true;
|
||||
@@ -22,11 +33,26 @@ struct SWindowAdditionalConfigData {
|
||||
int rounding = -1; // -1 means no
|
||||
bool forceNoBlur = false;
|
||||
bool forceOpaque = false;
|
||||
bool forceOpaqueOverriden = false; // if true, a rule will not change the forceOpaque state. This is for the force opaque dispatcher.
|
||||
bool forceAllowsInput = false;
|
||||
bool forceNoAnims = false;
|
||||
bool forceNoBorder = false;
|
||||
bool forceNoShadow = false;
|
||||
bool windowDanceCompat = false;
|
||||
bool noMaxSize = false;
|
||||
};
|
||||
|
||||
struct SWindowRule {
|
||||
std::string szRule;
|
||||
std::string szValue;
|
||||
|
||||
bool v2 = false;
|
||||
std::string szTitle;
|
||||
std::string szClass;
|
||||
int bX11 = -1; // -1 means "ANY"
|
||||
int bFloating = -1;
|
||||
int bFullscreen = -1;
|
||||
int bPinned = -1;
|
||||
};
|
||||
|
||||
class CWindow {
|
||||
@@ -106,13 +132,16 @@ public:
|
||||
bool m_bNoFocus = false;
|
||||
bool m_bNoInitialFocus = false;
|
||||
|
||||
// initial fullscreen
|
||||
// initial fullscreen and fullscreen disabled
|
||||
bool m_bWantsInitialFullscreen = false;
|
||||
bool m_bNoFullscreenRequest = false;
|
||||
|
||||
SSurfaceTreeNode* m_pSurfaceTree = nullptr;
|
||||
|
||||
// Animated border
|
||||
CAnimatedVariable m_cRealBorderColor;
|
||||
CGradientValueData m_cRealBorderColor = {0};
|
||||
CGradientValueData m_cRealBorderColorPrevious = {0};
|
||||
CAnimatedVariable m_fBorderAnimationProgress;
|
||||
|
||||
// Fade in-out
|
||||
CAnimatedVariable m_fAlpha;
|
||||
@@ -154,6 +183,9 @@ public:
|
||||
uint64_t m_iLastToplevelMonitorID = -1;
|
||||
uint64_t m_iLastSurfaceMonitorID = -1;
|
||||
|
||||
// for idle inhibiting windows
|
||||
eIdleInhibitMode m_eIdleInhibitMode = IDLEINHIBIT_NONE;
|
||||
|
||||
// For the list lookup
|
||||
bool operator==(const CWindow& rhs) {
|
||||
return m_uSurface.xdg == rhs.m_uSurface.xdg && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && m_bFadingOut == rhs.m_bFadingOut;
|
||||
@@ -173,8 +205,11 @@ public:
|
||||
void moveToWorkspace(int);
|
||||
CWindow* X11TransientFor();
|
||||
void onUnmap();
|
||||
void onMap();
|
||||
void setHidden(bool hidden);
|
||||
bool isHidden();
|
||||
void applyDynamicRule(const SWindowRule& r);
|
||||
void updateDynamicRules();
|
||||
|
||||
private:
|
||||
// For hidden windows and stuff
|
||||
|
48
src/config/ConfigDataValues.hpp
Normal file
48
src/config/ConfigDataValues.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
#include "../defines.hpp"
|
||||
|
||||
enum eConfigValueDataTypes {
|
||||
CVD_TYPE_INVALID = -1,
|
||||
CVD_TYPE_GRADIENT = 0
|
||||
};
|
||||
|
||||
interface ICustomConfigValueData {
|
||||
public:
|
||||
virtual ~ICustomConfigValueData() = 0;
|
||||
|
||||
virtual eConfigValueDataTypes getDataType() = 0;
|
||||
};
|
||||
|
||||
class CGradientValueData : public ICustomConfigValueData {
|
||||
public:
|
||||
CGradientValueData(CColor col) {
|
||||
m_vColors.push_back(col);
|
||||
};
|
||||
virtual ~CGradientValueData() { };
|
||||
|
||||
virtual eConfigValueDataTypes getDataType() {
|
||||
return CVD_TYPE_GRADIENT;
|
||||
}
|
||||
|
||||
void reset(CColor col) {
|
||||
m_vColors.clear();
|
||||
m_vColors.emplace_back(col);
|
||||
m_fAngle = 0;
|
||||
}
|
||||
|
||||
/* Vector containing the colors */
|
||||
std::vector<CColor> m_vColors;
|
||||
|
||||
/* Float corresponding to the angle (rad) */
|
||||
float m_fAngle = 0;
|
||||
|
||||
bool operator==(const CGradientValueData& other) {
|
||||
if (other.m_vColors.size() != m_vColors.size() || m_fAngle != other.m_fAngle)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < m_vColors.size(); ++i)
|
||||
if (m_vColors[i] != other.m_vColors[i]) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
@@ -11,6 +11,9 @@
|
||||
#include <iostream>
|
||||
|
||||
CConfigManager::CConfigManager() {
|
||||
configValues["general:col.active_border"].data = std::make_shared<CGradientValueData>(0xffffffff);
|
||||
configValues["general:col.inactive_border"].data = std::make_shared<CGradientValueData>(0xff444444);
|
||||
|
||||
setDefaultVars();
|
||||
setDefaultAnimationVars();
|
||||
|
||||
@@ -35,15 +38,12 @@ void CConfigManager::setDefaultVars() {
|
||||
configValues["general:main_mod"].strValue = "SUPER"; // exposed to the user for easier configuring
|
||||
configValues["general:main_mod_internal"].intValue = g_pKeybindManager->stringToModMask("SUPER"); // actually used and automatically calculated
|
||||
|
||||
configValues["general:damage_tracking"].strValue = "full";
|
||||
configValues["general:damage_tracking_internal"].intValue = DAMAGE_TRACKING_FULL;
|
||||
|
||||
configValues["general:border_size"].intValue = 1;
|
||||
configValues["general:no_border_on_floating"].intValue = 0;
|
||||
configValues["general:gaps_in"].intValue = 5;
|
||||
configValues["general:gaps_out"].intValue = 20;
|
||||
configValues["general:col.active_border"].intValue = 0xffffffff;
|
||||
configValues["general:col.inactive_border"].intValue = 0xff444444;
|
||||
((CGradientValueData*)configValues["general:col.active_border"].data.get())->reset(0xffffffff);
|
||||
((CGradientValueData*)configValues["general:col.inactive_border"].data.get())->reset(0xff444444);
|
||||
configValues["general:cursor_inactive_timeout"].intValue = 0;
|
||||
configValues["general:no_cursor_warps"].intValue = 0;
|
||||
|
||||
@@ -61,6 +61,7 @@ void CConfigManager::setDefaultVars() {
|
||||
configValues["misc:enable_swallow"].intValue = 0;
|
||||
configValues["misc:swallow_regex"].strValue = STRVAL_EMPTY;
|
||||
configValues["misc:focus_on_activate"].intValue = 0;
|
||||
configValues["misc:no_direct_scanout"].intValue = 0;
|
||||
|
||||
configValues["debug:int"].intValue = 0;
|
||||
configValues["debug:log_damage"].intValue = 0;
|
||||
@@ -68,13 +69,15 @@ void CConfigManager::setDefaultVars() {
|
||||
configValues["debug:damage_blink"].intValue = 0;
|
||||
configValues["debug:disable_logs"].intValue = 0;
|
||||
configValues["debug:disable_time"].intValue = 1;
|
||||
configValues["debug:damage_tracking"].intValue = DAMAGE_TRACKING_FULL;
|
||||
|
||||
configValues["decoration:rounding"].intValue = 0;
|
||||
configValues["decoration:blur"].intValue = 1;
|
||||
configValues["decoration:blur_size"].intValue = 8;
|
||||
configValues["decoration:blur_passes"].intValue = 1;
|
||||
configValues["decoration:blur_ignore_opacity"].intValue = 0;
|
||||
configValues["decoration:blur_new_optimizations"].intValue = 0;
|
||||
configValues["decoration:blur_new_optimizations"].intValue = 1;
|
||||
configValues["decoration:blur_xray"].intValue = 0;
|
||||
configValues["decoration:active_opacity"].floatValue = 1;
|
||||
configValues["decoration:inactive_opacity"].floatValue = 1;
|
||||
configValues["decoration:fullscreen_opacity"].floatValue = 1;
|
||||
@@ -85,10 +88,12 @@ void CConfigManager::setDefaultVars() {
|
||||
configValues["decoration:shadow_render_power"].intValue = 3;
|
||||
configValues["decoration:shadow_ignore_window"].intValue = 1;
|
||||
configValues["decoration:shadow_offset"].vecValue = Vector2D();
|
||||
configValues["decoration:shadow_scale"].floatValue = 1.f;
|
||||
configValues["decoration:col.shadow"].intValue = 0xee1a1a1a;
|
||||
configValues["decoration:col.shadow_inactive"].intValue = INT_MAX;
|
||||
configValues["decoration:dim_inactive"].intValue = 0;
|
||||
configValues["decoration:dim_strength"].floatValue = 0.5f;
|
||||
configValues["decoration:screen_shader"].strValue = STRVAL_EMPTY;
|
||||
|
||||
configValues["dwindle:pseudotile"].intValue = 0;
|
||||
configValues["dwindle:col.group_border"].intValue = 0x66777700;
|
||||
@@ -141,6 +146,7 @@ void CConfigManager::setDefaultVars() {
|
||||
configValues["input:float_switch_override_focus"].intValue = 1;
|
||||
configValues["input:left_handed"].intValue = 0;
|
||||
configValues["input:scroll_method"].strValue = STRVAL_EMPTY;
|
||||
configValues["input:scroll_button"].intValue = 0;
|
||||
configValues["input:touchpad:natural_scroll"].intValue = 0;
|
||||
configValues["input:touchpad:disable_while_typing"].intValue = 1;
|
||||
configValues["input:touchpad:clickfinger_behavior"].intValue = 0;
|
||||
@@ -163,6 +169,7 @@ void CConfigManager::setDefaultVars() {
|
||||
configValues["gestures:workspace_swipe_min_speed_to_force"].intValue = 30;
|
||||
configValues["gestures:workspace_swipe_cancel_ratio"].floatValue = 0.5f;
|
||||
configValues["gestures:workspace_swipe_create_new"].intValue = 1;
|
||||
configValues["gestures:workspace_swipe_forever"].intValue = 0;
|
||||
|
||||
configValues["input:follow_mouse"].intValue = 1;
|
||||
|
||||
@@ -191,6 +198,7 @@ void CConfigManager::setDeviceDefaultVars(const std::string& dev) {
|
||||
cfgValues["drag_lock"].intValue = 0;
|
||||
cfgValues["left_handed"].intValue = 0;
|
||||
cfgValues["scroll_method"].strValue = STRVAL_EMPTY;
|
||||
cfgValues["scroll_button"].intValue = 0;
|
||||
cfgValues["touch_transform"].intValue = 0;
|
||||
cfgValues["touch_output"].strValue = STRVAL_EMPTY;
|
||||
cfgValues["enabled"].intValue = 1; // only for mice / touchpads
|
||||
@@ -310,45 +318,10 @@ void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::s
|
||||
|
||||
if (CONFIGENTRY->intValue != -INT64_MAX) {
|
||||
try {
|
||||
if (VALUE.find("0x") == 0) {
|
||||
// Values with 0x are hex
|
||||
const auto VALUEWITHOUTHEX = VALUE.substr(2);
|
||||
CONFIGENTRY->intValue = stol(VALUEWITHOUTHEX, nullptr, 16);
|
||||
} else if (VALUE.find("rgba(") == 0 && VALUE.find(")") == VALUE.length() - 1) {
|
||||
const auto VALUEWITHOUTFUNC = VALUE.substr(5, VALUE.length() - 6);
|
||||
|
||||
if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 8) {
|
||||
Debug::log(WARN, "invalid length %i for rgba", VALUEWITHOUTFUNC.length());
|
||||
parseError = "rgba() expects length of 8 characters (4 bytes)";
|
||||
return;
|
||||
}
|
||||
|
||||
const auto RGBA = std::stol(VALUEWITHOUTFUNC, nullptr, 16);
|
||||
|
||||
// now we need to RGBA -> ARGB. The config holds ARGB only.
|
||||
CONFIGENTRY->intValue = (RGBA >> 8) + 0x1000000 * (RGBA & 0xFF);
|
||||
} else if (VALUE.find("rgb(") == 0 && VALUE.find(")") == VALUE.length() - 1) {
|
||||
const auto VALUEWITHOUTFUNC = VALUE.substr(4, VALUE.length() - 5);
|
||||
|
||||
if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 6) {
|
||||
Debug::log(WARN, "invalid length %i for rgb", VALUEWITHOUTFUNC.length());
|
||||
parseError = "rgb() expects length of 6 characters (3 bytes)";
|
||||
return;
|
||||
}
|
||||
|
||||
const auto RGB = std::stol(VALUEWITHOUTFUNC, nullptr, 16);
|
||||
|
||||
CONFIGENTRY->intValue = RGB + 0xFF000000; // 0xFF for opaque
|
||||
} else if (VALUE.find("true") == 0 || VALUE.find("on") == 0 || VALUE.find("yes") == 0) {
|
||||
CONFIGENTRY->intValue = 1;
|
||||
} else if (VALUE.find("false") == 0 || VALUE.find("off") == 0 || VALUE.find("no") == 0) {
|
||||
CONFIGENTRY->intValue = 0;
|
||||
}
|
||||
else
|
||||
CONFIGENTRY->intValue = stol(VALUE);
|
||||
} catch (...) {
|
||||
CONFIGENTRY->intValue = configStringToInt(VALUE);
|
||||
} catch (std::exception& e) {
|
||||
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
|
||||
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
|
||||
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">. " + e.what();
|
||||
}
|
||||
} else if (CONFIGENTRY->floatValue != -__FLT_MAX__) {
|
||||
try {
|
||||
@@ -381,67 +354,77 @@ void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::s
|
||||
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
|
||||
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
|
||||
}
|
||||
} else if (CONFIGENTRY->data.get() != nullptr) {
|
||||
|
||||
switch (CONFIGENTRY->data->getDataType()) {
|
||||
case CVD_TYPE_GRADIENT: {
|
||||
|
||||
CVarList varlist(VALUE, 0, ' ');
|
||||
|
||||
CGradientValueData* data = (CGradientValueData*)CONFIGENTRY->data.get();
|
||||
data->m_vColors.clear();
|
||||
|
||||
for (auto& var : varlist) {
|
||||
if (var.find("deg") != std::string::npos) {
|
||||
// last arg
|
||||
try {
|
||||
data->m_fAngle = std::stoi(var.substr(0, var.find("deg"))) * (PI / 180.0); // radians
|
||||
} catch (...) {
|
||||
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
|
||||
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (data->m_vColors.size() >= 10) {
|
||||
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
|
||||
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">. Max colors in a gradient is 10.";
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
data->m_vColors.push_back(CColor(configStringToInt(var)) * (1.f / 255.f));
|
||||
} catch (std::exception& e) {
|
||||
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
|
||||
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">. " + e.what();
|
||||
}
|
||||
}
|
||||
|
||||
if (data->m_vColors.size() == 0) {
|
||||
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
|
||||
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">. No colors provided.";
|
||||
|
||||
data->m_vColors.push_back(0); // transparent
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (COMMAND == "decoration:screen_shader") {
|
||||
const auto PATH = absolutePath(VALUE, configCurrentPath);
|
||||
|
||||
configPaths.push_back(PATH);
|
||||
|
||||
struct stat fileStat;
|
||||
int err = stat(PATH.c_str(), &fileStat);
|
||||
if (err != 0) {
|
||||
Debug::log(WARN, "Error at ticking config at %s, error %i: %s", PATH.c_str(), err, strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
configModifyTimes[PATH] = fileStat.st_mtime;
|
||||
}
|
||||
}
|
||||
|
||||
void CConfigManager::handleRawExec(const std::string& command, const std::string& args) {
|
||||
// Exec in the background dont wait for it.
|
||||
|
||||
std::string toExec = args;
|
||||
|
||||
if (g_pXWaylandManager->m_sWLRXWayland)
|
||||
toExec = std::string("WAYLAND_DISPLAY=") + std::string(g_pCompositor->m_szWLDisplaySocket) + " DISPLAY=" + std::string(g_pXWaylandManager->m_sWLRXWayland->display_name) + " " + toExec;
|
||||
else
|
||||
toExec = std::string("WAYLAND_DISPLAY=") + std::string(g_pCompositor->m_szWLDisplaySocket) + " " + toExec;
|
||||
|
||||
Debug::log(LOG, "Config executing %s", toExec.c_str());
|
||||
|
||||
int socket[2];
|
||||
if (pipe(socket) != 0) {
|
||||
Debug::log(LOG, "Unable to create pipe for fork");
|
||||
}
|
||||
|
||||
pid_t child, grandchild;
|
||||
child = fork();
|
||||
if (child < 0) {
|
||||
close(socket[0]);
|
||||
close(socket[1]);
|
||||
Debug::log(LOG, "Fail to create the first fork");
|
||||
return;
|
||||
}
|
||||
if (child == 0) {
|
||||
// run in child
|
||||
grandchild = fork();
|
||||
|
||||
sigset_t set;
|
||||
sigemptyset(&set);
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
|
||||
if (grandchild == 0) {
|
||||
// run in grandchild
|
||||
close(socket[0]);
|
||||
close(socket[1]);
|
||||
execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr);
|
||||
// exit grandchild
|
||||
_exit(0);
|
||||
}
|
||||
close(socket[0]);
|
||||
write(socket[1], &grandchild, sizeof(grandchild));
|
||||
close(socket[1]);
|
||||
// exit child
|
||||
_exit(0);
|
||||
}
|
||||
// run in parent
|
||||
close(socket[1]);
|
||||
read(socket[0], &grandchild, sizeof(grandchild));
|
||||
close(socket[0]);
|
||||
// clear child and leave child to init
|
||||
waitpid(child, NULL, 0);
|
||||
if (child < 0) {
|
||||
Debug::log(LOG, "Fail to create the second fork");
|
||||
return;
|
||||
}
|
||||
Debug::log(LOG, "Process created with pid %d", grandchild);
|
||||
g_pKeybindManager->spawn(args);
|
||||
}
|
||||
|
||||
void CConfigManager::handleMonitor(const std::string& command, const std::string& args) {
|
||||
@@ -756,6 +739,7 @@ bool windowRuleValid(const std::string& RULE) {
|
||||
&& RULE.find("maxsize") != 0
|
||||
&& RULE.find("pseudo") != 0
|
||||
&& RULE.find("monitor") != 0
|
||||
&& RULE.find("idleinhibit") != 0
|
||||
&& RULE != "nofocus"
|
||||
&& RULE != "noblur"
|
||||
&& RULE != "noshadow"
|
||||
@@ -764,12 +748,15 @@ bool windowRuleValid(const std::string& RULE) {
|
||||
&& RULE != "opaque"
|
||||
&& RULE != "forceinput"
|
||||
&& RULE != "fullscreen"
|
||||
&& RULE != "nofullscreenrequest"
|
||||
&& RULE != "nomaxsize"
|
||||
&& RULE != "pin"
|
||||
&& RULE != "noanim"
|
||||
&& RULE != "windowdance"
|
||||
&& RULE.find("animation") != 0
|
||||
&& RULE.find("rounding") != 0
|
||||
&& RULE.find("workspace") != 0);
|
||||
&& RULE.find("workspace") != 0
|
||||
&& RULE.find("bordercolor") != 0);
|
||||
}
|
||||
|
||||
void CConfigManager::handleWindowRule(const std::string& command, const std::string& value) {
|
||||
@@ -781,6 +768,13 @@ void CConfigManager::handleWindowRule(const std::string& command, const std::str
|
||||
return;
|
||||
}
|
||||
|
||||
if (RULE == "unset") {
|
||||
std::erase_if(m_dWindowRules, [&] (const SWindowRule& other) {
|
||||
return other.szValue == VALUE;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// verify we support a rule
|
||||
if (!windowRuleValid(RULE)) {
|
||||
Debug::log(ERR, "Invalid rule found: %s", RULE.c_str());
|
||||
@@ -795,7 +789,7 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
||||
const auto RULE = value.substr(0, value.find_first_of(","));
|
||||
const auto VALUE = value.substr(value.find_first_of(",") + 1);
|
||||
|
||||
if (!windowRuleValid(RULE)) {
|
||||
if (!windowRuleValid(RULE) && RULE != "unset") {
|
||||
Debug::log(ERR, "Invalid rulev2 found: %s", RULE.c_str());
|
||||
parseError = "Invalid rulev2 found: " + RULE;
|
||||
return;
|
||||
@@ -811,8 +805,12 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
||||
const auto CLASSPOS = VALUE.find("class:");
|
||||
const auto X11POS = VALUE.find("xwayland:");
|
||||
const auto FLOATPOS = VALUE.find("floating:");
|
||||
const auto FULLSCREENPOS = VALUE.find("fullscreen:");
|
||||
const auto PINNEDPOS = VALUE.find("pinned:");
|
||||
|
||||
if (TITLEPOS == std::string::npos && CLASSPOS == std::string::npos && X11POS == std::string::npos && FLOATPOS == std::string::npos) {
|
||||
if (TITLEPOS == std::string::npos && CLASSPOS == std::string::npos &&
|
||||
X11POS == std::string::npos && FLOATPOS == std::string::npos &&
|
||||
FULLSCREENPOS == std::string::npos && PINNEDPOS == std::string::npos) {
|
||||
Debug::log(ERR, "Invalid rulev2 syntax: %s", VALUE.c_str());
|
||||
parseError = "Invalid rulev2 syntax: " + VALUE;
|
||||
return;
|
||||
@@ -827,6 +825,8 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
||||
if (CLASSPOS > pos && CLASSPOS < min) min = CLASSPOS;
|
||||
if (X11POS > pos && X11POS < min) min = X11POS;
|
||||
if (FLOATPOS > pos && FLOATPOS < min) min = FLOATPOS;
|
||||
if (FULLSCREENPOS > pos && FULLSCREENPOS < min) min = FULLSCREENPOS;
|
||||
if (PINNEDPOS > pos && PINNEDPOS < min) min = PINNEDPOS;
|
||||
|
||||
result = result.substr(0, min - pos);
|
||||
|
||||
@@ -854,13 +854,56 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
||||
rule.bFloating = extract(FLOATPOS + 9) == "1" ? 1 : 0;
|
||||
}
|
||||
|
||||
if (FULLSCREENPOS != std::string::npos) {
|
||||
rule.bFullscreen = extract(FULLSCREENPOS + 11) == "1" ? 1 : 0;
|
||||
}
|
||||
|
||||
if (PINNEDPOS != std::string::npos) {
|
||||
rule.bPinned = extract(PINNEDPOS + 7) == "1" ? 1 : 0;
|
||||
}
|
||||
|
||||
if (RULE == "unset") {
|
||||
std::erase_if(m_dWindowRules, [&](const SWindowRule& other) {
|
||||
if (!other.v2) {
|
||||
return other.szClass == rule.szClass && !rule.szClass.empty();
|
||||
} else {
|
||||
if (!rule.szClass.empty() && rule.szClass != other.szClass) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!rule.szTitle.empty() && rule.szTitle != other.szTitle) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rule.bX11 != -1 && rule.bX11 != other.bX11) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rule.bFloating != -1 && rule.bFloating != other.bFloating) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rule.bFullscreen != -1 && rule.bFullscreen != other.bFullscreen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rule.bPinned != -1 && rule.bPinned != other.bPinned) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
m_dWindowRules.push_back(rule);
|
||||
}
|
||||
|
||||
void CConfigManager::handleBlurLS(const std::string& command, const std::string& value) {
|
||||
if (value.find("remove,") == 0) {
|
||||
const auto TOREMOVE = removeBeginEndSpacesTabs(value.substr(7));
|
||||
m_dBlurLSNamespaces.erase(std::remove(m_dBlurLSNamespaces.begin(), m_dBlurLSNamespaces.end(), TOREMOVE));
|
||||
std::erase_if(m_dBlurLSNamespaces, [&] (const auto& other) { return other == TOREMOVE; });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -958,6 +1001,8 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
|
||||
currentCategory = "";
|
||||
}
|
||||
|
||||
int needsLayoutRecalc = COMMAND == "monitor"; // 0 - no, 1 - yes, 2 - maybe
|
||||
|
||||
if (COMMAND == "exec") {
|
||||
if (isFirstLaunch) {
|
||||
firstExecRequests.push_back(VALUE);
|
||||
@@ -981,16 +1026,22 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
|
||||
else if (COMMAND == "submap") handleSubmap(COMMAND, VALUE);
|
||||
else if (COMMAND == "blurls") handleBlurLS(COMMAND, VALUE);
|
||||
else if (COMMAND == "wsbind") handleBindWS(COMMAND, VALUE);
|
||||
else
|
||||
else {
|
||||
configSetValueSafe(currentCategory + (currentCategory == "" ? "" : ":") + COMMAND, VALUE);
|
||||
needsLayoutRecalc = 2;
|
||||
}
|
||||
|
||||
if (dynamic) {
|
||||
std::string retval = parseError;
|
||||
parseError = "";
|
||||
|
||||
// invalidate layouts jic
|
||||
for (auto& m : g_pCompositor->m_vMonitors)
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
|
||||
// invalidate layouts if they changed
|
||||
if (needsLayoutRecalc) {
|
||||
if (needsLayoutRecalc == 1 || COMMAND.contains("gaps_") || COMMAND.find("dwindle:") == 0 || COMMAND.find("master:") == 0) {
|
||||
for (auto& m : g_pCompositor->m_vMonitors)
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
|
||||
}
|
||||
}
|
||||
|
||||
// Update window border colors
|
||||
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
|
||||
@@ -1036,7 +1087,7 @@ void CConfigManager::parseLine(std::string& line) {
|
||||
}
|
||||
|
||||
size_t startPos = 0;
|
||||
while ((startPos = line.find("##", startPos)) != std::string::npos) {
|
||||
while ((startPos = line.find("##", startPos)) != std::string::npos && startPos < line.length() - 1 && startPos > 0) {
|
||||
line.replace(startPos, 2, "#");
|
||||
startPos++;
|
||||
}
|
||||
@@ -1196,13 +1247,9 @@ void CConfigManager::loadConfigLoadVars() {
|
||||
|
||||
// Calculate the internal vars
|
||||
configValues["general:main_mod_internal"].intValue = g_pKeybindManager->stringToModMask(configValues["general:main_mod"].strValue);
|
||||
const auto DAMAGETRACKINGMODE = g_pHyprRenderer->damageTrackingModeFromStr(configValues["general:damage_tracking"].strValue);
|
||||
if (DAMAGETRACKINGMODE != DAMAGE_TRACKING_INVALID)
|
||||
configValues["general:damage_tracking_internal"].intValue = DAMAGETRACKINGMODE;
|
||||
else {
|
||||
parseError = "invalid value for general:damage_tracking, supported: full, monitor, none";
|
||||
configValues["general:damage_tracking_internal"].intValue = DAMAGE_TRACKING_NONE;
|
||||
}
|
||||
|
||||
if (!isFirstLaunch)
|
||||
g_pHyprOpenGL->m_bReloadScreenShader = true;
|
||||
|
||||
// parseError will be displayed next frame
|
||||
if (parseError != "")
|
||||
@@ -1217,9 +1264,8 @@ void CConfigManager::loadConfigLoadVars() {
|
||||
// and they'll be taken care of in the newMonitor event
|
||||
// ignore if nomonitorreload is set
|
||||
if (!isFirstLaunch && !m_bNoMonitorReload) {
|
||||
m_bWantsMonitorReload = true;
|
||||
|
||||
// check
|
||||
performMonitorReload();
|
||||
ensureDPMS();
|
||||
ensureVRR();
|
||||
}
|
||||
@@ -1288,13 +1334,10 @@ SConfigValue CConfigManager::getConfigValueSafe(const std::string& val) {
|
||||
SConfigValue CConfigManager::getConfigValueSafeDevice(const std::string& dev, const std::string& val) {
|
||||
std::lock_guard<std::mutex> lg(configmtx);
|
||||
|
||||
auto devcopy = dev;
|
||||
std::replace(devcopy.begin(), devcopy.end(), ' ', '-');
|
||||
|
||||
const auto it = deviceConfigs.find(devcopy);
|
||||
const auto it = deviceConfigs.find(dev);
|
||||
|
||||
if (it == deviceConfigs.end()) {
|
||||
Debug::log(ERR, "getConfigValueSafeDevice: No device config for %s found???", devcopy.c_str());
|
||||
Debug::log(ERR, "getConfigValueSafeDevice: No device config for %s found???", dev.c_str());
|
||||
return SConfigValue();
|
||||
}
|
||||
|
||||
@@ -1448,6 +1491,16 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
|
||||
if (pWindow->m_bIsFloating != rule.bFloating)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rule.bFullscreen != -1) {
|
||||
if (pWindow->m_bIsFullscreen != rule.bFullscreen)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rule.bPinned != -1) {
|
||||
if (pWindow->m_bPinned != rule.bPinned)
|
||||
continue;
|
||||
}
|
||||
} catch (...) {
|
||||
Debug::log(ERR, "Regex error at %s", rule.szValue.c_str());
|
||||
continue;
|
||||
@@ -1460,6 +1513,19 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
|
||||
returns.push_back(rule);
|
||||
}
|
||||
|
||||
const uint64_t PID = pWindow->getPID();
|
||||
bool anyExecFound = false;
|
||||
|
||||
for (auto& er : execRequestedRules) {
|
||||
if (er.iPid == PID) {
|
||||
returns.push_back({er.szRule, "execRule"});
|
||||
anyExecFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (anyExecFound) // remove exec rules to unclog searches in the future, why have the garbage here.
|
||||
execRequestedRules.erase(std::remove_if(execRequestedRules.begin(), execRequestedRules.end(), [&](const SExecRequestedRule& other) { return other.iPid == PID; }));
|
||||
|
||||
return returns;
|
||||
}
|
||||
|
||||
@@ -1493,20 +1559,23 @@ void CConfigManager::performMonitorReload() {
|
||||
for (auto& m : g_pCompositor->m_vRealMonitors) {
|
||||
auto rule = getMonitorRuleFor(m->szName, m->output->description ? m->output->description : "");
|
||||
|
||||
// ensure mirror
|
||||
m->setMirror(rule.mirrorOf);
|
||||
|
||||
if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule)) {
|
||||
overAgain = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// ensure mirror
|
||||
m->setMirror(rule.mirrorOf);
|
||||
|
||||
g_pHyprRenderer->arrangeLayersForMonitor(m->ID);
|
||||
}
|
||||
|
||||
if (overAgain)
|
||||
performMonitorReload();
|
||||
|
||||
if (!g_pCompositor->m_vMonitors.empty()) // reset unsafe state if we have monitors
|
||||
g_pCompositor->m_bUnsafeState = false;
|
||||
|
||||
m_bWantsMonitorReload = false;
|
||||
}
|
||||
|
||||
@@ -1603,6 +1672,8 @@ SAnimationPropertyConfig* CConfigManager::getAnimationPropertyConfig(const std::
|
||||
void CConfigManager::addParseError(const std::string& err) {
|
||||
if (parseError == "")
|
||||
parseError = err;
|
||||
|
||||
g_pHyprError->queueCreate(parseError + "\nHyprland may not work correctly.", CColor(255, 50, 50, 255));
|
||||
}
|
||||
|
||||
CMonitor* CConfigManager::getBoundMonitorForWS(std::string wsname) {
|
||||
@@ -1616,3 +1687,11 @@ CMonitor* CConfigManager::getBoundMonitorForWS(std::string wsname) {
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CConfigManager::addExecRule(SExecRequestedRule rule) {
|
||||
execRequestedRules.push_back(rule);
|
||||
}
|
||||
|
||||
ICustomConfigValueData::~ICustomConfigValueData() {
|
||||
; // empty
|
||||
}
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include "../Window.hpp"
|
||||
|
||||
#include "defaultConfig.hpp"
|
||||
#include "ConfigDataValues.hpp"
|
||||
|
||||
#define STRVAL_EMPTY "[[EMPTY]]"
|
||||
|
||||
@@ -24,6 +25,7 @@ struct SConfigValue {
|
||||
float floatValue = -__FLT_MAX__;
|
||||
std::string strValue = "";
|
||||
Vector2D vecValue = Vector2D(-__FLT_MAX__, -__FLT_MAX__);
|
||||
std::shared_ptr<ICustomConfigValueData> data;
|
||||
|
||||
bool set = false; // used for device configs
|
||||
};
|
||||
@@ -48,17 +50,6 @@ struct SMonitorAdditionalReservedArea {
|
||||
int right = 0;
|
||||
};
|
||||
|
||||
struct SWindowRule {
|
||||
std::string szRule;
|
||||
std::string szValue;
|
||||
|
||||
bool v2 = false;
|
||||
std::string szTitle;
|
||||
std::string szClass;
|
||||
int bX11 = -1; // -1 means "ANY"
|
||||
int bFloating = -1;
|
||||
};
|
||||
|
||||
struct SAnimationPropertyConfig {
|
||||
bool overriden = true;
|
||||
|
||||
@@ -71,14 +62,19 @@ struct SAnimationPropertyConfig {
|
||||
SAnimationPropertyConfig* pParentAnimation = nullptr;
|
||||
};
|
||||
|
||||
struct SExecRequestedRule {
|
||||
std::string szRule = "";
|
||||
uint64_t iPid = 0;
|
||||
};
|
||||
|
||||
class CVarList {
|
||||
public:
|
||||
CVarList(const std::string& in, long unsigned int lastArgNo = 0) {
|
||||
CVarList(const std::string& in, long unsigned int lastArgNo = 0, const char separator = ',') {
|
||||
std::string curitem = "";
|
||||
std::string argZ = in;
|
||||
|
||||
auto nextItem = [&]() {
|
||||
auto idx = lastArgNo != 0 && m_vArgs.size() >= lastArgNo - 1 ? std::string::npos : argZ.find_first_of(',');
|
||||
auto idx = lastArgNo != 0 && m_vArgs.size() >= lastArgNo - 1 ? std::string::npos : argZ.find_first_of(separator);
|
||||
|
||||
if (idx != std::string::npos) {
|
||||
curitem = argZ.substr(0, idx);
|
||||
@@ -109,7 +105,13 @@ public:
|
||||
return m_vArgs[idx];
|
||||
}
|
||||
|
||||
private:
|
||||
// for range-based loops
|
||||
std::vector<std::string>::iterator begin() { return m_vArgs.begin(); }
|
||||
std::vector<std::string>::const_iterator begin() const { return m_vArgs.begin(); }
|
||||
std::vector<std::string>::iterator end() { return m_vArgs.end(); }
|
||||
std::vector<std::string>::const_iterator end() const { return m_vArgs.end(); }
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_vArgs;
|
||||
};
|
||||
|
||||
@@ -160,6 +162,8 @@ public:
|
||||
|
||||
SAnimationPropertyConfig* getAnimationPropertyConfig(const std::string&);
|
||||
|
||||
void addExecRule(SExecRequestedRule);
|
||||
|
||||
std::string configCurrentPath;
|
||||
|
||||
private:
|
||||
@@ -179,6 +183,8 @@ private:
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> boundWorkspaces;
|
||||
|
||||
std::vector<SExecRequestedRule> execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty
|
||||
|
||||
bool isFirstLaunch = true; // For exec-once
|
||||
|
||||
std::deque<SMonitorRule> m_dMonitorRules;
|
||||
|
@@ -51,7 +51,7 @@ general {
|
||||
gaps_in = 5
|
||||
gaps_out = 20
|
||||
border_size = 2
|
||||
col.active_border = rgba(1affffee)
|
||||
col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg
|
||||
col.inactive_border = rgba(595959aa)
|
||||
|
||||
layout = dwindle
|
||||
|
@@ -68,14 +68,37 @@ R"#({
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string clientsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string result = "";
|
||||
if (format == HyprCtl::FORMAT_JSON) {
|
||||
result += "[";
|
||||
static std::string getGroupedData(CWindow* w, HyprCtl::eHyprCtlOutputFormat format) {
|
||||
const bool isJson = format == HyprCtl::FORMAT_JSON;
|
||||
if (g_pLayoutManager->getCurrentLayout()->getLayoutName() != "dwindle")
|
||||
return isJson ? "" : "0";
|
||||
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_bIsMapped) {
|
||||
result += getFormat(
|
||||
SLayoutMessageHeader header;
|
||||
header.pWindow = w;
|
||||
const auto groupMembers = std::any_cast<std::deque<CWindow*>>(g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "groupinfo"));
|
||||
if (groupMembers.empty())
|
||||
return isJson ? "" : "0";
|
||||
|
||||
const auto comma = isJson ? ", " : ",";
|
||||
const auto fmt = isJson ? "\"0x%x\"" : "%x";
|
||||
std::ostringstream result;
|
||||
|
||||
bool first = true;
|
||||
for (auto& gw : groupMembers) {
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
result << comma;
|
||||
|
||||
result << getFormat(fmt, gw);
|
||||
}
|
||||
|
||||
return result.str();
|
||||
}
|
||||
|
||||
static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat format) {
|
||||
if (format == HyprCtl::FORMAT_JSON) {
|
||||
return getFormat(
|
||||
R"#({
|
||||
"address": "0x%x",
|
||||
"at": [%i, %i],
|
||||
@@ -92,22 +115,40 @@ R"#({
|
||||
"xwayland": %s,
|
||||
"pinned": %s,
|
||||
"fullscreen": %s,
|
||||
"fullscreenMode": %i
|
||||
"fullscreenMode": %i,
|
||||
"grouped": [%s],
|
||||
"swallowing": %s
|
||||
},)#",
|
||||
w.get(),
|
||||
w,
|
||||
(int)w->m_vRealPosition.goalv().x, (int)w->m_vRealPosition.goalv().y,
|
||||
(int)w->m_vRealSize.goalv().x, (int)w->m_vRealSize.goalv().y,
|
||||
w->m_iWorkspaceID, escapeJSONStrings(w->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName : std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID))).c_str(),
|
||||
((int)w->m_bIsFloating == 1 ? "true" : "false"),
|
||||
w->m_iMonitorID,
|
||||
escapeJSONStrings(g_pXWaylandManager->getAppIDClass(w.get())).c_str(),
|
||||
escapeJSONStrings(g_pXWaylandManager->getTitle(w.get())).c_str(),
|
||||
escapeJSONStrings(g_pXWaylandManager->getAppIDClass(w)).c_str(),
|
||||
escapeJSONStrings(g_pXWaylandManager->getTitle(w)).c_str(),
|
||||
w->getPID(),
|
||||
((int)w->m_bIsX11 == 1 ? "true" : "false"),
|
||||
(w->m_bPinned ? "true" : "false"),
|
||||
(w->m_bIsFullscreen ? "true" : "false"),
|
||||
(w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0)
|
||||
(w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0),
|
||||
getGroupedData(w, format).c_str(),
|
||||
(w->m_pSwallowed ? getFormat("\"0x%x\"", w->m_pSwallowed).c_str() : "null")
|
||||
);
|
||||
} else {
|
||||
return getFormat("Window %x -> %s:\n\tat: %i,%i\n\tsize: %i,%i\n\tworkspace: %i (%s)\n\tfloating: %i\n\tmonitor: %i\n\tclass: %s\n\ttitle: %s\n\tpid: %i\n\txwayland: %i\n\tpinned: %i\n\tfullscreen: %i\n\tfullscreenmode: %i\n\tgrouped: %s\n\tswallowing: %x\n\n",
|
||||
w, w->m_szTitle.c_str(), (int)w->m_vRealPosition.goalv().x, (int)w->m_vRealPosition.goalv().y, (int)w->m_vRealSize.goalv().x, (int)w->m_vRealSize.goalv().y, w->m_iWorkspaceID, (w->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName.c_str() : std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID)).c_str()), (int)w->m_bIsFloating, w->m_iMonitorID, g_pXWaylandManager->getAppIDClass(w).c_str(), g_pXWaylandManager->getTitle(w).c_str(), w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen, (w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0), getGroupedData(w, format).c_str(), w->m_pSwallowed);
|
||||
}
|
||||
}
|
||||
|
||||
std::string clientsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string result = "";
|
||||
if (format == HyprCtl::FORMAT_JSON) {
|
||||
result += "[";
|
||||
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_bIsMapped) {
|
||||
result += getWindowData(w.get(), format);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,9 +160,7 @@ R"#({
|
||||
} else {
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_bIsMapped) {
|
||||
result += getFormat("Window %x -> %s:\n\tat: %i,%i\n\tsize: %i,%i\n\tworkspace: %i (%s)\n\tfloating: %i\n\tmonitor: %i\n\tclass: %s\n\ttitle: %s\n\tpid: %i\n\txwayland: %i\n\tpinned: %i\n\tfullscreen: %i\n\tfullscreenmode: %i\n\n",
|
||||
w.get(), w->m_szTitle.c_str(), (int)w->m_vRealPosition.goalv().x, (int)w->m_vRealPosition.goalv().y, (int)w->m_vRealSize.goalv().x, (int)w->m_vRealSize.goalv().y, w->m_iWorkspaceID, (w->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName.c_str() : std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID)).c_str()), (int)w->m_bIsFloating, w->m_iMonitorID, g_pXWaylandManager->getAppIDClass(w.get()).c_str(), g_pXWaylandManager->getTitle(w.get()).c_str(), w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen, (w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0));
|
||||
|
||||
result += getWindowData(w.get(), format);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,38 +215,12 @@ std::string activeWindowRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
if (!g_pCompositor->windowValidMapped(PWINDOW))
|
||||
return format == HyprCtl::FORMAT_JSON ? "{}" : "Invalid";
|
||||
|
||||
if (format == HyprCtl::FORMAT_JSON) {
|
||||
return getFormat(
|
||||
R"#({
|
||||
"address": "0x%x",
|
||||
"at": [%i, %i],
|
||||
"size": [%i, %i],
|
||||
"workspace": {
|
||||
"id": %i,
|
||||
"name": "%s"
|
||||
},
|
||||
"floating": %s,
|
||||
"monitor": %i,
|
||||
"class": "%s",
|
||||
"title": "%s",
|
||||
"pid": %i,
|
||||
"xwayland": %s
|
||||
})#",
|
||||
PWINDOW,
|
||||
(int)PWINDOW->m_vRealPosition.vec().x, (int)PWINDOW->m_vRealPosition.vec().y,
|
||||
(int)PWINDOW->m_vRealSize.vec().x, (int)PWINDOW->m_vRealSize.vec().y,
|
||||
PWINDOW->m_iWorkspaceID, escapeJSONStrings(PWINDOW->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_szName).c_str(),
|
||||
((int)PWINDOW->m_bIsFloating == 1 ? "true" : "false"),
|
||||
PWINDOW->m_iMonitorID,
|
||||
escapeJSONStrings(g_pXWaylandManager->getAppIDClass(PWINDOW)).c_str(),
|
||||
escapeJSONStrings(g_pXWaylandManager->getTitle(PWINDOW)).c_str(),
|
||||
PWINDOW->getPID(),
|
||||
((int)PWINDOW->m_bIsX11 == 1 ? "true" : "false")
|
||||
);
|
||||
} else {
|
||||
return getFormat("Window %x -> %s:\n\tat: %i,%i\n\tsize: %i,%i\n\tworkspace: %i (%s)\n\tfloating: %i\n\tmonitor: %i\n\tclass: %s\n\ttitle: %s\n\tpid: %i\n\txwayland: %i\n\n",
|
||||
PWINDOW, PWINDOW->m_szTitle.c_str(), (int)PWINDOW->m_vRealPosition.vec().x, (int)PWINDOW->m_vRealPosition.vec().y, (int)PWINDOW->m_vRealSize.vec().x, (int)PWINDOW->m_vRealSize.vec().y, PWINDOW->m_iWorkspaceID, (PWINDOW->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_szName.c_str()), (int)PWINDOW->m_bIsFloating, (int)PWINDOW->m_iMonitorID, g_pXWaylandManager->getAppIDClass(PWINDOW).c_str(), g_pXWaylandManager->getTitle(PWINDOW).c_str(), PWINDOW->getPID(), (int)PWINDOW->m_bIsX11);
|
||||
}
|
||||
auto result = getWindowData(PWINDOW, format);
|
||||
|
||||
if (format == HyprCtl::FORMAT_JSON)
|
||||
result.pop_back();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string layersRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
@@ -308,7 +321,7 @@ R"#( {
|
||||
"defaultSpeed": %f
|
||||
},)#",
|
||||
&m,
|
||||
escapeJSONStrings(m.mouse->name).c_str(),
|
||||
escapeJSONStrings(m.name).c_str(),
|
||||
wlr_input_device_is_libinput(m.mouse) ? libinput_device_config_accel_get_default_speed((libinput_device*)wlr_libinput_get_device_handle(m.mouse)) : 0.f
|
||||
);
|
||||
}
|
||||
@@ -333,7 +346,7 @@ R"#( {
|
||||
"main": %s
|
||||
},)#",
|
||||
&k,
|
||||
escapeJSONStrings(k.keyboard->name).c_str(),
|
||||
escapeJSONStrings(k.name).c_str(),
|
||||
escapeJSONStrings(k.currentRules.rules).c_str(),
|
||||
escapeJSONStrings(k.currentRules.model).c_str(),
|
||||
escapeJSONStrings(k.currentRules.layout).c_str(),
|
||||
@@ -362,7 +375,7 @@ R"#( {
|
||||
},)#",
|
||||
&d,
|
||||
d.pTabletParent,
|
||||
escapeJSONStrings(d.pTabletParent ? d.pTabletParent->wlrDevice ? d.pTabletParent->wlrDevice->name : "" : "").c_str()
|
||||
escapeJSONStrings(d.pTabletParent ? d.pTabletParent->name : "").c_str()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -373,7 +386,7 @@ R"#( {
|
||||
"name": "%s"
|
||||
},)#",
|
||||
&d,
|
||||
escapeJSONStrings(d.wlrDevice ? d.wlrDevice->name : "").c_str()
|
||||
escapeJSONStrings(d.name).c_str()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -402,7 +415,7 @@ R"#( {
|
||||
"name": "%s"
|
||||
},)#",
|
||||
&d,
|
||||
d.pWlrDevice ? d.pWlrDevice->name : ""
|
||||
d.name.c_str()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -435,24 +448,24 @@ R"#( {
|
||||
result += "mice:\n";
|
||||
|
||||
for (auto& m : g_pInputManager->m_lMice) {
|
||||
result += getFormat("\tMouse at %x:\n\t\t%s\n\t\t\tdefault speed: %f\n", &m, m.mouse->name, (wlr_input_device_is_libinput(m.mouse) ? libinput_device_config_accel_get_default_speed((libinput_device*)wlr_libinput_get_device_handle(m.mouse)) : 0.f));
|
||||
result += getFormat("\tMouse at %x:\n\t\t%s\n\t\t\tdefault speed: %f\n", &m, m.name.c_str(), (wlr_input_device_is_libinput(m.mouse) ? libinput_device_config_accel_get_default_speed((libinput_device*)wlr_libinput_get_device_handle(m.mouse)) : 0.f));
|
||||
}
|
||||
|
||||
result += "\n\nKeyboards:\n";
|
||||
|
||||
for (auto& k : g_pInputManager->m_lKeyboards) {
|
||||
const auto KM = g_pInputManager->getActiveLayoutForKeyboard(&k);
|
||||
result += getFormat("\tKeyboard at %x:\n\t\t%s\n\t\t\trules: r \"%s\", m \"%s\", l \"%s\", v \"%s\", o \"%s\"\n\t\t\tactive keymap: %s\n\t\t\tmain: %s\n", &k, k.keyboard->name, k.currentRules.rules.c_str(), k.currentRules.model.c_str(), k.currentRules.layout.c_str(), k.currentRules.variant.c_str(), k.currentRules.options.c_str(), KM.c_str(), (k.active ? "yes" : "no"));
|
||||
result += getFormat("\tKeyboard at %x:\n\t\t%s\n\t\t\trules: r \"%s\", m \"%s\", l \"%s\", v \"%s\", o \"%s\"\n\t\t\tactive keymap: %s\n\t\t\tmain: %s\n", &k, k.name.c_str(), k.currentRules.rules.c_str(), k.currentRules.model.c_str(), k.currentRules.layout.c_str(), k.currentRules.variant.c_str(), k.currentRules.options.c_str(), KM.c_str(), (k.active ? "yes" : "no"));
|
||||
}
|
||||
|
||||
result += "\n\nTablets:\n";
|
||||
|
||||
for (auto& d : g_pInputManager->m_lTabletPads) {
|
||||
result += getFormat("\tTablet Pad at %x (belongs to %x -> %s)\n", &d, d.pTabletParent, d.pTabletParent ? d.pTabletParent->wlrDevice ? d.pTabletParent->wlrDevice->name : "" : "");
|
||||
result += getFormat("\tTablet Pad at %x (belongs to %x -> %s)\n", &d, d.pTabletParent, d.pTabletParent ? d.pTabletParent->name.c_str() : "");
|
||||
}
|
||||
|
||||
for (auto& d : g_pInputManager->m_lTablets) {
|
||||
result += getFormat("\tTablet at %x:\n\t\t%s\n", &d, d.wlrDevice ? d.wlrDevice->name : "");
|
||||
result += getFormat("\tTablet at %x:\n\t\t%s\n", &d, d.name.c_str());
|
||||
}
|
||||
|
||||
for (auto& d : g_pInputManager->m_lTabletTools) {
|
||||
@@ -462,7 +475,7 @@ R"#( {
|
||||
result += "\n\nTouch:\n";
|
||||
|
||||
for (auto& d : g_pInputManager->m_lTouchDevices) {
|
||||
result += getFormat("\tTouch Device at %x:\n\t\t%s\n", &d, d.pWlrDevice ? d.pWlrDevice->name : "");
|
||||
result += getFormat("\tTouch Device at %x:\n\t\t%s\n", &d, d.name.c_str());
|
||||
}
|
||||
|
||||
result += "\n\nSwitches:\n";
|
||||
@@ -567,6 +580,9 @@ std::string dispatchKeyword(std::string in) {
|
||||
|
||||
if (COMMAND.contains("general:layout"))
|
||||
g_pLayoutManager->switchToLayout(g_pConfigManager->getString("general:layout")); // update layout
|
||||
|
||||
if (COMMAND.contains("decoration:screen_shader"))
|
||||
g_pHyprOpenGL->m_bReloadScreenShader = true;
|
||||
|
||||
Debug::log(LOG, "Hyprctl: keyword %s : %s", COMMAND.c_str(), VALUE.c_str());
|
||||
|
||||
@@ -702,6 +718,51 @@ std::string dispatchSetCursor(std::string request) {
|
||||
return "ok";
|
||||
}
|
||||
|
||||
std::string switchXKBLayoutRequest(std::string request) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
|
||||
const auto KB = vars[1];
|
||||
const auto CMD = vars[2];
|
||||
|
||||
// get kb
|
||||
const auto PKEYBOARD = std::find_if(g_pInputManager->m_lKeyboards.begin(), g_pInputManager->m_lKeyboards.end(), [&] (const SKeyboard& other) { return other.name == g_pInputManager->deviceNameToInternalString(KB); });
|
||||
|
||||
if (PKEYBOARD == g_pInputManager->m_lKeyboards.end())
|
||||
return "device not found";
|
||||
|
||||
const auto PWLRKEYBOARD = wlr_keyboard_from_input_device(PKEYBOARD->keyboard);
|
||||
const auto LAYOUTS = xkb_keymap_num_layouts(PWLRKEYBOARD->keymap);
|
||||
xkb_layout_index_t activeLayout = 0;
|
||||
while (activeLayout < LAYOUTS) {
|
||||
if (xkb_state_layout_index_is_active(PWLRKEYBOARD->xkb_state, activeLayout, XKB_STATE_LAYOUT_EFFECTIVE))
|
||||
break;
|
||||
|
||||
activeLayout++;
|
||||
}
|
||||
|
||||
if (CMD == "next") {
|
||||
wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked, activeLayout > LAYOUTS ? 0 : activeLayout + 1);
|
||||
} else if (CMD == "prev") {
|
||||
wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked, activeLayout == 0 ? LAYOUTS - 1 : activeLayout - 1);
|
||||
} else {
|
||||
|
||||
int requestedLayout = 0;
|
||||
try {
|
||||
requestedLayout = std::stoi(CMD);
|
||||
} catch (std::exception& e) {
|
||||
return "invalid arg 2";
|
||||
}
|
||||
|
||||
if (requestedLayout < 0 || (uint64_t)requestedLayout > LAYOUTS - 1) {
|
||||
return "layout idx out of range of " + std::to_string(LAYOUTS);
|
||||
}
|
||||
|
||||
wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked, requestedLayout);
|
||||
}
|
||||
|
||||
return "ok";
|
||||
}
|
||||
|
||||
std::string dispatchGetOption(std::string request, HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string curitem = "";
|
||||
|
||||
@@ -728,21 +789,102 @@ std::string dispatchGetOption(std::string request, HyprCtl::eHyprCtlOutputFormat
|
||||
return "no such option";
|
||||
|
||||
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL)
|
||||
return getFormat("option %s\n\tint: %i\n\tfloat: %f\n\tstr: \"%s\"", curitem.c_str(), PCFGOPT->intValue, PCFGOPT->floatValue, PCFGOPT->strValue.c_str());
|
||||
return getFormat("option %s\n\tint: %lld\n\tfloat: %f\n\tstr: \"%s\"\n\tdata: %x", curitem.c_str(), PCFGOPT->intValue, PCFGOPT->floatValue, PCFGOPT->strValue.c_str(), PCFGOPT->data.get());
|
||||
else {
|
||||
return getFormat(
|
||||
R"#(
|
||||
{
|
||||
"option": "%s",
|
||||
"int": %i,
|
||||
"int": %lld,
|
||||
"float": %f,
|
||||
"str": "%s"
|
||||
"str": "%s",
|
||||
"data": "0x%x"
|
||||
}
|
||||
)#", curitem.c_str(), PCFGOPT->intValue, PCFGOPT->floatValue, PCFGOPT->strValue.c_str()
|
||||
)#", curitem.c_str(), PCFGOPT->intValue, PCFGOPT->floatValue, PCFGOPT->strValue.c_str(), PCFGOPT->data.get()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void createOutputIter(wlr_backend* backend, void* data) {
|
||||
const auto DATA = (std::pair<std::string, bool>*)data;
|
||||
|
||||
if (DATA->second)
|
||||
return;
|
||||
|
||||
if (DATA->first.empty() || DATA->first == "auto") {
|
||||
if (wlr_backend_is_wl(backend)) {
|
||||
wlr_wl_output_create(backend);
|
||||
DATA->second = true;
|
||||
} else if (wlr_backend_is_x11(backend)) {
|
||||
wlr_x11_output_create(backend);
|
||||
DATA->second = true;
|
||||
} else if (wlr_backend_is_headless(backend)) {
|
||||
wlr_headless_add_output(backend, 1920, 1080);
|
||||
DATA->second = true;
|
||||
}
|
||||
} else {
|
||||
if (wlr_backend_is_wl(backend) && DATA->first == "wayland") {
|
||||
wlr_wl_output_create(backend);
|
||||
DATA->second = true;
|
||||
} else if (wlr_backend_is_x11(backend) && DATA->first == "x11") {
|
||||
wlr_x11_output_create(backend);
|
||||
DATA->second = true;
|
||||
} else if (wlr_backend_is_headless(backend) && DATA->first == "headless") {
|
||||
wlr_headless_add_output(backend, 1920, 1080);
|
||||
DATA->second = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string dispatchOutput(std::string request) {
|
||||
std::string curitem = "";
|
||||
|
||||
auto nextItem = [&]() {
|
||||
auto idx = request.find_first_of(' ');
|
||||
|
||||
if (idx != std::string::npos) {
|
||||
curitem = request.substr(0, idx);
|
||||
request = request.substr(idx + 1);
|
||||
} else {
|
||||
curitem = request;
|
||||
request = "";
|
||||
}
|
||||
|
||||
curitem = removeBeginEndSpacesTabs(curitem);
|
||||
};
|
||||
|
||||
nextItem();
|
||||
nextItem();
|
||||
|
||||
const auto MODE = curitem;
|
||||
|
||||
nextItem();
|
||||
|
||||
const auto NAME = curitem;
|
||||
|
||||
if (MODE == "create" || MODE == "add") {
|
||||
std::pair<std::string, bool> result = { NAME, false };
|
||||
|
||||
wlr_multi_for_each_backend(g_pCompositor->m_sWLRBackend, createOutputIter, &result);
|
||||
|
||||
if (!result.second)
|
||||
return "no backend replied to the request";
|
||||
|
||||
} else if (MODE == "destroy" || MODE == "remove") {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromName(NAME);
|
||||
|
||||
if (!PMONITOR)
|
||||
return "output not found";
|
||||
|
||||
if (!PMONITOR->createdByUser)
|
||||
return "cannot remove a real display. Use the monitor keyword.";
|
||||
|
||||
wlr_output_destroy(PMONITOR->output);
|
||||
}
|
||||
|
||||
return "ok";
|
||||
}
|
||||
|
||||
std::string getReply(std::string request) {
|
||||
auto format = HyprCtl::FORMAT_NORMAL;
|
||||
|
||||
@@ -786,6 +928,10 @@ std::string getReply(std::string request) {
|
||||
return splashRequest();
|
||||
else if (request == "cursorpos")
|
||||
return cursorPosRequest(format);
|
||||
else if (request.find("switchxkblayout") == 0)
|
||||
return switchXKBLayoutRequest(request);
|
||||
else if (request.find("output") == 0)
|
||||
return dispatchOutput(request);
|
||||
else if (request.find("dispatch") == 0)
|
||||
return dispatchRequest(request);
|
||||
else if (request.find("keyword") == 0)
|
||||
|
@@ -6,6 +6,8 @@
|
||||
|
||||
#include "wlrunstable/wlr_ext_workspace_v1.hpp"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#ifndef NDEBUG
|
||||
#ifdef HYPRLAND_DEBUG
|
||||
#define ISDEBUG true
|
||||
@@ -16,10 +18,10 @@
|
||||
#define ISDEBUG false
|
||||
#endif
|
||||
|
||||
#define LISTENER(name) void listener_##name(wl_listener*, void*); inline wl_listener listen_##name = { .notify = listener_##name };
|
||||
#define DYNLISTENFUNC(name) void listener_##name(void*, void*);
|
||||
#define DYNLISTENER(name) CHyprWLListener hyprListener_##name;
|
||||
#define DYNMULTILISTENER(name) wl_listener listen_##name;
|
||||
#define LISTENER(name) void listener_##name(wl_listener*, void*); inline wl_listener listen_##name = { .notify = listener_##name }
|
||||
#define DYNLISTENFUNC(name) void listener_##name(void*, void*)
|
||||
#define DYNLISTENER(name) CHyprWLListener hyprListener_##name
|
||||
#define DYNMULTILISTENER(name) wl_listener listen_##name
|
||||
|
||||
#define VECINRECT(vec, x1, y1, x2, y2) (vec.x >= (x1) && vec.x <= (x2) && vec.y >= (y1) && vec.y <= (y2))
|
||||
|
||||
@@ -29,6 +31,8 @@
|
||||
const auto RECTSARR = pixman_region32_rectangles(region, &rectsNum); \
|
||||
for (int i = 0; i < rectsNum; ++i)
|
||||
|
||||
#define PIXMAN_REGION_FOREACH(region) PIXMAN_DAMAGE_FOREACH(region)
|
||||
|
||||
|
||||
#define interface class
|
||||
|
||||
@@ -74,4 +78,6 @@
|
||||
#define GIT_DIRTY "?"
|
||||
#endif
|
||||
|
||||
#define SPECIAL_WORKSPACE_ID -99
|
||||
#define SPECIAL_WORKSPACE_START -99
|
||||
|
||||
#define PI 3.14159265358979
|
||||
|
@@ -91,7 +91,7 @@ void Events::listener_newInput(wl_listener* listener, void* data) {
|
||||
break;
|
||||
}
|
||||
|
||||
g_pInputManager->updateCapabilities(DEVICE);
|
||||
g_pInputManager->updateCapabilities();
|
||||
}
|
||||
|
||||
void Events::listener_newConstraint(wl_listener* listener, void* data) {
|
||||
|
@@ -96,6 +96,7 @@ namespace Events {
|
||||
// Monitor part 2 the sequel
|
||||
DYNLISTENFUNC(monitorFrame);
|
||||
DYNLISTENFUNC(monitorDestroy);
|
||||
DYNLISTENFUNC(monitorStateRequest);
|
||||
|
||||
// XWayland
|
||||
LISTENER(readyXWayland);
|
||||
|
@@ -31,15 +31,17 @@ void Events::listener_newLayerSurface(wl_listener* listener, void* data) {
|
||||
WLRLAYERSURFACE->output = PMONITOR->output;
|
||||
}
|
||||
|
||||
const auto PMONITOR = (CMonitor*)g_pCompositor->getMonitorFromOutput(WLRLAYERSURFACE->output);
|
||||
auto PMONITOR = (CMonitor*)g_pCompositor->getMonitorFromOutput(WLRLAYERSURFACE->output);
|
||||
|
||||
if (!WLRLAYERSURFACE->output || !PMONITOR || PMONITOR->pMirrorOf) {
|
||||
PMONITOR = g_pCompositor->m_vMonitors.front().get();
|
||||
WLRLAYERSURFACE->output = PMONITOR->output; // TODO: current mon
|
||||
}
|
||||
|
||||
SLayerSurface* layerSurface = PMONITOR->m_aLayerSurfaceLists[WLRLAYERSURFACE->pending.layer].emplace_back(std::make_unique<SLayerSurface>()).get();
|
||||
|
||||
layerSurface->szNamespace = WLRLAYERSURFACE->_namespace;
|
||||
|
||||
if (!WLRLAYERSURFACE->output) {
|
||||
WLRLAYERSURFACE->output = g_pCompositor->m_vMonitors.front()->output; // TODO: current mon
|
||||
}
|
||||
|
||||
layerSurface->hyprListener_commitLayerSurface.initCallback(&WLRLAYERSURFACE->surface->events.commit, &Events::listener_commitLayerSurface, layerSurface, "layerSurface");
|
||||
layerSurface->hyprListener_destroyLayerSurface.initCallback(&WLRLAYERSURFACE->events.destroy, &Events::listener_destroyLayerSurface, layerSurface, "layerSurface");
|
||||
layerSurface->hyprListener_mapLayerSurface.initCallback(&WLRLAYERSURFACE->events.map, &Events::listener_mapLayerSurface, layerSurface, "layerSurface");
|
||||
|
@@ -126,6 +126,8 @@ void Events::listener_startDrag(wl_listener* listener, void* data) {
|
||||
void Events::listener_destroyDrag(void* owner, void* data) {
|
||||
Debug::log(LOG, "Drag destroyed.");
|
||||
|
||||
static auto *const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
|
||||
|
||||
if (g_pInputManager->m_sDrag.drag && g_pInputManager->m_sDrag.dragIcon && g_pInputManager->m_sDrag.dragIcon->surface)
|
||||
g_pHyprRenderer->damageBox(g_pInputManager->m_sDrag.pos.x - 2, g_pInputManager->m_sDrag.pos.y - 2, g_pInputManager->m_sDrag.dragIcon->surface->current.width + 4, g_pInputManager->m_sDrag.dragIcon->surface->current.height + 4);
|
||||
|
||||
@@ -135,7 +137,7 @@ void Events::listener_destroyDrag(void* owner, void* data) {
|
||||
|
||||
g_pInputManager->refocus();
|
||||
|
||||
if (g_pInputManager->m_pFollowOnDnDBegin)
|
||||
if (g_pInputManager->m_pFollowOnDnDBegin && *PFOLLOWMOUSE != 1)
|
||||
g_pCompositor->focusWindow(g_pInputManager->m_pFollowOnDnDBegin);
|
||||
|
||||
g_pInputManager->m_pFollowOnDnDBegin = nullptr;
|
||||
@@ -189,6 +191,12 @@ void Events::listener_sessionActive(wl_listener* listener, void* data) {
|
||||
Debug::log(LOG, "Session got activated!");
|
||||
|
||||
g_pCompositor->m_bSessionActive = true;
|
||||
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
g_pCompositor->scheduleFrameForMonitor(m.get());
|
||||
}
|
||||
|
||||
g_pConfigManager->m_bWantsMonitorReload = true;
|
||||
}
|
||||
|
||||
void Events::listener_powerMgrSetMode(wl_listener* listener, void* data) {
|
||||
|
@@ -88,6 +88,9 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
|
||||
g_pCompositor->m_bReadyToProcess = true;
|
||||
g_pCompositor->m_bUnsafeState = false;
|
||||
}
|
||||
|
||||
g_pConfigManager->m_bWantsMonitorReload = true;
|
||||
g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR);
|
||||
}
|
||||
|
||||
void Events::listener_monitorFrame(void* owner, void* data) {
|
||||
@@ -106,9 +109,10 @@ void Events::listener_monitorFrame(void* owner, void* data) {
|
||||
static std::chrono::high_resolution_clock::time_point endRenderOverlay = std::chrono::high_resolution_clock::now();
|
||||
|
||||
static auto *const PDEBUGOVERLAY = &g_pConfigManager->getConfigValuePtr("debug:overlay")->intValue;
|
||||
static auto *const PDAMAGETRACKINGMODE = &g_pConfigManager->getConfigValuePtr("general:damage_tracking_internal")->intValue;
|
||||
static auto *const PDAMAGETRACKINGMODE = &g_pConfigManager->getConfigValuePtr("debug:damage_tracking")->intValue;
|
||||
static auto *const PDAMAGEBLINK = &g_pConfigManager->getConfigValuePtr("debug:damage_blink")->intValue;
|
||||
static auto *const PNOVFR = &g_pConfigManager->getConfigValuePtr("misc:no_vfr")->intValue;
|
||||
static auto *const PNODIRECTSCANOUT = &g_pConfigManager->getConfigValuePtr("misc:no_direct_scanout")->intValue;
|
||||
|
||||
static int damageBlinkCleanup = 0; // because double-buffered
|
||||
|
||||
@@ -154,6 +158,16 @@ void Events::listener_monitorFrame(void* owner, void* data) {
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
|
||||
}
|
||||
|
||||
// Direct scanout first
|
||||
if (!*PNODIRECTSCANOUT) {
|
||||
if (g_pHyprRenderer->attemptDirectScanout(PMONITOR)) {
|
||||
return;
|
||||
} else if (g_pHyprRenderer->m_pLastScanout) {
|
||||
Debug::log(LOG, "Left a direct scanout.");
|
||||
g_pHyprRenderer->m_pLastScanout = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
@@ -232,11 +246,11 @@ void Events::listener_monitorFrame(void* owner, void* data) {
|
||||
g_pHyprRenderer->renderAllClientsForMonitor(PMONITOR->ID, &now);
|
||||
|
||||
// if correct monitor draw hyprerror
|
||||
if (PMONITOR->ID == 0)
|
||||
if (PMONITOR == g_pCompositor->m_vMonitors.front().get())
|
||||
g_pHyprError->draw();
|
||||
|
||||
// for drawing the debug overlay
|
||||
if (PMONITOR->ID == 0 && *PDEBUGOVERLAY == 1) {
|
||||
if (PMONITOR == g_pCompositor->m_vMonitors.front().get() && *PDEBUGOVERLAY == 1) {
|
||||
startRenderOverlay = std::chrono::high_resolution_clock::now();
|
||||
g_pDebugOverlay->draw();
|
||||
endRenderOverlay = std::chrono::high_resolution_clock::now();
|
||||
@@ -252,15 +266,16 @@ void Events::listener_monitorFrame(void* owner, void* data) {
|
||||
damageBlinkCleanup = 0;
|
||||
}
|
||||
|
||||
wlr_renderer_begin(g_pCompositor->m_sWLRRenderer, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
|
||||
|
||||
wlr_output_render_software_cursors(PMONITOR->output, NULL);
|
||||
|
||||
wlr_renderer_end(g_pCompositor->m_sWLRRenderer);
|
||||
if (wlr_renderer_begin(g_pCompositor->m_sWLRRenderer, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y)) {
|
||||
wlr_output_render_software_cursors(PMONITOR->output, NULL);
|
||||
wlr_renderer_end(g_pCompositor->m_sWLRRenderer);
|
||||
}
|
||||
}
|
||||
|
||||
g_pHyprOpenGL->end();
|
||||
|
||||
g_pProtocolManager->m_pToplevelExportProtocolManager->onMonitorRender(PMONITOR); // dispatch any toplevel sharing
|
||||
|
||||
// calc frame damage
|
||||
pixman_region32_t frameDamage;
|
||||
pixman_region32_init(&frameDamage);
|
||||
@@ -291,7 +306,7 @@ void Events::listener_monitorFrame(void* owner, void* data) {
|
||||
if (*PDEBUGOVERLAY == 1) {
|
||||
const float µs = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - startRender).count() / 1000.f;
|
||||
g_pDebugOverlay->renderData(PMONITOR, µs);
|
||||
if (PMONITOR->ID == 0) {
|
||||
if (PMONITOR == g_pCompositor->m_vMonitors.front().get()) {
|
||||
const float µsNoOverlay = µs - std::chrono::duration_cast<std::chrono::nanoseconds>(endRenderOverlay - startRenderOverlay).count() / 1000.f;
|
||||
g_pDebugOverlay->renderDataNoOverlay(PMONITOR, µsNoOverlay);
|
||||
} else {
|
||||
@@ -305,8 +320,8 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
|
||||
|
||||
CMonitor* pMonitor = nullptr;
|
||||
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
if (m->szName == OUTPUT->name) {
|
||||
for (auto& m : g_pCompositor->m_vRealMonitors) {
|
||||
if (m->output == OUTPUT) {
|
||||
pMonitor = m.get();
|
||||
break;
|
||||
}
|
||||
@@ -315,11 +330,14 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
|
||||
if (!pMonitor)
|
||||
return;
|
||||
|
||||
Debug::log(LOG, "Destroy called for monitor %s", pMonitor->output->name);
|
||||
|
||||
pMonitor->onDisconnect();
|
||||
|
||||
// cleanup if not unsafe
|
||||
|
||||
if (!g_pCompositor->m_bUnsafeState) {
|
||||
Debug::log(LOG, "Removing monitor %s from realMonitors", pMonitor->output->name);
|
||||
|
||||
g_pCompositor->m_vRealMonitors.erase(std::remove_if(g_pCompositor->m_vRealMonitors.begin(), g_pCompositor->m_vRealMonitors.end(), [&](std::shared_ptr<CMonitor>& el) { return el.get() == pMonitor; }));
|
||||
|
||||
if (pMostHzMonitor == pMonitor) {
|
||||
@@ -337,3 +355,10 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Events::listener_monitorStateRequest(void* owner, void* data) {
|
||||
const auto PMONITOR = (CMonitor*)owner;
|
||||
const auto E = (wlr_output_event_request_state*)data;
|
||||
|
||||
wlr_output_commit_state(PMONITOR->output, E->state);
|
||||
}
|
||||
|
@@ -52,11 +52,11 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
static auto *const PSWALLOW = &g_pConfigManager->getConfigValuePtr("misc:enable_swallow")->intValue;
|
||||
static auto *const PSWALLOWREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_regex")->strValue;
|
||||
|
||||
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
|
||||
const auto PWORKSPACE = PMONITOR->specialWorkspaceOpen ? g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID) : g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
|
||||
auto PMONITOR = g_pCompositor->m_pLastMonitor;
|
||||
const auto PWORKSPACE = PMONITOR->specialWorkspaceID ? g_pCompositor->getWorkspaceByID(PMONITOR->specialWorkspaceID) : g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
|
||||
PWINDOW->m_iMonitorID = PMONITOR->ID;
|
||||
PWINDOW->m_bMappedX11 = true;
|
||||
PWINDOW->m_iWorkspaceID = PMONITOR->specialWorkspaceOpen ? SPECIAL_WORKSPACE_ID : PMONITOR->activeWorkspace;
|
||||
PWINDOW->m_iWorkspaceID = PMONITOR->specialWorkspaceID ? PMONITOR->specialWorkspaceID : PMONITOR->activeWorkspace;
|
||||
PWINDOW->m_bIsMapped = true;
|
||||
PWINDOW->m_bReadyToDelete = false;
|
||||
PWINDOW->m_bFadingOut = false;
|
||||
@@ -65,8 +65,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
if (PWINDOW->m_iX11Type == 2)
|
||||
g_pCompositor->moveUnmanagedX11ToWindows(PWINDOW);
|
||||
|
||||
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
|
||||
|
||||
// Set all windows tiled regardless of anything
|
||||
g_pXWaylandManager->setWindowStyleTiled(PWINDOW, WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP | WLR_EDGE_BOTTOM);
|
||||
|
||||
@@ -76,6 +74,9 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
// checks if the window wants borders and sets the appriopriate flag
|
||||
g_pXWaylandManager->checkBorders(PWINDOW);
|
||||
|
||||
// registers the animated vars and stuff
|
||||
PWINDOW->onMap();
|
||||
|
||||
const auto PWINDOWSURFACE = g_pXWaylandManager->getWindowSurface(PWINDOW);
|
||||
|
||||
if (!PWINDOWSURFACE) {
|
||||
@@ -112,7 +113,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(PWINDOW);
|
||||
std::string requestedWorkspace = "";
|
||||
bool workspaceSilent = false;
|
||||
bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen || (!PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xdg->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL && PWINDOW->m_uSurface.xdg->toplevel->requested.fullscreen);
|
||||
bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen || (!PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xdg->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL && PWINDOW->m_uSurface.xdg->toplevel->requested.fullscreen) || (PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xwayland->fullscreen);
|
||||
bool shouldFocus = true;
|
||||
bool workspaceSpecial = false;
|
||||
|
||||
@@ -132,7 +133,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
}
|
||||
|
||||
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->activeWorkspace;
|
||||
g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->m_iMonitorID));
|
||||
if (PWINDOW->m_iMonitorID != PMONITOR->ID) {
|
||||
g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->m_iMonitorID));
|
||||
PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
||||
}
|
||||
|
||||
Debug::log(ERR, "Rule monitor, applying to window %x -> mon: %i, workspace: %i", PWINDOW, PWINDOW->m_iMonitorID, PWINDOW->m_iWorkspaceID);
|
||||
} catch (std::exception& e) {
|
||||
@@ -160,48 +164,34 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
PWINDOW->m_bIsPseudotiled = true;
|
||||
} else if (r.szRule.find("nofocus") == 0) {
|
||||
PWINDOW->m_bNoFocus = true;
|
||||
} else if (r.szRule == "noblur") {
|
||||
PWINDOW->m_sAdditionalConfigData.forceNoBlur = true;
|
||||
} else if (r.szRule == "noborder") {
|
||||
PWINDOW->m_sAdditionalConfigData.forceNoBorder = true;
|
||||
} else if (r.szRule == "noshadow") {
|
||||
PWINDOW->m_sAdditionalConfigData.forceNoShadow = true;
|
||||
} else if (r.szRule.find("nofullscreenrequest") == 0) {
|
||||
PWINDOW->m_bNoFullscreenRequest = true;
|
||||
} else if (r.szRule == "fullscreen") {
|
||||
requestsFullscreen = true;
|
||||
} else if (r.szRule == "opaque") {
|
||||
PWINDOW->m_sAdditionalConfigData.forceOpaque = true;
|
||||
} else if (r.szRule == "windowdance") {
|
||||
PWINDOW->m_sAdditionalConfigData.windowDanceCompat = true;
|
||||
} else if (r.szRule == "nomaxsize") {
|
||||
PWINDOW->m_sAdditionalConfigData.noMaxSize = true;
|
||||
} else if (r.szRule == "forceinput") {
|
||||
PWINDOW->m_sAdditionalConfigData.forceAllowsInput = true;
|
||||
} else if (r.szRule == "pin") {
|
||||
PWINDOW->m_bPinned = true;
|
||||
} else if (r.szRule == "noanim") {
|
||||
PWINDOW->m_sAdditionalConfigData.forceNoAnims = true;
|
||||
} else if (r.szRule.find("rounding") == 0) {
|
||||
try {
|
||||
PWINDOW->m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
|
||||
} catch (std::exception& e) {
|
||||
Debug::log(ERR, "Rounding rule \"%s\" failed with: %s", r.szRule.c_str(), e.what());
|
||||
}
|
||||
} else if (r.szRule.find("opacity") == 0) {
|
||||
try {
|
||||
std::string alphaPart = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
|
||||
} else if (r.szRule.find("idleinhibit") == 0) {
|
||||
auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
|
||||
|
||||
if (alphaPart.contains(' ')) {
|
||||
// we have a comma, 2 values
|
||||
PWINDOW->m_sSpecialRenderData.alpha = std::stof(alphaPart.substr(0, alphaPart.find_first_of(' ')));
|
||||
PWINDOW->m_sSpecialRenderData.alphaInactive = std::stof(alphaPart.substr(alphaPart.find_first_of(' ') + 1));
|
||||
} else {
|
||||
PWINDOW->m_sSpecialRenderData.alpha = std::stof(alphaPart);
|
||||
}
|
||||
} catch(std::exception& e) {
|
||||
Debug::log(ERR, "Opacity rule \"%s\" failed with: %s", r.szRule.c_str(), e.what());
|
||||
if (IDLERULE == "none") {
|
||||
PWINDOW->m_eIdleInhibitMode = IDLEINHIBIT_NONE;
|
||||
} else if (IDLERULE == "always") {
|
||||
PWINDOW->m_eIdleInhibitMode = IDLEINHIBIT_ALWAYS;
|
||||
} else if (IDLERULE == "focus") {
|
||||
PWINDOW->m_eIdleInhibitMode = IDLEINHIBIT_FOCUS;
|
||||
} else if (IDLERULE == "fullscreen") {
|
||||
PWINDOW->m_eIdleInhibitMode = IDLEINHIBIT_FULLSCREEN;
|
||||
} else {
|
||||
Debug::log(ERR, "Rule idleinhibit: unknown mode %s", IDLERULE.c_str());
|
||||
}
|
||||
} else if (r.szRule.find("animation") == 0) {
|
||||
auto STYLE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
|
||||
PWINDOW->m_sAdditionalConfigData.animationStyle = STYLE;
|
||||
}
|
||||
PWINDOW->applyDynamicRule(r);
|
||||
}
|
||||
|
||||
// disallow tiled pinned
|
||||
@@ -223,9 +213,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
shouldFocus = true;
|
||||
}
|
||||
|
||||
if (requestedWorkspace == "special") {
|
||||
if (requestedWorkspace.find("special" == 0)) {
|
||||
workspaceSpecial = true;
|
||||
workspaceSilent = true;
|
||||
}
|
||||
|
||||
if (!workspaceSilent) {
|
||||
@@ -233,6 +222,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
|
||||
PWINDOW->m_iMonitorID = g_pCompositor->m_pLastMonitor->ID;
|
||||
PWINDOW->m_iWorkspaceID = g_pCompositor->m_pLastMonitor->activeWorkspace;
|
||||
|
||||
PMONITOR = g_pCompositor->m_pLastMonitor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,13 +235,13 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
if (!PWORKSPACE) {
|
||||
std::string workspaceName = "";
|
||||
int workspaceID = 0;
|
||||
|
||||
|
||||
if (requestedWorkspace.find("name:") == 0) {
|
||||
workspaceName = requestedWorkspace.substr(5);
|
||||
workspaceID = g_pCompositor->getNextAvailableNamedWorkspace();
|
||||
} else if (workspaceSpecial) {
|
||||
workspaceName = "";
|
||||
workspaceID = SPECIAL_WORKSPACE_ID;
|
||||
workspaceID = getWorkspaceIDFromString(requestedWorkspace, workspaceName);
|
||||
} else {
|
||||
try {
|
||||
workspaceID = std::stoi(requestedWorkspace);
|
||||
@@ -332,9 +323,15 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
}
|
||||
} else if (r.szRule.find("move") == 0) {
|
||||
try {
|
||||
const auto VALUE = r.szRule.substr(r.szRule.find(" ") + 1);
|
||||
const auto POSXSTR = VALUE.substr(0, VALUE.find(" "));
|
||||
const auto POSYSTR = VALUE.substr(VALUE.find(" ") + 1);
|
||||
auto value = r.szRule.substr(r.szRule.find(" ") + 1);
|
||||
|
||||
const bool CURSOR = value.find("cursor") == 0;
|
||||
|
||||
if (CURSOR)
|
||||
value = value.substr(value.find_first_of(' ') + 1);
|
||||
|
||||
const auto POSXSTR = value.substr(0, value.find(" "));
|
||||
const auto POSYSTR = value.substr(value.find(" ") + 1);
|
||||
|
||||
int posX = 0;
|
||||
int posY = 0;
|
||||
@@ -343,16 +340,36 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
||||
const auto POSXRAW = POSXSTR.substr(5);
|
||||
posX = PMONITOR->vecSize.x - (!POSXRAW.contains('%') ? std::stoi(POSXRAW) : std::stoi(POSXRAW.substr(0, POSXRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.x);
|
||||
} else {
|
||||
|
||||
if (CURSOR)
|
||||
Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!");
|
||||
} else if (!CURSOR) {
|
||||
posX = !POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stoi(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.x;
|
||||
} else {
|
||||
// cursor
|
||||
if (POSXSTR == "cursor") {
|
||||
posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x;
|
||||
} else {
|
||||
posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x + (!POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stoi(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goalv().x);
|
||||
}
|
||||
}
|
||||
|
||||
if (POSYSTR.find("100%-") == 0) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
||||
const auto POSYRAW = POSYSTR.substr(5);
|
||||
posY = PMONITOR->vecSize.y - (!POSYRAW.contains('%') ? std::stoi(POSYRAW) : std::stoi(POSYRAW.substr(0, POSYRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.y);
|
||||
} else {
|
||||
|
||||
if (CURSOR)
|
||||
Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!");
|
||||
} else if (!CURSOR) {
|
||||
posY = !POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stoi(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.y;
|
||||
} else {
|
||||
// cursor
|
||||
if (POSYSTR == "cursor") {
|
||||
posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y;
|
||||
} else {
|
||||
posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y + (!POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stoi(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goalv().y);
|
||||
}
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Rule move, applying to window %x", PWINDOW);
|
||||
@@ -388,6 +405,11 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
PWINDOW->m_bX11ShouldntFocus = false;
|
||||
}
|
||||
|
||||
// check LS focus grab
|
||||
const auto PLSFROMFOCUS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus);
|
||||
if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.keyboard_interactive)
|
||||
PWINDOW->m_bNoInitialFocus = true;
|
||||
|
||||
if (!PWINDOW->m_bNoFocus && !PWINDOW->m_bNoInitialFocus && PWINDOW->m_iX11Type != 2 && !workspaceSilent) {
|
||||
g_pCompositor->focusWindow(PWINDOW);
|
||||
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA);
|
||||
@@ -428,7 +450,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
const auto TIMER = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, setAnimToMove, PWINDOW);
|
||||
wl_event_source_timer_update(TIMER, PWINDOW->m_vRealPosition.getDurationLeftMs() + 5);
|
||||
|
||||
if (requestsFullscreen) {
|
||||
if (requestsFullscreen && !PWINDOW->m_bNoFullscreenRequest) {
|
||||
// fix fullscreen on requested (basically do a switcheroo)
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow) {
|
||||
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
|
||||
@@ -524,6 +546,9 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
|
||||
auto workspaceID = requestedWorkspace != "" ? requestedWorkspace : PWORKSPACE->m_szName;
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", getFormat("%x,%s,%s,%s", PWINDOW, workspaceID.c_str(), g_pXWaylandManager->getAppIDClass(PWINDOW).c_str(), PWINDOW->m_szTitle.c_str())});
|
||||
|
||||
// recalc the values for this window
|
||||
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
|
||||
}
|
||||
|
||||
void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
@@ -533,6 +558,8 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", getFormat("%x", PWINDOW)});
|
||||
|
||||
g_pProtocolManager->m_pToplevelExportProtocolManager->onWindowUnmap(PWINDOW);
|
||||
|
||||
if (!PWINDOW->m_bIsX11) {
|
||||
Debug::log(LOG, "Unregistered late callbacks XDG");
|
||||
PWINDOW->hyprListener_commitWindow.removeCallback();
|
||||
@@ -607,9 +634,6 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
Debug::log(LOG, "Unmapped was not focused, ignoring a refocus.");
|
||||
}
|
||||
|
||||
// update lastwindow after focus
|
||||
PWINDOW->onUnmap();
|
||||
|
||||
Debug::log(LOG, "Destroying the SubSurface tree of unmapped window %x", PWINDOW);
|
||||
SubsurfaceTree::destroySurfaceTree(PWINDOW->m_pSurfaceTree);
|
||||
|
||||
@@ -642,6 +666,9 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
|
||||
// force report all sizes (QT sometimes has an issue with this)
|
||||
g_pCompositor->forceReportSizesToWindowsOnWorkspace(PWINDOW->m_iWorkspaceID);
|
||||
|
||||
// update lastwindow after focus
|
||||
PWINDOW->onUnmap();
|
||||
}
|
||||
|
||||
void Events::listener_commitWindow(void* owner, void* data) {
|
||||
@@ -681,6 +708,11 @@ void Events::listener_destroyWindow(void* owner, void* data) {
|
||||
}
|
||||
|
||||
PWINDOW->m_bReadyToDelete = true;
|
||||
|
||||
if (!PWINDOW->m_bFadingOut) {
|
||||
g_pCompositor->removeWindowFromVectorSafe(PWINDOW); // most likely X11 unmanaged or sumn
|
||||
Debug::log(LOG, "Unmapped window %x removed instantly", PWINDOW);
|
||||
}
|
||||
}
|
||||
|
||||
void Events::listener_setTitleWindow(void* owner, void* data) {
|
||||
@@ -694,6 +726,8 @@ void Events::listener_setTitleWindow(void* owner, void* data) {
|
||||
if (PWINDOW == g_pCompositor->m_pLastWindow) // if it's the active, let's post an event to update others
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", g_pXWaylandManager->getAppIDClass(PWINDOW) + "," + PWINDOW->m_szTitle});
|
||||
|
||||
PWINDOW->updateDynamicRules();
|
||||
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
|
||||
PWINDOW->updateToplevel();
|
||||
|
||||
Debug::log(LOG, "Window %x set title to %s", PWINDOW, PWINDOW->m_szTitle.c_str());
|
||||
@@ -707,7 +741,7 @@ void Events::listener_fullscreenWindow(void* owner, void* data) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (PWINDOW->isHidden())
|
||||
if (PWINDOW->isHidden() || PWINDOW->m_bNoFullscreenRequest)
|
||||
return;
|
||||
|
||||
if (!PWINDOW->m_bIsX11) {
|
||||
@@ -774,7 +808,7 @@ void Events::listener_configureX11(void* owner, void* data) {
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
|
||||
if (!PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen) {
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.vec());
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv(), true);
|
||||
g_pInputManager->refocus();
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
return;
|
||||
@@ -825,6 +859,12 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
|
||||
else
|
||||
PWINDOW->setHidden(true);
|
||||
|
||||
if (PWINDOW->m_bIsFullscreen || !PWINDOW->m_bIsFloating) {
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv(), true);
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
return;
|
||||
}
|
||||
|
||||
if (abs(std::floor(POS.x) - PWINDOW->m_uSurface.xwayland->x) > 2 || abs(std::floor(POS.y) - PWINDOW->m_uSurface.xwayland->y) > 2 || abs(std::floor(SIZ.x) - PWINDOW->m_uSurface.xwayland->width) > 2 || abs(std::floor(SIZ.y) - PWINDOW->m_uSurface.xwayland->height) > 2) {
|
||||
Debug::log(LOG, "Unmanaged window %x requests geometry update to %i %i %i %i", PWINDOW, (int)PWINDOW->m_uSurface.xwayland->x, (int)PWINDOW->m_uSurface.xwayland->y, (int)PWINDOW->m_uSurface.xwayland->width, (int)PWINDOW->m_uSurface.xwayland->height);
|
||||
|
||||
@@ -887,8 +927,10 @@ void Events::listener_NewXDGDeco(wl_listener* listener, void* data) {
|
||||
void Events::listener_requestMaximize(void* owner, void* data) {
|
||||
const auto PWINDOW = (CWindow*)owner;
|
||||
|
||||
Debug::log(LOG, "Maximize request for %x", PWINDOW);
|
||||
if (PWINDOW->m_bNoFullscreenRequest)
|
||||
return;
|
||||
|
||||
Debug::log(LOG, "Maximize request for %x", PWINDOW);
|
||||
if (!PWINDOW->m_bIsX11) {
|
||||
const auto EV = (wlr_foreign_toplevel_handle_v1_maximized_event*)data;
|
||||
|
||||
@@ -908,14 +950,14 @@ void Events::listener_requestMinimize(void* owner, void* data) {
|
||||
|
||||
Debug::log(LOG, "Minimize request for %x", PWINDOW);
|
||||
|
||||
// if (PWINDOW->m_bIsX11) {
|
||||
// if (!PWINDOW->m_bMappedX11 || PWINDOW->m_iX11Type != 1)
|
||||
// return;
|
||||
if (PWINDOW->m_bIsX11) {
|
||||
if (!PWINDOW->m_bMappedX11 || PWINDOW->m_iX11Type != 1)
|
||||
return;
|
||||
|
||||
// const auto E = (wlr_xwayland_minimize_event*)data;
|
||||
const auto E = (wlr_xwayland_minimize_event*)data;
|
||||
|
||||
// wlr_xwayland_surface_set_minimized(PWINDOW->m_uSurface.xwayland, E->minimize && g_pCompositor->m_pLastWindow != PWINDOW); // fucking DXVK
|
||||
// }
|
||||
wlr_xwayland_surface_set_minimized(PWINDOW->m_uSurface.xwayland, E->minimize && g_pCompositor->m_pLastWindow != PWINDOW); // fucking DXVK
|
||||
}
|
||||
}
|
||||
|
||||
void Events::listener_requestMove(void* owner, void* data) {
|
||||
|
@@ -12,8 +12,6 @@ void CAnimatedVariable::create(ANIMATEDVARTYPE type, SAnimationPropertyConfig* p
|
||||
m_pConfig = pAnimConfig;
|
||||
m_pWindow = pWindow;
|
||||
|
||||
g_pAnimationManager->m_lAnimatedVariables.push_back(this);
|
||||
|
||||
m_bDummy = false;
|
||||
}
|
||||
|
||||
@@ -56,8 +54,20 @@ CAnimatedVariable::~CAnimatedVariable() {
|
||||
|
||||
void CAnimatedVariable::unregister() {
|
||||
g_pAnimationManager->m_lAnimatedVariables.remove(this);
|
||||
m_bIsRegistered = false;
|
||||
}
|
||||
|
||||
void CAnimatedVariable::registerVar() {
|
||||
if (!m_bIsRegistered)
|
||||
g_pAnimationManager->m_lAnimatedVariables.push_back(this);
|
||||
m_bIsRegistered = true;
|
||||
}
|
||||
|
||||
int CAnimatedVariable::getDurationLeftMs() {
|
||||
return std::max((int)(m_pConfig->pValues->internalSpeed * 100) - (int)std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - animationBegin).count(), 0);
|
||||
}
|
||||
|
||||
float CAnimatedVariable::getPercent() {
|
||||
const auto DURATIONPASSED = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - animationBegin).count();
|
||||
return std::clamp((DURATIONPASSED / 100.f) / m_pConfig->pValues->internalSpeed, 0.f, 1.f);
|
||||
}
|
@@ -21,6 +21,7 @@ class CAnimationManager;
|
||||
class CWorkspace;
|
||||
struct SLayerSurface;
|
||||
struct SAnimationPropertyConfig;
|
||||
class CHyprRenderer;
|
||||
|
||||
class CAnimatedVariable {
|
||||
public:
|
||||
@@ -32,6 +33,7 @@ public:
|
||||
~CAnimatedVariable();
|
||||
|
||||
void unregister();
|
||||
void registerVar();
|
||||
|
||||
// gets the current vector value (real time)
|
||||
const Vector2D& vec() const {
|
||||
@@ -67,18 +69,24 @@ public:
|
||||
m_vGoal = v;
|
||||
animationBegin = std::chrono::system_clock::now();
|
||||
m_vBegun = m_vValue;
|
||||
|
||||
onAnimationBegin();
|
||||
}
|
||||
|
||||
void operator=(const float& v) {
|
||||
m_fGoal = v;
|
||||
animationBegin = std::chrono::system_clock::now();
|
||||
m_fBegun = m_fValue;
|
||||
|
||||
onAnimationBegin();
|
||||
}
|
||||
|
||||
void operator=(const CColor& v) {
|
||||
m_cGoal = v;
|
||||
animationBegin = std::chrono::system_clock::now();
|
||||
m_cBegun = m_cValue;
|
||||
|
||||
onAnimationBegin();
|
||||
}
|
||||
|
||||
// Sets the actual stored value, without affecting the goal, but resets the timer
|
||||
@@ -86,6 +94,8 @@ public:
|
||||
m_vValue = v;
|
||||
animationBegin = std::chrono::system_clock::now();
|
||||
m_vBegun = m_vValue;
|
||||
|
||||
onAnimationBegin();
|
||||
}
|
||||
|
||||
// Sets the actual stored value, without affecting the goal, but resets the timer
|
||||
@@ -93,6 +103,8 @@ public:
|
||||
m_fValue = v;
|
||||
animationBegin = std::chrono::system_clock::now();
|
||||
m_vBegun = m_vValue;
|
||||
|
||||
onAnimationBegin();
|
||||
}
|
||||
|
||||
// Sets the actual stored value, without affecting the goal, but resets the timer
|
||||
@@ -100,6 +112,8 @@ public:
|
||||
m_cValue = v;
|
||||
animationBegin = std::chrono::system_clock::now();
|
||||
m_vBegun = m_vValue;
|
||||
|
||||
onAnimationBegin();
|
||||
}
|
||||
|
||||
// Sets the actual value and goal
|
||||
@@ -138,7 +152,7 @@ public:
|
||||
return false; // just so that the warning is suppressed
|
||||
}
|
||||
|
||||
void warp() {
|
||||
void warp(bool endCallback = true) {
|
||||
switch (m_eVarType) {
|
||||
case AVARTYPE_FLOAT: {
|
||||
m_fValue = m_fGoal;
|
||||
@@ -155,6 +169,9 @@ public:
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
if (endCallback)
|
||||
onAnimationEnd();
|
||||
}
|
||||
|
||||
void setConfig(SAnimationPropertyConfig* pConfig) {
|
||||
@@ -167,6 +184,35 @@ public:
|
||||
|
||||
int getDurationLeftMs();
|
||||
|
||||
/* returns the spent (completion) % */
|
||||
float getPercent();
|
||||
|
||||
/* sets a function to be ran when the animation finishes.
|
||||
if an animation is not running, runs instantly.
|
||||
if "remove" is set to true, will remove the callback when ran. */
|
||||
void setCallbackOnEnd(std::function<void(void* thisptr)> func, bool remove = true) {
|
||||
m_fEndCallback = func;
|
||||
m_bRemoveEndAfterRan = remove;
|
||||
|
||||
if (!isBeingAnimated())
|
||||
onAnimationEnd();
|
||||
}
|
||||
|
||||
/* sets a function to be ran when an animation is started.
|
||||
if "remove" is set to true, will remove the callback when ran. */
|
||||
void setCallbackOnBegin(std::function<void(void* thisptr)> func, bool remove = true) {
|
||||
m_fBeginCallback = func;
|
||||
m_bRemoveBeginAfterRan = remove;
|
||||
}
|
||||
|
||||
/* resets all callbacks. Does not call any. */
|
||||
void resetAllCallbacks() {
|
||||
m_fBeginCallback = nullptr;
|
||||
m_fEndCallback = nullptr;
|
||||
m_bRemoveBeginAfterRan = false;
|
||||
m_bRemoveEndAfterRan = false;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Vector2D m_vValue = Vector2D(0,0);
|
||||
@@ -189,13 +235,37 @@ private:
|
||||
SAnimationPropertyConfig* m_pConfig = nullptr;
|
||||
|
||||
bool m_bDummy = true;
|
||||
bool m_bIsRegistered = false;
|
||||
|
||||
std::chrono::system_clock::time_point animationBegin;
|
||||
|
||||
ANIMATEDVARTYPE m_eVarType = AVARTYPE_INVALID;
|
||||
AVARDAMAGEPOLICY m_eDamagePolicy = AVARDAMAGE_INVALID;
|
||||
|
||||
bool m_bRemoveEndAfterRan = true;
|
||||
bool m_bRemoveBeginAfterRan = true;
|
||||
std::function<void(void* thisptr)> m_fEndCallback;
|
||||
std::function<void(void* thisptr)> m_fBeginCallback;
|
||||
|
||||
// methods
|
||||
void onAnimationEnd() {
|
||||
if (m_fEndCallback) {
|
||||
m_fEndCallback(this);
|
||||
if (m_bRemoveEndAfterRan)
|
||||
m_fEndCallback = nullptr; // reset
|
||||
}
|
||||
}
|
||||
|
||||
void onAnimationBegin() {
|
||||
if (m_fBeginCallback) {
|
||||
m_fBeginCallback(this);
|
||||
if (m_bRemoveBeginAfterRan)
|
||||
m_fBeginCallback = nullptr; // reset
|
||||
}
|
||||
}
|
||||
|
||||
friend class CAnimationManager;
|
||||
friend class CWorkspace;
|
||||
friend struct SLayerSurface;
|
||||
friend class CHyprRenderer;
|
||||
};
|
||||
|
@@ -5,6 +5,31 @@
|
||||
#include <sys/utsname.h>
|
||||
#include <iomanip>
|
||||
|
||||
#if defined(__DragonFly__) || defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
# include <sys/sysctl.h>
|
||||
# if defined(__DragonFly__)
|
||||
# include <sys/kinfo.h> // struct kinfo_proc
|
||||
# elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
# include <sys/user.h> // struct kinfo_proc
|
||||
# endif
|
||||
|
||||
# if defined(__NetBSD__)
|
||||
# undef KERN_PROC
|
||||
# define KERN_PROC KERN_PROC2
|
||||
# define KINFO_PROC struct kinfo_proc2
|
||||
# else
|
||||
# define KINFO_PROC struct kinfo_proc
|
||||
# endif
|
||||
# if defined(__DragonFly__)
|
||||
# define KP_PPID(kp) kp.kp_ppid
|
||||
# elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
# define KP_PPID(kp) kp.ki_ppid
|
||||
# else
|
||||
# define KP_PPID(kp) kp.p_ppid
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static const float transforms[][9] = {{
|
||||
1.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f,
|
||||
@@ -120,6 +145,9 @@ void scaleBox(wlr_box* box, float scale) {
|
||||
}
|
||||
|
||||
std::string removeBeginEndSpacesTabs(std::string str) {
|
||||
if (str.empty())
|
||||
return str;
|
||||
|
||||
int countBefore = 0;
|
||||
while (str[countBefore] == ' ' || str[countBefore] == '\t') {
|
||||
countBefore++;
|
||||
@@ -206,7 +234,18 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||
int result = INT_MAX;
|
||||
if (in.find("special") == 0) {
|
||||
outName = "special";
|
||||
return SPECIAL_WORKSPACE_ID;
|
||||
|
||||
if (in.length() > 8) {
|
||||
const auto NAME = in.substr(8);
|
||||
|
||||
const auto WS = g_pCompositor->getWorkspaceByName("special:" + NAME);
|
||||
|
||||
outName = "special:" + NAME;
|
||||
|
||||
return WS ? WS->m_iID : g_pCompositor->getNewSpecialID();
|
||||
}
|
||||
|
||||
return SPECIAL_WORKSPACE_START;
|
||||
} else if (in.find("name:") == 0) {
|
||||
const auto WORKSPACENAME = in.substr(in.find_first_of(':') + 1);
|
||||
const auto WORKSPACE = g_pCompositor->getWorkspaceByName(WORKSPACENAME);
|
||||
@@ -216,6 +255,13 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||
result = WORKSPACE->m_iID;
|
||||
}
|
||||
outName = WORKSPACENAME;
|
||||
} else if (in.find("empty") == 0) {
|
||||
int id = 0;
|
||||
while (++id < INT_MAX) {
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id);
|
||||
if (!PWORKSPACE || (g_pCompositor->getWindowsOnWorkspace(id) == 0))
|
||||
return id;
|
||||
}
|
||||
} else {
|
||||
if ((in[0] == 'm' || in[0] == 'e') && (in[1] == '-' || in[1] == '+') && isNumber(in.substr(2))) {
|
||||
bool onAllMonitors = in[0] == 'e';
|
||||
@@ -246,7 +292,7 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||
int highestID = -99999;
|
||||
|
||||
for (auto& w : g_pCompositor->m_vWorkspaces) {
|
||||
if (w->m_iID == SPECIAL_WORKSPACE_ID)
|
||||
if (g_pCompositor->isWorkspaceSpecial(w->m_iID))
|
||||
continue;
|
||||
|
||||
if (w->m_iID < lowestID)
|
||||
@@ -262,7 +308,7 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
||||
searchID = lowestID;
|
||||
}
|
||||
|
||||
if (const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(searchID); PWORKSPACE && PWORKSPACE->m_iID != SPECIAL_WORKSPACE_ID) {
|
||||
if (const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(searchID); PWORKSPACE && !PWORKSPACE->m_bIsSpecialWorkspace) {
|
||||
if (onAllMonitors || PWORKSPACE->m_iMonitorID == g_pCompositor->m_pLastMonitor->ID) {
|
||||
currentID = PWORKSPACE->m_iID;
|
||||
|
||||
@@ -369,6 +415,25 @@ void matrixProjection(float mat[9], int w, int h, wl_output_transform tr) {
|
||||
}
|
||||
|
||||
int64_t getPPIDof(int64_t pid) {
|
||||
#if defined(KERN_PROC_PID)
|
||||
int mib[] = {
|
||||
CTL_KERN,
|
||||
KERN_PROC,
|
||||
KERN_PROC_PID,
|
||||
(int)pid,
|
||||
# if defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
sizeof(KINFO_PROC),
|
||||
1,
|
||||
# endif
|
||||
};
|
||||
u_int miblen = sizeof(mib) / sizeof(mib[0]);
|
||||
KINFO_PROC kp;
|
||||
size_t sz = sizeof(KINFO_PROC);
|
||||
if (sysctl(mib, miblen, &kp, &sz, NULL, 0) != -1)
|
||||
return KP_PPID(kp);
|
||||
|
||||
return 0;
|
||||
#else
|
||||
std::string dir = "/proc/" + std::to_string(pid) + "/status";
|
||||
FILE* infile;
|
||||
|
||||
@@ -401,4 +466,41 @@ int64_t getPPIDof(int64_t pid) {
|
||||
} catch (std::exception& e) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int64_t configStringToInt(const std::string& VALUE) {
|
||||
if (VALUE.find("0x") == 0) {
|
||||
// Values with 0x are hex
|
||||
const auto VALUEWITHOUTHEX = VALUE.substr(2);
|
||||
return stol(VALUEWITHOUTHEX, nullptr, 16);
|
||||
} else if (VALUE.find("rgba(") == 0 && VALUE.find(")") == VALUE.length() - 1) {
|
||||
const auto VALUEWITHOUTFUNC = VALUE.substr(5, VALUE.length() - 6);
|
||||
|
||||
if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 8) {
|
||||
Debug::log(WARN, "invalid length %i for rgba", VALUEWITHOUTFUNC.length());
|
||||
throw std::invalid_argument("rgba() expects length of 8 characters (4 bytes)");
|
||||
}
|
||||
|
||||
const auto RGBA = std::stol(VALUEWITHOUTFUNC, nullptr, 16);
|
||||
|
||||
// now we need to RGBA -> ARGB. The config holds ARGB only.
|
||||
return (RGBA >> 8) + 0x1000000 * (RGBA & 0xFF);
|
||||
} else if (VALUE.find("rgb(") == 0 && VALUE.find(")") == VALUE.length() - 1) {
|
||||
const auto VALUEWITHOUTFUNC = VALUE.substr(4, VALUE.length() - 5);
|
||||
|
||||
if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 6) {
|
||||
Debug::log(WARN, "invalid length %i for rgb", VALUEWITHOUTFUNC.length());
|
||||
throw std::invalid_argument("rgb() expects length of 6 characters (3 bytes)");
|
||||
}
|
||||
|
||||
const auto RGB = std::stol(VALUEWITHOUTFUNC, nullptr, 16);
|
||||
|
||||
return RGB + 0xFF000000; // 0xFF for opaque
|
||||
} else if (VALUE.find("true") == 0 || VALUE.find("on") == 0 || VALUE.find("yes") == 0) {
|
||||
return 1;
|
||||
} else if (VALUE.find("false") == 0 || VALUE.find("off") == 0 || VALUE.find("no") == 0) {
|
||||
return 0;
|
||||
}
|
||||
return stol(VALUE);
|
||||
}
|
||||
|
@@ -15,6 +15,7 @@ float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Ve
|
||||
void logSystemInfo();
|
||||
std::string execAndGet(const char*);
|
||||
int64_t getPPIDof(int64_t pid);
|
||||
int64_t configStringToInt(const std::string&);
|
||||
|
||||
float getPlusMinusKeywordResult(std::string in, float relative);
|
||||
|
||||
|
@@ -3,21 +3,30 @@
|
||||
#include "../Compositor.hpp"
|
||||
|
||||
void CMonitor::onConnect(bool noRule) {
|
||||
if (m_bEnabled)
|
||||
hyprListener_monitorDestroy.removeCallback();
|
||||
hyprListener_monitorFrame.removeCallback();
|
||||
hyprListener_monitorStateRequest.removeCallback();
|
||||
hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this);
|
||||
hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this);
|
||||
hyprListener_monitorStateRequest.initCallback(&output->events.request_state, &Events::listener_monitorStateRequest, this);
|
||||
|
||||
if (m_bEnabled) {
|
||||
wlr_output_enable(output, 1);
|
||||
wlr_output_commit(output);
|
||||
return;
|
||||
}
|
||||
|
||||
szName = output->name;
|
||||
|
||||
if (!wlr_backend_is_drm(output->backend))
|
||||
createdByUser = true; // should be true. WL, X11 and Headless backends should be addable / removable
|
||||
|
||||
// get monitor rule that matches
|
||||
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(output->name, output->description ? output->description : "");
|
||||
|
||||
hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this);
|
||||
hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this);
|
||||
|
||||
// if it's disabled, disable and ignore
|
||||
if (monitorRule.disabled) {
|
||||
|
||||
wlr_output_enable_adaptive_sync(output, 1);
|
||||
wlr_output_set_scale(output, 1);
|
||||
wlr_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL);
|
||||
|
||||
@@ -87,10 +96,8 @@ void CMonitor::onConnect(bool noRule) {
|
||||
}
|
||||
|
||||
m_bEnabled = true;
|
||||
|
||||
wlr_output_set_scale(output, monitorRule.scale);
|
||||
|
||||
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, monitorRule.scale);
|
||||
wlr_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL); // TODO: support other transforms
|
||||
|
||||
// create it in the arr
|
||||
vecPosition = monitorRule.offset;
|
||||
@@ -123,16 +130,16 @@ void CMonitor::onConnect(bool noRule) {
|
||||
forceFullFrames = 3; // force 3 full frames to make sure there is no blinking due to double-buffering.
|
||||
//
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName});
|
||||
|
||||
if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet
|
||||
g_pCompositor->m_pLastMonitor = this;
|
||||
g_pCompositor->setActiveMonitor(this);
|
||||
|
||||
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, scale);
|
||||
|
||||
g_pHyprRenderer->arrangeLayersForMonitor(ID);
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName});
|
||||
|
||||
// ensure VRR (will enable if necessary)
|
||||
g_pConfigManager->ensureVRR(this);
|
||||
}
|
||||
@@ -142,6 +149,8 @@ void CMonitor::onDisconnect() {
|
||||
if (!m_bEnabled || g_pCompositor->m_bIsShuttingDown)
|
||||
return;
|
||||
|
||||
Debug::log(LOG, "onDisconnect called for %s", output->name);
|
||||
|
||||
// Cleanup everything. Move windows back, snap cursor, shit.
|
||||
CMonitor* BACKUPMON = nullptr;
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
@@ -152,7 +161,7 @@ void CMonitor::onDisconnect() {
|
||||
}
|
||||
|
||||
if (g_pCompositor->m_pLastMonitor == this)
|
||||
g_pCompositor->m_pLastMonitor = BACKUPMON;
|
||||
g_pCompositor->setActiveMonitor(BACKUPMON);
|
||||
|
||||
// remove mirror
|
||||
if (pMirrorOf) {
|
||||
@@ -176,7 +185,7 @@ void CMonitor::onDisconnect() {
|
||||
if (!BACKUPMON) {
|
||||
Debug::log(WARN, "Unplugged last monitor, entering an unsafe state. Good luck my friend.");
|
||||
|
||||
hyprListener_monitorMode.removeCallback();
|
||||
hyprListener_monitorStateRequest.removeCallback();
|
||||
hyprListener_monitorDestroy.removeCallback();
|
||||
|
||||
g_pCompositor->m_bUnsafeState = true;
|
||||
@@ -184,10 +193,8 @@ void CMonitor::onDisconnect() {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto BACKUPWORKSPACE = BACKUPMON->activeWorkspace > 0 ? std::to_string(BACKUPMON->activeWorkspace) : "name:" + g_pCompositor->getWorkspaceByID(BACKUPMON->activeWorkspace)->m_szName;
|
||||
|
||||
// snap cursor
|
||||
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, BACKUPMON->vecPosition.x + BACKUPMON->vecTransformedSize.x / 2.f, BACKUPMON->vecPosition.y + BACKUPMON->vecTransformedSize.y / 2.f);
|
||||
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, BACKUPMON->vecPosition.x + BACKUPMON->vecTransformedSize.x / 2.f, BACKUPMON->vecPosition.y + BACKUPMON->vecTransformedSize.y / 2.f);
|
||||
|
||||
// move workspaces
|
||||
std::deque<CWorkspace*> wspToMove;
|
||||
@@ -212,13 +219,13 @@ void CMonitor::onDisconnect() {
|
||||
|
||||
wlr_output_commit(output);
|
||||
|
||||
g_pCompositor->m_vWorkspaces.erase(std::remove_if(g_pCompositor->m_vWorkspaces.begin(), g_pCompositor->m_vWorkspaces.end(), [&](std::unique_ptr<CWorkspace>& el) { return el->m_iMonitorID == ID; }));
|
||||
std::erase_if(g_pCompositor->m_vWorkspaces, [&](std::unique_ptr<CWorkspace>& el) { return el->m_iMonitorID == ID; });
|
||||
|
||||
Debug::log(LOG, "Removed monitor %s!", szName.c_str());
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName});
|
||||
|
||||
g_pCompositor->m_vMonitors.erase(std::remove_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](std::shared_ptr<CMonitor>& el) { return el.get() == this; }));
|
||||
std::erase_if(g_pCompositor->m_vMonitors, [&](std::shared_ptr<CMonitor>& el) { return el.get() == this; });
|
||||
}
|
||||
|
||||
void CMonitor::addDamage(pixman_region32_t* rg) {
|
||||
@@ -236,9 +243,9 @@ bool CMonitor::isMirror() {
|
||||
void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) {
|
||||
// Workspace
|
||||
std::string newDefaultWorkspaceName = "";
|
||||
auto WORKSPACEID = monitorRule.defaultWorkspace == "" ? g_pCompositor->m_vWorkspaces.size() + 1 : getWorkspaceIDFromString(monitorRule.defaultWorkspace, newDefaultWorkspaceName);
|
||||
int64_t WORKSPACEID = monitorRule.defaultWorkspace == "" ? g_pCompositor->m_vWorkspaces.size() + 1 : getWorkspaceIDFromString(monitorRule.defaultWorkspace, newDefaultWorkspaceName);
|
||||
|
||||
if (WORKSPACEID == INT_MAX || WORKSPACEID == (long unsigned int)SPECIAL_WORKSPACE_ID) {
|
||||
if (WORKSPACEID == INT_MAX || (WORKSPACEID >= SPECIAL_WORKSPACE_START && WORKSPACEID <= -2)) {
|
||||
WORKSPACEID = g_pCompositor->m_vWorkspaces.size() + 1;
|
||||
newDefaultWorkspaceName = std::to_string(WORKSPACEID);
|
||||
|
||||
@@ -320,7 +327,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
|
||||
|
||||
setupDefaultWS(RULE);
|
||||
|
||||
wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, output, (int)vecPosition.x, (int)vecPosition.y);
|
||||
g_pHyprRenderer->applyMonitorRule(this, (SMonitorRule*)&RULE, true); // will apply the offset and stuff
|
||||
} else {
|
||||
CMonitor* BACKUPMON = nullptr;
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
@@ -358,6 +365,6 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
|
||||
g_pCompositor->m_vMonitors.erase(std::remove_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](const auto& other) { return other.get() == this; }));
|
||||
}
|
||||
|
||||
g_pCompositor->m_pLastMonitor = g_pCompositor->m_vMonitors.front().get();
|
||||
g_pCompositor->setActiveMonitor(g_pCompositor->m_vMonitors.front().get());
|
||||
}
|
||||
}
|
||||
|
@@ -40,13 +40,14 @@ public:
|
||||
bool dpmsStatus = true;
|
||||
bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
|
||||
bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
|
||||
bool createdByUser = false;
|
||||
|
||||
// mirroring
|
||||
CMonitor* pMirrorOf = nullptr;
|
||||
std::vector<CMonitor*> mirrors;
|
||||
|
||||
// for the special workspace
|
||||
bool specialWorkspaceOpen = false;
|
||||
// for the special workspace. 0 means not open.
|
||||
int specialWorkspaceID = 0;
|
||||
|
||||
// Double-linked list because we need to have constant mem addresses for signals
|
||||
// We have to store pointers and use raw new/delete because they might be moved between them
|
||||
@@ -55,7 +56,7 @@ public:
|
||||
|
||||
DYNLISTENER(monitorFrame);
|
||||
DYNLISTENER(monitorDestroy);
|
||||
DYNLISTENER(monitorMode);
|
||||
DYNLISTENER(monitorStateRequest);
|
||||
|
||||
// hack: a group = workspaces on a monitor.
|
||||
// I don't really care lol :P
|
||||
|
@@ -3,8 +3,8 @@
|
||||
#include "../Compositor.hpp"
|
||||
|
||||
void addSurfaceGlobalOffset(SSurfaceTreeNode* node, int* lx, int* ly) {
|
||||
*lx += node->pSurface->sx;
|
||||
*ly += node->pSurface->sy;
|
||||
*lx += node->pSurface->current.dx;
|
||||
*ly += node->pSurface->current.dy;
|
||||
|
||||
if (node->offsetfn) {
|
||||
// This is the root node
|
||||
|
@@ -4,4 +4,5 @@
|
||||
SLayerSurface::SLayerSurface() {
|
||||
alpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), nullptr, AVARDAMAGE_ENTIRE);
|
||||
alpha.m_pLayer = this;
|
||||
alpha.registerVar();
|
||||
}
|
@@ -70,6 +70,7 @@ struct SRenderData {
|
||||
|
||||
// for blurring
|
||||
bool blur = false;
|
||||
bool blockBlurOptimization = false;
|
||||
|
||||
// only for windows, not popups
|
||||
bool squishOversized = true;
|
||||
|
@@ -31,6 +31,9 @@ CWorkspace::CWorkspace(int monitorID, std::string name, bool special) {
|
||||
m_fAlpha.create(AVARTYPE_FLOAT, special ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspace") : g_pConfigManager->getAnimationPropertyConfig("workspaces"), nullptr, AVARDAMAGE_ENTIRE);
|
||||
m_fAlpha.setValueAndWarp(255.f);
|
||||
|
||||
m_vRenderOffset.registerVar();
|
||||
m_fAlpha.registerVar();
|
||||
|
||||
g_pEventManager->postEvent({"createworkspace", m_szName}, true);
|
||||
}
|
||||
|
||||
@@ -93,7 +96,7 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
|
||||
}
|
||||
|
||||
// check LS-es
|
||||
if (in) {
|
||||
if (in && !m_bIsSpecialWorkspace) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||
for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
|
||||
if (!ls->fadingOut)
|
||||
|
@@ -133,6 +133,11 @@ struct wlr_xwayland_surface_configure_event {
|
||||
uint16_t mask; // xcb_config_window_t
|
||||
};
|
||||
|
||||
struct wlr_xwayland_minimize_event {
|
||||
struct wlr_xwayland_surface *surface;
|
||||
bool minimize;
|
||||
};
|
||||
|
||||
inline void wlr_xwayland_destroy(wlr_xwayland*) { }
|
||||
|
||||
inline void wlr_xwayland_surface_configure(wlr_xwayland_surface*, int, int, int, int) { }
|
||||
@@ -149,4 +154,8 @@ inline void wlr_xwayland_surface_close(wlr_xwayland_surface*) { }
|
||||
|
||||
inline void wlr_xwayland_surface_set_fullscreen(wlr_xwayland_surface*, bool) { }
|
||||
|
||||
inline void wlr_xwayland_surface_set_minimized(wlr_xwayland_surface *, bool) {}
|
||||
inline void wlr_xwayland_surface_set_minimized(wlr_xwayland_surface *, bool) { }
|
||||
|
||||
inline bool wlr_backend_is_x11(void*) { return false; }
|
||||
|
||||
inline void wlr_x11_output_create(void*) { }
|
@@ -67,10 +67,10 @@ void CHyprError::createQueued() {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
|
||||
#ifndef GLES2
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
|
||||
#endif
|
||||
#ifndef GLES2
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
|
||||
#endif
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
|
||||
|
||||
|
@@ -99,10 +99,15 @@ extern "C" {
|
||||
#include <wlr/types/wlr_text_input_v3.h>
|
||||
#include <wlr/types/wlr_touch.h>
|
||||
#include <wlr/types/wlr_switch.h>
|
||||
#include <wlr/config.h>
|
||||
#include <wlr/backend/headless.h>
|
||||
#include <wlr/backend/multi.h>
|
||||
#include <wlr/backend/wayland.h>
|
||||
|
||||
#include <drm_fourcc.h>
|
||||
|
||||
#ifndef NO_XWAYLAND
|
||||
#include <wlr/backend/x11.h>
|
||||
#include <wlr/xwayland.h>
|
||||
#include <X11/Xproto.h>
|
||||
#endif
|
||||
@@ -133,7 +138,4 @@ extern "C" {
|
||||
|
||||
#include "helpers/Vector2D.hpp"
|
||||
|
||||
#include "ext-workspace-unstable-v1-protocol.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include "ext-workspace-unstable-v1-protocol.h"
|
@@ -144,9 +144,9 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
|
||||
|
||||
CMonitor* PMONITOR = nullptr;
|
||||
|
||||
if (pNode->workspaceID == SPECIAL_WORKSPACE_ID) {
|
||||
if (g_pCompositor->isWorkspaceSpecial(pNode->workspaceID)) {
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
if (m->specialWorkspaceOpen) {
|
||||
if (m->specialWorkspaceID == pNode->workspaceID) {
|
||||
PMONITOR = m.get();
|
||||
break;
|
||||
}
|
||||
@@ -188,7 +188,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
|
||||
|
||||
const auto NODESONWORKSPACE = getNodesOnWorkspace(PWINDOW->m_iWorkspaceID);
|
||||
|
||||
if (*PNOGAPSWHENONLY && PWINDOW->m_iWorkspaceID != SPECIAL_WORKSPACE_ID && (NODESONWORKSPACE == 1 || (pNode->isGroupMember() && pNode->getGroupMemberCount() == NODESONWORKSPACE))) {
|
||||
if (*PNOGAPSWHENONLY && !g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID) && (NODESONWORKSPACE == 1 || (pNode->isGroupMember() && pNode->getGroupMemberCount() == NODESONWORKSPACE) || (PWINDOW->m_bIsFullscreen && g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) {
|
||||
PWINDOW->m_vRealPosition = calcPos - Vector2D(*PBORDERSIZE, *PBORDERSIZE);
|
||||
PWINDOW->m_vRealSize = calcSize + Vector2D(2 * *PBORDERSIZE, 2 * *PBORDERSIZE);
|
||||
|
||||
@@ -238,7 +238,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
|
||||
}
|
||||
}
|
||||
|
||||
if (PWINDOW->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) {
|
||||
if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID)) {
|
||||
// if special, we adjust the coords a bit
|
||||
static auto *const PSCALEFACTOR = &g_pConfigManager->getConfigValuePtr("dwindle:special_scale_factor")->floatValue;
|
||||
|
||||
@@ -293,7 +293,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
|
||||
SDwindleNodeData* OPENINGON;
|
||||
const auto MONFROMCURSOR = g_pCompositor->getMonitorFromCursor();
|
||||
|
||||
if (PMONITOR->ID == MONFROMCURSOR->ID && (PNODE->workspaceID == PMONITOR->activeWorkspace || (PNODE->workspaceID == SPECIAL_WORKSPACE_ID && PMONITOR->specialWorkspaceOpen)) && !*PUSEACTIVE) {
|
||||
if (PMONITOR->ID == MONFROMCURSOR->ID && (PNODE->workspaceID == PMONITOR->activeWorkspace || (g_pCompositor->isWorkspaceSpecial(PNODE->workspaceID) && PMONITOR->specialWorkspaceID)) && !*PUSEACTIVE) {
|
||||
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(g_pInputManager->getMouseCoordsInternal()));
|
||||
|
||||
// happens on reserved area
|
||||
@@ -336,6 +336,16 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
|
||||
g_pCompositor->setWindowFullscreen(PFULLWINDOW, false, FULLSCREEN_FULL);
|
||||
}
|
||||
|
||||
// last fail-safe to avoid duplicate fullscreens
|
||||
if ((!OPENINGON || OPENINGON->pWindow == pWindow) && getNodesOnWorkspace(PNODE->workspaceID) > 1) {
|
||||
for (auto& node : m_lDwindleNodesData) {
|
||||
if (node.workspaceID == PNODE->workspaceID && node.pWindow != pWindow) {
|
||||
OPENINGON = &node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if it's the first, it's easy. Make it fullscreen.
|
||||
if (!OPENINGON || OPENINGON->pWindow == pWindow) {
|
||||
PNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
|
||||
@@ -457,6 +467,10 @@ void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
pWindow->m_sSpecialRenderData.rounding = true;
|
||||
pWindow->m_sSpecialRenderData.border = true;
|
||||
pWindow->m_sSpecialRenderData.decorate = true;
|
||||
|
||||
if (pWindow->m_bIsFullscreen)
|
||||
g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL);
|
||||
|
||||
@@ -563,8 +577,8 @@ void CHyprDwindleLayout::recalculateMonitor(const int& monid) {
|
||||
|
||||
g_pHyprRenderer->damageMonitor(PMONITOR);
|
||||
|
||||
if (PMONITOR->specialWorkspaceOpen) {
|
||||
const auto TOPNODE = getMasterNodeOnWorkspace(SPECIAL_WORKSPACE_ID);
|
||||
if (PMONITOR->specialWorkspaceID) {
|
||||
const auto TOPNODE = getMasterNodeOnWorkspace(PMONITOR->specialWorkspaceID);
|
||||
|
||||
if (TOPNODE && PMONITOR) {
|
||||
TOPNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
|
||||
@@ -705,7 +719,7 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
|
||||
if (!g_pCompositor->windowValidMapped(pWindow))
|
||||
return;
|
||||
|
||||
if (on == pWindow->m_bIsFullscreen || pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
|
||||
if (on == pWindow->m_bIsFullscreen || g_pCompositor->isWorkspaceSpecial(pWindow->m_iWorkspaceID))
|
||||
return; // ignore
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
|
||||
@@ -1008,6 +1022,8 @@ void CHyprDwindleLayout::switchGroupWindow(CWindow* pWindow, bool forward, CWind
|
||||
|
||||
pNewNode->pWindow->updateWindowDecos();
|
||||
PNODE->pWindow->updateWindowDecos();
|
||||
|
||||
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID));
|
||||
}
|
||||
|
||||
SWindowRenderLayoutHints CHyprDwindleLayout::requestRenderHints(CWindow* pWindow) {
|
||||
@@ -1132,6 +1148,9 @@ void CHyprDwindleLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
|
||||
ACTIVE2->pWindow->m_vPosition = ACTIVE2->position;
|
||||
ACTIVE2->pWindow->m_vSize = ACTIVE2->size;
|
||||
}
|
||||
|
||||
g_pHyprRenderer->damageWindow(pWindow);
|
||||
g_pHyprRenderer->damageWindow(pWindow2);
|
||||
}
|
||||
|
||||
void CHyprDwindleLayout::alterSplitRatioBy(CWindow* pWindow, float ratio) {
|
||||
|
@@ -21,6 +21,9 @@ void IHyprLayout::onWindowCreated(CWindow* pWindow) {
|
||||
}
|
||||
|
||||
void IHyprLayout::onWindowRemoved(CWindow* pWindow) {
|
||||
if (pWindow->m_bIsFullscreen)
|
||||
g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL);
|
||||
|
||||
if (pWindow->m_bIsFloating) {
|
||||
onWindowRemovedFloating(pWindow);
|
||||
} else {
|
||||
@@ -134,6 +137,8 @@ void IHyprLayout::onBeginDragWindow() {
|
||||
return;
|
||||
}
|
||||
|
||||
g_pInputManager->setCursorImageUntilUnset("hand1");
|
||||
|
||||
DRAGGINGWINDOW->m_vRealPosition.setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsMove"));
|
||||
DRAGGINGWINDOW->m_vRealSize.setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsMove"));
|
||||
|
||||
@@ -181,12 +186,17 @@ void IHyprLayout::onEndDragWindow() {
|
||||
if (!g_pCompositor->windowValidMapped(DRAGGINGWINDOW))
|
||||
return;
|
||||
|
||||
g_pInputManager->unsetCursorImage();
|
||||
|
||||
if (DRAGGINGWINDOW->m_bDraggingTiled) {
|
||||
DRAGGINGWINDOW->m_bIsFloating = false;
|
||||
g_pInputManager->refocus();
|
||||
changeWindowFloatingMode(DRAGGINGWINDOW);
|
||||
}
|
||||
|
||||
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
|
||||
|
||||
g_pCompositor->focusWindow(DRAGGINGWINDOW);
|
||||
}
|
||||
|
||||
void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
|
||||
@@ -296,11 +306,11 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
|
||||
pWindow->moveToWorkspace(PNEWMON->activeWorkspace);
|
||||
|
||||
// save real pos cuz the func applies the default 5,5 mid
|
||||
const auto PSAVEDPOS = pWindow->m_vRealPosition.vec();
|
||||
const auto PSAVEDSIZE = pWindow->m_vRealSize.vec();
|
||||
const auto PSAVEDPOS = pWindow->m_vRealPosition.goalv();
|
||||
const auto PSAVEDSIZE = pWindow->m_vRealSize.goalv();
|
||||
|
||||
// if the window is pseudo, update its size
|
||||
pWindow->m_vPseudoSize = pWindow->m_vRealSize.vec();
|
||||
pWindow->m_vPseudoSize = pWindow->m_vRealSize.goalv();
|
||||
|
||||
pWindow->m_vLastFloatingSize = PSAVEDSIZE;
|
||||
|
||||
@@ -318,16 +328,16 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
|
||||
if (pWindow == g_pCompositor->m_pLastWindow)
|
||||
m_pLastTiledWindow = pWindow;
|
||||
} else {
|
||||
pWindow->m_vSize = pWindow->m_vRealSize.vec();
|
||||
pWindow->m_vPosition = pWindow->m_vRealPosition.vec();
|
||||
|
||||
onWindowRemovedTiling(pWindow);
|
||||
|
||||
g_pCompositor->moveWindowToTop(pWindow);
|
||||
|
||||
pWindow->m_vRealPosition = pWindow->m_vRealPosition.vec() + (pWindow->m_vRealSize.vec() - pWindow->m_vLastFloatingSize) / 2.f;
|
||||
pWindow->m_vRealPosition = pWindow->m_vRealPosition.goalv() + (pWindow->m_vRealSize.goalv() - pWindow->m_vLastFloatingSize) / 2.f;
|
||||
pWindow->m_vRealSize = pWindow->m_vLastFloatingSize;
|
||||
|
||||
pWindow->m_vSize = pWindow->m_vRealSize.goalv();
|
||||
pWindow->m_vPosition = pWindow->m_vRealPosition.goalv();
|
||||
|
||||
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID));
|
||||
|
||||
pWindow->m_sSpecialRenderData.rounding = true;
|
||||
@@ -373,8 +383,17 @@ CWindow* IHyprLayout::getNextWindowCandidate(CWindow* pWindow) {
|
||||
return g_pCompositor->getFullscreenWindowOnWorkspace(pWindow->m_iWorkspaceID);
|
||||
|
||||
if (pWindow->m_bIsFloating) {
|
||||
// the window was floating, let's try the last tiled window.
|
||||
|
||||
// find whether there is a floating window below this one
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && !w->m_bX11ShouldntFocus && !w->m_bNoFocus) {
|
||||
if (VECINRECT((pWindow->m_vSize / 2.f + pWindow->m_vPosition), w->m_vPosition.x, w->m_vPosition.y, w->m_vPosition.x + w->m_vSize.x, w->m_vPosition.y + w->m_vSize.y)) {
|
||||
return w.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// let's try the last tiled window.
|
||||
if (m_pLastTiledWindow && m_pLastTiledWindow->m_iWorkspaceID == pWindow->m_iWorkspaceID)
|
||||
return m_pLastTiledWindow;
|
||||
|
||||
@@ -400,3 +419,6 @@ CWindow* IHyprLayout::getNextWindowCandidate(CWindow* pWindow) {
|
||||
|
||||
return PWINDOWCANDIDATE;
|
||||
}
|
||||
|
||||
IHyprLayout::~IHyprLayout() {
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@ enum eFullscreenMode : uint8_t;
|
||||
|
||||
interface IHyprLayout {
|
||||
public:
|
||||
virtual ~IHyprLayout() = 0;
|
||||
virtual void onEnable() = 0;
|
||||
virtual void onDisable() = 0;
|
||||
|
||||
|
@@ -20,6 +20,16 @@ int CHyprMasterLayout::getNodesOnWorkspace(const int& ws) {
|
||||
return no;
|
||||
}
|
||||
|
||||
int CHyprMasterLayout::getMastersOnWorkspace(const int& ws) {
|
||||
int no = 0;
|
||||
for (auto& n : m_lMasterNodesData) {
|
||||
if (n.workspaceID == ws && n.isMaster)
|
||||
no++;
|
||||
}
|
||||
|
||||
return no;
|
||||
}
|
||||
|
||||
std::string CHyprMasterLayout::getLayoutName() {
|
||||
return "Master";
|
||||
}
|
||||
@@ -101,13 +111,19 @@ void CHyprMasterLayout::onWindowRemovedTiling(CWindow* pWindow) {
|
||||
if (!PNODE)
|
||||
return;
|
||||
|
||||
pWindow->m_sSpecialRenderData.rounding = true;
|
||||
pWindow->m_sSpecialRenderData.border = true;
|
||||
pWindow->m_sSpecialRenderData.decorate = true;
|
||||
|
||||
if (pWindow->m_bIsFullscreen)
|
||||
g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL);
|
||||
|
||||
if (PNODE->isMaster) {
|
||||
const auto MASTERSLEFT = getMastersOnWorkspace(PNODE->workspaceID);
|
||||
|
||||
if (PNODE->isMaster && MASTERSLEFT < 2) {
|
||||
// find new one
|
||||
for (auto& nd : m_lMasterNodesData) {
|
||||
if (!nd.isMaster) {
|
||||
if (!nd.isMaster && nd.workspaceID == PNODE->workspaceID) {
|
||||
nd.isMaster = true;
|
||||
break;
|
||||
}
|
||||
@@ -116,6 +132,15 @@ void CHyprMasterLayout::onWindowRemovedTiling(CWindow* pWindow) {
|
||||
|
||||
m_lMasterNodesData.remove(*PNODE);
|
||||
|
||||
if (getMastersOnWorkspace(PNODE->workspaceID) == getNodesOnWorkspace(PNODE->workspaceID) && MASTERSLEFT > 1) {
|
||||
for (auto it = m_lMasterNodesData.rbegin(); it != m_lMasterNodesData.rend(); it++) {
|
||||
if (it->workspaceID == PNODE->workspaceID) {
|
||||
it->isMaster = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
recalculateMonitor(pWindow->m_iMonitorID);
|
||||
}
|
||||
|
||||
@@ -128,8 +153,8 @@ void CHyprMasterLayout::recalculateMonitor(const int& monid) {
|
||||
|
||||
g_pHyprRenderer->damageMonitor(PMONITOR);
|
||||
|
||||
if (PMONITOR->specialWorkspaceOpen) {
|
||||
calculateWorkspace(SPECIAL_WORKSPACE_ID);
|
||||
if (PMONITOR->specialWorkspaceID) {
|
||||
calculateWorkspace(PMONITOR->specialWorkspaceID);
|
||||
}
|
||||
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow) {
|
||||
@@ -169,32 +194,52 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
|
||||
if (!PMASTERNODE)
|
||||
return;
|
||||
|
||||
const auto MASTERS = getMastersOnWorkspace(PWORKSPACE->m_iID);
|
||||
|
||||
if (getNodesOnWorkspace(PWORKSPACE->m_iID) < 2) {
|
||||
PMASTERNODE->position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition;
|
||||
PMASTERNODE->size = Vector2D(PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x, PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y);
|
||||
applyNodeDataToWindow(PMASTERNODE);
|
||||
return;
|
||||
} else {
|
||||
PMASTERNODE->position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition;
|
||||
PMASTERNODE->size = Vector2D((PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x) * PMASTERNODE->percMaster, PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y);
|
||||
float heightLeft = PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y;
|
||||
int nodesLeft = MASTERS;
|
||||
float nextY = 0;
|
||||
|
||||
for (auto& n : m_lMasterNodesData) {
|
||||
if (n.workspaceID == PWORKSPACE->m_iID && n.isMaster) {
|
||||
n.position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition + Vector2D(0, nextY);
|
||||
float HEIGHT = nodesLeft > 1 ? heightLeft / nodesLeft * n.percSize : heightLeft;
|
||||
if (HEIGHT > heightLeft * 0.9f && nodesLeft > 1)
|
||||
HEIGHT = heightLeft * 0.9f;
|
||||
n.size = Vector2D((PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x) * PMASTERNODE->percMaster, HEIGHT);
|
||||
|
||||
nodesLeft--;
|
||||
heightLeft -= HEIGHT;
|
||||
nextY += HEIGHT;
|
||||
|
||||
applyNodeDataToWindow(&n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto SLAVESIZE = 1.f / (getNodesOnWorkspace(PWORKSPACE->m_iID) - 1) * (PMASTERNODE->size.y);
|
||||
int slavesDone = 0;
|
||||
float heightLeft = PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y;
|
||||
int slavesLeft = getNodesOnWorkspace(PWORKSPACE->m_iID) - MASTERS;
|
||||
float nextY = 0;
|
||||
|
||||
for (auto& nd : m_lMasterNodesData) {
|
||||
if (nd.workspaceID != PWORKSPACE->m_iID)
|
||||
if (nd.workspaceID != PWORKSPACE->m_iID || nd.isMaster)
|
||||
continue;
|
||||
|
||||
if (nd == *PMASTERNODE) {
|
||||
applyNodeDataToWindow(PMASTERNODE);
|
||||
continue;
|
||||
}
|
||||
nd.position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition + Vector2D(PMASTERNODE->percMaster * PMONITOR->vecSize.x, nextY);
|
||||
float HEIGHT = slavesLeft > 1 ? heightLeft / slavesLeft * nd.percSize : heightLeft;
|
||||
if (HEIGHT > heightLeft * 0.9f && slavesLeft > 1)
|
||||
HEIGHT = heightLeft * 0.9f;
|
||||
nd.size = Vector2D(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PMONITOR->vecReservedTopLeft.x - PMASTERNODE->size.x, HEIGHT);
|
||||
|
||||
nd.position = Vector2D(PMASTERNODE->size.x + PMASTERNODE->position.x, slavesDone * SLAVESIZE + PMASTERNODE->position.y);
|
||||
nd.size = Vector2D(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PMONITOR->vecReservedTopLeft.x - PMASTERNODE->size.x, SLAVESIZE);
|
||||
|
||||
slavesDone++;
|
||||
slavesLeft--;
|
||||
heightLeft -= HEIGHT;
|
||||
nextY += HEIGHT;
|
||||
|
||||
applyNodeDataToWindow(&nd);
|
||||
}
|
||||
@@ -203,9 +248,9 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
|
||||
void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
|
||||
CMonitor* PMONITOR = nullptr;
|
||||
|
||||
if (pNode->workspaceID == SPECIAL_WORKSPACE_ID) {
|
||||
if (g_pCompositor->isWorkspaceSpecial(pNode->workspaceID)) {
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
if (m->specialWorkspaceOpen) {
|
||||
if (m->specialWorkspaceID == pNode->workspaceID) {
|
||||
PMONITOR = m.get();
|
||||
break;
|
||||
}
|
||||
@@ -244,7 +289,7 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
|
||||
auto calcPos = PWINDOW->m_vPosition + Vector2D(*PBORDERSIZE, *PBORDERSIZE);
|
||||
auto calcSize = PWINDOW->m_vSize - Vector2D(2 * *PBORDERSIZE, 2 * *PBORDERSIZE);
|
||||
|
||||
if (*PNOGAPSWHENONLY && PWINDOW->m_iWorkspaceID != SPECIAL_WORKSPACE_ID && getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) == 1) {
|
||||
if (*PNOGAPSWHENONLY && !g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID) && (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) == 1 || (PWINDOW->m_bIsFullscreen && g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) {
|
||||
PWINDOW->m_vRealPosition = calcPos - Vector2D(*PBORDERSIZE, *PBORDERSIZE);
|
||||
PWINDOW->m_vRealSize = calcSize + Vector2D(2 * *PBORDERSIZE, 2 * *PBORDERSIZE);
|
||||
|
||||
@@ -270,7 +315,7 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
|
||||
calcPos = calcPos + OFFSETTOPLEFT;
|
||||
calcSize = calcSize - OFFSETTOPLEFT - OFFSETBOTTOMRIGHT;
|
||||
|
||||
if (PWINDOW->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) {
|
||||
if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID)) {
|
||||
static auto *const PSCALEFACTOR = &g_pConfigManager->getConfigValuePtr("master:special_scale_factor")->floatValue;
|
||||
|
||||
PWINDOW->m_vRealPosition = calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f;
|
||||
@@ -309,13 +354,12 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow* p
|
||||
const auto PNODE = getNodeFromWindow(PWINDOW);
|
||||
|
||||
if (!PNODE) {
|
||||
PWINDOW->m_vRealSize = Vector2D(std::max((PWINDOW->m_vRealSize.goalv() + pixResize).x, 20.0), std::max((PWINDOW->m_vRealSize.goalv() + pixResize).y, 20.0));
|
||||
PWINDOW->m_vRealSize = Vector2D(std::max((PWINDOW->m_vRealSize.goalv() + pixResize).x, 20.0), std::max((PWINDOW->m_vRealSize.goalv() + pixResize).y, 20.0));
|
||||
PWINDOW->updateWindowDecos();
|
||||
return;
|
||||
}
|
||||
|
||||
// get master
|
||||
const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID);
|
||||
// get monitor
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
||||
|
||||
if (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) < 2)
|
||||
@@ -323,11 +367,24 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow* p
|
||||
|
||||
m_bForceWarps = true;
|
||||
|
||||
float delta = pixResize.x / PMONITOR->vecSize.x;
|
||||
double delta = pixResize.x / PMONITOR->vecSize.x;
|
||||
|
||||
PMASTER->percMaster += delta;
|
||||
for (auto& n : m_lMasterNodesData) {
|
||||
if (n.isMaster && n.workspaceID == PMONITOR->activeWorkspace)
|
||||
n.percMaster = std::clamp(n.percMaster + delta, 0.05, 0.95);
|
||||
}
|
||||
|
||||
std::clamp(PMASTER->percMaster, 0.05f, 0.95f);
|
||||
// check the up/down resize
|
||||
if (pixResize.y != 0) {
|
||||
if (PNODE->isMaster && getMastersOnWorkspace(PNODE->workspaceID) > 1) {
|
||||
// check master size
|
||||
const auto SIZEY = (PMONITOR->vecSize.y - PMONITOR->vecReservedTopLeft.y - PMONITOR->vecReservedBottomRight.y) / getMastersOnWorkspace(PNODE->workspaceID);
|
||||
PNODE->percSize = std::clamp(PNODE->percSize + pixResize.y / SIZEY, 0.05, 1.95);
|
||||
} else if (!PNODE->isMaster && (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) - getMastersOnWorkspace(PNODE->workspaceID)) > 1) {
|
||||
const auto SIZEY = (PMONITOR->vecSize.y - PMONITOR->vecReservedTopLeft.y - PMONITOR->vecReservedBottomRight.y) / getNodesOnWorkspace(PNODE->workspaceID);
|
||||
PNODE->percSize = std::clamp(PNODE->percSize + pixResize.y / SIZEY, 0.05, 1.95);
|
||||
}
|
||||
}
|
||||
|
||||
recalculateMonitor(PMONITOR->ID);
|
||||
|
||||
@@ -338,7 +395,7 @@ void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreen
|
||||
if (!g_pCompositor->windowValidMapped(pWindow))
|
||||
return;
|
||||
|
||||
if (on == pWindow->m_bIsFullscreen || pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
|
||||
if (on == pWindow->m_bIsFullscreen || g_pCompositor->isWorkspaceSpecial(pWindow->m_iWorkspaceID))
|
||||
return; // ignore
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
|
||||
@@ -445,6 +502,9 @@ void CHyprMasterLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
|
||||
recalculateMonitor(pWindow->m_iMonitorID);
|
||||
if (PNODE2->workspaceID != PNODE->workspaceID)
|
||||
recalculateMonitor(pWindow2->m_iMonitorID);
|
||||
|
||||
g_pHyprRenderer->damageWindow(pWindow);
|
||||
g_pHyprRenderer->damageWindow(pWindow2);
|
||||
}
|
||||
|
||||
void CHyprMasterLayout::alterSplitRatioBy(CWindow* pWindow, float ratio) {
|
||||
@@ -537,34 +597,73 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
|
||||
return;
|
||||
|
||||
g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
|
||||
Vector2D middle = PWINDOWTOCHANGETO->m_vRealPosition.goalv() + PWINDOWTOCHANGETO->m_vRealSize.goalv() / 2.f;
|
||||
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, middle.x, middle.y);
|
||||
g_pCompositor->warpCursorTo(PWINDOWTOCHANGETO->m_vRealPosition.goalv() + PWINDOWTOCHANGETO->m_vRealSize.goalv() / 2.f);
|
||||
};
|
||||
|
||||
if (message == "swapwithmaster") {
|
||||
|
||||
const auto PWINDOW = header.pWindow;
|
||||
|
||||
if (!PWINDOW)
|
||||
return 0;
|
||||
|
||||
if (!isWindowTiled(PWINDOW))
|
||||
return 0;
|
||||
|
||||
const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID);
|
||||
|
||||
if (!PMASTER || PMASTER->pWindow == PWINDOW)
|
||||
if (!PMASTER)
|
||||
return 0;
|
||||
|
||||
switchWindows(PWINDOW, PMASTER->pWindow);
|
||||
if (PMASTER->pWindow != PWINDOW) {
|
||||
switchWindows(PWINDOW, PMASTER->pWindow);
|
||||
switchToWindow(PWINDOW);
|
||||
} else {
|
||||
for (auto& n : m_lMasterNodesData) {
|
||||
if (n.workspaceID == PMASTER->workspaceID && !n.isMaster) {
|
||||
switchWindows(n.pWindow, PMASTER->pWindow);
|
||||
switchToWindow(n.pWindow);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switchToWindow(PWINDOW);
|
||||
return 0;
|
||||
} else if (message == "focusmaster") {
|
||||
const auto PWINDOW = header.pWindow;
|
||||
|
||||
if (!PWINDOW)
|
||||
return 0;
|
||||
|
||||
const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID);
|
||||
|
||||
if (!PMASTER)
|
||||
return 0;
|
||||
|
||||
if (PMASTER->pWindow != PWINDOW)
|
||||
switchToWindow(PMASTER->pWindow);
|
||||
else {
|
||||
for (auto& n : m_lMasterNodesData) {
|
||||
if (n.workspaceID == PMASTER->workspaceID && !n.isMaster) {
|
||||
switchToWindow(n.pWindow);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else if (message == "cyclenext") {
|
||||
const auto PWINDOW = header.pWindow;
|
||||
|
||||
if (!PWINDOW)
|
||||
return 0;
|
||||
|
||||
switchToWindow(getNextWindow(PWINDOW, true));
|
||||
} else if (message == "cycleprev") {
|
||||
const auto PWINDOW = header.pWindow;
|
||||
|
||||
if (!PWINDOW)
|
||||
return 0;
|
||||
|
||||
switchToWindow(getNextWindow(PWINDOW, false));
|
||||
} else if (message == "swapnext") {
|
||||
if (!g_pCompositor->windowValidMapped(header.pWindow))
|
||||
@@ -596,6 +695,64 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
|
||||
switchWindows(header.pWindow, PWINDOWTOSWAPWITH);
|
||||
g_pCompositor->focusWindow(header.pWindow);
|
||||
}
|
||||
} else if (message == "addmaster") {
|
||||
if (!g_pCompositor->windowValidMapped(header.pWindow))
|
||||
return 0;
|
||||
|
||||
if (header.pWindow->m_bIsFloating)
|
||||
return 0;
|
||||
|
||||
const auto PNODE = getNodeFromWindow(header.pWindow);
|
||||
|
||||
const auto WINDOWS = getNodesOnWorkspace(header.pWindow->m_iWorkspaceID);
|
||||
const auto MASTERS = getMastersOnWorkspace(header.pWindow->m_iWorkspaceID);
|
||||
|
||||
if (MASTERS + 2 > WINDOWS)
|
||||
return 0;
|
||||
|
||||
if (!PNODE || PNODE->isMaster) {
|
||||
// first non-master node
|
||||
for (auto& n : m_lMasterNodesData) {
|
||||
if (n.workspaceID == header.pWindow->m_iWorkspaceID && !n.isMaster) {
|
||||
n.isMaster = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PNODE->isMaster = true;
|
||||
}
|
||||
|
||||
recalculateMonitor(header.pWindow->m_iMonitorID);
|
||||
|
||||
} else if (message == "removemaster") {
|
||||
|
||||
if (!g_pCompositor->windowValidMapped(header.pWindow))
|
||||
return 0;
|
||||
|
||||
if (header.pWindow->m_bIsFloating)
|
||||
return 0;
|
||||
|
||||
const auto PNODE = getNodeFromWindow(header.pWindow);
|
||||
|
||||
const auto WINDOWS = getNodesOnWorkspace(header.pWindow->m_iWorkspaceID);
|
||||
const auto MASTERS = getMastersOnWorkspace(header.pWindow->m_iWorkspaceID);
|
||||
|
||||
if (WINDOWS < 2 || MASTERS < 2)
|
||||
return 0;
|
||||
|
||||
if (!PNODE || !PNODE->isMaster) {
|
||||
// first non-master node
|
||||
for (auto it = m_lMasterNodesData.rbegin(); it != m_lMasterNodesData.rend(); it++) {
|
||||
if (it->workspaceID == header.pWindow->m_iWorkspaceID && it->isMaster) {
|
||||
it->isMaster = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PNODE->isMaster = false;
|
||||
}
|
||||
|
||||
recalculateMonitor(header.pWindow->m_iMonitorID);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@@ -15,6 +15,8 @@ struct SMasterNodeData {
|
||||
Vector2D position;
|
||||
Vector2D size;
|
||||
|
||||
float percSize = 1.f; // size multiplier for resizing children
|
||||
|
||||
int workspaceID = -1;
|
||||
|
||||
bool operator==(const SMasterNodeData& rhs) {
|
||||
@@ -52,6 +54,7 @@ private:
|
||||
SMasterNodeData* getMasterNodeOnWorkspace(const int&);
|
||||
void calculateWorkspace(const int&);
|
||||
CWindow* getNextWindow(CWindow*, bool);
|
||||
int getMastersOnWorkspace(const int&);
|
||||
|
||||
friend struct SMasterNodeData;
|
||||
};
|
@@ -5,10 +5,6 @@
|
||||
#include "init/initHelpers.hpp"
|
||||
#include <iostream>
|
||||
|
||||
// I am a bad bad boy and have used some global vars here,
|
||||
// just for this file
|
||||
bool ignoreSudo = false;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
if (!getenv("XDG_RUNTIME_DIR"))
|
||||
@@ -19,9 +15,12 @@ int main(int argc, char** argv) {
|
||||
for (auto i = 0; i < argc; ++i)
|
||||
cmd += std::string(i == 0 ? "" : " ") + argv[i];
|
||||
setenv("HYPRLAND_CMD", cmd.c_str(), 1);
|
||||
setenv("XDG_BACKEND", "wayland", 1);
|
||||
setenv("_JAVA_AWT_WM_NONREPARENTING", "1", 0);
|
||||
|
||||
// parse some args
|
||||
std::string configPath;
|
||||
bool ignoreSudo = false;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (!strcmp(argv[i], "--i-am-really-stupid"))
|
||||
ignoreSudo = true;
|
||||
|
@@ -33,6 +33,8 @@ void CAnimationManager::tick() {
|
||||
|
||||
const auto DEFAULTBEZIER = m_mBezierCurves.find("default");
|
||||
|
||||
std::vector<CAnimatedVariable*> animationEndedVars;
|
||||
|
||||
for (auto& av : m_lAnimatedVariables) {
|
||||
|
||||
// first of all, check if we need to update it at all
|
||||
@@ -40,16 +42,12 @@ void CAnimationManager::tick() {
|
||||
continue;
|
||||
|
||||
if (av->m_eDamagePolicy == AVARDAMAGE_SHADOW && !*PSHADOWSENABLED) {
|
||||
av->warp();
|
||||
av->warp(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
// get speed
|
||||
const auto SPEED = av->m_pConfig->pValues->internalSpeed;
|
||||
|
||||
// get the spent % (0 - 1)
|
||||
const auto DURATIONPASSED = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - av->animationBegin).count();
|
||||
const float SPENT = std::clamp((DURATIONPASSED / 100.f) / SPEED, 0.f, 1.f);
|
||||
const float SPENT = av->getPercent();
|
||||
|
||||
// window stuff
|
||||
const auto PWINDOW = (CWindow*)av->m_pWindow;
|
||||
@@ -78,12 +76,12 @@ void CAnimationManager::tick() {
|
||||
case AVARTYPE_FLOAT: {
|
||||
// for disabled anims just warp
|
||||
if (av->m_pConfig->pValues->internalEnabled == 0 || animationsDisabled) {
|
||||
av->warp();
|
||||
av->warp(false);
|
||||
break;
|
||||
}
|
||||
|
||||
if (SPENT >= 1.f) {
|
||||
av->warp();
|
||||
av->warp(false);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -99,12 +97,12 @@ void CAnimationManager::tick() {
|
||||
case AVARTYPE_VECTOR: {
|
||||
// for disabled anims just warp
|
||||
if (av->m_pConfig->pValues->internalEnabled == 0 || animationsDisabled) {
|
||||
av->warp();
|
||||
av->warp(false);
|
||||
break;
|
||||
}
|
||||
|
||||
if (SPENT >= 1.f) {
|
||||
av->warp();
|
||||
av->warp(false);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -120,12 +118,12 @@ void CAnimationManager::tick() {
|
||||
case AVARTYPE_COLOR: {
|
||||
// for disabled anims just warp
|
||||
if (av->m_pConfig->pValues->internalEnabled == 0 || animationsDisabled) {
|
||||
av->warp();
|
||||
av->warp(false);
|
||||
break;
|
||||
}
|
||||
|
||||
if (SPENT >= 1.f) {
|
||||
av->warp();
|
||||
av->warp(false);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -166,8 +164,7 @@ void CAnimationManager::tick() {
|
||||
g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AVARDAMAGE_BORDER: {
|
||||
} case AVARDAMAGE_BORDER: {
|
||||
RASSERT(PWINDOW, "Tried to AVARDAMAGE_BORDER a non-window AVAR!");
|
||||
|
||||
// damage only the border.
|
||||
@@ -225,13 +222,21 @@ void CAnimationManager::tick() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// set size and pos if valid, but only if damage policy entire (dont if border for example)
|
||||
if (g_pCompositor->windowValidMapped(PWINDOW) && av->m_eDamagePolicy == AVARDAMAGE_ENTIRE && PWINDOW->m_iX11Type != 2)
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
|
||||
|
||||
// manually schedule a frame
|
||||
g_pCompositor->scheduleFrameForMonitor(PMONITOR);
|
||||
|
||||
// check if we did not finish animating. If so, trigger onAnimationEnd.
|
||||
if (!av->isBeingAnimated())
|
||||
animationEndedVars.push_back(av);
|
||||
}
|
||||
|
||||
// do it here, because if this alters the animation vars deque we would be in trouble above.
|
||||
for (auto& ave : animationEndedVars) {
|
||||
ave->onAnimationEnd();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,7 +292,7 @@ void CAnimationManager::animationPopin(CWindow* pWindow, bool close, float minPe
|
||||
}
|
||||
|
||||
void CAnimationManager::animationSlide(CWindow* pWindow, std::string force, bool close) {
|
||||
pWindow->m_vRealSize.warp(); // size we preserve in slide
|
||||
pWindow->m_vRealSize.warp(false); // size we preserve in slide
|
||||
|
||||
const auto GOALPOS = pWindow->m_vRealPosition.goalv();
|
||||
const auto GOALSIZE = pWindow->m_vRealSize.goalv();
|
||||
|
@@ -72,8 +72,6 @@ void CEventManager::startThread() {
|
||||
// add to event loop so we can close it when we need to
|
||||
m_dAcceptedSocketFDs.push_back({ACCEPTEDCONNECTION, wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, ACCEPTEDCONNECTION, WL_EVENT_READABLE, fdHandleWrite, &m_dAcceptedSocketFDs)});
|
||||
}
|
||||
|
||||
ensureFDsValid();
|
||||
}
|
||||
|
||||
close(SOCKET);
|
||||
@@ -82,28 +80,7 @@ void CEventManager::startThread() {
|
||||
m_tThread.detach();
|
||||
}
|
||||
|
||||
void CEventManager::ensureFDsValid() {
|
||||
static char readBuf[1024] = {0};
|
||||
|
||||
// pong if all FDs valid
|
||||
for (auto it = m_dAcceptedSocketFDs.begin(); it != m_dAcceptedSocketFDs.end();) {
|
||||
auto sizeRead = recv(it->first, &readBuf, 1024, 0);
|
||||
|
||||
if (sizeRead != 0) {
|
||||
it++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// invalid!
|
||||
Debug::log(LOG, "Removed invalid socket (2) FD: %d", *it);
|
||||
it = m_dAcceptedSocketFDs.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void CEventManager::flushEvents() {
|
||||
|
||||
ensureFDsValid();
|
||||
|
||||
eventQueueMutex.lock();
|
||||
|
||||
for (auto& ev : m_dQueuedEvents) {
|
||||
|
@@ -26,7 +26,6 @@ public:
|
||||
private:
|
||||
|
||||
void flushEvents();
|
||||
void ensureFDsValid();
|
||||
|
||||
std::mutex eventQueueMutex;
|
||||
std::deque<SHyprIPCEvent> m_dQueuedEvents;
|
||||
|
@@ -16,6 +16,7 @@ CKeybindManager::CKeybindManager() {
|
||||
m_mDispatchers["pseudo"] = toggleActivePseudo;
|
||||
m_mDispatchers["movefocus"] = moveFocusTo;
|
||||
m_mDispatchers["movewindow"] = moveActiveTo;
|
||||
m_mDispatchers["centerwindow"] = centerWindow;
|
||||
m_mDispatchers["togglegroup"] = toggleGroup;
|
||||
m_mDispatchers["changegroupactive"] = changeGroupActive;
|
||||
m_mDispatchers["togglesplit"] = toggleSplit;
|
||||
@@ -164,7 +165,7 @@ bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pKeyboard->isVirtual)
|
||||
if (pKeyboard->isVirtual && g_pInputManager->shouldIgnoreVirtualKeyboard(pKeyboard))
|
||||
return true;
|
||||
|
||||
if (!m_pXKBTranslationState) {
|
||||
@@ -482,6 +483,17 @@ bool CKeybindManager::handleInternalKeybinds(xkb_keysym_t keysym) {
|
||||
// Dispatchers
|
||||
|
||||
void CKeybindManager::spawn(std::string args) {
|
||||
|
||||
args = removeBeginEndSpacesTabs(args);
|
||||
|
||||
std::string RULES = "";
|
||||
|
||||
if (args[0] == '[') {
|
||||
// we have exec rules
|
||||
RULES = args.substr(1, args.substr(1).find_first_of(']'));
|
||||
args = args.substr(args.find_first_of(']') + 1);
|
||||
}
|
||||
|
||||
if (g_pXWaylandManager->m_sWLRXWayland)
|
||||
args = "WAYLAND_DISPLAY=" + std::string(g_pCompositor->m_szWLDisplaySocket) + " DISPLAY=" + std::string(g_pXWaylandManager->m_sWLRXWayland->display_name) + " " + args;
|
||||
else
|
||||
@@ -534,7 +546,18 @@ void CKeybindManager::spawn(std::string args) {
|
||||
Debug::log(LOG, "Fail to create the second fork");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Process Created with pid %d", grandchild);
|
||||
|
||||
if (!RULES.empty()) {
|
||||
const auto RULESLIST = CVarList(RULES, 0, ';');
|
||||
|
||||
for (auto& r : RULESLIST) {
|
||||
g_pConfigManager->addExecRule({r, (unsigned long)grandchild});
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Applied %i rule arguments for exec.", RULESLIST.size());
|
||||
}
|
||||
}
|
||||
|
||||
void CKeybindManager::killActive(std::string args) {
|
||||
@@ -571,14 +594,28 @@ void CKeybindManager::toggleActiveFloating(std::string args) {
|
||||
// remove drag status
|
||||
g_pInputManager->currentlyDraggedWindow = nullptr;
|
||||
|
||||
if (PWINDOW->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
|
||||
if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID))
|
||||
return;
|
||||
|
||||
PWINDOW->m_bIsFloating = !PWINDOW->m_bIsFloating;
|
||||
|
||||
PWINDOW->updateDynamicRules();
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(PWINDOW);
|
||||
}
|
||||
|
||||
void CKeybindManager::centerWindow(std::string args) {
|
||||
const auto PWINDOW = g_pCompositor->m_pLastWindow;
|
||||
|
||||
if (!PWINDOW || !PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen)
|
||||
return;
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
||||
|
||||
PWINDOW->m_vRealPosition = PMONITOR->vecPosition + PMONITOR->vecSize / 2.f - PWINDOW->m_vRealSize.goalv() / 2.f;
|
||||
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goalv();
|
||||
}
|
||||
|
||||
void CKeybindManager::toggleActivePseudo(std::string args) {
|
||||
const auto ACTIVEWINDOW = g_pCompositor->m_pLastWindow;
|
||||
|
||||
@@ -617,7 +654,7 @@ void CKeybindManager::changeworkspace(std::string args) {
|
||||
return;
|
||||
} else {
|
||||
workspaceToChangeTo = PCURRENTWORKSPACE->m_iPrevWorkspaceID;
|
||||
|
||||
|
||||
if (const auto PWORKSPACETOCHANGETO = g_pCompositor->getWorkspaceByID(workspaceToChangeTo); PWORKSPACETOCHANGETO)
|
||||
workspaceName = PWORKSPACETOCHANGETO->m_szName;
|
||||
else
|
||||
@@ -645,12 +682,12 @@ void CKeybindManager::changeworkspace(std::string args) {
|
||||
const auto PCURRENTWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace);
|
||||
static auto *const PBACKANDFORTH = &g_pConfigManager->getConfigValuePtr("binds:workspace_back_and_forth")->intValue;
|
||||
|
||||
if (*PBACKANDFORTH && PCURRENTWORKSPACE->m_iID == workspaceToChangeTo && PCURRENTWORKSPACE->m_iPrevWorkspaceID != -1 && !internal) {
|
||||
if (*PBACKANDFORTH && PCURRENTWORKSPACE && PCURRENTWORKSPACE->m_iID == workspaceToChangeTo && PCURRENTWORKSPACE->m_iPrevWorkspaceID != -1 && !internal) {
|
||||
|
||||
const auto PPREVWORKSPACE = g_pCompositor->getWorkspaceByID(PCURRENTWORKSPACE->m_iPrevWorkspaceID);
|
||||
|
||||
workspaceToChangeTo = PCURRENTWORKSPACE->m_iPrevWorkspaceID;
|
||||
|
||||
|
||||
if (PPREVWORKSPACE)
|
||||
workspaceName = PPREVWORKSPACE->m_szName;
|
||||
else
|
||||
@@ -664,12 +701,14 @@ void CKeybindManager::changeworkspace(std::string args) {
|
||||
if (!*PALLOWWORKSPACECYCLES)
|
||||
PCURRENTWORKSPACE->m_iPrevWorkspaceID = -1;
|
||||
|
||||
} else if (PCURRENTWORKSPACE->m_iID == workspaceToChangeTo && !internal)
|
||||
} else if (PCURRENTWORKSPACE && PCURRENTWORKSPACE->m_iID == workspaceToChangeTo && !internal)
|
||||
return;
|
||||
|
||||
// remove constraints
|
||||
g_pInputManager->unconstrainMouse();
|
||||
|
||||
g_pInputManager->m_bEmptyFocusCursorSet = false;
|
||||
|
||||
// if it's not internal, we will unfocus to prevent stuck focus
|
||||
if (!internal)
|
||||
g_pCompositor->focusWindow(nullptr);
|
||||
@@ -684,7 +723,7 @@ void CKeybindManager::changeworkspace(std::string args) {
|
||||
// Remember previous workspace.
|
||||
PWORKSPACETOCHANGETO->m_iPrevWorkspaceID = g_pCompositor->m_pLastMonitor->activeWorkspace;
|
||||
|
||||
if (workspaceToChangeTo == SPECIAL_WORKSPACE_ID)
|
||||
if (g_pCompositor->isWorkspaceSpecial(workspaceToChangeTo))
|
||||
PWORKSPACETOCHANGETO->m_iMonitorID = PMONITOR->ID;
|
||||
|
||||
// if it's not visible, make it visible.
|
||||
@@ -699,10 +738,10 @@ void CKeybindManager::changeworkspace(std::string args) {
|
||||
}
|
||||
|
||||
// change it
|
||||
if (workspaceToChangeTo != SPECIAL_WORKSPACE_ID)
|
||||
if (!g_pCompositor->isWorkspaceSpecial(workspaceToChangeTo))
|
||||
PMONITOR->activeWorkspace = workspaceToChangeTo;
|
||||
else
|
||||
PMONITOR->specialWorkspaceOpen = true;
|
||||
PMONITOR->specialWorkspaceID = workspaceToChangeTo;
|
||||
|
||||
// here and only here begin anim. we don't want to anim visible workspaces on other monitors.
|
||||
// check if anim left or right
|
||||
@@ -718,11 +757,9 @@ void CKeybindManager::changeworkspace(std::string args) {
|
||||
}
|
||||
|
||||
// If the monitor is not the one our cursor's at, warp to it.
|
||||
const bool anotherMonitor = PMONITOR != g_pCompositor->getMonitorFromCursor();
|
||||
if (anotherMonitor) {
|
||||
Vector2D middle = PMONITOR->vecPosition + PMONITOR->vecSize / 2.f;
|
||||
g_pCompositor->warpCursorTo(middle);
|
||||
}
|
||||
const bool anotherMonitor = PMONITOR != g_pCompositor->m_pLastMonitor;
|
||||
if (anotherMonitor)
|
||||
g_pCompositor->warpCursorTo(PMONITOR->vecPosition + PMONITOR->vecSize / 2.f);
|
||||
|
||||
// set active and deactivate all other in wlr
|
||||
g_pCompositor->deactivateAllWLRWorkspaces(PWORKSPACETOCHANGETO->m_pWlrHandle);
|
||||
@@ -747,7 +784,7 @@ void CKeybindManager::changeworkspace(std::string args) {
|
||||
g_pInputManager->refocus();
|
||||
|
||||
// set the new monitor as the last (no warps would bug otherwise)
|
||||
g_pCompositor->m_pLastMonitor = g_pCompositor->getMonitorFromID(PWORKSPACETOCHANGETO->m_iMonitorID);
|
||||
g_pCompositor->setActiveMonitor(g_pCompositor->getMonitorFromID(PWORKSPACETOCHANGETO->m_iMonitorID));
|
||||
|
||||
// mark the monitor dirty
|
||||
g_pHyprRenderer->damageMonitor(PMONITOR);
|
||||
@@ -771,6 +808,8 @@ void CKeybindManager::changeworkspace(std::string args) {
|
||||
|
||||
const auto PWORKSPACE = g_pCompositor->createNewWorkspace(workspaceToChangeTo, PMONITOR->ID, workspaceName);
|
||||
|
||||
const bool ANOTHERMONITOR = PMONITOR != g_pCompositor->m_pLastMonitor;
|
||||
|
||||
if (!isSwitchingToPrevious)
|
||||
// Remember previous workspace.
|
||||
PWORKSPACE->m_iPrevWorkspaceID = OLDWORKSPACE;
|
||||
@@ -778,7 +817,7 @@ void CKeybindManager::changeworkspace(std::string args) {
|
||||
// start anim on new workspace
|
||||
PWORKSPACE->startAnim(true, ANIMTOLEFT);
|
||||
|
||||
PMONITOR->specialWorkspaceOpen = false;
|
||||
PMONITOR->specialWorkspaceID = 0;
|
||||
|
||||
// fix pinned windows
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
@@ -787,10 +826,10 @@ void CKeybindManager::changeworkspace(std::string args) {
|
||||
}
|
||||
}
|
||||
|
||||
if (workspaceToChangeTo != SPECIAL_WORKSPACE_ID)
|
||||
if (!g_pCompositor->isWorkspaceSpecial(workspaceToChangeTo))
|
||||
PMONITOR->activeWorkspace = workspaceToChangeTo;
|
||||
else
|
||||
PMONITOR->specialWorkspaceOpen = true;
|
||||
PMONITOR->specialWorkspaceID = workspaceToChangeTo;
|
||||
|
||||
// set active and deactivate all other
|
||||
g_pCompositor->deactivateAllWLRWorkspaces(PWORKSPACE->m_pWlrHandle);
|
||||
@@ -803,13 +842,16 @@ void CKeybindManager::changeworkspace(std::string args) {
|
||||
if (g_pCompositor->m_pLastMonitor != PMONITOR)
|
||||
g_pCompositor->warpCursorTo(PMONITOR->vecPosition + PMONITOR->vecSize / 2.f);
|
||||
|
||||
g_pCompositor->m_pLastMonitor = PMONITOR;
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"workspace", PWORKSPACE->m_szName});
|
||||
|
||||
g_pCompositor->setActiveMonitor(PMONITOR);
|
||||
|
||||
// focus (clears the last)
|
||||
g_pInputManager->refocus();
|
||||
|
||||
// Event
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"workspace", PWORKSPACE->m_szName});
|
||||
// Events
|
||||
if (ANOTHERMONITOR)
|
||||
g_pCompositor->warpCursorTo(PMONITOR->vecPosition + PMONITOR->vecSize / 2.f);
|
||||
|
||||
Debug::log(LOG, "Changed to workspace %i", workspaceToChangeTo);
|
||||
}
|
||||
@@ -820,7 +862,7 @@ void CKeybindManager::fullscreenActive(std::string args) {
|
||||
if (!PWINDOW)
|
||||
return;
|
||||
|
||||
if (PWINDOW->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
|
||||
if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID))
|
||||
return;
|
||||
|
||||
g_pCompositor->setWindowFullscreen(PWINDOW, !PWINDOW->m_bIsFullscreen, args == "1" ? FULLSCREEN_MAXIMIZED : FULLSCREEN_FULL);
|
||||
@@ -843,8 +885,8 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
|
||||
const auto OLDWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID);
|
||||
|
||||
// hack
|
||||
std::string unusedName;
|
||||
const auto WORKSPACEID = getWorkspaceIDFromString(args, unusedName);
|
||||
std::string workspaceName;
|
||||
const auto WORKSPACEID = getWorkspaceIDFromString(args, workspaceName);
|
||||
|
||||
if (WORKSPACEID == PWINDOW->m_iWorkspaceID) {
|
||||
Debug::log(LOG, "Not moving to workspace because it didn't change.");
|
||||
@@ -853,12 +895,11 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
|
||||
|
||||
auto PSAVEDSIZE = PWINDOW->m_vRealSize.goalv();
|
||||
auto PSAVEDPOS = PWINDOW->m_vRealPosition.goalv();
|
||||
const bool WASFULLSCREEN = PWINDOW->m_bIsFullscreen;
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW);
|
||||
|
||||
g_pKeybindManager->changeworkspace(args);
|
||||
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);
|
||||
auto PWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);
|
||||
|
||||
if (PWORKSPACE == OLDWORKSPACE) {
|
||||
Debug::log(LOG, "Not moving to workspace because it didn't change.");
|
||||
@@ -866,19 +907,13 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
|
||||
}
|
||||
|
||||
if (!PWORKSPACE) {
|
||||
Debug::log(ERR, "Workspace null in moveActiveToWorkspace?");
|
||||
return;
|
||||
// create
|
||||
PWORKSPACE = g_pCompositor->createNewWorkspace(WORKSPACEID, OLDWORKSPACE->m_iMonitorID, workspaceName);
|
||||
}
|
||||
|
||||
OLDWORKSPACE->m_bHasFullscreenWindow = false;
|
||||
|
||||
PWINDOW->moveToWorkspace(PWORKSPACE->m_iID);
|
||||
PWINDOW->m_iMonitorID = PWORKSPACE->m_iMonitorID;
|
||||
|
||||
if (PWINDOW->m_bIsFullscreen) {
|
||||
g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL);
|
||||
}
|
||||
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow) {
|
||||
g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), false, FULLSCREEN_FULL);
|
||||
}
|
||||
@@ -895,17 +930,14 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
|
||||
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.vec();
|
||||
}
|
||||
|
||||
// undo the damage if we are moving to the special workspace
|
||||
if (WORKSPACEID == SPECIAL_WORKSPACE_ID) {
|
||||
changeworkspace("[internal]" + std::to_string(OLDWORKSPACE->m_iID));
|
||||
OLDWORKSPACE->startAnim(true, true, true);
|
||||
toggleSpecialWorkspace("");
|
||||
g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID)->startAnim(false, false, true);
|
||||
if (WASFULLSCREEN)
|
||||
g_pCompositor->setWindowFullscreen(PWINDOW, true, OLDWORKSPACE->m_efFullscreenMode);
|
||||
|
||||
for (auto& m : g_pCompositor->m_vMonitors)
|
||||
m->specialWorkspaceOpen = false;
|
||||
} else {
|
||||
if (!g_pCompositor->isWorkspaceSpecial(WORKSPACEID)) {
|
||||
g_pKeybindManager->changeworkspace(args);
|
||||
g_pCompositor->focusWindow(PWINDOW);
|
||||
} else {
|
||||
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID));
|
||||
}
|
||||
|
||||
PWINDOW->updateToplevel();
|
||||
@@ -1023,10 +1055,8 @@ void CKeybindManager::moveFocusTo(std::string args) {
|
||||
if (PLASTWINDOW->m_iMonitorID != PWINDOWTOCHANGETO->m_iMonitorID) {
|
||||
// event
|
||||
const auto PNEWMON = g_pCompositor->getMonitorFromID(PWINDOWTOCHANGETO->m_iMonitorID);
|
||||
const auto PNEWWS = g_pCompositor->getWorkspaceByID(PNEWMON->activeWorkspace);
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", PNEWMON->szName + "," + PNEWWS->m_szName});
|
||||
|
||||
g_pCompositor->m_pLastMonitor = PNEWMON;
|
||||
g_pCompositor->setActiveMonitor(PNEWMON);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1135,7 +1165,7 @@ void CKeybindManager::alterSplitRatio(std::string args) {
|
||||
void CKeybindManager::focusMonitor(std::string arg) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromString(arg);
|
||||
|
||||
if (!PMONITOR)
|
||||
if (!PMONITOR || PMONITOR == g_pCompositor->m_pLastMonitor)
|
||||
return;
|
||||
|
||||
changeworkspace("[internal]" + std::to_string(PMONITOR->activeWorkspace));
|
||||
@@ -1288,52 +1318,93 @@ void CKeybindManager::moveWorkspaceToMonitor(std::string args) {
|
||||
|
||||
void CKeybindManager::toggleSpecialWorkspace(std::string args) {
|
||||
|
||||
if (g_pCompositor->getWindowsOnWorkspace(SPECIAL_WORKSPACE_ID) == 0) {
|
||||
static auto *const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
|
||||
|
||||
std::string workspaceName = "";
|
||||
int workspaceID = getWorkspaceIDFromString("special:" + args, workspaceName);
|
||||
|
||||
if (workspaceID == INT_MAX || !g_pCompositor->isWorkspaceSpecial(workspaceID)) {
|
||||
Debug::log(ERR, "Invalid workspace passed to special");
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_pCompositor->getWindowsOnWorkspace(workspaceID) == 0) {
|
||||
Debug::log(LOG, "Can't open empty special workspace!");
|
||||
return;
|
||||
}
|
||||
|
||||
bool open = false;
|
||||
bool requestedWorkspaceIsAlreadyOpen = false;
|
||||
const auto PMONITOR = *PFOLLOWMOUSE == 1 ? g_pCompositor->getMonitorFromCursor() : g_pCompositor->m_pLastMonitor;
|
||||
int specialOpenOnMonitor = PMONITOR->specialWorkspaceID;
|
||||
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
if (m->specialWorkspaceOpen) {
|
||||
open = true;
|
||||
if (m->specialWorkspaceID == workspaceID) {
|
||||
requestedWorkspaceIsAlreadyOpen = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (open)
|
||||
Debug::log(LOG, "Toggling special workspace to closed");
|
||||
if (requestedWorkspaceIsAlreadyOpen && specialOpenOnMonitor == workspaceID)
|
||||
Debug::log(LOG, "Toggling special workspace %d to closed");
|
||||
else
|
||||
Debug::log(LOG, "Toggling special workspace to open");
|
||||
Debug::log(LOG, "Toggling special workspace %d to open");
|
||||
|
||||
if (open) {
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
if (m->specialWorkspaceOpen != !open) {
|
||||
m->specialWorkspaceOpen = !open;
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
|
||||
if (requestedWorkspaceIsAlreadyOpen && specialOpenOnMonitor == workspaceID) {
|
||||
// already open on this monitor
|
||||
|
||||
g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID)->startAnim(false, false);
|
||||
}
|
||||
PMONITOR->specialWorkspaceID = 0;
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
|
||||
|
||||
g_pCompositor->getWorkspaceByID(workspaceID)->startAnim(false, false);
|
||||
|
||||
if (const auto PWINDOW = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace)->getLastFocusedWindow(); PWINDOW)
|
||||
g_pCompositor->focusWindow(PWINDOW);
|
||||
else
|
||||
g_pInputManager->refocus();
|
||||
} else if (requestedWorkspaceIsAlreadyOpen) {
|
||||
// already open on another monitor
|
||||
|
||||
if (specialOpenOnMonitor) {
|
||||
g_pCompositor->getWorkspaceByID(PMONITOR->specialWorkspaceID)->startAnim(false, false);
|
||||
PMONITOR->specialWorkspaceID = 0;
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
|
||||
}
|
||||
|
||||
if (const auto PWINDOW = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace)->getLastFocusedWindow(); PWINDOW)
|
||||
// move to current
|
||||
const auto PSPECIALWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceID);
|
||||
const auto POLDMON = g_pCompositor->getMonitorFromID(PSPECIALWORKSPACE->m_iMonitorID);
|
||||
|
||||
POLDMON->specialWorkspaceID = 0;
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(POLDMON->ID);
|
||||
PMONITOR->specialWorkspaceID = workspaceID;
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
|
||||
PSPECIALWORKSPACE->m_iMonitorID = PMONITOR->ID;
|
||||
|
||||
if (const auto PWINDOW = PSPECIALWORKSPACE->getLastFocusedWindow(); PWINDOW)
|
||||
g_pCompositor->focusWindow(PWINDOW);
|
||||
else
|
||||
g_pInputManager->refocus();
|
||||
} else {
|
||||
auto PSPECIALWORKSPACE = g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID);
|
||||
// not open anywhere
|
||||
|
||||
if (specialOpenOnMonitor) {
|
||||
g_pCompositor->getWorkspaceByID(PMONITOR->specialWorkspaceID)->startAnim(false, false);
|
||||
PMONITOR->specialWorkspaceID = 0;
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
|
||||
}
|
||||
|
||||
auto PSPECIALWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceID);
|
||||
|
||||
if (!PSPECIALWORKSPACE) {
|
||||
// ??? happens sometimes...?
|
||||
PSPECIALWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(g_pCompositor->m_pLastMonitor->ID, "special", true)).get();
|
||||
PSPECIALWORKSPACE = g_pCompositor->createNewWorkspace(workspaceID, PMONITOR->ID, workspaceName);
|
||||
}
|
||||
|
||||
g_pCompositor->m_pLastMonitor->specialWorkspaceOpen = true;
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(g_pCompositor->m_pLastMonitor->ID);
|
||||
PMONITOR->specialWorkspaceID = workspaceID;
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
|
||||
|
||||
PSPECIALWORKSPACE->m_iMonitorID = PMONITOR->ID;
|
||||
PSPECIALWORKSPACE->startAnim(true, true);
|
||||
PSPECIALWORKSPACE->m_iMonitorID = g_pCompositor->m_pLastMonitor->ID;
|
||||
|
||||
if (const auto PWINDOW = PSPECIALWORKSPACE->getLastFocusedWindow(); PWINDOW)
|
||||
g_pCompositor->focusWindow(PWINDOW);
|
||||
@@ -1426,7 +1497,7 @@ void CKeybindManager::circleNext(std::string arg) {
|
||||
if (PWINDOWTOCHANGETO == g_pCompositor->m_pLastWindow || !PWINDOWTOCHANGETO)
|
||||
return;
|
||||
|
||||
if (g_pCompositor->m_pLastWindow->m_iWorkspaceID == PWINDOWTOCHANGETO->m_iWorkspaceID && g_pCompositor->m_pLastWindow->m_bIsFullscreen) {
|
||||
if (g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->m_iWorkspaceID == PWINDOWTOCHANGETO->m_iWorkspaceID && g_pCompositor->m_pLastWindow->m_bIsFullscreen) {
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastWindow->m_iWorkspaceID);
|
||||
const auto FSMODE = PWORKSPACE->m_efFullscreenMode;
|
||||
|
||||
@@ -1585,6 +1656,7 @@ void CKeybindManager::toggleOpaque(std::string unused) {
|
||||
return;
|
||||
|
||||
PWINDOW->m_sAdditionalConfigData.forceOpaque = !PWINDOW->m_sAdditionalConfigData.forceOpaque;
|
||||
PWINDOW->m_sAdditionalConfigData.forceOpaqueOverriden = true;
|
||||
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
}
|
||||
@@ -1668,6 +1740,9 @@ void CKeybindManager::pinActive(std::string args) {
|
||||
g_pCompositor->m_pLastWindow->m_bPinned = !g_pCompositor->m_pLastWindow->m_bPinned;
|
||||
g_pCompositor->m_pLastWindow->m_iWorkspaceID = g_pCompositor->getMonitorFromID(g_pCompositor->m_pLastWindow->m_iMonitorID)->activeWorkspace;
|
||||
|
||||
g_pCompositor->m_pLastWindow->updateDynamicRules();
|
||||
g_pCompositor->updateWindowAnimatedDecorationValues(g_pCompositor->m_pLastWindow);
|
||||
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastWindow->m_iWorkspaceID);
|
||||
|
||||
PWORKSPACE->m_pLastFocusedWindow = g_pCompositor->vectorToWindowTiled(g_pInputManager->getMouseCoordsInternal());
|
||||
|
@@ -7,6 +7,7 @@
|
||||
#include <functional>
|
||||
|
||||
class CInputManager;
|
||||
class CConfigManager;
|
||||
|
||||
struct SKeybind {
|
||||
std::string key = "";
|
||||
@@ -92,6 +93,7 @@ private:
|
||||
static void moveActiveToWorkspace(std::string);
|
||||
static void moveActiveToWorkspaceSilent(std::string);
|
||||
static void moveFocusTo(std::string);
|
||||
static void centerWindow(std::string);
|
||||
static void moveActiveTo(std::string);
|
||||
static void toggleGroup(std::string);
|
||||
static void changeGroupActive(std::string);
|
||||
@@ -124,6 +126,7 @@ private:
|
||||
|
||||
friend class CCompositor;
|
||||
friend class CInputManager;
|
||||
friend class CConfigManager;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CKeybindManager> g_pKeybindManager;
|
||||
|
5
src/managers/ProtocolManager.cpp
Normal file
5
src/managers/ProtocolManager.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
#include "ProtocolManager.hpp"
|
||||
|
||||
CProtocolManager::CProtocolManager() {
|
||||
m_pToplevelExportProtocolManager = std::make_unique<CToplevelExportProtocolManager>();
|
||||
}
|
13
src/managers/ProtocolManager.hpp
Normal file
13
src/managers/ProtocolManager.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "../defines.hpp"
|
||||
#include "../protocols/ToplevelExport.hpp"
|
||||
|
||||
class CProtocolManager {
|
||||
public:
|
||||
CProtocolManager();
|
||||
|
||||
std::unique_ptr<CToplevelExportProtocolManager> m_pToplevelExportProtocolManager;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CProtocolManager> g_pProtocolManager;
|
@@ -263,7 +263,7 @@ Vector2D CHyprXWaylandManager::getMaxSizeForWindow(CWindow* pWindow) {
|
||||
if (!g_pCompositor->windowValidMapped(pWindow))
|
||||
return Vector2D(99999, 99999);
|
||||
|
||||
if ((pWindow->m_bIsX11 && !pWindow->m_uSurface.xwayland->size_hints) || (!pWindow->m_bIsX11 && !pWindow->m_uSurface.xdg->toplevel))
|
||||
if ((pWindow->m_bIsX11 && !pWindow->m_uSurface.xwayland->size_hints) || (!pWindow->m_bIsX11 && !pWindow->m_uSurface.xdg->toplevel) || pWindow->m_sAdditionalConfigData.noMaxSize)
|
||||
return Vector2D(99999, 99999);
|
||||
|
||||
auto MAXSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_uSurface.xwayland->size_hints->max_width, pWindow->m_uSurface.xwayland->size_hints->max_height)
|
||||
|
@@ -49,6 +49,27 @@ void CInputManager::recheckIdleInhibitorStatus() {
|
||||
}
|
||||
}
|
||||
|
||||
// check manual user-set inhibitors
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_eIdleInhibitMode == IDLEINHIBIT_NONE)
|
||||
continue;
|
||||
|
||||
if (w->m_eIdleInhibitMode == IDLEINHIBIT_ALWAYS) {
|
||||
wlr_idle_set_enabled(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (w->m_eIdleInhibitMode == IDLEINHIBIT_FOCUS && g_pCompositor->isWindowActive(w.get())) {
|
||||
wlr_idle_set_enabled(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (w->m_eIdleInhibitMode == IDLEINHIBIT_FULLSCREEN && w->m_bIsFullscreen && g_pCompositor->isWorkspaceVisible(w->m_iWorkspaceID)) {
|
||||
wlr_idle_set_enabled(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
wlr_idle_set_enabled(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat, true);
|
||||
return;
|
||||
}
|
@@ -38,6 +38,11 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
m_pFoundSurfaceToFocus = nullptr;
|
||||
m_pFoundLSToFocus = nullptr;
|
||||
m_pFoundWindowToFocus = nullptr;
|
||||
wlr_surface* foundSurface = nullptr;
|
||||
Vector2D surfaceCoords;
|
||||
Vector2D surfacePos = Vector2D(-1337, -1337);
|
||||
CWindow* pFoundWindow = nullptr;
|
||||
SLayerSurface* pFoundLayerSurface = nullptr;
|
||||
|
||||
if (!g_pCompositor->m_bReadyToProcess || g_pCompositor->m_bIsShuttingDown)
|
||||
return;
|
||||
@@ -47,9 +52,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_pCompositor->m_sSeat.mouse->virt)
|
||||
return; // don't refocus on virt
|
||||
|
||||
if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS) {
|
||||
// enable dpms
|
||||
g_pKeybindManager->dpms("on");
|
||||
@@ -65,14 +67,13 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromCursor();
|
||||
|
||||
bool didConstraintOnCursor = false;
|
||||
|
||||
// constraints
|
||||
// All constraints TODO: multiple mice?
|
||||
if (g_pCompositor->m_sSeat.mouse->currentConstraint) {
|
||||
if (g_pCompositor->m_sSeat.mouse->currentConstraint && !g_pCompositor->m_sSeat.exclusiveClient) {
|
||||
// XWayland windows sometimes issue constraints weirdly.
|
||||
// TODO: We probably should search their parent. wlr_xwayland_surface->parent
|
||||
const auto CONSTRAINTWINDOW = g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse);
|
||||
const auto PCONSTRAINT = g_pCompositor->m_sSeat.mouse->currentConstraint;
|
||||
|
||||
if (!CONSTRAINTWINDOW) {
|
||||
unconstrainMouse();
|
||||
@@ -82,32 +83,37 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
const auto CONSTRAINTPOS = CONSTRAINTWINDOW->m_bIsX11 ? Vector2D(CONSTRAINTWINDOW->m_uSurface.xwayland->x, CONSTRAINTWINDOW->m_uSurface.xwayland->y) : CONSTRAINTWINDOW->m_vRealPosition.vec();
|
||||
const auto CONSTRAINTSIZE = CONSTRAINTWINDOW->m_bIsX11 ? Vector2D(CONSTRAINTWINDOW->m_uSurface.xwayland->width, CONSTRAINTWINDOW->m_uSurface.xwayland->height) : CONSTRAINTWINDOW->m_vRealSize.vec();
|
||||
|
||||
if (!VECINRECT(mouseCoords, CONSTRAINTPOS.x, CONSTRAINTPOS.y, CONSTRAINTPOS.x + CONSTRAINTSIZE.x - 1.0, CONSTRAINTPOS.y + CONSTRAINTSIZE.y - 1.0)) {
|
||||
if (g_pCompositor->m_sSeat.mouse->constraintActive) {
|
||||
Vector2D newConstrainedCoords = mouseCoords;
|
||||
if (g_pCompositor->m_sSeat.mouse->currentConstraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED) {
|
||||
// we just snap the cursor to where it should be.
|
||||
|
||||
if (mouseCoords.x < CONSTRAINTPOS.x)
|
||||
newConstrainedCoords.x = CONSTRAINTPOS.x;
|
||||
else if (mouseCoords.x >= CONSTRAINTPOS.x + CONSTRAINTSIZE.x)
|
||||
newConstrainedCoords.x = CONSTRAINTPOS.x + CONSTRAINTSIZE.x - 1.0;
|
||||
Vector2D hint = { PCONSTRAINT->current.cursor_hint.x, PCONSTRAINT->current.cursor_hint.y };
|
||||
|
||||
if (mouseCoords.y < CONSTRAINTPOS.y)
|
||||
newConstrainedCoords.y = CONSTRAINTPOS.y;
|
||||
else if (mouseCoords.y >= CONSTRAINTPOS.y + CONSTRAINTSIZE.y)
|
||||
newConstrainedCoords.y = CONSTRAINTPOS.y + CONSTRAINTSIZE.y - 1.0;
|
||||
wlr_cursor_warp_closest(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, CONSTRAINTPOS.x + hint.x, CONSTRAINTPOS.y + hint.y);
|
||||
|
||||
wlr_cursor_warp_closest(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, newConstrainedCoords.x, newConstrainedCoords.y);
|
||||
|
||||
mouseCoords = newConstrainedCoords;
|
||||
|
||||
didConstraintOnCursor = true;
|
||||
}
|
||||
return; // don't process anything else, the cursor is locked. The surface should not receive any further events.
|
||||
// these are usually FPS games. They will use the relative motion.
|
||||
} else {
|
||||
if ((!CONSTRAINTWINDOW->m_bIsX11 && PMONITOR && CONSTRAINTWINDOW->m_iWorkspaceID == PMONITOR->activeWorkspace) || (CONSTRAINTWINDOW->m_bIsX11)) {
|
||||
g_pCompositor->m_sSeat.mouse->constraintActive = true;
|
||||
didConstraintOnCursor = true;
|
||||
// we restrict the cursor to the confined region
|
||||
if (!pixman_region32_contains_point(&PCONSTRAINT->region, mouseCoords.x - CONSTRAINTPOS.x, mouseCoords.y - CONSTRAINTPOS.y, nullptr)) {
|
||||
if (g_pCompositor->m_sSeat.mouse->constraintActive) {
|
||||
wlr_cursor_warp_closest(g_pCompositor->m_sWLRCursor, NULL, mouseCoords.x, mouseCoords.y);
|
||||
mouseCoords = getMouseCoordsInternal();
|
||||
}
|
||||
} else {
|
||||
if ((!CONSTRAINTWINDOW->m_bIsX11 && PMONITOR && CONSTRAINTWINDOW->m_iWorkspaceID == PMONITOR->activeWorkspace) || (CONSTRAINTWINDOW->m_bIsX11)) {
|
||||
g_pCompositor->m_sSeat.mouse->constraintActive = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (CONSTRAINTWINDOW->m_bIsX11) {
|
||||
foundSurface = g_pXWaylandManager->getWindowSurface(CONSTRAINTWINDOW);
|
||||
surfacePos = CONSTRAINTWINDOW->m_vRealPosition.vec();
|
||||
} else {
|
||||
g_pCompositor->vectorWindowToSurface(mouseCoords, CONSTRAINTWINDOW, surfaceCoords);
|
||||
}
|
||||
|
||||
pFoundWindow = CONSTRAINTWINDOW;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,29 +122,15 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->onMouseMove(getMouseCoordsInternal());
|
||||
|
||||
// focus
|
||||
wlr_surface* foundSurface = nullptr;
|
||||
|
||||
if (didConstraintOnCursor)
|
||||
return; // don't process when cursor constrained
|
||||
|
||||
if (PMONITOR && PMONITOR != g_pCompositor->m_pLastMonitor) {
|
||||
g_pCompositor->m_pLastMonitor = PMONITOR;
|
||||
g_pCompositor->setActiveMonitor(PMONITOR);
|
||||
|
||||
// set active workspace and deactivate all other in wlr
|
||||
const auto ACTIVEWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
|
||||
g_pCompositor->deactivateAllWLRWorkspaces(ACTIVEWORKSPACE->m_pWlrHandle);
|
||||
ACTIVEWORKSPACE->setActive(true);
|
||||
|
||||
// event
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", PMONITOR->szName + "," + ACTIVEWORKSPACE->m_szName});
|
||||
}
|
||||
|
||||
Vector2D surfaceCoords;
|
||||
Vector2D surfacePos = Vector2D(-1337, -1337);
|
||||
CWindow* pFoundWindow = nullptr;
|
||||
SLayerSurface* pFoundLayerSurface = nullptr;
|
||||
|
||||
// overlay is above fullscreen
|
||||
if (!foundSurface)
|
||||
foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &surfaceCoords, &pFoundLayerSurface);
|
||||
@@ -160,7 +152,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
// only check floating because tiled cant be over fullscreen
|
||||
for (auto w = g_pCompositor->m_vWindows.rbegin(); w != g_pCompositor->m_vWindows.rend(); w++) {
|
||||
wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y};
|
||||
if ((((*w)->m_bIsFloating && (*w)->m_bIsMapped && ((*w)->m_bCreatedOverFullscreen || (*w)->m_bPinned)) || ((*w)->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && PMONITOR->specialWorkspaceOpen)) && wlr_box_contains_point(&box, mouseCoords.x, mouseCoords.y) && g_pCompositor->isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->isHidden()) {
|
||||
if ((((*w)->m_bIsFloating && (*w)->m_bIsMapped && ((*w)->m_bCreatedOverFullscreen || (*w)->m_bPinned)) || (g_pCompositor->isWorkspaceSpecial((*w)->m_iWorkspaceID) && PMONITOR->specialWorkspaceID)) && wlr_box_contains_point(&box, mouseCoords.x, mouseCoords.y) && g_pCompositor->isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->isHidden()) {
|
||||
pFoundWindow = (*w).get();
|
||||
break;
|
||||
}
|
||||
@@ -179,10 +171,10 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
if (!foundSurface) {
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) {
|
||||
|
||||
if (PMONITOR->specialWorkspaceOpen) {
|
||||
if (PMONITOR->specialWorkspaceID) {
|
||||
pFoundWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords);
|
||||
|
||||
if (pFoundWindow && pFoundWindow->m_iWorkspaceID != SPECIAL_WORKSPACE_ID) {
|
||||
if (pFoundWindow && !g_pCompositor->isWorkspaceSpecial(pFoundWindow->m_iWorkspaceID)) {
|
||||
pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
|
||||
}
|
||||
} else {
|
||||
@@ -226,7 +218,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "crosshair", g_pCompositor->m_sWLRCursor);
|
||||
else
|
||||
wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", g_pCompositor->m_sWLRCursor);
|
||||
|
||||
|
||||
m_bEmptyFocusCursorSet = true;
|
||||
}
|
||||
|
||||
@@ -278,7 +270,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
if (*PFOLLOWMOUSE != 3 && allowKeyboardRefocus)
|
||||
g_pCompositor->focusWindow(pFoundWindow, foundSurface);
|
||||
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
|
||||
} else if (*PFOLLOWMOUSE == 2) {
|
||||
} else if (*PFOLLOWMOUSE == 2 || *PFOLLOWMOUSE == 3) {
|
||||
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
|
||||
}
|
||||
|
||||
@@ -344,6 +336,10 @@ void CInputManager::processMouseRequest(wlr_seat_pointer_request_set_cursor_even
|
||||
g_pHyprRenderer->m_bWindowRequestedCursorHide = false;
|
||||
}
|
||||
|
||||
if (m_bCursorImageOverriden) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_ecbClickBehavior == CLICKMODE_KILL) {
|
||||
wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "crosshair", g_pCompositor->m_sWLRCursor);
|
||||
return;
|
||||
@@ -382,22 +378,20 @@ void CInputManager::setClickMode(eClickBehaviorMode mode) {
|
||||
}
|
||||
|
||||
void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
|
||||
const auto PKEYBOARD = wlr_seat_get_keyboard(g_pCompositor->m_sSeat.seat);
|
||||
|
||||
if (!PKEYBOARD) { // ???
|
||||
Debug::log(ERR, "No active keyboard in processMouseDownNormal??");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// notify the keybind manager
|
||||
static auto *const PPASSMOUSE = &g_pConfigManager->getConfigValuePtr("binds:pass_mouse_when_bound")->intValue;
|
||||
const auto PASS = g_pKeybindManager->onMouseEvent(e);
|
||||
static auto *const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
|
||||
|
||||
if (!PASS && !*PPASSMOUSE)
|
||||
return;
|
||||
|
||||
switch (e->state) {
|
||||
case WLR_BUTTON_PRESSED:
|
||||
if (*PFOLLOWMOUSE == 3) // don't refocus on full loose
|
||||
break;
|
||||
|
||||
if (!g_pCompositor->m_sSeat.mouse->currentConstraint)
|
||||
refocus();
|
||||
|
||||
@@ -465,7 +459,7 @@ void CInputManager::newKeyboard(wlr_input_device* keyboard) {
|
||||
PNEWKEYBOARD->keyboard = keyboard;
|
||||
|
||||
try {
|
||||
PNEWKEYBOARD->name = std::string(keyboard->name);
|
||||
PNEWKEYBOARD->name = getNameForNewDevice(keyboard->name);
|
||||
} catch (std::exception& e) {
|
||||
Debug::log(ERR, "Keyboard had no name???"); // logic error
|
||||
}
|
||||
@@ -501,7 +495,7 @@ void CInputManager::newVirtualKeyboard(wlr_input_device* keyboard) {
|
||||
PNEWKEYBOARD->isVirtual = true;
|
||||
|
||||
try {
|
||||
PNEWKEYBOARD->name = std::string(keyboard->name);
|
||||
PNEWKEYBOARD->name = getNameForNewDevice(keyboard->name);
|
||||
} catch (std::exception& e) {
|
||||
Debug::log(ERR, "Keyboard had no name???"); // logic error
|
||||
}
|
||||
@@ -538,7 +532,6 @@ void CInputManager::setKeyboardLayout() {
|
||||
|
||||
void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
|
||||
auto devname = pKeyboard->name;
|
||||
transform(devname.begin(), devname.end(), devname.begin(), ::tolower);
|
||||
|
||||
const auto HASCONFIG = g_pConfigManager->deviceConfigExists(devname);
|
||||
|
||||
@@ -662,7 +655,7 @@ void CInputManager::newMouse(wlr_input_device* mouse, bool virt) {
|
||||
PMOUSE->mouse = mouse;
|
||||
PMOUSE->virt = virt;
|
||||
try {
|
||||
PMOUSE->name = std::string(mouse->name);
|
||||
PMOUSE->name = getNameForNewDevice(mouse->name);
|
||||
} catch(std::exception& e) {
|
||||
Debug::log(ERR, "Mouse had no name???"); // logic error
|
||||
}
|
||||
@@ -673,14 +666,14 @@ void CInputManager::newMouse(wlr_input_device* mouse, bool virt) {
|
||||
Debug::log(LOG, "New mouse has libinput sens %.2f (%.2f) with accel profile %i (%i)", libinput_device_config_accel_get_speed(LIBINPUTDEV), libinput_device_config_accel_get_default_speed(LIBINPUTDEV), libinput_device_config_accel_get_profile(LIBINPUTDEV), libinput_device_config_accel_get_default_profile(LIBINPUTDEV));
|
||||
}
|
||||
|
||||
setPointerConfigs();
|
||||
|
||||
PMOUSE->hyprListener_destroyMouse.initCallback(&mouse->events.destroy, &Events::listener_destroyMouse, PMOUSE, "Mouse");
|
||||
|
||||
wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, mouse);
|
||||
|
||||
PMOUSE->connected = true;
|
||||
|
||||
setPointerConfigs();
|
||||
|
||||
PMOUSE->hyprListener_destroyMouse.initCallback(&mouse->events.destroy, &Events::listener_destroyMouse, PMOUSE, "Mouse");
|
||||
|
||||
g_pCompositor->m_sSeat.mouse = PMOUSE;
|
||||
|
||||
m_tmrLastCursorMovement.reset();
|
||||
@@ -693,7 +686,6 @@ void CInputManager::setPointerConfigs() {
|
||||
const auto PPOINTER = &m;
|
||||
|
||||
auto devname = PPOINTER->name;
|
||||
transform(devname.begin(), devname.end(), devname.begin(), ::tolower);
|
||||
|
||||
const auto HASCONFIG = g_pConfigManager->deviceConfigExists(devname);
|
||||
|
||||
@@ -729,7 +721,7 @@ void CInputManager::setPointerConfigs() {
|
||||
}
|
||||
|
||||
const auto SCROLLMETHOD = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "scroll_method") : g_pConfigManager->getString("input:scroll_method");
|
||||
if (SCROLLMETHOD == "" || SCROLLMETHOD == STRVAL_EMPTY) {
|
||||
if (SCROLLMETHOD == "") {
|
||||
libinput_device_config_scroll_set_method(LIBINPUTDEV, libinput_device_config_scroll_get_default_method(LIBINPUTDEV));
|
||||
} else if (SCROLLMETHOD == "no_scroll") {
|
||||
libinput_device_config_scroll_set_method(LIBINPUTDEV, LIBINPUT_CONFIG_SCROLL_NO_SCROLL);
|
||||
@@ -771,7 +763,7 @@ void CInputManager::setPointerConfigs() {
|
||||
|
||||
const auto ACCELPROFILE = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "accel_profile") : g_pConfigManager->getString("input:accel_profile");
|
||||
|
||||
if (ACCELPROFILE == "" || ACCELPROFILE == STRVAL_EMPTY) {
|
||||
if (ACCELPROFILE == "") {
|
||||
libinput_device_config_accel_set_profile(LIBINPUTDEV, libinput_device_config_accel_get_default_profile(LIBINPUTDEV));
|
||||
} else if (ACCELPROFILE == "adaptive") {
|
||||
libinput_device_config_accel_set_profile(LIBINPUTDEV, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE);
|
||||
@@ -779,7 +771,11 @@ void CInputManager::setPointerConfigs() {
|
||||
libinput_device_config_accel_set_profile(LIBINPUTDEV, LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT);
|
||||
} else {
|
||||
Debug::log(WARN, "Unknown acceleration profile, falling back to default");
|
||||
}
|
||||
}
|
||||
|
||||
const auto SCROLLBUTTON = HASCONFIG ? g_pConfigManager->getDeviceInt(devname, "scroll_button") : g_pConfigManager->getInt("input:scroll_button");
|
||||
|
||||
libinput_device_config_scroll_set_button(LIBINPUTDEV, SCROLLBUTTON == 0 ? libinput_device_config_scroll_get_default_button(LIBINPUTDEV) : SCROLLBUTTON);
|
||||
|
||||
Debug::log(LOG, "Applied config to mouse %s, sens %.2f", m.name.c_str(), LIBINPUTSENS);
|
||||
}
|
||||
@@ -819,6 +815,31 @@ void CInputManager::destroyMouse(wlr_input_device* mouse) {
|
||||
unconstrainMouse();
|
||||
}
|
||||
|
||||
|
||||
void CInputManager::updateKeyboardsLeds(wlr_input_device* pKeyboard) {
|
||||
auto keyboard = wlr_keyboard_from_input_device(pKeyboard);
|
||||
|
||||
if (keyboard->xkb_state == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t leds = 0;
|
||||
for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) {
|
||||
if (xkb_state_led_index_is_active(keyboard->xkb_state,
|
||||
keyboard->led_indexes[i])) {
|
||||
leds |= (1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& kb : m_lKeyboards) {
|
||||
if ((kb.isVirtual && shouldIgnoreVirtualKeyboard(&kb)) || kb.keyboard == pKeyboard)
|
||||
continue;
|
||||
|
||||
wlr_keyboard_led_update(wlr_keyboard_from_input_device(kb.keyboard), leds);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboard) {
|
||||
bool passEvent = g_pKeybindManager->onKeyEvent(e, pKeyboard);
|
||||
|
||||
@@ -835,6 +856,8 @@ void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboar
|
||||
wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, wlr_keyboard_from_input_device(pKeyboard->keyboard));
|
||||
wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, e->time_msec, e->keycode, e->state);
|
||||
}
|
||||
|
||||
updateKeyboardsLeds(pKeyboard->keyboard);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -854,6 +877,8 @@ void CInputManager::onKeyboardMod(void* data, SKeyboard* pKeyboard) {
|
||||
wlr_seat_keyboard_notify_modifiers(g_pCompositor->m_sSeat.seat, &MODS);
|
||||
}
|
||||
|
||||
updateKeyboardsLeds(pKeyboard->keyboard);
|
||||
|
||||
const auto PWLRKB = wlr_keyboard_from_input_device(pKeyboard->keyboard);
|
||||
|
||||
if (PWLRKB->modifiers.group != pKeyboard->activeLayout) {
|
||||
@@ -863,6 +888,10 @@ void CInputManager::onKeyboardMod(void* data, SKeyboard* pKeyboard) {
|
||||
}
|
||||
}
|
||||
|
||||
bool CInputManager::shouldIgnoreVirtualKeyboard(SKeyboard* pKeyboard) {
|
||||
return !pKeyboard || (m_sIMERelay.m_pKeyboardGrab && wl_resource_get_client(m_sIMERelay.m_pKeyboardGrab->pWlrKbGrab->resource) == wl_resource_get_client(wlr_input_device_get_virtual_keyboard(pKeyboard->keyboard)->resource));
|
||||
}
|
||||
|
||||
void CInputManager::refocus() {
|
||||
mouseMoveUnified(0, true);
|
||||
}
|
||||
@@ -979,24 +1008,20 @@ void Events::listener_commitConstraint(void* owner, void* data) {
|
||||
//g_pInputManager->recheckConstraint((SMouse*)owner);
|
||||
}
|
||||
|
||||
void CInputManager::updateCapabilities(wlr_input_device* pDev) {
|
||||
// TODO: this is dumb
|
||||
void CInputManager::updateCapabilities() {
|
||||
uint32_t caps = 0;
|
||||
|
||||
switch (pDev->type) {
|
||||
case WLR_INPUT_DEVICE_KEYBOARD:
|
||||
m_uiCapabilities |= WL_SEAT_CAPABILITY_KEYBOARD;
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_POINTER:
|
||||
m_uiCapabilities |= WL_SEAT_CAPABILITY_POINTER;
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_TOUCH:
|
||||
m_uiCapabilities |= WL_SEAT_CAPABILITY_TOUCH;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!m_lKeyboards.empty())
|
||||
caps |= WL_SEAT_CAPABILITY_KEYBOARD;
|
||||
if (!m_lMice.empty())
|
||||
caps |= WL_SEAT_CAPABILITY_POINTER;
|
||||
if (!m_lTouchDevices.empty())
|
||||
caps |= WL_SEAT_CAPABILITY_TOUCH;
|
||||
if (!m_lTabletTools.empty())
|
||||
caps |= WL_SEAT_CAPABILITY_POINTER;
|
||||
|
||||
wlr_seat_set_capabilities(g_pCompositor->m_sSeat.seat, m_uiCapabilities);
|
||||
wlr_seat_set_capabilities(g_pCompositor->m_sSeat.seat, caps);
|
||||
m_uiCapabilities = caps;
|
||||
}
|
||||
|
||||
uint32_t CInputManager::accumulateModsFromAllKBs() {
|
||||
@@ -1004,7 +1029,7 @@ uint32_t CInputManager::accumulateModsFromAllKBs() {
|
||||
uint32_t finalMask = 0;
|
||||
|
||||
for (auto& kb : m_lKeyboards) {
|
||||
if (kb.isVirtual)
|
||||
if (kb.isVirtual && shouldIgnoreVirtualKeyboard(&kb))
|
||||
continue;
|
||||
|
||||
finalMask |= wlr_keyboard_get_modifiers(wlr_keyboard_from_input_device(kb.keyboard));
|
||||
@@ -1047,7 +1072,7 @@ void CInputManager::newTouchDevice(wlr_input_device* pDevice) {
|
||||
PNEWDEV->pWlrDevice = pDevice;
|
||||
|
||||
try {
|
||||
PNEWDEV->name = std::string(pDevice->name);
|
||||
PNEWDEV->name = getNameForNewDevice(pDevice->name);
|
||||
} catch(std::exception& e) {
|
||||
Debug::log(ERR, "Touch Device had no name???"); // logic error
|
||||
}
|
||||
@@ -1101,18 +1126,15 @@ void CInputManager::setTouchDeviceConfigs() {
|
||||
for (auto& m : m_lTouchDevices) {
|
||||
const auto PTOUCHDEV = &m;
|
||||
|
||||
auto devname = PTOUCHDEV->name;
|
||||
transform(devname.begin(), devname.end(), devname.begin(), ::tolower);
|
||||
|
||||
const auto HASCONFIG = g_pConfigManager->deviceConfigExists(devname);
|
||||
const auto HASCONFIG = g_pConfigManager->deviceConfigExists(PTOUCHDEV->name);
|
||||
|
||||
if (wlr_input_device_is_libinput(m.pWlrDevice)) {
|
||||
const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(m.pWlrDevice);
|
||||
|
||||
const int ROTATION = std::clamp(HASCONFIG ? g_pConfigManager->getDeviceInt(devname, "touch_transform") : g_pConfigManager->getInt("input:touchdevice:transform"), 0, 7);
|
||||
const int ROTATION = std::clamp(HASCONFIG ? g_pConfigManager->getDeviceInt(PTOUCHDEV->name, "touch_transform") : g_pConfigManager->getInt("input:touchdevice:transform"), 0, 7);
|
||||
libinput_device_config_calibration_set_matrix(LIBINPUTDEV, MATRICES[ROTATION]);
|
||||
|
||||
const auto OUTPUT = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "touch_output") : g_pConfigManager->getString("input:touchdevice:output");
|
||||
const auto OUTPUT = HASCONFIG ? g_pConfigManager->getDeviceString(PTOUCHDEV->name, "touch_output") : g_pConfigManager->getString("input:touchdevice:output");
|
||||
if (!OUTPUT.empty() && OUTPUT != STRVAL_EMPTY)
|
||||
PTOUCHDEV->boundOutput = OUTPUT;
|
||||
else
|
||||
@@ -1152,3 +1174,49 @@ void CInputManager::newSwitch(wlr_input_device* pDevice) {
|
||||
void CInputManager::destroySwitch(SSwitchDevice* pDevice) {
|
||||
m_lSwitches.remove(*pDevice);
|
||||
}
|
||||
|
||||
void CInputManager::setCursorImageUntilUnset(std::string name) {
|
||||
wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, name.c_str(), g_pCompositor->m_sWLRCursor);
|
||||
m_bCursorImageOverriden = true;
|
||||
}
|
||||
|
||||
void CInputManager::unsetCursorImage() {
|
||||
if (!m_bCursorImageOverriden)
|
||||
return;
|
||||
|
||||
m_bCursorImageOverriden = false;
|
||||
if (!g_pHyprRenderer->m_bWindowRequestedCursorHide)
|
||||
wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", g_pCompositor->m_sWLRCursor);
|
||||
}
|
||||
|
||||
std::string CInputManager::deviceNameToInternalString(std::string in) {
|
||||
std::replace(in.begin(), in.end(), ' ', '-');
|
||||
std::transform(in.begin(), in.end(), in.begin(), ::tolower);
|
||||
return in;
|
||||
}
|
||||
|
||||
std::string CInputManager::getNameForNewDevice(std::string internalName) {
|
||||
|
||||
auto proposedNewName = deviceNameToInternalString(internalName);
|
||||
int dupeno = 0;
|
||||
|
||||
while (std::find_if(m_lKeyboards.begin(), m_lKeyboards.end(), [&] (const SKeyboard& other) { return other.name == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_lKeyboards.end())
|
||||
dupeno++;
|
||||
|
||||
while (std::find_if(m_lMice.begin(), m_lMice.end(), [&] (const SMouse& other) { return other.name == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_lMice.end())
|
||||
dupeno++;
|
||||
|
||||
while (std::find_if(m_lTouchDevices.begin(), m_lTouchDevices.end(), [&] (const STouchDevice& other) { return other.name == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_lTouchDevices.end())
|
||||
dupeno++;
|
||||
|
||||
while (std::find_if(m_lTabletPads.begin(), m_lTabletPads.end(), [&] (const STabletPad& other) { return other.name == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_lTabletPads.end())
|
||||
dupeno++;
|
||||
|
||||
while (std::find_if(m_lTablets.begin(), m_lTablets.end(), [&] (const STablet& other) { return other.name == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_lTablets.end())
|
||||
dupeno++;
|
||||
|
||||
while (std::find_if(m_lTabletTools.begin(), m_lTabletTools.end(), [&] (const STabletTool& other) { return other.name == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_lTabletTools.end())
|
||||
dupeno++;
|
||||
|
||||
return proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno)));
|
||||
}
|
||||
|
@@ -25,6 +25,8 @@ struct STouchData {
|
||||
Vector2D touchSurfaceOrigin;
|
||||
};
|
||||
|
||||
class CKeybindManager;
|
||||
|
||||
class CInputManager {
|
||||
public:
|
||||
|
||||
@@ -58,7 +60,7 @@ public:
|
||||
void setTouchDeviceConfigs();
|
||||
|
||||
void updateDragIcon();
|
||||
void updateCapabilities(wlr_input_device*);
|
||||
void updateCapabilities();
|
||||
|
||||
void setClickMode(eClickBehaviorMode);
|
||||
eClickBehaviorMode getClickMode();
|
||||
@@ -115,13 +117,27 @@ public:
|
||||
|
||||
CInputMethodRelay m_sIMERelay;
|
||||
|
||||
void updateKeyboardsLeds(wlr_input_device* pKeyboard);
|
||||
|
||||
// for shared mods
|
||||
uint32_t accumulateModsFromAllKBs();
|
||||
|
||||
CWindow* m_pFollowOnDnDBegin = nullptr;
|
||||
|
||||
// for virtual keyboards: whether we should respect them as normal ones
|
||||
bool shouldIgnoreVirtualKeyboard(SKeyboard*);
|
||||
|
||||
// for special cursors that we choose
|
||||
void setCursorImageUntilUnset(std::string);
|
||||
void unsetCursorImage();
|
||||
|
||||
std::string deviceNameToInternalString(std::string);
|
||||
std::string getNameForNewDevice(std::string);
|
||||
|
||||
private:
|
||||
|
||||
bool m_bCursorImageOverriden = false;
|
||||
|
||||
// for click behavior override
|
||||
eClickBehaviorMode m_ecbClickBehavior = CLICKMODE_DEFAULT;
|
||||
bool m_bEmptyFocusCursorSet = false;
|
||||
@@ -147,6 +163,11 @@ private:
|
||||
wlr_surface* m_pFoundSurfaceToFocus = nullptr;
|
||||
SLayerSurface* m_pFoundLSToFocus = nullptr;
|
||||
CWindow* m_pFoundWindowToFocus = nullptr;
|
||||
|
||||
// swipe
|
||||
void beginWorkspaceSwipe();
|
||||
|
||||
friend class CKeybindManager;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CInputManager> g_pInputManager;
|
||||
|
@@ -301,7 +301,7 @@ void CInputMethodRelay::createNewTextInput(wlr_text_input_v3* pInput) {
|
||||
const auto PINPUT = (STextInput*)owner;
|
||||
|
||||
if (!g_pInputManager->m_sIMERelay.m_pWLRIME) {
|
||||
Debug::log(WARN, "Enabling TextInput on no IME!");
|
||||
// Debug::log(WARN, "Enabling TextInput on no IME!");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -317,7 +317,7 @@ void CInputMethodRelay::createNewTextInput(wlr_text_input_v3* pInput) {
|
||||
const auto PINPUT = (STextInput*)owner;
|
||||
|
||||
if (!g_pInputManager->m_sIMERelay.m_pWLRIME) {
|
||||
Debug::log(WARN, "Committing TextInput on no IME!");
|
||||
// Debug::log(WARN, "Committing TextInput on no IME!");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -335,7 +335,7 @@ void CInputMethodRelay::createNewTextInput(wlr_text_input_v3* pInput) {
|
||||
const auto PINPUT = (STextInput*)owner;
|
||||
|
||||
if (!g_pInputManager->m_sIMERelay.m_pWLRIME) {
|
||||
Debug::log(WARN, "Disabling TextInput on no IME!");
|
||||
// Debug::log(WARN, "Disabling TextInput on no IME!");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -352,7 +352,7 @@ void CInputMethodRelay::createNewTextInput(wlr_text_input_v3* pInput) {
|
||||
const auto PINPUT = (STextInput*)owner;
|
||||
|
||||
if (!g_pInputManager->m_sIMERelay.m_pWLRIME) {
|
||||
Debug::log(WARN, "Disabling TextInput on no IME!");
|
||||
// Debug::log(WARN, "Disabling TextInput on no IME!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -3,6 +3,8 @@
|
||||
#include "../../defines.hpp"
|
||||
#include "../../helpers/WLClasses.hpp"
|
||||
|
||||
class CInputManager;
|
||||
|
||||
class CInputMethodRelay {
|
||||
public:
|
||||
CInputMethodRelay();
|
||||
@@ -45,4 +47,5 @@ private:
|
||||
void createNewTextInput(wlr_text_input_v3*);
|
||||
|
||||
friend class CHyprRenderer;
|
||||
friend class CInputManager;
|
||||
};
|
@@ -11,7 +11,7 @@ void CInputManager::onSwipeBegin(wlr_pointer_swipe_begin_event* e) {
|
||||
|
||||
int onMonitor = 0;
|
||||
for (auto& w : g_pCompositor->m_vWorkspaces) {
|
||||
if (w->m_iMonitorID == g_pCompositor->m_pLastMonitor->ID && w->m_iID != SPECIAL_WORKSPACE_ID) {
|
||||
if (w->m_iMonitorID == g_pCompositor->m_pLastMonitor->ID && !g_pCompositor->isWorkspaceSpecial(w->m_iID)) {
|
||||
onMonitor++;
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,10 @@ void CInputManager::onSwipeBegin(wlr_pointer_swipe_begin_event* e) {
|
||||
if (onMonitor < 2 && !*PSWIPENEW)
|
||||
return; // disallow swiping when there's 1 workspace on a monitor
|
||||
|
||||
beginWorkspaceSwipe();
|
||||
}
|
||||
|
||||
void CInputManager::beginWorkspaceSwipe() {
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace);
|
||||
|
||||
Debug::log(LOG, "Starting a swipe from %s", PWORKSPACE->m_szName.c_str());
|
||||
@@ -51,7 +55,7 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
|
||||
auto workspaceIDLeft = getWorkspaceIDFromString("m-1", wsname);
|
||||
auto workspaceIDRight = getWorkspaceIDFromString("m+1", wsname);
|
||||
|
||||
if ((workspaceIDRight <= m_sActiveSwipe.pWorkspaceBegin->m_iID || workspaceIDRight == workspaceIDLeft) && *PSWIPENEW) {
|
||||
if ((workspaceIDRight <= m_sActiveSwipe.pWorkspaceBegin->m_iID || (workspaceIDRight == workspaceIDLeft && workspaceIDLeft == m_sActiveSwipe.pWorkspaceBegin->m_iID)) && *PSWIPENEW) {
|
||||
workspaceIDRight = m_sActiveSwipe.pWorkspaceBegin->m_iID > 0 ? m_sActiveSwipe.pWorkspaceBegin->m_iID + 1 : 1;
|
||||
}
|
||||
|
||||
@@ -162,6 +166,7 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
|
||||
static auto *const PSWIPEDIST = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_distance")->intValue;
|
||||
static auto *const PSWIPEINVR = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_invert")->intValue;
|
||||
static auto *const PSWIPENEW = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_create_new")->intValue;
|
||||
static auto *const PSWIPEFOREVER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_forever")->intValue;
|
||||
|
||||
const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert";
|
||||
|
||||
@@ -183,7 +188,10 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
|
||||
|
||||
m_sActiveSwipe.delta = std::clamp(m_sActiveSwipe.delta, (double)-*PSWIPEDIST, (double)*PSWIPEDIST);
|
||||
|
||||
if (((m_sActiveSwipe.pWorkspaceBegin->m_iID == workspaceIDLeft || m_sActiveSwipe.pWorkspaceBegin->m_iID == workspaceIDRight) && *PSWIPENEW && (m_sActiveSwipe.delta < 0)) || (m_sActiveSwipe.delta > 0 && g_pCompositor->getWindowsOnWorkspace(m_sActiveSwipe.pWorkspaceBegin->m_iID) == 0 && workspaceIDRight <= m_sActiveSwipe.pWorkspaceBegin->m_iID)) {
|
||||
if ((m_sActiveSwipe.pWorkspaceBegin->m_iID == workspaceIDLeft && *PSWIPENEW && (m_sActiveSwipe.delta < 0)) ||
|
||||
(m_sActiveSwipe.delta > 0 && g_pCompositor->getWindowsOnWorkspace(m_sActiveSwipe.pWorkspaceBegin->m_iID) == 0 && workspaceIDRight <= m_sActiveSwipe.pWorkspaceBegin->m_iID) ||
|
||||
(m_sActiveSwipe.delta < 0 && m_sActiveSwipe.pWorkspaceBegin->m_iID <= workspaceIDLeft)) {
|
||||
|
||||
m_sActiveSwipe.delta = 0;
|
||||
return;
|
||||
}
|
||||
@@ -258,4 +266,11 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
|
||||
g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor);
|
||||
|
||||
g_pCompositor->updateWorkspaceWindowDecos(m_sActiveSwipe.pWorkspaceBegin->m_iID);
|
||||
|
||||
if (*PSWIPEFOREVER) {
|
||||
if (abs(m_sActiveSwipe.delta) >= *PSWIPEDIST) {
|
||||
onSwipeEnd(nullptr);
|
||||
beginWorkspaceSwipe();
|
||||
}
|
||||
}
|
||||
}
|
@@ -5,7 +5,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
|
||||
const auto PNEWTABLET = &m_lTablets.emplace_back();
|
||||
|
||||
try {
|
||||
PNEWTABLET->name = std::string(pDevice->name);
|
||||
PNEWTABLET->name = deviceNameToInternalString(pDevice->name);
|
||||
} catch (std::exception& e) {
|
||||
Debug::log(ERR, "Tablet had no name???"); // logic error
|
||||
}
|
||||
@@ -158,7 +158,7 @@ void CInputManager::newTabletPad(wlr_input_device* pDevice) {
|
||||
const auto PNEWPAD = &m_lTabletPads.emplace_back();
|
||||
|
||||
try {
|
||||
PNEWPAD->name = std::string(pDevice->name);
|
||||
PNEWPAD->name = deviceNameToInternalString(pDevice->name);
|
||||
} catch (std::exception& e) {
|
||||
Debug::log(ERR, "Pad had no name???"); // logic error
|
||||
}
|
||||
|
@@ -38,6 +38,8 @@ void CInputManager::onTouchDown(wlr_touch_down_event* e) {
|
||||
}
|
||||
|
||||
wlr_seat_touch_notify_down(g_pCompositor->m_sSeat.seat, m_sTouchData.touchFocusSurface, e->time_msec, e->touch_id, local.x, local.y);
|
||||
|
||||
wlr_idle_notify_activity(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat);
|
||||
}
|
||||
|
||||
void CInputManager::onTouchUp(wlr_touch_up_event* e){
|
||||
|
@@ -1,4 +1,4 @@
|
||||
globber = run_command('find', '-name', '*.cpp', check: true)
|
||||
globber = run_command('find', '.', '-name', '*.cpp', check: true)
|
||||
src = globber.stdout().strip().split('\n')
|
||||
|
||||
executable('Hyprland', src,
|
||||
@@ -18,7 +18,7 @@ executable('Hyprland', src,
|
||||
xcb_dep,
|
||||
|
||||
dependency('pixman-1'),
|
||||
dependency('GL', 'opengl'),
|
||||
dependency('gl', 'opengl'),
|
||||
dependency('threads')
|
||||
],
|
||||
install : true
|
||||
|
392
src/protocols/ToplevelExport.cpp
Normal file
392
src/protocols/ToplevelExport.cpp
Normal file
@@ -0,0 +1,392 @@
|
||||
#include "ToplevelExport.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include <drm_fourcc.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "ToplevelExportWlrFuncs.hpp"
|
||||
|
||||
#define TOPLEVEL_EXPORT_VERSION 1
|
||||
|
||||
static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint32_t id) {
|
||||
g_pProtocolManager->m_pToplevelExportProtocolManager->bindManager(client, data, version, id);
|
||||
}
|
||||
|
||||
static void handleDisplayDestroy(struct wl_listener* listener, void* data) {
|
||||
g_pProtocolManager->m_pToplevelExportProtocolManager->displayDestroy();
|
||||
}
|
||||
|
||||
void CToplevelExportProtocolManager::displayDestroy() {
|
||||
wl_global_destroy(m_pGlobal);
|
||||
}
|
||||
|
||||
CToplevelExportProtocolManager::CToplevelExportProtocolManager() {
|
||||
|
||||
#ifndef GLES32
|
||||
Debug::log(WARN, "Toplevel sharing is not supported on LEGACY_RENDERER!");
|
||||
return;
|
||||
#endif
|
||||
|
||||
m_pGlobal = wl_global_create(g_pCompositor->m_sWLDisplay, &hyprland_toplevel_export_manager_v1_interface,
|
||||
TOPLEVEL_EXPORT_VERSION, this, bindManagerInt);
|
||||
|
||||
if (!m_pGlobal) {
|
||||
Debug::log(ERR, "ToplevelExportManager could not start! Sharing windows will not work!");
|
||||
return;
|
||||
}
|
||||
|
||||
m_liDisplayDestroy.notify = handleDisplayDestroy;
|
||||
wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy);
|
||||
|
||||
Debug::log(LOG, "ToplevelExportManager started successfully!");
|
||||
}
|
||||
|
||||
void handleCaptureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, uint32_t handle) {
|
||||
g_pProtocolManager->m_pToplevelExportProtocolManager->captureToplevel(client, resource, frame, overlay_cursor, handle);
|
||||
}
|
||||
|
||||
void handleDestroy(wl_client* client, wl_resource* resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
void handleCopyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage) {
|
||||
g_pProtocolManager->m_pToplevelExportProtocolManager->copyFrame(client, resource, buffer, ignore_damage);
|
||||
}
|
||||
|
||||
void handleDestroyFrame(wl_client* client, wl_resource* resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static const struct hyprland_toplevel_export_manager_v1_interface toplevelExportManagerImpl = {
|
||||
.capture_toplevel = handleCaptureToplevel,
|
||||
.destroy = handleDestroy
|
||||
};
|
||||
|
||||
static const struct hyprland_toplevel_export_frame_v1_interface toplevelFrameImpl = {
|
||||
.copy = handleCopyFrame,
|
||||
.destroy = handleDestroyFrame
|
||||
};
|
||||
|
||||
SToplevelClient* clientFromResource(wl_resource* resource) {
|
||||
ASSERT(wl_resource_instance_of(resource, &hyprland_toplevel_export_manager_v1_interface, &toplevelExportManagerImpl));
|
||||
return (SToplevelClient*)wl_resource_get_user_data(resource);
|
||||
}
|
||||
|
||||
SToplevelFrame* frameFromResource(wl_resource* resource) {
|
||||
ASSERT(wl_resource_instance_of(resource, &hyprland_toplevel_export_frame_v1_interface, &toplevelFrameImpl));
|
||||
return (SToplevelFrame*)wl_resource_get_user_data(resource);
|
||||
}
|
||||
|
||||
void CToplevelExportProtocolManager::removeClient(SToplevelClient* client, bool force) {
|
||||
if (!force) {
|
||||
if (!client || client->ref <= 0)
|
||||
return;
|
||||
|
||||
if (--client->ref != 0)
|
||||
return;
|
||||
}
|
||||
|
||||
m_lClients.remove(*client); // TODO: this doesn't get cleaned up after sharing app exits???
|
||||
}
|
||||
|
||||
void handleManagerResourceDestroy(wl_resource* resource) {
|
||||
const auto PCLIENT = clientFromResource(resource);
|
||||
|
||||
g_pProtocolManager->m_pToplevelExportProtocolManager->removeClient(PCLIENT, true);
|
||||
}
|
||||
|
||||
void CToplevelExportProtocolManager::bindManager(wl_client* client, void* data, uint32_t version, uint32_t id) {
|
||||
const auto PCLIENT = &m_lClients.emplace_back();
|
||||
|
||||
PCLIENT->resource = wl_resource_create(client, &hyprland_toplevel_export_manager_v1_interface,
|
||||
version, id);
|
||||
|
||||
if (!PCLIENT->resource) {
|
||||
Debug::log(ERR, "ToplevelExportManager could not bind! (out of memory?)");
|
||||
m_lClients.remove(*PCLIENT);
|
||||
wl_client_post_no_memory(client);
|
||||
return;
|
||||
}
|
||||
|
||||
PCLIENT->ref = 1;
|
||||
|
||||
wl_resource_set_implementation(PCLIENT->resource, &toplevelExportManagerImpl, PCLIENT, handleManagerResourceDestroy);
|
||||
|
||||
Debug::log(LOG, "ToplevelExportManager bound successfully!");
|
||||
}
|
||||
|
||||
void handleFrameResourceDestroy(wl_resource* resource) {
|
||||
const auto PFRAME = frameFromResource(resource);
|
||||
|
||||
g_pProtocolManager->m_pToplevelExportProtocolManager->removeFrame(PFRAME);
|
||||
}
|
||||
|
||||
void CToplevelExportProtocolManager::removeFrame(SToplevelFrame* frame, bool force) {
|
||||
if (!frame)
|
||||
return;
|
||||
|
||||
std::erase_if(m_vFramesAwaitingWrite, [&] (const auto& other) { return other == frame; });
|
||||
|
||||
wl_resource_set_user_data(frame->resource, nullptr);
|
||||
wlr_buffer_unlock(frame->buffer);
|
||||
removeClient(frame->client, force);
|
||||
m_lFrames.remove(*frame);
|
||||
}
|
||||
|
||||
void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, uint32_t handle) {
|
||||
const auto PCLIENT = clientFromResource(resource);
|
||||
|
||||
const auto PWINDOW = g_pCompositor->getWindowFromHandle(handle);
|
||||
|
||||
// create a frame
|
||||
const auto PFRAME = &m_lFrames.emplace_back();
|
||||
PFRAME->overlayCursor = !!overlay_cursor;
|
||||
PFRAME->resource = wl_resource_create(client, &hyprland_toplevel_export_frame_v1_interface, wl_resource_get_version(resource), frame);
|
||||
PFRAME->pWindow = PWINDOW;
|
||||
|
||||
if (!PWINDOW) {
|
||||
Debug::log(ERR, "Client requested sharing of window handle %x which does not exist!", handle);
|
||||
hyprland_toplevel_export_frame_v1_send_failed(PFRAME->resource);
|
||||
removeFrame(PFRAME);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PWINDOW->m_bIsMapped || PWINDOW->isHidden()) {
|
||||
Debug::log(ERR, "Client requested sharing of window handle %x which is not shareable!", handle);
|
||||
hyprland_toplevel_export_frame_v1_send_failed(PFRAME->resource);
|
||||
removeFrame(PFRAME);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PFRAME->resource) {
|
||||
Debug::log(ERR, "Couldn't alloc frame for sharing! (no memory)");
|
||||
m_lFrames.remove(*PFRAME);
|
||||
wl_client_post_no_memory(client);
|
||||
return;
|
||||
}
|
||||
|
||||
wl_resource_set_implementation(PFRAME->resource, &toplevelFrameImpl, PFRAME, handleFrameResourceDestroy);
|
||||
|
||||
PFRAME->client = PCLIENT;
|
||||
PCLIENT->ref++;
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
||||
|
||||
PFRAME->shmFormat = wlr_output_preferred_read_format(PMONITOR->output);
|
||||
if (PFRAME->shmFormat == DRM_FORMAT_INVALID) {
|
||||
Debug::log(ERR, "No format supported by renderer in capture toplevel");
|
||||
hyprland_toplevel_export_frame_v1_send_failed(resource);
|
||||
removeFrame(PFRAME);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto PSHMINFO = drm_get_pixel_format_info(PFRAME->shmFormat);
|
||||
if (!PSHMINFO) {
|
||||
Debug::log(ERR, "No pixel format supported by renderer in capture toplevel");
|
||||
hyprland_toplevel_export_frame_v1_send_failed(resource);
|
||||
removeFrame(PFRAME);
|
||||
return;
|
||||
}
|
||||
|
||||
if (PMONITOR->output->allocator && (PMONITOR->output->allocator->buffer_caps & WLR_BUFFER_CAP_DMABUF)) {
|
||||
PFRAME->dmabufFormat = PMONITOR->output->render_format;
|
||||
} else {
|
||||
PFRAME->dmabufFormat = DRM_FORMAT_INVALID;
|
||||
}
|
||||
|
||||
PFRAME->box = {0, 0, (int)PWINDOW->m_vRealSize.vec().x, (int)PWINDOW->m_vRealSize.vec().y};
|
||||
int ow, oh;
|
||||
wlr_output_effective_resolution(PMONITOR->output, &ow, &oh);
|
||||
wlr_box_transform(&PFRAME->box, &PFRAME->box, PMONITOR->transform, ow, oh);
|
||||
|
||||
PFRAME->shmStride = (PSHMINFO->bpp / 8) * PFRAME->box.width;
|
||||
|
||||
hyprland_toplevel_export_frame_v1_send_buffer(PFRAME->resource, convert_drm_format_to_wl_shm(PFRAME->shmFormat), PFRAME->box.width, PFRAME->box.height, PFRAME->shmStride);
|
||||
}
|
||||
|
||||
void CToplevelExportProtocolManager::copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage) {
|
||||
const auto PFRAME = frameFromResource(resource);
|
||||
|
||||
if (!PFRAME) {
|
||||
Debug::log(ERR, "No frame in copyFrame??");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PFRAME->pWindow->m_bIsMapped || PFRAME->pWindow->isHidden()) {
|
||||
Debug::log(ERR, "Client requested sharing of window handle %x which is not shareable (2)!", PFRAME->pWindow);
|
||||
hyprland_toplevel_export_frame_v1_send_failed(PFRAME->resource);
|
||||
removeFrame(PFRAME);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto PBUFFER = wlr_buffer_from_resource(buffer);
|
||||
if (!PBUFFER) {
|
||||
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer");
|
||||
removeFrame(PFRAME);
|
||||
return;
|
||||
}
|
||||
|
||||
if (PBUFFER->width != PFRAME->box.width || PBUFFER->height != PFRAME->box.height) {
|
||||
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions");
|
||||
removeFrame(PFRAME);
|
||||
return;
|
||||
}
|
||||
|
||||
if (PFRAME->buffer) {
|
||||
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_ALREADY_USED, "frame already used");
|
||||
removeFrame(PFRAME);
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_dmabuf_attributes dmabufAttrs;
|
||||
void* wlrBufferAccessData;
|
||||
uint32_t wlrBufferAccessFormat;
|
||||
size_t wlrBufferAccessStride;
|
||||
if (wlr_buffer_get_dmabuf(PBUFFER, &dmabufAttrs)) {
|
||||
PFRAME->bufferCap = WLR_BUFFER_CAP_DMABUF;
|
||||
|
||||
if (dmabufAttrs.format != PFRAME->dmabufFormat) {
|
||||
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format");
|
||||
removeFrame(PFRAME);
|
||||
return;
|
||||
}
|
||||
} else if (wlr_buffer_begin_data_ptr_access(PBUFFER, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &wlrBufferAccessData, &wlrBufferAccessFormat, &wlrBufferAccessStride)) {
|
||||
wlr_buffer_end_data_ptr_access(PBUFFER);
|
||||
|
||||
if (wlrBufferAccessFormat != PFRAME->shmFormat) {
|
||||
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format");
|
||||
removeFrame(PFRAME);
|
||||
return;
|
||||
} else if ((int)wlrBufferAccessStride != PFRAME->shmStride) {
|
||||
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer stride");
|
||||
removeFrame(PFRAME);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer type");
|
||||
removeFrame(PFRAME);
|
||||
return;
|
||||
}
|
||||
|
||||
PFRAME->buffer = PBUFFER;
|
||||
|
||||
m_vFramesAwaitingWrite.emplace_back(PFRAME);
|
||||
}
|
||||
|
||||
void CToplevelExportProtocolManager::onMonitorRender(CMonitor* pMonitor) {
|
||||
|
||||
if (m_vFramesAwaitingWrite.empty())
|
||||
return; // nothing to share
|
||||
|
||||
std::vector<SToplevelFrame*> framesToRemove;
|
||||
|
||||
// share frame if correct output
|
||||
for (auto& f : m_vFramesAwaitingWrite) {
|
||||
if (!f->pWindow) {
|
||||
framesToRemove.push_back(f);
|
||||
continue;
|
||||
}
|
||||
|
||||
wlr_box geometry = { f->pWindow->m_vRealPosition.vec().x, f->pWindow->m_vRealPosition.vec().y,
|
||||
f->pWindow->m_vRealSize.vec().x, f->pWindow->m_vRealSize.vec().y };
|
||||
|
||||
if (!wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, &geometry))
|
||||
continue;
|
||||
|
||||
shareFrame(f);
|
||||
|
||||
framesToRemove.push_back(f);
|
||||
}
|
||||
|
||||
for (auto& f : framesToRemove) {
|
||||
removeFrame(f);
|
||||
}
|
||||
}
|
||||
|
||||
void CToplevelExportProtocolManager::shareFrame(SToplevelFrame* frame) {
|
||||
if (!frame->buffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: damage
|
||||
|
||||
timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
uint32_t flags = 0;
|
||||
if (frame->bufferCap == WLR_BUFFER_CAP_DMABUF) {
|
||||
if (!copyFrameDmabuf(frame)) {
|
||||
hyprland_toplevel_export_frame_v1_send_failed(frame->resource);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!copyFrameShm(frame, &now)) {
|
||||
hyprland_toplevel_export_frame_v1_send_failed(frame->resource);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
hyprland_toplevel_export_frame_v1_send_flags(frame->resource, flags);
|
||||
// todo: send damage
|
||||
uint32_t tvSecHi = (sizeof(now.tv_sec) > 4) ? now.tv_sec >> 32 : 0;
|
||||
uint32_t tvSecLo = now.tv_sec & 0xFFFFFFFF;
|
||||
hyprland_toplevel_export_frame_v1_send_ready(frame->resource, tvSecHi, tvSecLo, now.tv_nsec);
|
||||
}
|
||||
|
||||
bool CToplevelExportProtocolManager::copyFrameShm(SToplevelFrame* frame, timespec* now) {
|
||||
void* data;
|
||||
uint32_t format;
|
||||
size_t stride;
|
||||
if (!wlr_buffer_begin_data_ptr_access(frame->buffer, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &data, &format, &stride))
|
||||
return false;
|
||||
|
||||
// render the client
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(frame->pWindow->m_iMonitorID);
|
||||
pixman_region32_t fakeDamage;
|
||||
pixman_region32_init_rect(&fakeDamage, 0, 0, PMONITOR->vecPixelSize.x * 10, PMONITOR->vecPixelSize.y * 10);
|
||||
|
||||
g_pHyprOpenGL->begin(PMONITOR, &fakeDamage, true);
|
||||
g_pHyprOpenGL->clear(CColor(0, 0, 0, 255));
|
||||
|
||||
// render client at 0,0
|
||||
g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(frame->pWindow); // block the feedback to avoid spamming the surface if it's visible
|
||||
g_pHyprRenderer->renderWindow(frame->pWindow, PMONITOR, now, false, RENDER_PASS_ALL, true, true);
|
||||
g_pHyprRenderer->m_bBlockSurfaceFeedback = false;
|
||||
|
||||
// copy pixels
|
||||
const auto PFORMAT = get_gles2_format_from_drm(format);
|
||||
if (!PFORMAT) {
|
||||
Debug::log(ERR, "Cannot read pixels, unsupported format %x", PFORMAT);
|
||||
g_pHyprOpenGL->end();
|
||||
pixman_region32_fini(&fakeDamage);
|
||||
wlr_buffer_end_data_ptr_access(frame->buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, g_pHyprOpenGL->m_RenderData.pCurrentMonData->primaryFB.m_iFb);
|
||||
|
||||
glFinish(); // flush
|
||||
|
||||
glReadPixels(0, 0, frame->box.width, frame->box.height, PFORMAT->gl_format, PFORMAT->gl_type, data);
|
||||
|
||||
g_pHyprOpenGL->end();
|
||||
|
||||
pixman_region32_fini(&fakeDamage);
|
||||
|
||||
wlr_buffer_end_data_ptr_access(frame->buffer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CToplevelExportProtocolManager::copyFrameDmabuf(SToplevelFrame* frame) {
|
||||
// todo
|
||||
Debug::log(ERR, "DMABUF copying not impl'd!");
|
||||
return false;
|
||||
}
|
||||
|
||||
void CToplevelExportProtocolManager::onWindowUnmap(CWindow* pWindow) {
|
||||
for (auto& f : m_lFrames) {
|
||||
if (f.pWindow == pWindow)
|
||||
f.pWindow = nullptr;
|
||||
}
|
||||
}
|
69
src/protocols/ToplevelExport.hpp
Normal file
69
src/protocols/ToplevelExport.hpp
Normal file
@@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
|
||||
#include "../defines.hpp"
|
||||
#include "hyprland-toplevel-export-v1-protocol.h"
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
class CMonitor;
|
||||
class CWindow;
|
||||
|
||||
struct SToplevelClient {
|
||||
int ref = 0;
|
||||
wl_resource* resource = nullptr;
|
||||
|
||||
bool operator==(const SToplevelClient& other) {
|
||||
return resource == other.resource;
|
||||
}
|
||||
};
|
||||
|
||||
struct SToplevelFrame {
|
||||
wl_resource* resource = nullptr;
|
||||
SToplevelClient* client = nullptr;
|
||||
|
||||
uint32_t shmFormat = 0;
|
||||
uint32_t dmabufFormat = 0;
|
||||
wlr_box box = { 0 };
|
||||
int shmStride = 0;
|
||||
|
||||
bool overlayCursor = false;
|
||||
|
||||
wlr_buffer_cap bufferCap = WLR_BUFFER_CAP_SHM;
|
||||
|
||||
wlr_buffer* buffer = nullptr;
|
||||
|
||||
CWindow* pWindow = nullptr;
|
||||
|
||||
bool operator==(const SToplevelFrame& other) {
|
||||
return resource == other.resource && client == other.client;
|
||||
}
|
||||
};
|
||||
|
||||
class CToplevelExportProtocolManager {
|
||||
public:
|
||||
CToplevelExportProtocolManager();
|
||||
|
||||
void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id);
|
||||
void captureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, uint32_t handle);
|
||||
void removeClient(SToplevelClient* client, bool force = false);
|
||||
void removeFrame(SToplevelFrame* frame, bool force = false);
|
||||
void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage);
|
||||
|
||||
void onMonitorRender(CMonitor* pMonitor);
|
||||
void displayDestroy();
|
||||
void onWindowUnmap(CWindow* pWindow);
|
||||
|
||||
private:
|
||||
wl_global* m_pGlobal = nullptr;
|
||||
std::list<SToplevelFrame> m_lFrames;
|
||||
std::list<SToplevelClient> m_lClients;
|
||||
|
||||
wl_listener m_liDisplayDestroy;
|
||||
|
||||
std::vector<SToplevelFrame*> m_vFramesAwaitingWrite;
|
||||
|
||||
void shareFrame(SToplevelFrame* frame);
|
||||
bool copyFrameDmabuf(SToplevelFrame* frame);
|
||||
bool copyFrameShm(SToplevelFrame* frame, timespec* now);
|
||||
};
|
312
src/protocols/ToplevelExportWlrFuncs.hpp
Normal file
312
src/protocols/ToplevelExportWlrFuncs.hpp
Normal file
@@ -0,0 +1,312 @@
|
||||
#include <GLES2/gl2ext.h>
|
||||
|
||||
struct wlr_pixel_format_info {
|
||||
uint32_t drm_format;
|
||||
|
||||
/* Equivalent of the format if it has an alpha channel,
|
||||
* DRM_FORMAT_INVALID (0) if NA
|
||||
*/
|
||||
uint32_t opaque_substitute;
|
||||
|
||||
/* Bits per pixels */
|
||||
uint32_t bpp;
|
||||
|
||||
/* True if the format has an alpha channel */
|
||||
bool has_alpha;
|
||||
};
|
||||
|
||||
static const struct wlr_pixel_format_info pixel_format_info[] = {
|
||||
{
|
||||
.drm_format = DRM_FORMAT_XRGB8888,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 32,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_ARGB8888,
|
||||
.opaque_substitute = DRM_FORMAT_XRGB8888,
|
||||
.bpp = 32,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_XBGR8888,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 32,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_ABGR8888,
|
||||
.opaque_substitute = DRM_FORMAT_XBGR8888,
|
||||
.bpp = 32,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_RGBX8888,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 32,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_RGBA8888,
|
||||
.opaque_substitute = DRM_FORMAT_RGBX8888,
|
||||
.bpp = 32,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_BGRX8888,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 32,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_BGRA8888,
|
||||
.opaque_substitute = DRM_FORMAT_BGRX8888,
|
||||
.bpp = 32,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_BGR888,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 24,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_RGBX4444,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 16,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_RGBA4444,
|
||||
.opaque_substitute = DRM_FORMAT_RGBX4444,
|
||||
.bpp = 16,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_RGBX5551,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 16,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_RGBA5551,
|
||||
.opaque_substitute = DRM_FORMAT_RGBX5551,
|
||||
.bpp = 16,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_RGB565,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 16,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_BGR565,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 16,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_XRGB2101010,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 32,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_ARGB2101010,
|
||||
.opaque_substitute = DRM_FORMAT_XRGB2101010,
|
||||
.bpp = 32,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_XBGR2101010,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 32,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_ABGR2101010,
|
||||
.opaque_substitute = DRM_FORMAT_XBGR2101010,
|
||||
.bpp = 32,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_XBGR16161616F,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 64,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_ABGR16161616F,
|
||||
.opaque_substitute = DRM_FORMAT_XBGR16161616F,
|
||||
.bpp = 64,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_XBGR16161616,
|
||||
.opaque_substitute = DRM_FORMAT_INVALID,
|
||||
.bpp = 64,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_ABGR16161616,
|
||||
.opaque_substitute = DRM_FORMAT_XBGR16161616,
|
||||
.bpp = 64,
|
||||
.has_alpha = true,
|
||||
},
|
||||
};
|
||||
|
||||
static const size_t pixel_format_info_size =
|
||||
sizeof(pixel_format_info) / sizeof(pixel_format_info[0]);
|
||||
|
||||
const struct wlr_pixel_format_info* drm_get_pixel_format_info(uint32_t fmt) {
|
||||
for (size_t i = 0; i < pixel_format_info_size; ++i) {
|
||||
if (pixel_format_info[i].drm_format == fmt) {
|
||||
return &pixel_format_info[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32_t convert_wl_shm_format_to_drm(enum wl_shm_format fmt) {
|
||||
switch (fmt) {
|
||||
case WL_SHM_FORMAT_XRGB8888:
|
||||
return DRM_FORMAT_XRGB8888;
|
||||
case WL_SHM_FORMAT_ARGB8888:
|
||||
return DRM_FORMAT_ARGB8888;
|
||||
default:
|
||||
return (uint32_t)fmt;
|
||||
}
|
||||
}
|
||||
|
||||
enum wl_shm_format convert_drm_format_to_wl_shm(uint32_t fmt) {
|
||||
switch (fmt) {
|
||||
case DRM_FORMAT_XRGB8888:
|
||||
return WL_SHM_FORMAT_XRGB8888;
|
||||
case DRM_FORMAT_ARGB8888:
|
||||
return WL_SHM_FORMAT_ARGB8888;
|
||||
default:
|
||||
return (enum wl_shm_format)fmt;
|
||||
}
|
||||
}
|
||||
|
||||
struct wlr_gles2_pixel_format {
|
||||
uint32_t drm_format;
|
||||
// optional field, if empty then internalformat = format
|
||||
GLint gl_internalformat;
|
||||
GLint gl_format, gl_type;
|
||||
bool has_alpha;
|
||||
};
|
||||
|
||||
static const struct wlr_gles2_pixel_format formats[] = {
|
||||
{
|
||||
.drm_format = DRM_FORMAT_ARGB8888,
|
||||
.gl_format = GL_BGRA_EXT,
|
||||
.gl_type = GL_UNSIGNED_BYTE,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_XRGB8888,
|
||||
.gl_format = GL_BGRA_EXT,
|
||||
.gl_type = GL_UNSIGNED_BYTE,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_XBGR8888,
|
||||
.gl_format = GL_RGBA,
|
||||
.gl_type = GL_UNSIGNED_BYTE,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_ABGR8888,
|
||||
.gl_format = GL_RGBA,
|
||||
.gl_type = GL_UNSIGNED_BYTE,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_BGR888,
|
||||
.gl_format = GL_RGB,
|
||||
.gl_type = GL_UNSIGNED_BYTE,
|
||||
.has_alpha = false,
|
||||
},
|
||||
#if WLR_LITTLE_ENDIAN
|
||||
{
|
||||
.drm_format = DRM_FORMAT_RGBX4444,
|
||||
.gl_format = GL_RGBA,
|
||||
.gl_type = GL_UNSIGNED_SHORT_4_4_4_4,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_RGBA4444,
|
||||
.gl_format = GL_RGBA,
|
||||
.gl_type = GL_UNSIGNED_SHORT_4_4_4_4,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_RGBX5551,
|
||||
.gl_format = GL_RGBA,
|
||||
.gl_type = GL_UNSIGNED_SHORT_5_5_5_1,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_RGBA5551,
|
||||
.gl_format = GL_RGBA,
|
||||
.gl_type = GL_UNSIGNED_SHORT_5_5_5_1,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_RGB565,
|
||||
.gl_format = GL_RGB,
|
||||
.gl_type = GL_UNSIGNED_SHORT_5_6_5,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_XBGR2101010,
|
||||
.gl_format = GL_RGBA,
|
||||
.gl_type = GL_UNSIGNED_INT_2_10_10_10_REV_EXT,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_ABGR2101010,
|
||||
.gl_format = GL_RGBA,
|
||||
.gl_type = GL_UNSIGNED_INT_2_10_10_10_REV_EXT,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_XBGR16161616F,
|
||||
.gl_format = GL_RGBA,
|
||||
.gl_type = GL_HALF_FLOAT_OES,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_ABGR16161616F,
|
||||
.gl_format = GL_RGBA,
|
||||
.gl_type = GL_HALF_FLOAT_OES,
|
||||
.has_alpha = true,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_XBGR16161616,
|
||||
.gl_internalformat = GL_RGBA16_EXT,
|
||||
.gl_format = GL_RGBA,
|
||||
.gl_type = GL_UNSIGNED_SHORT,
|
||||
.has_alpha = false,
|
||||
},
|
||||
{
|
||||
.drm_format = DRM_FORMAT_ABGR16161616,
|
||||
.gl_internalformat = GL_RGBA16_EXT,
|
||||
.gl_format = GL_RGBA,
|
||||
.gl_type = GL_UNSIGNED_SHORT,
|
||||
.has_alpha = true,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
const struct wlr_gles2_pixel_format* get_gles2_format_from_drm(uint32_t fmt) {
|
||||
for (size_t i = 0; i < sizeof(formats) / sizeof(*formats); ++i) {
|
||||
if (formats[i].drm_format == fmt) {
|
||||
return &formats[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
@@ -27,7 +27,6 @@ bool CFramebuffer::alloc(int w, int h) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_iFb);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_cTex.m_iTexID, 0);
|
||||
|
||||
|
||||
// TODO: Allow this with gles2
|
||||
#ifndef GLES2
|
||||
if (m_pStencilTex) {
|
||||
@@ -80,3 +79,7 @@ void CFramebuffer::release() {
|
||||
CFramebuffer::~CFramebuffer() {
|
||||
release();
|
||||
}
|
||||
|
||||
bool CFramebuffer::isAllocated() {
|
||||
return m_iFb != (GLuint)-1;
|
||||
}
|
@@ -12,6 +12,7 @@ public:
|
||||
void bind();
|
||||
void release();
|
||||
void reset();
|
||||
bool isAllocated();
|
||||
|
||||
Vector2D m_Position;
|
||||
Vector2D m_Size;
|
||||
|
@@ -25,23 +25,27 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
|
||||
Debug::log(WARN, "!RENDERER: Using the legacy GLES2 renderer!");
|
||||
#endif
|
||||
|
||||
// End shaders
|
||||
|
||||
pixman_region32_init(&m_rOriginalDamageRegion);
|
||||
|
||||
// End
|
||||
|
||||
RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!");
|
||||
|
||||
// Done!
|
||||
}
|
||||
|
||||
GLuint CHyprOpenGLImpl::createProgram(const std::string& vert, const std::string& frag) {
|
||||
auto vertCompiled = compileShader(GL_VERTEX_SHADER, vert);
|
||||
RASSERT(vertCompiled, "Compiling shader failed. VERTEX NULL! Shader source:\n\n%s", vert.c_str());
|
||||
GLuint CHyprOpenGLImpl::createProgram(const std::string& vert, const std::string& frag, bool dynamic) {
|
||||
auto vertCompiled = compileShader(GL_VERTEX_SHADER, vert, dynamic);
|
||||
if (dynamic) {
|
||||
if (vertCompiled == 0)
|
||||
return 0;
|
||||
} else {
|
||||
RASSERT(vertCompiled, "Compiling shader failed. VERTEX NULL! Shader source:\n\n%s", vert.c_str());
|
||||
}
|
||||
|
||||
auto fragCompiled = compileShader(GL_FRAGMENT_SHADER, frag);
|
||||
RASSERT(fragCompiled, "Compiling shader failed. FRAGMENT NULL! Shader source:\n\n%s", frag.c_str());
|
||||
auto fragCompiled = compileShader(GL_FRAGMENT_SHADER, frag, dynamic);
|
||||
if (dynamic) {
|
||||
if (fragCompiled == 0)
|
||||
return 0;
|
||||
} else {
|
||||
RASSERT(fragCompiled, "Compiling shader failed. FRAGMENT NULL! Shader source:\n\n%s", frag.c_str());
|
||||
}
|
||||
|
||||
auto prog = glCreateProgram();
|
||||
glAttachShader(prog, vertCompiled);
|
||||
@@ -55,12 +59,17 @@ GLuint CHyprOpenGLImpl::createProgram(const std::string& vert, const std::string
|
||||
|
||||
GLint ok;
|
||||
glGetProgramiv(prog, GL_LINK_STATUS, &ok);
|
||||
RASSERT(ok != GL_FALSE, "createProgram() failed! GL_LINK_STATUS not OK!");
|
||||
if (dynamic) {
|
||||
if (ok == GL_FALSE)
|
||||
return 0;
|
||||
} else {
|
||||
RASSERT(ok != GL_FALSE, "createProgram() failed! GL_LINK_STATUS not OK!");
|
||||
}
|
||||
|
||||
return prog;
|
||||
}
|
||||
|
||||
GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src) {
|
||||
GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src, bool dynamic) {
|
||||
auto shader = glCreateShader(type);
|
||||
|
||||
auto shaderSource = src.c_str();
|
||||
@@ -70,7 +79,12 @@ GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src) {
|
||||
|
||||
GLint ok;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &ok);
|
||||
RASSERT(ok != GL_FALSE, "compileShader() failed! GL_COMPILE_STATUS not OK!");
|
||||
if (dynamic) {
|
||||
if (ok == GL_FALSE)
|
||||
return 0;
|
||||
} else {
|
||||
RASSERT(ok != GL_FALSE, "compileShader() failed! GL_COMPILE_STATUS not OK!");
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
@@ -118,6 +132,11 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, pixman_region32_t* pDamage, bool
|
||||
m_RenderData.pDamage = pDamage;
|
||||
|
||||
m_bFakeFrame = fake;
|
||||
|
||||
if (m_bReloadScreenShader) {
|
||||
m_bReloadScreenShader = false;
|
||||
applyScreenShader(g_pConfigManager->getString("decoration:screen_shader"));
|
||||
}
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::end() {
|
||||
@@ -134,9 +153,11 @@ void CHyprOpenGLImpl::end() {
|
||||
clear(CColor(11, 11, 11, 255));
|
||||
|
||||
m_bEndFrame = true;
|
||||
m_bApplyFinalShader = true;
|
||||
|
||||
renderTexture(m_RenderData.pCurrentMonData->primaryFB.m_cTex, &monbox, 255.f, 0);
|
||||
|
||||
m_bApplyFinalShader = false;
|
||||
m_bEndFrame = false;
|
||||
}
|
||||
|
||||
@@ -243,15 +264,48 @@ void CHyprOpenGLImpl::initShaders() {
|
||||
m_RenderData.pCurrentMonData->m_shBORDER1.topLeft = glGetUniformLocation(prog, "topLeft");
|
||||
m_RenderData.pCurrentMonData->m_shBORDER1.bottomRight = glGetUniformLocation(prog, "bottomRight");
|
||||
m_RenderData.pCurrentMonData->m_shBORDER1.fullSize = glGetUniformLocation(prog, "fullSize");
|
||||
m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed = glGetUniformLocation(prog, "fullSizeUntransformed");
|
||||
m_RenderData.pCurrentMonData->m_shBORDER1.radius = glGetUniformLocation(prog, "radius");
|
||||
m_RenderData.pCurrentMonData->m_shBORDER1.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample");
|
||||
m_RenderData.pCurrentMonData->m_shBORDER1.color = glGetUniformLocation(prog, "color");
|
||||
m_RenderData.pCurrentMonData->m_shBORDER1.gradient = glGetUniformLocation(prog, "gradient");
|
||||
m_RenderData.pCurrentMonData->m_shBORDER1.gradientLength = glGetUniformLocation(prog, "gradientLength");
|
||||
m_RenderData.pCurrentMonData->m_shBORDER1.angle = glGetUniformLocation(prog, "angle");
|
||||
m_RenderData.pCurrentMonData->m_shBORDER1.alpha = glGetUniformLocation(prog, "alpha");
|
||||
|
||||
m_RenderData.pCurrentMonData->m_bShadersInitialized = true;
|
||||
|
||||
Debug::log(LOG, "Shaders initialized successfully.");
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::applyScreenShader(const std::string& path) {
|
||||
|
||||
m_sFinalScreenShader.destroy();
|
||||
|
||||
if (path == "" || path == STRVAL_EMPTY)
|
||||
return;
|
||||
|
||||
std::ifstream infile(absolutePath(path, std::string(getenv("HOME")) + "/.config/hypr"));
|
||||
|
||||
if (!infile.good()) {
|
||||
g_pConfigManager->addParseError("Screen shader parser: Screen shader path not found");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string fragmentShader((std::istreambuf_iterator<char>(infile)), (std::istreambuf_iterator<char>()));
|
||||
|
||||
m_sFinalScreenShader.program = createProgram(TEXVERTSRC, fragmentShader, true);
|
||||
|
||||
if (!m_sFinalScreenShader.program) {
|
||||
g_pConfigManager->addParseError("Screen shader parser: Screen shader parse failed");
|
||||
return;
|
||||
}
|
||||
|
||||
m_sFinalScreenShader.proj = glGetUniformLocation(m_sFinalScreenShader.program, "proj");
|
||||
m_sFinalScreenShader.tex = glGetUniformLocation(m_sFinalScreenShader.program, "tex");
|
||||
m_sFinalScreenShader.texAttrib = glGetAttribLocation(m_sFinalScreenShader.program, "texcoord");
|
||||
m_sFinalScreenShader.posAttrib = glGetAttribLocation(m_sFinalScreenShader.program, "pos");
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::clear(const CColor& color) {
|
||||
RASSERT(m_RenderData.pMonitor, "Tried to render without begin()!");
|
||||
|
||||
@@ -422,18 +476,25 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
switch (tex.m_iType) {
|
||||
case TEXTURE_RGBA:
|
||||
shader = &m_RenderData.pCurrentMonData->m_shRGBA;
|
||||
break;
|
||||
case TEXTURE_RGBX:
|
||||
shader = &m_RenderData.pCurrentMonData->m_shRGBX;
|
||||
break;
|
||||
case TEXTURE_EXTERNAL:
|
||||
shader = &m_RenderData.pCurrentMonData->m_shEXT;
|
||||
break;
|
||||
default:
|
||||
RASSERT(false, "tex.m_iTarget unsupported!");
|
||||
bool usingFinalShader = false;
|
||||
|
||||
if (m_bApplyFinalShader && m_sFinalScreenShader.program) {
|
||||
shader = &m_sFinalScreenShader;
|
||||
usingFinalShader = true;
|
||||
} else {
|
||||
switch (tex.m_iType) {
|
||||
case TEXTURE_RGBA:
|
||||
shader = &m_RenderData.pCurrentMonData->m_shRGBA;
|
||||
break;
|
||||
case TEXTURE_RGBX:
|
||||
shader = &m_RenderData.pCurrentMonData->m_shRGBX;
|
||||
break;
|
||||
case TEXTURE_EXTERNAL:
|
||||
shader = &m_RenderData.pCurrentMonData->m_shEXT;
|
||||
break;
|
||||
default:
|
||||
RASSERT(false, "tex.m_iTarget unsupported!");
|
||||
}
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
@@ -450,8 +511,10 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
|
||||
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix);
|
||||
#endif
|
||||
glUniform1i(shader->tex, 0);
|
||||
glUniform1f(shader->alpha, alpha / 255.f);
|
||||
glUniform1i(shader->discardOpaque, (int)discardOpaque);
|
||||
if (!usingFinalShader) {
|
||||
glUniform1f(shader->alpha, alpha / 255.f);
|
||||
glUniform1i(shader->discardOpaque, (int)discardOpaque);
|
||||
}
|
||||
|
||||
wlr_box transformedBox;
|
||||
wlr_box_transform(&transformedBox, pBox, wlr_output_transform_invert(m_RenderData.pMonitor->transform),
|
||||
@@ -461,18 +524,20 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
|
||||
const auto FULLSIZE = Vector2D(transformedBox.width, transformedBox.height);
|
||||
static auto *const PMULTISAMPLEEDGES = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue;
|
||||
|
||||
// Rounded corners
|
||||
glUniform2f(shader->topLeft, TOPLEFT.x, TOPLEFT.y);
|
||||
glUniform2f(shader->fullSize, FULLSIZE.x ,FULLSIZE.y);
|
||||
glUniform1f(shader->radius, round);
|
||||
glUniform1i(shader->primitiveMultisample, (int)(*PMULTISAMPLEEDGES == 1 && round != 0 && !noAA));
|
||||
if (!usingFinalShader) {
|
||||
// Rounded corners
|
||||
glUniform2f(shader->topLeft, TOPLEFT.x, TOPLEFT.y);
|
||||
glUniform2f(shader->fullSize, FULLSIZE.x, FULLSIZE.y);
|
||||
glUniform1f(shader->radius, round);
|
||||
glUniform1i(shader->primitiveMultisample, (int)(*PMULTISAMPLEEDGES == 1 && round != 0 && !noAA));
|
||||
|
||||
if (allowDim && m_pCurrentWindow && *PDIMINACTIVE && m_pCurrentWindow != g_pCompositor->m_pLastWindow) {
|
||||
glUniform1i(shader->applyTint, 1);
|
||||
const auto DIM = m_pCurrentWindow->m_fDimPercent.fl();
|
||||
glUniform3f(shader->tint, 1.f - DIM, 1.f - DIM, 1.f - DIM);
|
||||
} else {
|
||||
glUniform1i(shader->applyTint, 0);
|
||||
if (allowDim && m_pCurrentWindow && *PDIMINACTIVE && m_pCurrentWindow != g_pCompositor->m_pLastWindow) {
|
||||
glUniform1i(shader->applyTint, 1);
|
||||
const auto DIM = m_pCurrentWindow->m_fDimPercent.fl();
|
||||
glUniform3f(shader->tint, 1.f - DIM, 1.f - DIM, 1.f - DIM);
|
||||
} else {
|
||||
glUniform1i(shader->applyTint, 0);
|
||||
}
|
||||
}
|
||||
|
||||
const float verts[] = {
|
||||
@@ -506,13 +571,13 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
|
||||
}
|
||||
}
|
||||
|
||||
pixman_region32_fini(&damageClip);
|
||||
pixman_region32_fini(&damageClip);
|
||||
} else {
|
||||
PIXMAN_DAMAGE_FOREACH(damage) {
|
||||
const auto RECT = RECTSARR[i];
|
||||
scissor(&RECT);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
PIXMAN_DAMAGE_FOREACH(damage) {
|
||||
const auto RECT = RECTSARR[i];
|
||||
scissor(&RECT);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
}
|
||||
|
||||
glDisableVertexAttribArray(shader->posAttrib);
|
||||
@@ -650,14 +715,16 @@ void CHyprOpenGLImpl::markBlurDirtyForMonitor(CMonitor* pMonitor) {
|
||||
|
||||
void CHyprOpenGLImpl::preRender(CMonitor* pMonitor) {
|
||||
static auto *const PBLURNEWOPTIMIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_new_optimizations")->intValue;
|
||||
static auto *const PBLURXRAY = &g_pConfigManager->getConfigValuePtr("decoration:blur_xray")->intValue;
|
||||
static auto *const PBLUR = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue;
|
||||
|
||||
if (!*PBLURNEWOPTIMIZE || !m_mMonitorRenderResources[pMonitor].blurFBDirty)
|
||||
if (!*PBLURNEWOPTIMIZE || !m_mMonitorRenderResources[pMonitor].blurFBDirty || !*PBLUR)
|
||||
return;
|
||||
|
||||
bool has = false;
|
||||
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_iWorkspaceID == pMonitor->activeWorkspace && w->m_bIsMapped && !w->isHidden() && !w->m_bIsFloating) {
|
||||
if (w->m_iWorkspaceID == pMonitor->activeWorkspace && w->m_bIsMapped && !w->isHidden() && (!w->m_bIsFloating || *PBLURXRAY)) {
|
||||
has = true;
|
||||
break;
|
||||
}
|
||||
@@ -694,13 +761,54 @@ void CHyprOpenGLImpl::preBlurForCurrentMonitor() {
|
||||
|
||||
void CHyprOpenGLImpl::preWindowPass() {
|
||||
static auto *const PBLURNEWOPTIMIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_new_optimizations")->intValue;
|
||||
static auto *const PBLURXRAY = &g_pConfigManager->getConfigValuePtr("decoration:blur_xray")->intValue;
|
||||
static auto *const PBLUR = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue;
|
||||
|
||||
if (!m_RenderData.pCurrentMonData->blurFBDirty || !*PBLURNEWOPTIMIZE)
|
||||
if (!m_RenderData.pCurrentMonData->blurFBDirty || !*PBLURNEWOPTIMIZE || !*PBLUR)
|
||||
return;
|
||||
|
||||
auto windowShouldBeBlurred = [&] (CWindow* pWindow) -> bool {
|
||||
if (!pWindow)
|
||||
return false;
|
||||
|
||||
if (pWindow->m_sAdditionalConfigData.forceNoBlur)
|
||||
return false;
|
||||
|
||||
const auto PSURFACE = g_pXWaylandManager->getWindowSurface(pWindow);
|
||||
|
||||
if (PSURFACE->opaque)
|
||||
return false;
|
||||
|
||||
pixman_region32_t inverseOpaque;
|
||||
pixman_region32_init(&inverseOpaque);
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
|
||||
const float A = pWindow->m_fAlpha.fl() * pWindow->m_fActiveInactiveAlpha.fl() * PWORKSPACE->m_fAlpha.fl() / 255.f;
|
||||
|
||||
if (A >= 255.f) {
|
||||
pixman_box32_t surfbox = {0, 0, PSURFACE->current.width, PSURFACE->current.height};
|
||||
pixman_region32_copy(&inverseOpaque, &PSURFACE->current.opaque);
|
||||
pixman_region32_inverse(&inverseOpaque, &inverseOpaque, &surfbox);
|
||||
pixman_region32_intersect_rect(&inverseOpaque, &inverseOpaque, 0, 0, PSURFACE->current.width, PSURFACE->current.height);
|
||||
|
||||
if (!pixman_region32_not_empty(&inverseOpaque)) {
|
||||
pixman_region32_fini(&inverseOpaque);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
pixman_region32_fini(&inverseOpaque);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
bool hasWindows = false;
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_iWorkspaceID == m_RenderData.pMonitor->activeWorkspace && !w->isHidden() && w->m_bIsMapped && !w->m_bIsFloating) {
|
||||
if (w->m_iWorkspaceID == m_RenderData.pMonitor->activeWorkspace && !w->isHidden() && w->m_bIsMapped && (!w->m_bIsFloating || *PBLURXRAY)) {
|
||||
|
||||
// check if window is valid
|
||||
if (!windowShouldBeBlurred(w.get()))
|
||||
continue;
|
||||
|
||||
hasWindows = true;
|
||||
break;
|
||||
}
|
||||
@@ -713,12 +821,13 @@ void CHyprOpenGLImpl::preWindowPass() {
|
||||
preBlurForCurrentMonitor();
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, float a, wlr_surface* pSurface, int round) {
|
||||
void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, float a, wlr_surface* pSurface, int round, bool blockBlurOptimization) {
|
||||
RASSERT(m_RenderData.pMonitor, "Tried to render texture with blur without begin()!");
|
||||
|
||||
static auto *const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue;
|
||||
static auto *const PNOBLUROVERSIZED = &g_pConfigManager->getConfigValuePtr("decoration:no_blur_on_oversized")->intValue;
|
||||
static auto *const PBLURNEWOPTIMIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_new_optimizations")->intValue;
|
||||
static auto *const PBLURXRAY = &g_pConfigManager->getConfigValuePtr("decoration:blur_xray")->intValue;
|
||||
|
||||
// make a damage region for this window
|
||||
pixman_region32_t damage;
|
||||
@@ -726,7 +835,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox,
|
||||
pixman_region32_intersect_rect(&damage, m_RenderData.pDamage, pBox->x, pBox->y, pBox->width, pBox->height); // clip it to the box
|
||||
|
||||
if(!pixman_region32_not_empty(&damage))
|
||||
return;
|
||||
return;
|
||||
|
||||
if (*PBLURENABLED == 0 || (*PNOBLUROVERSIZED && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) || (m_pCurrentWindow && m_pCurrentWindow->m_sAdditionalConfigData.forceNoBlur)) {
|
||||
renderTexture(tex, pBox, a, round, false, true);
|
||||
@@ -736,26 +845,33 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox,
|
||||
// amazing hack: the surface has an opaque region!
|
||||
pixman_region32_t inverseOpaque;
|
||||
pixman_region32_init(&inverseOpaque);
|
||||
if (a == 255.f) {
|
||||
pixman_box32_t monbox = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y};
|
||||
if (a >= 255.f) {
|
||||
pixman_box32_t surfbox = {0, 0, pSurface->current.width, pSurface->current.height};
|
||||
pixman_region32_copy(&inverseOpaque, &pSurface->current.opaque);
|
||||
pixman_region32_translate(&inverseOpaque, pBox->x, pBox->y);
|
||||
pixman_region32_inverse(&inverseOpaque, &inverseOpaque, &monbox);
|
||||
pixman_region32_intersect(&inverseOpaque, &damage, &inverseOpaque);
|
||||
pixman_region32_inverse(&inverseOpaque, &inverseOpaque, &surfbox);
|
||||
pixman_region32_intersect_rect(&inverseOpaque, &inverseOpaque, 0, 0, pSurface->current.width, pSurface->current.height);
|
||||
|
||||
if (!pixman_region32_not_empty(&inverseOpaque)) {
|
||||
pixman_region32_fini(&inverseOpaque);
|
||||
renderTexture(tex, pBox, a, round, false, true);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
pixman_region32_copy(&inverseOpaque, &damage);
|
||||
pixman_region32_init_rect(&inverseOpaque, 0, 0, pBox->width, pBox->height);
|
||||
}
|
||||
|
||||
if (!pixman_region32_not_empty(&inverseOpaque)) {
|
||||
renderTexture(tex, pBox, a, round, false, true); // reject blurring a fully opaque window
|
||||
return;
|
||||
// vvv TODO: layered blur fbs?
|
||||
const bool USENEWOPTIMIZE = (*PBLURNEWOPTIMIZE && !blockBlurOptimization && ((m_pCurrentWindow && !m_pCurrentWindow->m_bIsFloating) || *PBLURXRAY) && m_RenderData.pCurrentMonData->blurFB.m_cTex.m_iTexID && (!m_pCurrentWindow || !g_pCompositor->isWorkspaceSpecial(m_pCurrentWindow->m_iWorkspaceID) ));
|
||||
|
||||
CFramebuffer* POUTFB = nullptr;
|
||||
if (!USENEWOPTIMIZE) {
|
||||
pixman_region32_translate(&inverseOpaque, pBox->x, pBox->y);
|
||||
|
||||
POUTFB = blurMainFramebufferWithDamage(a, pBox, &inverseOpaque);
|
||||
} else {
|
||||
POUTFB = &m_RenderData.pCurrentMonData->blurFB;
|
||||
}
|
||||
|
||||
// vvv TODO: layered blur fbs?
|
||||
const bool USENEWOPTIMIZE = (*PBLURNEWOPTIMIZE && m_pCurrentWindow && !m_pCurrentWindow->m_bIsFloating && m_RenderData.pCurrentMonData->blurFB.m_cTex.m_iTexID && m_pCurrentWindow->m_iWorkspaceID != SPECIAL_WORKSPACE_ID);
|
||||
|
||||
const auto POUTFB = USENEWOPTIMIZE ? &m_RenderData.pCurrentMonData->blurFB : blurMainFramebufferWithDamage(a, pBox, &inverseOpaque);
|
||||
|
||||
pixman_region32_fini(&inverseOpaque);
|
||||
|
||||
// bind primary
|
||||
@@ -810,12 +926,12 @@ void pushVert2D(float x, float y, float* arr, int& counter, wlr_box* box) {
|
||||
counter++;
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int round) {
|
||||
void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CGradientValueData& grad, int round, float a) {
|
||||
RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!");
|
||||
RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!");
|
||||
|
||||
if (!pixman_region32_not_empty(m_RenderData.pDamage) || (m_pCurrentWindow && m_pCurrentWindow->m_sAdditionalConfigData.forceNoBorder))
|
||||
return;
|
||||
return;
|
||||
|
||||
static auto *const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
|
||||
static auto *const PMULTISAMPLE = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue;
|
||||
@@ -825,27 +941,13 @@ void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int round) {
|
||||
|
||||
int scaledBorderSize = *PBORDERSIZE * m_RenderData.pMonitor->scale;
|
||||
|
||||
if (round < 1) {
|
||||
// zero rounding, just lines
|
||||
wlr_box borderbox = {box->x - scaledBorderSize, box->y - scaledBorderSize, scaledBorderSize, box->height + 2 * scaledBorderSize};
|
||||
renderRect(&borderbox, col, 0); // left
|
||||
borderbox = {box->x, box->y - (int)scaledBorderSize, box->width + (int)scaledBorderSize, (int)scaledBorderSize};
|
||||
renderRect(&borderbox, col, 0); // top
|
||||
borderbox = {box->x + box->width, box->y, (int)scaledBorderSize, box->height + (int)scaledBorderSize};
|
||||
renderRect(&borderbox, col, 0); // right
|
||||
borderbox = {box->x, box->y + box->height, box->width, (int)scaledBorderSize};
|
||||
renderRect(&borderbox, col, 0); // bottom
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// adjust box
|
||||
box->x -= scaledBorderSize;
|
||||
box->y -= scaledBorderSize;
|
||||
box->width += 2 * scaledBorderSize;
|
||||
box->height += 2 * scaledBorderSize;
|
||||
|
||||
round += scaledBorderSize;
|
||||
round += round == 0 ? 0 : scaledBorderSize;
|
||||
|
||||
float matrix[9];
|
||||
wlr_matrix_project_box(matrix, box, wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), 0, m_RenderData.pMonitor->output->transform_matrix); // TODO: write own, don't use WLR here
|
||||
@@ -864,15 +966,24 @@ void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int round) {
|
||||
wlr_matrix_transpose(glMatrix, glMatrix);
|
||||
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_FALSE, glMatrix);
|
||||
#endif
|
||||
glUniform4f(m_RenderData.pCurrentMonData->m_shBORDER1.color, col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f);
|
||||
|
||||
const auto TOPLEFT = Vector2D(round, round);
|
||||
const auto BOTTOMRIGHT = Vector2D(box->width - round, box->height - round);
|
||||
const auto FULLSIZE = Vector2D(box->width, box->height);
|
||||
static_assert(sizeof(CColor) == 4 * sizeof(float)); // otherwise the line below this will fail
|
||||
|
||||
glUniform4fv(m_RenderData.pCurrentMonData->m_shBORDER1.gradient, grad.m_vColors.size(), (float*)grad.m_vColors.data());
|
||||
glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.gradientLength, grad.m_vColors.size());
|
||||
glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.angle, (int)(grad.m_fAngle / (PI / 180.0)) % 360 * (PI / 180.0));
|
||||
glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.alpha, a);
|
||||
|
||||
wlr_box transformedBox;
|
||||
wlr_box_transform(&transformedBox, box, wlr_output_transform_invert(m_RenderData.pMonitor->transform),
|
||||
m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y);
|
||||
|
||||
const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y);
|
||||
const auto FULLSIZE = Vector2D(transformedBox.width, transformedBox.height);
|
||||
|
||||
glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y);
|
||||
glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
|
||||
glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y);
|
||||
glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed, (float)box->width, (float)box->height);
|
||||
glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radius, round);
|
||||
glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.thick, scaledBorderSize);
|
||||
glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.primitiveMultisample, *PMULTISAMPLE);
|
||||
@@ -896,19 +1007,80 @@ void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int round) {
|
||||
}
|
||||
}
|
||||
|
||||
pixman_region32_fini(&damageClip);
|
||||
pixman_region32_fini(&damageClip);
|
||||
} else {
|
||||
PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) {
|
||||
const auto RECT = RECTSARR[i];
|
||||
scissor(&RECT);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) {
|
||||
const auto RECT = RECTSARR[i];
|
||||
scissor(&RECT);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
}
|
||||
|
||||
glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib);
|
||||
glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib);
|
||||
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// fix back box
|
||||
box->x += scaledBorderSize;
|
||||
box->y += scaledBorderSize;
|
||||
box->width -= 2 * scaledBorderSize;
|
||||
box->height -= 2 * scaledBorderSize;
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::makeRawWindowSnapshot(CWindow* pWindow, CFramebuffer* pFramebuffer) {
|
||||
// we trust the window is valid.
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
|
||||
wlr_output_attach_render(PMONITOR->output, nullptr);
|
||||
|
||||
// we need to "damage" the entire monitor
|
||||
// so that we render the entire window
|
||||
// this is temporary, doesnt mess with the actual wlr damage
|
||||
pixman_region32_t fakeDamage;
|
||||
pixman_region32_init(&fakeDamage);
|
||||
pixman_region32_union_rect(&fakeDamage, &fakeDamage, 0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y);
|
||||
|
||||
begin(PMONITOR, &fakeDamage, true);
|
||||
|
||||
clear(CColor(0, 0, 0, 0)); // JIC
|
||||
|
||||
timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
// this is a hack but it works :P
|
||||
// we need to disable blur or else we will get a black background, as the shader
|
||||
// will try to copy the bg to apply blur.
|
||||
// this isn't entirely correct, but like, oh well.
|
||||
// small todo: maybe make this correct? :P
|
||||
const auto BLURVAL = g_pConfigManager->getInt("decoration:blur");
|
||||
g_pConfigManager->setInt("decoration:blur", 0);
|
||||
|
||||
// TODO: how can we make this the size of the window? setting it to window's size makes the entire screen render with the wrong res forever more. odd.
|
||||
glViewport(0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
|
||||
|
||||
pFramebuffer->m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex;
|
||||
|
||||
pFramebuffer->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
|
||||
|
||||
pFramebuffer->bind();
|
||||
|
||||
clear(CColor(0, 0, 0, 0)); // JIC
|
||||
|
||||
g_pHyprRenderer->renderWindow(pWindow, PMONITOR, &now, false, RENDER_PASS_ALL, true);
|
||||
|
||||
g_pConfigManager->setInt("decoration:blur", BLURVAL);
|
||||
|
||||
// restore original fb
|
||||
#ifndef GLES2
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_iCurrentOutputFb);
|
||||
#else
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_iCurrentOutputFb);
|
||||
#endif
|
||||
end();
|
||||
|
||||
pixman_region32_fini(&fakeDamage);
|
||||
|
||||
wlr_output_rollback(PMONITOR->output);
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
|
||||
@@ -925,7 +1097,7 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
|
||||
|
||||
begin(PMONITOR, &fakeDamage, true);
|
||||
|
||||
clear(CColor(0,0,0,0)); // JIC
|
||||
clear(CColor(0, 0, 0, 0)); // JIC
|
||||
|
||||
timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
@@ -938,10 +1110,9 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
|
||||
const auto BLURVAL = g_pConfigManager->getInt("decoration:blur");
|
||||
g_pConfigManager->setInt("decoration:blur", 0);
|
||||
|
||||
// render onto the window fb
|
||||
const auto PFRAMEBUFFER = &m_mWindowFramebuffers[pWindow];
|
||||
glViewport(0, 0, m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y);
|
||||
|
||||
glViewport(0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.y);
|
||||
const auto PFRAMEBUFFER = &m_mWindowFramebuffers[pWindow];
|
||||
|
||||
PFRAMEBUFFER->m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex;
|
||||
|
||||
@@ -955,12 +1126,12 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
|
||||
|
||||
g_pConfigManager->setInt("decoration:blur", BLURVAL);
|
||||
|
||||
// restore original fb
|
||||
#ifndef GLES2
|
||||
// restore original fb
|
||||
#ifndef GLES2
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_iCurrentOutputFb);
|
||||
#else
|
||||
#else
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_iCurrentOutputFb);
|
||||
#endif
|
||||
#endif
|
||||
end();
|
||||
|
||||
pixman_region32_fini(&fakeDamage);
|
||||
@@ -1020,6 +1191,14 @@ void CHyprOpenGLImpl::makeLayerSnapshot(SLayerSurface* pLayer) {
|
||||
wlr_output_rollback(PMONITOR->output);
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::onWindowResizeStart(CWindow* pWindow) {
|
||||
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::onWindowResizeEnd(CWindow* pWindow) {
|
||||
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::renderSnapshot(CWindow** pWindow) {
|
||||
RASSERT(m_RenderData.pMonitor, "Tried to render snapshot rect without begin()!");
|
||||
const auto PWINDOW = *pWindow;
|
||||
@@ -1162,13 +1341,13 @@ void CHyprOpenGLImpl::renderRoundedShadow(wlr_box* box, int round, int range, fl
|
||||
}
|
||||
}
|
||||
|
||||
pixman_region32_fini(&damageClip);
|
||||
pixman_region32_fini(&damageClip);
|
||||
} else {
|
||||
PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) {
|
||||
const auto RECT = RECTSARR[i];
|
||||
scissor(&RECT);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) {
|
||||
const auto RECT = RECTSARR[i];
|
||||
scissor(&RECT);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
}
|
||||
|
||||
glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shSHADOW.posAttrib);
|
||||
|
@@ -12,6 +12,8 @@
|
||||
#include "Texture.hpp"
|
||||
#include "Framebuffer.hpp"
|
||||
|
||||
class CHyprRenderer;
|
||||
|
||||
inline const float fullVerts[] = {
|
||||
1, 0, // top right
|
||||
0, 0, // top left
|
||||
@@ -66,6 +68,8 @@ struct SCurrentRenderData {
|
||||
wlr_box clipBox = {};
|
||||
};
|
||||
|
||||
class CGradientValueData;
|
||||
|
||||
class CHyprOpenGLImpl {
|
||||
public:
|
||||
|
||||
@@ -78,11 +82,12 @@ public:
|
||||
void renderRectWithDamage(wlr_box*, const CColor&, pixman_region32_t* damage, int round = 0);
|
||||
void renderTexture(wlr_texture*, wlr_box*, float a, int round = 0, bool allowCustomUV = false);
|
||||
void renderTexture(const CTexture&, wlr_box*, float a, int round = 0, bool discardOpaque = false, bool allowCustomUV = false);
|
||||
void renderTextureWithBlur(const CTexture&, wlr_box*, float a, wlr_surface* pSurface, int round = 0);
|
||||
void renderTextureWithBlur(const CTexture&, wlr_box*, float a, wlr_surface* pSurface, int round = 0, bool blockBlurOptimization = false);
|
||||
void renderRoundedShadow(wlr_box*, int round, int range, float a = 1.0);
|
||||
void renderBorder(wlr_box*, const CColor&, int round);
|
||||
void renderBorder(wlr_box*, const CGradientValueData&, int round, float a = 1.0);
|
||||
|
||||
void makeWindowSnapshot(CWindow*);
|
||||
void makeRawWindowSnapshot(CWindow*, CFramebuffer*);
|
||||
void makeLayerSnapshot(SLayerSurface*);
|
||||
void renderSnapshot(CWindow**);
|
||||
void renderSnapshot(SLayerSurface**);
|
||||
@@ -103,11 +108,18 @@ public:
|
||||
void saveBufferForMirror();
|
||||
void renderMirrored();
|
||||
|
||||
void onWindowResizeStart(CWindow*);
|
||||
void onWindowResizeEnd(CWindow*);
|
||||
|
||||
void applyScreenShader(const std::string& path);
|
||||
|
||||
SCurrentRenderData m_RenderData;
|
||||
|
||||
GLint m_iCurrentOutputFb = 0;
|
||||
GLint m_iWLROutputFb = 0;
|
||||
|
||||
bool m_bReloadScreenShader = true; // at launch it can be set
|
||||
|
||||
CWindow* m_pCurrentWindow = nullptr; // hack to get the current rendered window
|
||||
|
||||
pixman_region32_t m_rOriginalDamageRegion; // used for storing the pre-expanded region
|
||||
@@ -126,9 +138,12 @@ private:
|
||||
|
||||
bool m_bFakeFrame = false;
|
||||
bool m_bEndFrame = false;
|
||||
bool m_bApplyFinalShader = false;
|
||||
|
||||
GLuint createProgram(const std::string&, const std::string&);
|
||||
GLuint compileShader(const GLuint&, std::string);
|
||||
CShader m_sFinalScreenShader;
|
||||
|
||||
GLuint createProgram(const std::string&, const std::string&, bool dynamic = false);
|
||||
GLuint compileShader(const GLuint&, std::string, bool dynamic = false);
|
||||
void createBGTextureForMonitor(CMonitor*);
|
||||
void initShaders();
|
||||
|
||||
@@ -139,6 +154,8 @@ private:
|
||||
void renderSplash(cairo_t *const, cairo_surface_t *const, double);
|
||||
|
||||
void preBlurForCurrentMonitor();
|
||||
|
||||
friend class CHyprRenderer;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CHyprOpenGLImpl> g_pHyprOpenGL;
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#include "Renderer.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "linux-dmabuf-unstable-v1-protocol.h"
|
||||
|
||||
void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
|
||||
const auto TEXTURE = wlr_surface_get_texture(surface);
|
||||
@@ -41,7 +42,7 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
|
||||
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true);
|
||||
} else {
|
||||
if (RDATA->blur)
|
||||
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, rounding);
|
||||
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, rounding, RDATA->blockBlurOptimization);
|
||||
else
|
||||
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true);
|
||||
}
|
||||
@@ -50,9 +51,10 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
|
||||
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true);
|
||||
}
|
||||
|
||||
wlr_surface_send_frame_done(surface, RDATA->when);
|
||||
|
||||
wlr_presentation_surface_sampled_on_output(g_pCompositor->m_sWLRPresentation, surface, RDATA->output);
|
||||
if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) {
|
||||
wlr_surface_send_frame_done(surface, RDATA->when);
|
||||
wlr_presentation_surface_sampled_on_output(g_pCompositor->m_sWLRPresentation, surface, RDATA->output);
|
||||
}
|
||||
|
||||
// reset the UV, we might've set it above
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
|
||||
@@ -87,7 +89,7 @@ bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow, CMonitor* pMonitor) {
|
||||
if (g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID) && pWindow->m_bIsFloating /* tiled windows can't be multi-ws */)
|
||||
return !pWindow->m_bIsFullscreen; // Do not draw fullscreen windows on other monitors
|
||||
|
||||
if (pMonitor->specialWorkspaceOpen && pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
|
||||
if (pMonitor->specialWorkspaceID && g_pCompositor->isWorkspaceSpecial(pWindow->m_iWorkspaceID))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@@ -110,7 +112,7 @@ bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow) {
|
||||
if (PWORKSPACE && PWORKSPACE->m_iMonitorID == m->ID && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated()))
|
||||
return true;
|
||||
|
||||
if (m->specialWorkspaceOpen && pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
|
||||
if (m->specialWorkspaceID && g_pCompositor->isWorkspaceSpecial(pWindow->m_iWorkspaceID))
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -182,11 +184,11 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(CMonitor* pMonitor, CWor
|
||||
}
|
||||
|
||||
// and then special windows
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (pMonitor->specialWorkspaceID) for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (!g_pCompositor->windowValidMapped(w.get()) && !w->m_bFadingOut)
|
||||
continue;
|
||||
|
||||
if (w->m_iWorkspaceID != SPECIAL_WORKSPACE_ID)
|
||||
if (w->m_iWorkspaceID != pMonitor->specialWorkspaceID)
|
||||
continue;
|
||||
|
||||
if (!shouldRenderWindow(w.get(), pMonitor))
|
||||
@@ -214,7 +216,7 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(CMonitor* pMonitor, CWor
|
||||
g_pHyprError->draw();
|
||||
}
|
||||
|
||||
void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec* time, bool decorate, eRenderPassMode mode) {
|
||||
void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec* time, bool decorate, eRenderPassMode mode, bool ignorePosition, bool ignoreAllGeometry) {
|
||||
if (pWindow->isHidden())
|
||||
return;
|
||||
|
||||
@@ -226,9 +228,17 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
|
||||
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
|
||||
const auto REALPOS = pWindow->m_vRealPosition.vec() + (pWindow->m_bPinned ? Vector2D{} : PWORKSPACE->m_vRenderOffset.vec());
|
||||
static const auto PNOFLOATINGBORDERS = &g_pConfigManager->getConfigValuePtr("general:no_border_on_floating")->intValue;
|
||||
static auto *const PNOFLOATINGBORDERS = &g_pConfigManager->getConfigValuePtr("general:no_border_on_floating")->intValue;
|
||||
|
||||
SRenderData renderdata = {pMonitor->output, time, REALPOS.x, REALPOS.y};
|
||||
if (ignorePosition) {
|
||||
renderdata.x = pMonitor->vecPosition.x;
|
||||
renderdata.y = pMonitor->vecPosition.y;
|
||||
}
|
||||
|
||||
if (ignoreAllGeometry)
|
||||
decorate = false;
|
||||
|
||||
renderdata.surface = g_pXWaylandManager->getWindowSurface(pWindow);
|
||||
renderdata.w = std::max(pWindow->m_vRealSize.vec().x, 5.0); // clamp the size to min 5,
|
||||
renderdata.h = std::max(pWindow->m_vRealSize.vec().y, 5.0); // otherwise we'll have issues later with invalid boxes
|
||||
@@ -236,10 +246,15 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
|
||||
renderdata.fadeAlpha = pWindow->m_fAlpha.fl() * (pWindow->m_bPinned ? 1.f : (PWORKSPACE->m_fAlpha.fl() / 255.f));
|
||||
renderdata.alpha = pWindow->m_fActiveInactiveAlpha.fl();
|
||||
renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && (pWindow->m_bIsFloating ? *PNOFLOATINGBORDERS == 0 : true) && (!pWindow->m_bIsFullscreen || PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL);
|
||||
renderdata.rounding = pWindow->m_sAdditionalConfigData.rounding;
|
||||
renderdata.blur = true; // if it shouldn't, it will be ignored later
|
||||
renderdata.rounding = ignoreAllGeometry ? 0 : pWindow->m_sAdditionalConfigData.rounding;
|
||||
renderdata.blur = !ignoreAllGeometry; // if it shouldn't, it will be ignored later
|
||||
renderdata.pWindow = pWindow;
|
||||
|
||||
if (ignoreAllGeometry) {
|
||||
renderdata.alpha = 1.f;
|
||||
renderdata.fadeAlpha = 255.f;
|
||||
}
|
||||
|
||||
// apply window special data
|
||||
if (pWindow->m_sSpecialRenderData.alphaInactive == -1)
|
||||
renderdata.alpha *= pWindow->m_sSpecialRenderData.alpha;
|
||||
@@ -254,33 +269,34 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
|
||||
|
||||
// clip box for animated offsets
|
||||
Vector2D offset;
|
||||
if (PWORKSPACE->m_vRenderOffset.vec().x != 0) {
|
||||
const auto PWSMON = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
|
||||
const auto PROGRESS = PWORKSPACE->m_vRenderOffset.vec().x / PWSMON->vecSize.x;
|
||||
const auto WINBB = pWindow->getFullWindowBoundingBox();
|
||||
if (!ignorePosition && pWindow->m_bIsFloating) {
|
||||
if (PWORKSPACE->m_vRenderOffset.vec().x != 0) {
|
||||
const auto PWSMON = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
|
||||
const auto PROGRESS = PWORKSPACE->m_vRenderOffset.vec().x / PWSMON->vecSize.x;
|
||||
const auto WINBB = pWindow->getFullWindowBoundingBox();
|
||||
|
||||
if (WINBB.x < PWSMON->vecPosition.x) {
|
||||
offset.x = (PWSMON->vecPosition.x - WINBB.x) * PROGRESS;
|
||||
} else if (WINBB.x > PWSMON->vecPosition.x + PWSMON->vecSize.x) {
|
||||
offset.x = (WINBB.x - PWSMON->vecPosition.x + PWSMON->vecSize.x) * PROGRESS;
|
||||
}
|
||||
} else if (PWORKSPACE->m_vRenderOffset.vec().y) {
|
||||
const auto PWSMON = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
|
||||
const auto PROGRESS = PWORKSPACE->m_vRenderOffset.vec().y / PWSMON->vecSize.y;
|
||||
const auto WINBB = pWindow->getFullWindowBoundingBox();
|
||||
if (WINBB.x < PWSMON->vecPosition.x) {
|
||||
offset.x = (PWSMON->vecPosition.x - WINBB.x) * PROGRESS;
|
||||
} else if (WINBB.x + WINBB.width > PWSMON->vecPosition.x + PWSMON->vecSize.x) {
|
||||
offset.x = (WINBB.x + WINBB.width - PWSMON->vecPosition.x - PWSMON->vecSize.x) * PROGRESS;
|
||||
}
|
||||
} else if (PWORKSPACE->m_vRenderOffset.vec().y) {
|
||||
const auto PWSMON = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
|
||||
const auto PROGRESS = PWORKSPACE->m_vRenderOffset.vec().y / PWSMON->vecSize.y;
|
||||
const auto WINBB = pWindow->getFullWindowBoundingBox();
|
||||
|
||||
if (WINBB.y < PWSMON->vecPosition.y) {
|
||||
offset.y = (PWSMON->vecPosition.y - WINBB.y) * PROGRESS;
|
||||
} else if (WINBB.y > PWSMON->vecPosition.y + PWSMON->vecSize.y) {
|
||||
offset.y = (WINBB.y - PWSMON->vecPosition.y + PWSMON->vecSize.y) * PROGRESS;
|
||||
if (WINBB.y < PWSMON->vecPosition.y) {
|
||||
offset.y = (PWSMON->vecPosition.y - WINBB.y) * PROGRESS;
|
||||
} else if (WINBB.y + WINBB.height > PWSMON->vecPosition.y + PWSMON->vecSize.y) {
|
||||
offset.y = (WINBB.y + WINBB.width - PWSMON->vecPosition.y - PWSMON->vecSize.y) * PROGRESS;
|
||||
}
|
||||
}
|
||||
|
||||
renderdata.x += offset.x;
|
||||
renderdata.y += offset.y;
|
||||
}
|
||||
|
||||
renderdata.x += offset.x;
|
||||
renderdata.y += offset.y;
|
||||
|
||||
|
||||
// render window decorations first, if not fullscreen full
|
||||
|
||||
if (mode == RENDER_PASS_ALL || mode == RENDER_PASS_MAIN) {
|
||||
if (!pWindow->m_bIsFullscreen || PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL) for (auto& wd : pWindow->m_dWindowDecorations)
|
||||
wd->draw(pMonitor, renderdata.alpha * renderdata.fadeAlpha / 255.f, offset);
|
||||
@@ -293,14 +309,20 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
|
||||
float rounding = renderdata.dontRound ? 0 : renderdata.rounding == -1 ? *PROUNDING : renderdata.rounding;
|
||||
rounding *= pMonitor->scale;
|
||||
|
||||
auto col = g_pHyprOpenGL->m_pCurrentWindow->m_cRealBorderColor.col();
|
||||
col.a *= renderdata.fadeAlpha * renderdata.alpha / 255.f;
|
||||
auto grad = g_pHyprOpenGL->m_pCurrentWindow->m_cRealBorderColor;
|
||||
const bool ANIMATED = g_pHyprOpenGL->m_pCurrentWindow->m_fBorderAnimationProgress.isBeingAnimated();
|
||||
float a1 = renderdata.fadeAlpha * renderdata.alpha / 255.f * (ANIMATED ? g_pHyprOpenGL->m_pCurrentWindow->m_fBorderAnimationProgress.fl() : 1.f);
|
||||
|
||||
wlr_box windowBox = {renderdata.x - pMonitor->vecPosition.x, renderdata.y - pMonitor->vecPosition.y, renderdata.w, renderdata.h};
|
||||
|
||||
scaleBox(&windowBox, pMonitor->scale);
|
||||
|
||||
g_pHyprOpenGL->renderBorder(&windowBox, col, rounding);
|
||||
g_pHyprOpenGL->renderBorder(&windowBox, grad, rounding, a1);
|
||||
|
||||
if (ANIMATED) {
|
||||
float a2 = renderdata.fadeAlpha * renderdata.alpha / 255.f * (1.f - g_pHyprOpenGL->m_pCurrentWindow->m_fBorderAnimationProgress.fl());
|
||||
g_pHyprOpenGL->renderBorder(&windowBox, g_pHyprOpenGL->m_pCurrentWindow->m_cRealBorderColorPrevious, rounding, a2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,6 +358,7 @@ void CHyprRenderer::renderLayer(SLayerSurface* pLayer, CMonitor* pMonitor, times
|
||||
renderdata.decorate = false;
|
||||
renderdata.w = pLayer->layerSurface->surface->current.width;
|
||||
renderdata.h = pLayer->layerSurface->surface->current.height;
|
||||
renderdata.blockBlurOptimization = pLayer->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM || pLayer->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND;
|
||||
wlr_surface_for_each_surface(pLayer->layerSurface->surface, renderSurface, &renderdata);
|
||||
|
||||
renderdata.squishOversized = false; // don't squish popups
|
||||
@@ -381,6 +404,8 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
|
||||
return;
|
||||
}
|
||||
|
||||
CWindow* lastWindow = nullptr;
|
||||
|
||||
// Non-floating main
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->isHidden() && !w->m_bIsMapped && !w->m_bFadingOut)
|
||||
@@ -389,16 +414,25 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
|
||||
if (w->m_bIsFloating)
|
||||
continue; // floating are in the second pass
|
||||
|
||||
if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
|
||||
if (g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID))
|
||||
continue; // special are in the third pass
|
||||
|
||||
if (!shouldRenderWindow(w.get(), PMONITOR))
|
||||
continue;
|
||||
|
||||
// render active window after all others of this pass
|
||||
if (w.get() == g_pCompositor->m_pLastWindow) {
|
||||
lastWindow = w.get();
|
||||
continue;
|
||||
}
|
||||
|
||||
// render the bad boy
|
||||
renderWindow(w.get(), PMONITOR, time, true, RENDER_PASS_MAIN);
|
||||
}
|
||||
|
||||
if (lastWindow)
|
||||
renderWindow(lastWindow, PMONITOR, time, true, RENDER_PASS_MAIN);
|
||||
|
||||
// Non-floating popup
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->isHidden() && !w->m_bIsMapped && !w->m_bFadingOut)
|
||||
@@ -407,7 +441,7 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
|
||||
if (w->m_bIsFloating)
|
||||
continue; // floating are in the second pass
|
||||
|
||||
if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
|
||||
if (g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID))
|
||||
continue; // special are in the third pass
|
||||
|
||||
if (!shouldRenderWindow(w.get(), PMONITOR))
|
||||
@@ -425,7 +459,7 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
|
||||
if (!w->m_bIsFloating)
|
||||
continue;
|
||||
|
||||
if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
|
||||
if (g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID))
|
||||
continue;
|
||||
|
||||
if (!shouldRenderWindow(w.get(), PMONITOR))
|
||||
@@ -440,7 +474,7 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
|
||||
if (w->isHidden() && !w->m_bIsMapped && !w->m_bFadingOut)
|
||||
continue;
|
||||
|
||||
if (w->m_iWorkspaceID != SPECIAL_WORKSPACE_ID)
|
||||
if (!g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID))
|
||||
continue;
|
||||
|
||||
if (!shouldRenderWindow(w.get(), PMONITOR))
|
||||
@@ -533,6 +567,154 @@ void CHyprRenderer::calculateUVForWindowSurface(CWindow* pWindow, wlr_surface* p
|
||||
}
|
||||
}
|
||||
|
||||
void countSubsurfacesIter(wlr_surface* pSurface, int x, int y, void* data) {
|
||||
*(int*)data += 1;
|
||||
}
|
||||
|
||||
bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) {
|
||||
if (!pMonitor->mirrors.empty())
|
||||
return false; // do not DS if this monitor is being mirrored. Will break the functionality.
|
||||
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pMonitor->activeWorkspace);
|
||||
|
||||
if (!PWORKSPACE || !PWORKSPACE->m_bHasFullscreenWindow || g_pInputManager->m_sDrag.drag || g_pCompositor->m_sSeat.exclusiveClient || pMonitor->specialWorkspaceID)
|
||||
return false;
|
||||
|
||||
const auto PCANDIDATE = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
|
||||
|
||||
if (!PCANDIDATE)
|
||||
return false; // ????
|
||||
|
||||
if (PCANDIDATE->m_fAlpha.fl() != 255.f || PCANDIDATE->m_fActiveInactiveAlpha.fl() != 1.f || PWORKSPACE->m_fAlpha.fl() != 255.f)
|
||||
return false;
|
||||
|
||||
if (PCANDIDATE->m_vRealSize.vec() != pMonitor->vecSize || PCANDIDATE->m_vRealPosition.vec() != pMonitor->vecPosition || PCANDIDATE->m_vRealPosition.isBeingAnimated() || PCANDIDATE->m_vRealSize.isBeingAnimated())
|
||||
return false;
|
||||
|
||||
if (!pMonitor->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY].empty())
|
||||
return false;
|
||||
|
||||
for (auto& topls : pMonitor->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
|
||||
if (topls->alpha.fl() != 0.f)
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if it did not open any subsurfaces or shit
|
||||
int surfaceCount = 0;
|
||||
if (PCANDIDATE->m_bIsX11) {
|
||||
surfaceCount = 1;
|
||||
|
||||
// check opaque
|
||||
if (PCANDIDATE->m_uSurface.xwayland->has_alpha)
|
||||
return false;
|
||||
} else {
|
||||
wlr_xdg_surface_for_each_surface(PCANDIDATE->m_uSurface.xdg, countSubsurfacesIter, &surfaceCount);
|
||||
wlr_xdg_surface_for_each_popup_surface(PCANDIDATE->m_uSurface.xdg, countSubsurfacesIter, &surfaceCount);
|
||||
|
||||
if (!PCANDIDATE->m_uSurface.xdg->surface->opaque)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (surfaceCount != 1)
|
||||
return false;
|
||||
|
||||
const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE);
|
||||
|
||||
if (!PSURFACE || PSURFACE->current.scale != pMonitor->output->scale || PSURFACE->current.transform != pMonitor->output->transform)
|
||||
return false;
|
||||
|
||||
// finally, we should be GTG.
|
||||
wlr_output_attach_buffer(pMonitor->output, &PSURFACE->buffer->base);
|
||||
|
||||
if (!wlr_output_test(pMonitor->output)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
wlr_surface_send_frame_done(PSURFACE, &now);
|
||||
wlr_presentation_surface_sampled_on_output(g_pCompositor->m_sWLRPresentation, PSURFACE, pMonitor->output);
|
||||
|
||||
if (wlr_output_commit(pMonitor->output)) {
|
||||
if (!m_pLastScanout) {
|
||||
m_pLastScanout = PCANDIDATE;
|
||||
Debug::log(LOG, "Entered a direct scanout to %x: \"%s\"", PCANDIDATE, PCANDIDATE->m_szTitle.c_str());
|
||||
}
|
||||
} else {
|
||||
m_pLastScanout = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CHyprRenderer::setWindowScanoutMode(CWindow* pWindow) {
|
||||
if (!g_pCompositor->m_sWLRLinuxDMABuf)
|
||||
return;
|
||||
|
||||
if (!pWindow->m_bIsFullscreen) {
|
||||
wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, g_pXWaylandManager->getWindowSurface(pWindow), nullptr);
|
||||
Debug::log(LOG, "Scanout mode OFF set for %x", pWindow);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto RENDERERDRMFD = wlr_renderer_get_drm_fd(g_pCompositor->m_sWLRRenderer);
|
||||
const auto BACKENDDRMFD = wlr_backend_get_drm_fd(g_pCompositor->m_sWLRBackend);
|
||||
|
||||
if (RENDERERDRMFD < 0 || BACKENDDRMFD < 0)
|
||||
return;
|
||||
|
||||
auto deviceIDFromFD = [](int fd, unsigned long* deviceID) -> bool {
|
||||
struct stat stat;
|
||||
if (fstat(fd, &stat) != 0) {
|
||||
return false;
|
||||
}
|
||||
*deviceID = stat.st_rdev;
|
||||
return true;
|
||||
};
|
||||
|
||||
unsigned long rendererDevice, scanoutDevice;
|
||||
if (!deviceIDFromFD(RENDERERDRMFD, &rendererDevice) || !deviceIDFromFD(BACKENDDRMFD, &scanoutDevice))
|
||||
return;
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
|
||||
|
||||
const auto POUTPUTFORMATS = wlr_output_get_primary_formats(PMONITOR->output, WLR_BUFFER_CAP_DMABUF);
|
||||
if (!POUTPUTFORMATS)
|
||||
return;
|
||||
|
||||
const auto PRENDERERFORMATS = wlr_renderer_get_dmabuf_texture_formats(g_pCompositor->m_sWLRRenderer);
|
||||
wlr_drm_format_set scanoutFormats = { 0 };
|
||||
|
||||
if (!wlr_drm_format_set_intersect(&scanoutFormats, POUTPUTFORMATS, PRENDERERFORMATS))
|
||||
return;
|
||||
|
||||
const wlr_linux_dmabuf_feedback_v1_tranche TRANCHES[] = {
|
||||
{
|
||||
.target_device = scanoutDevice,
|
||||
.flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT,
|
||||
.formats = &scanoutFormats
|
||||
}, {
|
||||
.target_device = rendererDevice,
|
||||
.formats = PRENDERERFORMATS
|
||||
}
|
||||
};
|
||||
|
||||
const wlr_linux_dmabuf_feedback_v1 FEEDBACK = {
|
||||
.main_device = rendererDevice,
|
||||
.tranches_len = sizeof(TRANCHES) / sizeof(TRANCHES[0]),
|
||||
.tranches = TRANCHES
|
||||
};
|
||||
|
||||
if (!wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, g_pXWaylandManager->getWindowSurface(pWindow), &FEEDBACK)) {
|
||||
Debug::log(ERR, "Error in scanout mode setting: wlr_linux_dmabuf_v1_set_surface_feedback returned false.");
|
||||
}
|
||||
|
||||
wlr_drm_format_set_finish(&scanoutFormats);
|
||||
|
||||
Debug::log(LOG, "Scanout mode ON set for %x", pWindow);
|
||||
}
|
||||
|
||||
void CHyprRenderer::outputMgrApplyTest(wlr_output_configuration_v1* config, bool test) {
|
||||
wlr_output_configuration_head_v1* head;
|
||||
bool noError = true;
|
||||
@@ -560,9 +742,17 @@ void CHyprRenderer::outputMgrApplyTest(wlr_output_configuration_v1* config, bool
|
||||
|
||||
commandForCfg += std::to_string(head->state.x) + "x" + std::to_string(head->state.y) + "," + std::to_string(head->state.scale);
|
||||
|
||||
if (!test)
|
||||
if (!test) {
|
||||
g_pConfigManager->parseKeyword("monitor", commandForCfg, true);
|
||||
|
||||
std::string transformStr = std::string(OUTPUT->name) + ",transform," + std::to_string((int)OUTPUT->transform);
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromName(OUTPUT->name);
|
||||
|
||||
if (!PMONITOR || OUTPUT->transform != PMONITOR->transform)
|
||||
g_pConfigManager->parseKeyword("monitor", transformStr);
|
||||
}
|
||||
|
||||
noError = wlr_output_test(OUTPUT);
|
||||
|
||||
if (!noError)
|
||||
@@ -846,7 +1036,7 @@ void CHyprRenderer::damageMonitor(CMonitor* pMonitor) {
|
||||
if (g_pCompositor->m_bUnsafeState || pMonitor->isMirror())
|
||||
return;
|
||||
|
||||
wlr_box damageBox = {0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y};
|
||||
wlr_box damageBox = { 0, 0, INT16_MAX, INT16_MAX };
|
||||
pMonitor->addDamage(&damageBox);
|
||||
|
||||
static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
|
||||
@@ -960,6 +1150,9 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
wlr_output_set_scale(pMonitor->output, pMonitorRule->scale);
|
||||
pMonitor->scale = pMonitorRule->scale;
|
||||
|
||||
wlr_output_set_transform(pMonitor->output, pMonitorRule->transform);
|
||||
pMonitor->transform = pMonitorRule->transform;
|
||||
|
||||
// loop over modes and choose an appropriate one.
|
||||
if (pMonitorRule->resolution != Vector2D() && pMonitorRule->resolution != Vector2D(-1,-1) && pMonitorRule->resolution != Vector2D(-1,-2)) {
|
||||
if (!wl_list_empty(&pMonitor->output->modes)) {
|
||||
@@ -1156,9 +1349,6 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
|
||||
pMonitor->vrrActive = pMonitor->output->pending.adaptive_sync_enabled; // disabled here, will be tested in CConfigManager::ensureVRR()
|
||||
|
||||
wlr_output_set_transform(pMonitor->output, pMonitorRule->transform);
|
||||
pMonitor->transform = pMonitorRule->transform;
|
||||
|
||||
pMonitor->vecPixelSize = pMonitor->vecSize;
|
||||
|
||||
if (pMonitorRule->enable10bit) {
|
||||
@@ -1188,7 +1378,6 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
|
||||
if (!wlr_output_commit(pMonitor->output)) {
|
||||
Debug::log(ERR, "Couldn't commit output named %s", pMonitor->output->name);
|
||||
return true;
|
||||
}
|
||||
|
||||
int x, y;
|
||||
@@ -1196,6 +1385,13 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
pMonitor->vecSize = (Vector2D(x, y) / pMonitor->scale).floor();
|
||||
pMonitor->vecTransformedSize = Vector2D(x,y);
|
||||
|
||||
if (pMonitor->createdByUser) {
|
||||
wlr_box transformedBox = { 0, 0, (int)pMonitor->vecTransformedSize.x, (int)pMonitor->vecTransformedSize.y };
|
||||
wlr_box_transform(&transformedBox, &transformedBox, wlr_output_transform_invert(pMonitor->output->transform), (int)pMonitor->vecTransformedSize.x, (int)pMonitor->vecTransformedSize.y);
|
||||
|
||||
pMonitor->vecPixelSize = Vector2D(transformedBox.width, transformedBox.height);
|
||||
}
|
||||
|
||||
if (pMonitorRule->offset == Vector2D(-1, -1) && pMonitor->vecPosition == Vector2D(-1, -1)) {
|
||||
// let's find manually a sensible position for it, to the right.
|
||||
Vector2D finalPos;
|
||||
@@ -1214,14 +1410,11 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
pMonitor->vecPosition = pMonitorRule->offset;
|
||||
}
|
||||
|
||||
wlr_output_enable(pMonitor->output, true);
|
||||
|
||||
// update renderer (here because it will call rollback, so we cannot do this before committing)
|
||||
g_pHyprOpenGL->destroyMonitorResources(pMonitor);
|
||||
|
||||
// updato wlroots
|
||||
wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, pMonitor->output, (int)pMonitor->vecPosition.x, (int)pMonitor->vecPosition.y);
|
||||
Events::listener_change(nullptr, nullptr);
|
||||
|
||||
// updato us
|
||||
arrangeLayersForMonitor(pMonitor->ID);
|
||||
|
@@ -23,6 +23,8 @@ enum eRenderPassMode {
|
||||
RENDER_PASS_POPUP
|
||||
};
|
||||
|
||||
class CToplevelExportProtocolManager;
|
||||
|
||||
class CHyprRenderer {
|
||||
public:
|
||||
|
||||
@@ -44,13 +46,18 @@ public:
|
||||
void calculateUVForWindowSurface(CWindow*, wlr_surface*, bool main = false);
|
||||
|
||||
bool m_bWindowRequestedCursorHide = false;
|
||||
bool m_bBlockSurfaceFeedback = false;
|
||||
CWindow* m_pLastScanout = nullptr;
|
||||
|
||||
DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&);
|
||||
|
||||
bool attemptDirectScanout(CMonitor*);
|
||||
void setWindowScanoutMode(CWindow*);
|
||||
|
||||
private:
|
||||
void arrangeLayerArray(CMonitor*, const std::vector<std::unique_ptr<SLayerSurface>>&, bool, wlr_box*);
|
||||
void renderWorkspaceWithFullscreenWindow(CMonitor*, CWorkspace*, timespec*);
|
||||
void renderWindow(CWindow*, CMonitor*, timespec*, bool, eRenderPassMode);
|
||||
void renderWindow(CWindow*, CMonitor*, timespec*, bool, eRenderPassMode, bool ignorePosition = false, bool ignoreAllGeometry = false);
|
||||
void renderLayer(SLayerSurface*, CMonitor*, timespec*);
|
||||
void renderDragIcon(CMonitor*, timespec*);
|
||||
void renderIMEPopup(SIMEPopup*, CMonitor*, timespec*);
|
||||
@@ -59,6 +66,7 @@ private:
|
||||
|
||||
|
||||
friend class CHyprOpenGLImpl;
|
||||
friend class CToplevelExportProtocolManager;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CHyprRenderer> g_pHyprRenderer;
|
||||
|
@@ -14,7 +14,11 @@ GLint CShader::getUniformLocation(const std::string& unif) {
|
||||
|
||||
CShader::~CShader() {
|
||||
// destroy shader
|
||||
if (program) {
|
||||
glDeleteProgram(program);
|
||||
}
|
||||
destroy();
|
||||
}
|
||||
|
||||
void CShader::destroy() {
|
||||
glDeleteProgram(program);
|
||||
|
||||
program = 0;
|
||||
}
|
@@ -19,6 +19,7 @@ public:
|
||||
GLint topLeft;
|
||||
GLint bottomRight;
|
||||
GLint fullSize;
|
||||
GLint fullSizeUntransformed;
|
||||
GLint radius;
|
||||
GLint primitiveMultisample;
|
||||
|
||||
@@ -32,8 +33,14 @@ public:
|
||||
GLint applyTint;
|
||||
GLint tint;
|
||||
|
||||
GLint gradient;
|
||||
GLint gradientLength;
|
||||
GLint angle;
|
||||
|
||||
GLint getUniformLocation(const std::string&);
|
||||
|
||||
void destroy();
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, GLint> m_muUniforms;
|
||||
};
|
@@ -66,6 +66,7 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a, const Vector2D
|
||||
static auto *const PSHADOWSIZE = &g_pConfigManager->getConfigValuePtr("decoration:shadow_range")->intValue;
|
||||
static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
|
||||
static auto *const PSHADOWIGNOREWINDOW = &g_pConfigManager->getConfigValuePtr("decoration:shadow_ignore_window")->intValue;
|
||||
static auto *const PSHADOWSCALE = &g_pConfigManager->getConfigValuePtr("decoration:shadow_scale")->floatValue;
|
||||
static auto *const PSHADOWOFFSET = &g_pConfigManager->getConfigValuePtr("decoration:shadow_offset")->vecValue;
|
||||
|
||||
if (*PSHADOWS != 1)
|
||||
@@ -73,22 +74,48 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a, const Vector2D
|
||||
|
||||
const auto ROUNDING = !m_pWindow->m_sSpecialRenderData.rounding ? 0 : (m_pWindow->m_sAdditionalConfigData.rounding == -1 ? *PROUNDING : m_pWindow->m_sAdditionalConfigData.rounding);
|
||||
|
||||
// update the extents
|
||||
m_seExtents = {{*PSHADOWSIZE + 2 - PSHADOWOFFSET->x, *PSHADOWSIZE + 2 - PSHADOWOFFSET->y}, {*PSHADOWSIZE + 2 + PSHADOWOFFSET->x, *PSHADOWSIZE + 2 + PSHADOWOFFSET->y}};
|
||||
|
||||
// draw the shadow
|
||||
wlr_box fullBox = {m_vLastWindowPos.x - m_seExtents.topLeft.x + 2, m_vLastWindowPos.y - m_seExtents.topLeft.y + 2, m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x - 4, m_vLastWindowSize.y + m_seExtents.topLeft.y + m_seExtents.bottomRight.y - 4};
|
||||
wlr_box fullBox = { m_vLastWindowPos.x - *PSHADOWSIZE, m_vLastWindowPos.y - *PSHADOWSIZE,
|
||||
m_vLastWindowSize.x + 2.0 * *PSHADOWSIZE, m_vLastWindowSize.y + 2.0 * *PSHADOWSIZE };
|
||||
|
||||
fullBox.x -= pMonitor->vecPosition.x;
|
||||
fullBox.y -= pMonitor->vecPosition.y;
|
||||
|
||||
const float SHADOWSCALE = std::clamp(*PSHADOWSCALE, 0.f, 1.f);
|
||||
|
||||
// scale the box in relation to the center of the box
|
||||
const Vector2D NEWSIZE = Vector2D { fullBox.width, fullBox.height } * SHADOWSCALE;
|
||||
fullBox.width = NEWSIZE.x;
|
||||
fullBox.height = NEWSIZE.y;
|
||||
|
||||
if (PSHADOWOFFSET->x < 0) {
|
||||
fullBox.x += PSHADOWOFFSET->x;
|
||||
} else if (PSHADOWOFFSET->x > 0) {
|
||||
fullBox.x = m_vLastWindowPos.x + m_vLastWindowSize.x - fullBox.width + (SHADOWSCALE * *PSHADOWSIZE) + PSHADOWOFFSET->x - pMonitor->vecPosition.x;
|
||||
} else {
|
||||
fullBox.x += ((m_vLastWindowSize.x + 2.0 * *PSHADOWSIZE) - NEWSIZE.x) / 2.0;
|
||||
}
|
||||
|
||||
if (PSHADOWOFFSET->y < 0) {
|
||||
fullBox.y += PSHADOWOFFSET->y;
|
||||
} else if (PSHADOWOFFSET->y > 0) {
|
||||
fullBox.y = m_vLastWindowPos.y + m_vLastWindowSize.y - fullBox.height + (SHADOWSCALE * *PSHADOWSIZE) + PSHADOWOFFSET->y - pMonitor->vecPosition.y;
|
||||
} else {
|
||||
fullBox.y += ((m_vLastWindowSize.y + 2.0 * *PSHADOWSIZE) - NEWSIZE.y) / 2.0;
|
||||
}
|
||||
|
||||
m_seExtents = { { m_vLastWindowPos.x - fullBox.x - pMonitor->vecPosition.x + 2,
|
||||
m_vLastWindowPos.y - fullBox.y - pMonitor->vecPosition.y + 2},
|
||||
{ fullBox.x + fullBox.width + pMonitor->vecPosition.x - m_vLastWindowPos.x - m_vLastWindowSize.x + 2,
|
||||
fullBox.y + fullBox.height + pMonitor->vecPosition.y - m_vLastWindowPos.y - m_vLastWindowSize.y + 2} };
|
||||
|
||||
fullBox.x += offset.x;
|
||||
fullBox.y += offset.y;
|
||||
|
||||
if (fullBox.width < 1 || fullBox.height < 1)
|
||||
return; // don't draw invisible shadows
|
||||
return; // don't draw invisible shadows
|
||||
|
||||
g_pHyprOpenGL->scissor((wlr_box *)nullptr);
|
||||
g_pHyprOpenGL->scissor((wlr_box*)nullptr);
|
||||
|
||||
if (*PSHADOWIGNOREWINDOW) {
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
|
@@ -9,82 +9,111 @@ varying vec4 v_color;
|
||||
varying vec2 v_texcoord;
|
||||
|
||||
uniform vec2 topLeft;
|
||||
uniform vec2 bottomRight;
|
||||
uniform vec2 fullSize;
|
||||
uniform vec2 fullSizeUntransformed;
|
||||
uniform float radius;
|
||||
uniform float thick;
|
||||
uniform int primitiveMultisample;
|
||||
|
||||
float getOpacityForPixAndCorner(vec2 pix, vec2 corner) {
|
||||
uniform vec4 gradient[10];
|
||||
uniform int gradientLength;
|
||||
uniform float angle;
|
||||
uniform float alpha;
|
||||
|
||||
if (primitiveMultisample == 0) {
|
||||
float dis = distance(pix + vec2(0.5, 0.5), corner);
|
||||
return dis < radius && dis > radius - thick ? 1.0 : 0.0;
|
||||
vec4 getColorForCoord(vec2 normalizedCoord) {
|
||||
if (gradientLength < 2)
|
||||
return gradient[0];
|
||||
|
||||
float finalAng = 0.0;
|
||||
|
||||
if (angle > 4.71 /* 270 deg */) {
|
||||
normalizedCoord[1] = 1.0 - normalizedCoord[1];
|
||||
finalAng = 6.28 - angle;
|
||||
} else if (angle > 3.14 /* 180 deg */) {
|
||||
normalizedCoord[0] = 1.0 - normalizedCoord[0];
|
||||
normalizedCoord[1] = 1.0 - normalizedCoord[1];
|
||||
finalAng = angle - 3.14;
|
||||
} else if (angle > 1.57 /* 90 deg */) {
|
||||
normalizedCoord[0] = 1.0 - normalizedCoord[0];
|
||||
finalAng = 3.14 - angle;
|
||||
} else {
|
||||
finalAng = angle;
|
||||
}
|
||||
|
||||
float distance1 = distance(pix + vec2(0.25, 0.25), corner);
|
||||
float distance2 = distance(pix + vec2(0.75, 0.25), corner);
|
||||
float distance3 = distance(pix + vec2(0.25, 0.75), corner);
|
||||
float distance4 = distance(pix + vec2(0.75, 0.75), corner);
|
||||
float sine = sin(finalAng);
|
||||
|
||||
float v1 = distance1 < radius && distance1 > radius - thick ? 1.0 : 0.0;
|
||||
float v2 = distance2 < radius && distance2 > radius - thick ? 1.0 : 0.0;
|
||||
float v3 = distance3 < radius && distance3 > radius - thick ? 1.0 : 0.0;
|
||||
float v4 = distance4 < radius && distance4 > radius - thick ? 1.0 : 0.0;
|
||||
float progress = (normalizedCoord[1] * sine + normalizedCoord[0] * (1.0 - sine)) * float(gradientLength - 1);
|
||||
int bottom = int(floor(progress));
|
||||
int top = bottom + 1;
|
||||
|
||||
return (v1 + v2 + v3 + v4) / 4.0;
|
||||
return gradient[top] * (progress - float(bottom)) + gradient[bottom] * (float(top) - progress);
|
||||
}
|
||||
|
||||
void main() {
|
||||
|
||||
vec2 pixCoord = fullSize * v_texcoord;
|
||||
highp vec2 pixCoord = vec2(gl_FragCoord);
|
||||
highp vec2 originalPixCoord = v_texcoord;
|
||||
originalPixCoord *= fullSizeUntransformed;
|
||||
|
||||
vec4 pixColor = v_color;
|
||||
vec4 pixColor = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
|
||||
bool done = false;
|
||||
|
||||
// check for edges
|
||||
if (pixCoord[0] < topLeft[0]) {
|
||||
if (pixCoord[1] < topLeft[1]) {
|
||||
// top left
|
||||
pixColor[3] = pixColor[3] * getOpacityForPixAndCorner(pixCoord, topLeft + vec2(1,1));
|
||||
done = true;
|
||||
} else if (pixCoord[1] > bottomRight[1]) {
|
||||
// bottom left
|
||||
pixColor[3] = pixColor[3] * getOpacityForPixAndCorner(pixCoord, vec2(topLeft[0] + 1.0, bottomRight[1]));
|
||||
done = true;
|
||||
}
|
||||
} else if (pixCoord[0] > bottomRight[0]) {
|
||||
if (pixCoord[1] < topLeft[1]) {
|
||||
// top right
|
||||
pixColor[3] = pixColor[3] * getOpacityForPixAndCorner(pixCoord, vec2(bottomRight[0], topLeft[1] + 1.0));
|
||||
done = true;
|
||||
} else if (pixCoord[1] > bottomRight[1]) {
|
||||
// bottom right
|
||||
pixColor[3] = pixColor[3] * getOpacityForPixAndCorner(pixCoord, bottomRight);
|
||||
done = true;
|
||||
}
|
||||
pixCoord -= topLeft + fullSize * 0.5;
|
||||
pixCoord *= vec2(lessThan(pixCoord, vec2(0.0))) * -2.0 + 1.0;
|
||||
pixCoord -= fullSize * 0.5 - radius;
|
||||
|
||||
if (min(pixCoord.x, pixCoord.y) > 0.0 && radius > 0.0) {
|
||||
|
||||
float dist = length(pixCoord);
|
||||
|
||||
if (dist > radius + 1.0 || dist < radius - thick - 1.0)
|
||||
discard;
|
||||
|
||||
if (primitiveMultisample == 1 && (dist > radius - 1.0 || dist < radius - thick + 1.0)) {
|
||||
float distances = 0.0;
|
||||
float len = length(pixCoord + vec2(0.25, 0.25));
|
||||
distances += float(len < radius && len > radius - thick);
|
||||
len = length(pixCoord + vec2(0.75, 0.25));
|
||||
distances += float(len < radius && len > radius - thick);
|
||||
len = length(pixCoord + vec2(0.25, 0.75));
|
||||
distances += float(len < radius && len > radius - thick);
|
||||
len = length(pixCoord + vec2(0.75, 0.75));
|
||||
distances += float(len < radius && len > radius - thick);
|
||||
|
||||
if (distances == 0.0)
|
||||
discard;
|
||||
|
||||
distances /= 4.0;
|
||||
|
||||
pixColor[3] *= distances;
|
||||
} else if (dist > radius || dist < radius - thick)
|
||||
discard;
|
||||
|
||||
done = true;
|
||||
}
|
||||
|
||||
// now check for other shit
|
||||
if (!done) {
|
||||
// distance to all straight bb borders
|
||||
float distanceT = pixCoord[1];
|
||||
float distanceB = fullSize[1] - pixCoord[1];
|
||||
float distanceL = pixCoord[0];
|
||||
float distanceR = fullSize[0] - pixCoord[0];
|
||||
float distanceT = originalPixCoord[1];
|
||||
float distanceB = fullSizeUntransformed[1] - originalPixCoord[1];
|
||||
float distanceL = originalPixCoord[0];
|
||||
float distanceR = fullSizeUntransformed[0] - originalPixCoord[0];
|
||||
|
||||
// get the smallest
|
||||
float smallest = min(min(distanceT, distanceB), min(distanceL, distanceR));
|
||||
|
||||
if (smallest > thick) {
|
||||
discard; return;
|
||||
}
|
||||
if (smallest > thick)
|
||||
discard;
|
||||
}
|
||||
|
||||
if (pixColor[3] == 0.0) {
|
||||
discard; return;
|
||||
}
|
||||
if (pixColor[3] == 0.0)
|
||||
discard;
|
||||
|
||||
float pixColor3 = pixColor[3];
|
||||
pixColor = getColorForCoord(v_texcoord);
|
||||
pixColor[3] *= alpha * pixColor3;
|
||||
|
||||
gl_FragColor = pixColor;
|
||||
}
|
||||
|
@@ -13,24 +13,24 @@ inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVar
|
||||
|
||||
if (pixCoord.x + pixCoord.y > radius) {
|
||||
|
||||
float dist = length(pixCoord);
|
||||
float dist = length(pixCoord);
|
||||
|
||||
if (dist > radius)
|
||||
discard;
|
||||
if (dist > radius)
|
||||
discard;
|
||||
|
||||
if (primitiveMultisample == 1 && dist > radius - 1.0) {
|
||||
float distances = 0.0;
|
||||
distances += float(length(pixCoord + vec2(0.25, 0.25)) < radius);
|
||||
distances += float(length(pixCoord + vec2(0.75, 0.25)) < radius);
|
||||
distances += float(length(pixCoord + vec2(0.25, 0.75)) < radius);
|
||||
distances += float(length(pixCoord + vec2(0.75, 0.75)) < radius);
|
||||
if (primitiveMultisample == 1 && dist > radius - 1.0) {
|
||||
float distances = 0.0;
|
||||
distances += float(length(pixCoord + vec2(0.25, 0.25)) < radius);
|
||||
distances += float(length(pixCoord + vec2(0.75, 0.25)) < radius);
|
||||
distances += float(length(pixCoord + vec2(0.25, 0.75)) < radius);
|
||||
distances += float(length(pixCoord + vec2(0.75, 0.75)) < radius);
|
||||
|
||||
if (distances == 0.0)
|
||||
discard;
|
||||
if (distances == 0.0)
|
||||
discard;
|
||||
|
||||
distances /= 4.0;
|
||||
distances /= 4.0;
|
||||
|
||||
)#" + colorVarName + R"#( = )#" + colorVarName + R"#( * distances;
|
||||
)#" + colorVarName + R"#( = )#" + colorVarName + R"#( * distances;
|
||||
}
|
||||
|
||||
}
|
||||
|
1
subprojects/hyprland-protocols
Submodule
1
subprojects/hyprland-protocols
Submodule
Submodule subprojects/hyprland-protocols added at 0dcff94fc1
Submodule subprojects/wlroots updated: c2d2773df5...86fc2199f8
Reference in New Issue
Block a user