update: added some new commits

This commit is contained in:
Kaley, Fischer 2023-12-27 18:39:20 +01:00
parent b376d72bba
commit 68b6a5ab23
63 changed files with 1431 additions and 874 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

3
.gitmodules vendored
View file

@ -1,7 +1,6 @@
[submodule "wlroots"] [submodule "wlroots"]
path = subprojects/wlroots path = subprojects/wlroots
url = https://github.com/DRAGONTOS/wlroots.git url = https://gitlab.freedesktop.org/wlroots/wlroots.git
branch = 0.17.0-dev
[submodule "subprojects/hyprland-protocols"] [submodule "subprojects/hyprland-protocols"]
path = subprojects/hyprland-protocols path = subprojects/hyprland-protocols
url = https://github.com/hyprwm/hyprland-protocols url = https://github.com/hyprwm/hyprland-protocols

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"
) )
@ -221,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

@ -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
@ -127,12 +131,12 @@ windowrulev2 = nomaximizerequest, class:.* # You'll probably like this.
$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

@ -25,35 +25,64 @@
const std::string USAGE = R"#(usage: hyprctl [flags] [<command> [args]] const std::string USAGE = R"#(usage: hyprctl [flags] [<command> [args]]
hyprctl --batch {<command 1> [args] ; <command 2> [args] ; ...} hyprctl --batch {<command 1> [args] ; <command 2> [args] ; ...}
commands:
LISTING COMMANDS: LISTING COMMANDS:
monitors
monitors: List outputs monitors: List outputs
workspaces
workspaces: List all workspaces workspaces: List all workspaces
activeworkspace
activeworkspace: Get currently active workspace activeworkspace: Get currently active workspace
workspacerules
clients: List clients (e.g. windows) clients: List clients (e.g. windows)
clients
activewindow: Get currently active window activewindow: Get currently active window
activewindow
layers: List layers layers: List layers
layers
animations: List animations and bezier curves in use animations: List animations and bezier curves in use
devices
devices: List devices devices: List devices
binds
binds: List registered binds binds: List registered binds
dispatch
instances: List running Hyprland instances instances: List running Hyprland instances
keyword
layouts: List layouts layouts: List layouts
version
globalshortcuts: List global shortcuts globalshortcuts: List global shortcuts
kill
version: Print hyprland version version: Print hyprland version
splash
CONFIGURATION COMMANDS: CONFIGURATION COMMANDS:
hyprpaper
keyword <keyword> [args]: Execute a keyword keyword <keyword> [args]: Execute a keyword
reload
getoption <option>: Get value of <option> getoption <option>: Get value of <option>
setcursor
reload: Reload configurations reload: Reload configurations
getoption
PLUGIN: PLUGIN:
cursorpos
plugin list: List loaded plugins plugin list: List loaded plugins
switchxkblayout
plugin load <path>: Load plugin from <path> plugin load <path>: Load plugin from <path>
seterror
plugin unload <path>: Unload plugin at <path> plugin unload <path>: Unload plugin at <path>
setprop
THEMING: THEMING:
plugin
hyprpaper <keywords> Issue hyprpaper keywords using IPC hyprpaper <keywords> Issue hyprpaper keywords using IPC
notify
splash: Prints the current random splash splash: Prints the current random splash
globalshortcuts
cursorpos: Get the current cursor position in global layout coordinates cursorpos: Get the current cursor position in global layout coordinates
instances
setcursor <theme> <size>: Set cursor theme and size, (except for GTK) setcursor <theme> <size>: Set cursor theme and size, (except for GTK)
layouts
ADDITIONAL COMMANDS: ADDITIONAL COMMANDS:
dispatch <name> [args]: Run a dispatcher dispatch <name> [args]: Run a dispatcher
flags:
kill: Enter kill mode, where you can kill an app by clicking on it, kill: Enter kill mode, where you can kill an app by clicking on it,
use ESCAPE to quit kill mode use ESCAPE to quit kill mode
switchxkblayout <args>: Sets the xkb layout index for a keyboard, see wiki for details switchxkblayout <args>: Sets the xkb layout index for a keyboard, see wiki for details

View file

@ -1,5 +1,6 @@
{ {
lib, lib,
fetchurl,
stdenv, stdenv,
pkg-config, pkg-config,
makeWrapper, makeWrapper,
@ -27,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,
@ -35,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 {
@ -73,7 +85,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
cairo cairo
hyprland-protocols hyprland-protocols
libGL libGL
libdrm libdrm_2_4_118
libinput libinput
libxkbcommon libxkbcommon
mesa mesa
@ -82,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.3" "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)
@ -519,14 +517,15 @@ void CCompositor::startCompositor() {
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
if (m_sWLRSession /* Session-less Hyprland usually means a nest, don't update the env in that case */) { if (m_sWLRSession /* Session-less Hyprland usually means a nest, don't update the env in that case */ && fork() == 0)
const auto CMD = execl(
"/bin/sh", "/bin/sh", "-c",
#ifdef USES_SYSTEMD #ifdef USES_SYSTEMD
"systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP && hash dbus-update-activation-environment 2>/dev/null && " "systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP && hash dbus-update-activation-environment 2>/dev/null && "
#endif #endif
"dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE"; "dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE",
g_pKeybindManager->spawn(CMD); nullptr);
}
Debug::log(LOG, "Running on WAYLAND_DISPLAY: {}", m_szWLDisplaySocket); Debug::log(LOG, "Running on WAYLAND_DISPLAY: {}", m_szWLDisplaySocket);
if (!wlr_backend_start(m_sWLRBackend)) { if (!wlr_backend_start(m_sWLRBackend)) {
@ -576,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;
@ -656,24 +655,6 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos, CWindow* pIgnoreW
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();
@ -688,48 +669,75 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos, CWindow* pIgnoreW
} }
} }
} }
auto windowForWorkspace = [&](bool special) -> CWindow* {
// first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter. // first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter.
for (auto& w : m_vWindows | std::views::reverse) { 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 (special && !isWorkspaceSpecial(w->m_iWorkspaceID)) // because special floating may creep up into regular
if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned && !w->m_bNoFocus) {
// 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() {
@ -1102,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)
@ -1124,21 +1147,6 @@ CWindow* CCompositor::getWindowFromHandle(uint32_t handle) {
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::getWindowFromZWLRHandle(wl_resource* handle) { CWindow* CCompositor::getWindowFromZWLRHandle(wl_resource* handle) {
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (!w->m_bIsMapped || w->isHidden() || !w->m_phForeignToplevel) if (!w->m_bIsMapped || w->isHidden() || !w->m_phForeignToplevel)
@ -1388,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;
} }
} }
@ -1437,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()) {
@ -2055,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();
} }
} }
@ -2534,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;
} }

View file

@ -29,7 +29,8 @@
#include "plugins/PluginSystem.hpp" #include "plugins/PluginSystem.hpp"
#include "helpers/Watchdog.hpp" #include "helpers/Watchdog.hpp"
enum eManagersInitStage { enum eManagersInitStage
{
STAGE_PRIORITY = 0, STAGE_PRIORITY = 0,
STAGE_LATE STAGE_LATE
}; };
@ -61,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;
@ -139,7 +139,7 @@ class CCompositor {
CWindow* vectorToWindowIdeal(const Vector2D&, CWindow* pIgnoreWindow = nullptr); // used only for finding a window to focus on, basically a "findFocusableWindow" CWindow* vectorToWindowIdeal(const Vector2D&, CWindow* pIgnoreWindow = nullptr); // 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); 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() {

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,7 +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; 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);
@ -189,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;
@ -197,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;
@ -272,7 +275,6 @@ void CConfigManager::setDefaultVars() {
configValues["xwayland:use_nearest_neighbor"].intValue = 1; configValues["xwayland:use_nearest_neighbor"].intValue = 1;
configValues["xwayland:force_zero_scaling"].intValue = 0; configValues["xwayland:force_zero_scaling"].intValue = 0;
configValues["xwayland:enabled"].intValue = 1;
configValues["autogenerated"].intValue = 0; configValues["autogenerated"].intValue = 0;
} }
@ -1211,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;
@ -1258,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;
@ -1512,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);
@ -1565,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);
@ -1670,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)
@ -2076,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;
@ -2157,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
@ -134,12 +139,12 @@ windowrulev2 = nomaximizerequest, class:.* # You'll probably like this.
$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

@ -75,7 +75,7 @@ std::string monitorsRequest(std::string request, HyprCtl::eHyprCtlOutputFormat f
"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, (int)m->vecPosition.x, (int)m->vecPosition.y, m->activeWorkspace,
(m->activeWorkspace == -1 ? "" : escapeJSONStrings(g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName)), m->specialWorkspaceID, (m->activeWorkspace == -1 ? "" : escapeJSONStrings(g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName)), m->specialWorkspaceID,
@ -99,7 +99,7 @@ std::string monitorsRequest(std::string request, HyprCtl::eHyprCtlOutputFormat f
"{} {} {}\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, (m->activeWorkspace == -1 ? "" : g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName), (m->output->serial ? m->output->serial : ""), m->activeWorkspace, (m->activeWorkspace == -1 ? "" : g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName),
m->specialWorkspaceID, getWorkspaceNameFromSpecialID(m->specialWorkspaceID), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, m->specialWorkspaceID, 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 ? "yes" : "no"), (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "yes" : "no"),
@ -754,7 +754,10 @@ std::string versionRequest(HyprCtl::eHyprCtlOutputFormat format) {
#ifdef LEGACY_RENDERER #ifdef LEGACY_RENDERER
result += "legacyrenderer\n"; result += "legacyrenderer\n";
#endif #endif
#ifndef ISDEBUG #ifndef NDEBUG
result += "debug\n";
#endif
#ifdef HYPRLAND_DEBUG
result += "debug\n"; result += "debug\n";
#endif #endif
#ifdef NO_XWAYLAND #ifdef NO_XWAYLAND
@ -776,7 +779,10 @@ std::string versionRequest(HyprCtl::eHyprCtlOutputFormat format) {
#ifdef LEGACY_RENDERER #ifdef LEGACY_RENDERER
result += "\"legacyrenderer\","; result += "\"legacyrenderer\",";
#endif #endif
#ifndef ISDEBUG #ifndef NDEBUG
result += "\"debug\",";
#endif
#ifdef HYPRLAND_DEBUG
result += "\"debug\","; result += "\"debug\",";
#endif #endif
#ifdef NO_XWAYLAND #ifdef NO_XWAYLAND

View file

@ -27,6 +27,7 @@ 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 inline std::string rollingLog = ""; // rolling log contains the ROLLING_LOG_SIZE tail of the log
@ -36,6 +37,9 @@ namespace Debug {
if (level == TRACE && !trace) if (level == TRACE && !trace)
return; return;
if (shuttingDown)
return;
std::string logMsg = ""; std::string logMsg = "";
switch (level) { switch (level) {

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

@ -1169,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

@ -781,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

@ -34,6 +34,7 @@ std::string replaceInString(std::string subject, const std:
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
@ -643,3 +647,12 @@ 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;
@ -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

@ -49,13 +49,6 @@ inline const std::vector<std::string> SPLASHES = {
"Ding ding pch n daa, bam-ba-ba-re-bam baram bom bom baba-bam-bam-bommm", "Ding ding pch n daa, bam-ba-ba-re-bam baram bom bom baba-bam-bam-bommm",
"Súbeme la radio que esta es mi canción", "Súbeme la radio que esta es mi canción",
"I'm beggin', beggin' you", "I'm beggin', beggin' you",
"Never Gonna Give You Up",
"People are strange, when you're a stranger",
"Sun is shining in the sky, there ain't a cloud in sight",
"Wham, bam, shang a lang",
"Did you think I'd die? Oh, no, not I, I will survive.",
"But I would walk 500 miles, and I would walk 500 more",
"COUNTRY ROADS, TAKE ME HOME!",
"Never gonna let you down (I am trying!)", "Never gonna let you down (I am trying!)",
"\"I use Arch, btw\" - John Cena", "\"I use Arch, btw\" - John Cena",
"\"Hyper\".replace(\"e\", \"\")", "\"Hyper\".replace(\"e\", \"\")",
@ -69,4 +62,4 @@ inline const std::vector<std::string> SPLASHES = {
"The AUR packages always work, except for the times they don't.", "The AUR packages always work, except for the times they don't.",
"Funny animation compositor woo" "Funny animation compositor woo"
// clang-format on // clang-format on
}; };

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

@ -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

@ -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

@ -38,7 +38,7 @@ int main(int argc, char** argv) {
setenv("QT_QPA_PLATFORM", "wayland", 1); setenv("QT_QPA_PLATFORM", "wayland", 1);
setenv("SDL_VIDEODRIVER", "wayland", 1); setenv("SDL_VIDEODRIVER", "wayland", 1);
setenv("OZONE_PLATFORM", "wayland", 1); setenv("OZONE_PLATFORM", "wayland", 1);
// parse some args // parse some args
std::string configPath; std::string configPath;
bool ignoreSudo = false; bool ignoreSudo = false;
@ -58,14 +58,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++;
@ -101,7 +104,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

@ -732,7 +732,7 @@ void CKeybindManager::toggleActiveFloating(std::string args) {
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)
@ -741,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();
@ -1476,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;
@ -1906,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;
} }
@ -2058,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

@ -9,10 +9,6 @@
CHyprXWaylandManager::CHyprXWaylandManager() { CHyprXWaylandManager::CHyprXWaylandManager() {
#ifndef NO_XWAYLAND #ifndef NO_XWAYLAND
static auto* const XWAYLANDENABLED = &g_pConfigManager->getConfigValuePtr("xwayland:enabled")->intValue;
if (!*XWAYLANDENABLED)
return;
m_sWLRXWayland = wlr_xwayland_create(g_pCompositor->m_sWLDisplay, g_pCompositor->m_sWLRCompositor, 1); m_sWLRXWayland = wlr_xwayland_create(g_pCompositor->m_sWLDisplay, g_pCompositor->m_sWLRCompositor, 1);
if (!m_sWLRXWayland) { if (!m_sWLRXWayland) {
@ -49,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);
} }
} }
@ -62,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

@ -233,13 +233,13 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
surfacePos = PMONITOR->vecPosition; surfacePos = PMONITOR->vecPosition;
} }
// overlay are 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 // also IME popups
if (!foundSurface) { if (!foundSurface) {
auto popup = g_pCompositor->vectorToIMEPopup(mouseCoords, &m_sIMERelay.m_lIMEPopups); auto popup = g_pCompositor->vectorToIMEPopup(mouseCoords, m_sIMERelay.m_lIMEPopups);
if (popup) { if (popup) {
foundSurface = popup->pSurface->surface; foundSurface = popup->pSurface->surface;
surfacePos = Vector2D(popup->realX, popup->realY); surfacePos = Vector2D(popup->realX, popup->realY);
@ -593,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;
@ -621,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;
} }
@ -688,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);
@ -706,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() {
@ -892,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);
} }
@ -1152,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

@ -72,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);
@ -81,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

@ -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,36 +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;
static auto* const PBLUR = &g_pConfigManager->getConfigValuePtr("decoration:blur:enabled")->intValue;
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);
@ -146,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() {
@ -166,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) {
@ -201,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);
@ -214,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;
@ -503,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
@ -555,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);
@ -642,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);
@ -803,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);
@ -857,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);
@ -916,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);
@ -949,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);
@ -1119,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;
} }
@ -1137,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.
@ -1227,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;
@ -1324,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
@ -1407,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);
@ -1481,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
@ -1506,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
@ -1520,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) {
@ -1541,14 +1615,18 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
if (!g_pHyprRenderer->shouldRenderWindow(pWindow)) if (!g_pHyprRenderer->shouldRenderWindow(pWindow))
return; // ignore, window is not being rendered return; // ignore, window is not being rendered
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();
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;
@ -1565,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) {
@ -1603,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
@ -1637,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) {
@ -1747,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);
@ -1814,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() {
@ -1974,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();
@ -1988,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() {
@ -2017,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"
@ -27,7 +30,8 @@ inline const float fullVerts[] = {
}; };
inline const float fanVertsFull[] = {-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f}; inline const float fanVertsFull[] = {-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f};
enum eDiscardMode { enum eDiscardMode
{
DISCARD_OPAQUE = 1, DISCARD_OPAQUE = 1,
DISCARD_ALPHA = 1 << 1 DISCARD_ALPHA = 1 << 1
}; };
@ -37,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;
@ -78,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;
@ -102,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;
@ -175,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;
@ -200,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

@ -4,11 +4,51 @@
#include "../helpers/Region.hpp" #include "../helpers/Region.hpp"
#include <algorithm> #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) {
@ -254,21 +294,6 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, CWorksp
renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_ALL); 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;
if (!w->m_bPinned || !w->m_bIsFloating)
continue;
if (!shouldRenderWindow(w.get(), pMonitor, pWorkspace))
continue;
// render the bad boy
renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_ALL);
}
} }
void CHyprRenderer::renderWorkspaceWindows(CMonitor* pMonitor, CWorkspace* pWorkspace, timespec* time) { void CHyprRenderer::renderWorkspaceWindows(CMonitor* pMonitor, CWorkspace* pWorkspace, timespec* time) {
@ -283,14 +308,12 @@ 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)) 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 && w->m_iWorkspaceID == pWorkspace->m_iID) { if (w.get() == g_pCompositor->m_pLastWindow && w->m_iWorkspaceID == pWorkspace->m_iID) {
@ -312,9 +335,6 @@ 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 (pWorkspace->m_bIsSpecialWorkspace != g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID)) if (pWorkspace->m_bIsSpecialWorkspace != g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID))
continue; continue;
@ -443,7 +463,6 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
// if window is floating and we have a slide animation, clip it to its full bb // 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()) { 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); CRegion rg = pWindow->getFullWindowBoundingBox().translate(-pMonitor->vecPosition + PWORKSPACE->m_vRenderOffset.vec()).scale(pMonitor->scale);
rg.add(CBox{0, 0, pMonitor->vecSize.x, pMonitor->vecSize.y});
g_pHyprOpenGL->m_RenderData.clipBox = rg.getExtents(); g_pHyprOpenGL->m_RenderData.clipBox = rg.getExtents();
} }
@ -631,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};
@ -665,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);
} }
@ -705,12 +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))
@ -879,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;
@ -889,8 +925,6 @@ 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 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;
@ -922,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);
@ -1026,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;
@ -1042,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;
@ -1097,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);
@ -1111,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);
@ -1132,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();
} }
@ -1153,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;
@ -1227,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);
@ -1992,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);
@ -2165,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;
@ -2226,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

@ -92,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}};

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() {}
@ -130,10 +135,11 @@ 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)
g_pHyprOpenGL->renderTexture((m_dwGroupMembers[i] == g_pCompositor->m_pLastWindow ? m_tGradientActive : m_tGradientInactive), &rect, 1.0); g_pHyprOpenGL->renderTexture(GRADIENTTEX, &rect, 1.0);
rect.y += (ASSIGNEDBOX.h / 2.0 - (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) / 2.0) * pMonitor->scale; 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;
@ -232,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);
@ -273,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) {

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

@ -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