Compare commits

..

128 Commits

Author SHA1 Message Date
Vaxry
d74607e414 props: bump ver to 0.33.1 2023-12-06 16:47:26 +00:00
Vaxry
c4bd91ec8a makefile: only require version.h before installheaders 2023-12-06 15:31:23 +00:00
Vaxry
03c6f4506a internal: various improvements to avoid crashes on exit 2023-12-06 14:46:29 +00:00
swwind
13b4c6de86 input: don't send mouse events on touch (#4071) 2023-12-06 14:30:40 +00:00
Tungsten842
8bd86cf37e hyprctl: order commands alphabetically (#4061) 2023-12-05 23:39:57 +00:00
dranull
cfd94c5b30 input: Stop propagating axis events after valid binds (#4059) 2023-12-05 21:16:26 +00:00
Vaxry
ab66fa430e screencopy: fix glReadPixels offset
fixes #4042
2023-12-05 20:04:53 +00:00
Vaxry
37d7a8c64d framebuffer: ignore addStencil on legacyRenderer
ref #4044
2023-12-05 15:41:17 +00:00
Vaxry
da863459c4 screencopy: fix legacyrenderer builds
fixes #4044
2023-12-05 14:59:12 +00:00
Vaxry
83248b6936 toplevelexport: fix getPreferredReadFormat param in captureToplevel
fixes #4043
2023-12-05 14:43:54 +00:00
Vaxry
3bb9c7c5cf props: bump ver to 0.33.0 2023-12-05 00:52:16 +00:00
Vaxry
2d04cb1cc6 input: make fallback layout us 2023-12-05 00:48:39 +00:00
Vaxry
c6804ccaab opengl: fixup blur dirty repaint conditions with solitary
fixes #4025
2023-12-05 00:43:09 +00:00
Glizda
aa46aaed04 config: Add variables to default config (#4032)
* update default config

* Fix inconsistency in variable naming

* continuation of last commit

* edited example/hyprland.conf for parity

* fix  issue

* deleted unwanted newline
2023-12-04 18:47:58 +00:00
Vaxry
68783d904d screencopy: use buffer format for glReadPixels
fixes #4029
2023-12-04 03:52:54 +00:00
Vaxry
5d100bdcbb opengl: clear layer fade fbs in ~dtor 2023-12-04 02:08:34 +00:00
Vaxry
45d3fbb8d8 opengl: free window framebuffers in ~dtor
ref #4036
2023-12-04 01:44:16 +00:00
dranull
9a9528d093 config: Minor --config improvements, fixes (#4034)
* Follow symlink, only file, absolute path for -c

* Create config file only for default paths

* Skip non-file source= glob results

* Check for absolute path on XDG_CONFIG_HOME

As per spec, all non-absolute paths should be ignored.
https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
2023-12-04 01:35:24 +00:00
Vaxry
e496b0f250 screencopy: fix detecting gl shm formats
ref #4029
2023-12-03 22:04:07 +00:00
Vaxry
dc2082b00a screencopy: fix transformed on shm 2023-12-03 19:06:51 +00:00
dranull
59cb0e20de input: Handle fullscreen windows in vectorToWindowIdeal (#4021) 2023-12-03 12:53:12 +00:00
Vaxry
80b9b21f9f opengl: fix nvidia read formats
fixes #4023
2023-12-02 14:51:45 +00:00
thejch
758cf90ea1 workspacerules: Add workspace rule for master layout orientation (#3964)
* add workspace rule for master layout orientation

* change rule format

* edit rule name

* use map for layoutopts

* use std::any instead of string
2023-12-02 14:42:49 +00:00
Vaxry
6e8b9ef7d8 opengl: fix swapped rgb drm formats 2023-12-01 17:23:50 +00:00
Vaxry
9c09f2a847 screencopy: fix shm exports with 10-bit
fixes #4019
2023-12-01 17:20:56 +00:00
Wren Baxter
8440a30231 input: fix overzealous mouse capture on resize_on_border (#4010)
fixes #2456
2023-12-01 01:12:08 +00:00
Vaxry
ab40f240c3 screencopy: use drmFormat instead of wlr funcs
ref #4014
2023-12-01 00:23:48 +00:00
vaxerski
b394c1695c [gha] Nix: update wlroots 2023-11-30 18:53:34 +00:00
Vaxry
0a4c4da5f0 deps: update wlroots 2023-11-30 18:52:49 +00:00
Vaxry
b2f3623131 events: add keyPress and mouseAxis
fixes #4011 fixes #4008
2023-11-30 18:45:12 +00:00
François Conzelmann
5513eed64d managers: fix debug log using printf format (#4007)
Some debug messages where using printf format style to print variable
content instead of std::format format.
2023-11-30 15:20:08 +00:00
André Silva
29970228c5 nix: override libdrm to use newer version (#4003) 2023-11-30 11:40:14 +00:00
vaxerski
12ec549a18 screencopy: fix shm sharing if introspection required 2023-11-30 11:07:17 +00:00
Vaxry
9f2027be4b opengl: don't make a mirror buffer on fakeFrame 2023-11-30 10:15:02 +00:00
Vaxry
b9937484f4 screencopy: fix broken shm copying
fixes #4001
2023-11-30 10:14:35 +00:00
Vaxry
776f944619 opengl: fix missed makeEGLCurrent
fixes #3998
2023-11-30 02:19:27 +00:00
François Conzelmann
1fc1e4e9cb monitor: remove comma from monitor description (#3996)
this allows for monitor specific rules to work on monitor with comma on
their description

fixes #2457
2023-11-30 01:48:10 +00:00
vaxerski
e1258707ad [gha] Nix: update wlroots 2023-11-30 01:19:51 +00:00
Vaxry
d2c3b23ace deps: update wlroots 2023-11-30 01:18:55 +00:00
Vaxry
b80c72c7dd groupbar: fix crash in renderGradientTo
fixes #3985
2023-11-29 13:36:37 +00:00
Vaxry
3caaa483d4 configmgr: fix parsing of touchdevice groups
fixes #3992
2023-11-29 03:39:45 +00:00
Vaxry
e2f18f8c7f groupbar: more safety around gradient textures 2023-11-28 19:03:02 +00:00
Vaxry
99ca26d4eb hooksystem: fix missed log include 2023-11-26 18:33:53 +00:00
Vaxry
e416ab740d config: log info about logs before loading vars 2023-11-26 18:02:33 +00:00
MightyPlaza
7a0a5666d5 groupbar: allow reload and fix locked groupbar gradient (#3546)
modified:   src/config/ConfigManager.cpp
modified:   src/render/decorations/CHyprGroupBarDecoration.cpp
modified:   src/render/decorations/CHyprGroupBarDecoration.hpp
2023-11-26 17:59:49 +00:00
Vaxry
1778fb77e2 functionhooks: throw an exception on unsupported %rip usage
ref #2479, now will actually tell you what's wrong instead of crashing
2023-11-26 17:53:51 +00:00
Vaxry
adeb20ea11 opengl: tiled special require introspection 2023-11-26 16:42:04 +00:00
Vaxry
68e57b7ee3 renderer: proper full occlusion checks for back layer 2023-11-26 15:24:24 +00:00
Vaxry
408d96668d renderer: use occlusion checks for buffer clear 2023-11-26 15:06:42 +00:00
Vaxry
75e5799310 layer-shell: simulate mouse movement on unmap 2023-11-26 14:54:34 +00:00
Vaxry
9e2b939024 surface: avoid infinite pointer image resets
fixes #3729, should also #3968
2023-11-26 14:53:22 +00:00
Vaxry
cd96ceecc5 build: remove nv patches (#3957) 2023-11-26 02:58:57 +00:00
Vaxry
ad3f688648 opengl: check for introspection on special_blur 2023-11-25 19:44:34 +00:00
vaxerski
98c7ba4782 [gha] Nix: update wlroots 2023-11-25 19:25:44 +00:00
Vaxry
a5f64b48ca deps: downgrade wlroots to fix crashes 2023-11-25 19:24:59 +00:00
Vaxry
b281d8647a screencopy: use new isNvidia() for format 2023-11-25 17:56:38 +00:00
Vaxry
15b282ee0c opengl: fix window introspection check 2023-11-25 17:46:50 +00:00
Vaxry
6f733292bf renderer: nvidia checks and use glFinish on nvidia
fixes #3952 #3946
2023-11-25 17:45:08 +00:00
Vaxry
3fe6162af1 opengl: fix xray modes in introspection checks for ls
fixes #3953
2023-11-25 14:52:52 +00:00
Jibin George
2ce4b94a22 input: Fix custom acceleration profile config (#3948) 2023-11-25 14:39:21 +00:00
coldified
de95e956a0 meson: Update wlroots-meson-build.patch (#3950) 2023-11-25 14:32:01 +00:00
Junxuan Liao
929c44e361 input: pass mouse input to IME popups (#3922) 2023-11-25 14:27:57 +00:00
Vaxry
512a59731b config: default special_scale_factor to 1 2023-11-25 01:45:04 +00:00
Vaxry
a6eba91935 opengl: require introspection on mirroring
fixes #3939
2023-11-25 00:48:02 +00:00
Xavier
745b998587 renderer: Adding an option to disable first launch animation (#3933) 2023-11-24 21:45:59 +00:00
Vaxry
1a2a2da6aa renderer: fixup cursor scaling
fixes #3935
2023-11-24 21:30:28 +00:00
Vaxry
822775aa8c renderer: Fixup double rendering cases with special (#3928)
* fixup

* better fullscreen
2023-11-24 21:18:50 +00:00
Vaxry
d79cf0afe2 renderer: fix software cursors on nvidia
fixes #3926
2023-11-24 13:47:36 +00:00
Vaxry
334d0ae31b monitor: fix transform matrix calculations for transformed
fixes #3929
2023-11-24 13:45:10 +00:00
Vaxry
be3d635265 makefile: update wlroots sover 2023-11-24 13:08:58 +00:00
André Silva
f9ba5a0551 flake.lock: update nixpkgs and xdph 2023-11-24 15:06:35 +02:00
thejch
258c83f3bb exec: remove redundant environment variables from spawn (#3923) 2023-11-24 12:42:20 +00:00
vaxerski
aedcade68d opengl: better checking for required introspection
performance woo
2023-11-24 12:37:10 +00:00
vaxerski
802ab58f8a renderer: fix inverseOpaque calcs in renderWithBlur 2023-11-24 12:32:35 +00:00
Vaxry
af5d06593f cmakelists: fix old wlroots sover 2023-11-24 10:59:02 +00:00
Vaxry
2ebfd0c745 renderer: Move to a full Hyprland GL rendering pipeline (#3920)
Also updates wlroots
2023-11-24 10:54:21 +00:00
vaxerski
e40e486f61 renderer: better checks for special rendering in renderWorkspaceWindows
ref #3916 #3888
2023-11-23 11:31:52 +00:00
Vaxry
e55c5a916a renderer: make sure lastWindow has correct ws in renderWorkspaceWindows
fixes #3916 fixes #3888
2023-11-22 23:43:46 +00:00
Vaxry
45ebe0df8f config: fix red warn in default config
fixes #3917
2023-11-22 23:38:14 +00:00
Vaxry
812a3f6d78 renderer: fix double render of tiled on workspace switch
fixes #3889
2023-11-22 20:05:50 +00:00
Vaxry
44accacff9 config: add nomaximizerequest all to default cfg 2023-11-22 19:50:37 +00:00
Ngô Huy
d417370bb7 makefile: Add CXXFLAGS to hyprlctl's Makefile (#3913) 2023-11-22 11:02:36 +00:00
zakk4223
4729265284 hyprctl: Add 'layouts' command (#3895)
* Add hyprctl 'layouts' command

formatting

* Add getAllLayoutNames(), move m_vLayouts back to private

Formatting

* clang-format
2023-11-21 18:43:38 +00:00
thejch
572fd554b8 renderer: Fix floating clipbox (#3907)
* fix floating decoration clipbox scale

* use vecTransformedSize

* use workspace offset
2023-11-21 00:34:34 +00:00
thejch
7d1c8d827a shadow: add workspace offset to floating window shadow (#3906) 2023-11-20 22:34:28 +00:00
thejch
6d26199e1c renderer: fix floating window rendering when scale > 1 (#3901) 2023-11-20 12:13:09 +00:00
end-4
646f4bc638 general: add workspace gaps (#3877)
* anims: workspace gap

* anims: ws gaps: on swipe end

* anims: ws gaps: add missing parentheses

* format

* refractor

* Update Swipe.cpp

* format

* fix swipe to right

* ws gaps: move animations:workspace_gap to general:gaps_workspace

* ws gaps: general:gaps_workspace -> general:gaps_workspaces
2023-11-19 12:33:26 +00:00
MightyPlaza
7e0c90b92c groupbar: fix text pos with verical offset (#3893)
modified:   src/render/decorations/CHyprGroupBarDecoration.cpp
2023-11-19 12:29:26 +00:00
MightyPlaza
add23a9ba2 group: fix dragging into floating groups (#3719)
* allow dragging into floating groups

modified:   src/Compositor.cpp
modified:   src/Compositor.hpp
modified:   src/layout/IHyprLayout.cpp
modified:   src/render/decorations/CHyprGroupBarDecoration.cpp

* floating-only
modified:   src/layout/IHyprLayout.cpp
2023-11-19 12:29:01 +00:00
Dickby
3d89654254 vector: New operator overloads and small fix in Vector2D. (#3891) 2023-11-18 21:37:16 +00:00
Dickby
6ad5f26cfe layout: Don't update pseudoSize after window moved by mouse. (#3873) 2023-11-18 19:59:12 +00:00
Vaxry
89f6457a99 renderer: avoid rendering floating windows twice with special
fixes #3887
2023-11-18 19:53:45 +00:00
Vaxry
8b57a1973e internal: Allow floating windows on special (#3872)
* allow floating on special

* fix mistake

* fix clipbox
2023-11-18 17:00:24 +00:00
Vaxry
483302a2cd env: add HYPRLAND_NO_RT 2023-11-17 23:29:30 +00:00
Vaxry
a903dba858 cmake: include tracy cpp if set 2023-11-17 23:26:54 +00:00
Vaxry
395985f815 pluginmgr: fix double use of dlerror() 2023-11-17 22:24:52 +00:00
Vaxry
51282f964f plugins: make logging on error more verbose
ref #3874
2023-11-17 22:22:31 +00:00
TheAngusMcFire
db8f13291a hyprctl: add monitors all to report all connected monitors (#3730)
---------

Co-authored-by: Christian Rieger <christian.rieger@student.tugraz.at>
2023-11-17 16:01:21 +00:00
André Silva
30ad71ff36 nix: add libGL to build inputs 2023-11-17 17:36:18 +02:00
Vaxry
84bc0a73f6 compositor: drop unused vectorToWindow func 2023-11-17 15:30:04 +00:00
Dickby
1d9bfa60a1 opengl: Don't use wrong shader just because it's GLES (#3867) 2023-11-16 21:03:17 +00:00
Vaxry
a34e192433 renderer: clip floating boxes on slide anim
fixes #3514
2023-11-16 20:20:41 +00:00
Vaxry
4868d4dfd3 shadow: avoid fatal mutation of the windowBox for calcs
fixes #3865
2023-11-16 17:31:52 +00:00
vaxerski
859841f4d1 renderer: don't make snapshots of invisible windows on close 2023-11-16 12:24:07 +00:00
vaxerski
28ef18a921 shadow: avoid using glClear and don't draw behind window if ignore_window
fixes #3860
2023-11-16 11:42:53 +00:00
Dickby
91d6be1f09 groupbar: Fix position of groupbar titles on monitor scales != 1.0 (#3856) 2023-11-15 20:32:44 +00:00
thejch
9e3dccca76 keybinds: Close special workspace after moving windows out of it (#3649)
* use old monitor

* use pMonitor for for special workspace
2023-11-15 12:32:02 +00:00
Vaxry
81598b3dbd README: update showcase 2023-11-14 20:08:00 +00:00
Vaxry
e195e51c1b logging: move to an internal rolling log buffer
disables logging to the logfile by default
2023-11-14 20:06:04 +00:00
Vaxry
e8469f8b1b renderer: drop unnecessary spammy logs 2023-11-14 19:51:47 +00:00
Vaxry
49597688e9 windowrules: make idleinhibit dynamic 2023-11-14 15:46:57 +00:00
Vaxry
5edb4e4a30 decorations: recalc layout and positioner on add/remove 2023-11-13 16:42:58 +00:00
Ching Pei Yang
4d6fa6ed0c pluginapi: add touch event hooks (#3836) 2023-11-13 16:32:12 +00:00
Vaxry
016a7a9c9b hyprctl: use a rolling buffer for reading requests
fixes #3846
2023-11-13 16:30:37 +00:00
Vaxry
2e26542e3b renderer: use viewporter corrected size for uv calcs 2023-11-12 23:57:53 +00:00
Vaxry
68935ba9dc renderer: separate oversize uv calcs in dimensions 2023-11-12 23:27:52 +00:00
Vaxry
ba5bc5871f subsurfaces: damage window on subsurface size change 2023-11-12 23:06:31 +00:00
Vaxry
824ccd957b renderer: pass proper arg to main param of uv calcs
was fucking up some non-fitting subsurfaces
2023-11-12 22:59:19 +00:00
Vaxry
45e86d4fdf groupbar: translate box by workspace offset 2023-11-12 22:40:21 +00:00
Vaxry
0ba2e68704 deco-positioner: don't remove hidden windows' data 2023-11-12 17:02:42 +00:00
Dickby
e974d1fe98 shaders: Some more changes in rgb2hsl. (#3834) 2023-11-12 16:20:23 +00:00
Vaxry
47d46aa56c inputmgr: clean lists in ~dtor
ref #3558
2023-11-12 14:03:46 +00:00
Vaxry
65efde32c9 internal: make getPlusMinusKeywordResult return optional 2023-11-12 13:40:02 +00:00
Vaxry
69e314207d internal: replace INT_MAX with WORKSPACE_INVALID 2023-11-12 13:34:54 +00:00
Alessio Molinari
1bfd4a2bff output-layout: fix wlroots display handling (#3718) 2023-11-12 13:14:05 +00:00
Vaxry
91cbe93cf8 decoration: add NON_SOLID flag for shadow
fixes #3841
2023-11-12 13:01:23 +00:00
Vaxry
9afdd61ade props: bump ver to 0.32.3 2023-11-11 18:14:46 +00:00
Vaxry
f39a6ca17c decoration-positioner: improve stability 2023-11-11 18:07:56 +00:00
88 changed files with 2011 additions and 1135 deletions

View File

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

View File

@@ -10,7 +10,6 @@ jobs:
matrix: matrix:
package: package:
- hyprland - hyprland
- hyprland-nvidia
- xdg-desktop-portal-hyprland - xdg-desktop-portal-hyprland
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@@ -57,12 +57,12 @@ ExternalProject_Add(
wlroots wlroots
PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots
SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots
PATCH_COMMAND sed -E -i -e "s/(soversion = 12)([^032]|$$)/soversion = 12032/g" meson.build PATCH_COMMAND sed -E -i -e "s/(soversion = 13)([^032]|$$)/soversion = 13032/g" meson.build
CONFIGURE_COMMAND meson setup build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dexamples=false -Drenderers=gles2 $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none> && meson setup build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dexamples=false -Drenderers=gles2 $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none> --reconfigure CONFIGURE_COMMAND meson setup build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dexamples=false -Drenderers=gles2 $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none> && meson setup build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dexamples=false -Drenderers=gles2 $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none> --reconfigure
BUILD_COMMAND ninja -C build BUILD_COMMAND ninja -C build
BUILD_ALWAYS true BUILD_ALWAYS true
BUILD_IN_SOURCE true BUILD_IN_SOURCE true
BUILD_BYPRODUCTS ${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.12032 BUILD_BYPRODUCTS ${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.13032
INSTALL_COMMAND echo "wlroots: install not needed" INSTALL_COMMAND echo "wlroots: install not needed"
) )
@@ -99,14 +99,19 @@ set(CMAKE_ENABLE_EXPORTS TRUE)
message(STATUS "Checking deps...") message(STATUS "Checking deps...")
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
find_package(OpenGL REQUIRED) find_package(OpenGL REQUIRED)
pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo libdrm xkbcommon libinput pango pangocairo pixman-1) # we do not check for wlroots, as we provide it ourselves pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo libdrm xkbcommon libinput pango pangocairo pixman-1) # we do not check for wlroots, as we provide it ourselves
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp") file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
add_executable(Hyprland ${SRCFILES}) set(TRACY_CPP_FILES "")
if(USE_TRACY)
set(TRACY_CPP_FILES "subprojects/tracy/public/TracyClient.cpp")
message(STATUS "Tracy enabled, TRACY_CPP_FILES: " ${TRACY_CPP_FILES})
endif()
add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES})
add_dependencies(Hyprland wlroots) add_dependencies(Hyprland wlroots)
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
@@ -216,7 +221,7 @@ function(protocol protoPath protoName external)
endfunction() endfunction()
target_link_libraries(Hyprland target_link_libraries(Hyprland
${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.12032 # wlroots is provided by us ${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.13032 # wlroots is provided by us
OpenGL::EGL OpenGL::EGL
OpenGL::GL OpenGL::GL
Threads::Threads Threads::Threads

View File

@@ -50,7 +50,7 @@ install:
install -m644 ./docs/*.1 ${PREFIX}/share/man/man1 install -m644 ./docs/*.1 ${PREFIX}/share/man/man1
mkdir -p ${PREFIX}/lib/ mkdir -p ${PREFIX}/lib/
cp ./subprojects/wlroots/build/libwlroots.so.12032 ${PREFIX}/lib/ cp ./subprojects/wlroots/build/libwlroots.so.13032 ${PREFIX}/lib/
$(MAKE) installheaders $(MAKE) installheaders
@@ -58,7 +58,7 @@ uninstall:
rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop
rm -f ${PREFIX}/bin/Hyprland rm -f ${PREFIX}/bin/Hyprland
rm -f ${PREFIX}/bin/hyprctl rm -f ${PREFIX}/bin/hyprctl
rm -f ${PREFIX}/lib/libwlroots.so.12032 rm -f ${PREFIX}/lib/libwlroots.so.13032
rm -rf ${PREFIX}/share/hyprland rm -rf ${PREFIX}/share/hyprland
rm -f ${PREFIX}/share/man/man1/Hyprland.1 rm -f ${PREFIX}/share/man/man1/Hyprland.1
rm -f ${PREFIX}/share/man/man1/hyprctl.1 rm -f ${PREFIX}/share/man/man1/hyprctl.1
@@ -68,7 +68,7 @@ pluginenv:
@exit 1 @exit 1
installheaders: installheaders:
@if [ ! -f ./build/Hyprland ]; then echo -en "You need to run $(MAKE) all first.\n" && exit 1; fi @if [ ! -f ./src/version.h ]; then echo -en "You need to run $(MAKE) all first.\n" && exit 1; fi
mkdir -p ${PREFIX}/include/hyprland mkdir -p ${PREFIX}/include/hyprland
mkdir -p ${PREFIX}/include/hyprland/protocols mkdir -p ${PREFIX}/include/hyprland/protocols

View File

@@ -128,8 +128,8 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
<!----------------------------------{ Images }---------------------------------> <!----------------------------------{ Images }--------------------------------->
[Stars Preview]: https://starchart.cc/vaxerski/Hyprland.svg [Stars Preview]: https://starchart.cc/vaxerski/Hyprland.svg
[Preview A]: https://cdn.discordapp.com/attachments/1091569872535814185/1107675866101723277/screenshot-summer.png [Preview A]: https://i.ibb.co/C1yTb0r/falf.png
[Preview B]: https://i.ibb.co/SX7GbYR/winter-rice.png [Preview B]: https://cdn.discordapp.com/attachments/1091569872535814185/1107675866101723277/screenshot-summer.png
[Preview C]: https://i.ibb.co/B3GJg28/20221126-20h53m26s-grim.png [Preview C]: https://i.ibb.co/B3GJg28/20221126-20h53m26s-grim.png

View File

@@ -19,6 +19,10 @@ monitor=,preferred,auto,auto
# Source a file (multi-file configs) # Source a file (multi-file configs)
# source = ~/.config/hypr/myColors.conf # source = ~/.config/hypr/myColors.conf
# Set programs that you use
$terminal = kitty
$fileManager = dolphin
$menu = wofi --show drun
# Some default env vars. # Some default env vars.
env = XCURSOR_SIZE,24 env = XCURSOR_SIZE,24
@@ -120,18 +124,19 @@ device:epic-mouse-v1 {
# Example windowrule v2 # Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$ # windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more # See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
windowrulev2 = nomaximizerequest, class:.* # You'll probably like this.
# See https://wiki.hyprland.org/Configuring/Keywords/ for more # See https://wiki.hyprland.org/Configuring/Keywords/ for more
$mainMod = SUPER $mainMod = SUPER
# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more # Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
bind = $mainMod, Q, exec, kitty bind = $mainMod, Q, exec, $terminal
bind = $mainMod, C, killactive, bind = $mainMod, C, killactive,
bind = $mainMod, M, exit, bind = $mainMod, M, exit,
bind = $mainMod, E, exec, dolphin bind = $mainMod, E, exec, $fileManager
bind = $mainMod, V, togglefloating, bind = $mainMod, V, togglefloating,
bind = $mainMod, R, exec, wofi --show drun bind = $mainMod, R, exec, $menu
bind = $mainMod, P, pseudo, # dwindle bind = $mainMod, P, pseudo, # dwindle
bind = $mainMod, J, togglesplit, # dwindle bind = $mainMod, J, togglesplit, # dwindle

20
flake.lock generated
View File

@@ -25,11 +25,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1698134075, "lastModified": 1700612854,
"narHash": "sha256-foCD+nuKzfh49bIoiCBur4+Fx1nozo+4C/6k8BYk4sg=", "narHash": "sha256-yrQ8osMD+vDLGFX7pcwsY/Qr5PUd6OmDMYJZzZi0+zc=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "8efd5d1e283604f75a808a20e6cde0ef313d07d4", "rev": "19cbff58383a4ae384dea4d1d0c823d72b49d614",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -67,18 +67,18 @@
"flake": false, "flake": false,
"locked": { "locked": {
"host": "gitlab.freedesktop.org", "host": "gitlab.freedesktop.org",
"lastModified": 1699292815, "lastModified": 1701368958,
"narHash": "sha256-HXu98PyBMKEWLqiTb8viuLDznud/SdkdJsx5A5CWx7I=", "narHash": "sha256-7kvyoA91etzVEl9mkA/EJfB6z/PltxX7Xc4gcr7/xlo=",
"owner": "wlroots", "owner": "wlroots",
"repo": "wlroots", "repo": "wlroots",
"rev": "5de9e1a99d6642c2d09d589aa37ff0a8945dcee1", "rev": "5d639394f3e83b01596dcd166a44a9a1a2583350",
"type": "gitlab" "type": "gitlab"
}, },
"original": { "original": {
"host": "gitlab.freedesktop.org", "host": "gitlab.freedesktop.org",
"owner": "wlroots", "owner": "wlroots",
"repo": "wlroots", "repo": "wlroots",
"rev": "5de9e1a99d6642c2d09d589aa37ff0a8945dcee1", "rev": "5d639394f3e83b01596dcd166a44a9a1a2583350",
"type": "gitlab" "type": "gitlab"
} }
}, },
@@ -95,11 +95,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1697981233, "lastModified": 1700508250,
"narHash": "sha256-y8q4XUwx+gVK7i2eLjfR32lVo7TYvEslyzrmzYEaPZU=", "narHash": "sha256-X4o/mifI7Nhu0UKYlxx53wIC+gYDo3pVM9L2u3PE2bE=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland", "repo": "xdg-desktop-portal-hyprland",
"rev": "22e7a65ff9633e1dedfa5317fdffc49f68de2ff2", "rev": "eb120ff25265ecacd0fc13d7dab12131b60d0f47",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -12,7 +12,7 @@
host = "gitlab.freedesktop.org"; host = "gitlab.freedesktop.org";
owner = "wlroots"; owner = "wlroots";
repo = "wlroots"; repo = "wlroots";
rev = "5de9e1a99d6642c2d09d589aa37ff0a8945dcee1"; rev = "5d639394f3e83b01596dcd166a44a9a1a2583350";
flake = false; flake = false;
}; };
@@ -65,7 +65,6 @@
hyprland hyprland
hyprland-unwrapped hyprland-unwrapped
hyprland-debug hyprland-debug
hyprland-nvidia
# hyprland-extras # hyprland-extras
xdg-desktop-portal-hyprland xdg-desktop-portal-hyprland
# dependencies # dependencies

View File

@@ -1,4 +1,4 @@
all: all:
$(CXX) -std=c++2b ./main.cpp -o ./hyprctl $(CXX) $(CXXFLAGS) -std=c++2b ./main.cpp -o ./hyprctl
clean: clean:
rm ./hyprctl rm ./hyprctl

View File

@@ -26,32 +26,33 @@
const std::string USAGE = R"#(usage: hyprctl [(opt)flags] [command] [(opt)args] const std::string USAGE = R"#(usage: hyprctl [(opt)flags] [command] [(opt)args]
commands: commands:
monitors
workspaces
activeworkspace
workspacerules
clients
activewindow activewindow
layers activeworkspace
devices
binds binds
clients
cursorpos
devices
dispatch dispatch
keyword getoption
version globalshortcuts
kill
splash
hyprpaper hyprpaper
instances
keyword
kill
layers
layouts
monitors
notify
plugin
reload reload
setcursor setcursor
getoption
cursorpos
switchxkblayout
seterror seterror
setprop setprop
plugin splash
notify switchxkblayout
globalshortcuts version
instances workspacerules
workspaces
flags: flags:
-j -> output in JSON -j -> output in JSON
@@ -396,6 +397,8 @@ int main(int argc, char** argv) {
request(fullRequest); request(fullRequest);
else if (fullRequest.contains("/globalshortcuts")) else if (fullRequest.contains("/globalshortcuts"))
request(fullRequest); request(fullRequest);
else if (fullRequest.contains("/rollinglog"))
request(fullRequest);
else if (fullRequest.contains("/instances")) else if (fullRequest.contains("/instances"))
instancesRequest(json); instancesRequest(json);
else if (fullRequest.contains("/switchxkblayout")) else if (fullRequest.contains("/switchxkblayout"))
@@ -418,6 +421,8 @@ int main(int argc, char** argv) {
request(fullRequest, 2); request(fullRequest, 2);
else if (fullRequest.contains("/hyprpaper")) else if (fullRequest.contains("/hyprpaper"))
requestHyprpaper(fullRequest); requestHyprpaper(fullRequest);
else if (fullRequest.contains("/layouts"))
request(fullRequest);
else if (fullRequest.contains("/--help")) else if (fullRequest.contains("/--help"))
printf("%s", USAGE.c_str()); printf("%s", USAGE.c_str());
else { else {

View File

@@ -1,5 +1,6 @@
{ {
lib, lib,
fetchurl,
stdenv, stdenv,
pkg-config, pkg-config,
makeWrapper, makeWrapper,
@@ -10,6 +11,7 @@
git, git,
hyprland-protocols, hyprland-protocols,
jq, jq,
libGL,
libdrm, libdrm,
libinput, libinput,
libxcb, libxcb,
@@ -26,7 +28,6 @@
xcbutilwm, xcbutilwm,
xwayland, xwayland,
debug ? false, debug ? false,
enableNvidiaPatches ? false,
enableXWayland ? true, enableXWayland ? true,
legacyRenderer ? false, legacyRenderer ? false,
withSystemd ? lib.meta.availableOn stdenv.hostPlatform systemd, withSystemd ? lib.meta.availableOn stdenv.hostPlatform systemd,
@@ -34,13 +35,25 @@
version ? "git", version ? "git",
commit, commit,
# deprecated flags # deprecated flags
enableNvidiaPatches ? false,
nvidiaPatches ? false, nvidiaPatches ? false,
hidpiXWayland ? false, hidpiXWayland ? false,
}: }:
assert lib.assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been renamed `enableNvidiaPatches`"; let
# NOTE: remove after https://github.com/NixOS/nixpkgs/pull/271096 reaches nixos-unstable
libdrm_2_4_118 = libdrm.overrideAttrs(attrs: rec {
version = "2.4.118";
src = fetchurl {
url = "https://dri.freedesktop.org/${attrs.pname}/${attrs.pname}-${version}.tar.xz";
hash = "sha256-p3e9hfK1/JxX+IbIIFgwBXgxfK/bx30Kdp1+mpVnq4g=";
};
});
in
assert lib.assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed.";
assert lib.assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed.";
assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland"; assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland";
stdenv.mkDerivation { stdenv.mkDerivation {
pname = "hyprland${lib.optionalString enableNvidiaPatches "-nvidia"}${lib.optionalString debug "-debug"}"; pname = "hyprland${lib.optionalString debug "-debug"}";
inherit version; inherit version;
src = lib.cleanSourceWith { src = lib.cleanSourceWith {
@@ -71,7 +84,8 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
git git
cairo cairo
hyprland-protocols hyprland-protocols
libdrm libGL
libdrm_2_4_118
libinput libinput
libxkbcommon libxkbcommon
mesa mesa
@@ -80,7 +94,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
wayland wayland
wayland-protocols wayland-protocols
pciutils pciutils
(wlroots.override {inherit enableNvidiaPatches;}) wlroots
] ]
++ lib.optionals enableXWayland [libxcb xcbutilwm xwayland] ++ lib.optionals enableXWayland [libxcb xcbutilwm xwayland]
++ lib.optionals withSystemd [systemd]; ++ lib.optionals withSystemd [systemd];

View File

@@ -7,7 +7,6 @@ self: {
cfg = config.wayland.windowManager.hyprland; cfg = config.wayland.windowManager.hyprland;
defaultHyprlandPackage = self.packages.${pkgs.stdenv.hostPlatform.system}.default.override { defaultHyprlandPackage = self.packages.${pkgs.stdenv.hostPlatform.system}.default.override {
enableXWayland = cfg.xwayland.enable; enableXWayland = cfg.xwayland.enable;
inherit (cfg) enableNvidiaPatches;
}; };
in { in {
disabledModules = ["services/window-managers/hyprland.nix"]; disabledModules = ["services/window-managers/hyprland.nix"];
@@ -35,12 +34,10 @@ in {
defaultText = lib.literalExpression '' defaultText = lib.literalExpression ''
hyprland.packages.''${pkgs.stdenv.hostPlatform.system}.default.override { hyprland.packages.''${pkgs.stdenv.hostPlatform.system}.default.override {
enableXWayland = config.wayland.windowManager.hyprland.xwayland.enable; enableXWayland = config.wayland.windowManager.hyprland.xwayland.enable;
inherit (config.wayland.windowManager.hyprland) enableNvidiaPatches;
} }
''; '';
description = lib.mdDoc '' description = lib.mdDoc ''
Hyprland package to use. Will override the 'xwayland' and Hyprland package to use. Will override the 'xwayland' option.
'enableNvidiaPatches' options.
Defaults to the one provided by the flake. Set it to Defaults to the one provided by the flake. Set it to
{package}`pkgs.hyprland` to use the one provided by nixpkgs or {package}`pkgs.hyprland` to use the one provided by nixpkgs or
@@ -86,8 +83,6 @@ in {
xwayland.enable = lib.mkEnableOption (lib.mdDoc "XWayland") // {default = true;}; xwayland.enable = lib.mkEnableOption (lib.mdDoc "XWayland") // {default = true;};
enableNvidiaPatches = lib.mkEnableOption (lib.mdDoc "patching wlroots for better Nvidia support.");
extraConfig = lib.mkOption { extraConfig = lib.mkOption {
type = lib.types.nullOr lib.types.lines; type = lib.types.nullOr lib.types.lines;
default = ""; default = "";
@@ -173,5 +168,7 @@ in {
imports = [ imports = [
(lib.mkRemovedOptionModule ["wayland" "windowManager" "hyprland" "xwayland" "hidpi"] (lib.mkRemovedOptionModule ["wayland" "windowManager" "hyprland" "xwayland" "hidpi"]
"Support for this option has been removed. Refer to https://wiki.hyprland.org/Configuring/XWayland for more info") "Support for this option has been removed. Refer to https://wiki.hyprland.org/Configuring/XWayland for more info")
(lib.mkRemovedOptionModule ["wayland" "windowManager" "hyprland" "xwayland" "enableNvidiaPatches"]
"Nvidia patches are no longer needed for Hyprland")
]; ];
} }

View File

@@ -37,7 +37,6 @@ in {
readOnly = true; readOnly = true;
default = cfg.package.override { default = cfg.package.override {
enableXWayland = cfg.xwayland.enable; enableXWayland = cfg.xwayland.enable;
enableNvidiaPatches = cfg.enableNvidiaPatches;
}; };
defaultText = defaultText =
literalExpression literalExpression
@@ -50,12 +49,6 @@ in {
portalPackage = mkPackageOptionMD inputs.xdph.packages.${system} "xdg-desktop-portal-hyprland" {}; portalPackage = mkPackageOptionMD inputs.xdph.packages.${system} "xdg-desktop-portal-hyprland" {};
xwayland.enable = mkEnableOption (mdDoc "support for XWayland") // {default = true;}; xwayland.enable = mkEnableOption (mdDoc "support for XWayland") // {default = true;};
enableNvidiaPatches =
mkEnableOption null
// {
description = mdDoc "Whether to apply patches to wlroots for better Nvidia support.";
};
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
@@ -91,9 +84,14 @@ in {
"XWayland patches are deprecated. Refer to https://wiki.hyprland.org/Configuring/XWayland" "XWayland patches are deprecated. Refer to https://wiki.hyprland.org/Configuring/XWayland"
) )
( (
mkRenamedOptionModule mkRemovedOptionModule
["programs" "hyprland" "nvidiaPatches"]
["programs" "hyprland" "enableNvidiaPatches"] ["programs" "hyprland" "enableNvidiaPatches"]
"Nvidia patches are no longer needed"
)
(
mkRemovedOptionModule
["programs" "hyprland" "nvidiaPatches"]
"Nvidia patches are no longer needed"
) )
]; ];
} }

View File

@@ -38,7 +38,12 @@ in {
}; };
hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;}; hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;};
hyprland-debug = final.hyprland.override {debug = true;}; hyprland-debug = final.hyprland.override {debug = true;};
hyprland-nvidia = final.hyprland.override {enableNvidiaPatches = true;}; hyprland-nvidia =
builtins.trace ''
hyprland-nvidia was removed. Please use the hyprland package.
Nvidia patches are no longer needed.
''
final.hyprland;
hyprland-hidpi = hyprland-hidpi =
builtins.trace '' builtins.trace ''
hyprland-hidpi was removed. Please use the hyprland package. hyprland-hidpi was removed. Please use the hyprland package.

View File

@@ -1,41 +0,0 @@
diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c
index 9fe934f7..9662d4ee 100644
--- a/render/gles2/renderer.c
+++ b/render/gles2/renderer.c
@@ -176,7 +176,7 @@ static bool gles2_bind_buffer(struct wlr_renderer *wlr_renderer,
assert(wlr_egl_is_current(renderer->egl));
push_gles2_debug(renderer);
- glFlush();
+ glFinish();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
pop_gles2_debug(renderer);
diff --git a/types/output/render.c b/types/output/render.c
index 2e38919a..97f78608 100644
--- a/types/output/render.c
+++ b/types/output/render.c
@@ -240,22 +240,7 @@ bool output_pick_format(struct wlr_output *output,
}
uint32_t wlr_output_preferred_read_format(struct wlr_output *output) {
- struct wlr_renderer *renderer = output->renderer;
- assert(renderer != NULL);
-
- if (!renderer->impl->preferred_read_format || !renderer->impl->read_pixels) {
- return DRM_FORMAT_INVALID;
- }
-
- if (!wlr_output_attach_render(output, NULL)) {
- return false;
- }
-
- uint32_t fmt = renderer->impl->preferred_read_format(renderer);
-
- output_clear_back_buffer(output);
-
- return fmt;
+ return DRM_FORMAT_XRGB8888;
}
struct wlr_render_pass *wlr_output_begin_render_pass(struct wlr_output *output,

View File

@@ -1,26 +1,31 @@
{ {
lib, fetchurl,
version, version,
src, src,
wlroots, wlroots,
hwdata, hwdata,
libdisplay-info, libdisplay-info,
libliftoff, libliftoff,
libdrm,
enableXWayland ? true, enableXWayland ? true,
enableNvidiaPatches ? false,
}: }:
let
# NOTE: remove after https://github.com/NixOS/nixpkgs/pull/271096 reaches nixos-unstable
libdrm_2_4_118 = libdrm.overrideAttrs(old: rec {
version = "2.4.118";
src = fetchurl {
url = "https://dri.freedesktop.org/${old.pname}/${old.pname}-${version}.tar.xz";
hash = "sha256-p3e9hfK1/JxX+IbIIFgwBXgxfK/bx30Kdp1+mpVnq4g=";
};
});
in
wlroots.overrideAttrs (old: { wlroots.overrideAttrs (old: {
inherit version src enableXWayland; inherit version src enableXWayland;
pname = "${old.pname}-hyprland${lib.optionalString enableNvidiaPatches "-nvidia"}"; pname = "${old.pname}-hyprland";
patches = # HACK: libdrm_2_4_118 is placed at the head of list to take precedence over libdrm in `old.buildInputs`
(old.patches or []) buildInputs = [libdrm_2_4_118] ++ old.buildInputs ++ [hwdata libliftoff libdisplay-info];
++ (lib.optionals enableNvidiaPatches [
./patches/wlroots-nvidia.patch
]);
buildInputs = old.buildInputs ++ [hwdata libliftoff libdisplay-info];
NIX_CFLAGS_COMPILE = toString [ NIX_CFLAGS_COMPILE = toString [
"-Wno-error=maybe-uninitialized" "-Wno-error=maybe-uninitialized"

View File

@@ -1,3 +1,3 @@
{ {
"version": "0.32.2" "version": "0.33.1"
} }

View File

@@ -190,7 +190,7 @@ void CCompositor::initServer() {
m_sWLRGammaCtrlMgr = wlr_gamma_control_manager_v1_create(m_sWLDisplay); m_sWLRGammaCtrlMgr = wlr_gamma_control_manager_v1_create(m_sWLDisplay);
m_sWLROutputLayout = wlr_output_layout_create(); m_sWLROutputLayout = wlr_output_layout_create(m_sWLDisplay);
m_sWLROutputPowerMgr = wlr_output_power_manager_v1_create(m_sWLDisplay); m_sWLROutputPowerMgr = wlr_output_power_manager_v1_create(m_sWLDisplay);
@@ -225,7 +225,6 @@ void CCompositor::initServer() {
m_sWLROutputMgr = wlr_output_manager_v1_create(m_sWLDisplay); m_sWLROutputMgr = wlr_output_manager_v1_create(m_sWLDisplay);
m_sWLRInhibitMgr = wlr_input_inhibit_manager_create(m_sWLDisplay);
m_sWLRKbShInhibitMgr = wlr_keyboard_shortcuts_inhibit_v1_create(m_sWLDisplay); m_sWLRKbShInhibitMgr = wlr_keyboard_shortcuts_inhibit_v1_create(m_sWLDisplay);
m_sWLRPointerConstraints = wlr_pointer_constraints_v1_create(m_sWLDisplay); m_sWLRPointerConstraints = wlr_pointer_constraints_v1_create(m_sWLDisplay);
@@ -283,7 +282,7 @@ void CCompositor::initServer() {
void CCompositor::initAllSignals() { void CCompositor::initAllSignals() {
addWLSignal(&m_sWLRBackend->events.new_output, &Events::listen_newOutput, m_sWLRBackend, "Backend"); addWLSignal(&m_sWLRBackend->events.new_output, &Events::listen_newOutput, m_sWLRBackend, "Backend");
addWLSignal(&m_sWLRXDGShell->events.new_surface, &Events::listen_newXDGSurface, m_sWLRXDGShell, "XDG Shell"); addWLSignal(&m_sWLRXDGShell->events.new_toplevel, &Events::listen_newXDGToplevel, m_sWLRXDGShell, "XDG Shell");
addWLSignal(&m_sWLRCursor->events.motion, &Events::listen_mouseMove, m_sWLRCursor, "WLRCursor"); addWLSignal(&m_sWLRCursor->events.motion, &Events::listen_mouseMove, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.motion_absolute, &Events::listen_mouseMoveAbsolute, m_sWLRCursor, "WLRCursor"); addWLSignal(&m_sWLRCursor->events.motion_absolute, &Events::listen_mouseMoveAbsolute, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.button, &Events::listen_mouseButton, m_sWLRCursor, "WLRCursor"); addWLSignal(&m_sWLRCursor->events.button, &Events::listen_mouseButton, m_sWLRCursor, "WLRCursor");
@@ -312,8 +311,6 @@ void CCompositor::initAllSignals() {
addWLSignal(&m_sWLROutputLayout->events.change, &Events::listen_change, m_sWLROutputLayout, "OutputLayout"); addWLSignal(&m_sWLROutputLayout->events.change, &Events::listen_change, m_sWLROutputLayout, "OutputLayout");
addWLSignal(&m_sWLROutputMgr->events.apply, &Events::listen_outputMgrApply, m_sWLROutputMgr, "OutputMgr"); addWLSignal(&m_sWLROutputMgr->events.apply, &Events::listen_outputMgrApply, m_sWLROutputMgr, "OutputMgr");
addWLSignal(&m_sWLROutputMgr->events.test, &Events::listen_outputMgrTest, m_sWLROutputMgr, "OutputMgr"); addWLSignal(&m_sWLROutputMgr->events.test, &Events::listen_outputMgrTest, m_sWLROutputMgr, "OutputMgr");
addWLSignal(&m_sWLRInhibitMgr->events.activate, &Events::listen_InhibitActivate, m_sWLRInhibitMgr, "InhibitMgr");
addWLSignal(&m_sWLRInhibitMgr->events.deactivate, &Events::listen_InhibitDeactivate, m_sWLRInhibitMgr, "InhibitMgr");
addWLSignal(&m_sWLRPointerConstraints->events.new_constraint, &Events::listen_newConstraint, m_sWLRPointerConstraints, "PointerConstraints"); addWLSignal(&m_sWLRPointerConstraints->events.new_constraint, &Events::listen_newConstraint, m_sWLRPointerConstraints, "PointerConstraints");
addWLSignal(&m_sWLRXDGDecoMgr->events.new_toplevel_decoration, &Events::listen_NewXDGDeco, m_sWLRXDGDecoMgr, "XDGDecoMgr"); addWLSignal(&m_sWLRXDGDecoMgr->events.new_toplevel_decoration, &Events::listen_NewXDGDeco, m_sWLRXDGDecoMgr, "XDGDecoMgr");
addWLSignal(&m_sWLRVirtPtrMgr->events.new_virtual_pointer, &Events::listen_newVirtPtr, m_sWLRVirtPtrMgr, "VirtPtrMgr"); addWLSignal(&m_sWLRVirtPtrMgr->events.new_virtual_pointer, &Events::listen_newVirtPtr, m_sWLRVirtPtrMgr, "VirtPtrMgr");
@@ -342,7 +339,8 @@ void CCompositor::cleanup() {
removeLockFile(); removeLockFile();
m_bIsShuttingDown = true; m_bIsShuttingDown = true;
Debug::shuttingDown = true;
#ifdef USES_SYSTEMD #ifdef USES_SYSTEMD
if (sd_booted() > 0) if (sd_booted() > 0)
@@ -577,7 +575,7 @@ CMonitor* CCompositor::getMonitorFromName(const std::string& name) {
CMonitor* CCompositor::getMonitorFromDesc(const std::string& desc) { CMonitor* CCompositor::getMonitorFromDesc(const std::string& desc) {
for (auto& m : m_vMonitors) { for (auto& m : m_vMonitors) {
if (m->output->description && std::string(m->output->description).starts_with(desc)) if (m->szDescription.starts_with(desc))
return m.get(); return m.get();
} }
return nullptr; return nullptr;
@@ -630,46 +628,6 @@ bool CCompositor::windowExists(CWindow* pWindow) {
return false; return false;
} }
CWindow* CCompositor::vectorToWindow(const Vector2D& pos) {
const auto PMONITOR = getMonitorFromVector(pos);
if (PMONITOR->specialWorkspaceID) {
for (auto& w : m_vWindows | std::views::reverse) {
auto box = w->getWindowMainSurfaceBox();
if (w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && box.containsPoint(pos) && !w->isHidden() && !w->m_bNoFocus)
return w.get();
}
for (auto& w : m_vWindows) {
auto box = w->getWindowMainSurfaceBox();
if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && box.containsPoint(pos) && w->m_bIsMapped && !w->m_bIsFloating && !w->isHidden() && !w->m_bNoFocus)
return w.get();
}
}
// pinned
for (auto& w : m_vWindows | std::views::reverse) {
auto box = w->getWindowMainSurfaceBox();
if (box.containsPoint(pos) && w->m_bIsMapped && w->m_bIsFloating && !w->isHidden() && w->m_bPinned && !w->m_bNoFocus)
return w.get();
}
// first loop over floating cuz they're above, m_vWindows should be sorted bottom->top, for tiled it doesn't matter.
for (auto& w : m_vWindows | std::views::reverse) {
auto box = w->getWindowMainSurfaceBox();
if (box.containsPoint(pos) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned && !w->m_bNoFocus)
return w.get();
}
for (auto& w : m_vWindows) {
auto box = w->getWindowMainSurfaceBox();
if (box.containsPoint(pos) && w->m_bIsMapped && !w->m_bIsFloating && PMONITOR->activeWorkspace == w->m_iWorkspaceID && !w->isHidden() && !w->m_bNoFocus)
return w.get();
}
return nullptr;
}
CWindow* CCompositor::vectorToWindowTiled(const Vector2D& pos) { CWindow* CCompositor::vectorToWindowTiled(const Vector2D& pos) {
const auto PMONITOR = getMonitorFromVector(pos); const auto PMONITOR = getMonitorFromVector(pos);
@@ -690,36 +648,18 @@ CWindow* CCompositor::vectorToWindowTiled(const Vector2D& pos) {
return nullptr; return nullptr;
} }
CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) { CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos, CWindow* pIgnoreWindow) {
const auto PMONITOR = getMonitorFromVector(pos); const auto PMONITOR = getMonitorFromVector(pos);
static auto* const PRESIZEONBORDER = &g_pConfigManager->getConfigValuePtr("general:resize_on_border")->intValue; static auto* const PRESIZEONBORDER = &g_pConfigManager->getConfigValuePtr("general:resize_on_border")->intValue;
static auto* const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue; static auto* const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
static auto* const PBORDERGRABEXTEND = &g_pConfigManager->getConfigValuePtr("general:extend_border_grab_area")->intValue; static auto* const PBORDERGRABEXTEND = &g_pConfigManager->getConfigValuePtr("general:extend_border_grab_area")->intValue;
const auto BORDER_GRAB_AREA = *PRESIZEONBORDER ? *PBORDERSIZE + *PBORDERGRABEXTEND : 0; const auto BORDER_GRAB_AREA = *PRESIZEONBORDER ? *PBORDERSIZE + *PBORDERGRABEXTEND : 0;
// special workspace
if (PMONITOR->specialWorkspaceID) {
for (auto& w : m_vWindows | std::views::reverse) {
const auto BB = w->getWindowInputBox();
CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
if (w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && box.containsPoint(pos) && !w->isHidden() && !w->m_bX11ShouldntFocus &&
!w->m_bNoFocus)
return w.get();
}
for (auto& w : m_vWindows) {
CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (!w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && box.containsPoint(pos) && !w->isHidden() && !w->m_bX11ShouldntFocus &&
!w->m_bNoFocus)
return w.get();
}
}
// pinned windows on top of floating regardless // pinned windows on top of floating regardless
for (auto& w : m_vWindows | std::views::reverse) { for (auto& w : m_vWindows | std::views::reverse) {
const auto BB = w->getWindowInputBox(); const auto BB = w->getWindowInputBox();
CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA}; CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_bNoFocus) { if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_bNoFocus && w.get() != pIgnoreWindow) {
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y})) if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}))
return w.get(); return w.get();
@@ -730,48 +670,74 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
} }
} }
// first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter. auto windowForWorkspace = [&](bool special) -> CWindow* {
for (auto& w : m_vWindows | std::views::reverse) { // first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter.
const auto BB = w->getWindowInputBox(); for (auto& w : m_vWindows | std::views::reverse) {
CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned && !w->m_bNoFocus) { if (special && !isWorkspaceSpecial(w->m_iWorkspaceID)) // because special floating may creep up into regular
// OR windows should add focus to parent
if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2)
continue; continue;
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y})) { const auto BB = w->getWindowInputBox();
CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned && !w->m_bNoFocus && w.get() != pIgnoreWindow) {
// OR windows should add focus to parent
if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2)
continue;
if (w->m_bIsX11 && w->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(w->m_uSurface.xwayland)) { if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y})) {
// Override Redirect
return g_pCompositor->m_pLastWindow; // we kinda trick everything here. if (w->m_bIsX11 && w->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(w->m_uSurface.xwayland)) {
// TODO: this is wrong, we should focus the parent, but idk how to get it considering it's nullptr in most cases. // Override Redirect
return g_pCompositor->m_pLastWindow; // we kinda trick everything here.
// TODO: this is wrong, we should focus the parent, but idk how to get it considering it's nullptr in most cases.
}
return w.get();
} }
return w.get(); if (!w->m_bIsX11) {
if (w->hasPopupAt(pos))
return w.get();
}
} }
}
if (!w->m_bIsX11) { const int64_t WORKSPACEID = special ? PMONITOR->specialWorkspaceID : PMONITOR->activeWorkspace;
const auto PWORKSPACE = getWorkspaceByID(WORKSPACEID);
if (PWORKSPACE->m_bHasFullscreenWindow)
return getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
// for windows, we need to check their extensions too, first.
for (auto& w : m_vWindows) {
if (special != isWorkspaceSpecial(w->m_iWorkspaceID))
continue;
if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->m_iWorkspaceID == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus && !w->m_bNoFocus &&
w.get() != pIgnoreWindow) {
if (w->hasPopupAt(pos)) if (w->hasPopupAt(pos))
return w.get(); return w.get();
} }
} }
}
// for windows, we need to check their extensions too, first. for (auto& w : m_vWindows) {
for (auto& w : m_vWindows) { if (special != isWorkspaceSpecial(w->m_iWorkspaceID))
if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->isHidden() && !w->m_bX11ShouldntFocus && !w->m_bNoFocus) { continue;
if ((w)->hasPopupAt(pos))
CBox box = {w->m_vPosition, w->m_vSize};
if (!w->m_bIsFloating && w->m_bIsMapped && box.containsPoint(pos) && w->m_iWorkspaceID == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus && !w->m_bNoFocus &&
w.get() != pIgnoreWindow)
return w.get(); return w.get();
} }
}
for (auto& w : m_vWindows) {
CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (!w->m_bIsFloating && w->m_bIsMapped && box.containsPoint(pos) && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->isHidden() && !w->m_bX11ShouldntFocus &&
!w->m_bNoFocus)
return w.get();
}
return nullptr; return nullptr;
};
// special workspace
if (PMONITOR->specialWorkspaceID)
return windowForWorkspace(true);
return windowForWorkspace(false);
} }
CWindow* CCompositor::windowFromCursor() { CWindow* CCompositor::windowFromCursor() {
@@ -1144,6 +1110,21 @@ wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector<
return nullptr; return nullptr;
} }
SIMEPopup* CCompositor::vectorToIMEPopup(const Vector2D& pos, std::list<SIMEPopup>& popups) {
for (auto& popup : popups) {
auto surface = popup.pSurface->surface;
CBox box{
popup.realX,
popup.realY,
surface->current.width,
surface->current.height,
};
if (box.containsPoint(pos))
return &popup;
}
return nullptr;
}
CWindow* CCompositor::getWindowFromSurface(wlr_surface* pSurface) { CWindow* CCompositor::getWindowFromSurface(wlr_surface* pSurface) {
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (!w->m_bIsMapped || w->m_bFadingOut || !w->m_bMappedX11) if (!w->m_bIsMapped || w->m_bFadingOut || !w->m_bMappedX11)
@@ -1415,14 +1396,11 @@ void CCompositor::cleanupFadingOut(const int& monid) {
if (valid && !w->m_bReadyToDelete) if (valid && !w->m_bReadyToDelete)
continue; continue;
std::erase_if(g_pHyprOpenGL->m_mWindowFramebuffers, [&](const auto& other) { return other.first == w; });
w->m_bFadingOut = false; w->m_bFadingOut = false;
removeWindowFromVectorSafe(w); removeWindowFromVectorSafe(w);
std::erase(m_vWindowsFadingOut, w); std::erase(m_vWindowsFadingOut, w);
Debug::log(LOG, "Cleanup: destroyed a window"); Debug::log(LOG, "Cleanup: destroyed a window");
glFlush(); // to free mem NOW.
return; return;
} }
} }
@@ -1464,9 +1442,6 @@ void CCompositor::cleanupFadingOut(const int& monid) {
g_pHyprOpenGL->markBlurDirtyForMonitor(getMonitorFromID(monid)); g_pHyprOpenGL->markBlurDirtyForMonitor(getMonitorFromID(monid));
if (ls->fadingOut && ls->readyToDelete && !ls->alpha.isBeingAnimated()) { if (ls->fadingOut && ls->readyToDelete && !ls->alpha.isBeingAnimated()) {
g_pHyprOpenGL->m_mLayerFramebuffers[ls].release();
g_pHyprOpenGL->m_mLayerFramebuffers.erase(ls);
for (auto& m : m_vMonitors) { for (auto& m : m_vMonitors) {
for (auto& lsl : m->m_aLayerSurfaceLayers) { for (auto& lsl : m->m_aLayerSurfaceLayers) {
if (!lsl.empty() && std::find_if(lsl.begin(), lsl.end(), [&](std::unique_ptr<SLayerSurface>& other) { return other.get() == ls; }) != lsl.end()) { if (!lsl.empty() && std::find_if(lsl.begin(), lsl.end(), [&](std::unique_ptr<SLayerSurface>& other) { return other.get() == ls; }) != lsl.end()) {
@@ -2082,7 +2057,7 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
if (!m->output) if (!m->output)
continue; continue;
if (m->output->description && std::string(m->output->description).starts_with(DESCRIPTION)) { if (m->szDescription.starts_with(DESCRIPTION)) {
return m.get(); return m.get();
} }
} }
@@ -2561,6 +2536,8 @@ CWorkspace* CCompositor::createNewWorkspace(const int& id, const int& monid, con
PWORKSPACE->m_iID = id; PWORKSPACE->m_iID = id;
PWORKSPACE->m_iMonitorID = monID; PWORKSPACE->m_iMonitorID = monID;
PWORKSPACE->m_fAlpha.setValueAndWarp(0);
return PWORKSPACE; return PWORKSPACE;
} }
@@ -2792,4 +2769,4 @@ void CCompositor::setPreferredScaleForSurface(wlr_surface* pSurface, double scal
void CCompositor::setPreferredTransformForSurface(wlr_surface* pSurface, wl_output_transform transform) { void CCompositor::setPreferredTransformForSurface(wlr_surface* pSurface, wl_output_transform transform) {
wlr_surface_set_preferred_buffer_transform(pSurface, transform); wlr_surface_set_preferred_buffer_transform(pSurface, transform);
} }

View File

@@ -62,7 +62,6 @@ class CCompositor {
wlr_virtual_keyboard_manager_v1* m_sWLRVKeyboardMgr; wlr_virtual_keyboard_manager_v1* m_sWLRVKeyboardMgr;
wlr_output_manager_v1* m_sWLROutputMgr; wlr_output_manager_v1* m_sWLROutputMgr;
wlr_presentation* m_sWLRPresentation; wlr_presentation* m_sWLRPresentation;
wlr_input_inhibit_manager* m_sWLRInhibitMgr;
wlr_keyboard_shortcuts_inhibit_manager_v1* m_sWLRKbShInhibitMgr; wlr_keyboard_shortcuts_inhibit_manager_v1* m_sWLRKbShInhibitMgr;
wlr_egl* m_sWLREGL; wlr_egl* m_sWLREGL;
int m_iDRMFD; int m_iDRMFD;
@@ -137,10 +136,10 @@ class CCompositor {
void focusSurface(wlr_surface*, CWindow* pWindowOwner = nullptr); void focusSurface(wlr_surface*, CWindow* pWindowOwner = nullptr);
bool windowExists(CWindow*); bool windowExists(CWindow*);
bool windowValidMapped(CWindow*); bool windowValidMapped(CWindow*);
CWindow* vectorToWindow(const Vector2D&); CWindow* vectorToWindowIdeal(const Vector2D&, CWindow* pIgnoreWindow = nullptr); // used only for finding a window to focus on, basically a "findFocusableWindow"
CWindow* vectorToWindowIdeal(const Vector2D&); // used only for finding a window to focus on, basically a "findFocusableWindow"
CWindow* vectorToWindowTiled(const Vector2D&); CWindow* vectorToWindowTiled(const Vector2D&);
wlr_surface* vectorToLayerSurface(const Vector2D&, std::vector<std::unique_ptr<SLayerSurface>>*, Vector2D*, SLayerSurface**); wlr_surface* vectorToLayerSurface(const Vector2D&, std::vector<std::unique_ptr<SLayerSurface>>*, Vector2D*, SLayerSurface**);
SIMEPopup* vectorToIMEPopup(const Vector2D& pos, std::list<SIMEPopup>& popups);
wlr_surface* vectorWindowToSurface(const Vector2D&, CWindow*, Vector2D& sl); wlr_surface* vectorWindowToSurface(const Vector2D&, CWindow*, Vector2D& sl);
Vector2D vectorToSurfaceLocal(const Vector2D&, CWindow*, wlr_surface*); Vector2D vectorToSurfaceLocal(const Vector2D&, CWindow*, wlr_surface*);
CWindow* windowFromCursor(); CWindow* windowFromCursor();

View File

@@ -21,6 +21,12 @@ CWindow::~CWindow() {
g_pCompositor->m_pLastFocus = nullptr; g_pCompositor->m_pLastFocus = nullptr;
g_pCompositor->m_pLastWindow = nullptr; g_pCompositor->m_pLastWindow = nullptr;
} }
if (!g_pHyprOpenGL)
return;
g_pHyprRenderer->makeEGLCurrent();
std::erase_if(g_pHyprOpenGL->m_mWindowFramebuffers, [&](const auto& other) { return other.first == this; });
} }
SWindowDecorationExtents CWindow::getFullWindowExtents() { SWindowDecorationExtents CWindow::getFullWindowExtents() {
@@ -202,12 +208,16 @@ void CWindow::updateWindowDecos() {
void CWindow::addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco) { void CWindow::addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco) {
m_dWindowDecorations.emplace_back(std::move(deco)); m_dWindowDecorations.emplace_back(std::move(deco));
g_pDecorationPositioner->forceRecalcFor(this);
updateWindowDecos(); updateWindowDecos();
g_pLayoutManager->getCurrentLayout()->recalculateWindow(this);
} }
void CWindow::removeWindowDeco(IHyprWindowDecoration* deco) { void CWindow::removeWindowDeco(IHyprWindowDecoration* deco) {
m_vDecosToRemove.push_back(deco); m_vDecosToRemove.push_back(deco);
g_pDecorationPositioner->forceRecalcFor(this);
updateWindowDecos(); updateWindowDecos();
g_pLayoutManager->getCurrentLayout()->recalculateWindow(this);
} }
pid_t CWindow::getPID() { pid_t CWindow::getPID() {
@@ -587,6 +597,19 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
try { try {
m_sAdditionalConfigData.xray = configStringToInt(vars[1]); m_sAdditionalConfigData.xray = configStringToInt(vars[1]);
} catch (...) {} } catch (...) {}
} else if (r.szRule.starts_with("idleinhibit")) {
auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
if (IDLERULE == "none")
m_eIdleInhibitMode = IDLEINHIBIT_NONE;
else if (IDLERULE == "always")
m_eIdleInhibitMode = IDLEINHIBIT_ALWAYS;
else if (IDLERULE == "focus")
m_eIdleInhibitMode = IDLEINHIBIT_FOCUS;
else if (IDLERULE == "fullscreen")
m_eIdleInhibitMode = IDLEINHIBIT_FULLSCREEN;
else
Debug::log(ERR, "Rule idleinhibit: unknown mode {}", IDLERULE);
} }
} }
@@ -611,6 +634,7 @@ void CWindow::updateDynamicRules() {
m_sAdditionalConfigData.xray = -1; m_sAdditionalConfigData.xray = -1;
m_sAdditionalConfigData.forceTearing = false; m_sAdditionalConfigData.forceTearing = false;
m_sAdditionalConfigData.nearestNeighbor = false; m_sAdditionalConfigData.nearestNeighbor = false;
m_eIdleInhibitMode = IDLEINHIBIT_NONE;
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(this); const auto WINDOWRULES = g_pConfigManager->getMatchingRules(this);
for (auto& r : WINDOWRULES) { for (auto& r : WINDOWRULES) {

View File

@@ -1,6 +1,8 @@
#include "ConfigManager.hpp" #include "ConfigManager.hpp"
#include "../managers/KeybindManager.hpp" #include "../managers/KeybindManager.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include <string.h> #include <string.h>
#include <string> #include <string>
#include <sys/stat.h> #include <sys/stat.h>
@@ -31,6 +33,8 @@ CConfigManager::CConfigManager() {
configValues["group:groupbar:col.locked_active"].data = std::make_shared<CGradientValueData>(0x66ff5500); configValues["group:groupbar:col.locked_active"].data = std::make_shared<CGradientValueData>(0x66ff5500);
configValues["group:groupbar:col.locked_inactive"].data = std::make_shared<CGradientValueData>(0x66775500); configValues["group:groupbar:col.locked_inactive"].data = std::make_shared<CGradientValueData>(0x66775500);
Debug::log(LOG, "NOTE: further logs to stdout / logfile are disabled by default. Use debug:disable_logs and debug:enable_stdout_logs to override this.");
setDefaultVars(); setDefaultVars();
setDefaultAnimationVars(); setDefaultAnimationVars();
@@ -44,12 +48,11 @@ CConfigManager::CConfigManager() {
std::string CConfigManager::getConfigDir() { std::string CConfigManager::getConfigDir() {
static const char* xdgConfigHome = getenv("XDG_CONFIG_HOME"); static const char* xdgConfigHome = getenv("XDG_CONFIG_HOME");
std::string configPath;
if (!xdgConfigHome) if (xdgConfigHome && std::filesystem::path(xdgConfigHome).is_absolute())
configPath = getenv("HOME") + std::string("/.config"); return xdgConfigHome;
else
configPath = xdgConfigHome; return getenv("HOME") + std::string("/.config");
return configPath;
} }
std::string CConfigManager::getMainConfigPath() { std::string CConfigManager::getMainConfigPath() {
@@ -79,6 +82,7 @@ void CConfigManager::setDefaultVars() {
configValues["general:no_border_on_floating"].intValue = 0; configValues["general:no_border_on_floating"].intValue = 0;
configValues["general:gaps_in"].intValue = 5; configValues["general:gaps_in"].intValue = 5;
configValues["general:gaps_out"].intValue = 20; configValues["general:gaps_out"].intValue = 20;
configValues["general:gaps_workspaces"].intValue = 0;
((CGradientValueData*)configValues["general:col.active_border"].data.get())->reset(0xffffffff); ((CGradientValueData*)configValues["general:col.active_border"].data.get())->reset(0xffffffff);
((CGradientValueData*)configValues["general:col.inactive_border"].data.get())->reset(0xff444444); ((CGradientValueData*)configValues["general:col.inactive_border"].data.get())->reset(0xff444444);
((CGradientValueData*)configValues["general:col.nogroup_border"].data.get())->reset(0xff444444); ((CGradientValueData*)configValues["general:col.nogroup_border"].data.get())->reset(0xff444444);
@@ -145,7 +149,7 @@ void CConfigManager::setDefaultVars() {
configValues["debug:log_damage"].intValue = 0; configValues["debug:log_damage"].intValue = 0;
configValues["debug:overlay"].intValue = 0; configValues["debug:overlay"].intValue = 0;
configValues["debug:damage_blink"].intValue = 0; configValues["debug:damage_blink"].intValue = 0;
configValues["debug:disable_logs"].intValue = 0; configValues["debug:disable_logs"].intValue = 1;
configValues["debug:disable_time"].intValue = 1; configValues["debug:disable_time"].intValue = 1;
configValues["debug:enable_stdout_logs"].intValue = 0; configValues["debug:enable_stdout_logs"].intValue = 0;
configValues["debug:damage_tracking"].intValue = DAMAGE_TRACKING_FULL; configValues["debug:damage_tracking"].intValue = DAMAGE_TRACKING_FULL;
@@ -188,7 +192,7 @@ void CConfigManager::setDefaultVars() {
configValues["dwindle:force_split"].intValue = 0; configValues["dwindle:force_split"].intValue = 0;
configValues["dwindle:permanent_direction_override"].intValue = 0; configValues["dwindle:permanent_direction_override"].intValue = 0;
configValues["dwindle:preserve_split"].intValue = 0; configValues["dwindle:preserve_split"].intValue = 0;
configValues["dwindle:special_scale_factor"].floatValue = 0.8f; configValues["dwindle:special_scale_factor"].floatValue = 1.f;
configValues["dwindle:split_width_multiplier"].floatValue = 1.0f; configValues["dwindle:split_width_multiplier"].floatValue = 1.0f;
configValues["dwindle:no_gaps_when_only"].intValue = 0; configValues["dwindle:no_gaps_when_only"].intValue = 0;
configValues["dwindle:use_active_for_splits"].intValue = 1; configValues["dwindle:use_active_for_splits"].intValue = 1;
@@ -196,7 +200,7 @@ void CConfigManager::setDefaultVars() {
configValues["dwindle:smart_split"].intValue = 0; configValues["dwindle:smart_split"].intValue = 0;
configValues["dwindle:smart_resizing"].intValue = 1; configValues["dwindle:smart_resizing"].intValue = 1;
configValues["master:special_scale_factor"].floatValue = 0.8f; configValues["master:special_scale_factor"].floatValue = 1.f;
configValues["master:mfact"].floatValue = 0.55f; configValues["master:mfact"].floatValue = 0.55f;
configValues["master:new_is_master"].intValue = 1; configValues["master:new_is_master"].intValue = 1;
configValues["master:always_center_master"].intValue = 0; configValues["master:always_center_master"].intValue = 0;
@@ -208,7 +212,8 @@ void CConfigManager::setDefaultVars() {
configValues["master:smart_resizing"].intValue = 1; configValues["master:smart_resizing"].intValue = 1;
configValues["master:drop_at_cursor"].intValue = 1; configValues["master:drop_at_cursor"].intValue = 1;
configValues["animations:enabled"].intValue = 1; configValues["animations:enabled"].intValue = 1;
configValues["animations:first_launch_animation"].intValue = 1;
configValues["input:follow_mouse"].intValue = 1; configValues["input:follow_mouse"].intValue = 1;
configValues["input:mouse_refocus"].intValue = 1; configValues["input:mouse_refocus"].intValue = 1;
@@ -1164,13 +1169,13 @@ void CConfigManager::handleWorkspaceRules(const std::string& command, const std:
auto rules = value.substr(FIRST_DELIM + 1); auto rules = value.substr(FIRST_DELIM + 1);
SWorkspaceRule wsRule; SWorkspaceRule wsRule;
wsRule.workspaceString = first_ident; wsRule.workspaceString = first_ident;
if (id == INT_MAX) { if (id == WORKSPACE_INVALID) {
// it could be the monitor. If so, second value MUST be // it could be the monitor. If so, second value MUST be
// the workspace. // the workspace.
const auto WORKSPACE_DELIM = value.find_first_of(',', FIRST_DELIM + 1); const auto WORKSPACE_DELIM = value.find_first_of(',', FIRST_DELIM + 1);
auto wsIdent = removeBeginEndSpacesTabs(value.substr(FIRST_DELIM + 1, (WORKSPACE_DELIM - FIRST_DELIM - 1))); auto wsIdent = removeBeginEndSpacesTabs(value.substr(FIRST_DELIM + 1, (WORKSPACE_DELIM - FIRST_DELIM - 1)));
id = getWorkspaceIDFromString(wsIdent, name); id = getWorkspaceIDFromString(wsIdent, name);
if (id == INT_MAX) { if (id == WORKSPACE_INVALID) {
Debug::log(ERR, "Invalid workspace identifier found: {}", wsIdent); Debug::log(ERR, "Invalid workspace identifier found: {}", wsIdent);
parseError = "Invalid workspace identifier found: " + wsIdent; parseError = "Invalid workspace identifier found: " + wsIdent;
return; return;
@@ -1208,6 +1213,8 @@ void CConfigManager::handleWorkspaceRules(const std::string& command, const std:
wsRule.isPersistent = configStringToInt(rule.substr(delim + 11)); wsRule.isPersistent = configStringToInt(rule.substr(delim + 11));
else if ((delim = rule.find(ruleOnCreatedEmtpy)) != std::string::npos) else if ((delim = rule.find(ruleOnCreatedEmtpy)) != std::string::npos)
wsRule.onCreatedEmptyRunCmd = cleanCmdForWorkspace(name, rule.substr(delim + ruleOnCreatedEmtpyLen)); wsRule.onCreatedEmptyRunCmd = cleanCmdForWorkspace(name, rule.substr(delim + ruleOnCreatedEmtpyLen));
else if ((delim = rule.find("layoutopt:orientation:")) != std::string::npos)
wsRule.layoutopts["orientation"] = rule.substr(delim + 22);
}; };
size_t pos = 0; size_t pos = 0;
@@ -1255,7 +1262,12 @@ void CConfigManager::handleSource(const std::string& command, const std::string&
for (size_t i = 0; i < glob_buf->gl_pathc; i++) { for (size_t i = 0; i < glob_buf->gl_pathc; i++) {
auto value = absolutePath(glob_buf->gl_pathv[i], configCurrentPath); auto value = absolutePath(glob_buf->gl_pathv[i], configCurrentPath);
if (!std::filesystem::exists(value)) { if (!std::filesystem::is_regular_file(value)) {
if (std::filesystem::exists(value)) {
Debug::log(WARN, "source= skipping non-file {}", value);
continue;
}
Debug::log(ERR, "source= file doesnt exist"); Debug::log(ERR, "source= file doesnt exist");
parseError = "source file " + value + " doesn't exist!"; parseError = "source file " + value + " doesn't exist!";
return; return;
@@ -1509,7 +1521,7 @@ void CConfigManager::parseLine(std::string& line) {
const auto LASTSEP = currentCategory.find_last_of(':'); const auto LASTSEP = currentCategory.find_last_of(':');
if (LASTSEP == std::string::npos || currentCategory.contains("device")) if (LASTSEP == std::string::npos || currentCategory.starts_with("device"))
currentCategory = ""; currentCategory = "";
else else
currentCategory = currentCategory.substr(0, LASTSEP); currentCategory = currentCategory.substr(0, LASTSEP);
@@ -1562,20 +1574,20 @@ void CConfigManager::loadConfigLoadVars() {
std::string mainConfigPath = getMainConfigPath(); std::string mainConfigPath = getMainConfigPath();
Debug::log(LOG, "Using config: {}", mainConfigPath); Debug::log(LOG, "Using config: {}", mainConfigPath);
configPaths.push_back(mainConfigPath); configPaths.push_back(mainConfigPath);
std::string configPath = mainConfigPath.substr(0, mainConfigPath.find_last_of('/'));
// find_last_of never returns npos since main_config at least has /hypr/
if (!std::filesystem::is_directory(configPath)) { if (g_pCompositor->explicitConfigPath.empty() && !std::filesystem::exists(mainConfigPath)) {
Debug::log(WARN, "Creating config home directory"); std::string configPath = std::filesystem::path(mainConfigPath).parent_path();
try {
std::filesystem::create_directories(configPath); if (!std::filesystem::is_directory(configPath)) {
} catch (...) { Debug::log(WARN, "Creating config home directory");
parseError = "Broken config file! (Could not create config directory)"; try {
return; std::filesystem::create_directories(configPath);
} catch (...) {
parseError = "Broken config file! (Could not create config directory)";
return;
}
} }
}
if (!std::filesystem::exists(mainConfigPath)) {
Debug::log(WARN, "No config file found; attempting to generate."); Debug::log(WARN, "No config file found; attempting to generate.");
std::ofstream ofs; std::ofstream ofs;
ofs.open(mainConfigPath, std::ios::trunc); ofs.open(mainConfigPath, std::ios::trunc);
@@ -1667,6 +1679,9 @@ void CConfigManager::loadConfigLoadVars() {
ensureVRR(); ensureVRR();
} }
if (!isFirstLaunch && !g_pCompositor->m_bUnsafeState)
refreshGroupBarGradients();
// Updates dynamic window and workspace rules // Updates dynamic window and workspace rules
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped) if (!w->m_bIsMapped)
@@ -2073,7 +2088,7 @@ void CConfigManager::performMonitorReload() {
if (!m->output || m->isUnsafeFallback) if (!m->output || m->isUnsafeFallback)
continue; continue;
auto rule = getMonitorRuleFor(m->szName, m->output->description ? m->output->description : ""); auto rule = getMonitorRuleFor(m->szName, m->szDescription);
if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule)) { if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule)) {
overAgain = true; overAgain = true;
@@ -2154,7 +2169,7 @@ void CConfigManager::ensureMonitorStatus() {
if (!rm->output || rm->isUnsafeFallback) if (!rm->output || rm->isUnsafeFallback)
continue; continue;
auto rule = getMonitorRuleFor(rm->szName, rm->output->description ? rm->output->description : ""); auto rule = getMonitorRuleFor(rm->szName, rm->szDescription);
if (rule.disabled == rm->m_bEnabled) if (rule.disabled == rm->m_bEnabled)
g_pHyprRenderer->applyMonitorRule(rm.get(), &rule); g_pHyprRenderer->applyMonitorRule(rm.get(), &rule);

View File

@@ -37,20 +37,21 @@ struct SConfigValue {
}; };
struct SWorkspaceRule { struct SWorkspaceRule {
std::string monitor = ""; std::string monitor = "";
std::string workspaceString = ""; std::string workspaceString = "";
std::string workspaceName = ""; std::string workspaceName = "";
int workspaceId = -1; int workspaceId = -1;
bool isDefault = false; bool isDefault = false;
bool isPersistent = false; bool isPersistent = false;
std::optional<int64_t> gapsIn; std::optional<int64_t> gapsIn;
std::optional<int64_t> gapsOut; std::optional<int64_t> gapsOut;
std::optional<int64_t> borderSize; std::optional<int64_t> borderSize;
std::optional<int> border; std::optional<int> border;
std::optional<int> rounding; std::optional<int> rounding;
std::optional<int> decorate; std::optional<int> decorate;
std::optional<int> shadow; std::optional<int> shadow;
std::optional<std::string> onCreatedEmptyRunCmd; std::optional<std::string> onCreatedEmptyRunCmd;
std::map<std::string, std::any> layoutopts;
}; };
struct SMonitorAdditionalReservedArea { struct SMonitorAdditionalReservedArea {

View File

@@ -28,6 +28,11 @@ monitor=,preferred,auto,auto
# Source a file (multi-file configs) # Source a file (multi-file configs)
# source = ~/.config/hypr/myColors.conf # source = ~/.config/hypr/myColors.conf
# Set programs that you use
$terminal = kitty
$fileManager = dolphin
$menu = wofi --show drun
# Some default env vars. # Some default env vars.
env = XCURSOR_SIZE,24 env = XCURSOR_SIZE,24
@@ -127,18 +132,19 @@ device:epic-mouse-v1 {
# Example windowrule v2 # Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$ # windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more # See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
windowrulev2 = nomaximizerequest, class:.* # You'll probably like this.
# See https://wiki.hyprland.org/Configuring/Keywords/ for more # See https://wiki.hyprland.org/Configuring/Keywords/ for more
$mainMod = SUPER $mainMod = SUPER
# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more # Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
bind = $mainMod, Q, exec, kitty bind = $mainMod, Q, exec, $terminal
bind = $mainMod, C, killactive, bind = $mainMod, C, killactive,
bind = $mainMod, M, exit, bind = $mainMod, M, exit,
bind = $mainMod, E, exec, dolphin bind = $mainMod, E, exec, $fileManager
bind = $mainMod, V, togglefloating, bind = $mainMod, V, togglefloating,
bind = $mainMod, R, exec, wofi --show drun bind = $mainMod, R, exec, $menu
bind = $mainMod, P, pseudo, # dwindle bind = $mainMod, P, pseudo, # dwindle
bind = $mainMod, J, togglesplit, # dwindle bind = $mainMod, J, togglesplit, # dwindle

View File

@@ -119,7 +119,7 @@ void CrashReporter::createAndSaveCrash(int sig) {
finalCrashReport += "\n\nLog tail:\n"; finalCrashReport += "\n\nLog tail:\n";
finalCrashReport += execAndGet(("cat \"" + Debug::logFile + "\" | tail -n 50").c_str()); finalCrashReport += Debug::rollingLog;
const auto HOME = getenv("HOME"); const auto HOME = getenv("HOME");
const auto CACHE_HOME = getenv("XDG_CACHE_HOME"); const auto CACHE_HOME = getenv("XDG_CACHE_HOME");

View File

@@ -28,13 +28,22 @@ static std::string getWorkspaceNameFromSpecialID(const int workspaceID) {
return workspace->m_szName; return workspace->m_szName;
} }
std::string monitorsRequest(HyprCtl::eHyprCtlOutputFormat format) { std::string monitorsRequest(std::string request, HyprCtl::eHyprCtlOutputFormat format) {
CVarList vars(request, 0, ' ');
auto allMonitors = false;
if (vars.size() > 2)
return "too many args";
if (vars.size() == 2 && vars[1] == "all")
allMonitors = true;
std::string result = ""; std::string result = "";
if (format == HyprCtl::FORMAT_JSON) { if (format == HyprCtl::FORMAT_JSON) {
result += "["; result += "[";
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) {
if (!m->output) if (!m->output || m->ID == -1ull)
continue; continue;
result += std::format( result += std::format(
@@ -66,10 +75,11 @@ std::string monitorsRequest(HyprCtl::eHyprCtlOutputFormat format) {
"vrr": {}, "vrr": {},
"activelyTearing": {} "activelyTearing": {}
}},)#", }},)#",
m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->output->description ? m->output->description : ""), (m->output->make ? m->output->make : ""), m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->szDescription), (m->output->make ? m->output->make : ""),
(m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate,
(int)m->vecPosition.x, (int)m->vecPosition.y, m->activeWorkspace, escapeJSONStrings(g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName), (int)m->vecPosition.x, (int)m->vecPosition.y, m->activeWorkspace,
m->specialWorkspaceID, escapeJSONStrings(getWorkspaceNameFromSpecialID(m->specialWorkspaceID)), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (m->activeWorkspace == -1 ? "" : escapeJSONStrings(g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName)), m->specialWorkspaceID,
escapeJSONStrings(getWorkspaceNameFromSpecialID(m->specialWorkspaceID)), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y,
(int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "true" : "false"), (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "true" : "false"),
(m->dpmsStatus ? "true" : "false"), (m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED ? "true" : "false"), (m->dpmsStatus ? "true" : "false"), (m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED ? "true" : "false"),
m->tearingState.activelyTearing ? "true" : "false"); m->tearingState.activelyTearing ? "true" : "false");
@@ -79,21 +89,21 @@ std::string monitorsRequest(HyprCtl::eHyprCtlOutputFormat format) {
result += "]"; result += "]";
} else { } else {
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) {
if (!m->output) if (!m->output || m->ID == -1ull)
continue; continue;
result += result += std::format(
std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\tspecial " "Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\tspecial "
"workspace: {} ({})\n\treserved: {} " "workspace: {} ({})\n\treserved: {} "
"{} {} {}\n\tscale: {:.2f}\n\ttransform: " "{} {} {}\n\tscale: {:.2f}\n\ttransform: "
"{}\n\tfocused: {}\n\tdpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\n", "{}\n\tfocused: {}\n\tdpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\n",
m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y,
(m->output->description ? m->output->description : ""), (m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""), m->szDescription, (m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""),
(m->output->serial ? m->output->serial : ""), m->activeWorkspace, g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName, m->specialWorkspaceID, (m->output->serial ? m->output->serial : ""), m->activeWorkspace, (m->activeWorkspace == -1 ? "" : g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName),
getWorkspaceNameFromSpecialID(m->specialWorkspaceID), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, m->specialWorkspaceID, getWorkspaceNameFromSpecialID(m->specialWorkspaceID), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y,
(int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "yes" : "no"),
(int)(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED), m->tearingState.activelyTearing); (int)m->dpmsStatus, (int)(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED), m->tearingState.activelyTearing);
} }
} }
@@ -250,7 +260,7 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, HyprCtl::eHyprC
std::string result = std::format(R"#({{ std::string result = std::format(R"#({{
"workspaceString": "{}"{}{}{}{}{}{}{}{} "workspaceString": "{}"{}{}{}{}{}{}{}{}
}})#", }})#",
escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, borderSize, border, rounding, decorate, shadow); escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, borderSize, border, rounding, decorate, shadow);
return result; return result;
} else { } else {
@@ -266,7 +276,7 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, HyprCtl::eHyprC
const std::string shadow = std::format("\tshadow: {}\n", (bool)(r.shadow) ? boolToString(r.shadow.value()) : "<unset>"); const std::string shadow = std::format("\tshadow: {}\n", (bool)(r.shadow) ? boolToString(r.shadow.value()) : "<unset>");
std::string result = std::format("Workspace rule {}:\n{}{}{}{}{}{}{}{}{}{}\n", escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, std::string result = std::format("Workspace rule {}:\n{}{}{}{}{}{}{}{}{}{}\n", escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut,
borderSize, border, rounding, decorate, shadow); borderSize, border, rounding, decorate, shadow);
return result; return result;
} }
@@ -413,6 +423,28 @@ std::string layersRequest(HyprCtl::eHyprCtlOutputFormat format) {
return result; return result;
} }
std::string layoutsRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string result = "";
if (format == HyprCtl::FORMAT_JSON) {
result += "[";
for (auto& m : g_pLayoutManager->getAllLayoutNames()) {
result += std::format(
R"#(
"{}",)#",
m);
}
trimTrailingComma(result);
result += "\n]\n";
} else {
for (auto& m : g_pLayoutManager->getAllLayoutNames()) {
result += std::format("{}\n", m);
}
}
return result;
}
std::string devicesRequest(HyprCtl::eHyprCtlOutputFormat format) { std::string devicesRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string result = ""; std::string result = "";
@@ -625,6 +657,20 @@ std::string animationsRequest(HyprCtl::eHyprCtlOutputFormat format) {
return ret; return ret;
} }
std::string rollinglogRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string result = "";
if (format == HyprCtl::FORMAT_JSON) {
result += "[\n\"log\":\"";
result += escapeJSONStrings(Debug::rollingLog);
result += "\"]";
} else {
result = Debug::rollingLog;
}
return result;
}
std::string globalShortcutsRequest(HyprCtl::eHyprCtlOutputFormat format) { std::string globalShortcutsRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string ret = ""; std::string ret = "";
const auto SHORTCUTS = g_pProtocolManager->m_pGlobalShortcutsProtocolManager->getAllShortcuts(); const auto SHORTCUTS = g_pProtocolManager->m_pGlobalShortcutsProtocolManager->getAllShortcuts();
@@ -1230,7 +1276,7 @@ std::string dispatchPlugin(std::string request) {
const auto PLUGIN = g_pPluginSystem->loadPlugin(PATH); const auto PLUGIN = g_pPluginSystem->loadPlugin(PATH);
if (!PLUGIN) if (!PLUGIN)
return "error in loading plugin"; return "error in loading plugin, last error: " + g_pPluginSystem->m_szLastError;
} else if (OPERATION == "unload") { } else if (OPERATION == "unload") {
if (vars.size() < 3) if (vars.size() < 3)
return "not enough args"; return "not enough args";
@@ -1319,8 +1365,8 @@ std::string getReply(std::string request) {
request = request.substr(sepIndex + 1); // remove flags and separator so we can compare the rest of the string request = request.substr(sepIndex + 1); // remove flags and separator so we can compare the rest of the string
} }
if (request == "monitors") if (request.starts_with("monitors"))
return monitorsRequest(format); return monitorsRequest(request, format);
else if (request == "workspaces") else if (request == "workspaces")
return workspacesRequest(format); return workspacesRequest(format);
else if (request == "workspacerules") else if (request == "workspacerules")
@@ -1351,6 +1397,10 @@ std::string getReply(std::string request) {
return globalShortcutsRequest(format); return globalShortcutsRequest(format);
else if (request == "animations") else if (request == "animations")
return animationsRequest(format); return animationsRequest(format);
else if (request == "rollinglog")
return rollinglogRequest(format);
else if (request == "layouts")
return layoutsRequest(format);
else if (request.starts_with("plugin")) else if (request.starts_with("plugin"))
return dispatchPlugin(request); return dispatchPlugin(request);
else if (request.starts_with("notify")) else if (request.starts_with("notify"))
@@ -1385,14 +1435,14 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP) if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP)
return 0; return 0;
sockaddr_in clientAddress; sockaddr_in clientAddress;
socklen_t clientSize = sizeof(clientAddress); socklen_t clientSize = sizeof(clientAddress);
const auto ACCEPTEDCONNECTION = accept4(HyprCtl::iSocketFD, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC); const auto ACCEPTEDCONNECTION = accept4(HyprCtl::iSocketFD, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC);
char readBuffer[1024]; std::array<char, 1024> readBuffer;
fd_set fdset; fd_set fdset;
FD_ZERO(&fdset); FD_ZERO(&fdset);
FD_SET(ACCEPTEDCONNECTION, &fdset); FD_SET(ACCEPTEDCONNECTION, &fdset);
timeval timeout = {.tv_sec = 0, .tv_usec = 5000}; timeval timeout = {.tv_sec = 0, .tv_usec = 5000};
@@ -1403,10 +1453,17 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
return 0; return 0;
} }
auto messageSize = read(ACCEPTEDCONNECTION, readBuffer, 1024); std::string request;
readBuffer[messageSize == 1024 ? 1023 : messageSize] = '\0'; while (true) {
readBuffer.fill(0);
std::string request(readBuffer); auto messageSize = read(ACCEPTEDCONNECTION, readBuffer.data(), 1023);
if (messageSize < 1)
break;
std::string recvd = readBuffer.data();
request += recvd;
if (messageSize < 1023)
break;
}
std::string reply = ""; std::string reply = "";

View File

@@ -19,7 +19,8 @@ namespace HyprCtl {
inline int iSocketFD = -1; inline int iSocketFD = -1;
enum eHyprCtlOutputFormat { enum eHyprCtlOutputFormat
{
FORMAT_NORMAL = 0, FORMAT_NORMAL = 0,
FORMAT_JSON FORMAT_JSON
}; };

View File

@@ -10,25 +10,24 @@ void Debug::init(const std::string& IS) {
} }
void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) { void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) {
if (disableLogs && *disableLogs)
return;
if (level > wlr_log_get_verbosity()) if (level > wlr_log_get_verbosity())
return; return;
char* outputStr = nullptr; char* outputStr = nullptr;
std::ofstream ofs;
ofs.open(logFile, std::ios::out | std::ios::app);
vasprintf(&outputStr, fmt, args); vasprintf(&outputStr, fmt, args);
std::string output = std::string(outputStr); std::string output = std::string(outputStr);
free(outputStr); free(outputStr);
ofs << "[wlr] " << output << "\n"; rollingLog += output + "\n";
ofs.close(); if (!disableLogs || !*disableLogs) {
std::ofstream ofs;
ofs.open(logFile, std::ios::out | std::ios::app);
ofs << "[wlr] " << output << "\n";
ofs.close();
}
if (!disableStdout) if (!disableStdout)
std::cout << output << "\n"; std::cout << output << "\n";

View File

@@ -7,9 +7,11 @@
#include "../includes.hpp" #include "../includes.hpp"
#include "../helpers/MiscFunctions.hpp" #include "../helpers/MiscFunctions.hpp"
#define LOGMESSAGESIZE 1024 #define LOGMESSAGESIZE 1024
#define ROLLING_LOG_SIZE 4096
enum LogLevel { enum LogLevel
{
NONE = -1, NONE = -1,
LOG = 0, LOG = 0,
WARN, WARN,
@@ -25,14 +27,17 @@ namespace Debug {
inline int64_t* disableTime = nullptr; inline int64_t* disableTime = nullptr;
inline bool disableStdout = false; inline bool disableStdout = false;
inline bool trace = false; inline bool trace = false;
inline bool shuttingDown = false;
inline std::string rollingLog = ""; // rolling log contains the ROLLING_LOG_SIZE tail of the log
void init(const std::string& IS); void init(const std::string& IS);
template <typename... Args> template <typename... Args>
void log(LogLevel level, std::format_string<Args...> fmt, Args&&... args) { void log(LogLevel level, std::format_string<Args...> fmt, Args&&... args) {
if (disableLogs && *disableLogs) if (level == TRACE && !trace)
return; return;
if (level == TRACE && !trace) if (shuttingDown)
return; return;
std::string logMsg = ""; std::string logMsg = "";
@@ -47,10 +52,6 @@ namespace Debug {
default: break; default: break;
} }
// log to a file
std::ofstream ofs;
ofs.open(logFile, std::ios::out | std::ios::app);
// print date and time to the ofs // print date and time to the ofs
if (disableTime && !*disableTime) { if (disableTime && !*disableTime) {
#ifndef _LIBCPP_VERSION #ifndef _LIBCPP_VERSION
@@ -69,9 +70,18 @@ namespace Debug {
// 3. this is actually what std::format in stdlib does // 3. this is actually what std::format in stdlib does
logMsg += std::vformat(fmt.get(), std::make_format_args(args...)); logMsg += std::vformat(fmt.get(), std::make_format_args(args...));
ofs << logMsg << "\n"; rollingLog += logMsg + "\n";
if (rollingLog.size() > ROLLING_LOG_SIZE)
rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE);
ofs.close(); if (!disableLogs || !*disableLogs) {
// log to a file
std::ofstream ofs;
ofs.open(logFile, std::ios::out | std::ios::app);
ofs << logMsg << "\n";
ofs.close();
}
// log it to the stdout too. // log it to the stdout too.
if (!disableStdout) if (!disableStdout)

View File

@@ -13,15 +13,6 @@ inline PFNGLGETQUERYOBJECTUI64VEXTPROC glGetQueryObjectui64v;
#include "../../subprojects/tracy/public/tracy/TracyOpenGL.hpp" #include "../../subprojects/tracy/public/tracy/TracyOpenGL.hpp"
inline void loadGLProc(void* pProc, const char* name) {
void* proc = (void*)eglGetProcAddress(name);
if (proc == NULL) {
Debug::log(CRIT, "[Tracy GPU Profiling] eglGetProcAddress({}) failed", name);
abort();
}
*(void**)pProc = proc;
}
#define TRACY_GPU_CONTEXT TracyGpuContext #define TRACY_GPU_CONTEXT TracyGpuContext
#define TRACY_GPU_ZONE(e) TracyGpuZone(e) #define TRACY_GPU_ZONE(e) TracyGpuZone(e)
#define TRACY_GPU_COLLECT TracyGpuCollect #define TRACY_GPU_COLLECT TracyGpuCollect

View File

@@ -42,7 +42,7 @@ namespace Events {
DYNLISTENFUNC(repositionPopupXDG); DYNLISTENFUNC(repositionPopupXDG);
// Surface XDG (window) // Surface XDG (window)
LISTENER(newXDGSurface); LISTENER(newXDGToplevel);
LISTENER(activateXDG); LISTENER(activateXDG);
// Window events // Window events
@@ -121,10 +121,6 @@ namespace Events {
DYNLISTENFUNC(destroyDragIcon); DYNLISTENFUNC(destroyDragIcon);
DYNLISTENFUNC(commitDragIcon); DYNLISTENFUNC(commitDragIcon);
// Inhibit
LISTENER(InhibitActivate);
LISTENER(InhibitDeactivate);
// Deco XDG // Deco XDG
LISTENER(NewXDGDeco); LISTENER(NewXDGDeco);

View File

@@ -254,6 +254,8 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
geomFixed = {layersurface->geometry.x + (int)PMONITOR->vecPosition.x, layersurface->geometry.y + (int)PMONITOR->vecPosition.y, geomFixed = {layersurface->geometry.x + (int)PMONITOR->vecPosition.x, layersurface->geometry.y + (int)PMONITOR->vecPosition.y,
(int)layersurface->layerSurface->surface->current.width, (int)layersurface->layerSurface->surface->current.height}; (int)layersurface->layerSurface->surface->current.width, (int)layersurface->layerSurface->surface->current.height};
g_pHyprRenderer->damageBox(&geomFixed); g_pHyprRenderer->damageBox(&geomFixed);
g_pInputManager->simulateMouseMovement();
} }
void Events::listener_commitLayerSurface(void* owner, void* data) { void Events::listener_commitLayerSurface(void* owner, void* data) {

View File

@@ -156,20 +156,6 @@ void Events::listener_commitDragIcon(void* owner, void* data) {
Debug::log(LOG, "Drag icon committed."); Debug::log(LOG, "Drag icon committed.");
} }
void Events::listener_InhibitActivate(wl_listener* listener, void* data) {
Debug::log(LOG, "Activated exclusive for {:x}.", (uintptr_t)g_pCompositor->m_sSeat.exclusiveClient);
g_pInputManager->refocus();
g_pCompositor->m_sSeat.exclusiveClient = g_pCompositor->m_sWLRInhibitMgr->active_client;
}
void Events::listener_InhibitDeactivate(wl_listener* listener, void* data) {
Debug::log(LOG, "Deactivated exclusive.");
g_pCompositor->m_sSeat.exclusiveClient = nullptr;
g_pInputManager->refocus();
}
void Events::listener_RendererDestroy(wl_listener* listener, void* data) { void Events::listener_RendererDestroy(wl_listener* listener, void* data) {
Debug::log(LOG, "!!Renderer destroyed!!"); Debug::log(LOG, "!!Renderer destroyed!!");
} }

View File

@@ -22,10 +22,13 @@ void Events::listener_change(wl_listener* listener, void* data) {
if (!CONFIG) if (!CONFIG)
return; return;
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vRealMonitors) {
if (!m->output) if (!m->output)
continue; continue;
if (g_pCompositor->m_pUnsafeOutput == m.get())
continue;
const auto CONFIGHEAD = wlr_output_configuration_head_v1_create(CONFIG, m->output); const auto CONFIGHEAD = wlr_output_configuration_head_v1_create(CONFIG, m->output);
CBox BOX; CBox BOX;
@@ -195,7 +198,7 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
Debug::log(LOG, "Destroy called for monitor {}", pMonitor->output->name); Debug::log(LOG, "Destroy called for monitor {}", pMonitor->output->name);
pMonitor->onDisconnect(); pMonitor->onDisconnect(true);
pMonitor->output = nullptr; pMonitor->output = nullptr;
pMonitor->m_bRenderingInitPassed = false; pMonitor->m_bRenderingInitPassed = false;

View File

@@ -246,20 +246,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
} }
vPrev = v; vPrev = v;
} }
} else if (r.szRule.starts_with("idleinhibit")) {
auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
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 {}", IDLERULE);
}
} }
PWINDOW->applyDynamicRule(r); PWINDOW->applyDynamicRule(r);
} }
@@ -279,7 +265,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
std::string requestedWorkspaceName; std::string requestedWorkspaceName;
const int REQUESTEDWORKSPACEID = getWorkspaceIDFromString(WORKSPACEARGS.join(" ", 0, workspaceSilent ? WORKSPACEARGS.size() - 1 : 0), requestedWorkspaceName); const int REQUESTEDWORKSPACEID = getWorkspaceIDFromString(WORKSPACEARGS.join(" ", 0, workspaceSilent ? WORKSPACEARGS.size() - 1 : 0), requestedWorkspaceName);
if (REQUESTEDWORKSPACEID != INT_MAX) { if (REQUESTEDWORKSPACEID != WORKSPACE_INVALID) {
auto pWorkspace = g_pCompositor->getWorkspaceByID(REQUESTEDWORKSPACEID); auto pWorkspace = g_pCompositor->getWorkspaceByID(REQUESTEDWORKSPACEID);
if (!pWorkspace) if (!pWorkspace)
@@ -1183,14 +1169,12 @@ void Events::listener_surfaceXWayland(wl_listener* listener, void* data) {
PNEWWINDOW->hyprListener_configureX11.initCallback(&XWSURFACE->events.request_configure, &Events::listener_configureX11, PNEWWINDOW, "XWayland Window"); PNEWWINDOW->hyprListener_configureX11.initCallback(&XWSURFACE->events.request_configure, &Events::listener_configureX11, PNEWWINDOW, "XWayland Window");
} }
void Events::listener_newXDGSurface(wl_listener* listener, void* data) { void Events::listener_newXDGToplevel(wl_listener* listener, void* data) {
// A window got opened // A window got opened
const auto XDGSURFACE = (wlr_xdg_surface*)data; const auto XDGTOPLEVEL = (wlr_xdg_toplevel*)data;
const auto XDGSURFACE = XDGTOPLEVEL->base;
if (XDGSURFACE->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) Debug::log(LOG, "New XDG Toplevel created. (class: {})", XDGSURFACE->toplevel->app_id ? XDGSURFACE->toplevel->app_id : "null");
return;
Debug::log(LOG, "New XDG Surface created. (class: {})", XDGSURFACE->toplevel->app_id ? XDGSURFACE->toplevel->app_id : "null");
const auto PNEWWINDOW = g_pCompositor->m_vWindows.emplace_back(std::make_unique<CWindow>()).get(); const auto PNEWWINDOW = g_pCompositor->m_vWindows.emplace_back(std::make_unique<CWindow>()).get();
PNEWWINDOW->m_uSurface.xdg = XDGSURFACE; PNEWWINDOW->m_uSurface.xdg = XDGSURFACE;

View File

@@ -112,6 +112,10 @@ CBox CBox::roundInternal() {
return CBox{std::floor(x), std::floor(y), std::floor(newW), std::floor(newH)}; return CBox{std::floor(x), std::floor(y), std::floor(newW), std::floor(newH)};
} }
CBox CBox::copy() const {
return CBox{*this};
}
Vector2D CBox::pos() const { Vector2D CBox::pos() const {
return {x, y}; return {x, y};
} }

View File

@@ -52,6 +52,8 @@ class CBox {
CBox& addExtents(const SWindowDecorationExtents& e); CBox& addExtents(const SWindowDecorationExtents& e);
CBox& expand(const double& value); CBox& expand(const double& value);
CBox copy() const;
SWindowDecorationExtents extentsFrom(const CBox&); // this is the big box SWindowDecorationExtents extentsFrom(const CBox&); // this is the big box
Vector2D middle() const; Vector2D middle() const;

View File

@@ -204,12 +204,12 @@ std::string removeBeginEndSpacesTabs(std::string str) {
return str; return str;
} }
float getPlusMinusKeywordResult(std::string source, float relative) { std::optional<float> getPlusMinusKeywordResult(std::string source, float relative) {
try { try {
return relative + stof(source); return relative + stof(source);
} catch (...) { } catch (...) {
Debug::log(ERR, "Invalid arg \"{}\" in getPlusMinusKeywordResult!", source); Debug::log(ERR, "Invalid arg \"{}\" in getPlusMinusKeywordResult!", source);
return INT_MAX; return {};
} }
} }
@@ -247,7 +247,7 @@ bool isDirection(const char& arg) {
} }
int getWorkspaceIDFromString(const std::string& in, std::string& outName) { int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
int result = INT_MAX; int result = WORKSPACE_INVALID;
if (in.starts_with("special")) { if (in.starts_with("special")) {
outName = "special"; outName = "special";
@@ -280,17 +280,17 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
} }
} else if (in.starts_with("prev")) { } else if (in.starts_with("prev")) {
if (!g_pCompositor->m_pLastMonitor) if (!g_pCompositor->m_pLastMonitor)
return INT_MAX; return WORKSPACE_INVALID;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace);
if (!PWORKSPACE) if (!PWORKSPACE)
return INT_MAX; return WORKSPACE_INVALID;
const auto PLASTWORKSPACE = g_pCompositor->getWorkspaceByID(PWORKSPACE->m_sPrevWorkspace.iID); const auto PLASTWORKSPACE = g_pCompositor->getWorkspaceByID(PWORKSPACE->m_sPrevWorkspace.iID);
if (!PLASTWORKSPACE) if (!PLASTWORKSPACE)
return INT_MAX; return WORKSPACE_INVALID;
outName = PLASTWORKSPACE->m_szName; outName = PLASTWORKSPACE->m_szName;
return PLASTWORKSPACE->m_iID; return PLASTWORKSPACE->m_iID;
@@ -298,10 +298,15 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
if (in[0] == 'r' && (in[1] == '-' || in[1] == '+') && isNumber(in.substr(2))) { if (in[0] == 'r' && (in[1] == '-' || in[1] == '+') && isNumber(in.substr(2))) {
if (!g_pCompositor->m_pLastMonitor) { if (!g_pCompositor->m_pLastMonitor) {
Debug::log(ERR, "Relative monitor workspace on monitor null!"); Debug::log(ERR, "Relative monitor workspace on monitor null!");
result = INT_MAX; return WORKSPACE_INVALID;
return result;
} }
result = (int)getPlusMinusKeywordResult(in.substr(1), 0);
const auto PLUSMINUSRESULT = getPlusMinusKeywordResult(in.substr(1), 0);
if (!PLUSMINUSRESULT.has_value())
return WORKSPACE_INVALID;
result = (int)PLUSMINUSRESULT.value();
int remains = (int)result; int remains = (int)result;
@@ -433,12 +438,16 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
if (!g_pCompositor->m_pLastMonitor) { if (!g_pCompositor->m_pLastMonitor) {
Debug::log(ERR, "Relative monitor workspace on monitor null!"); Debug::log(ERR, "Relative monitor workspace on monitor null!");
result = INT_MAX; return WORKSPACE_INVALID;
return result;
} }
// monitor relative // monitor relative
result = (int)getPlusMinusKeywordResult(in.substr(1), 0); const auto PLUSMINUSRESULT = getPlusMinusKeywordResult(in.substr(1), 0);
if (!PLUSMINUSRESULT.has_value())
return WORKSPACE_INVALID;
result = (int)PLUSMINUSRESULT.value();
// result now has +/- what we should move on mon // result now has +/- what we should move on mon
int remains = (int)result; int remains = (int)result;
@@ -479,11 +488,15 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
outName = g_pCompositor->getWorkspaceByID(validWSes[currentItem])->m_szName; outName = g_pCompositor->getWorkspaceByID(validWSes[currentItem])->m_szName;
} else { } else {
if (in[0] == '+' || in[0] == '-') { if (in[0] == '+' || in[0] == '-') {
if (g_pCompositor->m_pLastMonitor) if (g_pCompositor->m_pLastMonitor) {
result = std::max((int)getPlusMinusKeywordResult(in, g_pCompositor->m_pLastMonitor->activeWorkspace), 1); const auto PLUSMINUSRESULT = getPlusMinusKeywordResult(in, g_pCompositor->m_pLastMonitor->activeWorkspace);
else { if (!PLUSMINUSRESULT.has_value())
return WORKSPACE_INVALID;
result = std::max((int)PLUSMINUSRESULT.value(), 1);
} else {
Debug::log(ERR, "Relative workspace on no mon!"); Debug::log(ERR, "Relative workspace on no mon!");
result = INT_MAX; return WORKSPACE_INVALID;
} }
} else if (isNumber(in)) } else if (isNumber(in))
result = std::max(std::stoi(in), 1); result = std::max(std::stoi(in), 1);
@@ -695,6 +708,10 @@ int64_t configStringToInt(const std::string& VALUE) {
} else if (VALUE.starts_with("false") || VALUE.starts_with("off") || VALUE.starts_with("no")) { } else if (VALUE.starts_with("false") || VALUE.starts_with("off") || VALUE.starts_with("no")) {
return 0; return 0;
} }
if (VALUE.empty() || !isNumber(VALUE))
return 0;
return std::stoll(VALUE); return std::stoll(VALUE);
} }
@@ -764,4 +781,14 @@ uint32_t drmFormatToGL(uint32_t drm) {
} }
UNREACHABLE(); UNREACHABLE();
return GL_RGBA; return GL_RGBA;
}
uint32_t glFormatToType(uint32_t gl) {
return gl != GL_RGBA ?
#ifdef GLES2
GL_UNSIGNED_INT_2_10_10_10_REV_EXT :
#else
GL_UNSIGNED_INT_2_10_10_10_REV :
#endif
GL_UNSIGNED_BYTE;
} }

View File

@@ -27,13 +27,14 @@ void logSystemInfo();
std::string execAndGet(const char*); std::string execAndGet(const char*);
int64_t getPPIDof(int64_t pid); int64_t getPPIDof(int64_t pid);
int64_t configStringToInt(const std::string&); int64_t configStringToInt(const std::string&);
float getPlusMinusKeywordResult(std::string in, float relative); std::optional<float> getPlusMinusKeywordResult(std::string in, float relative);
void matrixProjection(float mat[9], int w, int h, wl_output_transform tr); void matrixProjection(float mat[9], int w, int h, wl_output_transform tr);
double normalizeAngleRad(double ang); double normalizeAngleRad(double ang);
std::string replaceInString(std::string subject, const std::string& search, const std::string& replace); std::string replaceInString(std::string subject, const std::string& search, const std::string& replace);
std::vector<SCallstackFrameInfo> getBacktrace(); std::vector<SCallstackFrameInfo> getBacktrace();
void throwError(const std::string& err); void throwError(const std::string& err);
uint32_t drmFormatToGL(uint32_t drm); uint32_t drmFormatToGL(uint32_t drm);
uint32_t glFormatToType(uint32_t gl);
template <typename... Args> template <typename... Args>
[[deprecated("use std::format instead")]] std::string getFormat(std::format_string<Args...> fmt, Args&&... args) { [[deprecated("use std::format instead")]] std::string getFormat(std::format_string<Args...> fmt, Args&&... args) {

View File

@@ -50,6 +50,10 @@ void CMonitor::onConnect(bool noRule) {
szName = output->name; szName = output->name;
szDescription = output->description ? output->description : "";
// remove comma character from description. This allow monitor specific rules to work on monitor with comma on their description
szDescription.erase(std::remove(szDescription.begin(), szDescription.end(), ','), szDescription.end());
if (!wlr_backend_is_drm(output->backend)) if (!wlr_backend_is_drm(output->backend))
createdByUser = true; // should be true. WL, X11 and Headless backends should be addable / removable createdByUser = true; // should be true. WL, X11 and Headless backends should be addable / removable
@@ -188,7 +192,7 @@ void CMonitor::onConnect(bool noRule) {
g_pCompositor->scheduleFrameForMonitor(this); g_pCompositor->scheduleFrameForMonitor(this);
} }
void CMonitor::onDisconnect() { void CMonitor::onDisconnect(bool destroy) {
if (renderTimer) { if (renderTimer) {
wl_event_source_remove(renderTimer); wl_event_source_remove(renderTimer);
@@ -276,7 +280,8 @@ void CMonitor::onDisconnect() {
activeWorkspace = -1; activeWorkspace = -1;
wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output); if (!destroy)
wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output);
wlr_output_enable(output, false); wlr_output_enable(output, false);
@@ -298,7 +303,6 @@ void CMonitor::onDisconnect() {
g_pHyprRenderer->m_pMostHzMonitor = pMonitorMostHz; g_pHyprRenderer->m_pMostHzMonitor = pMonitorMostHz;
} }
std::erase_if(g_pCompositor->m_vMonitors, [&](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; });
} }
@@ -353,7 +357,7 @@ void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) {
findAvailableDefaultWS() : findAvailableDefaultWS() :
getWorkspaceIDFromString(g_pConfigManager->getDefaultWorkspaceFor(szName), newDefaultWorkspaceName); getWorkspaceIDFromString(g_pConfigManager->getDefaultWorkspaceFor(szName), newDefaultWorkspaceName);
if (WORKSPACEID == INT_MAX || (WORKSPACEID >= SPECIAL_WORKSPACE_START && WORKSPACEID <= -2)) { if (WORKSPACEID == WORKSPACE_INVALID || (WORKSPACEID >= SPECIAL_WORKSPACE_START && WORKSPACEID <= -2)) {
WORKSPACEID = g_pCompositor->m_vWorkspaces.size() + 1; WORKSPACEID = g_pCompositor->m_vWorkspaces.size() + 1;
newDefaultWorkspaceName = std::to_string(WORKSPACEID); newDefaultWorkspaceName = std::to_string(WORKSPACEID);
@@ -642,4 +646,13 @@ void CMonitor::moveTo(const Vector2D& pos) {
Vector2D CMonitor::middle() { Vector2D CMonitor::middle() {
return vecPosition + vecSize / 2.f; return vecPosition + vecSize / 2.f;
} }
void CMonitor::updateMatrix() {
wlr_matrix_identity(projMatrix.data());
if (transform != WL_OUTPUT_TRANSFORM_NORMAL) {
wlr_matrix_translate(projMatrix.data(), vecPixelSize.x / 2.0, vecPixelSize.y / 2.0);
wlr_matrix_transform(projMatrix.data(), transform);
wlr_matrix_translate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0);
}
}

View File

@@ -43,6 +43,7 @@ class CMonitor {
float scale = 1; float scale = 1;
std::string szName = ""; std::string szName = "";
std::string szDescription = "";
Vector2D vecReservedTopLeft = Vector2D(0, 0); Vector2D vecReservedTopLeft = Vector2D(0, 0);
Vector2D vecReservedBottomRight = Vector2D(0, 0); Vector2D vecReservedBottomRight = Vector2D(0, 0);
@@ -50,32 +51,33 @@ class CMonitor {
drmModeModeInfo customDrmMode = {}; drmModeModeInfo customDrmMode = {};
// WLR stuff // WLR stuff
wlr_damage_ring damage; wlr_damage_ring damage;
wlr_output* output = nullptr; wlr_output* output = nullptr;
float refreshRate = 60; float refreshRate = 60;
int framesToSkip = 0; int framesToSkip = 0;
int forceFullFrames = 0; int forceFullFrames = 0;
bool noFrameSchedule = false; bool noFrameSchedule = false;
bool scheduledRecalc = false; bool scheduledRecalc = false;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
bool gammaChanged = false; bool gammaChanged = false;
float xwaylandScale = 1.f; float xwaylandScale = 1.f;
std::array<float, 9> projMatrix = {0};
bool dpmsStatus = true; 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 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 enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
bool createdByUser = false; bool createdByUser = false;
uint32_t drmFormat = DRM_FORMAT_INVALID; uint32_t drmFormat = DRM_FORMAT_INVALID;
bool isUnsafeFallback = false; bool isUnsafeFallback = false;
bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after
bool renderingActive = false; bool renderingActive = false;
wl_event_source* renderTimer = nullptr; // for RAT wl_event_source* renderTimer = nullptr; // for RAT
bool RATScheduled = false; bool RATScheduled = false;
CTimer lastPresentationTimer; CTimer lastPresentationTimer;
SMonitorRule activeMonitorRule; SMonitorRule activeMonitorRule;
// mirroring // mirroring
CMonitor* pMirrorOf = nullptr; CMonitor* pMirrorOf = nullptr;
@@ -110,7 +112,7 @@ class CMonitor {
// methods // methods
void onConnect(bool noRule); void onConnect(bool noRule);
void onDisconnect(); void onDisconnect(bool destroy = false);
void addDamage(const pixman_region32_t* rg); void addDamage(const pixman_region32_t* rg);
void addDamage(const CRegion* rg); void addDamage(const CRegion* rg);
void addDamage(const CBox* box); void addDamage(const CBox* box);
@@ -123,6 +125,7 @@ class CMonitor {
void setSpecialWorkspace(const int& id); void setSpecialWorkspace(const int& id);
void moveTo(const Vector2D& pos); void moveTo(const Vector2D& pos);
Vector2D middle(); Vector2D middle();
void updateMatrix();
bool m_bEnabled = false; bool m_bEnabled = false;
bool m_bRenderingInitPassed = false; bool m_bRenderingInitPassed = false;

View File

@@ -88,11 +88,25 @@ CRegion& CRegion::invert(pixman_box32_t* box) {
return *this; return *this;
} }
CRegion& CRegion::invert(const CBox& box) {
pixman_box32 pixmanBox = {box.x, box.y, box.w + box.x, box.h + box.y};
return this->invert(&pixmanBox);
}
CRegion& CRegion::translate(const Vector2D& vec) { CRegion& CRegion::translate(const Vector2D& vec) {
pixman_region32_translate(&m_rRegion, vec.x, vec.y); pixman_region32_translate(&m_rRegion, vec.x, vec.y);
return *this; return *this;
} }
CRegion& CRegion::transform(const wl_output_transform t, double w, double h) {
wlr_region_transform(&m_rRegion, &m_rRegion, t, w, h);
return *this;
}
CRegion CRegion::copy() const {
return CRegion(*this);
}
CRegion& CRegion::scale(float scale) { CRegion& CRegion::scale(float scale) {
wlr_region_scale(&m_rRegion, &m_rRegion, scale); wlr_region_scale(&m_rRegion, &m_rRegion, scale);
return *this; return *this;

View File

@@ -45,12 +45,15 @@ class CRegion {
CRegion& intersect(const CRegion& other); CRegion& intersect(const CRegion& other);
CRegion& intersect(double x, double y, double w, double h); CRegion& intersect(double x, double y, double w, double h);
CRegion& translate(const Vector2D& vec); CRegion& translate(const Vector2D& vec);
CRegion& transform(const wl_output_transform t, double w, double h);
CRegion& invert(pixman_box32_t* box); CRegion& invert(pixman_box32_t* box);
CRegion& invert(const CBox& box);
CRegion& scale(float scale); CRegion& scale(float scale);
CBox getExtents(); CBox getExtents();
bool containsPoint(const Vector2D& vec) const; bool containsPoint(const Vector2D& vec) const;
bool empty() const; bool empty() const;
Vector2D closestPoint(const Vector2D& vec) const; Vector2D closestPoint(const Vector2D& vec) const;
CRegion copy() const;
std::vector<pixman_box32_t> getRects() const; std::vector<pixman_box32_t> getRects() const;

View File

@@ -220,6 +220,8 @@ void Events::listener_commitSubsurface(void* owner, void* data) {
// no damaging if it's not visible // no damaging if it's not visible
if (!g_pHyprRenderer->shouldRenderWindow(pNode->pWindowOwner)) { if (!g_pHyprRenderer->shouldRenderWindow(pNode->pWindowOwner)) {
pNode->lastSize = pNode->pSurface->exists() ? Vector2D{pNode->pSurface->wlr()->current.width, pNode->pSurface->wlr()->current.height} : Vector2D{};
static auto* const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue; static auto* const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
if (*PLOGDAMAGE) if (*PLOGDAMAGE)
Debug::log(LOG, "Refusing to commit damage from {} because it's invisible.", pNode->pWindowOwner); Debug::log(LOG, "Refusing to commit damage from {} because it's invisible.", pNode->pWindowOwner);
@@ -244,9 +246,13 @@ void Events::listener_commitSubsurface(void* owner, void* data) {
} }
} }
if (pNode->pSurface && pNode->pSurface->exists()) if (pNode->pSurface && pNode->pSurface->exists()) {
g_pHyprRenderer->damageSurface(pNode->pSurface->wlr(), lx, ly, SCALE); g_pHyprRenderer->damageSurface(pNode->pSurface->wlr(), lx, ly, SCALE);
if (pNode->lastSize != Vector2D{pNode->pSurface->wlr()->current.width, pNode->pSurface->wlr()->current.height} && pNode->pWindowOwner)
g_pHyprRenderer->damageWindow(pNode->pWindowOwner);
}
if (pNode->pWindowOwner) { if (pNode->pWindowOwner) {
if (pNode->pWindowOwner->m_bIsX11) if (pNode->pWindowOwner->m_bIsX11)
pNode->pWindowOwner->m_vReportedSize = pNode->pWindowOwner->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged. pNode->pWindowOwner->m_vReportedSize = pNode->pWindowOwner->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged.
@@ -269,6 +275,8 @@ void Events::listener_commitSubsurface(void* owner, void* data) {
} }
} }
} }
pNode->lastSize = pNode->pSurface->exists() ? Vector2D{pNode->pSurface->wlr()->current.width, pNode->pSurface->wlr()->current.height} : Vector2D{};
} }
void Events::listener_destroySubsurface(void* owner, void* data) { void Events::listener_destroySubsurface(void* owner, void* data) {

View File

@@ -26,6 +26,8 @@ struct SSurfaceTreeNode {
void* globalOffsetData; void* globalOffsetData;
CWindow* pWindowOwner = nullptr; CWindow* pWindowOwner = nullptr;
Vector2D lastSize;
// //
bool operator==(const SSurfaceTreeNode& rhs) const { bool operator==(const SSurfaceTreeNode& rhs) const {
return pSurface == rhs.pSurface; return pSurface == rhs.pSurface;

View File

@@ -25,10 +25,10 @@ class Vector2D {
Vector2D operator-() const { Vector2D operator-() const {
return Vector2D(-this->x, -this->y); return Vector2D(-this->x, -this->y);
} }
Vector2D operator*(const float& a) const { Vector2D operator*(const double& a) const {
return Vector2D(this->x * a, this->y * a); return Vector2D(this->x * a, this->y * a);
} }
Vector2D operator/(const float& a) const { Vector2D operator/(const double& a) const {
return Vector2D(this->x / a, this->y / a); return Vector2D(this->x / a, this->y / a);
} }
@@ -55,6 +55,36 @@ class Vector2D {
bool operator<(const Vector2D& a) const { bool operator<(const Vector2D& a) const {
return this->x < a.x && this->y < a.y; return this->x < a.x && this->y < a.y;
} }
Vector2D& operator+=(const Vector2D& a) {
this->x += a.x;
this->y += a.y;
return *this;
}
Vector2D& operator-=(const Vector2D& a) {
this->x -= a.x;
this->y -= a.y;
return *this;
}
Vector2D& operator*=(const Vector2D& a) {
this->x *= a.x;
this->y *= a.y;
return *this;
}
Vector2D& operator/=(const Vector2D& a) {
this->x /= a.x;
this->y /= a.y;
return *this;
}
Vector2D& operator*=(const double& a) {
this->x *= a;
this->y *= a;
return *this;
}
Vector2D& operator/=(const double& a) {
this->x /= a;
this->y /= a;
return *this;
}
double distance(const Vector2D& other) const; double distance(const Vector2D& other) const;
double size() const; double size() const;

View File

@@ -8,6 +8,14 @@ SLayerSurface::SLayerSurface() {
alpha.registerVar(); alpha.registerVar();
} }
SLayerSurface::~SLayerSurface() {
if (!g_pHyprOpenGL)
return;
g_pHyprRenderer->makeEGLCurrent();
std::erase_if(g_pHyprOpenGL->m_mLayerFramebuffers, [&](const auto& other) { return other.first == this; });
}
void SLayerSurface::applyRules() { void SLayerSurface::applyRules() {
noAnimations = false; noAnimations = false;
forceBlur = false; forceBlur = false;

View File

@@ -16,6 +16,7 @@ struct SLayerRule {
struct SLayerSurface { struct SLayerSurface {
SLayerSurface(); SLayerSurface();
~SLayerSurface();
void applyRules(); void applyRules();

View File

@@ -65,7 +65,7 @@ void CWLSurface::destroy() {
if (g_pInputManager->m_pLastMouseSurface == m_pWLRSurface) if (g_pInputManager->m_pLastMouseSurface == m_pWLRSurface)
g_pInputManager->m_pLastMouseSurface = nullptr; g_pInputManager->m_pLastMouseSurface = nullptr;
if (g_pHyprRenderer->m_sLastCursorData.surf == m_pWLRSurface) if (g_pHyprRenderer->m_sLastCursorData.surf == m_pWLRSurface)
g_pInputManager->setCursorImageOverride("left_ptr"); g_pHyprRenderer->m_sLastCursorData.surf.reset();
m_pWLRSurface = nullptr; m_pWLRSurface = nullptr;

View File

@@ -38,7 +38,8 @@ CWorkspace::~CWorkspace() {
} }
void CWorkspace::startAnim(bool in, bool left, bool instant) { void CWorkspace::startAnim(bool in, bool left, bool instant) {
const auto ANIMSTYLE = m_fAlpha.m_pConfig->pValues->internalStyle; const auto ANIMSTYLE = m_fAlpha.m_pConfig->pValues->internalStyle;
const auto PWORKSPACEGAP = &g_pConfigManager->getConfigValuePtr("general:gaps_workspaces")->intValue;
if (ANIMSTYLE.starts_with("slidefade")) { if (ANIMSTYLE.starts_with("slidefade")) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
@@ -90,26 +91,28 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
} else if (ANIMSTYLE == "slidevert") { } else if (ANIMSTYLE == "slidevert") {
// fallback is slide // fallback is slide
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
const auto YDISTANCE = PMONITOR->vecSize.y + *PWORKSPACEGAP;
m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide. m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
if (in) { if (in) {
m_vRenderOffset.setValueAndWarp(Vector2D(0, left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y)); m_vRenderOffset.setValueAndWarp(Vector2D(0, left ? YDISTANCE : -YDISTANCE));
m_vRenderOffset = Vector2D(0, 0); m_vRenderOffset = Vector2D(0, 0);
} else { } else {
m_vRenderOffset = Vector2D(0, left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y); m_vRenderOffset = Vector2D(0, left ? -YDISTANCE : YDISTANCE);
} }
} else { } else {
// fallback is slide // fallback is slide
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
const auto XDISTANCE = PMONITOR->vecSize.x + *PWORKSPACEGAP;
m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide. m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
if (in) { if (in) {
m_vRenderOffset.setValueAndWarp(Vector2D(left ? PMONITOR->vecSize.x : -PMONITOR->vecSize.x, 0)); m_vRenderOffset.setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0));
m_vRenderOffset = Vector2D(0, 0); m_vRenderOffset = Vector2D(0, 0);
} else { } else {
m_vRenderOffset = Vector2D(left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x, 0); m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0);
} }
} }

View File

@@ -70,7 +70,6 @@ extern "C" {
#include <wlr/types/wlr_xdg_shell.h> #include <wlr/types/wlr_xdg_shell.h>
#include <wlr/types/wlr_subcompositor.h> #include <wlr/types/wlr_subcompositor.h>
#include <wlr/types/wlr_damage_ring.h> #include <wlr/types/wlr_damage_ring.h>
#include <wlr/types/wlr_input_inhibitor.h>
#include <wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h> #include <wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h>
#include <wlr/types/wlr_virtual_pointer_v1.h> #include <wlr/types/wlr_virtual_pointer_v1.h>
#include <wlr/types/wlr_foreign_toplevel_management_v1.h> #include <wlr/types/wlr_foreign_toplevel_management_v1.h>
@@ -106,6 +105,9 @@ extern "C" {
#include <wlr/types/wlr_cursor_shape_v1.h> #include <wlr/types/wlr_cursor_shape_v1.h>
#include <wlr/types/wlr_tearing_control_v1.h> #include <wlr/types/wlr_tearing_control_v1.h>
#include <wlr/util/box.h> #include <wlr/util/box.h>
#include <wlr/util/transform.h>
#include <wlr/render/swapchain.h>
#include <wlr/render/egl.h>
#include <libdrm/drm_fourcc.h> #include <libdrm/drm_fourcc.h>

View File

@@ -1,6 +1,7 @@
#include "IHyprLayout.hpp" #include "IHyprLayout.hpp"
#include "../defines.hpp" #include "../defines.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
void IHyprLayout::onWindowCreated(CWindow* pWindow, eDirection direction) { void IHyprLayout::onWindowCreated(CWindow* pWindow, eDirection direction) {
if (pWindow->m_bIsFloating) { if (pWindow->m_bIsFloating) {
@@ -264,10 +265,36 @@ void IHyprLayout::onEndDragWindow() {
g_pInputManager->refocus(); g_pInputManager->refocus();
changeWindowFloatingMode(DRAGGINGWINDOW); changeWindowFloatingMode(DRAGGINGWINDOW);
DRAGGINGWINDOW->m_vLastFloatingSize = m_vDraggingWindowOriginalFloatSize; DRAGGINGWINDOW->m_vLastFloatingSize = m_vDraggingWindowOriginalFloatSize;
} else if (g_pInputManager->dragMode == MBIND_MOVE) {
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
CWindow* pWindow = g_pCompositor->vectorToWindowIdeal(MOUSECOORDS, DRAGGINGWINDOW);
if (pWindow && pWindow->m_bIsFloating) {
for (auto& wd : pWindow->m_dWindowDecorations) {
if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
continue;
if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(MOUSECOORDS)) {
if (!wd->onEndWindowDragOnDeco(DRAGGINGWINDOW, MOUSECOORDS))
return;
break;
}
}
if (pWindow->m_sGroupData.pNextWindow && DRAGGINGWINDOW->canBeGroupedInto(pWindow)) {
static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue;
(*USECURRPOS ? pWindow : pWindow->getGroupTail())->insertWindowToGroup(DRAGGINGWINDOW);
pWindow->setGroupCurrent(DRAGGINGWINDOW);
DRAGGINGWINDOW->updateWindowDecos();
if (!DRAGGINGWINDOW->getDecorationByType(DECORATION_GROUPBAR))
DRAGGINGWINDOW->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(DRAGGINGWINDOW));
}
}
} }
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
g_pCompositor->focusWindow(DRAGGINGWINDOW); g_pCompositor->focusWindow(DRAGGINGWINDOW);
g_pInputManager->m_bWasDraggingWindow = false; g_pInputManager->m_bWasDraggingWindow = false;
@@ -427,7 +454,8 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
const auto PSAVEDSIZE = pWindow->m_vRealSize.goalv(); const auto PSAVEDSIZE = pWindow->m_vRealSize.goalv();
// if the window is pseudo, update its size // if the window is pseudo, update its size
pWindow->m_vPseudoSize = pWindow->m_vRealSize.goalv(); if (!pWindow->m_bDraggingTiled)
pWindow->m_vPseudoSize = pWindow->m_vRealSize.goalv();
pWindow->m_vLastFloatingSize = PSAVEDSIZE; pWindow->m_vLastFloatingSize = PSAVEDSIZE;

View File

@@ -42,13 +42,21 @@ SMasterWorkspaceData* CHyprMasterLayout::getMasterWorkspaceData(const int& ws) {
const auto PWORKSPACEDATA = &m_lMasterWorkspacesData.emplace_back(); const auto PWORKSPACEDATA = &m_lMasterWorkspacesData.emplace_back();
PWORKSPACEDATA->workspaceID = ws; PWORKSPACEDATA->workspaceID = ws;
const auto orientation = &g_pConfigManager->getConfigValuePtr("master:orientation")->strValue; const auto orientation = &g_pConfigManager->getConfigValuePtr("master:orientation")->strValue;
if (*orientation == "top") { const auto layoutoptsForWs = g_pConfigManager->getWorkspaceRuleFor(g_pCompositor->getWorkspaceByID(ws)).layoutopts;
auto orientationForWs = *orientation;
try {
if (layoutoptsForWs.contains("orientation"))
orientationForWs = std::any_cast<std::string>(layoutoptsForWs.at("orientation"));
} catch (std::exception& e) { Debug::log(ERR, "Error from layoutopt rules: {}", e.what()); }
if (orientationForWs == "top") {
PWORKSPACEDATA->orientation = ORIENTATION_TOP; PWORKSPACEDATA->orientation = ORIENTATION_TOP;
} else if (*orientation == "right") { } else if (orientationForWs == "right") {
PWORKSPACEDATA->orientation = ORIENTATION_RIGHT; PWORKSPACEDATA->orientation = ORIENTATION_RIGHT;
} else if (*orientation == "bottom") { } else if (orientationForWs == "bottom") {
PWORKSPACEDATA->orientation = ORIENTATION_BOTTOM; PWORKSPACEDATA->orientation = ORIENTATION_BOTTOM;
} else if (*orientation == "left") { } else if (orientationForWs == "left") {
PWORKSPACEDATA->orientation = ORIENTATION_LEFT; PWORKSPACEDATA->orientation = ORIENTATION_LEFT;
} else { } else {
PWORKSPACEDATA->orientation = ORIENTATION_CENTER; PWORKSPACEDATA->orientation = ORIENTATION_CENTER;

View File

@@ -22,6 +22,8 @@
#define STRVAL_EMPTY "[[EMPTY]]" #define STRVAL_EMPTY "[[EMPTY]]"
#define WORKSPACE_INVALID -1L
#define LISTENER(name) \ #define LISTENER(name) \
void listener_##name(wl_listener*, void*); \ void listener_##name(wl_listener*, void*); \
inline wl_listener listen_##name = {.notify = listener_##name} inline wl_listener listen_##name = {.notify = listener_##name}

View File

@@ -54,14 +54,17 @@ int main(int argc, char** argv) {
} }
std::string next_arg = std::next(it)->c_str(); std::string next_arg = std::next(it)->c_str();
if (!std::filesystem::exists(next_arg)) { if (std::filesystem::is_symlink(next_arg))
std::cerr << "[ ERROR ] Config path '" << next_arg << "' doesn't exist!\n"; next_arg = std::filesystem::read_symlink(next_arg);
if (!std::filesystem::is_regular_file(next_arg)) {
std::cerr << "[ ERROR ] Config file '" << next_arg << "' doesn't exist!\n";
help(); help();
return 1; return 1;
} }
configPath = next_arg; configPath = std::filesystem::weakly_canonical(next_arg);
Debug::log(LOG, "User-specified config location: '{}'", configPath); Debug::log(LOG, "User-specified config location: '{}'", configPath);
it++; it++;
@@ -97,7 +100,8 @@ int main(int argc, char** argv) {
g_pCompositor->initServer(); g_pCompositor->initServer();
Init::gainRealTime(); if (!getenv("HYPRLAND_NO_RT") || configStringToInt(std::string(getenv("HYPRLAND_NO_RT"))) == 0)
Init::gainRealTime();
Debug::log(LOG, "Hyprland init finished."); Debug::log(LOG, "Hyprland init finished.");

View File

@@ -213,6 +213,12 @@ void CAnimationManager::tick() {
continue; continue;
w->updateWindowDecos(); w->updateWindowDecos();
if (w->m_bIsFloating) {
auto bb = w->getFullWindowBoundingBox();
bb.translate(PWORKSPACE->m_vRenderOffset.vec());
g_pHyprRenderer->damageBox(&bb);
}
} }
} else if (PLAYER) { } else if (PLAYER) {
if (PLAYER->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || PLAYER->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM) if (PLAYER->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || PLAYER->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM)

View File

@@ -641,11 +641,6 @@ void CKeybindManager::spawn(std::string args) {
args = args.substr(args.find_first_of(']') + 1); 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
args = "WAYLAND_DISPLAY=" + std::string(g_pCompositor->m_szWLDisplaySocket) + " " + args;
const uint64_t PROC = spawnRaw(args); const uint64_t PROC = spawnRaw(args);
if (!RULES.empty()) { if (!RULES.empty()) {
@@ -735,11 +730,10 @@ void CKeybindManager::clearKeybinds() {
void CKeybindManager::toggleActiveFloating(std::string args) { void CKeybindManager::toggleActiveFloating(std::string args) {
CWindow* PWINDOW = nullptr; CWindow* PWINDOW = nullptr;
if (args != "" && args != "active" && args.length() > 1) { if (args != "" && args != "active" && args.length() > 1)
PWINDOW = g_pCompositor->getWindowByRegex(args); PWINDOW = g_pCompositor->getWindowByRegex(args);
} else { else
PWINDOW = g_pCompositor->m_pLastWindow; PWINDOW = g_pCompositor->m_pLastWindow;
}
if (!PWINDOW) if (!PWINDOW)
return; return;
@@ -747,9 +741,6 @@ void CKeybindManager::toggleActiveFloating(std::string args) {
// remove drag status // remove drag status
g_pInputManager->currentlyDraggedWindow = nullptr; g_pInputManager->currentlyDraggedWindow = nullptr;
if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID))
return;
if (PWINDOW->m_sGroupData.pNextWindow && PWINDOW->m_sGroupData.pNextWindow != PWINDOW) { if (PWINDOW->m_sGroupData.pNextWindow && PWINDOW->m_sGroupData.pNextWindow != PWINDOW) {
const auto PCURRENT = PWINDOW->getGroupCurrent(); const auto PCURRENT = PWINDOW->getGroupCurrent();
@@ -831,7 +822,7 @@ void CKeybindManager::changeworkspace(std::string args) {
workspaceToChangeTo = getWorkspaceIDFromString(args, workspaceName); workspaceToChangeTo = getWorkspaceIDFromString(args, workspaceName);
} }
if (workspaceToChangeTo == INT_MAX) { if (workspaceToChangeTo == WORKSPACE_INVALID) {
Debug::log(ERR, "Error in changeworkspace, invalid value"); Debug::log(ERR, "Error in changeworkspace, invalid value");
return; return;
} }
@@ -920,7 +911,7 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
std::string workspaceName; std::string workspaceName;
const auto WORKSPACEID = getWorkspaceIDFromString(args, workspaceName); const auto WORKSPACEID = getWorkspaceIDFromString(args, workspaceName);
if (WORKSPACEID == INT_MAX) { if (WORKSPACEID == WORKSPACE_INVALID) {
Debug::log(LOG, "Invalid workspace in moveActiveToWorkspace"); Debug::log(LOG, "Invalid workspace in moveActiveToWorkspace");
return; return;
} }
@@ -949,6 +940,11 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
POLDWS->m_pLastFocusedWindow = g_pCompositor->getFirstWindowOnWorkspace(POLDWS->m_iID); POLDWS->m_pLastFocusedWindow = g_pCompositor->getFirstWindowOnWorkspace(POLDWS->m_iID);
if (pWorkspace->m_bIsSpecialWorkspace)
pMonitor->setSpecialWorkspace(pWorkspace);
else if (POLDWS->m_bIsSpecialWorkspace)
g_pCompositor->getMonitorFromID(POLDWS->m_iMonitorID)->setSpecialWorkspace(nullptr);
pMonitor->changeWorkspace(pWorkspace); pMonitor->changeWorkspace(pWorkspace);
g_pCompositor->focusWindow(PWINDOW); g_pCompositor->focusWindow(PWINDOW);
@@ -977,7 +973,7 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
const int WORKSPACEID = getWorkspaceIDFromString(args, workspaceName); const int WORKSPACEID = getWorkspaceIDFromString(args, workspaceName);
if (WORKSPACEID == INT_MAX) { if (WORKSPACEID == WORKSPACE_INVALID) {
Debug::log(ERR, "Error in moveActiveToWorkspaceSilent, invalid value"); Debug::log(ERR, "Error in moveActiveToWorkspaceSilent, invalid value");
return; return;
} }
@@ -1216,24 +1212,16 @@ void CKeybindManager::toggleSplit(std::string args) {
} }
void CKeybindManager::alterSplitRatio(std::string args) { void CKeybindManager::alterSplitRatio(std::string args) {
float splitratio = 0; std::optional<float> splitResult;
bool exact = false; bool exact = false;
if (args == "+" || args == "-") { if (args.starts_with("exact")) {
Debug::log(LOG, "alterSplitRatio: using LEGACY +/-, consider switching to the Hyprland syntax."); exact = true;
splitratio = (args == "+" ? 0.05f : -0.05f); splitResult = getPlusMinusKeywordResult(args.substr(5), 0);
} } else
splitResult = getPlusMinusKeywordResult(args, 0);
if (splitratio == 0) { if (!splitResult.has_value()) {
if (args.starts_with("exact")) {
exact = true;
splitratio = getPlusMinusKeywordResult(args.substr(5), 0);
} else {
splitratio = getPlusMinusKeywordResult(args, 0);
}
}
if (splitratio == INT_MAX) {
Debug::log(ERR, "Splitratio invalid in alterSplitRatio!"); Debug::log(ERR, "Splitratio invalid in alterSplitRatio!");
return; return;
} }
@@ -1243,7 +1231,7 @@ void CKeybindManager::alterSplitRatio(std::string args) {
if (!PLASTWINDOW) if (!PLASTWINDOW)
return; return;
g_pLayoutManager->getCurrentLayout()->alterSplitRatio(PLASTWINDOW, splitratio, exact); g_pLayoutManager->getCurrentLayout()->alterSplitRatio(PLASTWINDOW, splitResult.value(), exact);
} }
void CKeybindManager::focusMonitor(std::string arg) { void CKeybindManager::focusMonitor(std::string arg) {
@@ -1425,7 +1413,7 @@ void CKeybindManager::moveWorkspaceToMonitor(std::string args) {
std::string workspaceName; std::string workspaceName;
const int WORKSPACEID = getWorkspaceIDFromString(workspace, workspaceName); const int WORKSPACEID = getWorkspaceIDFromString(workspace, workspaceName);
if (WORKSPACEID == INT_MAX) { if (WORKSPACEID == WORKSPACE_INVALID) {
Debug::log(ERR, "moveWorkspaceToMonitor invalid workspace!"); Debug::log(ERR, "moveWorkspaceToMonitor invalid workspace!");
return; return;
} }
@@ -1447,7 +1435,7 @@ void CKeybindManager::toggleSpecialWorkspace(std::string args) {
std::string workspaceName = ""; std::string workspaceName = "";
int workspaceID = getWorkspaceIDFromString("special:" + args, workspaceName); int workspaceID = getWorkspaceIDFromString("special:" + args, workspaceName);
if (workspaceID == INT_MAX || !g_pCompositor->isWorkspaceSpecial(workspaceID)) { if (workspaceID == WORKSPACE_INVALID || !g_pCompositor->isWorkspaceSpecial(workspaceID)) {
Debug::log(ERR, "Invalid workspace passed to special"); Debug::log(ERR, "Invalid workspace passed to special");
return; return;
} }
@@ -1485,7 +1473,7 @@ void CKeybindManager::forceRendererReload(std::string args) {
if (!m->output) if (!m->output)
continue; continue;
auto rule = g_pConfigManager->getMonitorRuleFor(m->szName, m->output->description ? m->output->description : ""); auto rule = g_pConfigManager->getMonitorRuleFor(m->szName, m->szDescription);
if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule, true)) { if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule, true)) {
overAgain = true; overAgain = true;
break; break;
@@ -1915,7 +1903,7 @@ void CKeybindManager::alterZOrder(std::string args) {
else if (POSITION == "bottom") else if (POSITION == "bottom")
g_pCompositor->changeWindowZOrder(PWINDOW, 0); g_pCompositor->changeWindowZOrder(PWINDOW, 0);
else { else {
Debug::log(ERR, "alterZOrder: bad position: %s", POSITION); Debug::log(ERR, "alterZOrder: bad position: {}", POSITION);
return; return;
} }
@@ -2067,7 +2055,7 @@ void CKeybindManager::moveWindowOrGroup(std::string args) {
static auto* const PIGNOREGROUPLOCK = &g_pConfigManager->getConfigValuePtr("binds:ignore_group_lock")->intValue; static auto* const PIGNOREGROUPLOCK = &g_pConfigManager->getConfigValuePtr("binds:ignore_group_lock")->intValue;
if (!isDirection(args)) { if (!isDirection(args)) {
Debug::log(ERR, "Cannot move into group in direction %c, unsupported direction. Supported: l,r,u/t,d/b", arg); Debug::log(ERR, "Cannot move into group in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg);
return; return;
} }

View File

@@ -51,3 +51,10 @@ bool CLayoutManager::removeLayout(IHyprLayout* layout) {
return true; return true;
} }
std::vector<std::string> CLayoutManager::getAllLayoutNames() {
std::vector<std::string> results(m_vLayouts.size());
for (size_t i = 0; i < m_vLayouts.size(); ++i)
results[i] = m_vLayouts[i].first;
return results;
}

View File

@@ -7,16 +7,16 @@ class CLayoutManager {
public: public:
CLayoutManager(); CLayoutManager();
IHyprLayout* getCurrentLayout(); IHyprLayout* getCurrentLayout();
void switchToLayout(std::string); void switchToLayout(std::string);
bool addLayout(const std::string& name, IHyprLayout* layout); bool addLayout(const std::string& name, IHyprLayout* layout);
bool removeLayout(IHyprLayout* layout); bool removeLayout(IHyprLayout* layout);
std::vector<std::string> getAllLayoutNames();
private: private:
enum HYPRLAYOUTS enum HYPRLAYOUTS {
{
LAYOUT_DWINDLE = 0, LAYOUT_DWINDLE = 0,
LAYOUT_MASTER LAYOUT_MASTER
}; };
@@ -25,8 +25,7 @@ class CLayoutManager {
CHyprDwindleLayout m_cDwindleLayout; CHyprDwindleLayout m_cDwindleLayout;
CHyprMasterLayout m_cMasterLayout; CHyprMasterLayout m_cMasterLayout;
std::vector<std::pair<std::string, IHyprLayout*>> m_vLayouts; std::vector<std::pair<std::string, IHyprLayout*>> m_vLayouts;
}; };
inline std::unique_ptr<CLayoutManager> g_pLayoutManager; inline std::unique_ptr<CLayoutManager> g_pLayoutManager;

View File

@@ -45,10 +45,11 @@ void CHyprXWaylandManager::activateSurface(wlr_surface* pSurface, bool activate)
wlr_xdg_toplevel_set_activated(PSURF->toplevel, activate); wlr_xdg_toplevel_set_activated(PSURF->toplevel, activate);
} else if (wlr_xwayland_surface_try_from_wlr_surface(pSurface)) { } else if (wlr_xwayland_surface_try_from_wlr_surface(pSurface)) {
wlr_xwayland_surface_activate(wlr_xwayland_surface_try_from_wlr_surface(pSurface), activate); const auto XSURF = wlr_xwayland_surface_try_from_wlr_surface(pSurface);
wlr_xwayland_surface_activate(XSURF, activate);
if (activate) if (activate && !XSURF->override_redirect)
wlr_xwayland_surface_restack(wlr_xwayland_surface_try_from_wlr_surface(pSurface), nullptr, XCB_STACK_MODE_ABOVE); wlr_xwayland_surface_restack(XSURF, nullptr, XCB_STACK_MODE_ABOVE);
} }
} }
@@ -58,7 +59,8 @@ void CHyprXWaylandManager::activateWindow(CWindow* pWindow, bool activate) {
if (activate) { if (activate) {
wlr_xwayland_surface_set_minimized(pWindow->m_uSurface.xwayland, false); wlr_xwayland_surface_set_minimized(pWindow->m_uSurface.xwayland, false);
wlr_xwayland_surface_restack(pWindow->m_uSurface.xwayland, nullptr, XCB_STACK_MODE_ABOVE); if (!pWindow->m_uSurface.xwayland->override_redirect)
wlr_xwayland_surface_restack(pWindow->m_uSurface.xwayland, nullptr, XCB_STACK_MODE_ABOVE);
} }
wlr_xwayland_surface_activate(pWindow->m_uSurface.xwayland, activate); wlr_xwayland_surface_activate(pWindow->m_uSurface.xwayland, activate);

View File

@@ -3,6 +3,18 @@
#include "wlr/types/wlr_switch.h" #include "wlr/types/wlr_switch.h"
#include <ranges> #include <ranges>
CInputManager::~CInputManager() {
m_lConstraints.clear();
m_lKeyboards.clear();
m_lMice.clear();
m_lTablets.clear();
m_lTabletTools.clear();
m_lTabletPads.clear();
m_lIdleInhibitors.clear();
m_lTouchDevices.clear();
m_lSwitches.clear();
}
void CInputManager::onMouseMoved(wlr_pointer_motion_event* e) { void CInputManager::onMouseMoved(wlr_pointer_motion_event* e) {
static auto* const PSENS = &g_pConfigManager->getConfigValuePtr("general:sensitivity")->floatValue; static auto* const PSENS = &g_pConfigManager->getConfigValuePtr("general:sensitivity")->floatValue;
static auto* const PNOACCEL = &g_pConfigManager->getConfigValuePtr("input:force_no_accel")->intValue; static auto* const PNOACCEL = &g_pConfigManager->getConfigValuePtr("input:force_no_accel")->intValue;
@@ -221,10 +233,20 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
surfacePos = PMONITOR->vecPosition; surfacePos = PMONITOR->vecPosition;
} }
// overlay is above fullscreen // overlays are above fullscreen
if (!foundSurface) if (!foundSurface)
foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &surfaceCoords, &pFoundLayerSurface); foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &surfaceCoords, &pFoundLayerSurface);
// also IME popups
if (!foundSurface) {
auto popup = g_pCompositor->vectorToIMEPopup(mouseCoords, m_sIMERelay.m_lIMEPopups);
if (popup) {
foundSurface = popup->pSurface->surface;
surfacePos = Vector2D(popup->realX, popup->realY);
}
}
// also top layers
if (!foundSurface) if (!foundSurface)
foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &surfaceCoords, &pFoundLayerSurface); foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &surfaceCoords, &pFoundLayerSurface);
@@ -459,7 +481,6 @@ void CInputManager::onMouseButton(wlr_pointer_button_event* e) {
} }
void CInputManager::processMouseRequest(wlr_seat_pointer_request_set_cursor_event* e) { void CInputManager::processMouseRequest(wlr_seat_pointer_request_set_cursor_event* e) {
if (!e->surface) if (!e->surface)
g_pHyprRenderer->m_bWindowRequestedCursorHide = true; g_pHyprRenderer->m_bWindowRequestedCursorHide = true;
else else
@@ -572,10 +593,13 @@ void CInputManager::setClickMode(eClickBehaviorMode mode) {
void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) { void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
// notify the keybind manager // notify the keybind manager
static auto* const PPASSMOUSE = &g_pConfigManager->getConfigValuePtr("binds:pass_mouse_when_bound")->intValue; static auto* const PPASSMOUSE = &g_pConfigManager->getConfigValuePtr("binds:pass_mouse_when_bound")->intValue;
const auto PASS = g_pKeybindManager->onMouseEvent(e); const auto PASS = g_pKeybindManager->onMouseEvent(e);
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue; static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
static auto* const PRESIZEONBORDER = &g_pConfigManager->getConfigValuePtr("general:resize_on_border")->intValue; static auto* const PRESIZEONBORDER = &g_pConfigManager->getConfigValuePtr("general:resize_on_border")->intValue;
static auto* const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
static auto* const PBORDERGRABEXTEND = &g_pConfigManager->getConfigValuePtr("general:extend_border_grab_area")->intValue;
const auto BORDER_GRAB_AREA = *PRESIZEONBORDER ? *PBORDERSIZE + *PBORDERGRABEXTEND : 0;
if (!PASS && !*PPASSMOUSE) if (!PASS && !*PPASSMOUSE)
return; return;
@@ -600,7 +624,8 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
if (*PRESIZEONBORDER && !m_bLastFocusOnLS) { if (*PRESIZEONBORDER && !m_bLastFocusOnLS) {
if (w && !w->m_bIsFullscreen) { if (w && !w->m_bIsFullscreen) {
const CBox real = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y}; const CBox real = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
if ((!real.containsPoint(mouseCoords) || w->isInCurvedCorner(mouseCoords.x, mouseCoords.y)) && !w->hasPopupAt(mouseCoords)) { const CBox grab = {real.x - BORDER_GRAB_AREA, real.y - BORDER_GRAB_AREA, real.width + 2 * BORDER_GRAB_AREA, real.height + 2 * BORDER_GRAB_AREA};
if ((grab.containsPoint(mouseCoords) && (!real.containsPoint(mouseCoords) || w->isInCurvedCorner(mouseCoords.x, mouseCoords.y))) && !w->hasPopupAt(mouseCoords)) {
g_pKeybindManager->resizeWithBorder(e); g_pKeybindManager->resizeWithBorder(e);
return; return;
} }
@@ -667,10 +692,16 @@ void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) {
auto factor = (*PSCROLLFACTOR <= 0.f || e->source != WLR_AXIS_SOURCE_FINGER ? 1.f : *PSCROLLFACTOR); auto factor = (*PSCROLLFACTOR <= 0.f || e->source != WLR_AXIS_SOURCE_FINGER ? 1.f : *PSCROLLFACTOR);
bool passEvent = g_pKeybindManager->onAxisEvent(e); const auto EMAP = std::unordered_map<std::string, std::any>{{"event", e}};
EMIT_HOOK_EVENT_CANCELLABLE("mouseAxis", EMAP);
bool passEvent = g_pKeybindManager->onAxisEvent(e);
g_pCompositor->notifyIdleActivity(); g_pCompositor->notifyIdleActivity();
if (!passEvent)
return;
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal(); const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
const auto pWindow = g_pCompositor->vectorToWindowIdeal(MOUSECOORDS); const auto pWindow = g_pCompositor->vectorToWindowIdeal(MOUSECOORDS);
@@ -685,8 +716,7 @@ void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) {
} }
} }
if (passEvent) wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, e->time_msec, e->orientation, factor * e->delta, std::round(factor * e->delta_discrete), e->source);
wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, e->time_msec, e->orientation, factor * e->delta, std::round(factor * e->delta_discrete), e->source);
} }
Vector2D CInputManager::getMouseCoordsInternal() { Vector2D CInputManager::getMouseCoordsInternal() {
@@ -871,7 +901,7 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
pKeyboard->currentRules.model = ""; pKeyboard->currentRules.model = "";
pKeyboard->currentRules.variant = ""; pKeyboard->currentRules.variant = "";
pKeyboard->currentRules.options = ""; pKeyboard->currentRules.options = "";
pKeyboard->currentRules.layout = ""; pKeyboard->currentRules.layout = "us";
KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
} }
@@ -1053,7 +1083,7 @@ void CInputManager::setPointerConfigs() {
const auto CONFIG = libinput_config_accel_create(LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM); const auto CONFIG = libinput_config_accel_create(LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM);
libinput_config_accel_set_points(CONFIG, LIBINPUT_ACCEL_TYPE_MOTION, step, points.size(), points.data()); libinput_config_accel_set_points(CONFIG, LIBINPUT_ACCEL_TYPE_MOTION, step, points.size(), points.data());
libinput_device_config_accel_set_profile(LIBINPUTDEV, LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM); libinput_device_config_accel_apply(LIBINPUTDEV, CONFIG);
libinput_config_accel_destroy(CONFIG); libinput_config_accel_destroy(CONFIG);
} catch (std::exception& e) { Debug::log(ERR, "Invalid values in custom accel profile"); } } catch (std::exception& e) { Debug::log(ERR, "Invalid values in custom accel profile"); }
} else { } else {
@@ -1131,6 +1161,9 @@ void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboar
if (!pKeyboard->enabled) if (!pKeyboard->enabled)
return; return;
const auto EMAP = std::unordered_map<std::string, std::any>{{"keyboard", pKeyboard}, {"event", e}};
EMIT_HOOK_EVENT_CANCELLABLE("keyPress", EMAP);
static auto* const PDPMS = &g_pConfigManager->getConfigValuePtr("misc:key_press_enables_dpms")->intValue; static auto* const PDPMS = &g_pConfigManager->getConfigValuePtr("misc:key_press_enables_dpms")->intValue;
if (*PDPMS && !g_pCompositor->m_bDPMSStateON) { if (*PDPMS && !g_pCompositor->m_bDPMSStateON) {
// enable dpms // enable dpms

View File

@@ -7,12 +7,14 @@
#include "../../helpers/Timer.hpp" #include "../../helpers/Timer.hpp"
#include "InputMethodRelay.hpp" #include "InputMethodRelay.hpp"
enum eClickBehaviorMode { enum eClickBehaviorMode
{
CLICKMODE_DEFAULT = 0, CLICKMODE_DEFAULT = 0,
CLICKMODE_KILL CLICKMODE_KILL
}; };
enum eMouseBindMode { enum eMouseBindMode
{
MBIND_INVALID = -1, MBIND_INVALID = -1,
MBIND_MOVE = 0, MBIND_MOVE = 0,
MBIND_RESIZE = 1, MBIND_RESIZE = 1,
@@ -20,7 +22,8 @@ enum eMouseBindMode {
MBIND_RESIZE_FORCE_RATIO = 3 MBIND_RESIZE_FORCE_RATIO = 3
}; };
enum eBorderIconDirection { enum eBorderIconDirection
{
BORDERICON_NONE, BORDERICON_NONE,
BORDERICON_UP, BORDERICON_UP,
BORDERICON_DOWN, BORDERICON_DOWN,
@@ -61,6 +64,8 @@ class CKeybindManager;
class CInputManager { class CInputManager {
public: public:
~CInputManager();
void onMouseMoved(wlr_pointer_motion_event*); void onMouseMoved(wlr_pointer_motion_event*);
void onMouseWarp(wlr_pointer_motion_absolute_event*); void onMouseWarp(wlr_pointer_motion_absolute_event*);
void onMouseButton(wlr_pointer_button_event*); void onMouseButton(wlr_pointer_button_event*);

View File

@@ -44,13 +44,14 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
if (!m_sActiveSwipe.pWorkspaceBegin) if (!m_sActiveSwipe.pWorkspaceBegin)
return; // no valid swipe return; // no valid swipe
static auto* const PSWIPEPERC = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_cancel_ratio")->floatValue; static auto* const PSWIPEPERC = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_cancel_ratio")->floatValue;
static auto* const PSWIPEDIST = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_distance")->intValue; static auto* const PSWIPEDIST = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_distance")->intValue;
static auto* const PSWIPEFORC = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_min_speed_to_force")->intValue; static auto* const PSWIPEFORC = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_min_speed_to_force")->intValue;
static auto* const PSWIPENEW = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_create_new")->intValue; static auto* const PSWIPENEW = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_create_new")->intValue;
static auto* const PSWIPENUMBER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_numbered")->intValue; static auto* const PSWIPENUMBER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_numbered")->intValue;
static auto* const PSWIPEUSER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_use_r")->intValue; static auto* const PSWIPEUSER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_use_r")->intValue;
const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || static auto* const PWORKSPACEGAP = &g_pConfigManager->getConfigValuePtr("general:gaps_workspaces")->intValue;
const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" ||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert");
// commit // commit
@@ -75,10 +76,12 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
workspaceIDRight = maxWorkspace + 1; workspaceIDRight = maxWorkspace + 1;
} }
auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); // not guaranteed if PSWIPENEW || PSWIPENUMBER auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); // not guaranteed if PSWIPENEW || PSWIPENUMBER
auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft); // not guaranteed if PSWIPENUMBER auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft); // not guaranteed if PSWIPENUMBER
const auto RENDEROFFSETMIDDLE = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.vec(); const auto RENDEROFFSETMIDDLE = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.vec();
const auto XDISTANCE = m_sActiveSwipe.pMonitor->vecSize.x + *PWORKSPACEGAP;
const auto YDISTANCE = m_sActiveSwipe.pMonitor->vecSize.y + *PWORKSPACEGAP;
CWorkspace* pSwitchedTo = nullptr; CWorkspace* pSwitchedTo = nullptr;
@@ -94,18 +97,19 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
} else { } else {
if (m_sActiveSwipe.delta < 0) { if (m_sActiveSwipe.delta < 0) {
// to left // to left
if (PWORKSPACEL) { if (PWORKSPACEL) {
if (VERTANIMS) if (VERTANIMS)
PWORKSPACEL->m_vRenderOffset = Vector2D({0, -m_sActiveSwipe.pMonitor->vecSize.y}); PWORKSPACEL->m_vRenderOffset = Vector2D({0, -YDISTANCE});
else else
PWORKSPACEL->m_vRenderOffset = Vector2D({-m_sActiveSwipe.pMonitor->vecSize.x, 0}); PWORKSPACEL->m_vRenderOffset = Vector2D({-XDISTANCE, 0});
} }
} else if (PWORKSPACER) { } else if (PWORKSPACER) {
// to right // to right
if (VERTANIMS) if (VERTANIMS)
PWORKSPACER->m_vRenderOffset = Vector2D({0, m_sActiveSwipe.pMonitor->vecSize.y}); PWORKSPACER->m_vRenderOffset = Vector2D({0, YDISTANCE});
else else
PWORKSPACER->m_vRenderOffset = Vector2D({m_sActiveSwipe.pMonitor->vecSize.x, 0}); PWORKSPACER->m_vRenderOffset = Vector2D({XDISTANCE, 0});
} }
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(); m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D();
@@ -128,9 +132,9 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValue(RENDEROFFSETMIDDLE); m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValue(RENDEROFFSETMIDDLE);
if (VERTANIMS) if (VERTANIMS)
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(0, m_sActiveSwipe.pMonitor->vecSize.y); m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(0, YDISTANCE);
else else
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(m_sActiveSwipe.pMonitor->vecSize.x, 0); m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(XDISTANCE, 0);
m_sActiveSwipe.pWorkspaceBegin->m_fAlpha.setValueAndWarp(1.f); m_sActiveSwipe.pWorkspaceBegin->m_fAlpha.setValueAndWarp(1.f);
g_pInputManager->unconstrainMouse(); g_pInputManager->unconstrainMouse();
@@ -154,9 +158,9 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValue(RENDEROFFSETMIDDLE); m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValue(RENDEROFFSETMIDDLE);
if (VERTANIMS) if (VERTANIMS)
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(0, -m_sActiveSwipe.pMonitor->vecSize.y); m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(0, -YDISTANCE);
else else
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(-m_sActiveSwipe.pMonitor->vecSize.x, 0); m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(-XDISTANCE, 0);
m_sActiveSwipe.pWorkspaceBegin->m_fAlpha.setValueAndWarp(1.f); m_sActiveSwipe.pWorkspaceBegin->m_fAlpha.setValueAndWarp(1.f);
g_pInputManager->unconstrainMouse(); g_pInputManager->unconstrainMouse();
@@ -198,8 +202,11 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
static auto* const PSWIPEFOREVER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_forever")->intValue; static auto* const PSWIPEFOREVER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_forever")->intValue;
static auto* const PSWIPENUMBER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_numbered")->intValue; static auto* const PSWIPENUMBER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_numbered")->intValue;
static auto* const PSWIPEUSER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_use_r")->intValue; static auto* const PSWIPEUSER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_use_r")->intValue;
static auto* const PWORKSPACEGAP = &g_pConfigManager->getConfigValuePtr("general:gaps_workspaces")->intValue;
const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || const auto XDISTANCE = m_sActiveSwipe.pMonitor->vecSize.x + *PWORKSPACEGAP;
const auto YDISTANCE = m_sActiveSwipe.pMonitor->vecSize.y + *PWORKSPACEGAP;
const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" ||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert");
m_sActiveSwipe.delta += VERTANIMS ? (*PSWIPEINVR ? -e->dy : e->dy) : (*PSWIPEINVR ? -e->dx : e->dx); m_sActiveSwipe.delta += VERTANIMS ? (*PSWIPEINVR ? -e->dy : e->dy) : (*PSWIPEINVR ? -e->dx : e->dx);
@@ -211,7 +218,7 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
auto workspaceIDLeft = getWorkspaceIDFromString(*PSWIPENUMBER ? "-1" : (*PSWIPEUSER ? "r-1" : "m-1"), wsname); auto workspaceIDLeft = getWorkspaceIDFromString(*PSWIPENUMBER ? "-1" : (*PSWIPEUSER ? "r-1" : "m-1"), wsname);
auto workspaceIDRight = getWorkspaceIDFromString(*PSWIPENUMBER ? "+1" : (*PSWIPEUSER ? "r+1" : "m+1"), wsname); auto workspaceIDRight = getWorkspaceIDFromString(*PSWIPENUMBER ? "+1" : (*PSWIPEUSER ? "r+1" : "m+1"), wsname);
if ((workspaceIDLeft == INT_MAX || workspaceIDRight == INT_MAX || workspaceIDLeft == m_sActiveSwipe.pWorkspaceBegin->m_iID) && !*PSWIPENEW) { if ((workspaceIDLeft == WORKSPACE_INVALID || workspaceIDRight == WORKSPACE_INVALID || workspaceIDLeft == m_sActiveSwipe.pWorkspaceBegin->m_iID) && !*PSWIPENEW) {
m_sActiveSwipe.pWorkspaceBegin = nullptr; // invalidate the swipe m_sActiveSwipe.pWorkspaceBegin = nullptr; // invalidate the swipe
return; return;
} }
@@ -244,9 +251,11 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor); g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor);
if (VERTANIMS) if (VERTANIMS)
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.y)); m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(
Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * YDISTANCE));
else else
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x, 0)); m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(
Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * XDISTANCE, 0));
g_pCompositor->updateWorkspaceWindowDecos(m_sActiveSwipe.pWorkspaceBegin->m_iID); g_pCompositor->updateWorkspaceWindowDecos(m_sActiveSwipe.pWorkspaceBegin->m_iID);
return; return;
@@ -268,13 +277,15 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
} }
if (VERTANIMS) { if (VERTANIMS) {
PWORKSPACE->m_vRenderOffset.setValueAndWarp( PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(
Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.y - m_sActiveSwipe.pMonitor->vecSize.y)); 0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * YDISTANCE - YDISTANCE));
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.y)); m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(
Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * YDISTANCE));
} else { } else {
PWORKSPACE->m_vRenderOffset.setValueAndWarp( PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(
Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x - m_sActiveSwipe.pMonitor->vecSize.x, 0)); ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * XDISTANCE - XDISTANCE, 0));
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x, 0)); m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(
Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * XDISTANCE, 0));
} }
g_pCompositor->updateWorkspaceWindowDecos(workspaceIDLeft); g_pCompositor->updateWorkspaceWindowDecos(workspaceIDLeft);
@@ -286,9 +297,11 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor); g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor);
if (VERTANIMS) if (VERTANIMS)
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.y)); m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(
Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * YDISTANCE));
else else
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x, 0)); m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(
Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * XDISTANCE, 0));
g_pCompositor->updateWorkspaceWindowDecos(m_sActiveSwipe.pWorkspaceBegin->m_iID); g_pCompositor->updateWorkspaceWindowDecos(m_sActiveSwipe.pWorkspaceBegin->m_iID);
return; return;
@@ -310,13 +323,15 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
} }
if (VERTANIMS) { if (VERTANIMS) {
PWORKSPACE->m_vRenderOffset.setValueAndWarp( PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(
Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.y + m_sActiveSwipe.pMonitor->vecSize.y)); 0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * YDISTANCE + YDISTANCE));
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.y)); m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(
Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * YDISTANCE));
} else { } else {
PWORKSPACE->m_vRenderOffset.setValueAndWarp( PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(
Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x + m_sActiveSwipe.pMonitor->vecSize.x, 0)); ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * XDISTANCE + XDISTANCE, 0));
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x, 0)); m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(
Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * XDISTANCE, 0));
} }
g_pCompositor->updateWorkspaceWindowDecos(workspaceIDRight); g_pCompositor->updateWorkspaceWindowDecos(workspaceIDRight);

View File

@@ -2,6 +2,8 @@
#include "../../Compositor.hpp" #include "../../Compositor.hpp"
void CInputManager::onTouchDown(wlr_touch_down_event* e) { void CInputManager::onTouchDown(wlr_touch_down_event* e) {
EMIT_HOOK_EVENT_CANCELLABLE("touchDown", e);
auto PMONITOR = g_pCompositor->getMonitorFromName(e->touch->output_name ? e->touch->output_name : ""); auto PMONITOR = g_pCompositor->getMonitorFromName(e->touch->output_name ? e->touch->output_name : "");
const auto PDEVIT = std::find_if(m_lTouchDevices.begin(), m_lTouchDevices.end(), [&](const STouchDevice& other) { return other.pWlrDevice == &e->touch->base; }); const auto PDEVIT = std::find_if(m_lTouchDevices.begin(), m_lTouchDevices.end(), [&](const STouchDevice& other) { return other.pWlrDevice == &e->touch->base; });
@@ -52,12 +54,14 @@ void CInputManager::onTouchDown(wlr_touch_down_event* e) {
} }
void CInputManager::onTouchUp(wlr_touch_up_event* e) { void CInputManager::onTouchUp(wlr_touch_up_event* e) {
EMIT_HOOK_EVENT_CANCELLABLE("touchUp", e);
if (m_sTouchData.touchFocusSurface) { if (m_sTouchData.touchFocusSurface) {
wlr_seat_touch_notify_up(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id); wlr_seat_touch_notify_up(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id);
} }
} }
void CInputManager::onTouchMove(wlr_touch_motion_event* e) { void CInputManager::onTouchMove(wlr_touch_motion_event* e) {
EMIT_HOOK_EVENT_CANCELLABLE("touchMove", e);
if (m_sTouchData.touchFocusWindow && g_pCompositor->windowValidMapped(m_sTouchData.touchFocusWindow)) { if (m_sTouchData.touchFocusWindow && g_pCompositor->windowValidMapped(m_sTouchData.touchFocusWindow)) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusWindow->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusWindow->m_iMonitorID);
@@ -68,7 +72,7 @@ void CInputManager::onTouchMove(wlr_touch_motion_event* e) {
local = local * m_sTouchData.touchFocusWindow->m_fX11SurfaceScaledBy; local = local * m_sTouchData.touchFocusWindow->m_fX11SurfaceScaledBy;
wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id, local.x, local.y); wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id, local.x, local.y);
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, local.x, local.y); // wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, local.x, local.y);
} else if (m_sTouchData.touchFocusLS) { } else if (m_sTouchData.touchFocusLS) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusLS->monitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusLS->monitorID);
@@ -77,7 +81,7 @@ void CInputManager::onTouchMove(wlr_touch_motion_event* e) {
const auto local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchSurfaceOrigin; const auto local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchSurfaceOrigin;
wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id, local.x, local.y); wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id, local.x, local.y);
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, local.x, local.y); // wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, local.x, local.y);
} }
} }

View File

@@ -1,4 +1,5 @@
#include "HookSystem.hpp" #include "HookSystem.hpp"
#include "../debug/Log.hpp"
#define register #define register
#include <udis86.h> #include <udis86.h>
@@ -45,6 +46,10 @@ size_t CFunctionHook::getInstructionLenAt(void* start) {
// I don't have an assembler. I don't think udis provides one. Besides, variables might be tricky. // I don't have an assembler. I don't think udis provides one. Besides, variables might be tricky.
if (((uint8_t*)start)[0] == 0xFF && ((uint8_t*)start)[1] == 0x15) if (((uint8_t*)start)[0] == 0xFF && ((uint8_t*)start)[1] == 0x15)
m_vTrampolineRIPUses.emplace_back(std::make_pair<>((uint64_t)start - (uint64_t)m_pSource, ins)); m_vTrampolineRIPUses.emplace_back(std::make_pair<>((uint64_t)start - (uint64_t)m_pSource, ins));
else {
Debug::log(ERR, "[CFunctionHook] Cannot hook: unsupported %rip usage: {}", ins);
throw std::runtime_error("unsupported %rip usage");
}
} }
return insSize; return insSize;
@@ -90,7 +95,10 @@ bool CFunctionHook::hook() {
static constexpr size_t CALL_WITH_RAX_ADDRESS_OFFSET = 2; static constexpr size_t CALL_WITH_RAX_ADDRESS_OFFSET = 2;
// get minimum size to overwrite // get minimum size to overwrite
const auto HOOKSIZE = probeMinimumJumpSize(m_pSource, sizeof(ABSOLUTE_JMP_ADDRESS) + sizeof(PUSH_RAX) + sizeof(POP_RAX)); size_t HOOKSIZE = 0;
try {
HOOKSIZE = probeMinimumJumpSize(m_pSource, sizeof(ABSOLUTE_JMP_ADDRESS) + sizeof(PUSH_RAX) + sizeof(POP_RAX));
} catch (std::exception& e) { return false; }
// alloc trampoline // alloc trampoline
const auto TRAMPOLINE_SIZE = sizeof(ABSOLUTE_JMP_ADDRESS) + HOOKSIZE + sizeof(PUSH_RAX) + m_vTrampolineRIPUses.size() * (sizeof(CALL_WITH_RAX) - 6); const auto TRAMPOLINE_SIZE = sizeof(ABSOLUTE_JMP_ADDRESS) + HOOKSIZE + sizeof(PUSH_RAX) + m_vTrampolineRIPUses.size() * (sizeof(CALL_WITH_RAX) - 6);

View File

@@ -10,7 +10,10 @@ CPluginSystem::CPluginSystem() {
CPlugin* CPluginSystem::loadPlugin(const std::string& path) { CPlugin* CPluginSystem::loadPlugin(const std::string& path) {
m_szLastError = "";
if (getPluginByPath(path)) { if (getPluginByPath(path)) {
m_szLastError = "Cannot load a plugin twice!";
Debug::log(ERR, " [PluginSystem] Cannot load a plugin twice!"); Debug::log(ERR, " [PluginSystem] Cannot load a plugin twice!");
return nullptr; return nullptr;
} }
@@ -22,7 +25,9 @@ CPlugin* CPluginSystem::loadPlugin(const std::string& path) {
HANDLE MODULE = dlopen(path.c_str(), RTLD_LAZY); HANDLE MODULE = dlopen(path.c_str(), RTLD_LAZY);
if (!MODULE) { if (!MODULE) {
Debug::log(ERR, " [PluginSystem] Plugin {} could not be loaded: {}", path, dlerror()); std::string strerr = dlerror();
m_szLastError = std::format("Plugin {} could not be loaded: {}", path, strerr);
Debug::log(ERR, " [PluginSystem] Plugin {} could not be loaded: {}", path, strerr);
m_vLoadedPlugins.pop_back(); m_vLoadedPlugins.pop_back();
return nullptr; return nullptr;
} }
@@ -33,6 +38,7 @@ CPlugin* CPluginSystem::loadPlugin(const std::string& path) {
PPLUGIN_INIT_FUNC initFunc = (PPLUGIN_INIT_FUNC)dlsym(MODULE, PLUGIN_INIT_FUNC_STR); PPLUGIN_INIT_FUNC initFunc = (PPLUGIN_INIT_FUNC)dlsym(MODULE, PLUGIN_INIT_FUNC_STR);
if (!apiVerFunc || !initFunc) { if (!apiVerFunc || !initFunc) {
m_szLastError = std::format("Plugin {} could not be loaded: {}", path, "missing apiver/init func");
Debug::log(ERR, " [PluginSystem] Plugin {} could not be loaded. (No apiver/init func)", path); Debug::log(ERR, " [PluginSystem] Plugin {} could not be loaded. (No apiver/init func)", path);
dlclose(MODULE); dlclose(MODULE);
m_vLoadedPlugins.pop_back(); m_vLoadedPlugins.pop_back();
@@ -42,6 +48,7 @@ CPlugin* CPluginSystem::loadPlugin(const std::string& path) {
const std::string PLUGINAPIVER = apiVerFunc(); const std::string PLUGINAPIVER = apiVerFunc();
if (PLUGINAPIVER != HYPRLAND_API_VERSION) { if (PLUGINAPIVER != HYPRLAND_API_VERSION) {
m_szLastError = std::format("Plugin {} could not be loaded: {}", path, "API version mismatch");
Debug::log(ERR, " [PluginSystem] Plugin {} could not be loaded. (API version mismatch)", path); Debug::log(ERR, " [PluginSystem] Plugin {} could not be loaded. (API version mismatch)", path);
dlclose(MODULE); dlclose(MODULE);
m_vLoadedPlugins.pop_back(); m_vLoadedPlugins.pop_back();
@@ -56,10 +63,11 @@ CPlugin* CPluginSystem::loadPlugin(const std::string& path) {
PLUGINDATA = initFunc(MODULE); PLUGINDATA = initFunc(MODULE);
} else { } else {
// this module crashed. // this module crashed.
throw std::exception(); throw std::runtime_error("received a fatal signal");
} }
} catch (std::exception& e) { } catch (std::exception& e) {
m_bAllowConfigVars = false; m_bAllowConfigVars = false;
m_szLastError = std::format("Plugin {} could not be loaded: plugin crashed/threw in main: {}", path, e.what());
Debug::log(ERR, " [PluginSystem] Plugin {} (Handle {:x}) crashed in init. Unloading.", path, (uintptr_t)MODULE); Debug::log(ERR, " [PluginSystem] Plugin {} (Handle {:x}) crashed in init. Unloading.", path, (uintptr_t)MODULE);
unloadPlugin(PLUGIN, true); // Plugin could've already hooked/done something unloadPlugin(PLUGIN, true); // Plugin could've already hooked/done something
return nullptr; return nullptr;

View File

@@ -38,6 +38,7 @@ class CPluginSystem {
std::vector<CPlugin*> getAllPlugins(); std::vector<CPlugin*> getAllPlugins();
bool m_bAllowConfigVars = false; bool m_bAllowConfigVars = false;
std::string m_szLastError = "";
private: private:
std::vector<std::unique_ptr<CPlugin>> m_vLoadedPlugins; std::vector<std::unique_ptr<CPlugin>> m_vLoadedPlugins;

View File

@@ -210,7 +210,8 @@ void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* r
PFRAME->client = PCLIENT; PFRAME->client = PCLIENT;
PCLIENT->ref++; PCLIENT->ref++;
PFRAME->shmFormat = wlr_output_preferred_read_format(PFRAME->pMonitor->output); g_pHyprRenderer->makeEGLCurrent();
PFRAME->shmFormat = g_pHyprOpenGL->getPreferredReadFormat(PFRAME->pMonitor);
if (PFRAME->shmFormat == DRM_FORMAT_INVALID) { if (PFRAME->shmFormat == DRM_FORMAT_INVALID) {
Debug::log(ERR, "No format supported by renderer in capture output"); Debug::log(ERR, "No format supported by renderer in capture output");
zwlr_screencopy_frame_v1_send_failed(PFRAME->resource); zwlr_screencopy_frame_v1_send_failed(PFRAME->resource);
@@ -241,7 +242,7 @@ void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* r
wlr_output_effective_resolution(PFRAME->pMonitor->output, &ow, &oh); wlr_output_effective_resolution(PFRAME->pMonitor->output, &ow, &oh);
PFRAME->box.transform(PFRAME->pMonitor->transform, ow, oh).scale(PFRAME->pMonitor->scale).round(); PFRAME->box.transform(PFRAME->pMonitor->transform, ow, oh).scale(PFRAME->pMonitor->scale).round();
PFRAME->shmStride = (PSHMINFO->bpp / 8) * PFRAME->box.width; PFRAME->shmStride = pixel_format_info_min_stride(PSHMINFO, PFRAME->box.w);
zwlr_screencopy_frame_v1_send_buffer(PFRAME->resource, convert_drm_format_to_wl_shm(PFRAME->shmFormat), PFRAME->box.width, PFRAME->box.height, PFRAME->shmStride); zwlr_screencopy_frame_v1_send_buffer(PFRAME->resource, convert_drm_format_to_wl_shm(PFRAME->shmFormat), PFRAME->box.width, PFRAME->box.height, PFRAME->shmStride);
@@ -424,23 +425,76 @@ void CScreencopyProtocolManager::sendFrameDamage(SScreencopyFrame* frame) {
} }
bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* now) { bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* now) {
wlr_texture* sourceTex = wlr_texture_from_buffer(g_pCompositor->m_sWLRRenderer, m_pLastMonitorBackBuffer);
if (!sourceTex)
return false;
void* data; void* data;
uint32_t format; uint32_t format;
size_t stride; size_t stride;
if (!wlr_buffer_begin_data_ptr_access(frame->buffer, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &data, &format, &stride)) if (!wlr_buffer_begin_data_ptr_access(frame->buffer, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &data, &format, &stride)) {
wlr_texture_destroy(sourceTex);
return false; return false;
}
if (!wlr_renderer_begin_with_buffer(g_pCompositor->m_sWLRRenderer, m_pLastMonitorBackBuffer)) { CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX};
Debug::log(ERR, "[sc] shm: Client requested a copy to a buffer that failed to pass wlr_renderer_begin_with_buffer");
g_pHyprRenderer->makeEGLCurrent();
CFramebuffer fb;
fb.alloc(frame->box.w, frame->box.h, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : frame->pMonitor->drmFormat);
if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &fb)) {
wlr_texture_destroy(sourceTex);
wlr_buffer_end_data_ptr_access(frame->buffer); wlr_buffer_end_data_ptr_access(frame->buffer);
return false; return false;
} }
bool success = wlr_renderer_read_pixels(g_pCompositor->m_sWLRRenderer, format, stride, frame->box.width, frame->box.height, frame->box.x, frame->box.y, 0, 0, data); CBox monbox = CBox{0, 0, frame->pMonitor->vecTransformedSize.x, frame->pMonitor->vecTransformedSize.y}.translate({-frame->box.x, -frame->box.y});
wlr_renderer_end(g_pCompositor->m_sWLRRenderer); g_pHyprOpenGL->setMonitorTransformEnabled(false);
wlr_buffer_end_data_ptr_access(frame->buffer); g_pHyprOpenGL->renderTexture(sourceTex, &monbox, 1);
g_pHyprOpenGL->setMonitorTransformEnabled(true);
return success; #ifndef GLES2
glBindFramebuffer(GL_READ_FRAMEBUFFER, fb.m_iFb);
#else
glBindFramebuffer(GL_FRAMEBUFFER, fb.m_iFb);
#endif
const auto PFORMAT = g_pHyprOpenGL->getPixelFormatFromDRM(format);
if (!PFORMAT) {
g_pHyprRenderer->endRender();
wlr_texture_destroy(sourceTex);
wlr_buffer_end_data_ptr_access(frame->buffer);
return false;
}
g_pHyprRenderer->endRender();
g_pHyprRenderer->makeEGLCurrent();
g_pHyprOpenGL->m_RenderData.pMonitor = frame->pMonitor;
fb.bind();
glPixelStorei(GL_PACK_ALIGNMENT, 1);
const wlr_pixel_format_info* drmFmtWlr = drm_get_pixel_format_info(format);
uint32_t packStride = pixel_format_info_min_stride(drmFmtWlr, frame->box.w);
if (packStride == stride) {
glReadPixels(0, 0, frame->box.w, frame->box.h, PFORMAT->glFormat, PFORMAT->glType, data);
} else {
for (size_t i = 0; i < frame->box.h; ++i) {
uint32_t y = i;
glReadPixels(0, y, frame->box.w, 1, PFORMAT->glFormat, PFORMAT->glType, ((unsigned char*)data) + i * stride);
}
}
g_pHyprOpenGL->m_RenderData.pMonitor = nullptr;
wlr_buffer_end_data_ptr_access(frame->buffer);
wlr_texture_destroy(sourceTex);
return true;
} }
bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) { bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) {
@@ -448,25 +502,19 @@ bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) {
if (!sourceTex) if (!sourceTex)
return false; return false;
float glMatrix[9]; CRegion fakeDamage = {0, 0, frame->box.width, frame->box.height};
wlr_matrix_identity(glMatrix);
wlr_matrix_translate(glMatrix, -frame->box.x, -frame->box.y);
wlr_matrix_scale(glMatrix, frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y);
if (!wlr_renderer_begin_with_buffer(g_pCompositor->m_sWLRRenderer, frame->buffer)) { if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer))
Debug::log(ERR, "[sc] dmabuf: Client requested a copy to a buffer that failed to pass wlr_renderer_begin_with_buffer");
wlr_texture_destroy(sourceTex);
return false; return false;
}
float color[] = {0, 0, 0, 0}; CBox monbox = CBox{0, 0, frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y}.translate({-frame->box.x, -frame->box.y});
wlr_renderer_clear(g_pCompositor->m_sWLRRenderer, color); g_pHyprOpenGL->setMonitorTransformEnabled(false);
// TODO: use hl render methods to use damage g_pHyprOpenGL->renderTexture(sourceTex, &monbox, 1);
wlr_render_texture_with_matrix(g_pCompositor->m_sWLRRenderer, sourceTex, glMatrix, 1.0f); g_pHyprOpenGL->setMonitorTransformEnabled(true);
g_pHyprRenderer->endRender();
wlr_texture_destroy(sourceTex); wlr_texture_destroy(sourceTex);
wlr_renderer_end(g_pCompositor->m_sWLRRenderer);
return true; return true;
} }

View File

@@ -134,7 +134,8 @@ void CToplevelExportProtocolManager::removeFrame(SScreencopyFrame* frame, bool f
std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other == frame; }); std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other == frame; });
wl_resource_set_user_data(frame->resource, nullptr); wl_resource_set_user_data(frame->resource, nullptr);
wlr_buffer_unlock(frame->buffer); if (frame->buffer && frame->buffer->n_locks > 0)
wlr_buffer_unlock(frame->buffer);
removeClient(frame->client, force); removeClient(frame->client, force);
m_lFrames.remove(*frame); m_lFrames.remove(*frame);
} }
@@ -176,7 +177,8 @@ void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resou
const auto PMONITOR = g_pCompositor->getMonitorFromID(PFRAME->pWindow->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(PFRAME->pWindow->m_iMonitorID);
PFRAME->shmFormat = wlr_output_preferred_read_format(PMONITOR->output); g_pHyprRenderer->makeEGLCurrent();
PFRAME->shmFormat = g_pHyprOpenGL->getPreferredReadFormat(PMONITOR);
if (PFRAME->shmFormat == DRM_FORMAT_INVALID) { if (PFRAME->shmFormat == DRM_FORMAT_INVALID) {
Debug::log(ERR, "No format supported by renderer in capture toplevel"); Debug::log(ERR, "No format supported by renderer in capture toplevel");
hyprland_toplevel_export_frame_v1_send_failed(resource); hyprland_toplevel_export_frame_v1_send_failed(resource);
@@ -203,7 +205,7 @@ void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resou
wlr_output_effective_resolution(PMONITOR->output, &ow, &oh); wlr_output_effective_resolution(PMONITOR->output, &ow, &oh);
PFRAME->box.transform(PMONITOR->transform, ow, oh).round(); PFRAME->box.transform(PMONITOR->transform, ow, oh).round();
PFRAME->shmStride = (PSHMINFO->bpp / 8) * PFRAME->box.width; PFRAME->shmStride = pixel_format_info_min_stride(PSHMINFO, PFRAME->box.w);
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); 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);
@@ -362,18 +364,19 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times
const auto PMONITOR = g_pCompositor->getMonitorFromID(frame->pWindow->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(frame->pWindow->m_iMonitorID);
CRegion fakeDamage{0, 0, PMONITOR->vecPixelSize.x * 10, PMONITOR->vecPixelSize.y * 10}; CRegion fakeDamage{0, 0, PMONITOR->vecPixelSize.x * 10, PMONITOR->vecPixelSize.y * 10};
if (frame->overlayCursor) g_pHyprRenderer->makeEGLCurrent();
wlr_output_lock_software_cursors(PMONITOR->output, true);
if (!wlr_output_attach_render(PMONITOR->output, nullptr)) { CFramebuffer outFB;
Debug::log(ERR, "[toplevel_export] Couldn't attach render"); outFB.alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : PMONITOR->drmFormat);
if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &outFB)) {
wlr_buffer_end_data_ptr_access(frame->buffer); wlr_buffer_end_data_ptr_access(frame->buffer);
if (frame->overlayCursor)
wlr_output_lock_software_cursors(PMONITOR->output, false);
return false; return false;
} }
g_pHyprOpenGL->begin(PMONITOR, &fakeDamage, true); if (frame->overlayCursor)
wlr_output_lock_software_cursors(PMONITOR->output, true);
g_pHyprOpenGL->clear(CColor(0, 0, 0, 1.0)); g_pHyprOpenGL->clear(CColor(0, 0, 0, 1.0));
// render client at 0,0 // render client at 0,0
@@ -381,46 +384,23 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times
g_pHyprRenderer->renderWindow(frame->pWindow, PMONITOR, now, false, RENDER_PASS_ALL, true, true); g_pHyprRenderer->renderWindow(frame->pWindow, PMONITOR, now, false, RENDER_PASS_ALL, true, true);
g_pHyprRenderer->m_bBlockSurfaceFeedback = false; g_pHyprRenderer->m_bBlockSurfaceFeedback = false;
if (frame->overlayCursor && wlr_renderer_begin(g_pCompositor->m_sWLRRenderer, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y)) { if (frame->overlayCursor)
// hack le massive g_pHyprRenderer->renderSoftwareCursors(PMONITOR, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow->m_vRealPosition.vec());
wlr_output_cursor* cursor;
const auto OFFSET = frame->pWindow->m_vRealPosition.vec() - PMONITOR->vecPosition;
wl_list_for_each(cursor, &PMONITOR->output->cursors, link) {
if (!cursor->enabled || !cursor->visible || PMONITOR->output->hardware_cursor == cursor) {
continue;
}
cursor->x -= OFFSET.x;
cursor->y -= OFFSET.y;
}
wlr_output_render_software_cursors(PMONITOR->output, NULL);
wl_list_for_each(cursor, &PMONITOR->output->cursors, link) {
if (!cursor->enabled || !cursor->visible || PMONITOR->output->hardware_cursor == cursor) {
continue;
}
cursor->x += OFFSET.x;
cursor->y += OFFSET.y;
}
wlr_renderer_end(g_pCompositor->m_sWLRRenderer);
}
// copy pixels const auto PFORMAT = g_pHyprOpenGL->getPixelFormatFromDRM(format);
const auto PFORMAT = gles2FromDRM(format);
if (!PFORMAT) { if (!PFORMAT) {
Debug::log(ERR, "[toplevel_export] Cannot read pixels, unsupported format {:x}", (uintptr_t)PFORMAT); g_pHyprRenderer->endRender();
g_pHyprOpenGL->end();
wlr_buffer_end_data_ptr_access(frame->buffer); wlr_buffer_end_data_ptr_access(frame->buffer);
if (frame->overlayCursor)
wlr_output_lock_software_cursors(PMONITOR->output, false);
return false; return false;
} }
glBindFramebuffer(GL_FRAMEBUFFER, g_pHyprOpenGL->m_RenderData.pCurrentMonData->primaryFB.m_iFb); g_pHyprOpenGL->m_RenderData.mainFB->bind();
glReadPixels(0, 0, frame->box.width, frame->box.height, PFORMAT->gl_format, PFORMAT->gl_type, data); glPixelStorei(GL_PACK_ALIGNMENT, 1);
g_pHyprOpenGL->end(); glReadPixels(0, 0, frame->box.width, frame->box.height, PFORMAT->glFormat, PFORMAT->glType, data);
wlr_output_rollback(PMONITOR->output); g_pHyprRenderer->endRender();
wlr_buffer_end_data_ptr_access(frame->buffer); wlr_buffer_end_data_ptr_access(frame->buffer);
@@ -431,14 +411,12 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times
} }
bool CToplevelExportProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame, timespec* now) { bool CToplevelExportProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame, timespec* now) {
if (!wlr_renderer_begin_with_buffer(g_pCompositor->m_sWLRRenderer, frame->buffer))
return false;
const auto PMONITOR = g_pCompositor->getMonitorFromID(frame->pWindow->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(frame->pWindow->m_iMonitorID);
CRegion fakeDamage{0, 0, INT16_MAX, INT16_MAX}; CRegion fakeDamage{0, 0, INT16_MAX, INT16_MAX};
g_pHyprOpenGL->begin(PMONITOR, &fakeDamage, true); if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer))
return false;
g_pHyprOpenGL->clear(CColor(0, 0, 0, 1.0)); g_pHyprOpenGL->clear(CColor(0, 0, 0, 1.0));
@@ -446,14 +424,10 @@ bool CToplevelExportProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame, ti
g_pHyprRenderer->renderWindow(frame->pWindow, PMONITOR, now, false, RENDER_PASS_ALL, true, true); g_pHyprRenderer->renderWindow(frame->pWindow, PMONITOR, now, false, RENDER_PASS_ALL, true, true);
g_pHyprRenderer->m_bBlockSurfaceFeedback = false; g_pHyprRenderer->m_bBlockSurfaceFeedback = false;
g_pHyprOpenGL->bindWlrOutputFb(); if (frame->overlayCursor)
g_pHyprRenderer->renderSoftwareCursors(PMONITOR, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow->m_vRealPosition.vec());
CBox monbox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y}; g_pHyprRenderer->endRender();
g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_RenderData.pCurrentMonData->primaryFB.m_cTex, &monbox, 1.f);
g_pHyprOpenGL->end();
wlr_renderer_end(g_pCompositor->m_sWLRRenderer);
return true; return true;
} }

View File

@@ -11,8 +11,10 @@ struct wlr_pixel_format_info {
*/ */
uint32_t opaque_substitute; uint32_t opaque_substitute;
/* Bits per pixels */ /* Bytes per block (including padding) */
uint32_t bpp; uint32_t bytes_per_block;
/* Size of a block in pixels (zero for 1×1) */
uint32_t block_width, block_height;
/* True if the format has an alpha channel */ /* True if the format has an alpha channel */
bool has_alpha; bool has_alpha;
@@ -20,143 +22,171 @@ struct wlr_pixel_format_info {
static const struct wlr_pixel_format_info pixel_format_info[] = { static const struct wlr_pixel_format_info pixel_format_info[] = {
{ {
.drm_format = DRM_FORMAT_XRGB8888, .drm_format = DRM_FORMAT_XRGB8888,
.opaque_substitute = DRM_FORMAT_INVALID, .bytes_per_block = 4,
.bpp = 32,
.has_alpha = false,
}, },
{ {
.drm_format = DRM_FORMAT_ARGB8888, .drm_format = DRM_FORMAT_ARGB8888,
.opaque_substitute = DRM_FORMAT_XRGB8888, .opaque_substitute = DRM_FORMAT_XRGB8888,
.bpp = 32, .bytes_per_block = 4,
.has_alpha = true, .has_alpha = true,
}, },
{ {
.drm_format = DRM_FORMAT_XBGR8888, .drm_format = DRM_FORMAT_XBGR8888,
.opaque_substitute = DRM_FORMAT_INVALID, .bytes_per_block = 4,
.bpp = 32,
.has_alpha = false,
}, },
{ {
.drm_format = DRM_FORMAT_ABGR8888, .drm_format = DRM_FORMAT_ABGR8888,
.opaque_substitute = DRM_FORMAT_XBGR8888, .opaque_substitute = DRM_FORMAT_XBGR8888,
.bpp = 32, .bytes_per_block = 4,
.has_alpha = true, .has_alpha = true,
}, },
{ {
.drm_format = DRM_FORMAT_RGBX8888, .drm_format = DRM_FORMAT_RGBX8888,
.opaque_substitute = DRM_FORMAT_INVALID, .bytes_per_block = 4,
.bpp = 32,
.has_alpha = false,
}, },
{ {
.drm_format = DRM_FORMAT_RGBA8888, .drm_format = DRM_FORMAT_RGBA8888,
.opaque_substitute = DRM_FORMAT_RGBX8888, .opaque_substitute = DRM_FORMAT_RGBX8888,
.bpp = 32, .bytes_per_block = 4,
.has_alpha = true, .has_alpha = true,
}, },
{ {
.drm_format = DRM_FORMAT_BGRX8888, .drm_format = DRM_FORMAT_BGRX8888,
.opaque_substitute = DRM_FORMAT_INVALID, .bytes_per_block = 4,
.bpp = 32,
.has_alpha = false,
}, },
{ {
.drm_format = DRM_FORMAT_BGRA8888, .drm_format = DRM_FORMAT_BGRA8888,
.opaque_substitute = DRM_FORMAT_BGRX8888, .opaque_substitute = DRM_FORMAT_BGRX8888,
.bpp = 32, .bytes_per_block = 4,
.has_alpha = true, .has_alpha = true,
}, },
{ {
.drm_format = DRM_FORMAT_BGR888, .drm_format = DRM_FORMAT_R8,
.opaque_substitute = DRM_FORMAT_INVALID, .bytes_per_block = 1,
.bpp = 24,
.has_alpha = false,
}, },
{ {
.drm_format = DRM_FORMAT_RGBX4444, .drm_format = DRM_FORMAT_GR88,
.opaque_substitute = DRM_FORMAT_INVALID, .bytes_per_block = 2,
.bpp = 16, },
.has_alpha = false, {
.drm_format = DRM_FORMAT_RGB888,
.bytes_per_block = 3,
},
{
.drm_format = DRM_FORMAT_BGR888,
.bytes_per_block = 3,
},
{
.drm_format = DRM_FORMAT_RGBX4444,
.bytes_per_block = 2,
}, },
{ {
.drm_format = DRM_FORMAT_RGBA4444, .drm_format = DRM_FORMAT_RGBA4444,
.opaque_substitute = DRM_FORMAT_RGBX4444, .opaque_substitute = DRM_FORMAT_RGBX4444,
.bpp = 16, .bytes_per_block = 2,
.has_alpha = true, .has_alpha = true,
}, },
{ {
.drm_format = DRM_FORMAT_RGBX5551, .drm_format = DRM_FORMAT_BGRX4444,
.opaque_substitute = DRM_FORMAT_INVALID, .bytes_per_block = 2,
.bpp = 16, },
.has_alpha = false, {
.drm_format = DRM_FORMAT_BGRA4444,
.opaque_substitute = DRM_FORMAT_BGRX4444,
.bytes_per_block = 2,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_RGBX5551,
.bytes_per_block = 2,
}, },
{ {
.drm_format = DRM_FORMAT_RGBA5551, .drm_format = DRM_FORMAT_RGBA5551,
.opaque_substitute = DRM_FORMAT_RGBX5551, .opaque_substitute = DRM_FORMAT_RGBX5551,
.bpp = 16, .bytes_per_block = 2,
.has_alpha = true, .has_alpha = true,
}, },
{ {
.drm_format = DRM_FORMAT_RGB565, .drm_format = DRM_FORMAT_BGRX5551,
.opaque_substitute = DRM_FORMAT_INVALID, .bytes_per_block = 2,
.bpp = 16,
.has_alpha = false,
}, },
{ {
.drm_format = DRM_FORMAT_BGR565, .drm_format = DRM_FORMAT_BGRA5551,
.opaque_substitute = DRM_FORMAT_INVALID, .opaque_substitute = DRM_FORMAT_BGRX5551,
.bpp = 16, .bytes_per_block = 2,
.has_alpha = false, .has_alpha = true,
}, },
{ {
.drm_format = DRM_FORMAT_XRGB2101010, .drm_format = DRM_FORMAT_XRGB1555,
.opaque_substitute = DRM_FORMAT_INVALID, .bytes_per_block = 2,
.bpp = 32, },
.has_alpha = false, {
.drm_format = DRM_FORMAT_ARGB1555,
.opaque_substitute = DRM_FORMAT_XRGB1555,
.bytes_per_block = 2,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_RGB565,
.bytes_per_block = 2,
},
{
.drm_format = DRM_FORMAT_BGR565,
.bytes_per_block = 2,
},
{
.drm_format = DRM_FORMAT_XRGB2101010,
.bytes_per_block = 4,
}, },
{ {
.drm_format = DRM_FORMAT_ARGB2101010, .drm_format = DRM_FORMAT_ARGB2101010,
.opaque_substitute = DRM_FORMAT_XRGB2101010, .opaque_substitute = DRM_FORMAT_XRGB2101010,
.bpp = 32, .bytes_per_block = 4,
.has_alpha = true, .has_alpha = true,
}, },
{ {
.drm_format = DRM_FORMAT_XBGR2101010, .drm_format = DRM_FORMAT_XBGR2101010,
.opaque_substitute = DRM_FORMAT_INVALID, .bytes_per_block = 4,
.bpp = 32,
.has_alpha = false,
}, },
{ {
.drm_format = DRM_FORMAT_ABGR2101010, .drm_format = DRM_FORMAT_ABGR2101010,
.opaque_substitute = DRM_FORMAT_XBGR2101010, .opaque_substitute = DRM_FORMAT_XBGR2101010,
.bpp = 32, .bytes_per_block = 4,
.has_alpha = true, .has_alpha = true,
}, },
{ {
.drm_format = DRM_FORMAT_XBGR16161616F, .drm_format = DRM_FORMAT_XBGR16161616F,
.opaque_substitute = DRM_FORMAT_INVALID, .bytes_per_block = 8,
.bpp = 64,
.has_alpha = false,
}, },
{ {
.drm_format = DRM_FORMAT_ABGR16161616F, .drm_format = DRM_FORMAT_ABGR16161616F,
.opaque_substitute = DRM_FORMAT_XBGR16161616F, .opaque_substitute = DRM_FORMAT_XBGR16161616F,
.bpp = 64, .bytes_per_block = 8,
.has_alpha = true, .has_alpha = true,
}, },
{ {
.drm_format = DRM_FORMAT_XBGR16161616, .drm_format = DRM_FORMAT_XBGR16161616,
.opaque_substitute = DRM_FORMAT_INVALID, .bytes_per_block = 8,
.bpp = 64,
.has_alpha = false,
}, },
{ {
.drm_format = DRM_FORMAT_ABGR16161616, .drm_format = DRM_FORMAT_ABGR16161616,
.opaque_substitute = DRM_FORMAT_XBGR16161616, .opaque_substitute = DRM_FORMAT_XBGR16161616,
.bpp = 64, .bytes_per_block = 8,
.has_alpha = true, .has_alpha = true,
}, },
{
.drm_format = DRM_FORMAT_YVYU,
.bytes_per_block = 4,
.block_width = 2,
.block_height = 1,
},
{
.drm_format = DRM_FORMAT_VYUY,
.bytes_per_block = 4,
.block_width = 2,
.block_height = 1,
},
}; };
static const size_t pixel_format_info_size = sizeof(pixel_format_info) / sizeof(pixel_format_info[0]); static const size_t pixel_format_info_size = sizeof(pixel_format_info) / sizeof(pixel_format_info[0]);
@@ -187,124 +217,27 @@ static enum wl_shm_format convert_drm_format_to_wl_shm(uint32_t fmt) {
} }
} }
struct wlr_gles2_pixel_format { static uint32_t pixel_format_info_pixels_per_block(const struct wlr_pixel_format_info* info) {
uint32_t drm_format; uint32_t pixels = info->block_width * info->block_height;
// optional field, if empty then internalformat = format return pixels > 0 ? pixels : 1;
GLint gl_internalformat; }
GLint gl_format, gl_type;
bool has_alpha;
};
static const struct wlr_gles2_pixel_format formats[] = { static int32_t div_round_up(int32_t dividend, int32_t divisor) {
{ int32_t quotient = dividend / divisor;
.drm_format = DRM_FORMAT_ARGB8888, if (dividend % divisor != 0) {
.gl_format = GL_BGRA_EXT, quotient++;
.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 __BYTE_ORDER__ == __ORDER_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
};
inline const struct wlr_gles2_pixel_format* gles2FromDRM(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; return quotient;
}
static int32_t pixel_format_info_min_stride(const wlr_pixel_format_info* fmt, int32_t width) {
int32_t pixels_per_block = (int32_t)pixel_format_info_pixels_per_block(fmt);
int32_t bytes_per_block = (int32_t)fmt->bytes_per_block;
if (width > INT32_MAX / bytes_per_block) {
wlr_log(WLR_DEBUG, "Invalid width %d (overflow)", width);
return 0;
}
return div_round_up(width * bytes_per_block, pixels_per_block);
} }
#endif #endif

View File

@@ -6,13 +6,7 @@ bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) {
RASSERT((w > 1 && h > 1), "cannot alloc a FB with negative / zero size! (attempted {}x{})", w, h); RASSERT((w > 1 && h > 1), "cannot alloc a FB with negative / zero size! (attempted {}x{})", w, h);
uint32_t glFormat = drmFormatToGL(drmFormat); uint32_t glFormat = drmFormatToGL(drmFormat);
uint32_t glType = glFormat != GL_RGBA ? uint32_t glType = glFormatToType(glFormat);
#ifdef GLES2
GL_UNSIGNED_INT_2_10_10_10_REV_EXT :
#else
GL_UNSIGNED_INT_2_10_10_10_REV :
#endif
GL_UNSIGNED_BYTE;
if (m_iFb == (uint32_t)-1) { if (m_iFb == (uint32_t)-1) {
firstAlloc = true; firstAlloc = true;
@@ -62,6 +56,24 @@ bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) {
return true; return true;
} }
void CFramebuffer::addStencil() {
// TODO: Allow this with gles2
#ifndef GLES2
glBindTexture(GL_TEXTURE_2D, m_pStencilTex->m_iTexID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, m_vSize.x, m_vSize.y, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 0);
glBindFramebuffer(GL_FRAMEBUFFER, m_iFb);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_pStencilTex->m_iTexID, 0);
auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
RASSERT((status == GL_FRAMEBUFFER_COMPLETE), "Failed adding a stencil to fbo!", status);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, g_pHyprOpenGL->m_iCurrentOutputFb);
#endif
}
void CFramebuffer::bind() { void CFramebuffer::bind() {
#ifndef GLES2 #ifndef GLES2
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_iFb); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_iFb);

View File

@@ -8,6 +8,7 @@ class CFramebuffer {
~CFramebuffer(); ~CFramebuffer();
bool alloc(int w, int h, uint32_t format = GL_RGBA); bool alloc(int w, int h, uint32_t format = GL_RGBA);
void addStencil();
void bind(); void bind();
void release(); void release();
void reset(); void reset();

View File

@@ -5,6 +5,15 @@
#include "Shaders.hpp" #include "Shaders.hpp"
#include <random> #include <random>
inline void loadGLProc(void* pProc, const char* name) {
void* proc = (void*)eglGetProcAddress(name);
if (proc == NULL) {
Debug::log(CRIT, "[Tracy GPU Profiling] eglGetProcAddress({}) failed", name);
abort();
}
*(void**)pProc = proc;
}
CHyprOpenGLImpl::CHyprOpenGLImpl() { CHyprOpenGLImpl::CHyprOpenGLImpl() {
RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL)), RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL)),
"Couldn't unset current EGL!"); "Couldn't unset current EGL!");
@@ -23,6 +32,11 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
Debug::log(LOG, "Renderer: {}", (char*)glGetString(GL_RENDERER)); Debug::log(LOG, "Renderer: {}", (char*)glGetString(GL_RENDERER));
Debug::log(LOG, "Supported extensions size: {}", std::count(m_szExtensions.begin(), m_szExtensions.end(), ' ')); Debug::log(LOG, "Supported extensions size: {}", std::count(m_szExtensions.begin(), m_szExtensions.end(), ' '));
loadGLProc(&m_sProc.glEGLImageTargetRenderbufferStorageOES, "glEGLImageTargetRenderbufferStorageOES");
loadGLProc(&m_sProc.eglDestroyImageKHR, "eglDestroyImageKHR");
m_sExts.EXT_read_format_bgra = m_szExtensions.contains("GL_EXT_read_format_bgra");
#ifdef USE_TRACY_GPU #ifdef USE_TRACY_GPU
loadGLProc(&glQueryCounter, "glQueryCounterEXT"); loadGLProc(&glQueryCounter, "glQueryCounterEXT");
@@ -103,34 +117,96 @@ GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src, bool
return shader; return shader;
} }
void CHyprOpenGLImpl::begin(CMonitor* pMonitor, CRegion* pDamage, bool fake) { bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) {
// passes requiring introspection are the ones that need to render blur.
static auto* const PBLUR = &g_pConfigManager->getConfigValuePtr("decoration:blur:enabled")->intValue;
static auto* const PXRAY = &g_pConfigManager->getConfigValuePtr("decoration:blur:xray")->intValue;
static auto* const POPTIM = &g_pConfigManager->getConfigValuePtr("decoration:blur:new_optimizations")->intValue;
static auto* const PBLURSPECIAL = &g_pConfigManager->getConfigValuePtr("decoration:blur:special")->intValue;
if (m_RenderData.mouseZoomFactor != 1.0)
return true;
if (!pMonitor->mirrors.empty())
return true;
if (*PBLUR == 0)
return false;
if (m_RenderData.pCurrentMonData->blurFBShouldRender)
return true;
if (pMonitor->solitaryClient)
return false;
for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) {
const auto XRAYMODE = ls->xray == -1 ? *PXRAY : ls->xray;
if (ls->forceBlur && !XRAYMODE)
return true;
}
for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
const auto XRAYMODE = ls->xray == -1 ? *PXRAY : ls->xray;
if (ls->forceBlur && !XRAYMODE)
return true;
}
if (*PBLURSPECIAL) {
for (auto& ws : g_pCompositor->m_vWorkspaces) {
if (!ws->m_bIsSpecialWorkspace || ws->m_iMonitorID != pMonitor->ID)
continue;
if (ws->m_fAlpha.fl() == 0)
continue;
return true;
}
}
if (*PXRAY)
return false;
for (auto& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped || w->isHidden() || (!w->m_bIsFloating && *POPTIM && !g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID)))
continue;
if (!g_pHyprRenderer->shouldRenderWindow(w.get()))
continue;
if (w->m_sAdditionalConfigData.forceNoBlur.toUnderlying() == true || w->m_sAdditionalConfigData.xray.toUnderlying() == true)
continue;
if (w->opaque())
continue;
return true;
}
return false;
}
void CHyprOpenGLImpl::begin(CMonitor* pMonitor, CRegion* pDamage, CFramebuffer* fb) {
m_RenderData.pMonitor = pMonitor; m_RenderData.pMonitor = pMonitor;
TRACY_GPU_ZONE("RenderBegin"); TRACY_GPU_ZONE("RenderBegin");
if (eglGetCurrentContext() != wlr_egl_get_context(g_pCompositor->m_sWLREGL)) {
eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL));
}
glViewport(0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); glViewport(0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y);
matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL); matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL);
m_RenderData.pCurrentMonData = &m_mMonitorRenderResources[pMonitor]; m_RenderData.pCurrentMonData = &m_mMonitorRenderResources[pMonitor];
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &m_iCurrentOutputFb);
m_iWLROutputFb = m_iCurrentOutputFb;
// ensure a framebuffer for the monitor exists // ensure a framebuffer for the monitor exists
if (!m_mMonitorRenderResources.contains(pMonitor) || m_RenderData.pCurrentMonData->primaryFB.m_vSize != pMonitor->vecPixelSize) { if (!m_mMonitorRenderResources.contains(pMonitor) || m_RenderData.pCurrentMonData->offloadFB.m_vSize != pMonitor->vecPixelSize) {
m_RenderData.pCurrentMonData->stencilTex.allocate(); m_RenderData.pCurrentMonData->stencilTex.allocate();
m_RenderData.pCurrentMonData->primaryFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; m_RenderData.pCurrentMonData->offloadFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex;
m_RenderData.pCurrentMonData->mirrorFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; m_RenderData.pCurrentMonData->mirrorFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex;
m_RenderData.pCurrentMonData->mirrorSwapFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; m_RenderData.pCurrentMonData->mirrorSwapFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex;
m_RenderData.pCurrentMonData->offMainFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; m_RenderData.pCurrentMonData->offMainFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex;
m_RenderData.pCurrentMonData->primaryFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat); m_RenderData.pCurrentMonData->offloadFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
m_RenderData.pCurrentMonData->mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat); m_RenderData.pCurrentMonData->mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
m_RenderData.pCurrentMonData->mirrorSwapFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat); m_RenderData.pCurrentMonData->mirrorSwapFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
m_RenderData.pCurrentMonData->offMainFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat); m_RenderData.pCurrentMonData->offMainFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
@@ -144,19 +220,38 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, CRegion* pDamage, bool fake) {
if (!m_RenderData.pCurrentMonData->m_bShadersInitialized) if (!m_RenderData.pCurrentMonData->m_bShadersInitialized)
initShaders(); initShaders();
// bind the primary Hypr Framebuffer
m_RenderData.pCurrentMonData->primaryFB.bind();
m_RenderData.damage.set(*pDamage); m_RenderData.damage.set(*pDamage);
m_bFakeFrame = fake; m_bFakeFrame = fb;
m_RenderData.currentFB = &m_RenderData.pCurrentMonData->primaryFB;
if (m_bReloadScreenShader) { if (m_bReloadScreenShader) {
m_bReloadScreenShader = false; m_bReloadScreenShader = false;
applyScreenShader(g_pConfigManager->getString("decoration:screen_shader")); applyScreenShader(g_pConfigManager->getString("decoration:screen_shader"));
} }
const auto PRBO = g_pHyprRenderer->getCurrentRBO();
const bool FBPROPERSIZE = fb && fb->m_vSize == pMonitor->vecPixelSize;
if (!FBPROPERSIZE || m_sFinalScreenShader.program > 0 || (PRBO && pMonitor->vecPixelSize != PRBO->getFB()->m_vSize) || passRequiresIntrospection(pMonitor)) {
// we have to offload
// bind the offload Hypr Framebuffer
m_RenderData.pCurrentMonData->offloadFB.bind();
m_RenderData.currentFB = &m_RenderData.pCurrentMonData->offloadFB;
m_bOffloadedFramebuffer = true;
} else {
// we can render to the rbo / fbo (fake) directly
const auto PFBO = fb ? fb : PRBO->getFB();
m_RenderData.currentFB = PFBO;
if (PFBO->m_pStencilTex != &m_RenderData.pCurrentMonData->stencilTex) {
PFBO->m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex;
PFBO->addStencil();
}
PFBO->bind();
m_bOffloadedFramebuffer = false;
}
m_RenderData.mainFB = m_RenderData.currentFB;
m_RenderData.outFB = fb ? fb : PRBO->getFB();
} }
void CHyprOpenGLImpl::end() { void CHyprOpenGLImpl::end() {
@@ -164,14 +259,15 @@ void CHyprOpenGLImpl::end() {
TRACY_GPU_ZONE("RenderEnd"); TRACY_GPU_ZONE("RenderEnd");
if (!m_RenderData.pMonitor->mirrors.empty() && !m_bFakeFrame)
saveBufferForMirror(); // save with original damage region
// end the render, copy the data to the WLR framebuffer // end the render, copy the data to the WLR framebuffer
if (!m_bFakeFrame) { if (m_bOffloadedFramebuffer) {
m_RenderData.damage = m_RenderData.pMonitor->lastFrameDamage; m_RenderData.damage = m_RenderData.pMonitor->lastFrameDamage;
if (!m_RenderData.pMonitor->mirrors.empty()) m_RenderData.outFB->bind();
saveBufferForMirror(); // save with original damage region
glBindFramebuffer(GL_FRAMEBUFFER, m_iWLROutputFb);
CBox monbox = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}; CBox monbox = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y};
if (m_RenderData.mouseZoomFactor != 1.f) { if (m_RenderData.mouseZoomFactor != 1.f) {
@@ -199,9 +295,9 @@ void CHyprOpenGLImpl::end() {
blend(false); blend(false);
if (m_sFinalScreenShader.program < 1) if (m_sFinalScreenShader.program < 1)
renderTexturePrimitive(m_RenderData.pCurrentMonData->primaryFB.m_cTex, &monbox); renderTexturePrimitive(m_RenderData.pCurrentMonData->offloadFB.m_cTex, &monbox);
else else
renderTexture(m_RenderData.pCurrentMonData->primaryFB.m_cTex, &monbox, 1.f); renderTexture(m_RenderData.pCurrentMonData->offloadFB.m_cTex, &monbox, 1.f);
blend(true); blend(true);
@@ -212,15 +308,10 @@ void CHyprOpenGLImpl::end() {
// reset our data // reset our data
m_RenderData.pMonitor = nullptr; m_RenderData.pMonitor = nullptr;
m_iWLROutputFb = 0;
m_RenderData.mouseZoomFactor = 1.f; m_RenderData.mouseZoomFactor = 1.f;
m_RenderData.mouseZoomUseMouse = true; m_RenderData.mouseZoomUseMouse = true;
} }
void CHyprOpenGLImpl::bindWlrOutputFb() {
glBindFramebuffer(GL_FRAMEBUFFER, m_iWLROutputFb);
}
void CHyprOpenGLImpl::initShaders() { void CHyprOpenGLImpl::initShaders() {
GLuint prog = createProgram(QUADVERTSRC, QUADFRAGSRC); GLuint prog = createProgram(QUADVERTSRC, QUADFRAGSRC);
m_RenderData.pCurrentMonData->m_shQUAD.program = prog; m_RenderData.pCurrentMonData->m_shQUAD.program = prog;
@@ -501,8 +592,7 @@ void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CColor& col, int round
CFramebuffer* POUTFB = blurMainFramebufferWithDamage(blurA, &damage); CFramebuffer* POUTFB = blurMainFramebufferWithDamage(blurA, &damage);
// bind primary m_RenderData.currentFB->bind();
m_RenderData.pCurrentMonData->primaryFB.bind();
// make a stencil for rounded corners to work with blur // make a stencil for rounded corners to work with blur
scissor((CBox*)nullptr); // allow the entire window and stencil to render scissor((CBox*)nullptr); // allow the entire window and stencil to render
@@ -553,7 +643,7 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion
float matrix[9]; float matrix[9];
wlr_matrix_project_box(matrix, box->pWlr(), wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), 0, wlr_matrix_project_box(matrix, box->pWlr(), 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 m_RenderData.pMonitor->projMatrix.data()); // TODO: write own, don't use WLR here
float glMatrix[9]; float glMatrix[9];
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
@@ -640,7 +730,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox*
// get transform // get transform
const auto TRANSFORM = wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform); const auto TRANSFORM = wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform);
float matrix[9]; float matrix[9];
wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, 0, m_RenderData.pMonitor->output->transform_matrix); wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, 0, m_RenderData.pMonitor->projMatrix.data());
float glMatrix[9]; float glMatrix[9];
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
@@ -801,7 +891,7 @@ void CHyprOpenGLImpl::renderTexturePrimitive(const CTexture& tex, CBox* pBox) {
// get transform // get transform
const auto TRANSFORM = wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform); const auto TRANSFORM = wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform);
float matrix[9]; float matrix[9];
wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, 0, m_RenderData.pMonitor->output->transform_matrix); wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, 0, m_RenderData.pMonitor->projMatrix.data());
float glMatrix[9]; float glMatrix[9];
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
@@ -855,7 +945,7 @@ void CHyprOpenGLImpl::renderTextureMatte(const CTexture& tex, CBox* pBox, CFrame
// get transform // get transform
const auto TRANSFORM = wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform); const auto TRANSFORM = wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform);
float matrix[9]; float matrix[9];
wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, 0, m_RenderData.pMonitor->output->transform_matrix); wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, 0, m_RenderData.pMonitor->projMatrix.data());
float glMatrix[9]; float glMatrix[9];
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
@@ -914,7 +1004,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
const auto TRANSFORM = wlr_output_transform_invert(m_RenderData.pMonitor->transform); const auto TRANSFORM = wlr_output_transform_invert(m_RenderData.pMonitor->transform);
float matrix[9]; float matrix[9];
CBox MONITORBOX = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}; CBox MONITORBOX = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y};
wlr_matrix_project_box(matrix, MONITORBOX.pWlr(), TRANSFORM, 0, m_RenderData.pMonitor->output->transform_matrix); wlr_matrix_project_box(matrix, MONITORBOX.pWlr(), TRANSFORM, 0, m_RenderData.pMonitor->projMatrix.data());
float glMatrix[9]; float glMatrix[9];
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
@@ -947,9 +1037,9 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(m_RenderData.pCurrentMonData->primaryFB.m_cTex.m_iTarget, m_RenderData.pCurrentMonData->primaryFB.m_cTex.m_iTexID); glBindTexture(m_RenderData.currentFB->m_cTex.m_iTarget, m_RenderData.currentFB->m_cTex.m_iTexID);
glTexParameteri(m_RenderData.pCurrentMonData->primaryFB.m_cTex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(m_RenderData.currentFB->m_cTex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glUseProgram(m_RenderData.pCurrentMonData->m_shBLURPREPARE.program); glUseProgram(m_RenderData.pCurrentMonData->m_shBLURPREPARE.program);
@@ -957,7 +1047,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_TRUE, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_TRUE, glMatrix);
#else #else
wlr_matrix_transpose(glMatrix, glMatrix); wlr_matrix_transpose(glMatrix, glMatrix);
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_FALSE, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_FALSE, glMatrix);
#endif #endif
glUniform1f(m_RenderData.pCurrentMonData->m_shBLURPREPARE.contrast, *PBLURCONTRAST); glUniform1f(m_RenderData.pCurrentMonData->m_shBLURPREPARE.contrast, *PBLURCONTRAST);
glUniform1f(m_RenderData.pCurrentMonData->m_shBLURPREPARE.brightness, *PBLURBRIGHTNESS); glUniform1f(m_RenderData.pCurrentMonData->m_shBLURPREPARE.brightness, *PBLURBRIGHTNESS);
@@ -1117,13 +1207,6 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
} }
void CHyprOpenGLImpl::markBlurDirtyForMonitor(CMonitor* pMonitor) { void CHyprOpenGLImpl::markBlurDirtyForMonitor(CMonitor* pMonitor) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pMonitor->activeWorkspace);
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(pMonitor->activeWorkspace);
if (PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL && PFULLWINDOW && !PFULLWINDOW->m_vRealSize.isBeingAnimated() &&
PFULLWINDOW->opaque())
return;
m_mMonitorRenderResources[pMonitor].blurFBDirty = true; m_mMonitorRenderResources[pMonitor].blurFBDirty = true;
} }
@@ -1135,6 +1218,10 @@ void CHyprOpenGLImpl::preRender(CMonitor* pMonitor) {
if (!*PBLURNEWOPTIMIZE || !m_mMonitorRenderResources[pMonitor].blurFBDirty || !*PBLUR) if (!*PBLURNEWOPTIMIZE || !m_mMonitorRenderResources[pMonitor].blurFBDirty || !*PBLUR)
return; return;
// ignore if solitary present, nothing to blur
if (pMonitor->solitaryClient)
return;
// check if we need to update the blur fb // check if we need to update the blur fb
// if there are no windows that would benefit from it, // if there are no windows that would benefit from it,
// we will ignore that the blur FB is dirty. // we will ignore that the blur FB is dirty.
@@ -1225,7 +1312,7 @@ void CHyprOpenGLImpl::preBlurForCurrentMonitor() {
renderTextureInternalWithDamage(POUTFB->m_cTex, &wholeMonitor, 1, &fakeDamage, 0, false, true, false); renderTextureInternalWithDamage(POUTFB->m_cTex, &wholeMonitor, 1, &fakeDamage, 0, false, true, false);
m_bEndFrame = false; m_bEndFrame = false;
m_RenderData.pCurrentMonData->primaryFB.bind(); m_RenderData.currentFB->bind();
m_RenderData.pCurrentMonData->blurFBDirty = false; m_RenderData.pCurrentMonData->blurFBDirty = false;
@@ -1294,7 +1381,8 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, CBox* pBox, flo
// amazing hack: the surface has an opaque region! // amazing hack: the surface has an opaque region!
CRegion inverseOpaque; CRegion inverseOpaque;
if (a >= 1.f) { if (a >= 1.f && std::round(pSurface->current.width * m_RenderData.pMonitor->scale) == pBox->w &&
std::round(pSurface->current.height * m_RenderData.pMonitor->scale) == pBox->h) {
pixman_box32_t surfbox = {0, 0, pSurface->current.width * pSurface->current.scale, pSurface->current.height * pSurface->current.scale}; pixman_box32_t surfbox = {0, 0, pSurface->current.width * pSurface->current.scale, pSurface->current.height * pSurface->current.scale};
inverseOpaque = &pSurface->current.opaque; inverseOpaque = &pSurface->current.opaque;
inverseOpaque.invert(&surfbox).intersect(0, 0, pSurface->current.width * pSurface->current.scale, pSurface->current.height * pSurface->current.scale); inverseOpaque.invert(&surfbox).intersect(0, 0, pSurface->current.width * pSurface->current.scale, pSurface->current.height * pSurface->current.scale);
@@ -1321,8 +1409,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, CBox* pBox, flo
POUTFB = &m_RenderData.pCurrentMonData->blurFB; POUTFB = &m_RenderData.pCurrentMonData->blurFB;
} }
// bind primary m_RenderData.currentFB->bind();
m_RenderData.pCurrentMonData->primaryFB.bind();
// make a stencil for rounded corners to work with blur // make a stencil for rounded corners to work with blur
scissor((CBox*)nullptr); // allow the entire window and stencil to render scissor((CBox*)nullptr); // allow the entire window and stencil to render
@@ -1404,7 +1491,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in
float matrix[9]; float matrix[9];
wlr_matrix_project_box(matrix, box->pWlr(), wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), 0, wlr_matrix_project_box(matrix, box->pWlr(), 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 m_RenderData.pMonitor->projMatrix.data()); // TODO: write own, don't use WLR here
float glMatrix[9]; float glMatrix[9];
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
@@ -1478,14 +1565,18 @@ void CHyprOpenGLImpl::makeRawWindowSnapshot(CWindow* pWindow, CFramebuffer* pFra
if (!PMONITOR || !PMONITOR->output || PMONITOR->vecPixelSize.x <= 0 || PMONITOR->vecPixelSize.y <= 0) if (!PMONITOR || !PMONITOR->output || PMONITOR->vecPixelSize.x <= 0 || PMONITOR->vecPixelSize.y <= 0)
return; return;
wlr_output_attach_render(PMONITOR->output, nullptr);
// we need to "damage" the entire monitor // we need to "damage" the entire monitor
// so that we render the entire window // so that we render the entire window
// this is temporary, doesnt mess with the actual wlr damage // this is temporary, doesnt mess with the actual wlr damage
CRegion fakeDamage{0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y}; CRegion fakeDamage{0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y};
begin(PMONITOR, &fakeDamage, true); g_pHyprRenderer->makeEGLCurrent();
pFramebuffer->m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex;
pFramebuffer->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->drmFormat);
g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, pFramebuffer);
clear(CColor(0, 0, 0, 0)); // JIC clear(CColor(0, 0, 0, 0)); // JIC
@@ -1503,12 +1594,6 @@ void CHyprOpenGLImpl::makeRawWindowSnapshot(CWindow* pWindow, CFramebuffer* pFra
// 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. // 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); glViewport(0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
pFramebuffer->m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex;
pFramebuffer->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->drmFormat);
pFramebuffer->bind();
m_RenderData.currentFB = pFramebuffer; m_RenderData.currentFB = pFramebuffer;
clear(CColor(0, 0, 0, 0)); // JIC clear(CColor(0, 0, 0, 0)); // JIC
@@ -1517,15 +1602,7 @@ void CHyprOpenGLImpl::makeRawWindowSnapshot(CWindow* pWindow, CFramebuffer* pFra
g_pConfigManager->setInt("decoration:blur:enabled", BLURVAL); g_pConfigManager->setInt("decoration:blur:enabled", BLURVAL);
// restore original fb g_pHyprRenderer->endRender();
#ifndef GLES2
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_iCurrentOutputFb);
#else
glBindFramebuffer(GL_FRAMEBUFFER, m_iCurrentOutputFb);
#endif
end();
wlr_output_rollback(PMONITOR->output);
} }
void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) { void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
@@ -1535,14 +1612,21 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
if (!PMONITOR || !PMONITOR->output || PMONITOR->vecPixelSize.x <= 0 || PMONITOR->vecPixelSize.y <= 0) if (!PMONITOR || !PMONITOR->output || PMONITOR->vecPixelSize.x <= 0 || PMONITOR->vecPixelSize.y <= 0)
return; return;
wlr_output_attach_render(PMONITOR->output, nullptr); if (!g_pHyprRenderer->shouldRenderWindow(pWindow))
return; // ignore, window is not being rendered
// we need to "damage" the entire monitor // we need to "damage" the entire monitor
// so that we render the entire window // so that we render the entire window
// this is temporary, doesnt mess with the actual wlr damage // this is temporary, doesnt mess with the actual wlr damage
CRegion fakeDamage{0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y}; CRegion fakeDamage{0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y};
begin(PMONITOR, &fakeDamage, true); g_pHyprRenderer->makeEGLCurrent();
const auto PFRAMEBUFFER = &m_mWindowFramebuffers[pWindow];
PFRAMEBUFFER->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->drmFormat);
g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, PFRAMEBUFFER);
g_pHyprRenderer->m_bRenderingSnapshot = true; g_pHyprRenderer->m_bRenderingSnapshot = true;
@@ -1559,35 +1643,15 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
const auto BLURVAL = g_pConfigManager->getInt("decoration:blur:enabled"); const auto BLURVAL = g_pConfigManager->getInt("decoration:blur:enabled");
g_pConfigManager->setInt("decoration:blur:enabled", 0); g_pConfigManager->setInt("decoration:blur:enabled", 0);
glViewport(0, 0, m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y);
const auto PFRAMEBUFFER = &m_mWindowFramebuffers[pWindow];
PFRAMEBUFFER->m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex;
PFRAMEBUFFER->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->drmFormat);
PFRAMEBUFFER->bind();
m_RenderData.currentFB = PFRAMEBUFFER;
clear(CColor(0, 0, 0, 0)); // JIC clear(CColor(0, 0, 0, 0)); // JIC
g_pHyprRenderer->renderWindow(pWindow, PMONITOR, &now, !pWindow->m_bX11DoesntWantBorders, RENDER_PASS_ALL); g_pHyprRenderer->renderWindow(pWindow, PMONITOR, &now, !pWindow->m_bX11DoesntWantBorders, RENDER_PASS_ALL);
g_pConfigManager->setInt("decoration:blur:enabled", BLURVAL); g_pConfigManager->setInt("decoration:blur:enabled", BLURVAL);
// restore original fb g_pHyprRenderer->endRender();
#ifndef GLES2
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_iCurrentOutputFb);
#else
glBindFramebuffer(GL_FRAMEBUFFER, m_iCurrentOutputFb);
#endif
end();
g_pHyprRenderer->m_bRenderingSnapshot = false; g_pHyprRenderer->m_bRenderingSnapshot = false;
wlr_output_rollback(PMONITOR->output);
} }
void CHyprOpenGLImpl::makeLayerSnapshot(SLayerSurface* pLayer) { void CHyprOpenGLImpl::makeLayerSnapshot(SLayerSurface* pLayer) {
@@ -1597,26 +1661,20 @@ void CHyprOpenGLImpl::makeLayerSnapshot(SLayerSurface* pLayer) {
if (!PMONITOR || !PMONITOR->output || PMONITOR->vecPixelSize.x <= 0 || PMONITOR->vecPixelSize.y <= 0) if (!PMONITOR || !PMONITOR->output || PMONITOR->vecPixelSize.x <= 0 || PMONITOR->vecPixelSize.y <= 0)
return; return;
wlr_output_attach_render(PMONITOR->output, nullptr);
// we need to "damage" the entire monitor // we need to "damage" the entire monitor
// so that we render the entire window // so that we render the entire window
// this is temporary, doesnt mess with the actual wlr damage // this is temporary, doesnt mess with the actual wlr damage
CRegion fakeDamage{0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y}; CRegion fakeDamage{0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y};
begin(PMONITOR, &fakeDamage, true); g_pHyprRenderer->makeEGLCurrent();
g_pHyprRenderer->m_bRenderingSnapshot = true;
const auto PFRAMEBUFFER = &m_mLayerFramebuffers[pLayer]; const auto PFRAMEBUFFER = &m_mLayerFramebuffers[pLayer];
glViewport(0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.y);
PFRAMEBUFFER->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->drmFormat); PFRAMEBUFFER->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->drmFormat);
PFRAMEBUFFER->bind(); g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, PFRAMEBUFFER);
m_RenderData.currentFB = PFRAMEBUFFER; g_pHyprRenderer->m_bRenderingSnapshot = true;
clear(CColor(0, 0, 0, 0)); // JIC clear(CColor(0, 0, 0, 0)); // JIC
@@ -1631,20 +1689,9 @@ void CHyprOpenGLImpl::makeLayerSnapshot(SLayerSurface* pLayer) {
pLayer->forceBlur = BLURLSSTATUS; pLayer->forceBlur = BLURLSSTATUS;
// TODO: WARN: g_pHyprRenderer->endRender();
// revise if any stencil-requiring rendering is done to the layers.
// restore original fb
#ifndef GLES2
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_iCurrentOutputFb);
#else
glBindFramebuffer(GL_FRAMEBUFFER, m_iCurrentOutputFb);
#endif
end();
g_pHyprRenderer->m_bRenderingSnapshot = false; g_pHyprRenderer->m_bRenderingSnapshot = false;
wlr_output_rollback(PMONITOR->output);
} }
void CHyprOpenGLImpl::renderSnapshot(CWindow** pWindow) { void CHyprOpenGLImpl::renderSnapshot(CWindow** pWindow) {
@@ -1741,7 +1788,7 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const
float matrix[9]; float matrix[9];
wlr_matrix_project_box(matrix, box->pWlr(), wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), 0, wlr_matrix_project_box(matrix, box->pWlr(), 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 m_RenderData.pMonitor->projMatrix.data()); // TODO: write own, don't use WLR here
float glMatrix[9]; float glMatrix[9];
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
@@ -1808,11 +1855,11 @@ void CHyprOpenGLImpl::saveBufferForMirror() {
blend(false); blend(false);
renderTexture(m_RenderData.pCurrentMonData->primaryFB.m_cTex, &monbox, 1.f, 0, false, false); renderTexture(m_RenderData.currentFB->m_cTex, &monbox, 1.f, 0, false, false);
blend(true); blend(true);
m_RenderData.pCurrentMonData->primaryFB.bind(); m_RenderData.currentFB->bind();
} }
void CHyprOpenGLImpl::renderMirrored() { void CHyprOpenGLImpl::renderMirrored() {
@@ -1968,10 +2015,10 @@ void CHyprOpenGLImpl::clearWithTex() {
} }
void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) { void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) {
wlr_output_attach_render(pMonitor->output, nullptr); g_pHyprRenderer->makeEGLCurrent();
g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].mirrorFB.release(); g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].mirrorFB.release();
g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].primaryFB.release(); g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].offloadFB.release();
g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].mirrorSwapFB.release(); g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].mirrorSwapFB.release();
g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].monitorMirrorFB.release(); g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].monitorMirrorFB.release();
g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].blurFB.release(); g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].blurFB.release();
@@ -1982,8 +2029,6 @@ void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) {
g_pHyprOpenGL->m_mMonitorBGTextures.erase(pMonitor); g_pHyprOpenGL->m_mMonitorBGTextures.erase(pMonitor);
Debug::log(LOG, "Monitor {} -> destroyed all render data", pMonitor->szName); Debug::log(LOG, "Monitor {} -> destroyed all render data", pMonitor->szName);
wlr_output_rollback(pMonitor->output);
} }
void CHyprOpenGLImpl::saveMatrix() { void CHyprOpenGLImpl::saveMatrix() {
@@ -2011,10 +2056,144 @@ void CHyprOpenGLImpl::renderOffToMain(CFramebuffer* off) {
} }
void CHyprOpenGLImpl::bindBackOnMain() { void CHyprOpenGLImpl::bindBackOnMain() {
m_RenderData.pCurrentMonData->primaryFB.bind(); m_RenderData.mainFB->bind();
m_RenderData.currentFB = &m_RenderData.pCurrentMonData->primaryFB; m_RenderData.currentFB = m_RenderData.mainFB;
} }
void CHyprOpenGLImpl::setMonitorTransformEnabled(bool enabled) { void CHyprOpenGLImpl::setMonitorTransformEnabled(bool enabled) {
m_bEndFrame = !enabled; m_bEndFrame = !enabled;
} }
inline const SGLPixelFormat GLES2_FORMATS[] = {
{
.drmFormat = DRM_FORMAT_ARGB8888,
.glFormat = GL_BGRA_EXT,
.glType = GL_UNSIGNED_BYTE,
.withAlpha = true,
},
{
.drmFormat = DRM_FORMAT_XRGB8888,
.glFormat = GL_BGRA_EXT,
.glType = GL_UNSIGNED_BYTE,
.withAlpha = false,
},
{
.drmFormat = DRM_FORMAT_XBGR8888,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_BYTE,
.withAlpha = false,
},
{
.drmFormat = DRM_FORMAT_ABGR8888,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_BYTE,
.withAlpha = true,
},
{
.drmFormat = DRM_FORMAT_BGR888,
.glFormat = GL_RGB,
.glType = GL_UNSIGNED_BYTE,
.withAlpha = false,
},
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
{
.drmFormat = DRM_FORMAT_RGBX4444,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_SHORT_4_4_4_4,
.withAlpha = false,
},
{
.drmFormat = DRM_FORMAT_RGBA4444,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_SHORT_4_4_4_4,
.withAlpha = true,
},
{
.drmFormat = DRM_FORMAT_RGBX5551,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_SHORT_5_5_5_1,
.withAlpha = false,
},
{
.drmFormat = DRM_FORMAT_RGBA5551,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_SHORT_5_5_5_1,
.withAlpha = true,
},
{
.drmFormat = DRM_FORMAT_RGB565,
.glFormat = GL_RGB,
.glType = GL_UNSIGNED_SHORT_5_6_5,
.withAlpha = false,
},
{
.drmFormat = DRM_FORMAT_XBGR2101010,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT,
.withAlpha = false,
},
{
.drmFormat = DRM_FORMAT_ABGR2101010,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT,
.withAlpha = true,
},
{
.drmFormat = DRM_FORMAT_XBGR16161616F,
.glFormat = GL_RGBA,
.glType = GL_HALF_FLOAT_OES,
.withAlpha = false,
},
{
.drmFormat = DRM_FORMAT_ABGR16161616F,
.glFormat = GL_RGBA,
.glType = GL_HALF_FLOAT_OES,
.withAlpha = true,
},
{
.drmFormat = DRM_FORMAT_XBGR16161616,
.glInternalFormat = GL_RGBA16_EXT,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_SHORT,
.withAlpha = false,
},
{
.drmFormat = DRM_FORMAT_ABGR16161616,
.glInternalFormat = GL_RGBA16_EXT,
.glFormat = GL_RGBA,
.glType = GL_UNSIGNED_SHORT,
.withAlpha = true,
},
#endif
};
uint32_t CHyprOpenGLImpl::getPreferredReadFormat(CMonitor* pMonitor) {
GLint glf = -1, glt = -1, as = -1;
glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &glf);
glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &glt);
glGetIntegerv(GL_ALPHA_BITS, &as);
if (glf == 0 || glt == 0) {
glf = drmFormatToGL(pMonitor->drmFormat);
glt = glFormatToType(glf);
}
for (auto& fmt : GLES2_FORMATS) {
if (fmt.glFormat == glf && fmt.glType == glt && fmt.withAlpha == (as > 0))
return fmt.drmFormat;
}
if (m_sExts.EXT_read_format_bgra)
return DRM_FORMAT_XRGB8888;
return DRM_FORMAT_XBGR8888;
}
const SGLPixelFormat* CHyprOpenGLImpl::getPixelFormatFromDRM(uint32_t drmFormat) {
for (auto& fmt : GLES2_FORMATS) {
if (fmt.drmFormat == drmFormat)
return &fmt;
}
return nullptr;
}

View File

@@ -14,6 +14,9 @@
#include "Texture.hpp" #include "Texture.hpp"
#include "Framebuffer.hpp" #include "Framebuffer.hpp"
#include "Transformer.hpp" #include "Transformer.hpp"
#include "Renderbuffer.hpp"
#include <GLES2/gl2ext.h>
#include "../debug/TracyDefines.hpp" #include "../debug/TracyDefines.hpp"
@@ -38,8 +41,16 @@ struct SRenderModifData {
float scale = 1.f; float scale = 1.f;
}; };
struct SGLPixelFormat {
uint32_t drmFormat = DRM_FORMAT_INVALID;
GLint glInternalFormat = 0;
GLint glFormat = 0;
GLint glType = 0;
bool withAlpha = false;
};
struct SMonitorRenderData { struct SMonitorRenderData {
CFramebuffer primaryFB; CFramebuffer offloadFB;
CFramebuffer mirrorFB; // these are used for some effects, CFramebuffer mirrorFB; // these are used for some effects,
CFramebuffer mirrorSwapFB; // etc CFramebuffer mirrorSwapFB; // etc
CFramebuffer offMainFB; CFramebuffer offMainFB;
@@ -79,7 +90,9 @@ struct SCurrentRenderData {
float savedProjection[9]; float savedProjection[9];
SMonitorRenderData* pCurrentMonData = nullptr; SMonitorRenderData* pCurrentMonData = nullptr;
CFramebuffer* currentFB = nullptr; CFramebuffer* currentFB = nullptr; // current rendering to
CFramebuffer* mainFB = nullptr; // main to render to
CFramebuffer* outFB = nullptr; // out to render to (if offloaded, etc)
CRegion damage; CRegion damage;
@@ -103,72 +116,82 @@ class CHyprOpenGLImpl {
public: public:
CHyprOpenGLImpl(); CHyprOpenGLImpl();
void begin(CMonitor*, CRegion*, bool fake = false); void begin(CMonitor*, CRegion*, CFramebuffer* fb = nullptr /* if provided, it's not a real frame */);
void end(); void end();
void bindWlrOutputFb();
void renderRect(CBox*, const CColor&, int round = 0); void renderRect(CBox*, const CColor&, int round = 0);
void renderRectWithBlur(CBox*, const CColor&, int round = 0, float blurA = 1.f); void renderRectWithBlur(CBox*, const CColor&, int round = 0, float blurA = 1.f);
void renderRectWithDamage(CBox*, const CColor&, CRegion* damage, int round = 0); void renderRectWithDamage(CBox*, const CColor&, CRegion* damage, int round = 0);
void renderTexture(wlr_texture*, CBox*, float a, int round = 0, bool allowCustomUV = false); void renderTexture(wlr_texture*, CBox*, float a, int round = 0, bool allowCustomUV = false);
void renderTexture(const CTexture&, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); void renderTexture(const CTexture&, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false);
void renderTextureWithBlur(const CTexture&, CBox*, float a, wlr_surface* pSurface, int round = 0, bool blockBlurOptimization = false, float blurA = 1.f); void renderTextureWithBlur(const CTexture&, CBox*, float a, wlr_surface* pSurface, int round = 0, bool blockBlurOptimization = false, float blurA = 1.f);
void renderRoundedShadow(CBox*, int round, int range, const CColor& color, float a = 1.0); void renderRoundedShadow(CBox*, int round, int range, const CColor& color, float a = 1.0);
void renderBorder(CBox*, const CGradientValueData&, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */); void renderBorder(CBox*, const CGradientValueData&, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */);
void renderTextureMatte(const CTexture& tex, CBox* pBox, CFramebuffer& matte); void renderTextureMatte(const CTexture& tex, CBox* pBox, CFramebuffer& matte);
void setMonitorTransformEnabled(bool enabled); void setMonitorTransformEnabled(bool enabled);
void saveMatrix(); void saveMatrix();
void setMatrixScaleTranslate(const Vector2D& translate, const float& scale); void setMatrixScaleTranslate(const Vector2D& translate, const float& scale);
void restoreMatrix(); void restoreMatrix();
void blend(bool enabled); void blend(bool enabled);
void makeWindowSnapshot(CWindow*); void makeWindowSnapshot(CWindow*);
void makeRawWindowSnapshot(CWindow*, CFramebuffer*); void makeRawWindowSnapshot(CWindow*, CFramebuffer*);
void makeLayerSnapshot(SLayerSurface*); void makeLayerSnapshot(SLayerSurface*);
void renderSnapshot(CWindow**); void renderSnapshot(CWindow**);
void renderSnapshot(SLayerSurface**); void renderSnapshot(SLayerSurface**);
void clear(const CColor&); void clear(const CColor&);
void clearWithTex(); void clearWithTex();
void scissor(const CBox*, bool transform = true); void scissor(const CBox*, bool transform = true);
void scissor(const pixman_box32*, bool transform = true); void scissor(const pixman_box32*, bool transform = true);
void scissor(const int x, const int y, const int w, const int h, bool transform = true); void scissor(const int x, const int y, const int w, const int h, bool transform = true);
void destroyMonitorResources(CMonitor*); void destroyMonitorResources(CMonitor*);
void markBlurDirtyForMonitor(CMonitor*); void markBlurDirtyForMonitor(CMonitor*);
void preWindowPass(); void preWindowPass();
bool preBlurQueued(); bool preBlurQueued();
void preRender(CMonitor*); void preRender(CMonitor*);
void saveBufferForMirror(); void saveBufferForMirror();
void renderMirrored(); void renderMirrored();
void applyScreenShader(const std::string& path); void applyScreenShader(const std::string& path);
void bindOffMain(); void bindOffMain();
void renderOffToMain(CFramebuffer* off); void renderOffToMain(CFramebuffer* off);
void bindBackOnMain(); void bindBackOnMain();
SCurrentRenderData m_RenderData; uint32_t getPreferredReadFormat(CMonitor* pMonitor);
const SGLPixelFormat* getPixelFormatFromDRM(uint32_t drmFormat);
GLint m_iCurrentOutputFb = 0; SCurrentRenderData m_RenderData;
GLint m_iWLROutputFb = 0;
bool m_bReloadScreenShader = true; // at launch it can be set GLint m_iCurrentOutputFb = 0;
CWindow* m_pCurrentWindow = nullptr; // hack to get the current rendered window bool m_bReloadScreenShader = true; // at launch it can be set
SLayerSurface* m_pCurrentLayer = nullptr; // hack to get the current rendered layer
CWindow* m_pCurrentWindow = nullptr; // hack to get the current rendered window
SLayerSurface* m_pCurrentLayer = nullptr; // hack to get the current rendered layer
std::unordered_map<CWindow*, CFramebuffer> m_mWindowFramebuffers; std::unordered_map<CWindow*, CFramebuffer> m_mWindowFramebuffers;
std::unordered_map<SLayerSurface*, CFramebuffer> m_mLayerFramebuffers; std::unordered_map<SLayerSurface*, CFramebuffer> m_mLayerFramebuffers;
std::unordered_map<CMonitor*, SMonitorRenderData> m_mMonitorRenderResources; std::unordered_map<CMonitor*, SMonitorRenderData> m_mMonitorRenderResources;
std::unordered_map<CMonitor*, CTexture> m_mMonitorBGTextures; std::unordered_map<CMonitor*, CTexture> m_mMonitorBGTextures;
struct {
PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES = nullptr;
PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = nullptr;
} m_sProc;
struct {
bool EXT_read_format_bgra = false;
} m_sExts;
private: private:
std::list<GLuint> m_lBuffers; std::list<GLuint> m_lBuffers;
std::list<GLuint> m_lTextures; std::list<GLuint> m_lTextures;
@@ -176,10 +199,11 @@ class CHyprOpenGLImpl {
int m_iDRMFD; int m_iDRMFD;
std::string m_szExtensions; std::string m_szExtensions;
bool m_bFakeFrame = false; bool m_bFakeFrame = false;
bool m_bEndFrame = false; bool m_bEndFrame = false;
bool m_bApplyFinalShader = false; bool m_bApplyFinalShader = false;
bool m_bBlend = false; bool m_bBlend = false;
bool m_bOffloadedFramebuffer = false;
CShader m_sFinalScreenShader; CShader m_sFinalScreenShader;
CTimer m_tGlobalTimer; CTimer m_tGlobalTimer;
@@ -201,6 +225,8 @@ class CHyprOpenGLImpl {
bool shouldUseNewBlurOptimizations(SLayerSurface* pLayer, CWindow* pWindow); bool shouldUseNewBlurOptimizations(SLayerSurface* pLayer, CWindow* pWindow);
bool passRequiresIntrospection(CMonitor* pMonitor);
friend class CHyprRenderer; friend class CHyprRenderer;
}; };

View File

@@ -0,0 +1,84 @@
#include "Renderbuffer.hpp"
#include "OpenGL.hpp"
#include "../Compositor.hpp"
#include <dlfcn.h>
CRenderbuffer::~CRenderbuffer() {
if (!g_pCompositor)
return;
if (eglGetCurrentContext() != wlr_egl_get_context(g_pCompositor->m_sWLREGL))
eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL));
m_sFramebuffer.release();
glDeleteRenderbuffers(1, &m_iRBO);
g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), m_iImage);
}
CRenderbuffer::CRenderbuffer(wlr_buffer* buffer, uint32_t format) : m_pWlrBuffer(buffer) {
// EVIL, but we can't include a hidden header because nixos is fucking special
static EGLImageKHR (*PWLREGLCREATEIMAGEFROMDMABUF)(wlr_egl*, wlr_dmabuf_attributes*, bool*);
static bool symbolFound = false;
if (!symbolFound) {
PWLREGLCREATEIMAGEFROMDMABUF = reinterpret_cast<EGLImageKHR (*)(wlr_egl*, wlr_dmabuf_attributes*, bool*)>(dlsym(RTLD_DEFAULT, "wlr_egl_create_image_from_dmabuf"));
symbolFound = true;
RASSERT(PWLREGLCREATEIMAGEFROMDMABUF, "wlr_egl_create_image_from_dmabuf was not found in wlroots!");
Debug::log(LOG, "CRenderbuffer: wlr_egl_create_image_from_dmabuf found at {:x}", (uintptr_t)PWLREGLCREATEIMAGEFROMDMABUF);
}
// end evil hack
struct wlr_dmabuf_attributes dmabuf = {0};
if (!wlr_buffer_get_dmabuf(buffer, &dmabuf))
throw std::runtime_error("wlr_buffer_get_dmabuf failed");
bool externalOnly;
m_iImage = PWLREGLCREATEIMAGEFROMDMABUF(g_pCompositor->m_sWLREGL, &dmabuf, &externalOnly);
if (m_iImage == EGL_NO_IMAGE_KHR)
throw std::runtime_error("wlr_egl_create_image_from_dmabuf failed");
glGenRenderbuffers(1, &m_iRBO);
glBindRenderbuffer(GL_RENDERBUFFER, m_iRBO);
g_pHyprOpenGL->m_sProc.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, (GLeglImageOES)m_iImage);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glGenFramebuffers(1, &m_sFramebuffer.m_iFb);
m_sFramebuffer.m_vSize = {buffer->width, buffer->height};
m_sFramebuffer.bind();
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_iRBO);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
throw std::runtime_error("rbo: glCheckFramebufferStatus failed");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
hyprListener_destroyBuffer.initCallback(
&buffer->events.destroy, [](void* owner, void* data) { g_pHyprRenderer->onRenderbufferDestroy((CRenderbuffer*)owner); }, this, "CRenderbuffer");
}
void CRenderbuffer::bind() {
glBindRenderbuffer(GL_RENDERBUFFER, m_iRBO);
bindFB();
}
void CRenderbuffer::bindFB() {
m_sFramebuffer.bind();
}
void CRenderbuffer::unbind() {
glBindRenderbuffer(GL_RENDERBUFFER, 0);
#ifndef GLES2
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
#else
glBindFramebuffer(GL_FRAMEBUFFER, 0);
#endif
}
CFramebuffer* CRenderbuffer::getFB() {
return &m_sFramebuffer;
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include "Framebuffer.hpp"
class CMonitor;
class CRenderbuffer {
public:
CRenderbuffer(wlr_buffer* buffer, uint32_t format);
~CRenderbuffer();
void bind();
void bindFB();
void unbind();
CFramebuffer* getFB();
wlr_buffer* m_pWlrBuffer = nullptr;
DYNLISTENER(destroyBuffer);
private:
EGLImageKHR m_iImage = 0;
GLuint m_iRBO = 0;
CFramebuffer m_sFramebuffer;
};

View File

@@ -2,12 +2,53 @@
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "linux-dmabuf-unstable-v1-protocol.h" #include "linux-dmabuf-unstable-v1-protocol.h"
#include "../helpers/Region.hpp" #include "../helpers/Region.hpp"
#include <algorithm>
extern "C" {
#include <xf86drm.h>
}
CHyprRenderer::CHyprRenderer() { CHyprRenderer::CHyprRenderer() {
const auto ENV = getenv("WLR_DRM_NO_ATOMIC"); const auto ENV = getenv("WLR_DRM_NO_ATOMIC");
if (ENV && std::string(ENV) == "1") if (ENV && std::string(ENV) == "1")
m_bTearingEnvSatisfied = true; m_bTearingEnvSatisfied = true;
if (g_pCompositor->m_sWLRSession) {
wlr_device* dev;
wl_list_for_each(dev, &g_pCompositor->m_sWLRSession->devices, link) {
const auto DRMV = drmGetVersion(dev->fd);
std::string name = std::string{DRMV->name, DRMV->name_len};
std::transform(name.begin(), name.end(), name.begin(), tolower);
if (name.contains("nvidia"))
m_bNvidia = true;
Debug::log(LOG, "DRM driver information: {} v{}.{}.{} from {} description {}", name, DRMV->version_major, DRMV->version_minor, DRMV->version_patchlevel,
std::string{DRMV->date, DRMV->date_len}, std::string{DRMV->desc, DRMV->desc_len});
drmFreeVersion(DRMV);
}
} else {
Debug::log(LOG, "m_sWLRSession is null, omitting full DRM node checks");
const auto DRMV = drmGetVersion(g_pCompositor->m_iDRMFD);
std::string name = std::string{DRMV->name, DRMV->name_len};
std::transform(name.begin(), name.end(), name.begin(), tolower);
if (name.contains("nvidia"))
m_bNvidia = true;
Debug::log(LOG, "Primary DRM driver information: {} v{}.{}.{} from {} description {}", name, DRMV->version_major, DRMV->version_minor, DRMV->version_patchlevel,
std::string{DRMV->date, DRMV->date_len}, std::string{DRMV->desc, DRMV->desc_len});
drmFreeVersion(DRMV);
}
if (m_bNvidia)
Debug::log(WARN, "NVIDIA detected, please remember to follow nvidia instructions on the wiki");
} }
void renderSurface(struct wlr_surface* surface, int x, int y, void* data) { void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
@@ -65,7 +106,7 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
if (windowBox.width <= 1 || windowBox.height <= 1) if (windowBox.width <= 1 || windowBox.height <= 1)
return; // invisible return; // invisible
g_pHyprRenderer->calculateUVForSurface(RDATA->pWindow, surface, RDATA->squishOversized); g_pHyprRenderer->calculateUVForSurface(RDATA->pWindow, surface, RDATA->surface == surface);
windowBox.scale(RDATA->pMonitor->scale); windowBox.scale(RDATA->pMonitor->scale);
windowBox.round(); windowBox.round();
@@ -188,6 +229,9 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, CWorksp
if (w->m_bIsFullscreen || w->m_bIsFloating) if (w->m_bIsFullscreen || w->m_bIsFloating)
continue; continue;
if (pWorkspace->m_bIsSpecialWorkspace != g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID))
continue;
renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_ALL); renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_ALL);
} }
@@ -202,9 +246,16 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, CWorksp
if (w->m_bIsFullscreen || !w->m_bIsFloating) if (w->m_bIsFullscreen || !w->m_bIsFloating)
continue; continue;
if (w->m_iMonitorID == pWorkspace->m_iMonitorID && pWorkspace->m_bIsSpecialWorkspace != g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID))
continue;
if (pWorkspace->m_bIsSpecialWorkspace && w->m_iMonitorID != pWorkspace->m_iMonitorID)
continue; // special on another are rendered as a part of the base pass
renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_ALL); renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_ALL);
} }
// TODO: this pass sucks
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID);
@@ -216,7 +267,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, CWorksp
continue; continue;
} }
if (w->m_iWorkspaceID == pMonitor->activeWorkspace && !w->m_bIsFullscreen) if (w->m_iWorkspaceID != pMonitor->activeWorkspace || !w->m_bIsFullscreen)
continue; continue;
renderWindow(w.get(), pMonitor, time, pWorkspace->m_efFullscreenMode != FULLSCREEN_FULL, RENDER_PASS_ALL); renderWindow(w.get(), pMonitor, time, pWorkspace->m_efFullscreenMode != FULLSCREEN_FULL, RENDER_PASS_ALL);
@@ -235,6 +286,12 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, CWorksp
if (w->m_iWorkspaceID != pWorkspaceWindow->m_iWorkspaceID || (!w->m_bCreatedOverFullscreen && !w->m_bPinned) || (!w->m_bIsMapped && !w->m_bFadingOut) || w->m_bIsFullscreen) if (w->m_iWorkspaceID != pWorkspaceWindow->m_iWorkspaceID || (!w->m_bCreatedOverFullscreen && !w->m_bPinned) || (!w->m_bIsMapped && !w->m_bFadingOut) || w->m_bIsFullscreen)
continue; continue;
if (w->m_iMonitorID == pWorkspace->m_iMonitorID && pWorkspace->m_bIsSpecialWorkspace != g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID))
continue;
if (pWorkspace->m_bIsSpecialWorkspace && w->m_iMonitorID != pWorkspace->m_iMonitorID)
continue; // special on another are rendered as a part of the base pass
renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_ALL); renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_ALL);
} }
} }
@@ -252,14 +309,14 @@ void CHyprRenderer::renderWorkspaceWindows(CMonitor* pMonitor, CWorkspace* pWork
if (w->m_bIsFloating) if (w->m_bIsFloating)
continue; // floating are in the second pass continue; // floating are in the second pass
if (g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID))
continue; // special are in the third pass
if (!shouldRenderWindow(w.get(), pMonitor, pWorkspace)) if (!shouldRenderWindow(w.get(), pMonitor, pWorkspace))
continue; continue;
if (pWorkspace->m_bIsSpecialWorkspace != g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID))
continue;
// render active window after all others of this pass // render active window after all others of this pass
if (w.get() == g_pCompositor->m_pLastWindow) { if (w.get() == g_pCompositor->m_pLastWindow && w->m_iWorkspaceID == pWorkspace->m_iID) {
lastWindow = w.get(); lastWindow = w.get();
continue; continue;
} }
@@ -279,8 +336,8 @@ void CHyprRenderer::renderWorkspaceWindows(CMonitor* pMonitor, CWorkspace* pWork
if (w->m_bIsFloating) if (w->m_bIsFloating)
continue; // floating are in the second pass continue; // floating are in the second pass
if (g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID)) if (pWorkspace->m_bIsSpecialWorkspace != g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID))
continue; // special are in the third pass continue;
if (!shouldRenderWindow(w.get(), pMonitor, pWorkspace)) if (!shouldRenderWindow(w.get(), pMonitor, pWorkspace))
continue; continue;
@@ -297,29 +354,14 @@ void CHyprRenderer::renderWorkspaceWindows(CMonitor* pMonitor, CWorkspace* pWork
if (!w->m_bIsFloating || w->m_bPinned) if (!w->m_bIsFloating || w->m_bPinned)
continue; continue;
if (g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID))
continue;
if (!shouldRenderWindow(w.get(), pMonitor, pWorkspace)) if (!shouldRenderWindow(w.get(), pMonitor, pWorkspace))
continue; continue;
// render the bad boy if (w->m_iMonitorID == pWorkspace->m_iMonitorID && pWorkspace->m_bIsSpecialWorkspace != g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID))
renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_ALL);
}
// pinned always above
for (auto& w : g_pCompositor->m_vWindows) {
if (w->isHidden() && !w->m_bIsMapped && !w->m_bFadingOut)
continue; continue;
if (!w->m_bPinned || !w->m_bIsFloating) if (pWorkspace->m_bIsSpecialWorkspace && w->m_iMonitorID != pWorkspace->m_iMonitorID)
continue; continue; // special on another are rendered as a part of the base pass
if (g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID))
continue;
if (!shouldRenderWindow(w.get(), pMonitor, pWorkspace))
continue;
// render the bad boy // render the bad boy
renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_ALL); renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_ALL);
@@ -418,6 +460,12 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
renderdata.y += offset.y; renderdata.y += offset.y;
} }
// if window is floating and we have a slide animation, clip it to its full bb
if (!ignorePosition && pWindow->m_bIsFloating && !pWindow->m_bIsFullscreen && PWORKSPACE->m_vRenderOffset.isBeingAnimated()) {
CRegion rg = pWindow->getFullWindowBoundingBox().translate(-pMonitor->vecPosition + PWORKSPACE->m_vRenderOffset.vec()).scale(pMonitor->scale);
g_pHyprOpenGL->m_RenderData.clipBox = rg.getExtents();
}
// render window decorations first, if not fullscreen full // render window decorations first, if not fullscreen full
if (mode == RENDER_PASS_ALL || mode == RENDER_PASS_MAIN) { if (mode == RENDER_PASS_ALL || mode == RENDER_PASS_MAIN) {
@@ -507,6 +555,8 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
} }
} }
g_pHyprOpenGL->m_RenderData.clipBox = CBox();
if (mode == RENDER_PASS_ALL || mode == RENDER_PASS_POPUP) { if (mode == RENDER_PASS_ALL || mode == RENDER_PASS_POPUP) {
if (!pWindow->m_bIsX11) { if (!pWindow->m_bIsX11) {
CBox geom; CBox geom;
@@ -539,7 +589,7 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
EMIT_HOOK_EVENT("render", RENDER_POST_WINDOW); EMIT_HOOK_EVENT("render", RENDER_POST_WINDOW);
g_pHyprOpenGL->m_pCurrentWindow = nullptr; g_pHyprOpenGL->m_pCurrentWindow = nullptr;
g_pHyprOpenGL->m_RenderData.clipBox = {0, 0, 0, 0}; g_pHyprOpenGL->m_RenderData.clipBox = CBox();
} }
void CHyprRenderer::renderLayer(SLayerSurface* pLayer, CMonitor* pMonitor, timespec* time) { void CHyprRenderer::renderLayer(SLayerSurface* pLayer, CMonitor* pMonitor, timespec* time) {
@@ -600,9 +650,11 @@ void CHyprRenderer::renderSessionLockSurface(SSessionLockSurface* pSurface, CMon
} }
void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, CWorkspace* pWorkspace, timespec* time, const Vector2D& translate, const float& scale) { void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, CWorkspace* pWorkspace, timespec* time, const Vector2D& translate, const float& scale) {
static auto* const PDIMSPECIAL = &g_pConfigManager->getConfigValuePtr("decoration:dim_special")->floatValue; static auto* const PDIMSPECIAL = &g_pConfigManager->getConfigValuePtr("decoration:dim_special")->floatValue;
static auto* const PBLURSPECIAL = &g_pConfigManager->getConfigValuePtr("decoration:blur:special")->intValue; static auto* const PBLURSPECIAL = &g_pConfigManager->getConfigValuePtr("decoration:blur:special")->intValue;
static auto* const PBLUR = &g_pConfigManager->getConfigValuePtr("decoration:blur:enabled")->intValue; static auto* const PBLUR = &g_pConfigManager->getConfigValuePtr("decoration:blur:enabled")->intValue;
static auto* const PRENDERTEX = &g_pConfigManager->getConfigValuePtr("misc:disable_hyprland_logo")->intValue;
static auto* const PBACKGROUNDCOLOR = &g_pConfigManager->getConfigValuePtr("misc:background_color")->intValue;
const SRenderModifData RENDERMODIFDATA = {translate, scale}; const SRenderModifData RENDERMODIFDATA = {translate, scale};
@@ -634,6 +686,15 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, CWorkspace*
if (!g_pHyprOpenGL->m_RenderData.pCurrentMonData->blurFBShouldRender) if (!g_pHyprOpenGL->m_RenderData.pCurrentMonData->blurFBShouldRender)
setOccludedForBackLayers(g_pHyprOpenGL->m_RenderData.damage, pWorkspace); setOccludedForBackLayers(g_pHyprOpenGL->m_RenderData.damage, pWorkspace);
g_pHyprOpenGL->blend(false);
if (!canSkipBackBufferClear(pMonitor)) {
if (*PRENDERTEX /* inverted cfg flag */)
g_pHyprOpenGL->clear(CColor(*PBACKGROUNDCOLOR));
else
g_pHyprOpenGL->clearWithTex(); // will apply the hypr "wallpaper"
}
g_pHyprOpenGL->blend(true);
for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) {
renderLayer(ls.get(), pMonitor, time); renderLayer(ls.get(), pMonitor, time);
} }
@@ -674,11 +735,18 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, CWorkspace*
} }
} }
// special
for (auto& ws : g_pCompositor->m_vWorkspaces) {
if (ws->m_iMonitorID == pMonitor->ID && ws->m_fAlpha.fl() > 0.f && ws->m_bIsSpecialWorkspace)
renderWorkspaceWindows(pMonitor, ws.get(), time);
}
// pinned always above
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->isHidden() && !w->m_bIsMapped && !w->m_bFadingOut) if (w->isHidden() && !w->m_bIsMapped && !w->m_bFadingOut)
continue; continue;
if (!g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID)) if (!w->m_bPinned || !w->m_bIsFloating)
continue; continue;
if (!shouldRenderWindow(w.get(), pMonitor, pWorkspace)) if (!shouldRenderWindow(w.get(), pMonitor, pWorkspace))
@@ -775,10 +843,16 @@ void CHyprRenderer::calculateUVForSurface(CWindow* pWindow, wlr_surface* pSurfac
uvBR = uvBR - Vector2D(1.0 - WPERC * (uvBR.x - uvTL.x), 1.0 - HPERC * (uvBR.y - uvTL.y)); uvBR = uvBR - Vector2D(1.0 - WPERC * (uvBR.x - uvTL.x), 1.0 - HPERC * (uvBR.y - uvTL.y));
uvTL = uvTL + TOADDTL; uvTL = uvTL + TOADDTL;
if (geom.width > pWindow->m_vRealSize.vec().x || geom.height > pWindow->m_vRealSize.vec().y) { // TODO: make this passed to the func. Might break in the future.
uvBR.x = uvBR.x * (pWindow->m_vRealSize.vec().x / geom.width); auto maxSize = pWindow->m_vRealSize.vec();
uvBR.y = uvBR.y * (pWindow->m_vRealSize.vec().y / geom.height);
} if (pWindow->m_pWLSurface.small() && !pWindow->m_pWLSurface.m_bFillIgnoreSmall)
maxSize = pWindow->m_pWLSurface.getViewporterCorrectedSize();
if (geom.width > maxSize.x)
uvBR.x = uvBR.x * (maxSize.x / geom.width);
if (geom.height > maxSize.y)
uvBR.y = uvBR.y * (maxSize.y / geom.height);
} }
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = uvTL; g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = uvTL;
@@ -841,8 +915,8 @@ bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) {
} }
void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
static std::chrono::high_resolution_clock::time_point startRender = std::chrono::high_resolution_clock::now(); static std::chrono::high_resolution_clock::time_point renderStart = std::chrono::high_resolution_clock::now();
static std::chrono::high_resolution_clock::time_point startRenderOverlay = std::chrono::high_resolution_clock::now(); static std::chrono::high_resolution_clock::time_point renderStartOverlay = std::chrono::high_resolution_clock::now();
static std::chrono::high_resolution_clock::time_point endRenderOverlay = std::chrono::high_resolution_clock::now(); 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 PDEBUGOVERLAY = &g_pConfigManager->getConfigValuePtr("debug:overlay")->intValue;
@@ -851,9 +925,8 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
static auto* const PNODIRECTSCANOUT = &g_pConfigManager->getConfigValuePtr("misc:no_direct_scanout")->intValue; static auto* const PNODIRECTSCANOUT = &g_pConfigManager->getConfigValuePtr("misc:no_direct_scanout")->intValue;
static auto* const PVFR = &g_pConfigManager->getConfigValuePtr("misc:vfr")->intValue; static auto* const PVFR = &g_pConfigManager->getConfigValuePtr("misc:vfr")->intValue;
static auto* const PZOOMFACTOR = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor")->floatValue; static auto* const PZOOMFACTOR = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor")->floatValue;
static auto* const PRENDERTEX = &g_pConfigManager->getConfigValuePtr("misc:disable_hyprland_logo")->intValue;
static auto* const PBACKGROUNDCOLOR = &g_pConfigManager->getConfigValuePtr("misc:background_color")->intValue;
static auto* const PANIMENABLED = &g_pConfigManager->getConfigValuePtr("animations:enabled")->intValue; static auto* const PANIMENABLED = &g_pConfigManager->getConfigValuePtr("animations:enabled")->intValue;
static auto* const PFIRSTLAUNCHANIM = &g_pConfigManager->getConfigValuePtr("animations:first_launch_animation")->intValue;
static auto* const PTEARINGENABLED = &g_pConfigManager->getConfigValuePtr("general:allow_tearing")->intValue; static auto* const PTEARINGENABLED = &g_pConfigManager->getConfigValuePtr("general:allow_tearing")->intValue;
static int damageBlinkCleanup = 0; // because double-buffered static int damageBlinkCleanup = 0; // because double-buffered
@@ -862,7 +935,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
damageBlinkCleanup = 0; damageBlinkCleanup = 0;
static bool firstLaunch = true; static bool firstLaunch = true;
static bool firstLaunchAnimActive = true; static bool firstLaunchAnimActive = *PFIRSTLAUNCHANIM;
float zoomInFactorFirstLaunch = 1.f; float zoomInFactorFirstLaunch = 1.f;
@@ -883,7 +956,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
firstLaunchAnimActive = false; firstLaunchAnimActive = false;
} }
startRender = std::chrono::high_resolution_clock::now(); renderStart = std::chrono::high_resolution_clock::now();
if (*PDEBUGOVERLAY == 1) { if (*PDEBUGOVERLAY == 1) {
g_pDebugOverlay->frameData(pMonitor); g_pDebugOverlay->frameData(pMonitor);
@@ -987,7 +1060,6 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
// check the damage // check the damage
CRegion damage; CRegion damage;
bool hasChanged = pMonitor->output->needs_frame || pixman_region32_not_empty(&pMonitor->damage.current); bool hasChanged = pMonitor->output->needs_frame || pixman_region32_not_empty(&pMonitor->damage.current);
int bufferAge;
if (!hasChanged && *PDAMAGETRACKINGMODE != DAMAGE_TRACKING_NONE && pMonitor->forceFullFrames == 0 && damageBlinkCleanup == 0) if (!hasChanged && *PDAMAGETRACKINGMODE != DAMAGE_TRACKING_NONE && pMonitor->forceFullFrames == 0 && damageBlinkCleanup == 0)
return; return;
@@ -1003,16 +1075,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
if (UNLOCK_SC) if (UNLOCK_SC)
wlr_output_lock_software_cursors(pMonitor->output, true); wlr_output_lock_software_cursors(pMonitor->output, true);
if (!wlr_output_attach_render(pMonitor->output, &bufferAge)) { wlr_damage_ring_get_buffer_damage(&pMonitor->damage, m_iLastBufferAge, damage.pixman());
Debug::log(ERR, "Couldn't attach render to display {} ???", pMonitor->szName);
if (UNLOCK_SC)
wlr_output_lock_software_cursors(pMonitor->output, false);
return;
}
wlr_damage_ring_get_buffer_damage(&pMonitor->damage, bufferAge, damage.pixman());
pMonitor->renderingActive = true; pMonitor->renderingActive = true;
@@ -1058,7 +1121,25 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
TRACY_GPU_ZONE("Render"); TRACY_GPU_ZONE("Render");
g_pHyprOpenGL->begin(pMonitor, &damage); if (pMonitor == g_pCompositor->getMonitorFromCursor())
g_pHyprOpenGL->m_RenderData.mouseZoomFactor = std::clamp(*PZOOMFACTOR, 1.f, INFINITY);
else
g_pHyprOpenGL->m_RenderData.mouseZoomFactor = 1.f;
if (zoomInFactorFirstLaunch > 1.f) {
g_pHyprOpenGL->m_RenderData.mouseZoomFactor = zoomInFactorFirstLaunch;
g_pHyprOpenGL->m_RenderData.mouseZoomUseMouse = false;
g_pHyprOpenGL->m_RenderData.useNearestNeighbor = false;
}
if (!beginRender(pMonitor, damage, RENDER_MODE_NORMAL)) {
Debug::log(ERR, "renderer: couldn't beginRender()!");
if (UNLOCK_SC)
wlr_output_lock_software_cursors(pMonitor->output, false);
return;
}
EMIT_HOOK_EVENT("render", RENDER_BEGIN); EMIT_HOOK_EVENT("render", RENDER_BEGIN);
@@ -1072,15 +1153,6 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
EMIT_HOOK_EVENT("render", RENDER_POST_MIRROR); EMIT_HOOK_EVENT("render", RENDER_POST_MIRROR);
renderCursor = false; renderCursor = false;
} else { } else {
g_pHyprOpenGL->blend(false);
if (!canSkipBackBufferClear(pMonitor)) {
if (*PRENDERTEX /* inverted cfg flag */)
g_pHyprOpenGL->clear(CColor(*PBACKGROUNDCOLOR));
else
g_pHyprOpenGL->clearWithTex(); // will apply the hypr "wallpaper"
}
g_pHyprOpenGL->blend(true);
CBox renderBox = {0, 0, (int)pMonitor->vecPixelSize.x, (int)pMonitor->vecPixelSize.y}; CBox renderBox = {0, 0, (int)pMonitor->vecPixelSize.x, (int)pMonitor->vecPixelSize.y};
renderWorkspace(pMonitor, g_pCompositor->getWorkspaceByID(pMonitor->activeWorkspace), &now, renderBox); renderWorkspace(pMonitor, g_pCompositor->getWorkspaceByID(pMonitor->activeWorkspace), &now, renderBox);
@@ -1093,7 +1165,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
// for drawing the debug overlay // for drawing the debug overlay
if (pMonitor == g_pCompositor->m_vMonitors.front().get() && *PDEBUGOVERLAY == 1) { if (pMonitor == g_pCompositor->m_vMonitors.front().get() && *PDEBUGOVERLAY == 1) {
startRenderOverlay = std::chrono::high_resolution_clock::now(); renderStartOverlay = std::chrono::high_resolution_clock::now();
g_pDebugOverlay->draw(); g_pDebugOverlay->draw();
endRenderOverlay = std::chrono::high_resolution_clock::now(); endRenderOverlay = std::chrono::high_resolution_clock::now();
} }
@@ -1114,35 +1186,22 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
renderCursor = renderCursor && shouldRenderCursor(); renderCursor = renderCursor && shouldRenderCursor();
if (renderCursor && wlr_renderer_begin(g_pCompositor->m_sWLRRenderer, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y)) { if (renderCursor) {
TRACY_GPU_ZONE("RenderCursor"); TRACY_GPU_ZONE("RenderCursor");
bool lockSoftware = pMonitor == g_pCompositor->getMonitorFromCursor() && *PZOOMFACTOR != 1.f; bool lockSoftware = pMonitor == g_pCompositor->getMonitorFromCursor() && *PZOOMFACTOR != 1.f;
if (lockSoftware) { if (lockSoftware) {
wlr_output_lock_software_cursors(pMonitor->output, true); wlr_output_lock_software_cursors(pMonitor->output, true);
wlr_output_render_software_cursors(pMonitor->output, NULL); g_pHyprRenderer->renderSoftwareCursors(pMonitor, g_pHyprOpenGL->m_RenderData.damage);
wlr_output_lock_software_cursors(pMonitor->output, false); wlr_output_lock_software_cursors(pMonitor->output, false);
} else } else
wlr_output_render_software_cursors(pMonitor->output, NULL); g_pHyprRenderer->renderSoftwareCursors(pMonitor, g_pHyprOpenGL->m_RenderData.damage);
wlr_renderer_end(g_pCompositor->m_sWLRRenderer);
}
if (pMonitor == g_pCompositor->getMonitorFromCursor())
g_pHyprOpenGL->m_RenderData.mouseZoomFactor = std::clamp(*PZOOMFACTOR, 1.f, INFINITY);
else
g_pHyprOpenGL->m_RenderData.mouseZoomFactor = 1.f;
if (zoomInFactorFirstLaunch > 1.f) {
g_pHyprOpenGL->m_RenderData.mouseZoomFactor = zoomInFactorFirstLaunch;
g_pHyprOpenGL->m_RenderData.mouseZoomUseMouse = false;
g_pHyprOpenGL->m_RenderData.useNearestNeighbor = false;
} }
EMIT_HOOK_EVENT("render", RENDER_LAST_MOMENT); EMIT_HOOK_EVENT("render", RENDER_LAST_MOMENT);
g_pHyprOpenGL->end(); endRender();
TRACY_GPU_COLLECT; TRACY_GPU_COLLECT;
@@ -1188,12 +1247,12 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
pMonitor->pendingFrame = false; pMonitor->pendingFrame = false;
const float µs = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - startRender).count() / 1000.f; const float µs = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - renderStart).count() / 1000.f;
g_pDebugOverlay->renderData(pMonitor, µs); g_pDebugOverlay->renderData(pMonitor, µs);
if (*PDEBUGOVERLAY == 1) { if (*PDEBUGOVERLAY == 1) {
if (pMonitor == g_pCompositor->m_vMonitors.front().get()) { if (pMonitor == g_pCompositor->m_vMonitors.front().get()) {
const float µsNoOverlay = µs - std::chrono::duration_cast<std::chrono::nanoseconds>(endRenderOverlay - startRenderOverlay).count() / 1000.f; const float µsNoOverlay = µs - std::chrono::duration_cast<std::chrono::nanoseconds>(endRenderOverlay - renderStartOverlay).count() / 1000.f;
g_pDebugOverlay->renderDataNoOverlay(pMonitor, µsNoOverlay); g_pDebugOverlay->renderDataNoOverlay(pMonitor, µsNoOverlay);
} else { } else {
g_pDebugOverlay->renderDataNoOverlay(pMonitor, µs); g_pDebugOverlay->renderDataNoOverlay(pMonitor, µs);
@@ -1287,13 +1346,22 @@ void CHyprRenderer::outputMgrApplyTest(wlr_output_configuration_v1* config, bool
break; break;
} }
if (!test) if (!test) {
g_pConfigManager->m_bWantsMonitorReload = true; // for monitor keywords g_pConfigManager->m_bWantsMonitorReload = true; // for monitor keywords
// if everything is disabled, performMonitorReload won't be called from renderMonitor
bool allDisabled = std::all_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(),
[](const auto m) { return !m->m_bEnabled || g_pCompositor->m_pUnsafeOutput == m.get(); });
if (allDisabled) {
Debug::log(LOG, "OutputMgr apply: All monitors disabled; performing monitor reload.");
g_pConfigManager->performMonitorReload();
}
}
if (ok) if (ok)
wlr_output_configuration_v1_send_succeeded(config); wlr_output_configuration_v1_send_succeeded(config);
else else
wlr_output_configuration_v1_send_failed(config); wlr_output_configuration_v1_send_failed(config);
wlr_output_configuration_v1_destroy(config); wlr_output_configuration_v1_destroy(config);
Debug::log(LOG, "OutputMgr Applied/Tested."); Debug::log(LOG, "OutputMgr Applied/Tested.");
@@ -1439,9 +1507,6 @@ void CHyprRenderer::arrangeLayerArray(CMonitor* pMonitor, const std::vector<std:
if (Vector2D{box.width, box.height} != OLDSIZE) if (Vector2D{box.width, box.height} != OLDSIZE)
wlr_layer_surface_v1_configure(ls->layerSurface, box.width, box.height); wlr_layer_surface_v1_configure(ls->layerSurface, box.width, box.height);
Debug::log(LOG, "LayerSurface {:x} arranged: x: {} y: {} w: {} h: {} with margins: t: {} l: {} r: {} b: {}", (uintptr_t)&ls, box.x, box.y, box.width, box.height,
PSTATE->margin.top, PSTATE->margin.left, PSTATE->margin.right, PSTATE->margin.bottom);
} }
} }
@@ -1480,8 +1545,6 @@ void CHyprRenderer::arrangeLayersForMonitor(const int& monitor) {
damageMonitor(PMONITOR); damageMonitor(PMONITOR);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitor); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitor);
Debug::log(LOG, "Monitor {} layers arranged: reserved: {:5j} {:5j}", PMONITOR->szName, PMONITOR->vecReservedTopLeft, PMONITOR->vecReservedBottomRight);
} }
void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y, double scale) { void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y, double scale) {
@@ -1645,7 +1708,6 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
// if it's disabled, disable and ignore // if it's disabled, disable and ignore
if (pMonitorRule->disabled) { if (pMonitorRule->disabled) {
if (pMonitor->m_bEnabled) if (pMonitor->m_bEnabled)
pMonitor->onDisconnect(); pMonitor->onDisconnect();
@@ -1950,6 +2012,8 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
pMonitor->vecPixelSize = Vector2D(transformedBox.width, transformedBox.height); pMonitor->vecPixelSize = Vector2D(transformedBox.width, transformedBox.height);
} }
pMonitor->updateMatrix();
// update renderer (here because it will call rollback, so we cannot do this before committing) // update renderer (here because it will call rollback, so we cannot do this before committing)
g_pHyprOpenGL->destroyMonitorResources(pMonitor); g_pHyprOpenGL->destroyMonitorResources(pMonitor);
@@ -2123,7 +2187,12 @@ bool CHyprRenderer::canSkipBackBufferClear(CMonitor* pMonitor) {
ls->geometry.height != pMonitor->vecSize.y) ls->geometry.height != pMonitor->vecSize.y)
continue; continue;
if (!ls->layerSurface->surface->opaque) // TODO: cache maybe?
CRegion opaque = &ls->layerSurface->surface->opaque_region;
CBox lsbox = {0, 0, ls->layerSurface->surface->current.buffer_width, ls->layerSurface->surface->current.buffer_height};
opaque.invert(lsbox);
if (!opaque.empty())
continue; continue;
return true; return true;
@@ -2184,3 +2253,125 @@ void CHyprRenderer::recheckSolitaryForMonitor(CMonitor* pMonitor) {
// found one! // found one!
pMonitor->solitaryClient = PCANDIDATE; pMonitor->solitaryClient = PCANDIDATE;
} }
void CHyprRenderer::renderSoftwareCursors(CMonitor* pMonitor, const CRegion& damage, std::optional<Vector2D> overridePos) {
const auto CURSORPOS = overridePos.value_or(g_pInputManager->getMouseCoordsInternal() - pMonitor->vecPosition) * pMonitor->scale;
wlr_output_cursor* cursor;
wl_list_for_each(cursor, &pMonitor->output->cursors, link) {
if (!cursor->enabled || !cursor->visible || pMonitor->output->hardware_cursor == cursor)
continue;
if (!cursor->texture)
continue;
CBox cursorBox = CBox{CURSORPOS.x, CURSORPOS.y, cursor->width, cursor->height}.translate({-cursor->hotspot_x, -cursor->hotspot_y});
// TODO: NVIDIA doesn't like if we use renderTexturePrimitive here. Why?
g_pHyprOpenGL->renderTexture(cursor->texture, &cursorBox, 1.0);
}
}
CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(wlr_buffer* buffer, uint32_t fmt) {
auto it = std::find_if(m_vRenderbuffers.begin(), m_vRenderbuffers.end(), [&](const auto& other) { return other->m_pWlrBuffer == buffer; });
if (it != m_vRenderbuffers.end())
return it->get();
return m_vRenderbuffers.emplace_back(std::make_unique<CRenderbuffer>(buffer, fmt)).get();
}
void CHyprRenderer::makeEGLCurrent() {
if (!g_pCompositor)
return;
if (eglGetCurrentContext() != wlr_egl_get_context(g_pCompositor->m_sWLREGL))
eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL));
}
void CHyprRenderer::unsetEGL() {
eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, wlr_buffer* buffer, CFramebuffer* fb) {
makeEGLCurrent();
m_eRenderMode = mode;
g_pHyprOpenGL->m_RenderData.pMonitor = pMonitor; // has to be set cuz allocs
if (mode == RENDER_MODE_FULL_FAKE) {
RASSERT(fb, "Cannot render FULL_FAKE without a provided fb!");
fb->bind();
g_pHyprOpenGL->begin(pMonitor, &damage, fb);
return true;
}
if (!buffer) {
if (!wlr_output_configure_primary_swapchain(pMonitor->output, &pMonitor->output->pending, &pMonitor->output->swapchain))
return false;
m_pCurrentWlrBuffer = wlr_swapchain_acquire(pMonitor->output->swapchain, &m_iLastBufferAge);
if (!m_pCurrentWlrBuffer)
return false;
} else {
m_pCurrentWlrBuffer = wlr_buffer_lock(buffer);
}
try {
m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentWlrBuffer, pMonitor->drmFormat);
} catch (std::exception& e) {
wlr_buffer_unlock(m_pCurrentWlrBuffer);
return false;
}
m_pCurrentRenderbuffer->bind();
g_pHyprOpenGL->begin(pMonitor, &damage);
return true;
}
void CHyprRenderer::endRender() {
const auto PMONITOR = g_pHyprOpenGL->m_RenderData.pMonitor;
if (m_eRenderMode != RENDER_MODE_TO_BUFFER_READ_ONLY)
g_pHyprOpenGL->end();
else {
g_pHyprOpenGL->m_RenderData.pMonitor = nullptr;
g_pHyprOpenGL->m_RenderData.mouseZoomFactor = 1.f;
g_pHyprOpenGL->m_RenderData.mouseZoomUseMouse = true;
}
if (m_eRenderMode == RENDER_MODE_FULL_FAKE)
return;
if (isNvidia())
glFinish();
else
glFlush();
if (m_eRenderMode == RENDER_MODE_NORMAL) {
wlr_output_state_set_buffer(&PMONITOR->output->pending, m_pCurrentWlrBuffer);
unsetEGL(); // flush the context
}
wlr_buffer_unlock(m_pCurrentWlrBuffer);
m_pCurrentRenderbuffer->unbind();
m_pCurrentRenderbuffer = nullptr;
m_pCurrentWlrBuffer = nullptr;
m_iLastBufferAge = 0;
}
void CHyprRenderer::onRenderbufferDestroy(CRenderbuffer* rb) {
std::erase_if(m_vRenderbuffers, [&](const auto& rbo) { return rbo.get() == rb; });
}
CRenderbuffer* CHyprRenderer::getCurrentRBO() {
return m_pCurrentRenderbuffer;
}
bool CHyprRenderer::isNvidia() {
return m_bNvidia;
}

View File

@@ -6,6 +6,7 @@
#include "../helpers/Workspace.hpp" #include "../helpers/Workspace.hpp"
#include "../Window.hpp" #include "../Window.hpp"
#include "OpenGL.hpp" #include "OpenGL.hpp"
#include "Renderbuffer.hpp"
#include "../helpers/Timer.hpp" #include "../helpers/Timer.hpp"
#include "../helpers/Region.hpp" #include "../helpers/Region.hpp"
@@ -27,6 +28,14 @@ enum eRenderPassMode
RENDER_PASS_POPUP RENDER_PASS_POPUP
}; };
enum eRenderMode
{
RENDER_MODE_NORMAL = 0,
RENDER_MODE_FULL_FAKE = 1,
RENDER_MODE_TO_BUFFER = 2,
RENDER_MODE_TO_BUFFER_READ_ONLY = 3,
};
class CToplevelExportProtocolManager; class CToplevelExportProtocolManager;
class CInputManager; class CInputManager;
struct SSessionLockSurface; struct SSessionLockSurface;
@@ -58,15 +67,24 @@ class CHyprRenderer {
void recheckSolitaryForMonitor(CMonitor* pMonitor); void recheckSolitaryForMonitor(CMonitor* pMonitor);
void setCursorSurface(wlr_surface* surf, int hotspotX, int hotspotY); void setCursorSurface(wlr_surface* surf, int hotspotX, int hotspotY);
void setCursorFromName(const std::string& name); void setCursorFromName(const std::string& name);
void renderSoftwareCursors(CMonitor* pMonitor, const CRegion& damage, std::optional<Vector2D> overridePos = {});
void onRenderbufferDestroy(CRenderbuffer* rb);
CRenderbuffer* getCurrentRBO();
bool isNvidia();
void makeEGLCurrent();
void unsetEGL();
bool m_bWindowRequestedCursorHide = false; bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, wlr_buffer* buffer = nullptr, CFramebuffer* fb = nullptr);
bool m_bBlockSurfaceFeedback = false; void endRender();
bool m_bRenderingSnapshot = false;
CWindow* m_pLastScanout = nullptr; bool m_bWindowRequestedCursorHide = false;
CMonitor* m_pMostHzMonitor = nullptr; bool m_bBlockSurfaceFeedback = false;
bool m_bDirectScanoutBlocked = false; bool m_bRenderingSnapshot = false;
bool m_bSoftwareCursorsLocked = false; CWindow* m_pLastScanout = nullptr;
bool m_bTearingEnvSatisfied = false; CMonitor* m_pMostHzMonitor = nullptr;
bool m_bDirectScanoutBlocked = false;
bool m_bSoftwareCursorsLocked = false;
bool m_bTearingEnvSatisfied = false;
DAMAGETRACKINGMODES DAMAGETRACKINGMODES
damageTrackingModeFromStr(const std::string&); damageTrackingModeFromStr(const std::string&);
@@ -89,19 +107,28 @@ class CHyprRenderer {
} m_sLastCursorData; } m_sLastCursorData;
private: private:
void arrangeLayerArray(CMonitor*, const std::vector<std::unique_ptr<SLayerSurface>>&, bool, CBox*); void arrangeLayerArray(CMonitor*, const std::vector<std::unique_ptr<SLayerSurface>>&, bool, CBox*);
void renderWorkspaceWindowsFullscreen(CMonitor*, CWorkspace*, timespec*); // renders workspace windows (fullscreen) (tiled, floating, pinned, but no special) void renderWorkspaceWindowsFullscreen(CMonitor*, CWorkspace*, timespec*); // renders workspace windows (fullscreen) (tiled, floating, pinned, but no special)
void renderWorkspaceWindows(CMonitor*, CWorkspace*, timespec*); // renders workspace windows (no fullscreen) (tiled, floating, pinned, but no special) void renderWorkspaceWindows(CMonitor*, CWorkspace*, timespec*); // renders workspace windows (no fullscreen) (tiled, floating, pinned, but no special)
void renderWindow(CWindow*, CMonitor*, timespec*, bool, eRenderPassMode, bool ignorePosition = false, bool ignoreAllGeometry = false); void renderWindow(CWindow*, CMonitor*, timespec*, bool, eRenderPassMode, bool ignorePosition = false, bool ignoreAllGeometry = false);
void renderLayer(SLayerSurface*, CMonitor*, timespec*); void renderLayer(SLayerSurface*, CMonitor*, timespec*);
void renderSessionLockSurface(SSessionLockSurface*, CMonitor*, timespec*); void renderSessionLockSurface(SSessionLockSurface*, CMonitor*, timespec*);
void renderDragIcon(CMonitor*, timespec*); void renderDragIcon(CMonitor*, timespec*);
void renderIMEPopup(SIMEPopup*, CMonitor*, timespec*); void renderIMEPopup(SIMEPopup*, CMonitor*, timespec*);
void renderWorkspace(CMonitor* pMonitor, CWorkspace* pWorkspace, timespec* now, const CBox& geometry); void renderWorkspace(CMonitor* pMonitor, CWorkspace* pWorkspace, timespec* now, const CBox& geometry);
void renderAllClientsForWorkspace(CMonitor* pMonitor, CWorkspace* pWorkspace, timespec* now, const Vector2D& translate = {0, 0}, const float& scale = 1.f); void renderAllClientsForWorkspace(CMonitor* pMonitor, CWorkspace* pWorkspace, timespec* now, const Vector2D& translate = {0, 0}, const float& scale = 1.f);
bool m_bHasARenderedCursor = true; bool m_bHasARenderedCursor = true;
bool m_bCursorHasSurface = false; bool m_bCursorHasSurface = false;
CRenderbuffer* m_pCurrentRenderbuffer = nullptr;
wlr_buffer* m_pCurrentWlrBuffer = nullptr;
eRenderMode m_eRenderMode = RENDER_MODE_NORMAL;
int m_iLastBufferAge = 0;
bool m_bNvidia = false;
CRenderbuffer* getOrCreateRenderbuffer(wlr_buffer* buffer, uint32_t fmt);
std::vector<std::unique_ptr<CRenderbuffer>> m_vRenderbuffers;
friend class CHyprOpenGLImpl; friend class CHyprOpenGLImpl;
friend class CToplevelExportProtocolManager; friend class CToplevelExportProtocolManager;

View File

@@ -26,6 +26,10 @@ void CHyprDropShadowDecoration::onPositioningReply(const SDecorationPositioningR
updateWindow(m_pWindow); updateWindow(m_pWindow);
} }
uint64_t CHyprDropShadowDecoration::getDecorationFlags() {
return DECORATION_NON_SOLID;
}
void CHyprDropShadowDecoration::damageEntire() { void CHyprDropShadowDecoration::damageEntire() {
static auto* const PSHADOWS = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue; static auto* const PSHADOWS = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue;
@@ -88,6 +92,7 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a, const Vector2D
// scale the box in relation to the center of the box // scale the box in relation to the center of the box
fullBox.scaleFromCenter(SHADOWSCALE).translate(*PSHADOWOFFSET); fullBox.scaleFromCenter(SHADOWSCALE).translate(*PSHADOWOFFSET);
m_vLastWindowPos += WORKSPACEOFFSET;
m_seExtents = {{m_vLastWindowPos.x - fullBox.x - pMonitor->vecPosition.x + 2, m_vLastWindowPos.y - fullBox.y - pMonitor->vecPosition.y + 2}, 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.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.y + fullBox.height + pMonitor->vecPosition.y - m_vLastWindowPos.y - m_vLastWindowSize.y + 2}};
@@ -122,12 +127,17 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a, const Vector2D
if (windowBox.width < 1 || windowBox.height < 1) if (windowBox.width < 1 || windowBox.height < 1)
return; // prevent assert failed return; // prevent assert failed
CRegion saveDamage = g_pHyprOpenGL->m_RenderData.damage;
g_pHyprOpenGL->m_RenderData.damage = fullBox;
g_pHyprOpenGL->m_RenderData.damage.subtract(windowBox.copy().expand(-ROUNDING * pMonitor->scale)).intersect(saveDamage);
alphaFB.bind(); alphaFB.bind();
// build the matte // build the matte
// 10-bit formats have dogshit alpha channels, so we have to use the matte to its fullest. // 10-bit formats have dogshit alpha channels, so we have to use the matte to its fullest.
// first, clear with black (fully transparent) // first, clear region of interest with black (fully transparent)
g_pHyprOpenGL->clear(CColor(0, 0, 0, 1)); g_pHyprOpenGL->renderRect(&fullBox, CColor(0, 0, 0, 1), 0);
// render white shadow with the alpha of the shadow color (otherwise we clear with alpha later and shit it to 2 bit) // render white shadow with the alpha of the shadow color (otherwise we clear with alpha later and shit it to 2 bit)
g_pHyprOpenGL->renderRoundedShadow(&fullBox, ROUNDING * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, CColor(1, 1, 1, m_pWindow->m_cRealShadowColor.col().a), a); g_pHyprOpenGL->renderRoundedShadow(&fullBox, ROUNDING * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, CColor(1, 1, 1, m_pWindow->m_cRealShadowColor.col().a), a);
@@ -138,7 +148,7 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a, const Vector2D
alphaSwapFB.bind(); alphaSwapFB.bind();
// alpha swap just has the shadow color. It will be the "texture" to render. // alpha swap just has the shadow color. It will be the "texture" to render.
g_pHyprOpenGL->clear(m_pWindow->m_cRealShadowColor.col().stripA()); g_pHyprOpenGL->renderRect(&fullBox, m_pWindow->m_cRealShadowColor.col().stripA(), 0);
LASTFB->bind(); LASTFB->bind();
@@ -146,6 +156,8 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a, const Vector2D
g_pHyprOpenGL->setMonitorTransformEnabled(false); g_pHyprOpenGL->setMonitorTransformEnabled(false);
g_pHyprOpenGL->renderTextureMatte(alphaSwapFB.m_cTex, &monbox, alphaFB); g_pHyprOpenGL->renderTextureMatte(alphaSwapFB.m_cTex, &monbox, alphaFB);
g_pHyprOpenGL->setMonitorTransformEnabled(true); g_pHyprOpenGL->setMonitorTransformEnabled(true);
g_pHyprOpenGL->m_RenderData.damage = saveDamage;
} else { } else {
g_pHyprOpenGL->renderRoundedShadow(&fullBox, ROUNDING * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, a); g_pHyprOpenGL->renderRoundedShadow(&fullBox, ROUNDING * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, a);
} }

View File

@@ -21,6 +21,8 @@ class CHyprDropShadowDecoration : public IHyprWindowDecoration {
virtual eDecorationLayer getDecorationLayer(); virtual eDecorationLayer getDecorationLayer();
virtual uint64_t getDecorationFlags();
private: private:
SWindowDecorationExtents m_seExtents; SWindowDecorationExtents m_seExtents;
SWindowDecorationExtents m_seReportedExtents; SWindowDecorationExtents m_seReportedExtents;

View File

@@ -6,6 +6,9 @@
// shared things to conserve VRAM // shared things to conserve VRAM
static CTexture m_tGradientActive; static CTexture m_tGradientActive;
static CTexture m_tGradientInactive; static CTexture m_tGradientInactive;
static CTexture m_tGradientLockedActive;
static CTexture m_tGradientLockedInactive;
constexpr int BAR_INDICATOR_HEIGHT = 3; constexpr int BAR_INDICATOR_HEIGHT = 3;
constexpr int BAR_PADDING_OUTER_VERT = 2; constexpr int BAR_PADDING_OUTER_VERT = 2;
constexpr int BAR_TEXT_PAD = 2; constexpr int BAR_TEXT_PAD = 2;
@@ -13,6 +16,8 @@ constexpr int BAR_HORIZONTAL_PADDING = 2;
CHyprGroupBarDecoration::CHyprGroupBarDecoration(CWindow* pWindow) : IHyprWindowDecoration(pWindow) { CHyprGroupBarDecoration::CHyprGroupBarDecoration(CWindow* pWindow) : IHyprWindowDecoration(pWindow) {
m_pWindow = pWindow; m_pWindow = pWindow;
if (m_tGradientActive.m_iTexID == 0)
refreshGroupBarGradients();
} }
CHyprGroupBarDecoration::~CHyprGroupBarDecoration() {} CHyprGroupBarDecoration::~CHyprGroupBarDecoration() {}
@@ -118,8 +123,9 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D&
// render title if necessary // render title if necessary
if (*PRENDERTITLES) { if (*PRENDERTITLES) {
CBox rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + offset.x, ASSIGNEDBOX.y - pMonitor->vecPosition.y + offset.y + BAR_PADDING_OUTER_VERT, m_fBarWidth, CBox rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + offset.x, ASSIGNEDBOX.y - pMonitor->vecPosition.y + offset.y + BAR_PADDING_OUTER_VERT, m_fBarWidth,
ASSIGNEDBOX.h - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT * 2}; ASSIGNEDBOX.h - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT * 2};
rect.scale(pMonitor->scale);
CTitleTex* pTitleTex = textureFromTitle(m_dwGroupMembers[i]->m_szTitle); CTitleTex* pTitleTex = textureFromTitle(m_dwGroupMembers[i]->m_szTitle);
@@ -129,15 +135,13 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D&
Vector2D{m_fBarWidth * pMonitor->scale, (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale})) Vector2D{m_fBarWidth * pMonitor->scale, (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale}))
.get(); .get();
refreshGradients(); const auto& GRADIENTTEX = (m_dwGroupMembers[i] == g_pCompositor->m_pLastWindow ? (GROUPLOCKED ? m_tGradientLockedActive : m_tGradientActive) :
(GROUPLOCKED ? m_tGradientLockedInactive : m_tGradientInactive));
if (*PGRADIENTS) { if (*PGRADIENTS && GRADIENTTEX.m_iTexID != 0)
CBox rect2 = rect; g_pHyprOpenGL->renderTexture(GRADIENTTEX, &rect, 1.0);
rect2.scale(pMonitor->scale);
g_pHyprOpenGL->renderTexture((m_dwGroupMembers[i] == g_pCompositor->m_pLastWindow ? m_tGradientActive : m_tGradientInactive), &rect2, 1.0);
}
rect.y = ASSIGNEDBOX.y + ASSIGNEDBOX.h / 2.0 - (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) / 2.0; rect.y += (ASSIGNEDBOX.h / 2.0 - (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) / 2.0) * pMonitor->scale;
rect.height = (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale; rect.height = (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale;
g_pHyprOpenGL->renderTexture(pTitleTex->tex, &rect, 1.f); g_pHyprOpenGL->renderTexture(pTitleTex->tex, &rect, 1.f);
@@ -234,6 +238,9 @@ CTitleTex::~CTitleTex() {
void renderGradientTo(CTexture& tex, const CColor& grad) { void renderGradientTo(CTexture& tex, const CColor& grad) {
if (!g_pCompositor->m_pLastMonitor)
return;
const Vector2D& bufferSize = g_pCompositor->m_pLastMonitor->vecPixelSize; const Vector2D& bufferSize = g_pCompositor->m_pLastMonitor->vecPixelSize;
const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, bufferSize.x, bufferSize.y); const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, bufferSize.x, bufferSize.y);
@@ -275,21 +282,23 @@ void renderGradientTo(CTexture& tex, const CColor& grad) {
cairo_surface_destroy(CAIROSURFACE); cairo_surface_destroy(CAIROSURFACE);
} }
void CHyprGroupBarDecoration::refreshGradients() { void refreshGroupBarGradients() {
if (m_tGradientActive.m_iTexID > 0)
return;
static auto* const PGROUPCOLACTIVE = &g_pConfigManager->getConfigValuePtr("group:groupbar:col.active")->data; static auto* const PGROUPCOLACTIVE = &g_pConfigManager->getConfigValuePtr("group:groupbar:col.active")->data;
static auto* const PGROUPCOLINACTIVE = &g_pConfigManager->getConfigValuePtr("group:groupbar:col.inactive")->data; static auto* const PGROUPCOLINACTIVE = &g_pConfigManager->getConfigValuePtr("group:groupbar:col.inactive")->data;
static auto* const PGROUPCOLACTIVELOCKED = &g_pConfigManager->getConfigValuePtr("group:groupbar:col.locked_active")->data; static auto* const PGROUPCOLACTIVELOCKED = &g_pConfigManager->getConfigValuePtr("group:groupbar:col.locked_active")->data;
static auto* const PGROUPCOLINACTIVELOCKED = &g_pConfigManager->getConfigValuePtr("group:groupbar:col.locked_inactive")->data; static auto* const PGROUPCOLINACTIVELOCKED = &g_pConfigManager->getConfigValuePtr("group:groupbar:col.locked_inactive")->data;
const bool GROUPLOCKED = m_pWindow->getGroupHead()->m_sGroupData.locked; if (m_tGradientActive.m_iTexID != 0) {
const auto* const PCOLACTIVE = GROUPLOCKED ? PGROUPCOLACTIVELOCKED : PGROUPCOLACTIVE; m_tGradientActive.destroyTexture();
const auto* const PCOLINACTIVE = GROUPLOCKED ? PGROUPCOLINACTIVELOCKED : PGROUPCOLINACTIVE; m_tGradientInactive.destroyTexture();
m_tGradientLockedActive.destroyTexture();
m_tGradientLockedInactive.destroyTexture();
}
renderGradientTo(m_tGradientActive, ((CGradientValueData*)PCOLACTIVE->get())->m_vColors[0]); renderGradientTo(m_tGradientActive, ((CGradientValueData*)PGROUPCOLACTIVE->get())->m_vColors[0]);
renderGradientTo(m_tGradientInactive, ((CGradientValueData*)PCOLINACTIVE->get())->m_vColors[0]); renderGradientTo(m_tGradientInactive, ((CGradientValueData*)PGROUPCOLINACTIVE->get())->m_vColors[0]);
renderGradientTo(m_tGradientLockedActive, ((CGradientValueData*)PGROUPCOLACTIVELOCKED->get())->m_vColors[0]);
renderGradientTo(m_tGradientLockedInactive, ((CGradientValueData*)PGROUPCOLINACTIVELOCKED->get())->m_vColors[0]);
} }
bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(CWindow* pDraggedWindow, const Vector2D& pos) { bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(CWindow* pDraggedWindow, const Vector2D& pos) {
@@ -346,6 +355,9 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(CWindow* pDraggedWindow, con
pDraggedWindow->updateWindowDecos(); pDraggedWindow->updateWindowDecos();
g_pLayoutManager->getCurrentLayout()->recalculateWindow(pDraggedWindow); g_pLayoutManager->getCurrentLayout()->recalculateWindow(pDraggedWindow);
if (!pDraggedWindow->getDecorationByType(DECORATION_GROUPBAR))
pDraggedWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pDraggedWindow));
return false; return false;
} }
@@ -405,5 +417,13 @@ uint64_t CHyprGroupBarDecoration::getDecorationFlags() {
CBox CHyprGroupBarDecoration::assignedBoxGlobal() { CBox CHyprGroupBarDecoration::assignedBoxGlobal() {
CBox box = m_bAssignedBox; CBox box = m_bAssignedBox;
return box.translate(g_pDecorationPositioner->getEdgeDefinedPoint(DECORATION_EDGE_TOP, m_pWindow)); box.translate(g_pDecorationPositioner->getEdgeDefinedPoint(DECORATION_EDGE_TOP, m_pWindow));
}
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_pWindow->m_iWorkspaceID);
if (!PWORKSPACE)
return box;
const auto WORKSPACEOFFSET = PWORKSPACE && !m_pWindow->m_bPinned ? PWORKSPACE->m_vRenderOffset.vec() : Vector2D();
return box.translate(WORKSPACEOFFSET);
}

View File

@@ -16,6 +16,8 @@ class CTitleTex {
CWindow* pWindowOwner = nullptr; CWindow* pWindowOwner = nullptr;
}; };
void refreshGroupBarGradients();
class CHyprGroupBarDecoration : public IHyprWindowDecoration { class CHyprGroupBarDecoration : public IHyprWindowDecoration {
public: public:
CHyprGroupBarDecoration(CWindow*); CHyprGroupBarDecoration(CWindow*);
@@ -57,8 +59,6 @@ class CHyprGroupBarDecoration : public IHyprWindowDecoration {
CTitleTex* textureFromTitle(const std::string&); CTitleTex* textureFromTitle(const std::string&);
void invalidateTextures(); void invalidateTextures();
void refreshGradients();
CBox assignedBoxGlobal(); CBox assignedBoxGlobal();
struct STitleTexs { struct STitleTexs {

View File

@@ -6,6 +6,11 @@ CDecorationPositioner::CDecorationPositioner() {
auto* const PWINDOW = std::any_cast<CWindow*>(data); auto* const PWINDOW = std::any_cast<CWindow*>(data);
this->onWindowUnmap(PWINDOW); this->onWindowUnmap(PWINDOW);
}); });
g_pHookSystem->hookDynamic("openWindow", [this](void* call, SCallbackInfo& info, std::any data) {
auto* const PWINDOW = std::any_cast<CWindow*>(data);
this->onWindowMap(PWINDOW);
});
} }
Vector2D CDecorationPositioner::getEdgeDefinedPoint(uint32_t edges, CWindow* pWindow) { Vector2D CDecorationPositioner::getEdgeDefinedPoint(uint32_t edges, CWindow* pWindow) {
@@ -52,7 +57,12 @@ Vector2D CDecorationPositioner::getEdgeDefinedPoint(uint32_t edges, CWindow* pWi
void CDecorationPositioner::uncacheDecoration(IHyprWindowDecoration* deco) { void CDecorationPositioner::uncacheDecoration(IHyprWindowDecoration* deco) {
std::erase_if(m_vWindowPositioningDatas, [&](const auto& data) { return data->pDecoration == deco; }); std::erase_if(m_vWindowPositioningDatas, [&](const auto& data) { return data->pDecoration == deco; });
m_mWindowDatas[deco->m_pWindow].needsRecalc = true;
const auto WIT = std::find_if(m_mWindowDatas.begin(), m_mWindowDatas.end(), [&](const auto& other) { return other.first == deco->m_pWindow; });
if (WIT == m_mWindowDatas.end())
return;
WIT->second.needsRecalc = true;
} }
void CDecorationPositioner::repositionDeco(IHyprWindowDecoration* deco) { void CDecorationPositioner::repositionDeco(IHyprWindowDecoration* deco) {
@@ -73,11 +83,39 @@ CDecorationPositioner::SWindowPositioningData* CDecorationPositioner::getDataFor
return DATA; return DATA;
} }
void CDecorationPositioner::onWindowUpdate(CWindow* pWindow) { void CDecorationPositioner::sanitizeDatas() {
if (!g_pCompositor->windowValidMapped(pWindow)) std::erase_if(m_mWindowDatas, [](const auto& other) { return !g_pCompositor->windowExists(other.first); });
std::erase_if(m_vWindowPositioningDatas, [](const auto& other) {
if (!g_pCompositor->windowExists(other->pWindow))
return true;
if (std::find_if(other->pWindow->m_dWindowDecorations.begin(), other->pWindow->m_dWindowDecorations.end(),
[&](const auto& el) { return el.get() == other->pDecoration; }) == other->pWindow->m_dWindowDecorations.end())
return true;
return false;
});
}
void CDecorationPositioner::forceRecalcFor(CWindow* pWindow) {
const auto WIT = std::find_if(m_mWindowDatas.begin(), m_mWindowDatas.end(), [&](const auto& other) { return other.first == pWindow; });
if (WIT == m_mWindowDatas.end())
return; return;
auto* const WINDOWDATA = &m_mWindowDatas[pWindow]; const auto WINDOWDATA = &WIT->second;
WINDOWDATA->needsRecalc = true;
}
void CDecorationPositioner::onWindowUpdate(CWindow* pWindow) {
if (!g_pCompositor->windowExists(pWindow) || !pWindow->m_bIsMapped)
return;
const auto WIT = std::find_if(m_mWindowDatas.begin(), m_mWindowDatas.end(), [&](const auto& other) { return other.first == pWindow; });
if (WIT == m_mWindowDatas.end())
return;
const auto WINDOWDATA = &WIT->second;
sanitizeDatas();
// //
std::vector<CDecorationPositioner::SWindowPositioningData*> datas; std::vector<CDecorationPositioner::SWindowPositioningData*> datas;
@@ -140,16 +178,20 @@ void CDecorationPositioner::onWindowUpdate(CWindow* pWindow) {
const bool LEFT = wd->positioningInfo.edges & DECORATION_EDGE_LEFT; const bool LEFT = wd->positioningInfo.edges & DECORATION_EDGE_LEFT;
const bool RIGHT = wd->positioningInfo.edges & DECORATION_EDGE_RIGHT; const bool RIGHT = wd->positioningInfo.edges & DECORATION_EDGE_RIGHT;
const int EDGESNO = TOP + BOTTOM + LEFT + RIGHT; const int EDGESNO = TOP + BOTTOM + LEFT + RIGHT;
const bool SOLID = !(wd->pDecoration->getDecorationFlags() & DECORATION_NON_SOLID);
if (wd->positioningInfo.policy == DECORATION_POSITION_ABSOLUTE) { if (wd->positioningInfo.policy == DECORATION_POSITION_ABSOLUTE) {
if (LEFT)
stickyOffsetXL += wd->positioningInfo.desiredExtents.topLeft.x; if (SOLID) {
if (RIGHT) if (LEFT)
stickyOffsetXR += wd->positioningInfo.desiredExtents.bottomRight.x; stickyOffsetXL += wd->positioningInfo.desiredExtents.topLeft.x;
if (TOP) if (RIGHT)
stickyOffsetYT += wd->positioningInfo.desiredExtents.topLeft.y; stickyOffsetXR += wd->positioningInfo.desiredExtents.bottomRight.x;
if (BOTTOM) if (TOP)
stickyOffsetYB += wd->positioningInfo.desiredExtents.bottomRight.y; stickyOffsetYT += wd->positioningInfo.desiredExtents.topLeft.y;
if (BOTTOM)
stickyOffsetYB += wd->positioningInfo.desiredExtents.bottomRight.y;
}
wd->lastReply = {}; wd->lastReply = {};
wd->pDecoration->onPositioningReply({}); wd->pDecoration->onPositioningReply({});
@@ -182,23 +224,27 @@ void CDecorationPositioner::onWindowUpdate(CWindow* pWindow) {
pos.x -= desiredSize; pos.x -= desiredSize;
size = {desiredSize, wb.size().y}; size = {desiredSize, wb.size().y};
stickyOffsetXL += desiredSize; if (SOLID)
stickyOffsetXL += desiredSize;
} else if (RIGHT) { } else if (RIGHT) {
pos = wb.pos() + Vector2D{wb.size().x, 0} - EDGEPOINT + Vector2D{stickyOffsetXR, 0}; pos = wb.pos() + Vector2D{wb.size().x, 0} - EDGEPOINT + Vector2D{stickyOffsetXR, 0};
size = {desiredSize, wb.size().y}; size = {desiredSize, wb.size().y};
stickyOffsetXR += desiredSize; if (SOLID)
stickyOffsetXR += desiredSize;
} else if (TOP) { } else if (TOP) {
pos = wb.pos() - EDGEPOINT - Vector2D{0, stickyOffsetYT}; pos = wb.pos() - EDGEPOINT - Vector2D{0, stickyOffsetYT};
pos.y -= desiredSize; pos.y -= desiredSize;
size = {wb.size().x, desiredSize}; size = {wb.size().x, desiredSize};
stickyOffsetYT += desiredSize; if (SOLID)
stickyOffsetYT += desiredSize;
} else { } else {
pos = wb.pos() + Vector2D{0, wb.size().y} - EDGEPOINT - Vector2D{0, stickyOffsetYB}; pos = wb.pos() + Vector2D{0, wb.size().y} - EDGEPOINT - Vector2D{0, stickyOffsetYB};
size = {wb.size().x, desiredSize}; size = {wb.size().x, desiredSize};
stickyOffsetYB += desiredSize; if (SOLID)
stickyOffsetYB += desiredSize;
} }
wd->lastReply = {{pos, size}, EPHEMERAL}; wd->lastReply = {{pos, size}, EPHEMERAL};
@@ -221,8 +267,15 @@ void CDecorationPositioner::onWindowUnmap(CWindow* pWindow) {
m_mWindowDatas.erase(pWindow); m_mWindowDatas.erase(pWindow);
} }
void CDecorationPositioner::onWindowMap(CWindow* pWindow) {
m_mWindowDatas[pWindow] = {};
}
SWindowDecorationExtents CDecorationPositioner::getWindowDecorationReserved(CWindow* pWindow) { SWindowDecorationExtents CDecorationPositioner::getWindowDecorationReserved(CWindow* pWindow) {
return m_mWindowDatas[pWindow].reserved; try {
const auto E = m_mWindowDatas.at(pWindow);
return E.reserved;
} catch (std::out_of_range& e) { return {}; }
} }
SWindowDecorationExtents CDecorationPositioner::getWindowDecorationExtents(CWindow* pWindow, bool inputOnly) { SWindowDecorationExtents CDecorationPositioner::getWindowDecorationExtents(CWindow* pWindow, bool inputOnly) {
@@ -232,6 +285,9 @@ SWindowDecorationExtents CDecorationPositioner::getWindowDecorationExtents(CWind
if (data->pWindow != pWindow) if (data->pWindow != pWindow)
continue; continue;
if (!data->pWindow || !data->pDecoration)
continue;
if (!(data->pDecoration->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT) && inputOnly) if (!(data->pDecoration->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT) && inputOnly)
continue; continue;

View File

@@ -11,7 +11,7 @@ class IHyprWindowDecoration;
enum eDecorationPositioningPolicy enum eDecorationPositioningPolicy
{ {
DECORATION_POSITION_ABSOLUTE = 0, /* Decoration does not interfere with anything else */ DECORATION_POSITION_ABSOLUTE = 0, /* Decoration wants absolute positioning */
DECORATION_POSITION_STICKY, /* Decoration is stuck to some edge of a window */ DECORATION_POSITION_STICKY, /* Decoration is stuck to some edge of a window */
}; };
@@ -71,6 +71,7 @@ class CDecorationPositioner {
CBox getBoxWithIncludedDecos(CWindow* pWindow); CBox getBoxWithIncludedDecos(CWindow* pWindow);
void repositionDeco(IHyprWindowDecoration* deco); void repositionDeco(IHyprWindowDecoration* deco);
CBox getWindowDecorationBox(IHyprWindowDecoration* deco); CBox getWindowDecorationBox(IHyprWindowDecoration* deco);
void forceRecalcFor(CWindow* pWindow);
private: private:
struct SWindowPositioningData { struct SWindowPositioningData {
@@ -93,6 +94,8 @@ class CDecorationPositioner {
SWindowPositioningData* getDataFor(IHyprWindowDecoration* pDecoration, CWindow* pWindow); SWindowPositioningData* getDataFor(IHyprWindowDecoration* pDecoration, CWindow* pWindow);
void onWindowUnmap(CWindow* pWindow); void onWindowUnmap(CWindow* pWindow);
void onWindowMap(CWindow* pWindow);
void sanitizeDatas();
}; };
inline std::unique_ptr<CDecorationPositioner> g_pDecorationPositioner; inline std::unique_ptr<CDecorationPositioner> g_pDecorationPositioner;

View File

@@ -24,6 +24,7 @@ enum eDecorationFlags
{ {
DECORATION_ALLOWS_MOUSE_INPUT = 1 << 0, /* this decoration accepts mouse input */ DECORATION_ALLOWS_MOUSE_INPUT = 1 << 0, /* this decoration accepts mouse input */
DECORATION_PART_OF_MAIN_WINDOW = 1 << 1, /* this decoration is a *seamless* part of the main window, so stuff like shadows will include it */ DECORATION_PART_OF_MAIN_WINDOW = 1 << 1, /* this decoration is a *seamless* part of the main window, so stuff like shadows will include it */
DECORATION_NON_SOLID = 1 << 2, /* this decoration is not solid. Other decorations should draw on top of it. Example: shadow */
}; };
class CWindow; class CWindow;

View File

@@ -234,11 +234,11 @@ vec3 rgb2hsl(vec3 col) {
sat = delta / (mul * 2.0); sat = delta / (mul * 2.0);
} }
vec3 masks = vec3((maxc == red && maxc != green) ? 1.0 : 0.0, (maxc == green && maxc != blue) ? 1.0 : 0.0, (maxc == blue && maxc != red) ? 1.0 : 0.0);
vec3 adds = vec3(((green - blue) / delta), 2.0 + ((blue - red) / delta), 4.0 + ((red - green) / delta));
if (delta > 0.0) { if (delta > 0.0) {
vec3 maxcVec = vec3(maxc);
vec3 masks = vec3(equal(maxcVec, col)) * vec3(notEqual(maxcVec, vec3(green, blue, red)));
vec3 adds = vec3(0.0, 2.0, 4.0) + vec3(green - blue, blue - red, red - green) / delta;
hue += dot(adds, masks); hue += dot(adds, masks);
hue /= 6.0; hue /= 6.0;
@@ -248,6 +248,7 @@ vec3 rgb2hsl(vec3 col) {
return vec3(hue, sat, lum); return vec3(hue, sat, lum);
} }
vec3 hsl2rgb(vec3 col) { vec3 hsl2rgb(vec3 col) {
const float onethird = 1.0 / 3.0; const float onethird = 1.0 / 3.0;
const float twothird = 2.0 / 3.0; const float twothird = 2.0 / 3.0;

View File

@@ -38,8 +38,8 @@ index 29b103a..0b6e5a4 100644
# necessary for bugfix releases. Increasing soversion is required because # necessary for bugfix releases. Increasing soversion is required because
# wlroots never guarantees ABI stability -- only API stability is guaranteed # wlroots never guarantees ABI stability -- only API stability is guaranteed
# between minor releases. # between minor releases.
-soversion = 12 -soversion = 13
+soversion = 12032 +soversion = 13032
little_endian = target_machine.endian() == 'little' little_endian = target_machine.endian() == 'little'
big_endian = target_machine.endian() == 'big' big_endian = target_machine.endian() == 'big'

View File

@@ -1,7 +1,7 @@
[wrap-git] [wrap-git]
directory = wlroots directory = wlroots
url = https://gitlab.freedesktop.org/wlroots/wlroots.git url = https://gitlab.freedesktop.org/wlroots/wlroots.git
revision = 5de9e1a99d6642c2d09d589aa37ff0a8945dcee1 revision = 5d639394f3e83b01596dcd166a44a9a1a2583350
depth = 1 depth = 1
diff_files = wlroots-meson-build.patch diff_files = wlroots-meson-build.patch